aboutsummaryrefslogtreecommitdiffstats
path: root/recipes/linux/linux-mtx-1-2.4.27
diff options
context:
space:
mode:
authorAndrea Adami <andrea.adami@gmail.com>2011-04-24 01:06:51 +0200
committerAndrea Adami <andrea.adami@gmail.com>2011-04-24 01:06:51 +0200
commit1120fcedb3cd935e501a101ad5ff959fde7da2e5 (patch)
treede8183f94065df59278d760d3e3831e13e58f849 /recipes/linux/linux-mtx-1-2.4.27
parent8aec40346f8931e6c201dea0a29e1d3b253ed337 (diff)
downloadopenembedded-1120fcedb3cd935e501a101ad5ff959fde7da2e5.tar.gz
linux: move er0100, mtx-1, mtx-2 2.4 kernels to /obsolete
* nowadays we support only 2.6 kernels Signed-off-by: Andrea Adami <andrea.adami@gmail.com>
Diffstat (limited to 'recipes/linux/linux-mtx-1-2.4.27')
-rw-r--r--recipes/linux/linux-mtx-1-2.4.27/01-mtd-2004-01-27.diff51503
-rw-r--r--recipes/linux/linux-mtx-1-2.4.27/02-mtd-mtx-1-map.diff248
-rw-r--r--recipes/linux/linux-mtx-1-2.4.27/03-mtd-erase-compiler-bug.diff21
-rw-r--r--recipes/linux/linux-mtx-1-2.4.27/04-mtx-1-board-reset.diff15
-rw-r--r--recipes/linux/linux-mtx-1-2.4.27/05-mtx-1-pci-irq.diff18
-rw-r--r--recipes/linux/linux-mtx-1-2.4.27/06-zboot-2.4.26.patch5317
-rw-r--r--recipes/linux/linux-mtx-1-2.4.27/07-zboot-zimage-flash-bin.diff11
-rw-r--r--recipes/linux/linux-mtx-1-2.4.27/08-usb-nonpci-2.4.24.patch3185
-rw-r--r--recipes/linux/linux-mtx-1-2.4.27/09-au1000-eth-vlan.diff10
-rw-r--r--recipes/linux/linux-mtx-1-2.4.27/10-iw-max-spy-32.diff11
-rw-r--r--recipes/linux/linux-mtx-1-2.4.27/11-mtd-proc-partition-rw.diff173
-rw-r--r--recipes/linux/linux-mtx-1-2.4.27/12-openswan-2.2.0-nat-t.diff143
-rw-r--r--recipes/linux/linux-mtx-1-2.4.27/13-openswan-2.2.0.patch61293
-rw-r--r--recipes/linux/linux-mtx-1-2.4.27/14-au1000-eth-link-beat.diff64
-rw-r--r--recipes/linux/linux-mtx-1-2.4.27/16-i2c.patch7482
-rw-r--r--recipes/linux/linux-mtx-1-2.4.27/17-lmsensors.2.8.8.patch40940
-rw-r--r--recipes/linux/linux-mtx-1-2.4.27/18-i2c-au1x00gpio.patch466
-rw-r--r--recipes/linux/linux-mtx-1-2.4.27/19-kernel-make-depend.diff11
-rw-r--r--recipes/linux/linux-mtx-1-2.4.27/20-au1x00_ethernet_tx_stats.diff64
-rw-r--r--recipes/linux/linux-mtx-1-2.4.27/21-mtx-1-watchdog.diff231
-rw-r--r--recipes/linux/linux-mtx-1-2.4.27/22-umts.diff28
-rw-r--r--recipes/linux/linux-mtx-1-2.4.27/23-mtx-1_watchdog_autotrigger.patch98
-rw-r--r--recipes/linux/linux-mtx-1-2.4.27/24-mtx-1_sysbtn.patch257
-rw-r--r--recipes/linux/linux-mtx-1-2.4.27/25-mtx-sio2.diff12
-rw-r--r--recipes/linux/linux-mtx-1-2.4.27/26-usbd-amd-pb1x00-kit-23may2003-update.diff130
-rw-r--r--recipes/linux/linux-mtx-1-2.4.27/27-usbd-amd-pb1x00-kit-23may2003-usbd.diff15816
-rw-r--r--recipes/linux/linux-mtx-1-2.4.27/28-idsel-cardbus.diff67
-rw-r--r--recipes/linux/linux-mtx-1-2.4.27/29-au1000-pci-config-clear-errors.diff15
-rw-r--r--recipes/linux/linux-mtx-1-2.4.27/30-mtx-1-sysled.diff446
-rw-r--r--recipes/linux/linux-mtx-1-2.4.27/31-mtx-1u-led-init.diff16
-rw-r--r--recipes/linux/linux-mtx-1-2.4.27/32-usbserial-stalled-hack.diff22
-rw-r--r--recipes/linux/linux-mtx-1-2.4.27/33-usbserial-bulk_in_size-4096.diff140
-rw-r--r--recipes/linux/linux-mtx-1-2.4.27/39-mppe-mpc.patch1665
-rw-r--r--recipes/linux/linux-mtx-1-2.4.27/40-option-hsdpa.patch2961
-rw-r--r--recipes/linux/linux-mtx-1-2.4.27/42-usb-ohci-fixes.patch51
-rw-r--r--recipes/linux/linux-mtx-1-2.4.27/43-usbserial-27-32-backport.diff33
-rw-r--r--recipes/linux/linux-mtx-1-2.4.27/45-acm-tty-and-sb2.patch721
-rw-r--r--recipes/linux/linux-mtx-1-2.4.27/48-pptp.patch5092
-rw-r--r--recipes/linux/linux-mtx-1-2.4.27/49-bash4-configure.patch11
-rw-r--r--recipes/linux/linux-mtx-1-2.4.27/defconfig-mtx-11347
40 files changed, 0 insertions, 200134 deletions
diff --git a/recipes/linux/linux-mtx-1-2.4.27/01-mtd-2004-01-27.diff b/recipes/linux/linux-mtx-1-2.4.27/01-mtd-2004-01-27.diff
deleted file mode 100644
index 6c3b3b9acb..0000000000
--- a/recipes/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: Config.in,v 1.74 2002/04/23 13:52:14 mag Exp $
-+# $Id: Config.in,v 1.75 2003/05/23 11:38:29 dwmw2 Exp $
-
- 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: Makefile,v 1.65 2002/03/22 07:10:34 dwmw2 Exp $
--
--
--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: Makefile.common,v 1.2 2003/05/23 11:38:29 dwmw2 Exp $
-
- # *** 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: afs.c,v 1.8 2002/05/04 08:49:09 rmk Exp $
-+ $Id: afs.c,v 1.12 2003/06/13 15:31:06 rmk Exp $
-
- ======================================================================*/
-
-@@ -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: Config.in,v 1.16 2002/09/03 13:30:43 joern Exp $
-+# $Id: Config.in,v 1.17 2003/09/25 14:40:34 thayne Exp $
-
- 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: Makefile,v 1.8 2002/01/10 20:27:40 eric Exp $
-+# $Id: Makefile.common,v 1.3 2003/09/25 14:40:34 thayne Exp $
-
-+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: amd_flash.c,v 1.19 2003/01/24 13:30:11 dwmw2 Exp $
-+ * $Id: amd_flash.c,v 1.23 2003/06/12 09:24:13 dwmw2 Exp $
- *
- * 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: cfi_cmdset_0001.c,v 1.114 2003/03/18 12:28:40 dwmw2 Exp $
-+ * $Id: cfi_cmdset_0001.c,v 1.132 2003/11/04 19:34:22 thayne Exp $
- *
- *
- * 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: cfi_cmdset_0002.c,v 1.62 2003/01/24 23:30:13 dwmw2 Exp $
-+ * $Id: cfi_cmdset_0002.c,v 1.94 2004/01/27 10:16:20 dvrabel Exp $
- *
- */
-
-+#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: cfi_probe.c,v 1.69 2002/05/11 22:13:03 dwmw2 Exp $
-+ $Id: cfi_probe.c,v 1.73 2003/11/08 00:51:21 dsaxena Exp $
- */
-
- #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: cfi_util.c,v 1.3 2003/11/14 19:50:03 thayne Exp $
-+ *
-+ */
-+
-+#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: chipreg.c,v 1.13 2002/02/21 08:26:58 dwmw2 Exp $
-+ * $Id: chipreg.c,v 1.16 2003/05/29 09:36:15 dwmw2 Exp $
- *
- * 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: gen_probe.c,v 1.9 2002/09/05 05:15:32 acurtis Exp $
-+ * $Id: gen_probe.c,v 1.14 2003/11/08 00:51:21 dsaxena Exp $
- */
-
- #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: jedec.c,v 1.14 2002/06/27 02:19:12 dwmw2 Exp $
-+ * $Id: jedec.c,v 1.19 2003/05/29 09:25:23 dwmw2 Exp $
- */
-
-+#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: jedec_probe.c,v 1.19 2002/11/12 13:12:10 dwmw2 Exp $
-+ $Id: jedec_probe.c,v 1.44 2003/11/17 15:57:35 thayne Exp $
- 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: map_absent.c,v 1.2 2001/10/02 15:05:12 dwmw2 Exp $
-+ * $Id: map_absent.c,v 1.4 2003/05/28 12:51:49 dwmw2 Exp $
- *
- * 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: map_ram.c,v 1.14 2001/10/02 15:05:12 dwmw2 Exp $
-+ * $Id: map_ram.c,v 1.17 2003/05/28 12:51:49 dwmw2 Exp $
- */
-
- #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: map_rom.c,v 1.17 2001/10/02 15:05:12 dwmw2 Exp $
-+ * $Id: map_rom.c,v 1.20 2003/05/28 12:51:49 dwmw2 Exp $
- */
-
- #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: sharp.c,v 1.8 2002/05/17 08:59:19 dwmw2 Exp $
-+ * $Id: sharp.c,v 1.12 2003/05/28 15:39:52 dwmw2 Exp $
- *
- * 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: cmdlinepart.c,v 1.6 2002/11/16 01:37:39 dneuer Exp $
-+ * $Id: cmdlinepart.c,v 1.11 2003/10/23 08:32:45 dwmw2 Exp $
- *
- * 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: Config.in,v 1.8 2003/01/24 23:25:14 dwmw2 Exp $
-+# $Id: Config.in,v 1.11 2003/05/28 10:54:23 dwmw2 Exp $
-
- 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: Makefile,v 1.4 2001/06/26 21:10:05 spse Exp $
-+# $Id: Makefile.common,v 1.4 2003/08/21 17:52:29 joern Exp $
-
-+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-25.c,v 1.5 2003/07/16 06:48:27 spse Exp $
-+ *
-+ * 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: 1.5 $"
-+
-+/* 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: blkmtd.c,v 1.17 2003/01/24 13:00:24 dwmw2 Exp $
-+ * $Id: blkmtd.c,v 1.20 2003/06/27 15:10:35 dwmw2 Exp $
- *
- * 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: doc2000.c,v 1.50 2002/12/10 15:05:42 gleixner Exp $
-+ * $Id: doc2000.c,v 1.58 2003/11/05 16:42:25 dwmw2 Exp $
- */
-
- #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: doc2001.c,v 1.38 2002/12/10 15:05:42 gleixner Exp $
-+ * $Id: doc2001.c,v 1.41 2003/06/11 09:45:19 dwmw2 Exp $
- */
-
- #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: doc2001plus.c,v 1.7 2003/07/11 07:36:22 dwmw2 Exp $
-+ *
-+ * 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: docecc.c,v 1.4 2001/10/02 15:05:13 dwmw2 Exp $
-+ * $Id: docecc.c,v 1.5 2003/05/21 15:15:06 dwmw2 Exp $
- *
- * 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: docprobe.c,v 1.33 2003/01/24 14:02:47 dwmw2 Exp $ */
-+/* $Id: docprobe.c,v 1.41 2003/12/03 10:19:57 dwmw2 Exp $ */
-
-
-
-@@ -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: lart.c,v 1.2 2001/10/02 15:05:13 dwmw2 Exp $
-+ * $Id: lart.c,v 1.5 2003/05/20 21:03:07 dwmw2 Exp $
- *
- * 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: ms02-nv.c,v 1.2 2003/01/24 14:05:17 dwmw2 Exp $
-+ * $Id: ms02-nv.c,v 1.6 2003/08/19 09:25:36 dwmw2 Exp $
- */
-
- #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: mtdram.c,v 1.29 2002/10/21 13:40:06 jocke Exp $
-+ * $Id: mtdram.c,v 1.32 2003/05/21 15:15:07 dwmw2 Exp $
- * 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: phram.c,v 1.1 2003/08/21 17:52:30 joern Exp $
-+ *
-+ * 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: pmc551.c,v 1.22 2003/01/24 13:34:30 dwmw2 Exp $
-+ * $Id: pmc551.c,v 1.25 2003/06/23 12:24:01 dwmw2 Exp $
- *
- * 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: slram.c,v 1.28 2003/01/24 13:35:34 dwmw2 Exp $
-+ $Id: slram.c,v 1.30 2003/05/20 21:03:08 dwmw2 Exp $
-
- 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: ftl.c,v 1.45 2003/01/24 23:31:27 dwmw2 Exp $
-+ * $Id: ftl.c,v 1.52 2003/08/11 09:00:44 dwmw2 Exp $
- *
- * 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: ftl.c,v 1.52 2003/08/11 09:00:44 dwmw2 Exp $\n");
-
-- DEBUG(0, "$Id: ftl.c,v 1.45 2003/01/24 23:31:27 dwmw2 Exp $\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: inftlcore.c,v 1.14 2003/06/26 08:28:26 dwmw2 Exp $
-+ *
-+ * 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: 1.14 $, "
-+ "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: inftlmount.c,v 1.12 2003/06/26 07:31:36 dwmw2 Exp $
-+ *
-+ * 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: 1.12 $";
-+
-+/*
-+ * 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: Config.in,v 1.43 2003/01/24 14:26:38 dwmw2 Exp $
-+# $Id: Config.in,v 1.63 2003/11/26 21:26:09 dsaxena Exp $
-
- 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: Makefile,v 1.37 2003/01/24 14:26:38 dwmw2 Exp $
-+# $Id: Makefile.common,v 1.8 2003/11/26 21:26:09 dsaxena Exp $
-
--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: amd76xrom.c,v 1.1 2002/10/18 22:45:48 eric Exp $
-+ * $Id: amd76xrom.c,v 1.9 2003/10/23 23:10:59 thayne Exp $
- */
-
- #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: arctic-mtd.c,v 1.10 2003/06/02 16:37:59 trini Exp $
-+ *
-+ * 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: autcpu12-nvram.c,v 1.1 2002/02/22 09:30:24 gleixner Exp $
-+ * $Id: autcpu12-nvram.c,v 1.5 2003/05/21 12:45:18 dwmw2 Exp $
- *
- * 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: beech-mtd.c,v 1.7 2003/05/21 12:45:18 dwmw2 Exp $
-+ *
-+ * 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: cdb89712.c,v 1.3 2001/10/02 15:14:43 rmk Exp $
-+ * $Id: cdb89712.c,v 1.7 2003/05/21 12:45:18 dwmw2 Exp $
- */
-
- #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: ceiva.c,v 1.2 2002/10/14 12:50:22 rmk Exp $
-+ * $Id: ceiva.c,v 1.8 2003/05/21 12:45:18 dwmw2 Exp $
- */
-
- #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: cfi_flagadm.c,v 1.7 2001/10/02 15:05:13 dwmw2 Exp $
-+ * $Id: cfi_flagadm.c,v 1.11 2003/05/21 12:45:18 dwmw2 Exp $
- *
- * 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: cstm_mips_ixx.c,v 1.5 2001/10/02 15:05:14 dwmw2 Exp $
-+ * $Id: cstm_mips_ixx.c,v 1.9 2003/05/21 12:45:18 dwmw2 Exp $
- *
- * 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: dbox2-flash.c,v 1.4 2001/10/02 15:05:14 dwmw2 Exp $
-+ * $Id: dbox2-flash.c,v 1.9 2003/05/21 12:45:18 dwmw2 Exp $
- *
-- * 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: dc21285.c,v 1.9 2002/10/14 12:22:10 rmk Exp $
-+ * $Id: dc21285.c,v 1.15 2003/05/21 12:45:18 dwmw2 Exp $
- */
- #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: dilnetpc.c,v 1.8 2002/03/12 13:07:26 rkaiser Exp $
-+ * $Id: dilnetpc.c,v 1.12 2003/05/21 12:45:18 dwmw2 Exp $
- *
- * 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: ebony.c,v 1.8 2003/06/23 11:48:18 dwmw2 Exp $
-+ *
-+ * 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: edb7312.c,v 1.2 2002/09/05 05:11:24 acurtis Exp $
-+ * $Id: edb7312.c,v 1.9 2003/06/23 11:48:18 dwmw2 Exp $
- *
- * 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: elan-104nc.c,v 1.13 2002/02/13 15:30:20 dwmw2 Exp $
-+ $Id: elan-104nc.c,v 1.18 2003/06/23 07:37:02 dwmw2 Exp $
-
- 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: epxa10db-flash.c,v 1.4 2002/08/22 10:46:19 cdavies Exp $
-+ * $Id: epxa10db-flash.c,v 1.10 2003/05/21 12:45:18 dwmw2 Exp $
- *
- * 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: fortunet.c,v 1.2 2002/10/14 12:50:22 rmk Exp $
-+ * $Id: fortunet.c,v 1.6 2003/05/21 12:45:18 dwmw2 Exp $
- */
-
- #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: ichxrom.c,v 1.1 2003/10/27 19:49:23 thayne Exp $
-+ */
-+
-+#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: impa7.c,v 1.2 2002/09/05 05:11:24 acurtis Exp $
-+ * $Id: impa7.c,v 1.9 2003/06/23 11:47:43 dwmw2 Exp $
- *
- * 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: integrator-flash-v24.c,v 1.12 2003/10/11 09:43:58 rmk Exp $
-+
-+======================================================================*/
-+
-+#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: integrator-flash.c,v 1.7 2001/11/01 20:55:47 rmk Exp $
-+ $Id: integrator-flash.c,v 1.14 2003/10/11 10:00:31 rmk Exp $
-
- ======================================================================*/
-
-@@ -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: iq80310.c,v 1.9 2002/01/01 22:45:02 rmk Exp $
-+ * $Id: iq80310.c,v 1.17 2003/06/23 11:48:18 dwmw2 Exp $
- *
- * 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: ixp425.c,v 1.1 2003/11/26 21:26:09 dsaxena Exp $
-+ *
-+ * 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: l440gx.c,v 1.8 2002/01/10 20:27:40 eric Exp $
-+ * $Id: l440gx.c,v 1.12 2003/05/21 12:45:19 dwmw2 Exp $
- *
- * 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: lasat.c,v 1.6 2003/09/02 16:36:40 brm Exp $
- *
- */
-
- #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: lubbock-flash.c,v 1.9 2003/06/23 11:48:18 dwmw2 Exp $
-+ *
-+ * 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: map_funcs.c,v 1.3 2003/11/14 19:50:04 thayne Exp $
-+ *
-+ * 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: mbx860.c,v 1.1 2001/11/18 19:43:09 dwmw2 Exp $
-+ * $Id: mbx860.c,v 1.5 2003/05/21 12:45:19 dwmw2 Exp $
- *
- * 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: netsc520.c,v 1.5 2001/10/02 15:05:14 dwmw2 Exp $
-+ * $Id: netsc520.c,v 1.9 2003/05/21 12:45:19 dwmw2 Exp $
- *
- * 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: nettel.c,v 1.1 2002/08/08 06:30:13 gerg Exp $
-+ * $Id: nettel.c,v 1.4 2003/05/20 20:59:30 dwmw2 Exp $
- */
-
- /****************************************************************************/
-@@ -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: ocelot.c,v 1.6 2001/10/02 15:05:14 dwmw2 Exp $
-+ * $Id: ocelot.c,v 1.12 2003/05/21 12:45:19 dwmw2 Exp $
- *
- * 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: octagon-5066.c,v 1.20 2003/01/07 17:21:55 dwmw2 Exp $
-+// $Id: octagon-5066.c,v 1.24 2003/05/21 15:15:07 dwmw2 Exp $
- /* ######################################################################
-
- 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: omap-toto-flash.c,v 1.1 2003/10/21 13:55:21 dwmw2 Exp $
-+ */
-+
-+#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: pb1xxx-flash.c,v 1.4 2002/09/13 13:51:54 dwmw2 Exp $
-+ * $Id: pb1xxx-flash.c,v 1.10 2003/08/28 06:50:24 ppopov Exp $
- */
-
- #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: pci.c,v 1.2 2003/01/24 13:11:43 dwmw2 Exp $
-+ * $Id: pci.c,v 1.5 2003/05/20 20:59:31 dwmw2 Exp $
- *
- * 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: pcmciamtd.c,v 1.39 2003/01/06 17:51:38 spse Exp $
-+ * $Id: pcmciamtd.c,v 1.48 2003/06/24 07:14:38 spse Exp $
- *
- * 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: 1.39 $"
-+#define DRIVER_VERSION "$Revision: 1.48 $"
-
- /* 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: physmap.c,v 1.21 2002/09/05 05:12:54 acurtis Exp $
-+ * $Id: physmap.c,v 1.30 2003/11/11 19:05:18 jsun Exp $
- *
- * 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: pnc2000.c,v 1.10 2001/10/02 15:05:14 dwmw2 Exp $
-+ * $Id: pnc2000.c,v 1.14 2003/05/21 12:45:19 dwmw2 Exp $
- */
-
- #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,v 1.7 2003/11/21 23:09:52 trini Exp $
- *
-- * 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: rpxlite.c,v 1.15 2001/10/02 15:05:14 dwmw2 Exp $
-+ * $Id: rpxlite.c,v 1.19 2003/05/21 12:45:19 dwmw2 Exp $
- *
- * 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: sa1100-flash.c,v 1.29 2002/09/06 14:36:19 abz Exp $
-+ * $Id: sa1100-flash.c,v 1.38 2004/01/22 19:11:08 rmk Exp $
- */
-
- #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: sbc8240.c,v 1.2 2003/09/30 19:37:00 thayne Exp $
-+ *
-+ */
-+
-+/*
-+ * 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: sbc_gxx.c,v 1.21 2003/01/24 13:40:14 dwmw2 Exp $
-+ $Id: sbc_gxx.c,v 1.26 2003/05/26 08:50:36 dwmw2 Exp $
-
- 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: sc520cdp.c,v 1.11 2002/03/08 16:34:35 rkaiser Exp $
-+ * $Id: sc520cdp.c,v 1.15 2003/05/21 12:45:20 dwmw2 Exp $
- *
- *
- * 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: scb2_flash.c,v 1.2 2003/01/24 13:09:56 dwmw2 Exp $
-+ * $Id: scb2_flash.c,v 1.6 2003/05/21 12:45:20 dwmw2 Exp $
- * 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: scx200_docflash.c,v 1.1 2003/01/24 13:20:40 dwmw2 Exp $
-+ $Id: scx200_docflash.c,v 1.5 2003/05/21 12:45:20 dwmw2 Exp $
-
- 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: solutionengine.c,v 1.4 2001/11/07 01:20:59 jsiegel Exp $
-+ * $Id: solutionengine.c,v 1.10 2003/05/21 12:45:20 dwmw2 Exp $
- *
- * 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: sun_uflash.c,v 1.4 2001/10/02 15:05:14 dwmw2 Exp $
-+/* $Id: sun_uflash.c,v 1.7 2003/05/20 20:59:32 dwmw2 Exp $
- *
- * 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: tqm8xxl.c,v 1.4 2002/06/20 13:41:20 mag Exp $
-+ * $Id: tqm8xxl.c,v 1.9 2003/06/23 11:48:18 dwmw2 Exp $
- *
- * 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: tsunami_flash.c,v 1.1 2002/01/10 22:59:13 eric Exp $
-+ * $Id: tsunami_flash.c,v 1.6 2003/05/21 15:15:08 dwmw2 Exp $
- */
- #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: uclinux.c,v 1.2 2002/08/07 00:43:45 gerg Exp $
-+ * $Id: uclinux.c,v 1.5 2003/05/20 20:59:32 dwmw2 Exp $
- */
-
- /****************************************************************************/
-@@ -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: vmax301.c,v 1.24 2001/10/02 15:05:14 dwmw2 Exp $
-+// $Id: vmax301.c,v 1.28 2003/05/21 15:15:08 dwmw2 Exp $
- /* ######################################################################
-
- 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: mtd_blkdevs-24.c,v 1.15 2003/10/10 08:55:03 dwmw2 Exp $
-+ *
-+ * (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: mtd_blkdevs.c,v 1.19 2003/11/07 09:52:46 dwmw2 Exp $
-+ *
-+ * (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: mtdblock.c,v 1.51 2001/11/20 11:42:33 dwmw2 Exp $
-+ * $Id: mtdblock.c,v 1.64 2003/10/04 17:14:14 dwmw2 Exp $
- *
-- * 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: mtdblock_ro.c,v 1.12 2001/11/20 11:42:33 dwmw2 Exp $
-+ * $Id: mtdblock_ro.c,v 1.18 2003/06/23 12:00:08 dwmw2 Exp $
- *
-- * 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: mtdchar.c,v 1.49 2003/01/24 12:02:58 dwmw2 Exp $
-+ * $Id: mtdchar.c,v 1.56 2003/11/14 19:50:03 thayne Exp $
- *
- * 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: mtdconcat.c,v 1.3 2002/05/21 21:04:25 dwmw2 Exp $
-+ * $Id: mtdconcat.c,v 1.8 2003/06/30 11:01:26 dwmw2 Exp $
- */
-
- #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: mtdcore.c,v 1.34 2003/01/24 23:32:25 dwmw2 Exp $
-+ * $Id: mtdcore.c,v 1.39 2003/05/21 15:15:03 dwmw2 Exp $
- *
- * 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: mtdpart.c,v 1.32 2002/10/21 13:40:05 jocke Exp $
-+ * $Id: mtdpart.c,v 1.42 2003/07/09 11:19:01 dwmw2 Exp $
- *
- * 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: Config.in,v 1.11 2002/12/01 13:23:05 gleixner Exp $
-+# $Id: Config.in,v 1.14 2003/11/04 22:59:11 ahennessy Exp $
-
- 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: Makefile,v 1.10 2002/12/01 13:23:05 gleixner Exp $
-+# $Id: Makefile.common,v 1.4 2003/11/04 22:59:11 ahennessy Exp $
-
-+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: autcpu12.c,v 1.6 2002/11/11 15:47:56 gleixner Exp $
-+ * $Id: autcpu12.c,v 1.13 2003/07/11 15:12:29 dwmw2 Exp $
- *
- * 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: diskonchip.c,v 1.8 2003/11/05 16:52:34 dwmw2 Exp $
-+ */
-+
-+#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: edb7312.c,v 1.3 2002/06/06 12:58:16 mag Exp $
-+ * $Id: edb7312.c,v 1.7 2003/07/11 15:12:29 dwmw2 Exp $
- *
- * 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: nand.c,v 1.36 2002/12/05 20:59:11 gleixner Exp $
-+ * 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: nand.c,v 1.60 2003/10/23 08:28:43 dwmw2 Exp $
- *
- * 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: nand_ecc.c,v 1.8 2002/09/16 09:19:53 dwmw2 Exp $
-+ * $Id: nand_ecc.c,v 1.10 2003/07/01 23:31:15 dwmw2 Exp $
- *
- * 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: nand_ids.c,v 1.1 2002/12/02 22:06:04 gleixner Exp $
-+ * $Id: nand_ids.c,v 1.4 2003/05/21 15:15:08 dwmw2 Exp $
- *
- * 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: spia.c,v 1.16 2002/03/05 13:50:47 dwmw2 Exp $
-+ * $Id: spia.c,v 1.21 2003/07/11 15:12:29 dwmw2 Exp $
- *
- * 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: toto.c,v 1.2 2003/10/21 10:04:58 dwmw2 Exp $
-+ */
-+
-+#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: tx4925ndfmc.c,v 1.1 2003/11/04 22:59:11 ahennessy Exp $
-+ *
-+ * 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: tx4938ndfmc.c,v 1.1 2003/11/04 22:59:11 ahennessy Exp $
-+ *
-+ * 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: nftlcore.c,v 1.87 2002/09/13 14:35:33 dwmw2 Exp $ */
-+/* $Id: nftlcore.c,v 1.94 2003/06/23 12:00:08 dwmw2 Exp $ */
-
- /*
- 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: 1.87 $, 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: 1.94 $, 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: nftlmount.c,v 1.31 2002/11/15 16:34:43 dwmw2 Exp $
-+ * $Id: nftlmount.c,v 1.34 2003/05/21 10:54:10 dwmw2 Exp $
- *
- * 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: 1.31 $";
-+char nftlmountrev[]="$Revision: 1.34 $";
-
- /* 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: redboot.c,v 1.6 2001/10/25 09:16:06 dwmw2 Exp $
-+ * $Id: redboot.c,v 1.12 2003/06/25 16:08:10 dwmw2 Exp $
- *
- * 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: Makefile,v 1.25.2.1 2002/10/11 09:04:44 dwmw2 Exp $
-+# $Id: Makefile.common,v 1.1 2003/05/27 09:34:41 dwmw2 Exp $
- #
- # 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: background.c,v 1.16 2001/10/08 09:22:38 dwmw2 Exp $
-+ * $Id: background.c,v 1.47 2003/11/26 15:30:58 dwmw2 Exp $
- *
- */
-
- #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: build.c,v 1.16.2.3 2003/04/30 09:43:32 dwmw2 Exp $
-+ * $Id: build.c,v 1.55 2003/10/28 17:02:44 dwmw2 Exp $
- *
- */
-
- #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: compr.c,v 1.17 2001/09/23 09:56:46 dwmw2 Exp $
-+ * $Id: compr.c,v 1.33 2003/11/28 17:22:54 dwmw2 Exp $
- *
- */
-
- #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: compr_rtime.c,v 1.5 2001/03/15 15:38:23 dwmw2 Exp $
-+ * $Id: compr_rtime.c,v 1.11 2003/10/04 08:33:06 dwmw2 Exp $
- *
- *
- * 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: compr_rubin.c,v 1.13 2001/09/23 10:06:05 rmk Exp $
-+ * $Id: compr_rubin.c,v 1.17 2002/05/20 14:56:37 dwmw2 Exp $
- *
- */
-
-@@ -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: compr_rubin.h,v 1.5 2001/02/26 13:50:01 dwmw2 Exp $ */
-+/* $Id: compr_rubin.h,v 1.6 2002/01/25 01:49:26 dwmw2 Exp $ */
-
- #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: compr_zlib.c,v 1.8.2.1 2002/10/11 09:04:44 dwmw2 Exp $
-+ * $Id: compr_zlib.c,v 1.25 2003/12/03 09:25:43 dwmw2 Exp $
- *
- */
-
--#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: comprtest.c,v 1.4 2001/02/21 14:03:20 dwmw2 Exp $ */
-+/* $Id: comprtest.c,v 1.5 2002/01/03 15:20:44 dwmw2 Exp $ */
-
- #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: crc32.c,v 1.4 2002/01/03 15:20:44 dwmw2 Exp $ */
-+
-+#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: crc32.h,v 1.4 2002/01/03 15:20:44 dwmw2 Exp $ */
-+
-+#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: dir.c,v 1.45.2.8 2003/11/02 13:51:17 dwmw2 Exp $
-+ * $Id: dir.c,v 1.82 2003/10/11 11:47:23 dwmw2 Exp $
- *
- */
-
- #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: erase.c,v 1.24.2.1 2003/11/02 13:51:17 dwmw2 Exp $
-+ * $Id: erase.c,v 1.58 2003/11/26 13:02:46 dwmw2 Exp $
- *
- */
-+
- #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: file.c,v 1.58.2.7 2003/11/02 13:51:17 dwmw2 Exp $
-+ * $Id: file.c,v 1.97 2003/11/02 08:52:35 dwmw2 Exp $
- *
- */
-
-+#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: fs.c,v 1.37 2004/01/26 12:34:21 dwmw2 Exp $
-+ *
-+ */
-+
-+#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: gc.c,v 1.52.2.7 2003/11/02 13:54:20 dwmw2 Exp $
-+ * $Id: gc.c,v 1.132 2003/12/01 11:32:11 dwmw2 Exp $
- *
- */
-
- #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: ioctl.c,v 1.5 2001/03/15 15:38:24 dwmw2 Exp $
-+ * $Id: ioctl.c,v 1.8 2003/10/28 16:16:28 dwmw2 Exp $
- *
- */
-
-@@ -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: malloc.c,v 1.16 2001/03/15 15:38:24 dwmw2 Exp $
-+ * $Id: malloc.c,v 1.27 2003/10/28 17:14:58 dwmw2 Exp $
- *
- */
-
-@@ -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: nodelist.c,v 1.30.2.6 2003/02/24 21:49:33 dwmw2 Exp $
-+ * $Id: nodelist.c,v 1.86 2003/10/31 15:37:51 dwmw2 Exp $
- *
- */
-
- #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: nodelist.h,v 1.46.2.5 2003/11/02 13:54:20 dwmw2 Exp $
-+ * $Id: nodelist.h,v 1.115 2003/11/26 15:30:58 dwmw2 Exp $
- *
- */
-
-+#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: nodemgmt.c,v 1.45.2.1 2002/02/23 14:13:34 dwmw2 Exp $
-+ * $Id: nodemgmt.c,v 1.107 2003/11/26 15:30:58 dwmw2 Exp $
- *
- */
-
- #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: os-linux.h,v 1.41 2003/11/26 13:02:46 dwmw2 Exp $
-+ *
-+ */
-+
-+#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: pushpull.h,v 1.5 2001/09/23 10:04:15 rmk Exp $
-+ * $Id: pushpull.h,v 1.9 2003/10/04 08:33:06 dwmw2 Exp $
- *
- */
-
- #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: rbtree.c,v 1.3 2003/10/16 08:02:19 dwmw2 Exp $
-+*/
-+
-+#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: read.c,v 1.13.2.2 2003/11/02 13:51:18 dwmw2 Exp $
-+ * $Id: read.c,v 1.34 2003/10/04 08:33:06 dwmw2 Exp $
- *
- */
-
- #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: readinode.c,v 1.58.2.8 2003/11/02 13:54:20 dwmw2 Exp $
-+ * $Id: readinode.c,v 1.113 2003/11/03 13:20:33 dwmw2 Exp $
- *
- */
-
--/* 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: scan.c,v 1.51.2.4 2003/11/02 13:51:18 dwmw2 Exp $
-+ * $Id: scan.c,v 1.106 2003/10/28 17:01:13 dwmw2 Exp $
- *
- */
- #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: super-v24.c,v 1.75 2003/10/06 12:52:29 dwmw2 Exp $
-+ *
-+ */
-+
-+#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: super.c,v 1.48.2.3 2002/10/11 09:04:44 dwmw2 Exp $
-+ * $Id: super.c,v 1.90 2003/10/11 11:47:23 dwmw2 Exp $
- *
- */
-
- #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: symlink.c,v 1.5.2.1 2002/01/15 10:39:06 dwmw2 Exp $
-+ * $Id: symlink.c,v 1.12 2003/10/04 08:33:07 dwmw2 Exp $
- *
- */
-
-@@ -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: wbuf.c,v 1.58 2003/11/02 09:51:10 dwmw2 Exp $
-+ *
-+ */
-+
-+#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: write.c,v 1.30.2.2 2003/11/02 13:51:18 dwmw2 Exp $
-+ * $Id: write.c,v 1.80 2004/01/27 13:21:50 dwmw2 Exp $
- *
- */
-
- #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: writev.c,v 1.4 2003/10/04 08:33:07 dwmw2 Exp $
-+ *
-+ */
-+
-+#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: jffs2.h,v 1.19 2001/10/09 13:20:23 dwmw2 Exp $
-+ * $Id: jffs2.h,v 1.31 2003/10/04 08:33:05 dwmw2 Exp $
- *
- */
-
- #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: jffs2_fs_i.h,v 1.8 2001/04/18 13:05:28 dwmw2 Exp $ */
-+/* $Id: jffs2_fs_i.h,v 1.16 2003/01/09 14:03:21 dwmw2 Exp $ */
-
- #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: jffs2_fs_sb.h,v 1.16.2.1 2002/02/23 14:13:34 dwmw2 Exp $ */
-+/* $Id: jffs2_fs_sb.h,v 1.45 2003/10/08 11:46:27 dwmw2 Exp $ */
-
- #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: blktrans.h,v 1.5 2003/06/23 12:00:08 dwmw2 Exp $
-+ *
-+ * (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: cfi.h,v 1.32 2002/09/05 05:15:32 acurtis Exp $
-+ * $Id: cfi.h,v 1.38 2003/11/08 00:51:21 dsaxena Exp $
- */
-
- #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: compatmac.h,v 1.45 2003/01/24 15:50:57 dwmw2 Exp $
-+ * $Id: compatmac.h,v 1.63 2003/11/14 19:50:04 thayne Exp $
- *
- * 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: doc2000.h,v 1.15 2001/09/19 00:22:15 dwmw2 Exp $ */
-+/*
-+ * 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: doc2000.h,v 1.22 2003/11/05 10:51:36 dwmw2 Exp $
-+ *
-+ * 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: flashchip.h,v 1.8 2002/10/21 13:20:52 jocke Exp $
-+ * $Id: flashchip.h,v 1.10 2004/01/27 10:16:20 dvrabel Exp $
- *
- */
-
-@@ -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: gen_probe.h,v 1.1 2001/09/02 18:50:13 dwmw2 Exp $
-+ * $Id: gen_probe.h,v 1.2 2003/11/08 00:51:21 dsaxena Exp $
- */
-
- #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: inftl.h,v 1.4 2003/06/29 16:15:46 dwmw2 Exp $
-+ */
-+
-+#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: jedec.h,v 1.2 2001/11/06 14:37:36 dwmw2 Exp $
-+ * $Id: jedec.h,v 1.3 2003/05/21 11:51:01 dwmw2 Exp $
- */
-
- #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: map.h,v 1.29 2002/10/21 13:20:52 jocke Exp $ */
-+/* $Id: map.h,v 1.34 2003/05/28 12:42:22 dwmw2 Exp $ */
-
- #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: mtd.h,v 1.38 2003/01/12 16:30:19 spse Exp $ */
-+/*
-+ * $Id: mtd.h,v 1.46 2003/07/11 07:36:21 dwmw2 Exp $
-+ *
-+ * 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: nand.h,v 1.19 2002/12/02 21:48:17 gleixner Exp $
-+ * $Id: nand.h,v 1.31 2003/07/11 15:07:02 dwmw2 Exp $
- *
- * 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: nand_ecc.h,v 1.1 2000/10/12 00:57:15 sjhill Exp $
-+ * $Id: nand_ecc.h,v 1.3 2003/07/01 23:31:15 dwmw2 Exp $
- *
- * 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: nftl.h,v 1.11 2002/06/18 13:54:24 dwmw2 Exp $ */
-+/*
-+ * $Id: nftl.h,v 1.13 2003/05/23 11:25:02 dwmw2 Exp $
-+ *
-+ * (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: partitions.h,v 1.8 2002/03/08 16:34:36 rkaiser Exp $
-+ * $Id: partitions.h,v 1.15 2003/07/09 11:15:43 dwmw2 Exp $
- */
-
- #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: rbtree.h,v 1.3 2003/01/14 13:56:05 dwmw2 Exp $
-+ */
-+
-+#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: suspend.h,v 1.1 2003/10/13 20:56:47 dwmw2 Exp $ */
-+
-+#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: workqueue.h,v 1.1 2002/11/11 16:39:10 dwmw2 Exp $
-+ */
-+
-+#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__ */
diff --git a/recipes/linux/linux-mtx-1-2.4.27/02-mtd-mtx-1-map.diff b/recipes/linux/linux-mtx-1-2.4.27/02-mtd-mtx-1-map.diff
deleted file mode 100644
index ba24bb1381..0000000000
--- a/recipes/linux/linux-mtx-1-2.4.27/02-mtd-mtx-1-map.diff
+++ /dev/null
@@ -1,248 +0,0 @@
-diff -Nurb linux/drivers/mtd/maps/Config.in linux-mips-2.4.24-pre2+mtd-2004-01-27+mtx-map/drivers/mtd/maps/Config.in
---- linux/drivers/mtd/maps/Config.in 2004-11-17 18:17:59.049312400 +0100
-+++ linux-mips-2.4.24-pre2+mtd-2004-01-27+mtx-map/drivers/mtd/maps/Config.in 2004-11-17 18:12:26.000000000 +0100
-@@ -80,6 +80,7 @@
- bool ' Db1x00 boot flash device' CONFIG_MTD_DB1X00_BOOT
- bool ' Db1x00 user flash device (2nd bank)' CONFIG_MTD_DB1X00_USER
- fi
-+ dep_tristate ' MTX-1 flash device' CONFIG_MTD_MTX1 $CONFIG_MIPS_MTX1
- 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
-diff -Nurb linux/drivers/mtd/maps/Makefile linux-mips-2.4.24-pre2+mtd-2004-01-27+mtx-map/drivers/mtd/maps/Makefile
---- linux/drivers/mtd/maps/Makefile 2004-11-17 18:17:59.051312096 +0100
-+++ linux-mips-2.4.24-pre2+mtd-2004-01-27+mtx-map/drivers/mtd/maps/Makefile 2004-11-17 18:12:26.000000000 +0100
-@@ -49,6 +49,7 @@
- obj-$(CONFIG_MTD_PCI) += pci.o
- obj-$(CONFIG_MTD_PB1XXX) += pb1xxx-flash.o
- obj-$(CONFIG_MTD_DB1X00) += db1x00-flash.o
-+obj-$(CONFIG_MTD_MTX1) += mtx-1.o
- obj-$(CONFIG_MTD_LASAT) += lasat.o
- obj-$(CONFIG_MTD_AUTCPU12) += autcpu12-nvram.o
- obj-$(CONFIG_MTD_EDB7312) += edb7312.o
-diff -Nurb linux/drivers/mtd/maps/mtx-1.c linux-mips-2.4.24-pre2+mtd-2004-01-27+mtx-map/drivers/mtd/maps/mtx-1.c
---- linux/drivers/mtd/maps/mtx-1.c 2004-11-17 18:17:02.689880336 +0100
-+++ linux-mips-2.4.24-pre2+mtd-2004-01-27+mtx-map/drivers/mtd/maps/mtx-1.c 2004-11-17 18:12:26.000000000 +0100
-@@ -1,166 +1,78 @@
- /*
- * Flash memory access on 4G Systems MTX-1 board
- *
-- * (C) 2003 Pete Popov <ppopov@mvista.com>
-- * Bruno Randolf <bruno.randolf@4g-systems.de>
-+ * (C) Bruno Randolf (4G Systeme GmbH) <bruno.randolf@4g-systems.biz>
- */
-
- #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>
- #include <linux/mtd/partitions.h>
-
- #include <asm/io.h>
--#include <asm/au1000.h>
-
--#ifdef DEBUG_RW
--#define DBG(x...) printk(x)
--#else
--#define DBG(x...)
--#endif
--
--#ifdef CONFIG_MIPS_MTX1
- #define WINDOW_ADDR 0x1E000000
- #define WINDOW_SIZE 0x2000000
--#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);
--}
--
--
-+#define BUSWIDTH 4
-
- static struct map_info mtx1_map = {
-- name: "MTX-1 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,
-+ .name = "MTX-1 flash",
-+ .size = WINDOW_SIZE,
-+ .buswidth = BUSWIDTH,
-+ .phys = WINDOW_ADDR
- };
-
--
--static unsigned long flash_size = 0x01000000;
--static unsigned char flash_buswidth = 4;
- static struct mtd_partition mtx1_partitions[] = {
- {
-- name: "user fs",
-- size: 0x1c00000,
-- offset: 0,
-+ .name = "user fs",
-+ .size = 0x1c00000,
-+ .offset = 0,
- },{
-- name: "yamon",
-- size: 0x0100000,
-- offset: MTDPART_OFS_APPEND,
-- mask_flags: MTD_WRITEABLE
-+ .name = "yamon",
-+ .size = 0x0100000,
-+ .offset = MTDPART_OFS_APPEND,
-+ .mask_flags = MTD_WRITEABLE /* force read-only */
- },{
-- name: "raw kernel",
-- size: 0x02c0000,
-- offset: MTDPART_OFS_APPEND,
-+ .name = "raw kernel",
-+ .size = 0x02c0000,
-+ .offset = MTDPART_OFS_APPEND,
- },{
-- name: "yamon env vars",
-- size: 0x0040000,
-- offset: MTDPART_OFS_APPEND,
-- mask_flags: MTD_WRITEABLE
-+ .name = "yamon environment",
-+ .size = 0x0040000,
-+ .offset = MTDPART_OFS_APPEND,
-+ .mask_flags = MTD_WRITEABLE /* force read-only */
- }
- };
-
--
--#define NB_OF(x) (sizeof(x)/sizeof(x[0]))
--
--static struct mtd_partition *parsed_parts;
- static struct mtd_info *mymtd;
-
- int __init mtx1_mtd_init(void)
- {
-- struct mtd_partition *parts;
-- int nb_parts = 0;
-- char *part_type;
-+ printk(KERN_NOTICE "MTX-1 flash: probing %d-bit flash bus at %x\n",
-+ mtx1_map.buswidth*8, WINDOW_ADDR);
-
-- /* Default flash buswidth */
-- mtx1_map.buswidth = flash_buswidth;
-+ mtx1_map.virt = (unsigned long)ioremap(WINDOW_ADDR, WINDOW_SIZE);
-+ if (!mtx1_map.virt) {
-+ printk("mtx_mtd_init: failed to ioremap\n");
-+ return -EIO;
-+ }
-+
-+ simple_map_init(&mtx1_map);
-
-- /*
-- * Static partition definition selection
-- */
-- part_type = "static";
-- parts = mtx1_partitions;
-- nb_parts = NB_OF(mtx1_partitions);
-- mtx1_map.size = flash_size;
--
-- /*
-- * Now let's probe for the actual flash. Do it here since
-- * specific machine settings might have been set above.
-- */
-- printk(KERN_NOTICE "MTX-1 flash: probing %d-bit flash bus\n",
-- mtx1_map.buswidth*8);
-- mtx1_map.map_priv_1 =
-- (unsigned long)ioremap(WINDOW_ADDR, WINDOW_SIZE);
- mymtd = do_map_probe("cfi_probe", &mtx1_map);
-- if (!mymtd) return -ENXIO;
-- mymtd->module = THIS_MODULE;
-+ if (!mymtd) {
-+ iounmap(mtx1_map.virt);
-+ return -ENXIO;
-+ }
-+
-+ mymtd->owner = THIS_MODULE;
-
-- add_mtd_partitions(mymtd, parts, nb_parts);
-- return 0;
-+ return add_mtd_partitions(mymtd, mtx1_partitions, ARRAY_SIZE(mtx1_partitions));
- }
-
- static void __exit mtx1_mtd_cleanup(void)
-@@ -168,14 +80,14 @@
- if (mymtd) {
- del_mtd_partitions(mymtd);
- map_destroy(mymtd);
-- if (parsed_parts)
-- kfree(parsed_parts);
- }
-+ if (mtx1_map.virt)
-+ iounmap(mtx1_map.virt);
- }
-
- module_init(mtx1_mtd_init);
- module_exit(mtx1_mtd_cleanup);
-
--MODULE_AUTHOR("Pete Popov");
-+MODULE_AUTHOR("Bruno Randolf <bruno.randolf@4g-systems.biz>");
- MODULE_DESCRIPTION("MTX-1 CFI map driver");
- MODULE_LICENSE("GPL");
-
diff --git a/recipes/linux/linux-mtx-1-2.4.27/03-mtd-erase-compiler-bug.diff b/recipes/linux/linux-mtx-1-2.4.27/03-mtd-erase-compiler-bug.diff
deleted file mode 100644
index 9e310bf327..0000000000
--- a/recipes/linux/linux-mtx-1-2.4.27/03-mtd-erase-compiler-bug.diff
+++ /dev/null
@@ -1,21 +0,0 @@
---- linux-mips-2.4.24-pre2+mtd-2004-01-27/fs/jffs2/erase.c 2004-11-17 18:17:59.000000000 +0100
-+++ linux/fs/jffs2/erase.c 2004-11-17 18:44:52.260067088 +0100
-@@ -365,11 +365,13 @@
- 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)
-- };
-+ /* compiler workaround, structure was not initialized before
-+ on mipsel cross compilers
-+ fix by Eugene.Wisor@flukenetworks.com */
-+ struct jffs2_unknown_node marker;
-+ marker.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
-+ marker.nodetype = cpu_to_je16(JFFS2_NODETYPE_CLEANMARKER);
-+ marker.totlen = cpu_to_je32(c->cleanmarker_size);
-
- marker.hdr_crc = cpu_to_je32(crc32(0, &marker, sizeof(struct jffs2_unknown_node)-4));
-
diff --git a/recipes/linux/linux-mtx-1-2.4.27/04-mtx-1-board-reset.diff b/recipes/linux/linux-mtx-1-2.4.27/04-mtx-1-board-reset.diff
deleted file mode 100644
index 9a13c2a403..0000000000
--- a/recipes/linux/linux-mtx-1-2.4.27/04-mtx-1-board-reset.diff
+++ /dev/null
@@ -1,15 +0,0 @@
---- linux/arch/mips/au1000/mtx-1/board_setup.c.orig 2004-10-13 19:05:15.340583632 +0200
-+++ linux/arch/mips/au1000/mtx-1/board_setup.c 2004-10-13 19:01:03.402883984 +0200
-@@ -48,6 +48,12 @@
-
- extern struct rtc_ops no_rtc_ops;
-
-+void board_reset (void)
-+{
-+ /* Hit BCSR.SYSTEM_CONTROL[SW_RST] */
-+ au_writel(0x00000000, 0xAE00001C);
-+}
-+
- void __init board_setup(void)
- {
- rtc_ops = &no_rtc_ops;
diff --git a/recipes/linux/linux-mtx-1-2.4.27/05-mtx-1-pci-irq.diff b/recipes/linux/linux-mtx-1-2.4.27/05-mtx-1-pci-irq.diff
deleted file mode 100644
index 4fc6b9e667..0000000000
--- a/recipes/linux/linux-mtx-1-2.4.27/05-mtx-1-pci-irq.diff
+++ /dev/null
@@ -1,18 +0,0 @@
-diff -Nurb linux-mips-2.4.27/arch/mips/au1000/mtx-1/irqmap.c linux/arch/mips/au1000/mtx-1/irqmap.c
---- linux-mips-2.4.27/arch/mips/au1000/mtx-1/irqmap.c 2004-04-02 11:04:00.000000000 +0200
-+++ linux/arch/mips/au1000/mtx-1/irqmap.c 2004-11-22 14:15:56.000000000 +0100
-@@ -72,10 +72,10 @@
- * A B C D
- */
- {
-- {INTA, INTB, INTC, INTD}, /* IDSEL 0 */
-- {INTA, INTB, INTC, INTD}, /* IDSEL 1 */
-- {INTA, INTB, INTC, INTD}, /* IDSEL 2 */
-- {INTA, INTB, INTC, INTD}, /* IDSEL 3 */
-+ {INTA, INTB, INTX, INTX}, /* IDSEL 0 */
-+ {INTB, INTA, INTX, INTX}, /* IDSEL 1 */
-+ {INTC, INTD, INTX, INTX}, /* IDSEL 2 */
-+ {INTD, INTC, INTX, INTX}, /* IDSEL 3 */
- };
- const long min_idsel = 0, max_idsel = 3, irqs_per_slot = 4;
- return PCI_IRQ_TABLE_LOOKUP;
diff --git a/recipes/linux/linux-mtx-1-2.4.27/06-zboot-2.4.26.patch b/recipes/linux/linux-mtx-1-2.4.27/06-zboot-2.4.26.patch
deleted file mode 100644
index f4a8754228..0000000000
--- a/recipes/linux/linux-mtx-1-2.4.27/06-zboot-2.4.26.patch
+++ /dev/null
@@ -1,5317 +0,0 @@
-diff -Naru linux/arch/mips/Makefile linux.spi/arch/mips/Makefile
---- linux/arch/mips/Makefile 2004-05-06 15:23:41.000000000 -0400
-+++ linux.spi/arch/mips/Makefile 2004-05-11 23:19:24.000000000 -0400
-@@ -17,7 +17,7 @@
- # Select the object file format to substitute into the linker script.
- #
- ifdef CONFIG_CPU_LITTLE_ENDIAN
--tool-prefix = mipsel-linux-
-+tool-prefix = mipsel-nylon-linux-
- ld-emul = elf32ltsmip
- else
- tool-prefix = mips-linux-
-@@ -29,6 +29,8 @@
- endif
-
- MAKEBOOT = $(MAKE) -C arch/$(ARCH)/boot
-+MAKEZBOOT = $(MAKE) -C arch/$(ARCH)/zboot
-+BOOT_TARGETS = zImage zImage.initrd zImage.flash
-
- check_gcc = $(shell if $(CC) $(1) -S -o /dev/null -xc /dev/null > /dev/null 2>&1; then echo "$(1)"; else echo "$(2)"; fi)
-
-@@ -757,12 +749,16 @@
-
- vmlinux.ecoff: vmlinux
- @$(MAKEBOOT) $@
-+
-+$(BOOT_TARGETS): vmlinux
-+ @$(MAKEZBOOT) $@
-
- vmlinux.srec: vmlinux
- @$(MAKEBOOT) $@
-
- archclean:
- @$(MAKEBOOT) clean
-+ @$(MAKEZBOOT) clean
- rm -f arch/$(ARCH)/ld.script
- $(MAKE) -C arch/$(ARCH)/tools clean
- $(MAKE) -C arch/mips/baget clean
-diff -Naru linux/arch/mips/zboot/common/au1k_uart.c linux.spi/arch/mips/zboot/common/au1k_uart.c
---- linux/arch/mips/zboot/common/au1k_uart.c 1969-12-31 19:00:00.000000000 -0500
-+++ linux.spi/arch/mips/zboot/common/au1k_uart.c 2004-05-11 23:19:24.000000000 -0400
-@@ -0,0 +1,103 @@
-+/*
-+ * BRIEF MODULE DESCRIPTION
-+ * Simple Au1000 uart routines.
-+ *
-+ * Copyright 2001 MontaVista Software Inc.
-+ * Author: MontaVista Software, Inc.
-+ * ppopov@mvista.com or source@mvista.com
-+ *
-+ * 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.
-+ */
-+#include <linux/config.h>
-+#include <asm/io.h>
-+#include <asm/au1000.h>
-+#include "ns16550.h"
-+
-+typedef unsigned char uint8;
-+typedef unsigned int uint32;
-+
-+#define UART16550_BAUD_2400 2400
-+#define UART16550_BAUD_4800 4800
-+#define UART16550_BAUD_9600 9600
-+#define UART16550_BAUD_19200 19200
-+#define UART16550_BAUD_38400 38400
-+#define UART16550_BAUD_57600 57600
-+#define UART16550_BAUD_115200 115200
-+
-+#define UART16550_PARITY_NONE 0
-+#define UART16550_PARITY_ODD 0x08
-+#define UART16550_PARITY_EVEN 0x18
-+#define UART16550_PARITY_MARK 0x28
-+#define UART16550_PARITY_SPACE 0x38
-+
-+#define UART16550_DATA_5BIT 0x0
-+#define UART16550_DATA_6BIT 0x1
-+#define UART16550_DATA_7BIT 0x2
-+#define UART16550_DATA_8BIT 0x3
-+
-+#define UART16550_STOP_1BIT 0x0
-+#define UART16550_STOP_2BIT 0x4
-+
-+/* It would be nice if we had a better way to do this.
-+ * It could be a variable defined in one of the board specific files.
-+ */
-+#undef UART_BASE
-+#ifdef CONFIG_COGENT_CSB250
-+#define UART_BASE UART3_ADDR
-+#else
-+#define UART_BASE UART0_ADDR
-+#endif
-+
-+/* memory-mapped read/write of the port */
-+#define UART16550_READ(y) (readl(UART_BASE + y) & 0xff)
-+#define UART16550_WRITE(y,z) (writel(z&0xff, UART_BASE + y))
-+
-+/*
-+ * We use uart 0, which is already initialized by
-+ * yamon.
-+ */
-+volatile struct NS16550 *
-+serial_init(int chan)
-+{
-+ volatile struct NS16550 *com_port;
-+ com_port = (struct NS16550 *) UART_BASE;
-+ return (com_port);
-+}
-+
-+void
-+serial_putc(volatile struct NS16550 *com_port, unsigned char c)
-+{
-+ while ((UART16550_READ(UART_LSR)&0x40) == 0);
-+ UART16550_WRITE(UART_TX, c);
-+}
-+
-+unsigned char
-+serial_getc(volatile struct NS16550 *com_port)
-+{
-+ while((UART16550_READ(UART_LSR) & 0x1) == 0);
-+ return UART16550_READ(UART_RX);
-+}
-+
-+int
-+serial_tstc(volatile struct NS16550 *com_port)
-+{
-+ return((UART16550_READ(UART_LSR) & LSR_DR) != 0);
-+}
-diff -Naru linux/arch/mips/zboot/common/ctype.c linux.spi/arch/mips/zboot/common/ctype.c
---- linux/arch/mips/zboot/common/ctype.c 1969-12-31 19:00:00.000000000 -0500
-+++ linux.spi/arch/mips/zboot/common/ctype.c 2004-05-11 23:19:24.000000000 -0400
-@@ -0,0 +1,35 @@
-+/*
-+ * linux/lib/ctype.c
-+ *
-+ * Copyright (C) 1991, 1992 Linus Torvalds
-+ */
-+
-+#include <linux/ctype.h>
-+
-+unsigned char _ctype[] = {
-+_C,_C,_C,_C,_C,_C,_C,_C, /* 0-7 */
-+_C,_C|_S,_C|_S,_C|_S,_C|_S,_C|_S,_C,_C, /* 8-15 */
-+_C,_C,_C,_C,_C,_C,_C,_C, /* 16-23 */
-+_C,_C,_C,_C,_C,_C,_C,_C, /* 24-31 */
-+_S|_SP,_P,_P,_P,_P,_P,_P,_P, /* 32-39 */
-+_P,_P,_P,_P,_P,_P,_P,_P, /* 40-47 */
-+_D,_D,_D,_D,_D,_D,_D,_D, /* 48-55 */
-+_D,_D,_P,_P,_P,_P,_P,_P, /* 56-63 */
-+_P,_U|_X,_U|_X,_U|_X,_U|_X,_U|_X,_U|_X,_U, /* 64-71 */
-+_U,_U,_U,_U,_U,_U,_U,_U, /* 72-79 */
-+_U,_U,_U,_U,_U,_U,_U,_U, /* 80-87 */
-+_U,_U,_U,_P,_P,_P,_P,_P, /* 88-95 */
-+_P,_L|_X,_L|_X,_L|_X,_L|_X,_L|_X,_L|_X,_L, /* 96-103 */
-+_L,_L,_L,_L,_L,_L,_L,_L, /* 104-111 */
-+_L,_L,_L,_L,_L,_L,_L,_L, /* 112-119 */
-+_L,_L,_L,_P,_P,_P,_P,_C, /* 120-127 */
-+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 128-143 */
-+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 144-159 */
-+_S|_SP,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P, /* 160-175 */
-+_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P, /* 176-191 */
-+_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U, /* 192-207 */
-+_U,_U,_U,_U,_U,_U,_U,_P,_U,_U,_U,_U,_U,_U,_U,_L, /* 208-223 */
-+_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L, /* 224-239 */
-+_L,_L,_L,_L,_L,_L,_L,_P,_L,_L,_L,_L,_L,_L,_L,_L}; /* 240-255 */
-+
-+
-diff -Naru linux/arch/mips/zboot/common/dummy.c linux.spi/arch/mips/zboot/common/dummy.c
---- linux/arch/mips/zboot/common/dummy.c 1969-12-31 19:00:00.000000000 -0500
-+++ linux.spi/arch/mips/zboot/common/dummy.c 2004-05-11 23:19:24.000000000 -0400
-@@ -0,0 +1,4 @@
-+int main(void)
-+{
-+ return 0;
-+}
-diff -Naru linux/arch/mips/zboot/common/Makefile linux.spi/arch/mips/zboot/common/Makefile
---- linux/arch/mips/zboot/common/Makefile 1969-12-31 19:00:00.000000000 -0500
-+++ linux.spi/arch/mips/zboot/common/Makefile 2004-05-11 23:19:24.000000000 -0400
-@@ -0,0 +1,27 @@
-+#
-+# arch/mips/zboot/common/Makefile
-+#
-+# This file is subject to the terms and conditions of the GNU General Public
-+# License. See the file "COPYING" in the main directory of this archive
-+# for more details.
-+#
-+# Tom Rini January 2001
-+#
-+
-+.c.s:
-+ $(CC) $(CFLAGS) -S -o $*.s $<
-+.s.o:
-+ $(AS) -o $*.o $<
-+.c.o:
-+ $(CC) $(CFLAGS) -c -o $*.o $<
-+.S.s:
-+ $(CPP) $(AFLAGS) -o $*.o $<
-+.S.o:
-+ $(CC) $(AFLAGS) -c -o $*.o $<
-+
-+clean:
-+ rm -rf *.o
-+
-+OBJCOPY_ARGS = -O elf32-tradlittlemips
-+
-+include $(TOPDIR)/Rules.make
-diff -Naru linux/arch/mips/zboot/common/misc-common.c linux.spi/arch/mips/zboot/common/misc-common.c
---- linux/arch/mips/zboot/common/misc-common.c 1969-12-31 19:00:00.000000000 -0500
-+++ linux.spi/arch/mips/zboot/common/misc-common.c 2004-05-11 23:19:24.000000000 -0400
-@@ -0,0 +1,437 @@
-+/*
-+ * arch/mips/zboot/common/misc-common.c
-+ *
-+ * Misc. bootloader code (almost) all platforms can use
-+ *
-+ * Author: Johnnie Peters <jpeters@mvista.com>
-+ * Editor: Tom Rini <trini@mvista.com>
-+ *
-+ * Derived from arch/ppc/boot/prep/misc.c
-+ *
-+ * Ported by Pete Popov <ppopov@mvista.com> to
-+ * support mips board(s). I also got rid of the vga console
-+ * code.
-+ *
-+ * Copyright 2000-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 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.
-+ */
-+
-+#include <linux/config.h>
-+#include "zlib.h"
-+#include <stdarg.h>
-+
-+extern char *avail_ram;
-+extern char *end_avail;
-+extern char _end[];
-+
-+void puts(const char *);
-+void putc(const char c);
-+void puthex(unsigned long val);
-+void _bcopy(char *src, char *dst, int len);
-+void gunzip(void *, int, unsigned char *, int *);
-+static int _cvt(unsigned long val, char *buf, long radix, char *digits);
-+
-+void _vprintk(void(*)(const char), const char *, va_list ap);
-+
-+struct NS16550 *com_port;
-+
-+int serial_tstc(volatile struct NS16550 *);
-+unsigned char serial_getc(volatile struct NS16550 *);
-+void serial_putc(volatile struct NS16550 *, unsigned char);
-+
-+void pause(void)
-+{
-+ puts("pause\n");
-+}
-+
-+void exit(void)
-+{
-+ puts("exit\n");
-+ while(1);
-+}
-+
-+int tstc(void)
-+{
-+ return (serial_tstc(com_port));
-+}
-+
-+int getc(void)
-+{
-+ while (1) {
-+ if (serial_tstc(com_port))
-+ return (serial_getc(com_port));
-+ }
-+}
-+
-+void
-+putc(const char c)
-+{
-+ int x,y;
-+
-+ serial_putc(com_port, c);
-+ if ( c == '\n' )
-+ serial_putc(com_port, '\r');
-+}
-+
-+void puts(const char *s)
-+{
-+ char c;
-+ while ( ( c = *s++ ) != '\0' ) {
-+ serial_putc(com_port, c);
-+ if ( c == '\n' ) serial_putc(com_port, '\r');
-+ }
-+}
-+
-+void error(char *x)
-+{
-+ puts("\n\n");
-+ puts(x);
-+ puts("\n\n -- System halted");
-+
-+ while(1); /* Halt */
-+}
-+
-+void *zalloc(void *x, unsigned items, unsigned size)
-+{
-+ void *p = avail_ram;
-+
-+ size *= items;
-+ size = (size + 7) & -8;
-+ avail_ram += size;
-+ if (avail_ram > end_avail) {
-+ puts("oops... out of memory\n");
-+ pause();
-+ }
-+ return p;
-+}
-+
-+void zfree(void *x, void *addr, unsigned nb)
-+{
-+}
-+
-+#define HEAD_CRC 2
-+#define EXTRA_FIELD 4
-+#define ORIG_NAME 8
-+#define COMMENT 0x10
-+#define RESERVED 0xe0
-+
-+#define DEFLATED 8
-+
-+void gunzip(void *dst, int dstlen, unsigned char *src, int *lenp)
-+{
-+ z_stream s;
-+ int r, i, flags;
-+
-+ /* skip header */
-+ i = 10;
-+ flags = src[3];
-+ if (src[2] != DEFLATED || (flags & RESERVED) != 0) {
-+ puts("bad gzipped data\n");
-+ exit();
-+ }
-+ if ((flags & EXTRA_FIELD) != 0)
-+ i = 12 + src[10] + (src[11] << 8);
-+ if ((flags & ORIG_NAME) != 0)
-+ while (src[i++] != 0)
-+ ;
-+ if ((flags & COMMENT) != 0)
-+ while (src[i++] != 0)
-+ ;
-+ if ((flags & HEAD_CRC) != 0)
-+ i += 2;
-+ if (i >= *lenp) {
-+ puts("gunzip: ran out of data in header\n");
-+ exit();
-+ }
-+
-+ s.zalloc = zalloc;
-+ s.zfree = zfree;
-+ r = inflateInit2(&s, -MAX_WBITS);
-+ if (r != Z_OK) {
-+ puts("inflateInit2 returned %d\n");
-+ exit();
-+ }
-+ s.next_in = src + i;
-+ s.avail_in = *lenp - i;
-+ s.next_out = dst;
-+ s.avail_out = dstlen;
-+ r = inflate(&s, Z_FINISH);
-+ if (r != Z_OK && r != Z_STREAM_END) {
-+ puts("inflate returned %d\n");
-+ exit();
-+ }
-+ *lenp = s.next_out - (unsigned char *) dst;
-+ inflateEnd(&s);
-+}
-+
-+void
-+puthex(unsigned long val)
-+{
-+
-+ unsigned char buf[10];
-+ int i;
-+ for (i = 7; i >= 0; i--)
-+ {
-+ buf[i] = "0123456789ABCDEF"[val & 0x0F];
-+ val >>= 4;
-+ }
-+ buf[8] = '\0';
-+ puts(buf);
-+}
-+
-+#define FALSE 0
-+#define TRUE 1
-+
-+void
-+_printk(char const *fmt, ...)
-+{
-+ va_list ap;
-+
-+ va_start(ap, fmt);
-+ _vprintk(putc, fmt, ap);
-+ va_end(ap);
-+ return;
-+}
-+
-+#define is_digit(c) ((c >= '0') && (c <= '9'))
-+
-+void
-+_vprintk(void(*putc)(const char), const char *fmt0, va_list ap)
-+{
-+ char c, sign, *cp = 0;
-+ int left_prec, right_prec, zero_fill, length = 0, pad, pad_on_right;
-+ char buf[32];
-+ long val;
-+ while ((c = *fmt0++))
-+ {
-+ if (c == '%')
-+ {
-+ c = *fmt0++;
-+ left_prec = right_prec = pad_on_right = 0;
-+ if (c == '-')
-+ {
-+ c = *fmt0++;
-+ pad_on_right++;
-+ }
-+ if (c == '0')
-+ {
-+ zero_fill = TRUE;
-+ c = *fmt0++;
-+ } else
-+ {
-+ zero_fill = FALSE;
-+ }
-+ while (is_digit(c))
-+ {
-+ left_prec = (left_prec * 10) + (c - '0');
-+ c = *fmt0++;
-+ }
-+ if (c == '.')
-+ {
-+ c = *fmt0++;
-+ zero_fill++;
-+ while (is_digit(c))
-+ {
-+ right_prec = (right_prec * 10) + (c - '0');
-+ c = *fmt0++;
-+ }
-+ } else
-+ {
-+ right_prec = left_prec;
-+ }
-+ sign = '\0';
-+ switch (c)
-+ {
-+ case 'd':
-+ case 'x':
-+ case 'X':
-+ val = va_arg(ap, long);
-+ switch (c)
-+ {
-+ case 'd':
-+ if (val < 0)
-+ {
-+ sign = '-';
-+ val = -val;
-+ }
-+ length = _cvt(val, buf, 10, "0123456789");
-+ break;
-+ case 'x':
-+ length = _cvt(val, buf, 16, "0123456789abcdef");
-+ break;
-+ case 'X':
-+ length = _cvt(val, buf, 16, "0123456789ABCDEF");
-+ break;
-+ }
-+ cp = buf;
-+ break;
-+ case 's':
-+ cp = va_arg(ap, char *);
-+ length = strlen(cp);
-+ break;
-+ case 'c':
-+ c = va_arg(ap, long /*char*/);
-+ (*putc)(c);
-+ continue;
-+ default:
-+ (*putc)('?');
-+ }
-+ pad = left_prec - length;
-+ if (sign != '\0')
-+ {
-+ pad--;
-+ }
-+ if (zero_fill)
-+ {
-+ c = '0';
-+ if (sign != '\0')
-+ {
-+ (*putc)(sign);
-+ sign = '\0';
-+ }
-+ } else
-+ {
-+ c = ' ';
-+ }
-+ if (!pad_on_right)
-+ {
-+ while (pad-- > 0)
-+ {
-+ (*putc)(c);
-+ }
-+ }
-+ if (sign != '\0')
-+ {
-+ (*putc)(sign);
-+ }
-+ while (length-- > 0)
-+ {
-+ (*putc)(c = *cp++);
-+ if (c == '\n')
-+ {
-+ (*putc)('\r');
-+ }
-+ }
-+ if (pad_on_right)
-+ {
-+ while (pad-- > 0)
-+ {
-+ (*putc)(c);
-+ }
-+ }
-+ } else
-+ {
-+ (*putc)(c);
-+ if (c == '\n')
-+ {
-+ (*putc)('\r');
-+ }
-+ }
-+ }
-+}
-+
-+int
-+_cvt(unsigned long val, char *buf, long radix, char *digits)
-+{
-+ char temp[80];
-+ char *cp = temp;
-+ int length = 0;
-+ if (val == 0)
-+ { /* Special case */
-+ *cp++ = '0';
-+ } else
-+ while (val)
-+ {
-+ *cp++ = digits[val % radix];
-+ val /= radix;
-+ }
-+ while (cp != temp)
-+ {
-+ *buf++ = *--cp;
-+ length++;
-+ }
-+ *buf = '\0';
-+ return (length);
-+}
-+
-+void
-+_dump_buf_with_offset(unsigned char *p, int s, unsigned char *base)
-+{
-+ int i, c;
-+ if ((unsigned int)s > (unsigned int)p)
-+ {
-+ s = (unsigned int)s - (unsigned int)p;
-+ }
-+ while (s > 0)
-+ {
-+ if (base)
-+ {
-+ _printk("%06X: ", (int)p - (int)base);
-+ } else
-+ {
-+ _printk("%06X: ", p);
-+ }
-+ for (i = 0; i < 16; i++)
-+ {
-+ if (i < s)
-+ {
-+ _printk("%02X", p[i] & 0xFF);
-+ } else
-+ {
-+ _printk(" ");
-+ }
-+ if ((i % 2) == 1) _printk(" ");
-+ if ((i % 8) == 7) _printk(" ");
-+ }
-+ _printk(" |");
-+ for (i = 0; i < 16; i++)
-+ {
-+ if (i < s)
-+ {
-+ c = p[i] & 0xFF;
-+ if ((c < 0x20) || (c >= 0x7F)) c = '.';
-+ } else
-+ {
-+ c = ' ';
-+ }
-+ _printk("%c", c);
-+ }
-+ _printk("|\n");
-+ s -= 16;
-+ p += 16;
-+ }
-+}
-+
-+void
-+_dump_buf(unsigned char *p, int s)
-+{
-+ _printk("\n");
-+ _dump_buf_with_offset(p, s, 0);
-+}
-+
-+/*
-+ * Local variables:
-+ * c-indent-level: 8
-+ * c-basic-offset: 8
-+ * tab-width: 8
-+ * End:
-+ */
-diff -Naru linux/arch/mips/zboot/common/misc-simple.c linux.spi/arch/mips/zboot/common/misc-simple.c
---- linux/arch/mips/zboot/common/misc-simple.c 1969-12-31 19:00:00.000000000 -0500
-+++ linux.spi/arch/mips/zboot/common/misc-simple.c 2004-05-11 23:19:24.000000000 -0400
-@@ -0,0 +1,127 @@
-+/*
-+ * arch/mips/zboot/common/misc-simple.c
-+ *
-+ * Misc. bootloader code for many machines. This assumes you have are using
-+ * a 6xx/7xx/74xx CPU in your machine. This assumes the chunk of memory
-+ * below 8MB is free. Finally, it assumes you have a NS16550-style uart for
-+ * your serial console. If a machine meets these requirements, it can quite
-+ * likely use this code during boot.
-+ *
-+ * Author: Matt Porter <mporter@mvista.com>
-+ * Derived from arch/ppc/boot/prep/misc.c
-+ *
-+ * Copyright 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 as published by the
-+ * Free Software Foundation; either version 2 of the License, or (at your
-+ * option) any later version.
-+ */
-+
-+#include <linux/types.h>
-+#include <linux/elf.h>
-+#include <linux/config.h>
-+
-+#include <asm/page.h>
-+#include <asm/processor.h>
-+#include <asm/mmu.h>
-+
-+#include "zlib.h"
-+
-+extern struct NS16550 *com_port;
-+
-+char *avail_ram;
-+char *end_avail;
-+extern char _end[];
-+char *zimage_start;
-+
-+#ifdef CONFIG_CMDLINE
-+#define CMDLINE CONFIG_CMDLINE
-+#else
-+#define CMDLINE ""
-+#endif
-+char cmd_preset[] = CMDLINE;
-+char cmd_buf[256];
-+char *cmd_line = cmd_buf;
-+
-+/* The linker tells us where the image is.
-+*/
-+extern unsigned char __image_begin, __image_end;
-+extern unsigned char __ramdisk_begin, __ramdisk_end;
-+unsigned long initrd_size;
-+
-+extern void puts(const char *);
-+extern void putc(const char c);
-+extern void puthex(unsigned long val);
-+extern void *memcpy(void * __dest, __const void * __src,
-+ __kernel_size_t __n);
-+extern void gunzip(void *, int, unsigned char *, int *);
-+extern void udelay(long delay);
-+extern int tstc(void);
-+extern int getc(void);
-+extern volatile struct NS16550 *serial_init(int chan);
-+
-+void
-+decompress_kernel(unsigned long load_addr, int num_words,
-+ unsigned long cksum, unsigned long *sp)
-+{
-+ int timer = 0;
-+ extern unsigned long start;
-+ char *cp, ch;
-+ int i;
-+ int zimage_size;
-+
-+ com_port = (struct NS16550 *)serial_init(0);
-+
-+ initrd_size = (unsigned long)(&__ramdisk_end) -
-+ (unsigned long)(&__ramdisk_begin);
-+
-+ /*
-+ * Reveal where we were loaded at and where we
-+ * were relocated to.
-+ */
-+ puts("loaded at: "); puthex(load_addr);
-+ puts(" "); puthex((unsigned long)(load_addr + (4*num_words))); puts("\n");
-+ if ( (unsigned long)load_addr != (unsigned long)&start )
-+ {
-+ puts("relocated to: "); puthex((unsigned long)&start);
-+ puts(" ");
-+ puthex((unsigned long)((unsigned long)&start + (4*num_words)));
-+ puts("\n");
-+ }
-+
-+ /*
-+ * We link ourself to an arbitrary low address. When we run, we
-+ * relocate outself to that address. __image_being points to
-+ * the part of the image where the zImage is. -- Tom
-+ */
-+ zimage_start = (char *)(unsigned long)(&__image_begin);
-+ zimage_size = (unsigned long)(&__image_end) -
-+ (unsigned long)(&__image_begin);
-+
-+ /*
-+ * The zImage and initrd will be between start and _end, so they've
-+ * already been moved once. We're good to go now. -- Tom
-+ */
-+ puts("zimage at: "); puthex((unsigned long)zimage_start);
-+ puts(" "); puthex((unsigned long)(zimage_size+zimage_start));
-+ puts("\n");
-+
-+ if ( initrd_size ) {
-+ puts("initrd at: ");
-+ puthex((unsigned long)(&__ramdisk_begin));
-+ puts(" "); puthex((unsigned long)(&__ramdisk_end));puts("\n");
-+ }
-+
-+ /* assume the chunk below 8M is free */
-+ avail_ram = (char *)AVAIL_RAM_START;
-+ end_avail = (char *)AVAIL_RAM_END;
-+
-+ /* Display standard Linux/MIPS boot prompt for kernel args */
-+ puts("Uncompressing Linux at load address ");
-+ puthex(LOADADDR);
-+ puts("\n");
-+ /* I don't like this hard coded gunzip size (fixme) */
-+ gunzip((void *)LOADADDR, 0x400000, zimage_start, &zimage_size);
-+ puts("Now booting the kernel\n");
-+}
-diff -Naru linux/arch/mips/zboot/common/no_initrd.c linux.spi/arch/mips/zboot/common/no_initrd.c
---- linux/arch/mips/zboot/common/no_initrd.c 1969-12-31 19:00:00.000000000 -0500
-+++ linux.spi/arch/mips/zboot/common/no_initrd.c 2004-05-11 23:19:24.000000000 -0400
-@@ -0,0 +1,2 @@
-+char initrd_data[1];
-+int initrd_len = 0;
-diff -Naru linux/arch/mips/zboot/common/ns16550.c linux.spi/arch/mips/zboot/common/ns16550.c
---- linux/arch/mips/zboot/common/ns16550.c 1969-12-31 19:00:00.000000000 -0500
-+++ linux.spi/arch/mips/zboot/common/ns16550.c 2004-05-11 23:19:24.000000000 -0400
-@@ -0,0 +1,57 @@
-+/*
-+ * NS16550 support
-+ */
-+
-+#include <linux/config.h>
-+#include <asm/serial.h>
-+#include "ns16550.h"
-+
-+typedef struct NS16550 *NS16550_t;
-+
-+const NS16550_t COM_PORTS[] = { (NS16550_t) COM1,
-+ (NS16550_t) COM2,
-+ (NS16550_t) COM3,
-+ (NS16550_t) COM4 };
-+
-+volatile struct NS16550 *
-+serial_init(int chan)
-+{
-+ volatile struct NS16550 *com_port;
-+ com_port = (struct NS16550 *) COM_PORTS[chan];
-+ /* See if port is present */
-+ com_port->lcr = 0x00;
-+ com_port->ier = 0xFF;
-+#if 0
-+ if (com_port->ier != 0x0F) return ((struct NS16550 *)0);
-+#endif
-+ com_port->ier = 0x00;
-+ com_port->lcr = 0x80; /* Access baud rate */
-+#ifdef CONFIG_SERIAL_CONSOLE_NONSTD
-+ com_port->dll = (BASE_BAUD / CONFIG_SERIAL_CONSOLE_BAUD);
-+ com_port->dlm = (BASE_BAUD / CONFIG_SERIAL_CONSOLE_BAUD) >> 8;
-+#endif
-+ com_port->lcr = 0x03; /* 8 data, 1 stop, no parity */
-+ com_port->mcr = 0x03; /* RTS/DTR */
-+ com_port->fcr = 0x07; /* Clear & enable FIFOs */
-+ return (com_port);
-+}
-+
-+void
-+serial_putc(volatile struct NS16550 *com_port, unsigned char c)
-+{
-+ while ((com_port->lsr & LSR_THRE) == 0) ;
-+ com_port->thr = c;
-+}
-+
-+unsigned char
-+serial_getc(volatile struct NS16550 *com_port)
-+{
-+ while ((com_port->lsr & LSR_DR) == 0) ;
-+ return (com_port->rbr);
-+}
-+
-+int
-+serial_tstc(volatile struct NS16550 *com_port)
-+{
-+ return ((com_port->lsr & LSR_DR) != 0);
-+}
-diff -Naru linux/arch/mips/zboot/common/string.c linux.spi/arch/mips/zboot/common/string.c
---- linux/arch/mips/zboot/common/string.c 1969-12-31 19:00:00.000000000 -0500
-+++ linux.spi/arch/mips/zboot/common/string.c 2004-05-11 23:19:24.000000000 -0400
-@@ -0,0 +1,497 @@
-+/*
-+ * linux/lib/string.c
-+ *
-+ * Copyright (C) 1991, 1992 Linus Torvalds
-+ */
-+
-+/*
-+ * stupid library routines.. The optimized versions should generally be found
-+ * as inline code in <asm-xx/string.h>
-+ *
-+ * These are buggy as well..
-+ *
-+ * * Fri Jun 25 1999, Ingo Oeser <ioe@informatik.tu-chemnitz.de>
-+ * - Added strsep() which will replace strtok() soon (because strsep() is
-+ * reentrant and should be faster). Use only strsep() in new code, please.
-+ */
-+
-+#include <linux/types.h>
-+#include <linux/string.h>
-+#include <linux/ctype.h>
-+
-+/**
-+ * strnicmp - Case insensitive, length-limited string comparison
-+ * @s1: One string
-+ * @s2: The other string
-+ * @len: the maximum number of characters to compare
-+ */
-+int strnicmp(const char *s1, const char *s2, size_t len)
-+{
-+ /* Yes, Virginia, it had better be unsigned */
-+ unsigned char c1, c2;
-+
-+ c1 = 0; c2 = 0;
-+ if (len) {
-+ do {
-+ c1 = *s1; c2 = *s2;
-+ s1++; s2++;
-+ if (!c1)
-+ break;
-+ if (!c2)
-+ break;
-+ if (c1 == c2)
-+ continue;
-+ c1 = tolower(c1);
-+ c2 = tolower(c2);
-+ if (c1 != c2)
-+ break;
-+ } while (--len);
-+ }
-+ return (int)c1 - (int)c2;
-+}
-+
-+char * ___strtok;
-+
-+#ifndef __HAVE_ARCH_STRCPY
-+/**
-+ * strcpy - Copy a %NUL terminated string
-+ * @dest: Where to copy the string to
-+ * @src: Where to copy the string from
-+ */
-+char * strcpy(char * dest,const char *src)
-+{
-+ char *tmp = dest;
-+
-+ while ((*dest++ = *src++) != '\0')
-+ /* nothing */;
-+ return tmp;
-+}
-+#endif
-+
-+#ifndef __HAVE_ARCH_STRNCPY
-+/**
-+ * strncpy - Copy a length-limited, %NUL-terminated string
-+ * @dest: Where to copy the string to
-+ * @src: Where to copy the string from
-+ * @count: The maximum number of bytes to copy
-+ *
-+ * Note that unlike userspace strncpy, this does not %NUL-pad the buffer.
-+ * However, the result is not %NUL-terminated if the source exceeds
-+ * @count bytes.
-+ */
-+char * strncpy(char * dest,const char *src,size_t count)
-+{
-+ char *tmp = dest;
-+
-+ while (count-- && (*dest++ = *src++) != '\0')
-+ /* nothing */;
-+
-+ return tmp;
-+}
-+#endif
-+
-+/**
-+ * strcat - Append one %NUL-terminated string to another
-+ * @dest: The string to be appended to
-+ * @src: The string to append to it
-+ */
-+char * strcat(char * dest, const char * src)
-+{
-+ char *tmp = dest;
-+
-+ while (*dest)
-+ dest++;
-+ while ((*dest++ = *src++) != '\0')
-+ ;
-+
-+ return tmp;
-+}
-+
-+/**
-+ * strncat - Append a length-limited, %NUL-terminated string to another
-+ * @dest: The string to be appended to
-+ * @src: The string to append to it
-+ * @count: The maximum numbers of bytes to copy
-+ *
-+ * Note that in contrast to strncpy, strncat ensures the result is
-+ * terminated.
-+ */
-+char * strncat(char *dest, const char *src, size_t count)
-+{
-+ char *tmp = dest;
-+
-+ if (count) {
-+ while (*dest)
-+ dest++;
-+ while ((*dest++ = *src++)) {
-+ if (--count == 0) {
-+ *dest = '\0';
-+ break;
-+ }
-+ }
-+ }
-+
-+ return tmp;
-+}
-+
-+#ifndef __HAVE_ARCH_STRCMP
-+/**
-+ * strcmp - Compare two strings
-+ * @cs: One string
-+ * @ct: Another string
-+ */
-+int strcmp(const char * cs,const char * ct)
-+{
-+ register signed char __res;
-+
-+ while (1) {
-+ if ((__res = *cs - *ct++) != 0 || !*cs++)
-+ break;
-+ }
-+
-+ return __res;
-+}
-+#endif
-+
-+#ifndef __HAVE_ARCH_STRNCMP
-+/**
-+ * strncmp - Compare two length-limited strings
-+ * @cs: One string
-+ * @ct: Another string
-+ * @count: The maximum number of bytes to compare
-+ */
-+int strncmp(const char * cs,const char * ct,size_t count)
-+{
-+ register signed char __res = 0;
-+
-+ while (count) {
-+ if ((__res = *cs - *ct++) != 0 || !*cs++)
-+ break;
-+ count--;
-+ }
-+
-+ return __res;
-+}
-+#endif
-+
-+/**
-+ * strchr - Find the first occurrence of a character in a string
-+ * @s: The string to be searched
-+ * @c: The character to search for
-+ */
-+char * strchr(const char * s, int c)
-+{
-+ for(; *s != (char) c; ++s)
-+ if (*s == '\0')
-+ return NULL;
-+ return (char *) s;
-+}
-+
-+/**
-+ * strrchr - Find the last occurrence of a character in a string
-+ * @s: The string to be searched
-+ * @c: The character to search for
-+ */
-+char * strrchr(const char * s, int c)
-+{
-+ const char *p = s + strlen(s);
-+ do {
-+ if (*p == (char)c)
-+ return (char *)p;
-+ } while (--p >= s);
-+ return NULL;
-+}
-+
-+/**
-+ * strlen - Find the length of a string
-+ * @s: The string to be sized
-+ */
-+size_t strlen(const char * s)
-+{
-+ const char *sc;
-+
-+ for (sc = s; *sc != '\0'; ++sc)
-+ /* nothing */;
-+ return sc - s;
-+}
-+
-+/**
-+ * strnlen - Find the length of a length-limited string
-+ * @s: The string to be sized
-+ * @count: The maximum number of bytes to search
-+ */
-+size_t strnlen(const char * s, size_t count)
-+{
-+ const char *sc;
-+
-+ for (sc = s; count-- && *sc != '\0'; ++sc)
-+ /* nothing */;
-+ return sc - s;
-+}
-+
-+/**
-+ * strspn - Calculate the length of the initial substring of @s which only
-+ * contain letters in @accept
-+ * @s: The string to be searched
-+ * @accept: The string to search for
-+ */
-+size_t strspn(const char *s, const char *accept)
-+{
-+ const char *p;
-+ const char *a;
-+ size_t count = 0;
-+
-+ for (p = s; *p != '\0'; ++p) {
-+ for (a = accept; *a != '\0'; ++a) {
-+ if (*p == *a)
-+ break;
-+ }
-+ if (*a == '\0')
-+ return count;
-+ ++count;
-+ }
-+
-+ return count;
-+}
-+
-+/**
-+ * strpbrk - Find the first occurrence of a set of characters
-+ * @cs: The string to be searched
-+ * @ct: The characters to search for
-+ */
-+char * strpbrk(const char * cs,const char * ct)
-+{
-+ const char *sc1,*sc2;
-+
-+ for( sc1 = cs; *sc1 != '\0'; ++sc1) {
-+ for( sc2 = ct; *sc2 != '\0'; ++sc2) {
-+ if (*sc1 == *sc2)
-+ return (char *) sc1;
-+ }
-+ }
-+ return NULL;
-+}
-+
-+/**
-+ * strtok - Split a string into tokens
-+ * @s: The string to be searched
-+ * @ct: The characters to search for
-+ *
-+ * WARNING: strtok is deprecated, use strsep instead.
-+ */
-+char * strtok(char * s,const char * ct)
-+{
-+ char *sbegin, *send;
-+
-+ sbegin = s ? s : ___strtok;
-+ if (!sbegin) {
-+ return NULL;
-+ }
-+ sbegin += strspn(sbegin,ct);
-+ if (*sbegin == '\0') {
-+ ___strtok = NULL;
-+ return( NULL );
-+ }
-+ send = strpbrk( sbegin, ct);
-+ if (send && *send != '\0')
-+ *send++ = '\0';
-+ ___strtok = send;
-+ return (sbegin);
-+}
-+
-+/**
-+ * strsep - Split a string into tokens
-+ * @s: The string to be searched
-+ * @ct: The characters to search for
-+ *
-+ * strsep() updates @s to point after the token, ready for the next call.
-+ *
-+ * It returns empty tokens, too, behaving exactly like the libc function
-+ * of that name. In fact, it was stolen from glibc2 and de-fancy-fied.
-+ * Same semantics, slimmer shape. ;)
-+ */
-+char * strsep(char **s, const char *ct)
-+{
-+ char *sbegin = *s, *end;
-+
-+ if (sbegin == NULL)
-+ return NULL;
-+
-+ end = strpbrk(sbegin, ct);
-+ if (end)
-+ *end++ = '\0';
-+ *s = end;
-+
-+ return sbegin;
-+}
-+
-+/**
-+ * memset - Fill a region of memory with the given value
-+ * @s: Pointer to the start of the area.
-+ * @c: The byte to fill the area with
-+ * @count: The size of the area.
-+ *
-+ * Do not use memset() to access IO space, use memset_io() instead.
-+ */
-+void * memset(void * s,int c, size_t count)
-+{
-+ char *xs = (char *) s;
-+
-+ while (count--)
-+ *xs++ = c;
-+
-+ return s;
-+}
-+
-+/**
-+ * bcopy - Copy one area of memory to another
-+ * @src: Where to copy from
-+ * @dest: Where to copy to
-+ * @count: The size of the area.
-+ *
-+ * Note that this is the same as memcpy(), with the arguments reversed.
-+ * memcpy() is the standard, bcopy() is a legacy BSD function.
-+ *
-+ * You should not use this function to access IO space, use memcpy_toio()
-+ * or memcpy_fromio() instead.
-+ */
-+char * bcopy(const char * src, char * dest, int count)
-+{
-+ char *tmp = dest;
-+
-+ while (count--)
-+ *tmp++ = *src++;
-+
-+ return dest;
-+}
-+
-+/**
-+ * memcpy - Copy one area of memory to another
-+ * @dest: Where to copy to
-+ * @src: Where to copy from
-+ * @count: The size of the area.
-+ *
-+ * You should not use this function to access IO space, use memcpy_toio()
-+ * or memcpy_fromio() instead.
-+ */
-+void * memcpy(void * dest,const void *src,size_t count)
-+{
-+ char *tmp = (char *) dest, *s = (char *) src;
-+
-+ while (count--)
-+ *tmp++ = *s++;
-+
-+ return dest;
-+}
-+
-+/**
-+ * memmove - Copy one area of memory to another
-+ * @dest: Where to copy to
-+ * @src: Where to copy from
-+ * @count: The size of the area.
-+ *
-+ * Unlike memcpy(), memmove() copes with overlapping areas.
-+ */
-+void * memmove(void * dest,const void *src,size_t count)
-+{
-+ char *tmp, *s;
-+
-+ if (dest <= src) {
-+ tmp = (char *) dest;
-+ s = (char *) src;
-+ while (count--)
-+ *tmp++ = *s++;
-+ }
-+ else {
-+ tmp = (char *) dest + count;
-+ s = (char *) src + count;
-+ while (count--)
-+ *--tmp = *--s;
-+ }
-+
-+ return dest;
-+}
-+
-+/**
-+ * memcmp - Compare two areas of memory
-+ * @cs: One area of memory
-+ * @ct: Another area of memory
-+ * @count: The size of the area.
-+ */
-+int memcmp(const void * cs,const void * ct,size_t count)
-+{
-+ const unsigned char *su1, *su2;
-+ signed char res = 0;
-+
-+ for( su1 = cs, su2 = ct; 0 < count; ++su1, ++su2, count--)
-+ if ((res = *su1 - *su2) != 0)
-+ break;
-+ return res;
-+}
-+
-+#ifndef __HAVE_ARCH_MEMSCAN
-+/**
-+ * memscan - Find a character in an area of memory.
-+ * @addr: The memory area
-+ * @c: The byte to search for
-+ * @size: The size of the area.
-+ *
-+ * returns the address of the first occurrence of @c, or 1 byte past
-+ * the area if @c is not found
-+ */
-+void * memscan(void * addr, int c, size_t size)
-+{
-+ unsigned char * p = (unsigned char *) addr;
-+ unsigned char * e = p + size;
-+
-+ while (p != e) {
-+ if (*p == c)
-+ return (void *) p;
-+ p++;
-+ }
-+
-+ return (void *) p;
-+}
-+#endif
-+
-+/**
-+ * strstr - Find the first substring in a %NUL terminated string
-+ * @s1: The string to be searched
-+ * @s2: The string to search for
-+ */
-+char * strstr(const char * s1,const char * s2)
-+{
-+ int l1, l2;
-+
-+ l2 = strlen(s2);
-+ if (!l2)
-+ return (char *) s1;
-+ l1 = strlen(s1);
-+ while (l1 >= l2) {
-+ l1--;
-+ if (!memcmp(s1,s2,l2))
-+ return (char *) s1;
-+ s1++;
-+ }
-+ return NULL;
-+}
-+
-+/**
-+ * memchr - Find a character in an area of memory.
-+ * @s: The memory area
-+ * @c: The byte to search for
-+ * @n: The size of the area.
-+ *
-+ * returns the address of the first occurrence of @c, or %NULL
-+ * if @c is not found
-+ */
-+void *memchr(const void *s, int c, size_t n)
-+{
-+ const unsigned char *p = s;
-+ while (n-- != 0) {
-+ if ((unsigned char)c == *p++) {
-+ return (void *)(p-1);
-+ }
-+ }
-+ return NULL;
-+}
-diff -Naru linux/arch/mips/zboot/csb250/head.S linux.spi/arch/mips/zboot/csb250/head.S
---- linux/arch/mips/zboot/csb250/head.S 1969-12-31 19:00:00.000000000 -0500
-+++ linux.spi/arch/mips/zboot/csb250/head.S 2004-05-11 23:19:24.000000000 -0400
-@@ -0,0 +1,157 @@
-+/*
-+ * arch/mips/kernel/head.S
-+ *
-+ * This file is subject to the terms and conditions of the GNU General Public
-+ * License. See the file "COPYING" in the main directory of this archive
-+ * for more details.
-+ *
-+ * Copyright (C) 1994, 1995 Waldorf Electronics
-+ * Written by Ralf Baechle and Andreas Busse
-+ * Copyright (C) 1995 - 1999 Ralf Baechle
-+ * Copyright (C) 1996 Paul M. Antoine
-+ * Modified for DECStation and hence R3000 support by Paul M. Antoine
-+ * Further modifications by David S. Miller and Harald Koerfgen
-+ * Copyright (C) 1999 Silicon Graphics, Inc.
-+ *
-+ * Head.S contains the MIPS exception handler and startup code.
-+ *
-+ **************************************************************************
-+ * 9 Nov, 2000.
-+ * Added Cache Error exception handler and SBDDP EJTAG debug exception.
-+ *
-+ * Kevin Kissell, kevink@mips.com and Carsten Langgaard, carstenl@mips.com
-+ * Copyright (C) 2000 MIPS Technologies, Inc. All rights reserved.
-+ **************************************************************************
-+ */
-+#include <linux/config.h>
-+#include <linux/threads.h>
-+
-+#include <asm/asm.h>
-+#include <asm/cacheops.h>
-+#include <asm/mipsregs.h>
-+#include <asm/offset.h>
-+#include <asm/cachectl.h>
-+#include <asm/regdef.h>
-+
-+#define IndexInvalidate_I 0x00
-+#define IndexWriteBack_D 0x01
-+
-+ .set noreorder
-+ .cprestore
-+ LEAF(start)
-+start:
-+ bal locate
-+ nop
-+
-+ .globl asize /* Someday we'll put the initrd info here. */
-+asize: .word 0
-+ .word 0
-+ .word 0
-+ .word 0
-+
-+locate:
-+ subu s8, ra, 8 /* Where we were loaded */
-+ la sp, (.stack + 8192)
-+
-+ move s0, a0 /* Save boot rom start args */
-+ move s1, a1
-+ move s2, a2
-+ move s3, a3
-+
-+ la a0, start /* Where we were linked to run */
-+
-+ move a1, s8
-+ la a2, _edata
-+ subu t1, a2, a0
-+ srl t1, t1, 2
-+
-+ /* copy text section */
-+ li t0, 0
-+1: lw v0, 0(a1)
-+ nop
-+ sw v0, 0(a0)
-+ xor t0, t0, v0
-+ addu a0, 4
-+ bne a2, a0, 1b
-+ addu a1, 4
-+
-+ /* Clear BSS */
-+ la a0, _edata
-+ la a2, _end
-+2: sw zero, 0(a0)
-+ bne a2, a0, 2b
-+ addu a0, 4
-+
-+ /* push the D-Cache and invalidate I-Cache */
-+ li k0, 0x80000000 # start address
-+ li k1, 0x80004000 # end address (16KB I-Cache)
-+ subu k1, 128
-+
-+1:
-+ .set mips3
-+ cache IndexWriteBack_D, 0(k0)
-+ cache IndexWriteBack_D, 32(k0)
-+ cache IndexWriteBack_D, 64(k0)
-+ cache IndexWriteBack_D, 96(k0)
-+ cache IndexInvalidate_I, 0(k0)
-+ cache IndexInvalidate_I, 32(k0)
-+ cache IndexInvalidate_I, 64(k0)
-+ cache IndexInvalidate_I, 96(k0)
-+ .set mips0
-+
-+ bne k0, k1, 1b
-+ addu k0, k0, 128
-+ /* done */
-+
-+/* move a0, s8 /* load address */
-+ subu a0, s8, 0x1000 /* load address */
-+ move a1, t1 /* length in words */
-+ move a2, t0 /* checksum */
-+ move a3, sp
-+
-+ la ra, 1f
-+ la k0, decompress_kernel
-+ jr k0
-+ nop
-+1:
-+
-+ la a2, __ramdisk_begin
-+ la a3, initrd_size
-+ lw a0, 0(a2)
-+ lw a1, 0(a3)
-+ li k0, KERNEL_ENTRY
-+ jr k0
-+ nop
-+3:
-+ b 3b
-+ END(start)
-+
-+ LEAF(udelay)
-+udelay:
-+ END(udelay)
-+
-+
-+ LEAF(FlushCache)
-+ li k0, 0x80000000 # start address
-+ li k1, 0x80004000 # end address (16KB I-Cache)
-+ subu k1, 128
-+
-+1:
-+ .set mips3
-+ cache IndexWriteBack_D, 0(k0)
-+ cache IndexWriteBack_D, 32(k0)
-+ cache IndexWriteBack_D, 64(k0)
-+ cache IndexWriteBack_D, 96(k0)
-+ cache IndexInvalidate_I, 0(k0)
-+ cache IndexInvalidate_I, 32(k0)
-+ cache IndexInvalidate_I, 64(k0)
-+ cache IndexInvalidate_I, 96(k0)
-+ .set mips0
-+
-+ bne k0, k1, 1b
-+ addu k0, k0, 128
-+ jr ra
-+ nop
-+ END(FlushCache)
-+
-+ .comm .stack,4096*2,4
-diff -Naru linux/arch/mips/zboot/csb250/Makefile linux.spi/arch/mips/zboot/csb250/Makefile
---- linux/arch/mips/zboot/csb250/Makefile 1969-12-31 19:00:00.000000000 -0500
-+++ linux.spi/arch/mips/zboot/csb250/Makefile 2004-05-11 23:19:24.000000000 -0400
-@@ -0,0 +1,90 @@
-+# arch/mips/zboot/pb1xxx/Makefile
-+#
-+# Makefile for Cogent CSB250 Au1500 board.
-+# All of the boot loader code was derived from the ppc
-+# boot code.
-+#
-+# 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.
-+
-+.c.s:
-+ $(CC) $(CFLAGS) -S -o $*.s $<
-+.s.o:
-+ $(AS) -o $*.o $<
-+.c.o:
-+ $(CC) $(CFLAGS) -D__BOOTER__ -c -o $*.o $<
-+.S.s:
-+ $(CPP) $(AFLAGS) -o $*.o $<
-+.S.o:
-+ $(CC) $(AFLAGS) -c -o $*.o $<
-+
-+#########################################################################
-+# START BOARD SPECIFIC VARIABLES
-+BNAME=csb250
-+
-+# These two variables control where the zImage is stored
-+# in flash and loaded in memory. It only controls how the srec
-+# file is generated, the code is the same.
-+RAM_RUN_ADDR = 0x80a00000
-+FLASH_LOAD_ADDR = 0xBFD00000
-+
-+# These two variables specify the free ram region
-+# that can be used for temporary malloc area
-+AVAIL_RAM_START=0x80400000
-+AVAIL_RAM_END=0x80800000
-+
-+# This one must match the LOADADDR in arch/mips/Makefile!
-+LOADADDR=0x80100000
-+# END BOARD SPECIFIC VARIABLES
-+#########################################################################
-+
-+OBJECTS := head.o ../common/misc-common.o ../common/misc-simple.o \
-+ ../common/au1k_uart.o ../common/string.o ../common/ctype.o
-+LIBS := ../lib/zlib.a
-+
-+ENTRY := ../utils/entry
-+OFFSET := ../utils/offset
-+SIZE := ../utils/size
-+
-+LD_ARGS := -T ../ld.script -Ttext $(RAM_RUN_ADDR) -Bstatic
-+OBJCOPY_ARGS = -O elf32-tradbigmips
-+
-+all: zImage
-+
-+clean:
-+ rm -rf *.o vmlinux* zvmlinux.* ../images/*.srec
-+
-+head.o: head.S $(TOPDIR)/vmlinux
-+ $(CC) $(AFLAGS) \
-+ -DKERNEL_ENTRY=$(shell sh $(ENTRY) $(NM) $(TOPDIR)/vmlinux ) \
-+ -c -o $*.o $<
-+
-+../common/misc-simple.o:
-+ $(CC) $(CFLAGS) -DINITRD_OFFSET=0 -DINITRD_SIZE=0 -DZIMAGE_OFFSET=0 \
-+ -DAVAIL_RAM_START=$(AVAIL_RAM_START) \
-+ -DAVAIL_RAM_END=$(AVAIL_RAM_END) \
-+ -DLOADADDR=$(LOADADDR) \
-+ -DZIMAGE_SIZE=0 -c -o $@ $*.c
-+
-+zvmlinux: $(OBJECTS) $(LIBS) ../ld.script ../images/vmlinux.gz ../common/dummy.o
-+ $(OBJCOPY) \
-+ --add-section=.image=../images/vmlinux.gz \
-+ --set-section-flags=.image=contents,alloc,load,readonly,data \
-+ ../common/dummy.o image.o
-+ $(LD) $(LD_ARGS) -o $@ $(OBJECTS) image.o $(LIBS)
-+ $(OBJCOPY) $(OBJCOPY_ARGS) $@ $@ -R .comment -R .stab -R .stabstr \
-+ -R .initrd -R .sysmap
-+
-+# Here we manipulate the image in order to get it the necessary
-+# srecord file we need.
-+zImage: zvmlinux
-+ mv zvmlinux ../images/zImage.$(BNAME)
-+ $(OBJCOPY) -O binary ../images/zImage.$(BNAME) ../images/$(BNAME).bin
-+
-+zImage.flash: zImage
-+ $(OBJCOPY) -O srec --adjust-vma 0x3ed00000 \
-+ ../images/zImage.$(BNAME) ../images/$(BNAME).flash.srec
-+
-+include $(TOPDIR)/Rules.make
-diff -Naru linux/arch/mips/zboot/images/Makefile linux.spi/arch/mips/zboot/images/Makefile
---- linux/arch/mips/zboot/images/Makefile 1969-12-31 19:00:00.000000000 -0500
-+++ linux.spi/arch/mips/zboot/images/Makefile 2004-05-11 23:19:24.000000000 -0400
-@@ -0,0 +1,10 @@
-+
-+include $(TOPDIR)/Rules.make
-+
-+vmlinux.gz: $(TOPDIR)/vmlinux
-+ $(OBJCOPY) -S -O binary $(TOPDIR)/vmlinux vmlinux
-+ gzip -vf vmlinux
-+
-+clean:
-+ rm -f vmlinux.* zImage.*
-+
-diff -Naru linux/arch/mips/zboot/include/nonstdio.h linux.spi/arch/mips/zboot/include/nonstdio.h
---- linux/arch/mips/zboot/include/nonstdio.h 1969-12-31 19:00:00.000000000 -0500
-+++ linux.spi/arch/mips/zboot/include/nonstdio.h 2004-05-11 23:19:24.000000000 -0400
-@@ -0,0 +1,18 @@
-+/*
-+ * Copyright (C) Paul Mackerras 1997.
-+ *
-+ * 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.
-+ */
-+typedef int FILE;
-+extern FILE *stdin, *stdout;
-+#define NULL ((void *)0)
-+#define EOF (-1)
-+#define fopen(n, m) NULL
-+#define fflush(f) 0
-+#define fclose(f) 0
-+extern char *fgets();
-+
-+#define perror(s) printf("%s: no files!\n", (s))
-diff -Naru linux/arch/mips/zboot/include/ns16550.h linux.spi/arch/mips/zboot/include/ns16550.h
---- linux/arch/mips/zboot/include/ns16550.h 1969-12-31 19:00:00.000000000 -0500
-+++ linux.spi/arch/mips/zboot/include/ns16550.h 2004-05-11 23:19:24.000000000 -0400
-@@ -0,0 +1,49 @@
-+/*
-+ * NS16550 Serial Port
-+ */
-+
-+/*
-+ * Figure out which file will have the definitons of COMx
-+ */
-+#if !defined(CONFIG_AU1X00_UART)
-+#error no serial.h
-+#endif
-+
-+/* Some machines have their uart registers 16 bytes apart. Most don't.
-+ * TODO: Make this work like drivers/char/serial does - Tom */
-+#if !defined(UART_REG_PAD)
-+#define UART_REG_PAD(x)
-+#endif
-+
-+struct NS16550
-+ {
-+ unsigned char rbr; /* 0 */
-+ UART_REG_PAD(rbr)
-+ unsigned char ier; /* 1 */
-+ UART_REG_PAD(ier)
-+ unsigned char fcr; /* 2 */
-+ UART_REG_PAD(fcr)
-+ unsigned char lcr; /* 3 */
-+ UART_REG_PAD(lcr)
-+ unsigned char mcr; /* 4 */
-+ UART_REG_PAD(mcr)
-+ unsigned char lsr; /* 5 */
-+ UART_REG_PAD(lsr)
-+ unsigned char msr; /* 6 */
-+ UART_REG_PAD(msr)
-+ unsigned char scr; /* 7 */
-+ };
-+
-+#define thr rbr
-+#define iir fcr
-+#define dll rbr
-+#define dlm ier
-+
-+#define LSR_DR 0x01 /* Data ready */
-+#define LSR_OE 0x02 /* Overrun */
-+#define LSR_PE 0x04 /* Parity error */
-+#define LSR_FE 0x08 /* Framing error */
-+#define LSR_BI 0x10 /* Break */
-+#define LSR_THRE 0x20 /* Xmit holding register empty */
-+#define LSR_TEMT 0x40 /* Xmitter empty */
-+#define LSR_ERR 0x80 /* Error */
-diff -Naru linux/arch/mips/zboot/include/pb1000_serial.h linux.spi/arch/mips/zboot/include/pb1000_serial.h
---- linux/arch/mips/zboot/include/pb1000_serial.h 1969-12-31 19:00:00.000000000 -0500
-+++ linux.spi/arch/mips/zboot/include/pb1000_serial.h 2004-05-11 23:19:24.000000000 -0400
-@@ -0,0 +1,20 @@
-+/*
-+ * arch/ppc/boot/include/sandpoint_serial.h
-+ *
-+ * Location of the COM ports on Motorola SPS Sandpoint machines
-+ *
-+ * Author: Mark A. Greer
-+ * mgreer@mvista.com
-+ *
-+ * Copyright 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 as published by the
-+ * Free Software Foundation; either version 2 of the License, or (at your
-+ * option) any later version.
-+ */
-+
-+#define COM1 0xfe0003f8
-+#define COM2 0xfe0002f8
-+#define COM3 0x00000000 /* No COM3 */
-+#define COM4 0x00000000 /* No COM4 */
-diff -Naru linux/arch/mips/zboot/include/zlib.h linux.spi/arch/mips/zboot/include/zlib.h
---- linux/arch/mips/zboot/include/zlib.h 1969-12-31 19:00:00.000000000 -0500
-+++ linux.spi/arch/mips/zboot/include/zlib.h 2004-05-11 23:19:24.000000000 -0400
-@@ -0,0 +1,432 @@
-+/* $Id: zlib.h,v 1.2 2002/02/16 16:55:45 ppopov Exp $ */
-+
-+/*
-+ * This file is derived from zlib.h and zconf.h from the zlib-0.95
-+ * distribution by Jean-loup Gailly and Mark Adler, with some additions
-+ * by Paul Mackerras to aid in implementing Deflate compression and
-+ * decompression for PPP packets.
-+ */
-+
-+/*
-+ * ==FILEVERSION 960122==
-+ *
-+ * This marker is used by the Linux installation script to determine
-+ * whether an up-to-date version of this file is already installed.
-+ */
-+
-+/* zlib.h -- interface of the 'zlib' general purpose compression library
-+ version 0.95, Aug 16th, 1995.
-+
-+ Copyright (C) 1995 Jean-loup Gailly and Mark Adler
-+
-+ This software is provided 'as-is', without any express or implied
-+ warranty. In no event will the authors be held liable for any damages
-+ arising from the use of this software.
-+
-+ Permission is granted to anyone to use this software for any purpose,
-+ including commercial applications, and to alter it and redistribute it
-+ freely, subject to the following restrictions:
-+
-+ 1. The origin of this software must not be misrepresented; you must not
-+ claim that you wrote the original software. If you use this software
-+ in a product, an acknowledgment in the product documentation would be
-+ appreciated but is not required.
-+ 2. Altered source versions must be plainly marked as such, and must not be
-+ misrepresented as being the original software.
-+ 3. This notice may not be removed or altered from any source distribution.
-+
-+ Jean-loup Gailly Mark Adler
-+ gzip@prep.ai.mit.edu madler@alumni.caltech.edu
-+ */
-+
-+#ifndef _ZLIB_H
-+#define _ZLIB_H
-+
-+/* #include "zconf.h" */ /* included directly here */
-+
-+/* zconf.h -- configuration of the zlib compression library
-+ * Copyright (C) 1995 Jean-loup Gailly.
-+ * For conditions of distribution and use, see copyright notice in zlib.h
-+ */
-+
-+/* From: zconf.h,v 1.12 1995/05/03 17:27:12 jloup Exp */
-+
-+/*
-+ The library does not install any signal handler. It is recommended to
-+ add at least a handler for SIGSEGV when decompressing; the library checks
-+ the consistency of the input data whenever possible but may go nuts
-+ for some forms of corrupted input.
-+ */
-+
-+/*
-+ * Compile with -DMAXSEG_64K if the alloc function cannot allocate more
-+ * than 64k bytes at a time (needed on systems with 16-bit int).
-+ * Compile with -DUNALIGNED_OK if it is OK to access shorts or ints
-+ * at addresses which are not a multiple of their size.
-+ * Under DOS, -DFAR=far or -DFAR=__far may be needed.
-+ */
-+
-+#ifndef STDC
-+# if defined(MSDOS) || defined(__STDC__) || defined(__cplusplus)
-+# define STDC
-+# endif
-+#endif
-+
-+#ifdef __MWERKS__ /* Metrowerks CodeWarrior declares fileno() in unix.h */
-+# include <unix.h>
-+#endif
-+
-+/* Maximum value for memLevel in deflateInit2 */
-+#ifndef MAX_MEM_LEVEL
-+# ifdef MAXSEG_64K
-+# define MAX_MEM_LEVEL 8
-+# else
-+# define MAX_MEM_LEVEL 9
-+# endif
-+#endif
-+
-+#ifndef FAR
-+# define FAR
-+#endif
-+
-+/* Maximum value for windowBits in deflateInit2 and inflateInit2 */
-+#ifndef MAX_WBITS
-+# define MAX_WBITS 15 /* 32K LZ77 window */
-+#endif
-+
-+/* The memory requirements for deflate are (in bytes):
-+ 1 << (windowBits+2) + 1 << (memLevel+9)
-+ that is: 128K for windowBits=15 + 128K for memLevel = 8 (default values)
-+ plus a few kilobytes for small objects. For example, if you want to reduce
-+ the default memory requirements from 256K to 128K, compile with
-+ make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7"
-+ Of course this will generally degrade compression (there's no free lunch).
-+
-+ The memory requirements for inflate are (in bytes) 1 << windowBits
-+ that is, 32K for windowBits=15 (default value) plus a few kilobytes
-+ for small objects.
-+*/
-+
-+ /* Type declarations */
-+
-+#ifndef OF /* function prototypes */
-+# ifdef STDC
-+# define OF(args) args
-+# else
-+# define OF(args) ()
-+# endif
-+#endif
-+
-+typedef unsigned char Byte; /* 8 bits */
-+typedef unsigned int uInt; /* 16 bits or more */
-+typedef unsigned long uLong; /* 32 bits or more */
-+
-+typedef Byte FAR Bytef;
-+typedef char FAR charf;
-+typedef int FAR intf;
-+typedef uInt FAR uIntf;
-+typedef uLong FAR uLongf;
-+
-+#ifdef STDC
-+ typedef void FAR *voidpf;
-+ typedef void *voidp;
-+#else
-+ typedef Byte FAR *voidpf;
-+ typedef Byte *voidp;
-+#endif
-+
-+/* end of original zconf.h */
-+
-+#define ZLIB_VERSION "0.95P"
-+
-+/*
-+ The 'zlib' compression library provides in-memory compression and
-+ decompression functions, including integrity checks of the uncompressed
-+ data. This version of the library supports only one compression method
-+ (deflation) but other algorithms may be added later and will have the same
-+ stream interface.
-+
-+ For compression the application must provide the output buffer and
-+ may optionally provide the input buffer for optimization. For decompression,
-+ the application must provide the input buffer and may optionally provide
-+ the output buffer for optimization.
-+
-+ Compression can be done in a single step if the buffers are large
-+ enough (for example if an input file is mmap'ed), or can be done by
-+ repeated calls of the compression function. In the latter case, the
-+ application must provide more input and/or consume the output
-+ (providing more output space) before each call.
-+*/
-+
-+typedef voidpf (*alloc_func) OF((voidpf opaque, uInt items, uInt size));
-+typedef void (*free_func) OF((voidpf opaque, voidpf address, uInt nbytes));
-+
-+struct internal_state;
-+
-+typedef struct z_stream_s {
-+ Bytef *next_in; /* next input byte */
-+ uInt avail_in; /* number of bytes available at next_in */
-+ uLong total_in; /* total nb of input bytes read so far */
-+
-+ Bytef *next_out; /* next output byte should be put there */
-+ uInt avail_out; /* remaining free space at next_out */
-+ uLong total_out; /* total nb of bytes output so far */
-+
-+ char *msg; /* last error message, NULL if no error */
-+ struct internal_state FAR *state; /* not visible by applications */
-+
-+ alloc_func zalloc; /* used to allocate the internal state */
-+ free_func zfree; /* used to free the internal state */
-+ voidp opaque; /* private data object passed to zalloc and zfree */
-+
-+ Byte data_type; /* best guess about the data type: ascii or binary */
-+
-+} z_stream;
-+
-+/*
-+ The application must update next_in and avail_in when avail_in has
-+ dropped to zero. It must update next_out and avail_out when avail_out
-+ has dropped to zero. The application must initialize zalloc, zfree and
-+ opaque before calling the init function. All other fields are set by the
-+ compression library and must not be updated by the application.
-+
-+ The opaque value provided by the application will be passed as the first
-+ parameter for calls of zalloc and zfree. This can be useful for custom
-+ memory management. The compression library attaches no meaning to the
-+ opaque value.
-+
-+ zalloc must return Z_NULL if there is not enough memory for the object.
-+ On 16-bit systems, the functions zalloc and zfree must be able to allocate
-+ exactly 65536 bytes, but will not be required to allocate more than this
-+ if the symbol MAXSEG_64K is defined (see zconf.h). WARNING: On MSDOS,
-+ pointers returned by zalloc for objects of exactly 65536 bytes *must*
-+ have their offset normalized to zero. The default allocation function
-+ provided by this library ensures this (see zutil.c). To reduce memory
-+ requirements and avoid any allocation of 64K objects, at the expense of
-+ compression ratio, compile the library with -DMAX_WBITS=14 (see zconf.h).
-+
-+ The fields total_in and total_out can be used for statistics or
-+ progress reports. After compression, total_in holds the total size of
-+ the uncompressed data and may be saved for use in the decompressor
-+ (particularly if the decompressor wants to decompress everything in
-+ a single step).
-+*/
-+
-+ /* constants */
-+
-+#define Z_NO_FLUSH 0
-+#define Z_PARTIAL_FLUSH 1
-+#define Z_FULL_FLUSH 2
-+#define Z_SYNC_FLUSH 3 /* experimental: partial_flush + byte align */
-+#define Z_FINISH 4
-+#define Z_PACKET_FLUSH 5
-+/* See deflate() below for the usage of these constants */
-+
-+#define Z_OK 0
-+#define Z_STREAM_END 1
-+#define Z_ERRNO (-1)
-+#define Z_STREAM_ERROR (-2)
-+#define Z_DATA_ERROR (-3)
-+#define Z_MEM_ERROR (-4)
-+#define Z_BUF_ERROR (-5)
-+/* error codes for the compression/decompression functions */
-+
-+#define Z_BEST_SPEED 1
-+#define Z_BEST_COMPRESSION 9
-+#define Z_DEFAULT_COMPRESSION (-1)
-+/* compression levels */
-+
-+#define Z_FILTERED 1
-+#define Z_HUFFMAN_ONLY 2
-+#define Z_DEFAULT_STRATEGY 0
-+
-+#define Z_BINARY 0
-+#define Z_ASCII 1
-+#define Z_UNKNOWN 2
-+/* Used to set the data_type field */
-+
-+#define Z_NULL 0 /* for initializing zalloc, zfree, opaque */
-+
-+extern char *zlib_version;
-+/* The application can compare zlib_version and ZLIB_VERSION for consistency.
-+ If the first character differs, the library code actually used is
-+ not compatible with the zlib.h header file used by the application.
-+ */
-+
-+ /* basic functions */
-+
-+extern int inflateInit OF((z_stream *strm));
-+/*
-+ Initializes the internal stream state for decompression. The fields
-+ zalloc and zfree must be initialized before by the caller. If zalloc and
-+ zfree are set to Z_NULL, inflateInit updates them to use default allocation
-+ functions.
-+
-+ inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not
-+ enough memory. msg is set to null if there is no error message.
-+ inflateInit does not perform any decompression: this will be done by
-+ inflate().
-+*/
-+
-+
-+extern int inflate OF((z_stream *strm, int flush));
-+/*
-+ Performs one or both of the following actions:
-+
-+ - Decompress more input starting at next_in and update next_in and avail_in
-+ accordingly. If not all input can be processed (because there is not
-+ enough room in the output buffer), next_in is updated and processing
-+ will resume at this point for the next call of inflate().
-+
-+ - Provide more output starting at next_out and update next_out and avail_out
-+ accordingly. inflate() always provides as much output as possible
-+ (until there is no more input data or no more space in the output buffer).
-+
-+ Before the call of inflate(), the application should ensure that at least
-+ one of the actions is possible, by providing more input and/or consuming
-+ more output, and updating the next_* and avail_* values accordingly.
-+ The application can consume the uncompressed output when it wants, for
-+ example when the output buffer is full (avail_out == 0), or after each
-+ call of inflate().
-+
-+ If the parameter flush is set to Z_PARTIAL_FLUSH or Z_PACKET_FLUSH,
-+ inflate flushes as much output as possible to the output buffer. The
-+ flushing behavior of inflate is not specified for values of the flush
-+ parameter other than Z_PARTIAL_FLUSH, Z_PACKET_FLUSH or Z_FINISH, but the
-+ current implementation actually flushes as much output as possible
-+ anyway. For Z_PACKET_FLUSH, inflate checks that once all the input data
-+ has been consumed, it is expecting to see the length field of a stored
-+ block; if not, it returns Z_DATA_ERROR.
-+
-+ inflate() should normally be called until it returns Z_STREAM_END or an
-+ error. However if all decompression is to be performed in a single step
-+ (a single call of inflate), the parameter flush should be set to
-+ Z_FINISH. In this case all pending input is processed and all pending
-+ output is flushed; avail_out must be large enough to hold all the
-+ uncompressed data. (The size of the uncompressed data may have been saved
-+ by the compressor for this purpose.) The next operation on this stream must
-+ be inflateEnd to deallocate the decompression state. The use of Z_FINISH
-+ is never required, but can be used to inform inflate that a faster routine
-+ may be used for the single inflate() call.
-+
-+ inflate() returns Z_OK if some progress has been made (more input
-+ processed or more output produced), Z_STREAM_END if the end of the
-+ compressed data has been reached and all uncompressed output has been
-+ produced, Z_DATA_ERROR if the input data was corrupted, Z_STREAM_ERROR if
-+ the stream structure was inconsistent (for example if next_in or next_out
-+ was NULL), Z_MEM_ERROR if there was not enough memory, Z_BUF_ERROR if no
-+ progress is possible or if there was not enough room in the output buffer
-+ when Z_FINISH is used. In the Z_DATA_ERROR case, the application may then
-+ call inflateSync to look for a good compression block. */
-+
-+
-+extern int inflateEnd OF((z_stream *strm));
-+/*
-+ All dynamically allocated data structures for this stream are freed.
-+ This function discards any unprocessed input and does not flush any
-+ pending output.
-+
-+ inflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state
-+ was inconsistent. In the error case, msg may be set but then points to a
-+ static string (which must not be deallocated).
-+*/
-+
-+ /* advanced functions */
-+
-+extern int inflateInit2 OF((z_stream *strm,
-+ int windowBits));
-+/*
-+ This is another version of inflateInit with more compression options. The
-+ fields next_out, zalloc and zfree must be initialized before by the caller.
-+
-+ The windowBits parameter is the base two logarithm of the maximum window
-+ size (the size of the history buffer). It should be in the range 8..15 for
-+ this version of the library (the value 16 will be allowed soon). The
-+ default value is 15 if inflateInit is used instead. If a compressed stream
-+ with a larger window size is given as input, inflate() will return with
-+ the error code Z_DATA_ERROR instead of trying to allocate a larger window.
-+
-+ If next_out is not null, the library will use this buffer for the history
-+ buffer; the buffer must either be large enough to hold the entire output
-+ data, or have at least 1<<windowBits bytes. If next_out is null, the
-+ library will allocate its own buffer (and leave next_out null). next_in
-+ need not be provided here but must be provided by the application for the
-+ next call of inflate().
-+
-+ If the history buffer is provided by the application, next_out must
-+ never be changed by the application since the decompressor maintains
-+ history information inside this buffer from call to call; the application
-+ can only reset next_out to the beginning of the history buffer when
-+ avail_out is zero and all output has been consumed.
-+
-+ inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was
-+ not enough memory, Z_STREAM_ERROR if a parameter is invalid (such as
-+ windowBits < 8). msg is set to null if there is no error message.
-+ inflateInit2 does not perform any decompression: this will be done by
-+ inflate().
-+*/
-+
-+extern int inflateSync OF((z_stream *strm));
-+/*
-+ Skips invalid compressed data until the special marker (see deflate()
-+ above) can be found, or until all available input is skipped. No output
-+ is provided.
-+
-+ inflateSync returns Z_OK if the special marker has been found, Z_BUF_ERROR
-+ if no more input was provided, Z_DATA_ERROR if no marker has been found,
-+ or Z_STREAM_ERROR if the stream structure was inconsistent. In the success
-+ case, the application may save the current current value of total_in which
-+ indicates where valid compressed data was found. In the error case, the
-+ application may repeatedly call inflateSync, providing more input each time,
-+ until success or end of the input data.
-+*/
-+
-+extern int inflateReset OF((z_stream *strm));
-+/*
-+ This function is equivalent to inflateEnd followed by inflateInit,
-+ but does not free and reallocate all the internal decompression state.
-+ The stream will keep attributes that may have been set by inflateInit2.
-+
-+ inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source
-+ stream state was inconsistent (such as zalloc or state being NULL).
-+*/
-+
-+extern int inflateIncomp OF((z_stream *strm));
-+/*
-+ This function adds the data at next_in (avail_in bytes) to the output
-+ history without performing any output. There must be no pending output,
-+ and the decompressor must be expecting to see the start of a block.
-+ Calling this function is equivalent to decompressing a stored block
-+ containing the data at next_in (except that the data is not output).
-+*/
-+
-+ /* checksum functions */
-+
-+/*
-+ This function is not related to compression but is exported
-+ anyway because it might be useful in applications using the
-+ compression library.
-+*/
-+
-+extern uLong adler32 OF((uLong adler, Bytef *buf, uInt len));
-+
-+/*
-+ Update a running Adler-32 checksum with the bytes buf[0..len-1] and
-+ return the updated checksum. If buf is NULL, this function returns
-+ the required initial value for the checksum.
-+ An Adler-32 checksum is almost as reliable as a CRC32 but can be computed
-+ much faster. Usage example:
-+
-+ uLong adler = adler32(0L, Z_NULL, 0);
-+
-+ while (read_buffer(buffer, length) != EOF) {
-+ adler = adler32(adler, buffer, length);
-+ }
-+ if (adler != original_adler) error();
-+*/
-+
-+#ifndef _Z_UTIL_H
-+ struct internal_state {int dummy;}; /* hack for buggy compilers */
-+#endif
-+
-+#endif /* _ZLIB_H */
-diff -Naru linux/arch/mips/zboot/ld.script linux.spi/arch/mips/zboot/ld.script
---- linux/arch/mips/zboot/ld.script 1969-12-31 19:00:00.000000000 -0500
-+++ linux.spi/arch/mips/zboot/ld.script 2004-05-11 23:19:24.000000000 -0400
-@@ -0,0 +1,151 @@
-+OUTPUT_ARCH(mips)
-+ENTRY(start)
-+SECTIONS
-+{
-+ /* Read-only sections, merged into text segment: */
-+ /* . = 0x81000000; */
-+ .init : { *(.init) } =0
-+ .text :
-+ {
-+ _ftext = . ;
-+ *(.text)
-+ *(.rodata)
-+ *(.rodata1)
-+ /* .gnu.warning sections are handled specially by elf32.em. */
-+ *(.gnu.warning)
-+ } =0
-+ .kstrtab : { *(.kstrtab) }
-+
-+ . = ALIGN(16); /* Exception table */
-+ __start___ex_table = .;
-+ __ex_table : { *(__ex_table) }
-+ __stop___ex_table = .;
-+
-+ __start___dbe_table = .; /* Exception table for data bus errors */
-+ __dbe_table : { *(__dbe_table) }
-+ __stop___dbe_table = .;
-+
-+ __start___ksymtab = .; /* Kernel symbol table */
-+ __ksymtab : { *(__ksymtab) }
-+ __stop___ksymtab = .;
-+
-+ _etext = .;
-+
-+ . = ALIGN(8192);
-+ .data.init_task : { *(.data.init_task) }
-+
-+ /* Startup code */
-+ . = ALIGN(4096);
-+ __init_begin = .;
-+ .text.init : { *(.text.init) }
-+ .data.init : { *(.data.init) }
-+ . = ALIGN(16);
-+ __setup_start = .;
-+ .setup.init : { *(.setup.init) }
-+ __setup_end = .;
-+ __initcall_start = .;
-+ .initcall.init : { *(.initcall.init) }
-+ __initcall_end = .;
-+ . = ALIGN(4096); /* Align double page for init_task_union */
-+ __init_end = .;
-+
-+ . = ALIGN(4096);
-+ .data.page_aligned : { *(.data.idt) }
-+
-+ . = ALIGN(32);
-+ .data.cacheline_aligned : { *(.data.cacheline_aligned) }
-+
-+ .fini : { *(.fini) } =0
-+ .reginfo : { *(.reginfo) }
-+ /* Adjust the address for the data segment. We want to adjust up to
-+ the same address within the page on the next page up. It would
-+ be more correct to do this:
-+ . = .;
-+ The current expression does not correctly handle the case of a
-+ text segment ending precisely at the end of a page; it causes the
-+ data segment to skip a page. The above expression does not have
-+ this problem, but it will currently (2/95) cause BFD to allocate
-+ a single segment, combining both text and data, for this case.
-+ This will prevent the text segment from being shared among
-+ multiple executions of the program; I think that is more
-+ important than losing a page of the virtual address space (note
-+ that no actual memory is lost; the page which is skipped can not
-+ be referenced). */
-+ . = .;
-+ .data :
-+ {
-+ _fdata = . ;
-+ *(.data)
-+
-+ /* Put the compressed image here, so bss is on the end. */
-+ __image_begin = .;
-+ *(.image)
-+ __image_end = .;
-+ /* Align the initial ramdisk image (INITRD) on page boundaries. */
-+ . = ALIGN(4096);
-+ __ramdisk_begin = .;
-+ *(.initrd)
-+ __ramdisk_end = .;
-+ . = ALIGN(4096);
-+
-+ CONSTRUCTORS
-+ }
-+ .data1 : { *(.data1) }
-+ _gp = . + 0x8000;
-+ .lit8 : { *(.lit8) }
-+ .lit4 : { *(.lit4) }
-+ .ctors : { *(.ctors) }
-+ .dtors : { *(.dtors) }
-+ .got : { *(.got.plt) *(.got) }
-+ .dynamic : { *(.dynamic) }
-+ /* We want the small data sections together, so single-instruction offsets
-+ can access them all, and initialized data all before uninitialized, so
-+ we can shorten the on-disk segment size. */
-+ .sdata : { *(.sdata) }
-+ . = ALIGN(4);
-+ _edata = .;
-+ PROVIDE (edata = .);
-+
-+ __bss_start = .;
-+ _fbss = .;
-+ .sbss : { *(.sbss) *(.scommon) }
-+ .bss :
-+ {
-+ *(.dynbss)
-+ *(.bss)
-+ *(COMMON)
-+ . = ALIGN(4);
-+ _end = . ;
-+ PROVIDE (end = .);
-+ }
-+
-+ /* Sections to be discarded */
-+ /DISCARD/ :
-+ {
-+ *(.text.exit)
-+ *(.data.exit)
-+ *(.exitcall.exit)
-+ }
-+
-+ /* This is the MIPS specific mdebug section. */
-+ .mdebug : { *(.mdebug) }
-+ /* These are needed for ELF backends which have not yet been
-+ converted to the new style linker. */
-+ .stab 0 : { *(.stab) }
-+ .stabstr 0 : { *(.stabstr) }
-+ /* DWARF debug sections.
-+ Symbols in the .debug DWARF section are relative to the beginning of the
-+ section so we begin .debug at 0. It's not clear yet what needs to happen
-+ for the others. */
-+ .debug 0 : { *(.debug) }
-+ .debug_srcinfo 0 : { *(.debug_srcinfo) }
-+ .debug_aranges 0 : { *(.debug_aranges) }
-+ .debug_pubnames 0 : { *(.debug_pubnames) }
-+ .debug_sfnames 0 : { *(.debug_sfnames) }
-+ .line 0 : { *(.line) }
-+ /* These must appear regardless of . */
-+ .gptab.sdata : { *(.gptab.data) *(.gptab.sdata) }
-+ .gptab.sbss : { *(.gptab.bss) *(.gptab.sbss) }
-+ .comment : { *(.comment) }
-+ .note : { *(.note) }
-+}
-diff -Naru linux/arch/mips/zboot/lib/Makefile linux.spi/arch/mips/zboot/lib/Makefile
---- linux/arch/mips/zboot/lib/Makefile 1969-12-31 19:00:00.000000000 -0500
-+++ linux.spi/arch/mips/zboot/lib/Makefile 2004-05-11 23:19:24.000000000 -0400
-@@ -0,0 +1,9 @@
-+#
-+# Makefile for some libs needed by zImage.
-+#
-+
-+L_TARGET := zlib.a
-+
-+obj-y := zlib.o
-+
-+include $(TOPDIR)/Rules.make
-diff -Naru linux/arch/mips/zboot/lib/zlib.c linux.spi/arch/mips/zboot/lib/zlib.c
---- linux/arch/mips/zboot/lib/zlib.c 1969-12-31 19:00:00.000000000 -0500
-+++ linux.spi/arch/mips/zboot/lib/zlib.c 2004-05-11 23:19:24.000000000 -0400
-@@ -0,0 +1,2148 @@
-+/*
-+ * This file is derived from various .h and .c files from the zlib-0.95
-+ * distribution by Jean-loup Gailly and Mark Adler, with some additions
-+ * by Paul Mackerras to aid in implementing Deflate compression and
-+ * decompression for PPP packets. See zlib.h for conditions of
-+ * distribution and use.
-+ *
-+ * Changes that have been made include:
-+ * - changed functions not used outside this file to "local"
-+ * - added minCompression parameter to deflateInit2
-+ * - added Z_PACKET_FLUSH (see zlib.h for details)
-+ * - added inflateIncomp
-+ *
-+ * $Id: zlib.c,v 1.2 2002/02/16 16:55:45 ppopov Exp $
-+ */
-+
-+/*+++++*/
-+/* zutil.h -- internal interface and configuration of the compression library
-+ * Copyright (C) 1995 Jean-loup Gailly.
-+ * For conditions of distribution and use, see copyright notice in zlib.h
-+ */
-+
-+/* WARNING: this file should *not* be used by applications. It is
-+ part of the implementation of the compression library and is
-+ subject to change. Applications should only use zlib.h.
-+ */
-+
-+/* From: zutil.h,v 1.9 1995/05/03 17:27:12 jloup Exp */
-+
-+#define _Z_UTIL_H
-+
-+#include "zlib.h"
-+
-+#ifndef local
-+# define local static
-+#endif
-+/* compile with -Dlocal if your debugger can't find static symbols */
-+
-+#define FAR
-+
-+typedef unsigned char uch;
-+typedef uch FAR uchf;
-+typedef unsigned short ush;
-+typedef ush FAR ushf;
-+typedef unsigned long ulg;
-+
-+extern char *z_errmsg[]; /* indexed by 1-zlib_error */
-+
-+#define ERR_RETURN(strm,err) return (strm->msg=z_errmsg[1-err], err)
-+/* To be used only when the state is known to be valid */
-+
-+#ifndef NULL
-+#define NULL ((void *) 0)
-+#endif
-+
-+ /* common constants */
-+
-+#define DEFLATED 8
-+
-+#ifndef DEF_WBITS
-+# define DEF_WBITS MAX_WBITS
-+#endif
-+/* default windowBits for decompression. MAX_WBITS is for compression only */
-+
-+#if MAX_MEM_LEVEL >= 8
-+# define DEF_MEM_LEVEL 8
-+#else
-+# define DEF_MEM_LEVEL MAX_MEM_LEVEL
-+#endif
-+/* default memLevel */
-+
-+#define STORED_BLOCK 0
-+#define STATIC_TREES 1
-+#define DYN_TREES 2
-+/* The three kinds of block type */
-+
-+#define MIN_MATCH 3
-+#define MAX_MATCH 258
-+/* The minimum and maximum match lengths */
-+
-+ /* functions */
-+
-+#include <linux/string.h>
-+#define zmemcpy memcpy
-+#define zmemzero(dest, len) memset(dest, 0, len)
-+
-+/* Diagnostic functions */
-+#ifdef DEBUG_ZLIB
-+# include <stdio.h>
-+# ifndef verbose
-+# define verbose 0
-+# endif
-+# define Assert(cond,msg) {if(!(cond)) z_error(msg);}
-+# define Trace(x) fprintf x
-+# define Tracev(x) {if (verbose) fprintf x ;}
-+# define Tracevv(x) {if (verbose>1) fprintf x ;}
-+# define Tracec(c,x) {if (verbose && (c)) fprintf x ;}
-+# define Tracecv(c,x) {if (verbose>1 && (c)) fprintf x ;}
-+#else
-+# define Assert(cond,msg)
-+# define Trace(x)
-+# define Tracev(x)
-+# define Tracevv(x)
-+# define Tracec(c,x)
-+# define Tracecv(c,x)
-+#endif
-+
-+
-+typedef uLong (*check_func) OF((uLong check, Bytef *buf, uInt len));
-+
-+/* voidpf zcalloc OF((voidpf opaque, unsigned items, unsigned size)); */
-+/* void zcfree OF((voidpf opaque, voidpf ptr)); */
-+
-+#define ZALLOC(strm, items, size) \
-+ (*((strm)->zalloc))((strm)->opaque, (items), (size))
-+#define ZFREE(strm, addr, size) \
-+ (*((strm)->zfree))((strm)->opaque, (voidpf)(addr), (size))
-+#define TRY_FREE(s, p, n) {if (p) ZFREE(s, p, n);}
-+
-+/* deflate.h -- internal compression state
-+ * Copyright (C) 1995 Jean-loup Gailly
-+ * For conditions of distribution and use, see copyright notice in zlib.h
-+ */
-+
-+/* WARNING: this file should *not* be used by applications. It is
-+ part of the implementation of the compression library and is
-+ subject to change. Applications should only use zlib.h.
-+ */
-+
-+/*+++++*/
-+/* infblock.h -- header to use infblock.c
-+ * Copyright (C) 1995 Mark Adler
-+ * For conditions of distribution and use, see copyright notice in zlib.h
-+ */
-+
-+/* WARNING: this file should *not* be used by applications. It is
-+ part of the implementation of the compression library and is
-+ subject to change. Applications should only use zlib.h.
-+ */
-+
-+struct inflate_blocks_state;
-+typedef struct inflate_blocks_state FAR inflate_blocks_statef;
-+
-+local inflate_blocks_statef * inflate_blocks_new OF((
-+ z_stream *z,
-+ check_func c, /* check function */
-+ uInt w)); /* window size */
-+
-+local int inflate_blocks OF((
-+ inflate_blocks_statef *,
-+ z_stream *,
-+ int)); /* initial return code */
-+
-+local void inflate_blocks_reset OF((
-+ inflate_blocks_statef *,
-+ z_stream *,
-+ uLongf *)); /* check value on output */
-+
-+local int inflate_blocks_free OF((
-+ inflate_blocks_statef *,
-+ z_stream *,
-+ uLongf *)); /* check value on output */
-+
-+local int inflate_addhistory OF((
-+ inflate_blocks_statef *,
-+ z_stream *));
-+
-+local int inflate_packet_flush OF((
-+ inflate_blocks_statef *));
-+
-+/*+++++*/
-+/* inftrees.h -- header to use inftrees.c
-+ * Copyright (C) 1995 Mark Adler
-+ * For conditions of distribution and use, see copyright notice in zlib.h
-+ */
-+
-+/* WARNING: this file should *not* be used by applications. It is
-+ part of the implementation of the compression library and is
-+ subject to change. Applications should only use zlib.h.
-+ */
-+
-+/* Huffman code lookup table entry--this entry is four bytes for machines
-+ that have 16-bit pointers (e.g. PC's in the small or medium model). */
-+
-+typedef struct inflate_huft_s FAR inflate_huft;
-+
-+struct inflate_huft_s {
-+ union {
-+ struct {
-+ Byte Exop; /* number of extra bits or operation */
-+ Byte Bits; /* number of bits in this code or subcode */
-+ } what;
-+ uInt Nalloc; /* number of these allocated here */
-+ Bytef *pad; /* pad structure to a power of 2 (4 bytes for */
-+ } word; /* 16-bit, 8 bytes for 32-bit machines) */
-+ union {
-+ uInt Base; /* literal, length base, or distance base */
-+ inflate_huft *Next; /* pointer to next level of table */
-+ } more;
-+};
-+
-+#ifdef DEBUG_ZLIB
-+ local uInt inflate_hufts;
-+#endif
-+
-+local int inflate_trees_bits OF((
-+ uIntf *, /* 19 code lengths */
-+ uIntf *, /* bits tree desired/actual depth */
-+ inflate_huft * FAR *, /* bits tree result */
-+ z_stream *)); /* for zalloc, zfree functions */
-+
-+local int inflate_trees_dynamic OF((
-+ uInt, /* number of literal/length codes */
-+ uInt, /* number of distance codes */
-+ uIntf *, /* that many (total) code lengths */
-+ uIntf *, /* literal desired/actual bit depth */
-+ uIntf *, /* distance desired/actual bit depth */
-+ inflate_huft * FAR *, /* literal/length tree result */
-+ inflate_huft * FAR *, /* distance tree result */
-+ z_stream *)); /* for zalloc, zfree functions */
-+
-+local int inflate_trees_fixed OF((
-+ uIntf *, /* literal desired/actual bit depth */
-+ uIntf *, /* distance desired/actual bit depth */
-+ inflate_huft * FAR *, /* literal/length tree result */
-+ inflate_huft * FAR *)); /* distance tree result */
-+
-+local int inflate_trees_free OF((
-+ inflate_huft *, /* tables to free */
-+ z_stream *)); /* for zfree function */
-+
-+
-+/*+++++*/
-+/* infcodes.h -- header to use infcodes.c
-+ * Copyright (C) 1995 Mark Adler
-+ * For conditions of distribution and use, see copyright notice in zlib.h
-+ */
-+
-+/* WARNING: this file should *not* be used by applications. It is
-+ part of the implementation of the compression library and is
-+ subject to change. Applications should only use zlib.h.
-+ */
-+
-+struct inflate_codes_state;
-+typedef struct inflate_codes_state FAR inflate_codes_statef;
-+
-+local inflate_codes_statef *inflate_codes_new OF((
-+ uInt, uInt,
-+ inflate_huft *, inflate_huft *,
-+ z_stream *));
-+
-+local int inflate_codes OF((
-+ inflate_blocks_statef *,
-+ z_stream *,
-+ int));
-+
-+local void inflate_codes_free OF((
-+ inflate_codes_statef *,
-+ z_stream *));
-+
-+
-+/*+++++*/
-+/* inflate.c -- zlib interface to inflate modules
-+ * Copyright (C) 1995 Mark Adler
-+ * For conditions of distribution and use, see copyright notice in zlib.h
-+ */
-+
-+/* inflate private state */
-+struct internal_state {
-+
-+ /* mode */
-+ enum {
-+ METHOD, /* waiting for method byte */
-+ FLAG, /* waiting for flag byte */
-+ BLOCKS, /* decompressing blocks */
-+ CHECK4, /* four check bytes to go */
-+ CHECK3, /* three check bytes to go */
-+ CHECK2, /* two check bytes to go */
-+ CHECK1, /* one check byte to go */
-+ DONE, /* finished check, done */
-+ BAD} /* got an error--stay here */
-+ mode; /* current inflate mode */
-+
-+ /* mode dependent information */
-+ union {
-+ uInt method; /* if FLAGS, method byte */
-+ struct {
-+ uLong was; /* computed check value */
-+ uLong need; /* stream check value */
-+ } check; /* if CHECK, check values to compare */
-+ uInt marker; /* if BAD, inflateSync's marker bytes count */
-+ } sub; /* submode */
-+
-+ /* mode independent information */
-+ int nowrap; /* flag for no wrapper */
-+ uInt wbits; /* log2(window size) (8..15, defaults to 15) */
-+ inflate_blocks_statef
-+ *blocks; /* current inflate_blocks state */
-+
-+};
-+
-+
-+int inflateReset(z)
-+z_stream *z;
-+{
-+ uLong c;
-+
-+ if (z == Z_NULL || z->state == Z_NULL)
-+ return Z_STREAM_ERROR;
-+ z->total_in = z->total_out = 0;
-+ z->msg = Z_NULL;
-+ z->state->mode = z->state->nowrap ? BLOCKS : METHOD;
-+ inflate_blocks_reset(z->state->blocks, z, &c);
-+ Trace((stderr, "inflate: reset\n"));
-+ return Z_OK;
-+}
-+
-+
-+int inflateEnd(z)
-+z_stream *z;
-+{
-+ uLong c;
-+
-+ if (z == Z_NULL || z->state == Z_NULL || z->zfree == Z_NULL)
-+ return Z_STREAM_ERROR;
-+ if (z->state->blocks != Z_NULL)
-+ inflate_blocks_free(z->state->blocks, z, &c);
-+ ZFREE(z, z->state, sizeof(struct internal_state));
-+ z->state = Z_NULL;
-+ Trace((stderr, "inflate: end\n"));
-+ return Z_OK;
-+}
-+
-+
-+int inflateInit2(z, w)
-+z_stream *z;
-+int w;
-+{
-+ /* initialize state */
-+ if (z == Z_NULL)
-+ return Z_STREAM_ERROR;
-+/* if (z->zalloc == Z_NULL) z->zalloc = zcalloc; */
-+/* if (z->zfree == Z_NULL) z->zfree = zcfree; */
-+ if ((z->state = (struct internal_state FAR *)
-+ ZALLOC(z,1,sizeof(struct internal_state))) == Z_NULL)
-+ return Z_MEM_ERROR;
-+ z->state->blocks = Z_NULL;
-+
-+ /* handle undocumented nowrap option (no zlib header or check) */
-+ z->state->nowrap = 0;
-+ if (w < 0)
-+ {
-+ w = - w;
-+ z->state->nowrap = 1;
-+ }
-+
-+ /* set window size */
-+ if (w < 8 || w > 15)
-+ {
-+ inflateEnd(z);
-+ return Z_STREAM_ERROR;
-+ }
-+ z->state->wbits = (uInt)w;
-+
-+ /* create inflate_blocks state */
-+ if ((z->state->blocks =
-+ inflate_blocks_new(z, z->state->nowrap ? Z_NULL : adler32, 1 << w))
-+ == Z_NULL)
-+ {
-+ inflateEnd(z);
-+ return Z_MEM_ERROR;
-+ }
-+ Trace((stderr, "inflate: allocated\n"));
-+
-+ /* reset state */
-+ inflateReset(z);
-+ return Z_OK;
-+}
-+
-+
-+int inflateInit(z)
-+z_stream *z;
-+{
-+ return inflateInit2(z, DEF_WBITS);
-+}
-+
-+
-+#define NEEDBYTE {if(z->avail_in==0)goto empty;r=Z_OK;}
-+#define NEXTBYTE (z->avail_in--,z->total_in++,*z->next_in++)
-+
-+int inflate(z, f)
-+z_stream *z;
-+int f;
-+{
-+ int r;
-+ uInt b;
-+
-+ if (z == Z_NULL || z->next_in == Z_NULL)
-+ return Z_STREAM_ERROR;
-+ r = Z_BUF_ERROR;
-+ while (1) switch (z->state->mode)
-+ {
-+ case METHOD:
-+ NEEDBYTE
-+ if (((z->state->sub.method = NEXTBYTE) & 0xf) != DEFLATED)
-+ {
-+ z->state->mode = BAD;
-+ z->msg = "unknown compression method";
-+ z->state->sub.marker = 5; /* can't try inflateSync */
-+ break;
-+ }
-+ if ((z->state->sub.method >> 4) + 8 > z->state->wbits)
-+ {
-+ z->state->mode = BAD;
-+ z->msg = "invalid window size";
-+ z->state->sub.marker = 5; /* can't try inflateSync */
-+ break;
-+ }
-+ z->state->mode = FLAG;
-+ case FLAG:
-+ NEEDBYTE
-+ if ((b = NEXTBYTE) & 0x20)
-+ {
-+ z->state->mode = BAD;
-+ z->msg = "invalid reserved bit";
-+ z->state->sub.marker = 5; /* can't try inflateSync */
-+ break;
-+ }
-+ if (((z->state->sub.method << 8) + b) % 31)
-+ {
-+ z->state->mode = BAD;
-+ z->msg = "incorrect header check";
-+ z->state->sub.marker = 5; /* can't try inflateSync */
-+ break;
-+ }
-+ Trace((stderr, "inflate: zlib header ok\n"));
-+ z->state->mode = BLOCKS;
-+ case BLOCKS:
-+ r = inflate_blocks(z->state->blocks, z, r);
-+ if (f == Z_PACKET_FLUSH && z->avail_in == 0 && z->avail_out != 0)
-+ r = inflate_packet_flush(z->state->blocks);
-+ if (r == Z_DATA_ERROR)
-+ {
-+ z->state->mode = BAD;
-+ z->state->sub.marker = 0; /* can try inflateSync */
-+ break;
-+ }
-+ if (r != Z_STREAM_END)
-+ return r;
-+ r = Z_OK;
-+ inflate_blocks_reset(z->state->blocks, z, &z->state->sub.check.was);
-+ if (z->state->nowrap)
-+ {
-+ z->state->mode = DONE;
-+ break;
-+ }
-+ z->state->mode = CHECK4;
-+ case CHECK4:
-+ NEEDBYTE
-+ z->state->sub.check.need = (uLong)NEXTBYTE << 24;
-+ z->state->mode = CHECK3;
-+ case CHECK3:
-+ NEEDBYTE
-+ z->state->sub.check.need += (uLong)NEXTBYTE << 16;
-+ z->state->mode = CHECK2;
-+ case CHECK2:
-+ NEEDBYTE
-+ z->state->sub.check.need += (uLong)NEXTBYTE << 8;
-+ z->state->mode = CHECK1;
-+ case CHECK1:
-+ NEEDBYTE
-+ z->state->sub.check.need += (uLong)NEXTBYTE;
-+
-+ if (z->state->sub.check.was != z->state->sub.check.need)
-+ {
-+ z->state->mode = BAD;
-+ z->msg = "incorrect data check";
-+ z->state->sub.marker = 5; /* can't try inflateSync */
-+ break;
-+ }
-+ Trace((stderr, "inflate: zlib check ok\n"));
-+ z->state->mode = DONE;
-+ case DONE:
-+ return Z_STREAM_END;
-+ case BAD:
-+ return Z_DATA_ERROR;
-+ default:
-+ return Z_STREAM_ERROR;
-+ }
-+
-+ empty:
-+ if (f != Z_PACKET_FLUSH)
-+ return r;
-+ z->state->mode = BAD;
-+ z->state->sub.marker = 0; /* can try inflateSync */
-+ return Z_DATA_ERROR;
-+}
-+
-+/*
-+ * This subroutine adds the data at next_in/avail_in to the output history
-+ * without performing any output. The output buffer must be "caught up";
-+ * i.e. no pending output (hence s->read equals s->write), and the state must
-+ * be BLOCKS (i.e. we should be willing to see the start of a series of
-+ * BLOCKS). On exit, the output will also be caught up, and the checksum
-+ * will have been updated if need be.
-+ */
-+
-+int inflateIncomp(z)
-+z_stream *z;
-+{
-+ if (z->state->mode != BLOCKS)
-+ return Z_DATA_ERROR;
-+ return inflate_addhistory(z->state->blocks, z);
-+}
-+
-+
-+int inflateSync(z)
-+z_stream *z;
-+{
-+ uInt n; /* number of bytes to look at */
-+ Bytef *p; /* pointer to bytes */
-+ uInt m; /* number of marker bytes found in a row */
-+ uLong r, w; /* temporaries to save total_in and total_out */
-+
-+ /* set up */
-+ if (z == Z_NULL || z->state == Z_NULL)
-+ return Z_STREAM_ERROR;
-+ if (z->state->mode != BAD)
-+ {
-+ z->state->mode = BAD;
-+ z->state->sub.marker = 0;
-+ }
-+ if ((n = z->avail_in) == 0)
-+ return Z_BUF_ERROR;
-+ p = z->next_in;
-+ m = z->state->sub.marker;
-+
-+ /* search */
-+ while (n && m < 4)
-+ {
-+ if (*p == (Byte)(m < 2 ? 0 : 0xff))
-+ m++;
-+ else if (*p)
-+ m = 0;
-+ else
-+ m = 4 - m;
-+ p++, n--;
-+ }
-+
-+ /* restore */
-+ z->total_in += p - z->next_in;
-+ z->next_in = p;
-+ z->avail_in = n;
-+ z->state->sub.marker = m;
-+
-+ /* return no joy or set up to restart on a new block */
-+ if (m != 4)
-+ return Z_DATA_ERROR;
-+ r = z->total_in; w = z->total_out;
-+ inflateReset(z);
-+ z->total_in = r; z->total_out = w;
-+ z->state->mode = BLOCKS;
-+ return Z_OK;
-+}
-+
-+#undef NEEDBYTE
-+#undef NEXTBYTE
-+
-+/*+++++*/
-+/* infutil.h -- types and macros common to blocks and codes
-+ * Copyright (C) 1995 Mark Adler
-+ * For conditions of distribution and use, see copyright notice in zlib.h
-+ */
-+
-+/* WARNING: this file should *not* be used by applications. It is
-+ part of the implementation of the compression library and is
-+ subject to change. Applications should only use zlib.h.
-+ */
-+
-+/* inflate blocks semi-private state */
-+struct inflate_blocks_state {
-+
-+ /* mode */
-+ enum {
-+ TYPE, /* get type bits (3, including end bit) */
-+ LENS, /* get lengths for stored */
-+ STORED, /* processing stored block */
-+ TABLE, /* get table lengths */
-+ BTREE, /* get bit lengths tree for a dynamic block */
-+ DTREE, /* get length, distance trees for a dynamic block */
-+ CODES, /* processing fixed or dynamic block */
-+ DRY, /* output remaining window bytes */
-+ DONEB, /* finished last block, done */
-+ BADB} /* got a data error--stuck here */
-+ mode; /* current inflate_block mode */
-+
-+ /* mode dependent information */
-+ union {
-+ uInt left; /* if STORED, bytes left to copy */
-+ struct {
-+ uInt table; /* table lengths (14 bits) */
-+ uInt index; /* index into blens (or border) */
-+ uIntf *blens; /* bit lengths of codes */
-+ uInt bb; /* bit length tree depth */
-+ inflate_huft *tb; /* bit length decoding tree */
-+ int nblens; /* # elements allocated at blens */
-+ } trees; /* if DTREE, decoding info for trees */
-+ struct {
-+ inflate_huft *tl, *td; /* trees to free */
-+ inflate_codes_statef
-+ *codes;
-+ } decode; /* if CODES, current state */
-+ } sub; /* submode */
-+ uInt last; /* true if this block is the last block */
-+
-+ /* mode independent information */
-+ uInt bitk; /* bits in bit buffer */
-+ uLong bitb; /* bit buffer */
-+ Bytef *window; /* sliding window */
-+ Bytef *end; /* one byte after sliding window */
-+ Bytef *read; /* window read pointer */
-+ Bytef *write; /* window write pointer */
-+ check_func checkfn; /* check function */
-+ uLong check; /* check on output */
-+
-+};
-+
-+
-+/* defines for inflate input/output */
-+/* update pointers and return */
-+#define UPDBITS {s->bitb=b;s->bitk=k;}
-+#define UPDIN {z->avail_in=n;z->total_in+=p-z->next_in;z->next_in=p;}
-+#define UPDOUT {s->write=q;}
-+#define UPDATE {UPDBITS UPDIN UPDOUT}
-+#define LEAVE {UPDATE return inflate_flush(s,z,r);}
-+/* get bytes and bits */
-+#define LOADIN {p=z->next_in;n=z->avail_in;b=s->bitb;k=s->bitk;}
-+#define NEEDBYTE {if(n)r=Z_OK;else LEAVE}
-+#define NEXTBYTE (n--,*p++)
-+#define NEEDBITS(j) {while(k<(j)){NEEDBYTE;b|=((uLong)NEXTBYTE)<<k;k+=8;}}
-+#define DUMPBITS(j) {b>>=(j);k-=(j);}
-+/* output bytes */
-+#define WAVAIL (q<s->read?s->read-q-1:s->end-q)
-+#define LOADOUT {q=s->write;m=WAVAIL;}
-+#define WRAP {if(q==s->end&&s->read!=s->window){q=s->window;m=WAVAIL;}}
-+#define FLUSH {UPDOUT r=inflate_flush(s,z,r); LOADOUT}
-+#define NEEDOUT {if(m==0){WRAP if(m==0){FLUSH WRAP if(m==0) LEAVE}}r=Z_OK;}
-+#define OUTBYTE(a) {*q++=(Byte)(a);m--;}
-+/* load local pointers */
-+#define LOAD {LOADIN LOADOUT}
-+
-+/*
-+ * The IBM 150 firmware munges the data right after _etext[]. This
-+ * protects it. -- Cort
-+ */
-+local uInt protect_mask[] = {0, 0, 0, 0, 0, 0, 0, 0, 0 ,0 ,0 ,0};
-+/* And'ing with mask[n] masks the lower n bits */
-+local uInt inflate_mask[] = {
-+ 0x0000,
-+ 0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff,
-+ 0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff
-+};
-+
-+/* copy as much as possible from the sliding window to the output area */
-+local int inflate_flush OF((
-+ inflate_blocks_statef *,
-+ z_stream *,
-+ int));
-+
-+/*+++++*/
-+/* inffast.h -- header to use inffast.c
-+ * Copyright (C) 1995 Mark Adler
-+ * For conditions of distribution and use, see copyright notice in zlib.h
-+ */
-+
-+/* WARNING: this file should *not* be used by applications. It is
-+ part of the implementation of the compression library and is
-+ subject to change. Applications should only use zlib.h.
-+ */
-+
-+local int inflate_fast OF((
-+ uInt,
-+ uInt,
-+ inflate_huft *,
-+ inflate_huft *,
-+ inflate_blocks_statef *,
-+ z_stream *));
-+
-+
-+/*+++++*/
-+/* infblock.c -- interpret and process block types to last block
-+ * Copyright (C) 1995 Mark Adler
-+ * For conditions of distribution and use, see copyright notice in zlib.h
-+ */
-+
-+/* Table for deflate from PKZIP's appnote.txt. */
-+local uInt border[] = { /* Order of the bit length code lengths */
-+ 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15};
-+
-+/*
-+ Notes beyond the 1.93a appnote.txt:
-+
-+ 1. Distance pointers never point before the beginning of the output
-+ stream.
-+ 2. Distance pointers can point back across blocks, up to 32k away.
-+ 3. There is an implied maximum of 7 bits for the bit length table and
-+ 15 bits for the actual data.
-+ 4. If only one code exists, then it is encoded using one bit. (Zero
-+ would be more efficient, but perhaps a little confusing.) If two
-+ codes exist, they are coded using one bit each (0 and 1).
-+ 5. There is no way of sending zero distance codes--a dummy must be
-+ sent if there are none. (History: a pre 2.0 version of PKZIP would
-+ store blocks with no distance codes, but this was discovered to be
-+ too harsh a criterion.) Valid only for 1.93a. 2.04c does allow
-+ zero distance codes, which is sent as one code of zero bits in
-+ length.
-+ 6. There are up to 286 literal/length codes. Code 256 represents the
-+ end-of-block. Note however that the static length tree defines
-+ 288 codes just to fill out the Huffman codes. Codes 286 and 287
-+ cannot be used though, since there is no length base or extra bits
-+ defined for them. Similarily, there are up to 30 distance codes.
-+ However, static trees define 32 codes (all 5 bits) to fill out the
-+ Huffman codes, but the last two had better not show up in the data.
-+ 7. Unzip can check dynamic Huffman blocks for complete code sets.
-+ The exception is that a single code would not be complete (see #4).
-+ 8. The five bits following the block type is really the number of
-+ literal codes sent minus 257.
-+ 9. Length codes 8,16,16 are interpreted as 13 length codes of 8 bits
-+ (1+6+6). Therefore, to output three times the length, you output
-+ three codes (1+1+1), whereas to output four times the same length,
-+ you only need two codes (1+3). Hmm.
-+ 10. In the tree reconstruction algorithm, Code = Code + Increment
-+ only if BitLength(i) is not zero. (Pretty obvious.)
-+ 11. Correction: 4 Bits: # of Bit Length codes - 4 (4 - 19)
-+ 12. Note: length code 284 can represent 227-258, but length code 285
-+ really is 258. The last length deserves its own, short code
-+ since it gets used a lot in very redundant files. The length
-+ 258 is special since 258 - 3 (the min match length) is 255.
-+ 13. The literal/length and distance code bit lengths are read as a
-+ single stream of lengths. It is possible (and advantageous) for
-+ a repeat code (16, 17, or 18) to go across the boundary between
-+ the two sets of lengths.
-+ */
-+
-+
-+local void inflate_blocks_reset(s, z, c)
-+inflate_blocks_statef *s;
-+z_stream *z;
-+uLongf *c;
-+{
-+ if (s->checkfn != Z_NULL)
-+ *c = s->check;
-+ if (s->mode == BTREE || s->mode == DTREE)
-+ ZFREE(z, s->sub.trees.blens, s->sub.trees.nblens * sizeof(uInt));
-+ if (s->mode == CODES)
-+ {
-+ inflate_codes_free(s->sub.decode.codes, z);
-+ inflate_trees_free(s->sub.decode.td, z);
-+ inflate_trees_free(s->sub.decode.tl, z);
-+ }
-+ s->mode = TYPE;
-+ s->bitk = 0;
-+ s->bitb = 0;
-+ s->read = s->write = s->window;
-+ if (s->checkfn != Z_NULL)
-+ s->check = (*s->checkfn)(0L, Z_NULL, 0);
-+ Trace((stderr, "inflate: blocks reset\n"));
-+}
-+
-+
-+local inflate_blocks_statef *inflate_blocks_new(z, c, w)
-+z_stream *z;
-+check_func c;
-+uInt w;
-+{
-+ inflate_blocks_statef *s;
-+
-+ if ((s = (inflate_blocks_statef *)ZALLOC
-+ (z,1,sizeof(struct inflate_blocks_state))) == Z_NULL)
-+ return s;
-+ if ((s->window = (Bytef *)ZALLOC(z, 1, w)) == Z_NULL)
-+ {
-+ ZFREE(z, s, sizeof(struct inflate_blocks_state));
-+ return Z_NULL;
-+ }
-+ s->end = s->window + w;
-+ s->checkfn = c;
-+ s->mode = TYPE;
-+ Trace((stderr, "inflate: blocks allocated\n"));
-+ inflate_blocks_reset(s, z, &s->check);
-+ return s;
-+}
-+
-+
-+local int inflate_blocks(s, z, r)
-+inflate_blocks_statef *s;
-+z_stream *z;
-+int r;
-+{
-+ uInt t; /* temporary storage */
-+ uLong b; /* bit buffer */
-+ uInt k; /* bits in bit buffer */
-+ Bytef *p; /* input data pointer */
-+ uInt n; /* bytes available there */
-+ Bytef *q; /* output window write pointer */
-+ uInt m; /* bytes to end of window or read pointer */
-+
-+ /* copy input/output information to locals (UPDATE macro restores) */
-+ LOAD
-+
-+ /* process input based on current state */
-+ while (1) switch (s->mode)
-+ {
-+ case TYPE:
-+ NEEDBITS(3)
-+ t = (uInt)b & 7;
-+ s->last = t & 1;
-+ switch (t >> 1)
-+ {
-+ case 0: /* stored */
-+ Trace((stderr, "inflate: stored block%s\n",
-+ s->last ? " (last)" : ""));
-+ DUMPBITS(3)
-+ t = k & 7; /* go to byte boundary */
-+ DUMPBITS(t)
-+ s->mode = LENS; /* get length of stored block */
-+ break;
-+ case 1: /* fixed */
-+ Trace((stderr, "inflate: fixed codes block%s\n",
-+ s->last ? " (last)" : ""));
-+ {
-+ uInt bl, bd;
-+ inflate_huft *tl, *td;
-+
-+ inflate_trees_fixed(&bl, &bd, &tl, &td);
-+ s->sub.decode.codes = inflate_codes_new(bl, bd, tl, td, z);
-+ if (s->sub.decode.codes == Z_NULL)
-+ {
-+ r = Z_MEM_ERROR;
-+ LEAVE
-+ }
-+ s->sub.decode.tl = Z_NULL; /* don't try to free these */
-+ s->sub.decode.td = Z_NULL;
-+ }
-+ DUMPBITS(3)
-+ s->mode = CODES;
-+ break;
-+ case 2: /* dynamic */
-+ Trace((stderr, "inflate: dynamic codes block%s\n",
-+ s->last ? " (last)" : ""));
-+ DUMPBITS(3)
-+ s->mode = TABLE;
-+ break;
-+ case 3: /* illegal */
-+ DUMPBITS(3)
-+ s->mode = BADB;
-+ z->msg = "invalid block type";
-+ r = Z_DATA_ERROR;
-+ LEAVE
-+ }
-+ break;
-+ case LENS:
-+ NEEDBITS(32)
-+ if (((~b) >> 16) != (b & 0xffff))
-+ {
-+ s->mode = BADB;
-+ z->msg = "invalid stored block lengths";
-+ r = Z_DATA_ERROR;
-+ LEAVE
-+ }
-+ s->sub.left = (uInt)b & 0xffff;
-+ b = k = 0; /* dump bits */
-+ Tracev((stderr, "inflate: stored length %u\n", s->sub.left));
-+ s->mode = s->sub.left ? STORED : TYPE;
-+ break;
-+ case STORED:
-+ if (n == 0)
-+ LEAVE
-+ NEEDOUT
-+ t = s->sub.left;
-+ if (t > n) t = n;
-+ if (t > m) t = m;
-+ zmemcpy(q, p, t);
-+ p += t; n -= t;
-+ q += t; m -= t;
-+ if ((s->sub.left -= t) != 0)
-+ break;
-+ Tracev((stderr, "inflate: stored end, %lu total out\n",
-+ z->total_out + (q >= s->read ? q - s->read :
-+ (s->end - s->read) + (q - s->window))));
-+ s->mode = s->last ? DRY : TYPE;
-+ break;
-+ case TABLE:
-+ NEEDBITS(14)
-+ s->sub.trees.table = t = (uInt)b & 0x3fff;
-+#ifndef PKZIP_BUG_WORKAROUND
-+ if ((t & 0x1f) > 29 || ((t >> 5) & 0x1f) > 29)
-+ {
-+ s->mode = BADB;
-+ z->msg = "too many length or distance symbols";
-+ r = Z_DATA_ERROR;
-+ LEAVE
-+ }
-+#endif
-+ t = 258 + (t & 0x1f) + ((t >> 5) & 0x1f);
-+ if (t < 19)
-+ t = 19;
-+ if ((s->sub.trees.blens = (uIntf*)ZALLOC(z, t, sizeof(uInt))) == Z_NULL)
-+ {
-+ r = Z_MEM_ERROR;
-+ LEAVE
-+ }
-+ s->sub.trees.nblens = t;
-+ DUMPBITS(14)
-+ s->sub.trees.index = 0;
-+ Tracev((stderr, "inflate: table sizes ok\n"));
-+ s->mode = BTREE;
-+ case BTREE:
-+ while (s->sub.trees.index < 4 + (s->sub.trees.table >> 10))
-+ {
-+ NEEDBITS(3)
-+ s->sub.trees.blens[border[s->sub.trees.index++]] = (uInt)b & 7;
-+ DUMPBITS(3)
-+ }
-+ while (s->sub.trees.index < 19)
-+ s->sub.trees.blens[border[s->sub.trees.index++]] = 0;
-+ s->sub.trees.bb = 7;
-+ t = inflate_trees_bits(s->sub.trees.blens, &s->sub.trees.bb,
-+ &s->sub.trees.tb, z);
-+ if (t != Z_OK)
-+ {
-+ r = t;
-+ if (r == Z_DATA_ERROR)
-+ s->mode = BADB;
-+ LEAVE
-+ }
-+ s->sub.trees.index = 0;
-+ Tracev((stderr, "inflate: bits tree ok\n"));
-+ s->mode = DTREE;
-+ case DTREE:
-+ while (t = s->sub.trees.table,
-+ s->sub.trees.index < 258 + (t & 0x1f) + ((t >> 5) & 0x1f))
-+ {
-+ inflate_huft *h;
-+ uInt i, j, c;
-+
-+ t = s->sub.trees.bb;
-+ NEEDBITS(t)
-+ h = s->sub.trees.tb + ((uInt)b & inflate_mask[t]);
-+ t = h->word.what.Bits;
-+ c = h->more.Base;
-+ if (c < 16)
-+ {
-+ DUMPBITS(t)
-+ s->sub.trees.blens[s->sub.trees.index++] = c;
-+ }
-+ else /* c == 16..18 */
-+ {
-+ i = c == 18 ? 7 : c - 14;
-+ j = c == 18 ? 11 : 3;
-+ NEEDBITS(t + i)
-+ DUMPBITS(t)
-+ j += (uInt)b & inflate_mask[i];
-+ DUMPBITS(i)
-+ i = s->sub.trees.index;
-+ t = s->sub.trees.table;
-+ if (i + j > 258 + (t & 0x1f) + ((t >> 5) & 0x1f) ||
-+ (c == 16 && i < 1))
-+ {
-+ s->mode = BADB;
-+ z->msg = "invalid bit length repeat";
-+ r = Z_DATA_ERROR;
-+ LEAVE
-+ }
-+ c = c == 16 ? s->sub.trees.blens[i - 1] : 0;
-+ do {
-+ s->sub.trees.blens[i++] = c;
-+ } while (--j);
-+ s->sub.trees.index = i;
-+ }
-+ }
-+ inflate_trees_free(s->sub.trees.tb, z);
-+ s->sub.trees.tb = Z_NULL;
-+ {
-+ uInt bl, bd;
-+ inflate_huft *tl, *td;
-+ inflate_codes_statef *c;
-+
-+ bl = 9; /* must be <= 9 for lookahead assumptions */
-+ bd = 6; /* must be <= 9 for lookahead assumptions */
-+ t = s->sub.trees.table;
-+ t = inflate_trees_dynamic(257 + (t & 0x1f), 1 + ((t >> 5) & 0x1f),
-+ s->sub.trees.blens, &bl, &bd, &tl, &td, z);
-+ if (t != Z_OK)
-+ {
-+ if (t == (uInt)Z_DATA_ERROR)
-+ s->mode = BADB;
-+ r = t;
-+ LEAVE
-+ }
-+ Tracev((stderr, "inflate: trees ok\n"));
-+ if ((c = inflate_codes_new(bl, bd, tl, td, z)) == Z_NULL)
-+ {
-+ inflate_trees_free(td, z);
-+ inflate_trees_free(tl, z);
-+ r = Z_MEM_ERROR;
-+ LEAVE
-+ }
-+ ZFREE(z, s->sub.trees.blens, s->sub.trees.nblens * sizeof(uInt));
-+ s->sub.decode.codes = c;
-+ s->sub.decode.tl = tl;
-+ s->sub.decode.td = td;
-+ }
-+ s->mode = CODES;
-+ case CODES:
-+ UPDATE
-+ if ((r = inflate_codes(s, z, r)) != Z_STREAM_END)
-+ return inflate_flush(s, z, r);
-+ r = Z_OK;
-+ inflate_codes_free(s->sub.decode.codes, z);
-+ inflate_trees_free(s->sub.decode.td, z);
-+ inflate_trees_free(s->sub.decode.tl, z);
-+ LOAD
-+ Tracev((stderr, "inflate: codes end, %lu total out\n",
-+ z->total_out + (q >= s->read ? q - s->read :
-+ (s->end - s->read) + (q - s->window))));
-+ if (!s->last)
-+ {
-+ s->mode = TYPE;
-+ break;
-+ }
-+ if (k > 7) /* return unused byte, if any */
-+ {
-+ Assert(k < 16, "inflate_codes grabbed too many bytes")
-+ k -= 8;
-+ n++;
-+ p--; /* can always return one */
-+ }
-+ s->mode = DRY;
-+ case DRY:
-+ FLUSH
-+ if (s->read != s->write)
-+ LEAVE
-+ s->mode = DONEB;
-+ case DONEB:
-+ r = Z_STREAM_END;
-+ LEAVE
-+ case BADB:
-+ r = Z_DATA_ERROR;
-+ LEAVE
-+ default:
-+ r = Z_STREAM_ERROR;
-+ LEAVE
-+ }
-+}
-+
-+
-+local int inflate_blocks_free(s, z, c)
-+inflate_blocks_statef *s;
-+z_stream *z;
-+uLongf *c;
-+{
-+ inflate_blocks_reset(s, z, c);
-+ ZFREE(z, s->window, s->end - s->window);
-+ ZFREE(z, s, sizeof(struct inflate_blocks_state));
-+ Trace((stderr, "inflate: blocks freed\n"));
-+ return Z_OK;
-+}
-+
-+/*
-+ * This subroutine adds the data at next_in/avail_in to the output history
-+ * without performing any output. The output buffer must be "caught up";
-+ * i.e. no pending output (hence s->read equals s->write), and the state must
-+ * be BLOCKS (i.e. we should be willing to see the start of a series of
-+ * BLOCKS). On exit, the output will also be caught up, and the checksum
-+ * will have been updated if need be.
-+ */
-+local int inflate_addhistory(s, z)
-+inflate_blocks_statef *s;
-+z_stream *z;
-+{
-+ uLong b; /* bit buffer */ /* NOT USED HERE */
-+ uInt k; /* bits in bit buffer */ /* NOT USED HERE */
-+ uInt t; /* temporary storage */
-+ Bytef *p; /* input data pointer */
-+ uInt n; /* bytes available there */
-+ Bytef *q; /* output window write pointer */
-+ uInt m; /* bytes to end of window or read pointer */
-+
-+ if (s->read != s->write)
-+ return Z_STREAM_ERROR;
-+ if (s->mode != TYPE)
-+ return Z_DATA_ERROR;
-+
-+ /* we're ready to rock */
-+ LOAD
-+ /* while there is input ready, copy to output buffer, moving
-+ * pointers as needed.
-+ */
-+ while (n) {
-+ t = n; /* how many to do */
-+ /* is there room until end of buffer? */
-+ if (t > m) t = m;
-+ /* update check information */
-+ if (s->checkfn != Z_NULL)
-+ s->check = (*s->checkfn)(s->check, q, t);
-+ zmemcpy(q, p, t);
-+ q += t;
-+ p += t;
-+ n -= t;
-+ z->total_out += t;
-+ s->read = q; /* drag read pointer forward */
-+/* WRAP */ /* expand WRAP macro by hand to handle s->read */
-+ if (q == s->end) {
-+ s->read = q = s->window;
-+ m = WAVAIL;
-+ }
-+ }
-+ UPDATE
-+ return Z_OK;
-+}
-+
-+
-+/*
-+ * At the end of a Deflate-compressed PPP packet, we expect to have seen
-+ * a `stored' block type value but not the (zero) length bytes.
-+ */
-+local int inflate_packet_flush(s)
-+ inflate_blocks_statef *s;
-+{
-+ if (s->mode != LENS)
-+ return Z_DATA_ERROR;
-+ s->mode = TYPE;
-+ return Z_OK;
-+}
-+
-+
-+/*+++++*/
-+/* inftrees.c -- generate Huffman trees for efficient decoding
-+ * Copyright (C) 1995 Mark Adler
-+ * For conditions of distribution and use, see copyright notice in zlib.h
-+ */
-+
-+/* simplify the use of the inflate_huft type with some defines */
-+#define base more.Base
-+#define next more.Next
-+#define exop word.what.Exop
-+#define bits word.what.Bits
-+
-+
-+local int huft_build OF((
-+ uIntf *, /* code lengths in bits */
-+ uInt, /* number of codes */
-+ uInt, /* number of "simple" codes */
-+ uIntf *, /* list of base values for non-simple codes */
-+ uIntf *, /* list of extra bits for non-simple codes */
-+ inflate_huft * FAR*,/* result: starting table */
-+ uIntf *, /* maximum lookup bits (returns actual) */
-+ z_stream *)); /* for zalloc function */
-+
-+local voidpf falloc OF((
-+ voidpf, /* opaque pointer (not used) */
-+ uInt, /* number of items */
-+ uInt)); /* size of item */
-+
-+local void ffree OF((
-+ voidpf q, /* opaque pointer (not used) */
-+ voidpf p, /* what to free (not used) */
-+ uInt n)); /* number of bytes (not used) */
-+
-+/* Tables for deflate from PKZIP's appnote.txt. */
-+local uInt cplens[] = { /* Copy lengths for literal codes 257..285 */
-+ 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
-+ 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0};
-+ /* actually lengths - 2; also see note #13 above about 258 */
-+local uInt cplext[] = { /* Extra bits for literal codes 257..285 */
-+ 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2,
-+ 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 192, 192}; /* 192==invalid */
-+local uInt cpdist[] = { /* Copy offsets for distance codes 0..29 */
-+ 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,
-+ 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,
-+ 8193, 12289, 16385, 24577};
-+local uInt cpdext[] = { /* Extra bits for distance codes */
-+ 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6,
-+ 7, 7, 8, 8, 9, 9, 10, 10, 11, 11,
-+ 12, 12, 13, 13};
-+
-+/*
-+ Huffman code decoding is performed using a multi-level table lookup.
-+ The fastest way to decode is to simply build a lookup table whose
-+ size is determined by the longest code. However, the time it takes
-+ to build this table can also be a factor if the data being decoded
-+ is not very long. The most common codes are necessarily the
-+ shortest codes, so those codes dominate the decoding time, and hence
-+ the speed. The idea is you can have a shorter table that decodes the
-+ shorter, more probable codes, and then point to subsidiary tables for
-+ the longer codes. The time it costs to decode the longer codes is
-+ then traded against the time it takes to make longer tables.
-+
-+ This results of this trade are in the variables lbits and dbits
-+ below. lbits is the number of bits the first level table for literal/
-+ length codes can decode in one step, and dbits is the same thing for
-+ the distance codes. Subsequent tables are also less than or equal to
-+ those sizes. These values may be adjusted either when all of the
-+ codes are shorter than that, in which case the longest code length in
-+ bits is used, or when the shortest code is *longer* than the requested
-+ table size, in which case the length of the shortest code in bits is
-+ used.
-+
-+ There are two different values for the two tables, since they code a
-+ different number of possibilities each. The literal/length table
-+ codes 286 possible values, or in a flat code, a little over eight
-+ bits. The distance table codes 30 possible values, or a little less
-+ than five bits, flat. The optimum values for speed end up being
-+ about one bit more than those, so lbits is 8+1 and dbits is 5+1.
-+ The optimum values may differ though from machine to machine, and
-+ possibly even between compilers. Your mileage may vary.
-+ */
-+
-+
-+/* If BMAX needs to be larger than 16, then h and x[] should be uLong. */
-+#define BMAX 15 /* maximum bit length of any code */
-+#define N_MAX 288 /* maximum number of codes in any set */
-+
-+#ifdef DEBUG_ZLIB
-+ uInt inflate_hufts;
-+#endif
-+
-+local int huft_build(b, n, s, d, e, t, m, zs)
-+uIntf *b; /* code lengths in bits (all assumed <= BMAX) */
-+uInt n; /* number of codes (assumed <= N_MAX) */
-+uInt s; /* number of simple-valued codes (0..s-1) */
-+uIntf *d; /* list of base values for non-simple codes */
-+uIntf *e; /* list of extra bits for non-simple codes */
-+inflate_huft * FAR *t; /* result: starting table */
-+uIntf *m; /* maximum lookup bits, returns actual */
-+z_stream *zs; /* for zalloc function */
-+/* Given a list of code lengths and a maximum table size, make a set of
-+ tables to decode that set of codes. Return Z_OK on success, Z_BUF_ERROR
-+ if the given code set is incomplete (the tables are still built in this
-+ case), Z_DATA_ERROR if the input is invalid (all zero length codes or an
-+ over-subscribed set of lengths), or Z_MEM_ERROR if not enough memory. */
-+{
-+
-+ uInt a; /* counter for codes of length k */
-+ uInt c[BMAX+1]; /* bit length count table */
-+ uInt f; /* i repeats in table every f entries */
-+ int g; /* maximum code length */
-+ int h; /* table level */
-+ register uInt i; /* counter, current code */
-+ register uInt j; /* counter */
-+ register int k; /* number of bits in current code */
-+ int l; /* bits per table (returned in m) */
-+ register uIntf *p; /* pointer into c[], b[], or v[] */
-+ inflate_huft *q; /* points to current table */
-+ struct inflate_huft_s r; /* table entry for structure assignment */
-+ inflate_huft *u[BMAX]; /* table stack */
-+ uInt v[N_MAX]; /* values in order of bit length */
-+ register int w; /* bits before this table == (l * h) */
-+ uInt x[BMAX+1]; /* bit offsets, then code stack */
-+ uIntf *xp; /* pointer into x */
-+ int y; /* number of dummy codes added */
-+ uInt z; /* number of entries in current table */
-+
-+
-+ /* Generate counts for each bit length */
-+ p = c;
-+#define C0 *p++ = 0;
-+#define C2 C0 C0 C0 C0
-+#define C4 C2 C2 C2 C2
-+ C4 /* clear c[]--assume BMAX+1 is 16 */
-+ p = b; i = n;
-+ do {
-+ c[*p++]++; /* assume all entries <= BMAX */
-+ } while (--i);
-+ if (c[0] == n) /* null input--all zero length codes */
-+ {
-+ *t = (inflate_huft *)Z_NULL;
-+ *m = 0;
-+ return Z_OK;
-+ }
-+
-+
-+ /* Find minimum and maximum length, bound *m by those */
-+ l = *m;
-+ for (j = 1; j <= BMAX; j++)
-+ if (c[j])
-+ break;
-+ k = j; /* minimum code length */
-+ if ((uInt)l < j)
-+ l = j;
-+ for (i = BMAX; i; i--)
-+ if (c[i])
-+ break;
-+ g = i; /* maximum code length */
-+ if ((uInt)l > i)
-+ l = i;
-+ *m = l;
-+
-+
-+ /* Adjust last length count to fill out codes, if needed */
-+ for (y = 1 << j; j < i; j++, y <<= 1)
-+ if ((y -= c[j]) < 0)
-+ return Z_DATA_ERROR;
-+ if ((y -= c[i]) < 0)
-+ return Z_DATA_ERROR;
-+ c[i] += y;
-+
-+
-+ /* Generate starting offsets into the value table for each length */
-+ x[1] = j = 0;
-+ p = c + 1; xp = x + 2;
-+ while (--i) { /* note that i == g from above */
-+ *xp++ = (j += *p++);
-+ }
-+
-+
-+ /* Make a table of values in order of bit lengths */
-+ p = b; i = 0;
-+ do {
-+ if ((j = *p++) != 0)
-+ v[x[j]++] = i;
-+ } while (++i < n);
-+
-+
-+ /* Generate the Huffman codes and for each, make the table entries */
-+ x[0] = i = 0; /* first Huffman code is zero */
-+ p = v; /* grab values in bit order */
-+ h = -1; /* no tables yet--level -1 */
-+ w = -l; /* bits decoded == (l * h) */
-+ u[0] = (inflate_huft *)Z_NULL; /* just to keep compilers happy */
-+ q = (inflate_huft *)Z_NULL; /* ditto */
-+ z = 0; /* ditto */
-+
-+ /* go through the bit lengths (k already is bits in shortest code) */
-+ for (; k <= g; k++)
-+ {
-+ a = c[k];
-+ while (a--)
-+ {
-+ /* here i is the Huffman code of length k bits for value *p */
-+ /* make tables up to required level */
-+ while (k > w + l)
-+ {
-+ h++;
-+ w += l; /* previous table always l bits */
-+
-+ /* compute minimum size table less than or equal to l bits */
-+ z = (z = g - w) > (uInt)l ? l : z; /* table size upper limit */
-+ if ((f = 1 << (j = k - w)) > a + 1) /* try a k-w bit table */
-+ { /* too few codes for k-w bit table */
-+ f -= a + 1; /* deduct codes from patterns left */
-+ xp = c + k;
-+ if (j < z)
-+ while (++j < z) /* try smaller tables up to z bits */
-+ {
-+ if ((f <<= 1) <= *++xp)
-+ break; /* enough codes to use up j bits */
-+ f -= *xp; /* else deduct codes from patterns */
-+ }
-+ }
-+ z = 1 << j; /* table entries for j-bit table */
-+
-+ /* allocate and link in new table */
-+ if ((q = (inflate_huft *)ZALLOC
-+ (zs,z + 1,sizeof(inflate_huft))) == Z_NULL)
-+ {
-+ if (h)
-+ inflate_trees_free(u[0], zs);
-+ return Z_MEM_ERROR; /* not enough memory */
-+ }
-+ q->word.Nalloc = z + 1;
-+#ifdef DEBUG_ZLIB
-+ inflate_hufts += z + 1;
-+#endif
-+ *t = q + 1; /* link to list for huft_free() */
-+ *(t = &(q->next)) = Z_NULL;
-+ u[h] = ++q; /* table starts after link */
-+
-+ /* connect to last table, if there is one */
-+ if (h)
-+ {
-+ x[h] = i; /* save pattern for backing up */
-+ r.bits = (Byte)l; /* bits to dump before this table */
-+ r.exop = (Byte)j; /* bits in this table */
-+ r.next = q; /* pointer to this table */
-+ j = i >> (w - l); /* (get around Turbo C bug) */
-+ u[h-1][j] = r; /* connect to last table */
-+ }
-+ }
-+
-+ /* set up table entry in r */
-+ r.bits = (Byte)(k - w);
-+ if (p >= v + n)
-+ r.exop = 128 + 64; /* out of values--invalid code */
-+ else if (*p < s)
-+ {
-+ r.exop = (Byte)(*p < 256 ? 0 : 32 + 64); /* 256 is end-of-block */
-+ r.base = *p++; /* simple code is just the value */
-+ }
-+ else
-+ {
-+ r.exop = (Byte)e[*p - s] + 16 + 64; /* non-simple--look up in lists */
-+ r.base = d[*p++ - s];
-+ }
-+
-+ /* fill code-like entries with r */
-+ f = 1 << (k - w);
-+ for (j = i >> w; j < z; j += f)
-+ q[j] = r;
-+
-+ /* backwards increment the k-bit code i */
-+ for (j = 1 << (k - 1); i & j; j >>= 1)
-+ i ^= j;
-+ i ^= j;
-+
-+ /* backup over finished tables */
-+ while ((i & ((1 << w) - 1)) != x[h])
-+ {
-+ h--; /* don't need to update q */
-+ w -= l;
-+ }
-+ }
-+ }
-+
-+
-+ /* Return Z_BUF_ERROR if we were given an incomplete table */
-+ return y != 0 && g != 1 ? Z_BUF_ERROR : Z_OK;
-+}
-+
-+
-+local int inflate_trees_bits(c, bb, tb, z)
-+uIntf *c; /* 19 code lengths */
-+uIntf *bb; /* bits tree desired/actual depth */
-+inflate_huft * FAR *tb; /* bits tree result */
-+z_stream *z; /* for zfree function */
-+{
-+ int r;
-+
-+ r = huft_build(c, 19, 19, (uIntf*)Z_NULL, (uIntf*)Z_NULL, tb, bb, z);
-+ if (r == Z_DATA_ERROR)
-+ z->msg = "oversubscribed dynamic bit lengths tree";
-+ else if (r == Z_BUF_ERROR)
-+ {
-+ inflate_trees_free(*tb, z);
-+ z->msg = "incomplete dynamic bit lengths tree";
-+ r = Z_DATA_ERROR;
-+ }
-+ return r;
-+}
-+
-+
-+local int inflate_trees_dynamic(nl, nd, c, bl, bd, tl, td, z)
-+uInt nl; /* number of literal/length codes */
-+uInt nd; /* number of distance codes */
-+uIntf *c; /* that many (total) code lengths */
-+uIntf *bl; /* literal desired/actual bit depth */
-+uIntf *bd; /* distance desired/actual bit depth */
-+inflate_huft * FAR *tl; /* literal/length tree result */
-+inflate_huft * FAR *td; /* distance tree result */
-+z_stream *z; /* for zfree function */
-+{
-+ int r;
-+
-+ /* build literal/length tree */
-+ if ((r = huft_build(c, nl, 257, cplens, cplext, tl, bl, z)) != Z_OK)
-+ {
-+ if (r == Z_DATA_ERROR)
-+ z->msg = "oversubscribed literal/length tree";
-+ else if (r == Z_BUF_ERROR)
-+ {
-+ inflate_trees_free(*tl, z);
-+ z->msg = "incomplete literal/length tree";
-+ r = Z_DATA_ERROR;
-+ }
-+ return r;
-+ }
-+
-+ /* build distance tree */
-+ if ((r = huft_build(c + nl, nd, 0, cpdist, cpdext, td, bd, z)) != Z_OK)
-+ {
-+ if (r == Z_DATA_ERROR)
-+ z->msg = "oversubscribed literal/length tree";
-+ else if (r == Z_BUF_ERROR) {
-+#ifdef PKZIP_BUG_WORKAROUND
-+ r = Z_OK;
-+ }
-+#else
-+ inflate_trees_free(*td, z);
-+ z->msg = "incomplete literal/length tree";
-+ r = Z_DATA_ERROR;
-+ }
-+ inflate_trees_free(*tl, z);
-+ return r;
-+#endif
-+ }
-+
-+ /* done */
-+ return Z_OK;
-+}
-+
-+
-+/* build fixed tables only once--keep them here */
-+local int fixed_lock = 0;
-+local int fixed_built = 0;
-+#define FIXEDH 530 /* number of hufts used by fixed tables */
-+local uInt fixed_left = FIXEDH;
-+local inflate_huft fixed_mem[FIXEDH];
-+local uInt fixed_bl;
-+local uInt fixed_bd;
-+local inflate_huft *fixed_tl;
-+local inflate_huft *fixed_td;
-+
-+
-+local voidpf falloc(q, n, s)
-+voidpf q; /* opaque pointer (not used) */
-+uInt n; /* number of items */
-+uInt s; /* size of item */
-+{
-+ Assert(s == sizeof(inflate_huft) && n <= fixed_left,
-+ "inflate_trees falloc overflow");
-+ if (q) s++; /* to make some compilers happy */
-+ fixed_left -= n;
-+ return (voidpf)(fixed_mem + fixed_left);
-+}
-+
-+
-+local void ffree(q, p, n)
-+voidpf q;
-+voidpf p;
-+uInt n;
-+{
-+ Assert(0, "inflate_trees ffree called!");
-+ if (q) q = p; /* to make some compilers happy */
-+}
-+
-+
-+local int inflate_trees_fixed(bl, bd, tl, td)
-+uIntf *bl; /* literal desired/actual bit depth */
-+uIntf *bd; /* distance desired/actual bit depth */
-+inflate_huft * FAR *tl; /* literal/length tree result */
-+inflate_huft * FAR *td; /* distance tree result */
-+{
-+ /* build fixed tables if not built already--lock out other instances */
-+ while (++fixed_lock > 1)
-+ fixed_lock--;
-+ if (!fixed_built)
-+ {
-+ int k; /* temporary variable */
-+ unsigned c[288]; /* length list for huft_build */
-+ z_stream z; /* for falloc function */
-+
-+ /* set up fake z_stream for memory routines */
-+ z.zalloc = falloc;
-+ z.zfree = ffree;
-+ z.opaque = Z_NULL;
-+
-+ /* literal table */
-+ for (k = 0; k < 144; k++)
-+ c[k] = 8;
-+ for (; k < 256; k++)
-+ c[k] = 9;
-+ for (; k < 280; k++)
-+ c[k] = 7;
-+ for (; k < 288; k++)
-+ c[k] = 8;
-+ fixed_bl = 7;
-+ huft_build(c, 288, 257, cplens, cplext, &fixed_tl, &fixed_bl, &z);
-+
-+ /* distance table */
-+ for (k = 0; k < 30; k++)
-+ c[k] = 5;
-+ fixed_bd = 5;
-+ huft_build(c, 30, 0, cpdist, cpdext, &fixed_td, &fixed_bd, &z);
-+
-+ /* done */
-+ fixed_built = 1;
-+ }
-+ fixed_lock--;
-+ *bl = fixed_bl;
-+ *bd = fixed_bd;
-+ *tl = fixed_tl;
-+ *td = fixed_td;
-+ return Z_OK;
-+}
-+
-+
-+local int inflate_trees_free(t, z)
-+inflate_huft *t; /* table to free */
-+z_stream *z; /* for zfree function */
-+/* Free the malloc'ed tables built by huft_build(), which makes a linked
-+ list of the tables it made, with the links in a dummy first entry of
-+ each table. */
-+{
-+ register inflate_huft *p, *q;
-+
-+ /* Go through linked list, freeing from the malloced (t[-1]) address. */
-+ p = t;
-+ while (p != Z_NULL)
-+ {
-+ q = (--p)->next;
-+ ZFREE(z, p, p->word.Nalloc * sizeof(inflate_huft));
-+ p = q;
-+ }
-+ return Z_OK;
-+}
-+
-+/*+++++*/
-+/* infcodes.c -- process literals and length/distance pairs
-+ * Copyright (C) 1995 Mark Adler
-+ * For conditions of distribution and use, see copyright notice in zlib.h
-+ */
-+
-+/* simplify the use of the inflate_huft type with some defines */
-+#define base more.Base
-+#define next more.Next
-+#define exop word.what.Exop
-+#define bits word.what.Bits
-+
-+/* inflate codes private state */
-+struct inflate_codes_state {
-+
-+ /* mode */
-+ enum { /* waiting for "i:"=input, "o:"=output, "x:"=nothing */
-+ START, /* x: set up for LEN */
-+ LEN, /* i: get length/literal/eob next */
-+ LENEXT, /* i: getting length extra (have base) */
-+ DIST, /* i: get distance next */
-+ DISTEXT, /* i: getting distance extra */
-+ COPY, /* o: copying bytes in window, waiting for space */
-+ LIT, /* o: got literal, waiting for output space */
-+ WASH, /* o: got eob, possibly still output waiting */
-+ END, /* x: got eob and all data flushed */
-+ BADCODE} /* x: got error */
-+ mode; /* current inflate_codes mode */
-+
-+ /* mode dependent information */
-+ uInt len;
-+ union {
-+ struct {
-+ inflate_huft *tree; /* pointer into tree */
-+ uInt need; /* bits needed */
-+ } code; /* if LEN or DIST, where in tree */
-+ uInt lit; /* if LIT, literal */
-+ struct {
-+ uInt get; /* bits to get for extra */
-+ uInt dist; /* distance back to copy from */
-+ } copy; /* if EXT or COPY, where and how much */
-+ } sub; /* submode */
-+
-+ /* mode independent information */
-+ Byte lbits; /* ltree bits decoded per branch */
-+ Byte dbits; /* dtree bits decoder per branch */
-+ inflate_huft *ltree; /* literal/length/eob tree */
-+ inflate_huft *dtree; /* distance tree */
-+
-+};
-+
-+
-+local inflate_codes_statef *inflate_codes_new(bl, bd, tl, td, z)
-+uInt bl, bd;
-+inflate_huft *tl, *td;
-+z_stream *z;
-+{
-+ inflate_codes_statef *c;
-+
-+ if ((c = (inflate_codes_statef *)
-+ ZALLOC(z,1,sizeof(struct inflate_codes_state))) != Z_NULL)
-+ {
-+ c->mode = START;
-+ c->lbits = (Byte)bl;
-+ c->dbits = (Byte)bd;
-+ c->ltree = tl;
-+ c->dtree = td;
-+ Tracev((stderr, "inflate: codes new\n"));
-+ }
-+ return c;
-+}
-+
-+
-+local int inflate_codes(s, z, r)
-+inflate_blocks_statef *s;
-+z_stream *z;
-+int r;
-+{
-+ uInt j; /* temporary storage */
-+ inflate_huft *t; /* temporary pointer */
-+ uInt e; /* extra bits or operation */
-+ uLong b; /* bit buffer */
-+ uInt k; /* bits in bit buffer */
-+ Bytef *p; /* input data pointer */
-+ uInt n; /* bytes available there */
-+ Bytef *q; /* output window write pointer */
-+ uInt m; /* bytes to end of window or read pointer */
-+ Bytef *f; /* pointer to copy strings from */
-+ inflate_codes_statef *c = s->sub.decode.codes; /* codes state */
-+
-+ /* copy input/output information to locals (UPDATE macro restores) */
-+ LOAD
-+
-+ /* process input and output based on current state */
-+ while (1) switch (c->mode)
-+ { /* waiting for "i:"=input, "o:"=output, "x:"=nothing */
-+ case START: /* x: set up for LEN */
-+#ifndef SLOW
-+ if (m >= 258 && n >= 10)
-+ {
-+ UPDATE
-+ r = inflate_fast(c->lbits, c->dbits, c->ltree, c->dtree, s, z);
-+ LOAD
-+ if (r != Z_OK)
-+ {
-+ c->mode = r == Z_STREAM_END ? WASH : BADCODE;
-+ break;
-+ }
-+ }
-+#endif /* !SLOW */
-+ c->sub.code.need = c->lbits;
-+ c->sub.code.tree = c->ltree;
-+ c->mode = LEN;
-+ case LEN: /* i: get length/literal/eob next */
-+ j = c->sub.code.need;
-+ NEEDBITS(j)
-+ t = c->sub.code.tree + ((uInt)b & inflate_mask[j]);
-+ DUMPBITS(t->bits)
-+ e = (uInt)(t->exop);
-+ if (e == 0) /* literal */
-+ {
-+ c->sub.lit = t->base;
-+ Tracevv((stderr, t->base >= 0x20 && t->base < 0x7f ?
-+ "inflate: literal '%c'\n" :
-+ "inflate: literal 0x%02x\n", t->base));
-+ c->mode = LIT;
-+ break;
-+ }
-+ if (e & 16) /* length */
-+ {
-+ c->sub.copy.get = e & 15;
-+ c->len = t->base;
-+ c->mode = LENEXT;
-+ break;
-+ }
-+ if ((e & 64) == 0) /* next table */
-+ {
-+ c->sub.code.need = e;
-+ c->sub.code.tree = t->next;
-+ break;
-+ }
-+ if (e & 32) /* end of block */
-+ {
-+ Tracevv((stderr, "inflate: end of block\n"));
-+ c->mode = WASH;
-+ break;
-+ }
-+ c->mode = BADCODE; /* invalid code */
-+ z->msg = "invalid literal/length code";
-+ r = Z_DATA_ERROR;
-+ LEAVE
-+ case LENEXT: /* i: getting length extra (have base) */
-+ j = c->sub.copy.get;
-+ NEEDBITS(j)
-+ c->len += (uInt)b & inflate_mask[j];
-+ DUMPBITS(j)
-+ c->sub.code.need = c->dbits;
-+ c->sub.code.tree = c->dtree;
-+ Tracevv((stderr, "inflate: length %u\n", c->len));
-+ c->mode = DIST;
-+ case DIST: /* i: get distance next */
-+ j = c->sub.code.need;
-+ NEEDBITS(j)
-+ t = c->sub.code.tree + ((uInt)b & inflate_mask[j]);
-+ DUMPBITS(t->bits)
-+ e = (uInt)(t->exop);
-+ if (e & 16) /* distance */
-+ {
-+ c->sub.copy.get = e & 15;
-+ c->sub.copy.dist = t->base;
-+ c->mode = DISTEXT;
-+ break;
-+ }
-+ if ((e & 64) == 0) /* next table */
-+ {
-+ c->sub.code.need = e;
-+ c->sub.code.tree = t->next;
-+ break;
-+ }
-+ c->mode = BADCODE; /* invalid code */
-+ z->msg = "invalid distance code";
-+ r = Z_DATA_ERROR;
-+ LEAVE
-+ case DISTEXT: /* i: getting distance extra */
-+ j = c->sub.copy.get;
-+ NEEDBITS(j)
-+ c->sub.copy.dist += (uInt)b & inflate_mask[j];
-+ DUMPBITS(j)
-+ Tracevv((stderr, "inflate: distance %u\n", c->sub.copy.dist));
-+ c->mode = COPY;
-+ case COPY: /* o: copying bytes in window, waiting for space */
-+#ifndef __TURBOC__ /* Turbo C bug for following expression */
-+ f = (uInt)(q - s->window) < c->sub.copy.dist ?
-+ s->end - (c->sub.copy.dist - (q - s->window)) :
-+ q - c->sub.copy.dist;
-+#else
-+ f = q - c->sub.copy.dist;
-+ if ((uInt)(q - s->window) < c->sub.copy.dist)
-+ f = s->end - (c->sub.copy.dist - (q - s->window));
-+#endif
-+ while (c->len)
-+ {
-+ NEEDOUT
-+ OUTBYTE(*f++)
-+ if (f == s->end)
-+ f = s->window;
-+ c->len--;
-+ }
-+ c->mode = START;
-+ break;
-+ case LIT: /* o: got literal, waiting for output space */
-+ NEEDOUT
-+ OUTBYTE(c->sub.lit)
-+ c->mode = START;
-+ break;
-+ case WASH: /* o: got eob, possibly more output */
-+ FLUSH
-+ if (s->read != s->write)
-+ LEAVE
-+ c->mode = END;
-+ case END:
-+ r = Z_STREAM_END;
-+ LEAVE
-+ case BADCODE: /* x: got error */
-+ r = Z_DATA_ERROR;
-+ LEAVE
-+ default:
-+ r = Z_STREAM_ERROR;
-+ LEAVE
-+ }
-+}
-+
-+
-+local void inflate_codes_free(c, z)
-+inflate_codes_statef *c;
-+z_stream *z;
-+{
-+ ZFREE(z, c, sizeof(struct inflate_codes_state));
-+ Tracev((stderr, "inflate: codes free\n"));
-+}
-+
-+/*+++++*/
-+/* inflate_util.c -- data and routines common to blocks and codes
-+ * Copyright (C) 1995 Mark Adler
-+ * For conditions of distribution and use, see copyright notice in zlib.h
-+ */
-+
-+/* copy as much as possible from the sliding window to the output area */
-+local int inflate_flush(s, z, r)
-+inflate_blocks_statef *s;
-+z_stream *z;
-+int r;
-+{
-+ uInt n;
-+ Bytef *p, *q;
-+
-+ /* local copies of source and destination pointers */
-+ p = z->next_out;
-+ q = s->read;
-+
-+ /* compute number of bytes to copy as far as end of window */
-+ n = (uInt)((q <= s->write ? s->write : s->end) - q);
-+ if (n > z->avail_out) n = z->avail_out;
-+ if (n && r == Z_BUF_ERROR) r = Z_OK;
-+
-+ /* update counters */
-+ z->avail_out -= n;
-+ z->total_out += n;
-+
-+ /* update check information */
-+ if (s->checkfn != Z_NULL)
-+ s->check = (*s->checkfn)(s->check, q, n);
-+
-+ /* copy as far as end of window */
-+ zmemcpy(p, q, n);
-+ p += n;
-+ q += n;
-+
-+ /* see if more to copy at beginning of window */
-+ if (q == s->end)
-+ {
-+ /* wrap pointers */
-+ q = s->window;
-+ if (s->write == s->end)
-+ s->write = s->window;
-+
-+ /* compute bytes to copy */
-+ n = (uInt)(s->write - q);
-+ if (n > z->avail_out) n = z->avail_out;
-+ if (n && r == Z_BUF_ERROR) r = Z_OK;
-+
-+ /* update counters */
-+ z->avail_out -= n;
-+ z->total_out += n;
-+
-+ /* update check information */
-+ if (s->checkfn != Z_NULL)
-+ s->check = (*s->checkfn)(s->check, q, n);
-+
-+ /* copy */
-+ zmemcpy(p, q, n);
-+ p += n;
-+ q += n;
-+ }
-+
-+ /* update pointers */
-+ z->next_out = p;
-+ s->read = q;
-+
-+ /* done */
-+ return r;
-+}
-+
-+
-+/*+++++*/
-+/* inffast.c -- process literals and length/distance pairs fast
-+ * Copyright (C) 1995 Mark Adler
-+ * For conditions of distribution and use, see copyright notice in zlib.h
-+ */
-+
-+/* simplify the use of the inflate_huft type with some defines */
-+#define base more.Base
-+#define next more.Next
-+#define exop word.what.Exop
-+#define bits word.what.Bits
-+
-+/* macros for bit input with no checking and for returning unused bytes */
-+#define GRABBITS(j) {while(k<(j)){b|=((uLong)NEXTBYTE)<<k;k+=8;}}
-+#define UNGRAB {n+=(c=k>>3);p-=c;k&=7;}
-+
-+/* Called with number of bytes left to write in window at least 258
-+ (the maximum string length) and number of input bytes available
-+ at least ten. The ten bytes are six bytes for the longest length/
-+ distance pair plus four bytes for overloading the bit buffer. */
-+
-+local int inflate_fast(bl, bd, tl, td, s, z)
-+uInt bl, bd;
-+inflate_huft *tl, *td;
-+inflate_blocks_statef *s;
-+z_stream *z;
-+{
-+ inflate_huft *t; /* temporary pointer */
-+ uInt e; /* extra bits or operation */
-+ uLong b; /* bit buffer */
-+ uInt k; /* bits in bit buffer */
-+ Bytef *p; /* input data pointer */
-+ uInt n; /* bytes available there */
-+ Bytef *q; /* output window write pointer */
-+ uInt m; /* bytes to end of window or read pointer */
-+ uInt ml; /* mask for literal/length tree */
-+ uInt md; /* mask for distance tree */
-+ uInt c; /* bytes to copy */
-+ uInt d; /* distance back to copy from */
-+ Bytef *r; /* copy source pointer */
-+
-+ /* load input, output, bit values */
-+ LOAD
-+
-+ /* initialize masks */
-+ ml = inflate_mask[bl];
-+ md = inflate_mask[bd];
-+
-+ /* do until not enough input or output space for fast loop */
-+ do { /* assume called with m >= 258 && n >= 10 */
-+ /* get literal/length code */
-+ GRABBITS(20) /* max bits for literal/length code */
-+ if ((e = (t = tl + ((uInt)b & ml))->exop) == 0)
-+ {
-+ DUMPBITS(t->bits)
-+ Tracevv((stderr, t->base >= 0x20 && t->base < 0x7f ?
-+ "inflate: * literal '%c'\n" :
-+ "inflate: * literal 0x%02x\n", t->base));
-+ *q++ = (Byte)t->base;
-+ m--;
-+ continue;
-+ }
-+ do {
-+ DUMPBITS(t->bits)
-+ if (e & 16)
-+ {
-+ /* get extra bits for length */
-+ e &= 15;
-+ c = t->base + ((uInt)b & inflate_mask[e]);
-+ DUMPBITS(e)
-+ Tracevv((stderr, "inflate: * length %u\n", c));
-+
-+ /* decode distance base of block to copy */
-+ GRABBITS(15); /* max bits for distance code */
-+ e = (t = td + ((uInt)b & md))->exop;
-+ do {
-+ DUMPBITS(t->bits)
-+ if (e & 16)
-+ {
-+ /* get extra bits to add to distance base */
-+ e &= 15;
-+ GRABBITS(e) /* get extra bits (up to 13) */
-+ d = t->base + ((uInt)b & inflate_mask[e]);
-+ DUMPBITS(e)
-+ Tracevv((stderr, "inflate: * distance %u\n", d));
-+
-+ /* do the copy */
-+ m -= c;
-+ if ((uInt)(q - s->window) >= d) /* offset before dest */
-+ { /* just copy */
-+ r = q - d;
-+ *q++ = *r++; c--; /* minimum count is three, */
-+ *q++ = *r++; c--; /* so unroll loop a little */
-+ }
-+ else /* else offset after destination */
-+ {
-+ e = d - (q - s->window); /* bytes from offset to end */
-+ r = s->end - e; /* pointer to offset */
-+ if (c > e) /* if source crosses, */
-+ {
-+ c -= e; /* copy to end of window */
-+ do {
-+ *q++ = *r++;
-+ } while (--e);
-+ r = s->window; /* copy rest from start of window */
-+ }
-+ }
-+ do { /* copy all or what's left */
-+ *q++ = *r++;
-+ } while (--c);
-+ break;
-+ }
-+ else if ((e & 64) == 0)
-+ e = (t = t->next + ((uInt)b & inflate_mask[e]))->exop;
-+ else
-+ {
-+ z->msg = "invalid distance code";
-+ UNGRAB
-+ UPDATE
-+ return Z_DATA_ERROR;
-+ }
-+ } while (1);
-+ break;
-+ }
-+ if ((e & 64) == 0)
-+ {
-+ if ((e = (t = t->next + ((uInt)b & inflate_mask[e]))->exop) == 0)
-+ {
-+ DUMPBITS(t->bits)
-+ Tracevv((stderr, t->base >= 0x20 && t->base < 0x7f ?
-+ "inflate: * literal '%c'\n" :
-+ "inflate: * literal 0x%02x\n", t->base));
-+ *q++ = (Byte)t->base;
-+ m--;
-+ break;
-+ }
-+ }
-+ else if (e & 32)
-+ {
-+ Tracevv((stderr, "inflate: * end of block\n"));
-+ UNGRAB
-+ UPDATE
-+ return Z_STREAM_END;
-+ }
-+ else
-+ {
-+ z->msg = "invalid literal/length code";
-+ UNGRAB
-+ UPDATE
-+ return Z_DATA_ERROR;
-+ }
-+ } while (1);
-+ } while (m >= 258 && n >= 10);
-+
-+ /* not enough input or output--restore pointers and return */
-+ UNGRAB
-+ UPDATE
-+ return Z_OK;
-+}
-+
-+
-+/*+++++*/
-+/* zutil.c -- target dependent utility functions for the compression library
-+ * Copyright (C) 1995 Jean-loup Gailly.
-+ * For conditions of distribution and use, see copyright notice in zlib.h
-+ */
-+
-+/* From: zutil.c,v 1.8 1995/05/03 17:27:12 jloup Exp */
-+
-+char *zlib_version = ZLIB_VERSION;
-+
-+char *z_errmsg[] = {
-+"stream end", /* Z_STREAM_END 1 */
-+"", /* Z_OK 0 */
-+"file error", /* Z_ERRNO (-1) */
-+"stream error", /* Z_STREAM_ERROR (-2) */
-+"data error", /* Z_DATA_ERROR (-3) */
-+"insufficient memory", /* Z_MEM_ERROR (-4) */
-+"buffer error", /* Z_BUF_ERROR (-5) */
-+""};
-+
-+
-+/*+++++*/
-+/* adler32.c -- compute the Adler-32 checksum of a data stream
-+ * Copyright (C) 1995 Mark Adler
-+ * For conditions of distribution and use, see copyright notice in zlib.h
-+ */
-+
-+/* From: adler32.c,v 1.6 1995/05/03 17:27:08 jloup Exp */
-+
-+#define BASE 65521L /* largest prime smaller than 65536 */
-+#define NMAX 5552
-+/* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */
-+
-+#define DO1(buf) {s1 += *buf++; s2 += s1;}
-+#define DO2(buf) DO1(buf); DO1(buf);
-+#define DO4(buf) DO2(buf); DO2(buf);
-+#define DO8(buf) DO4(buf); DO4(buf);
-+#define DO16(buf) DO8(buf); DO8(buf);
-+
-+/* ========================================================================= */
-+uLong adler32(adler, buf, len)
-+ uLong adler;
-+ Bytef *buf;
-+ uInt len;
-+{
-+ unsigned long s1 = adler & 0xffff;
-+ unsigned long s2 = (adler >> 16) & 0xffff;
-+ int k;
-+
-+ if (buf == Z_NULL) return 1L;
-+
-+ while (len > 0) {
-+ k = len < NMAX ? len : NMAX;
-+ len -= k;
-+ while (k >= 16) {
-+ DO16(buf);
-+ k -= 16;
-+ }
-+ if (k != 0) do {
-+ DO1(buf);
-+ } while (--k);
-+ s1 %= BASE;
-+ s2 %= BASE;
-+ }
-+ return (s2 << 16) | s1;
-+}
-diff -Naru linux/arch/mips/zboot/Makefile linux.spi/arch/mips/zboot/Makefile
---- linux/arch/mips/zboot/Makefile 1969-12-31 19:00:00.000000000 -0500
-+++ linux.spi/arch/mips/zboot/Makefile 2004-05-11 23:19:24.000000000 -0400
-@@ -0,0 +1,84 @@
-+#
-+# arch/mips/zboot/Makefile
-+#
-+# This file is subject to the terms and conditions of the GNU General Public
-+# License. See the file "COPYING" in the main directory of this archive
-+# for more details.
-+
-+# Adapted for MIPS Pete Popov, Dan Malek
-+#
-+# Copyright (C) 1994 by Linus Torvalds
-+# Adapted for PowerPC by Gary Thomas
-+# modified by Cort (cort@cs.nmt.edu)
-+#
-+
-+.c.s:
-+ $(CC) $(CFLAGS) -S -o $*.s $<
-+.s.o:
-+ $(AS) -o $*.o $<
-+.c.o:
-+ $(CC) $(CFLAGS) -c -o $*.o $<
-+.S.s:
-+ $(CPP) $(AFLAGS) -o $*.o $<
-+.S.o:
-+ $(CC) $(AFLAGS) -c -o $*.o $<
-+
-+GZIP_FLAGS = -v9f
-+
-+CFLAGS += -D__BOOTER__ -I$(TOPDIR)/arch/$(ARCH)/zboot/include
-+AFLAGS += -D__BOOTER__
-+
-+BOOT_TARGETS = zImage zImage.initrd zImage.flash zImage.initrd.flash
-+
-+lib/zlib.a:
-+ $(MAKE) -C lib
-+
-+images/vmlinux.gz: $(TOPDIR)/vmlinux
-+ $(MAKE) -C images vmlinux.gz
-+
-+$(BOOT_TARGETS): lib/zlib.a images/vmlinux.gz
-+ifdef CONFIG_MIPS_PB1000
-+ $(MAKE) -C pb1xxx $@
-+endif
-+ifdef CONFIG_MIPS_PB1500
-+ $(MAKE) -C pb1xxx $@
-+endif
-+ifdef CONFIG_MIPS_PB1100
-+ $(MAKE) -C pb1xxx $@
-+endif
-+ifdef CONFIG_MIPS_PB1550
-+ $(MAKE) -C pb1xxx $@
-+endif
-+ifdef CONFIG_MIPS_DB1000
-+ $(MAKE) -C pb1xxx $@
-+endif
-+ifdef CONFIG_MIPS_DB1100
-+ $(MAKE) -C pb1xxx $@
-+endif
-+ifdef CONFIG_MIPS_DB1500
-+ $(MAKE) -C pb1xxx $@
-+endif
-+ifdef CONFIG_MIPS_BOSPORUS
-+ $(MAKE) -C pb1xxx $@
-+endif
-+ifdef CONFIG_MIPS_MIRAGE
-+ $(MAKE) -C pb1xxx $@
-+endif
-+ifdef CONFIG_MIPS_MTX1
-+ $(MAKE) -C pb1xxx $@
-+endif
-+ifdef CONFIG_COGENT_CSB250
-+ $(MAKE) -C csb250 $@
-+endif
-+ifdef CONFIG_MIPS_XXS1500
-+BOOT_DIR = xxs1500
-+endif
-+
-+# Do the dirs
-+clean:
-+ $(MAKE) -C common clean
-+ $(MAKE) -C images clean
-+ $(MAKE) -C pb1xxx clean
-+ $(MAKE) -C xxs1500 clean
-+
-+include $(TOPDIR)/Rules.make
-diff -Naru linux/arch/mips/zboot/pb1xxx/head.S linux.spi/arch/mips/zboot/pb1xxx/head.S
---- linux/arch/mips/zboot/pb1xxx/head.S 1969-12-31 19:00:00.000000000 -0500
-+++ linux.spi/arch/mips/zboot/pb1xxx/head.S 2004-05-11 23:19:24.000000000 -0400
-@@ -0,0 +1,149 @@
-+/*
-+ * arch/mips/kernel/head.S
-+ *
-+ * This file is subject to the terms and conditions of the GNU General Public
-+ * License. See the file "COPYING" in the main directory of this archive
-+ * for more details.
-+ *
-+ * Copyright (C) 1994, 1995 Waldorf Electronics
-+ * Written by Ralf Baechle and Andreas Busse
-+ * Copyright (C) 1995 - 1999 Ralf Baechle
-+ * Copyright (C) 1996 Paul M. Antoine
-+ * Modified for DECStation and hence R3000 support by Paul M. Antoine
-+ * Further modifications by David S. Miller and Harald Koerfgen
-+ * Copyright (C) 1999 Silicon Graphics, Inc.
-+ *
-+ * Head.S contains the MIPS exception handler and startup code.
-+ *
-+ **************************************************************************
-+ * 9 Nov, 2000.
-+ * Added Cache Error exception handler and SBDDP EJTAG debug exception.
-+ *
-+ * Kevin Kissell, kevink@mips.com and Carsten Langgaard, carstenl@mips.com
-+ * Copyright (C) 2000 MIPS Technologies, Inc. All rights reserved.
-+ **************************************************************************
-+ */
-+#include <linux/config.h>
-+#include <linux/threads.h>
-+
-+#include <asm/asm.h>
-+#include <asm/cacheops.h>
-+#include <asm/mipsregs.h>
-+#include <asm/offset.h>
-+#include <asm/cachectl.h>
-+#include <asm/regdef.h>
-+
-+#define IndexInvalidate_I 0x00
-+#define IndexWriteBack_D 0x01
-+
-+ .set noreorder
-+ .cprestore
-+ LEAF(start)
-+start:
-+ bal locate
-+ nop
-+locate:
-+ subu s8, ra, 8 /* Where we were loaded */
-+ la sp, (.stack + 8192)
-+
-+ move s0, a0 /* Save boot rom start args */
-+ move s1, a1
-+ move s2, a2
-+ move s3, a3
-+
-+ la a0, start /* Where we were linked to run */
-+
-+ move a1, s8
-+ la a2, _edata
-+ subu t1, a2, a0
-+ srl t1, t1, 2
-+
-+ /* copy text section */
-+ li t0, 0
-+1: lw v0, 0(a1)
-+ nop
-+ sw v0, 0(a0)
-+ xor t0, t0, v0
-+ addu a0, 4
-+ bne a2, a0, 1b
-+ addu a1, 4
-+
-+ /* Clear BSS */
-+ la a0, _edata
-+ la a2, _end
-+2: sw zero, 0(a0)
-+ bne a2, a0, 2b
-+ addu a0, 4
-+
-+ /* push the D-Cache and invalidate I-Cache */
-+ li k0, 0x80000000 # start address
-+ li k1, 0x80004000 # end address (16KB I-Cache)
-+ subu k1, 128
-+
-+1:
-+ .set mips3
-+ cache IndexWriteBack_D, 0(k0)
-+ cache IndexWriteBack_D, 32(k0)
-+ cache IndexWriteBack_D, 64(k0)
-+ cache IndexWriteBack_D, 96(k0)
-+ cache IndexInvalidate_I, 0(k0)
-+ cache IndexInvalidate_I, 32(k0)
-+ cache IndexInvalidate_I, 64(k0)
-+ cache IndexInvalidate_I, 96(k0)
-+ .set mips0
-+
-+ bne k0, k1, 1b
-+ addu k0, k0, 128
-+ /* done */
-+
-+ move a0, s8 /* load address */
-+ move a1, t1 /* length in words */
-+ move a2, t0 /* checksum */
-+ move a3, sp
-+
-+ la ra, 1f
-+ la k0, decompress_kernel
-+ jr k0
-+ nop
-+1:
-+
-+ move a0, s0
-+ move a1, s1
-+ move a2, s2
-+ move a3, s3
-+ li k0, KERNEL_ENTRY
-+ jr k0
-+ nop
-+3:
-+ b 3b
-+ END(start)
-+
-+ LEAF(udelay)
-+udelay:
-+ END(udelay)
-+
-+
-+ LEAF(FlushCache)
-+ li k0, 0x80000000 # start address
-+ li k1, 0x80004000 # end address (16KB I-Cache)
-+ subu k1, 128
-+
-+1:
-+ .set mips3
-+ cache IndexWriteBack_D, 0(k0)
-+ cache IndexWriteBack_D, 32(k0)
-+ cache IndexWriteBack_D, 64(k0)
-+ cache IndexWriteBack_D, 96(k0)
-+ cache IndexInvalidate_I, 0(k0)
-+ cache IndexInvalidate_I, 32(k0)
-+ cache IndexInvalidate_I, 64(k0)
-+ cache IndexInvalidate_I, 96(k0)
-+ .set mips0
-+
-+ bne k0, k1, 1b
-+ addu k0, k0, 128
-+ jr ra
-+ nop
-+ END(FlushCache)
-+
-+ .comm .stack,4096*2,4
-diff -Naru linux/arch/mips/zboot/pb1xxx/Makefile linux.spi/arch/mips/zboot/pb1xxx/Makefile
---- linux/arch/mips/zboot/pb1xxx/Makefile 1969-12-31 19:00:00.000000000 -0500
-+++ linux.spi/arch/mips/zboot/pb1xxx/Makefile 2004-05-11 23:19:24.000000000 -0400
-@@ -0,0 +1,135 @@
-+# arch/mips/zboot/pb1xxx/Makefile
-+#
-+# Makefile for Alchemy Semiconductor Pb1[015]00 boards.
-+# All of the boot loader code was derived from the ppc
-+# boot code.
-+#
-+# Copyright 2001,2002 MontaVista Software Inc.
-+#
-+# Author: Mark A. Greer
-+# mgreer@mvista.com
-+# Ported and modified for mips support by
-+# Pete Popov <ppopov@mvista.com>
-+#
-+# 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.
-+
-+.c.s:
-+ $(CC) $(CFLAGS) -S -o $*.s $<
-+.s.o:
-+ $(AS) -o $*.o $<
-+.c.o:
-+ $(CC) $(CFLAGS) -D__BOOTER__ -c -o $*.o $<
-+.S.s:
-+ $(CPP) $(AFLAGS) -o $*.o $<
-+.S.o:
-+ $(CC) $(AFLAGS) -c -o $*.o $<
-+
-+#########################################################################
-+# START BOARD SPECIFIC VARIABLES
-+ifdef CONFIG_MIPS_PB1000
-+BNAME=pb1000
-+endif
-+
-+ifdef CONFIG_MIPS_PB1100
-+BNAME=pb1100
-+endif
-+
-+ifdef CONFIG_MIPS_PB1500
-+BNAME=pb1500
-+endif
-+
-+ifdef CONFIG_MIPS_PB1550
-+BNAME=pb1550
-+endif
-+
-+ifdef CONFIG_MIPS_DB1000
-+BNAME=db1000
-+endif
-+
-+ifdef CONFIG_MIPS_DB1100
-+BNAME=db1100
-+endif
-+
-+ifdef CONFIG_MIPS_DB1500
-+BNAME=db1500
-+endif
-+
-+ifdef CONFIG_MIPS_BOSPORUS
-+BNAME=bosporus
-+endif
-+
-+ifdef CONFIG_MIPS_MIRAGE
-+BNAME=mirage
-+endif
-+
-+ifdef CONFIG_MIPS_MTX1
-+BNAME=mtx-1
-+endif
-+
-+# These two variables control where the zImage is stored
-+# in flash and loaded in memory. It only controls how the srec
-+# file is generated, the code is the same.
-+RAM_RUN_ADDR = 0x81000000
-+FLASH_LOAD_ADDR = 0xBFD00000
-+
-+# These two variables specify the free ram region
-+# that can be used for temporary malloc area
-+AVAIL_RAM_START=0x80400000
-+AVAIL_RAM_END=0x80800000
-+
-+# This one must match the LOADADDR in arch/mips/Makefile!
-+LOADADDR=0x80100000
-+# END BOARD SPECIFIC VARIABLES
-+#########################################################################
-+
-+OBJECTS := head.o ../common/misc-common.o ../common/misc-simple.o \
-+ ../common/au1k_uart.o ../common/string.o ../common/ctype.o
-+LIBS := ../lib/zlib.a
-+
-+ENTRY := ../utils/entry
-+OFFSET := ../utils/offset
-+SIZE := ../utils/size
-+
-+LD_ARGS := -T ../ld.script -Ttext $(RAM_RUN_ADDR) -Bstatic
-+OBJCOPY_ARGS = -O elf32-tradlittlemips
-+
-+all: zImage
-+
-+clean:
-+ rm -rf *.o vmlinux* zvmlinux.* ../images/*.srec
-+
-+head.o: head.S $(TOPDIR)/vmlinux
-+ $(CC) $(AFLAGS) \
-+ -DKERNEL_ENTRY=$(shell sh $(ENTRY) $(NM) $(TOPDIR)/vmlinux ) \
-+ -c -o $*.o $<
-+
-+../common/misc-simple.o:
-+ $(CC) $(CFLAGS) -DINITRD_OFFSET=0 -DINITRD_SIZE=0 -DZIMAGE_OFFSET=0 \
-+ -DAVAIL_RAM_START=$(AVAIL_RAM_START) \
-+ -DAVAIL_RAM_END=$(AVAIL_RAM_END) \
-+ -DLOADADDR=$(LOADADDR) \
-+ -DZIMAGE_SIZE=0 -c -o $@ $*.c
-+
-+zvmlinux: $(OBJECTS) $(LIBS) ../ld.script ../images/vmlinux.gz ../common/dummy.o
-+ $(OBJCOPY) \
-+ --add-section=.image=../images/vmlinux.gz \
-+ --set-section-flags=.image=contents,alloc,load,readonly,data \
-+ ../common/dummy.o image.o
-+ $(LD) $(LD_ARGS) -o $@ $(OBJECTS) image.o $(LIBS)
-+ $(OBJCOPY) $(OBJCOPY_ARGS) $@ $@ -R .comment -R .stab -R .stabstr \
-+ -R .initrd -R .sysmap
-+
-+# Here we manipulate the image in order to get it the necessary
-+# srecord file we need.
-+zImage: zvmlinux
-+ mv zvmlinux ../images/zImage.$(BNAME)
-+ $(OBJCOPY) -O srec ../images/zImage.$(BNAME) ../images/$(BNAME).srec
-+
-+zImage.flash: zImage
-+ $(OBJCOPY) -O srec --adjust-vma 0x3ed00000 \
-+ ../images/zImage.$(BNAME) ../images/$(BNAME).flash.srec
-+
-+include $(TOPDIR)/Rules.make
-diff -Naru linux/arch/mips/zboot/utils/entry linux.spi/arch/mips/zboot/utils/entry
---- linux/arch/mips/zboot/utils/entry 1969-12-31 19:00:00.000000000 -0500
-+++ linux.spi/arch/mips/zboot/utils/entry 2004-05-11 23:19:24.000000000 -0400
-@@ -0,0 +1,12 @@
-+#!/bin/sh
-+
-+# grab the kernel_entry address from the vmlinux elf image
-+entry=`$1 $2 | grep kernel_entry`
-+
-+fs=`echo $entry | grep ffffffff` # check toolchain output
-+
-+if [ -n "$fs" ]; then
-+ echo "0x"`$1 $2 | grep kernel_entry | cut -c9- | awk '{print $1}'`
-+else
-+ echo "0x"`$1 $2 | grep kernel_entry | cut -c1- | awk '{print $1}'`
-+fi
-diff -Naru linux/arch/mips/zboot/utils/offset linux.spi/arch/mips/zboot/utils/offset
---- linux/arch/mips/zboot/utils/offset 1969-12-31 19:00:00.000000000 -0500
-+++ linux.spi/arch/mips/zboot/utils/offset 2004-05-11 23:19:24.000000000 -0400
-@@ -0,0 +1,3 @@
-+#!/bin/sh
-+
-+echo "0x"`$1 -h $2 | grep $3 | grep -v zvmlinux| awk '{print $6}'`
-diff -Naru linux/arch/mips/zboot/utils/size linux.spi/arch/mips/zboot/utils/size
---- linux/arch/mips/zboot/utils/size 1969-12-31 19:00:00.000000000 -0500
-+++ linux.spi/arch/mips/zboot/utils/size 2004-05-11 23:19:24.000000000 -0400
-@@ -0,0 +1,4 @@
-+#!/bin/sh
-+
-+OFFSET=`$1 -h $2 | grep $3 | grep -v zvmlinux | awk '{print $3}'`
-+echo "0x"$OFFSET
-diff -Naru linux/arch/mips/zboot/xxs1500/head.S linux.spi/arch/mips/zboot/xxs1500/head.S
---- linux/arch/mips/zboot/xxs1500/head.S 1969-12-31 19:00:00.000000000 -0500
-+++ linux.spi/arch/mips/zboot/xxs1500/head.S 2004-05-11 23:19:24.000000000 -0400
-@@ -0,0 +1,137 @@
-+/*
-+ * arch/mips/kernel/head.S
-+ *
-+ * This file is subject to the terms and conditions of the GNU General Public
-+ * License. See the file "COPYING" in the main directory of this archive
-+ * for more details.
-+ *
-+ * Copyright (C) 1994, 1995 Waldorf Electronics
-+ * Written by Ralf Baechle and Andreas Busse
-+ * Copyright (C) 1995 - 1999 Ralf Baechle
-+ * Copyright (C) 1996 Paul M. Antoine
-+ * Modified for DECStation and hence R3000 support by Paul M. Antoine
-+ * Further modifications by David S. Miller and Harald Koerfgen
-+ * Copyright (C) 1999 Silicon Graphics, Inc.
-+ *
-+ * Head.S contains the MIPS exception handler and startup code.
-+ *
-+ **************************************************************************
-+ * 9 Nov, 2000.
-+ * Added Cache Error exception handler and SBDDP EJTAG debug exception.
-+ *
-+ * Kevin Kissell, kevink@mips.com and Carsten Langgaard, carstenl@mips.com
-+ * Copyright (C) 2000 MIPS Technologies, Inc. All rights reserved.
-+ **************************************************************************
-+ */
-+#include <linux/config.h>
-+#include <linux/threads.h>
-+
-+#include <asm/asm.h>
-+#include <asm/cacheops.h>
-+#include <asm/mipsregs.h>
-+#include <asm/offset.h>
-+#include <asm/cachectl.h>
-+#include <asm/regdef.h>
-+
-+#define IndexInvalidate_I 0x00
-+
-+ .set noreorder
-+ .cprestore
-+ LEAF(start)
-+start:
-+
-+locate:
-+ la sp, .stack
-+ move s0, a0
-+ move s1, a1
-+ move s2, a2
-+ move s3, a3
-+
-+ la a0, start
-+
-+ li a1, FLASH_LOAD_ADDR
-+ la a2, _edata
-+ subu t1, a2, a0
-+ srl t1, t1, 2
-+
-+ /* copy text section */
-+ li t0, 0
-+1: lw v0, 0(a1)
-+ nop
-+ sw v0, 0(a0)
-+ xor t0, t0, v0
-+ addu a0, 4
-+ bne a2, a0, 1b
-+ addu a1, 4
-+
-+ /* Clear BSS */
-+ la a0, _edata
-+ la a2, _end
-+2: sw zero, 0(a0)
-+ bne a2, a0, 2b
-+ addu a0, 4
-+
-+ /* flush the I-Cache */
-+ li k0, 0x80000000 # start address
-+ li k1, 0x80004000 # end address (16KB I-Cache)
-+ subu k1, 128
-+
-+1:
-+ .set mips3
-+ cache IndexInvalidate_I, 0(k0)
-+ cache IndexInvalidate_I, 32(k0)
-+ cache IndexInvalidate_I, 64(k0)
-+ cache IndexInvalidate_I, 96(k0)
-+ .set mips0
-+
-+ bne k0, k1, 1b
-+ addu k0, k0, 128
-+ /* done */
-+
-+ li a0, FLASH_LOAD_ADDR /* load address */
-+ move a1, t1 /* length in words */
-+ move a2, t0 /* checksum */
-+ move a3, sp
-+
-+ la ra, 1f
-+ la k0, decompress_kernel
-+ jr k0
-+ nop
-+1:
-+
-+ move a0, s0
-+ move a1, s1
-+ move a2, s2
-+ move a3, s3
-+ li k0, KERNEL_ENTRY
-+ jr k0
-+ nop
-+3:
-+ b 3b
-+ END(start)
-+
-+ LEAF(udelay)
-+udelay:
-+ END(udelay)
-+
-+
-+ LEAF(FlushCache)
-+ li k0, 0x80000000 # start address
-+ li k1, 0x80004000 # end address (16KB I-Cache)
-+ subu k1, 128
-+
-+1:
-+ .set mips3
-+ cache IndexInvalidate_I, 0(k0)
-+ cache IndexInvalidate_I, 32(k0)
-+ cache IndexInvalidate_I, 64(k0)
-+ cache IndexInvalidate_I, 96(k0)
-+ .set mips0
-+
-+ bne k0, k1, 1b
-+ addu k0, k0, 128
-+ jr ra
-+ nop
-+ END(FlushCache)
-+
-+ .comm .stack,4096*2,4
-diff -Naru linux/arch/mips/zboot/xxs1500/ld.script linux.spi/arch/mips/zboot/xxs1500/ld.script
---- linux/arch/mips/zboot/xxs1500/ld.script 1969-12-31 19:00:00.000000000 -0500
-+++ linux.spi/arch/mips/zboot/xxs1500/ld.script 2004-05-11 23:19:24.000000000 -0400
-@@ -0,0 +1,147 @@
-+OUTPUT_ARCH(mips)
-+ENTRY(start)
-+SECTIONS
-+{
-+ /* Read-only sections, merged into text segment: */
-+ /* . = 0x81000000; */
-+ .init : { *(.init) } =0
-+ .text :
-+ {
-+ _ftext = . ;
-+ *(.text)
-+ *(.rodata)
-+ *(.rodata1)
-+ /* .gnu.warning sections are handled specially by elf32.em. */
-+ *(.gnu.warning)
-+ } =0
-+ .kstrtab : { *(.kstrtab) }
-+
-+ . = ALIGN(16); /* Exception table */
-+ __start___ex_table = .;
-+ __ex_table : { *(__ex_table) }
-+ __stop___ex_table = .;
-+
-+ __start___dbe_table = .; /* Exception table for data bus errors */
-+ __dbe_table : { *(__dbe_table) }
-+ __stop___dbe_table = .;
-+
-+ __start___ksymtab = .; /* Kernel symbol table */
-+ __ksymtab : { *(__ksymtab) }
-+ __stop___ksymtab = .;
-+
-+ _etext = .;
-+
-+ . = ALIGN(8192);
-+ .data.init_task : { *(.data.init_task) }
-+
-+ /* Startup code */
-+ . = ALIGN(4096);
-+ __init_begin = .;
-+ .text.init : { *(.text.init) }
-+ .data.init : { *(.data.init) }
-+ . = ALIGN(16);
-+ __setup_start = .;
-+ .setup.init : { *(.setup.init) }
-+ __setup_end = .;
-+ __initcall_start = .;
-+ .initcall.init : { *(.initcall.init) }
-+ __initcall_end = .;
-+ . = ALIGN(4096); /* Align double page for init_task_union */
-+ __init_end = .;
-+
-+ . = ALIGN(4096);
-+ .data.page_aligned : { *(.data.idt) }
-+
-+ . = ALIGN(32);
-+ .data.cacheline_aligned : { *(.data.cacheline_aligned) }
-+
-+ .fini : { *(.fini) } =0
-+ .reginfo : { *(.reginfo) }
-+ /* Adjust the address for the data segment. We want to adjust up to
-+ the same address within the page on the next page up. It would
-+ be more correct to do this:
-+ . = .;
-+ The current expression does not correctly handle the case of a
-+ text segment ending precisely at the end of a page; it causes the
-+ data segment to skip a page. The above expression does not have
-+ this problem, but it will currently (2/95) cause BFD to allocate
-+ a single segment, combining both text and data, for this case.
-+ This will prevent the text segment from being shared among
-+ multiple executions of the program; I think that is more
-+ important than losing a page of the virtual address space (note
-+ that no actual memory is lost; the page which is skipped can not
-+ be referenced). */
-+ . = .;
-+ .data :
-+ {
-+ _fdata = . ;
-+ *(.data)
-+
-+ /* Align the initial ramdisk image (INITRD) on page boundaries. */
-+ . = ALIGN(4096);
-+ __rd_start = .;
-+ *(.initrd)
-+ __rd_end = .;
-+ . = ALIGN(4096);
-+
-+ CONSTRUCTORS
-+ }
-+ .data1 : { *(.data1) }
-+ _gp = . + 0x8000;
-+ .lit8 : { *(.lit8) }
-+ .lit4 : { *(.lit4) }
-+ .ctors : { *(.ctors) }
-+ .dtors : { *(.dtors) }
-+ .got : { *(.got.plt) *(.got) }
-+ .dynamic : { *(.dynamic) }
-+ /* We want the small data sections together, so single-instruction offsets
-+ can access them all, and initialized data all before uninitialized, so
-+ we can shorten the on-disk segment size. */
-+ .sdata : { *(.sdata) }
-+ . = ALIGN(4);
-+ _edata = .;
-+ PROVIDE (edata = .);
-+
-+ __bss_start = .;
-+ _fbss = .;
-+ .sbss : { *(.sbss) *(.scommon) }
-+ .bss :
-+ {
-+ *(.dynbss)
-+ *(.bss)
-+ *(COMMON)
-+ . = ALIGN(4);
-+ _end = . ;
-+ PROVIDE (end = .);
-+ }
-+
-+ /* Sections to be discarded */
-+ /DISCARD/ :
-+ {
-+ *(.text.exit)
-+ *(.data.exit)
-+ *(.exitcall.exit)
-+ }
-+
-+ /* This is the MIPS specific mdebug section. */
-+ .mdebug : { *(.mdebug) }
-+ /* These are needed for ELF backends which have not yet been
-+ converted to the new style linker. */
-+ .stab 0 : { *(.stab) }
-+ .stabstr 0 : { *(.stabstr) }
-+ /* DWARF debug sections.
-+ Symbols in the .debug DWARF section are relative to the beginning of the
-+ section so we begin .debug at 0. It's not clear yet what needs to happen
-+ for the others. */
-+ .debug 0 : { *(.debug) }
-+ .debug_srcinfo 0 : { *(.debug_srcinfo) }
-+ .debug_aranges 0 : { *(.debug_aranges) }
-+ .debug_pubnames 0 : { *(.debug_pubnames) }
-+ .debug_sfnames 0 : { *(.debug_sfnames) }
-+ .line 0 : { *(.line) }
-+ /* These must appear regardless of . */
-+ .gptab.sdata : { *(.gptab.data) *(.gptab.sdata) }
-+ .gptab.sbss : { *(.gptab.bss) *(.gptab.sbss) }
-+ .comment : { *(.comment) }
-+ .note : { *(.note) }
-+}
-diff -Naru linux/arch/mips/zboot/xxs1500/Makefile linux.spi/arch/mips/zboot/xxs1500/Makefile
---- linux/arch/mips/zboot/xxs1500/Makefile 1969-12-31 19:00:00.000000000 -0500
-+++ linux.spi/arch/mips/zboot/xxs1500/Makefile 2004-05-11 23:19:24.000000000 -0400
-@@ -0,0 +1,123 @@
-+# arch/mips/compressed/alchemy/Makefile
-+#
-+# Makefile for Alchemy Semiconductor Pb1[015]00 boards.
-+# All of the boot loader code was derived from the ppc
-+# boot code.
-+#
-+# Copyright 2001,2002 MontaVista Software Inc.
-+#
-+# Author: Mark A. Greer
-+# mgreer@mvista.com
-+# Ported and modified for mips support by
-+# Pete Popov <ppopov@mvista.com>
-+#
-+# 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.
-+
-+.c.s:
-+ $(CC) $(CFLAGS) -S -o $*.s $<
-+.s.o:
-+ $(AS) -o $*.o $<
-+.c.o:
-+ $(CC) $(CFLAGS) -D__BOOTER__ -c -o $*.o $<
-+.S.s:
-+ $(CPP) $(AFLAGS) -o $*.o $<
-+.S.o:
-+ $(CC) $(AFLAGS) -c -o $*.o $<
-+
-+#########################################################################
-+# START BOARD SPECIFIC VARIABLES
-+BNAME=xxs1500
-+
-+
-+# These two variables control where the zImage is stored
-+# in flash and loaded in memory. If you change either one,
-+# be sure to make the appropriate change to the zImage
-+# rule.
-+RAM_LOAD_ADDR = 0x81000000
-+FLASH_LOAD_ADDR = 0xBF000000
-+
-+# These two variables specify the free ram region
-+# that can be used for temporary malloc area
-+AVAIL_RAM_START=0x80400000
-+AVAIL_RAM_END=0x80800000
-+
-+# This one must match the LOADADDR in arch/mips/Makefile!
-+LOADADDR=0x80100000
-+# END BOARD SPECIFIC VARIABLES
-+#########################################################################
-+
-+ZLINKFLAGS = -T ld.script -Ttext $(RAM_LOAD_ADDR)
-+
-+OBJECTS := head.o ../common/misc-common.o ../common/misc-simple.o \
-+ ../common/au1k_uart.o ../common/string.o ../common/ctype.o
-+LIBS := ../lib/zlib.a
-+
-+ENTRY := ../utils/entry
-+OFFSET := ../utils/offset
-+SIZE := ../utils/size
-+
-+all: zImage
-+
-+clean:
-+ rm -rf *.o vmlinux* zvmlinux.*
-+
-+head.o: head.S $(TOPDIR)/vmlinux
-+ $(CC) -DFLASH_LOAD_ADDR=$(FLASH_LOAD_ADDR) $(AFLAGS) \
-+ -DKERNEL_ENTRY=$(shell sh $(ENTRY) $(NM) $(TOPDIR)/vmlinux ) \
-+ -c -o $*.o $<
-+
-+../common/misc-simple.o:
-+ $(CC) $(CFLAGS) -DINITRD_OFFSET=0 -DINITRD_SIZE=0 -DZIMAGE_OFFSET=0 \
-+ -DAVAIL_RAM_START=$(AVAIL_RAM_START) \
-+ -DAVAIL_RAM_END=$(AVAIL_RAM_END) \
-+ -DLOADADDR=$(LOADADDR) \
-+ -DZIMAGE_SIZE=0 -c -o $@ $*.c
-+
-+# This is the first pass at building the boot loader image,
-+# without knowing the file offset where the vmlinuz.gz
-+# kernel will end up. We build this image, check the offset,
-+# and then rebuild it with the correct offset and size
-+# passed to mips-simple.c
-+zvmlinux.no: $(OBJECTS) $(LIBS) ../images/vmlinux.gz
-+ $(LD) $(ZLINKFLAGS) -o $@.tmp $(OBJECTS) $(LIBS)
-+ $(OBJCOPY) -R .comment \
-+ --add-section=image=../images/vmlinux.gz \
-+ $@.tmp $@
-+ # rm -f $@.tmp
-+
-+
-+# This is the final image we build, now that we know what
-+# the vmlinuz.gz offset is.
-+zvmlinux: $(OBJECTS) $(LIBS) ../images/vmlinux.gz zvmlinux.no
-+ $(CC) $(CFLAGS) -DINITRD_OFFSET=0 -DINITRD_SIZE=0 \
-+ -DZIMAGE_OFFSET=$(shell sh $(OFFSET) $(OBJDUMP) $@.no image) \
-+ -DZIMAGE_SIZE=$(shell sh $(SIZE) $(OBJDUMP) $@.no image) \
-+ -D__BOOTER__ \
-+ -DAVAIL_RAM_START=$(AVAIL_RAM_START) \
-+ -DAVAIL_RAM_END=$(AVAIL_RAM_END) \
-+ -DLOADADDR=$(LOADADDR) \
-+ -c -o ../common/misc-simple.o ../common/misc-simple.c
-+ $(LD) $(ZLINKFLAGS) -o $@.tmp $(OBJECTS) $(LIBS)
-+ $(OBJCOPY) -R .comment \
-+ --add-section=image=../images/vmlinux.gz \
-+ $@.tmp $@
-+ $(OBJCOPY) --adjust-section-vma=image+$(RAM_LOAD_ADDR) $@
-+ $(OBJCOPY) --adjust-section-vma=image+$(shell sh $(OFFSET) \
-+ $(OBJDUMP) $@.no image ) $@
-+ # rm -f $@.tmp
-+ # rm -f $@.no
-+
-+
-+# Here we manipulate the image in order to get it the necessary
-+# srecord file we need.
-+zImage: zvmlinux
-+ mv zvmlinux ../images/$@.$(BNAME)
-+ $(OBJCOPY) --set-section-flags=image=alloc,load,code ../images/$@.$(BNAME)
-+ $(OBJCOPY) -O srec --adjust-vma 0x3e000000 \
-+ ../images/$@.$(BNAME) ../images/$@.$(BNAME).srec
-+ # rm ../images/vmlinux.gz
-+
-+include $(TOPDIR)/Rules.make
diff --git a/recipes/linux/linux-mtx-1-2.4.27/07-zboot-zimage-flash-bin.diff b/recipes/linux/linux-mtx-1-2.4.27/07-zboot-zimage-flash-bin.diff
deleted file mode 100644
index dca79a3000..0000000000
--- a/recipes/linux/linux-mtx-1-2.4.27/07-zboot-zimage-flash-bin.diff
+++ /dev/null
@@ -1,11 +0,0 @@
-diff -Nurb oe/tmp/work/linux-mtx-1-2.4.27-r0/linux/arch/mips/zboot/pb1xxx/Makefile linux.m/arch/mips/zboot/pb1xxx/Makefile
---- oe/tmp/work/linux-mtx-1-2.4.27-r0/linux/arch/mips/zboot/pb1xxx/Makefile 2004-10-13 21:08:49.840408328 +0200
-+++ linux.m/arch/mips/zboot/pb1xxx/Makefile 2004-10-13 21:08:29.736464592 +0200
-@@ -131,5 +131,7 @@
- zImage.flash: zImage
- $(OBJCOPY) -O srec --adjust-vma 0x3ed00000 \
- ../images/zImage.$(BNAME) ../images/$(BNAME).flash.srec
-+ $(OBJCOPY) -O binary --adjust-vma 0x3ed00000 \
-+ ../images/zImage.$(BNAME) ../images/$(BNAME).flash.bin
-
- include $(TOPDIR)/Rules.make
diff --git a/recipes/linux/linux-mtx-1-2.4.27/08-usb-nonpci-2.4.24.patch b/recipes/linux/linux-mtx-1-2.4.27/08-usb-nonpci-2.4.24.patch
deleted file mode 100644
index ca093e1a67..0000000000
--- a/recipes/linux/linux-mtx-1-2.4.27/08-usb-nonpci-2.4.24.patch
+++ /dev/null
@@ -1,3185 +0,0 @@
-diff -Nurb linux-mips-2.4.27/drivers/usb/host/Config.in linux/drivers/usb/host/Config.in
---- linux-mips-2.4.27/drivers/usb/host/Config.in 2003-11-17 02:07:42.000000000 +0100
-+++ linux/drivers/usb/host/Config.in 2004-11-23 11:24:10.599627448 +0100
-@@ -17,3 +17,4 @@
- dep_tristate ' SL811HS Alternate (x86, StrongARM, isosynchronous mode)' CONFIG_USB_SL811HS_ALT $CONFIG_USB $CONFIG_EXPERIMENTAL
- dep_tristate ' SL811HS (x86, StrongARM) support, old driver' CONFIG_USB_SL811HS $CONFIG_USB $CONFIG_EXPERIMENTAL
- fi
-+dep_tristate ' Non-PCI OHCI support' CONFIG_USB_NON_PCI_OHCI $CONFIG_USB_OHCI
-diff -Nurb linux-mips-2.4.27/drivers/usb/host/usb-ohci.c linux/drivers/usb/host/usb-ohci.c
---- linux-mips-2.4.27/drivers/usb/host/usb-ohci.c 2004-04-16 05:14:18.000000000 +0200
-+++ linux/drivers/usb/host/usb-ohci.c 2004-11-23 11:24:10.602626992 +0100
-@@ -2564,6 +2564,7 @@
- hc_release_ohci (ohci);
- return ret;
- }
-+#ifndef CONFIG_USB_NON_PCI_OHCI
- ohci->flags = id->driver_data;
-
- /* Check for NSC87560. We have to look at the bridge (fn1) to identify
-@@ -2582,6 +2583,7 @@
- printk (KERN_INFO __FILE__ ": Using NSC SuperIO setup\n");
- if (ohci->flags & OHCI_QUIRK_AMD756)
- printk (KERN_INFO __FILE__ ": AMD756 erratum 4 workaround\n");
-+#endif
-
- if (hc_reset (ohci) < 0) {
- hc_release_ohci (ohci);
-@@ -2627,8 +2629,10 @@
- int temp;
- int i;
-
-+#ifndef CONFIG_USB_NON_PCI_OHCI
- if (ohci->pci_latency)
- pci_write_config_byte (ohci->ohci_dev, PCI_LATENCY_TIMER, ohci->pci_latency);
-+#endif
-
- ohci->disabled = 1;
- ohci->sleeping = 0;
-@@ -2658,6 +2662,7 @@
-
- /*-------------------------------------------------------------------------*/
-
-+#ifndef CONFIG_USB_NON_PCI_OHCI
- /* configured so that an OHCI device is always provided */
- /* always called with process context; sleeping is OK */
-
-@@ -2705,6 +2710,88 @@
- }
- return status;
- }
-+#else /* CONFIG_USB_NON_PCI_OHCI */
-+
-+// Boot options
-+static int ohci_base=0, ohci_len=0;
-+static int ohci_irq=-1;
-+
-+MODULE_PARM(ohci_base, "i");
-+MODULE_PARM(ohci_len, "i");
-+MODULE_PARM(ohci_irq, "i");
-+MODULE_PARM_DESC(ohci_base, "IO Base address of OHCI Oper. registers");
-+MODULE_PARM_DESC(ohci_len, "IO length of OHCI Oper. registers");
-+MODULE_PARM_DESC(ohci_irq, "IRQ for OHCI interrupts");
-+
-+// bogus pci_dev
-+static struct pci_dev bogus_pcidev;
-+
-+static struct pci_driver ohci_pci_driver = {
-+ name: "usb-ohci",
-+};
-+
-+static int __devinit
-+ohci_non_pci_init (void)
-+{
-+ void *mem_base;
-+
-+ if (!ohci_base || !ohci_len || (ohci_irq < 0))
-+ return -ENODEV;
-+
-+ if (!request_mem_region (ohci_base, ohci_len, ohci_pci_driver.name)) {
-+ dbg ("controller already in use");
-+ return -EBUSY;
-+ }
-+
-+ mem_base = ioremap_nocache (ohci_base, ohci_len);
-+ if (!mem_base) {
-+ err("Error mapping OHCI memory");
-+ return -EFAULT;
-+ }
-+
-+ /*
-+ * Fill in the bogus pci_dev. Only those members actually
-+ * dereferenced in this driver are initialized.
-+ */
-+ memset(&bogus_pcidev, 0, sizeof(struct pci_dev));
-+ strcpy(bogus_pcidev.name, "non-PCI OHCI");
-+ strcpy(bogus_pcidev.slot_name, "builtin");
-+ bogus_pcidev.resource[0].name = "OHCI Operational Registers";
-+ bogus_pcidev.resource[0].start = ohci_base;
-+ bogus_pcidev.resource[0].end = ohci_base + ohci_len;
-+ bogus_pcidev.resource[0].flags = 0;
-+ bogus_pcidev.irq = ohci_irq;
-+
-+ return hc_found_ohci (&bogus_pcidev, bogus_pcidev.irq, mem_base, NULL);
-+}
-+
-+#ifndef MODULE
-+
-+static int __init
-+ohci_setup (char* options)
-+{
-+ char* this_opt;
-+
-+ if (!options || !*options)
-+ return 0;
-+
-+ for(this_opt=strtok(options,",");this_opt;this_opt=strtok(NULL,",")) {
-+ if (!strncmp(this_opt, "base:", 5)) {
-+ ohci_base = simple_strtoul(this_opt+5, NULL, 0);
-+ } else if (!strncmp(this_opt, "len:", 4)) {
-+ ohci_len = simple_strtoul(this_opt+4, NULL, 0);
-+ } else if (!strncmp(this_opt, "irq:", 4)) {
-+ ohci_irq = simple_strtoul(this_opt+4, NULL, 0);
-+ }
-+ }
-+ return 0;
-+}
-+
-+__setup("usb_ohci=", ohci_setup);
-+
-+#endif /* !MODULE */
-+
-+#endif /* CONFIG_USB_NON_PCI_OHCI */
-
- /*-------------------------------------------------------------------------*/
-
-@@ -2745,6 +2832,7 @@
- }
-
-
-+#ifndef CONFIG_USB_NON_PCI_OHCI
- #ifdef CONFIG_PM
-
- /*-------------------------------------------------------------------------*/
-@@ -2983,20 +3071,29 @@
- resume: ohci_pci_resume,
- #endif /* PM */
- };
-+#endif /* CONFIG_USB_NON_PCI_OHCI */
-
-
- /*-------------------------------------------------------------------------*/
-
- static int __init ohci_hcd_init (void)
- {
-+#ifndef CONFIG_USB_NON_PCI_OHCI
- return pci_module_init (&ohci_pci_driver);
-+#else
-+ return ohci_non_pci_init();
-+#endif
- }
-
- /*-------------------------------------------------------------------------*/
-
- static void __exit ohci_hcd_cleanup (void)
- {
-+#ifndef CONFIG_USB_NON_PCI_OHCI
- pci_unregister_driver (&ohci_pci_driver);
-+#else
-+ ohci_pci_remove(&bogus_pcidev);
-+#endif
- }
-
- module_init (ohci_hcd_init);
-diff -Nurb linux-mips-2.4.27/drivers/usb/host/usb-ohci.c.orig linux/drivers/usb/host/usb-ohci.c.orig
---- linux-mips-2.4.27/drivers/usb/host/usb-ohci.c.orig 1970-01-01 01:00:00.000000000 +0100
-+++ linux/drivers/usb/host/usb-ohci.c.orig 2004-11-23 11:21:54.984244120 +0100
-@@ -0,0 +1,3008 @@
-+/*
-+ * URB OHCI HCD (Host Controller Driver) for USB.
-+ *
-+ * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
-+ * (C) Copyright 2000-2001 David Brownell <dbrownell@users.sourceforge.net>
-+ *
-+ * [ Initialisation is based on Linus' ]
-+ * [ uhci code and gregs ohci fragments ]
-+ * [ (C) Copyright 1999 Linus Torvalds ]
-+ * [ (C) Copyright 1999 Gregory P. Smith]
-+ *
-+ *
-+ * History:
-+ *
-+ * 2002/10/22 OHCI_USB_OPER for ALi lockup in IBM i1200 (ALEX <thchou@ali>)
-+ * 2002/03/08 interrupt unlink fix (Matt Hughes), better cleanup on
-+ * load failure (Matthew Frederickson)
-+ * 2002/01/20 async unlink fixes: return -EINPROGRESS (per spec) and
-+ * make interrupt unlink-in-completion work (db)
-+ * 2001/09/19 USB_ZERO_PACKET support (Jean Tourrilhes)
-+ * 2001/07/17 power management and pmac cleanup (Benjamin Herrenschmidt)
-+ * 2001/03/24 td/ed hashing to remove bus_to_virt (Steve Longerbeam);
-+ pci_map_single (db)
-+ * 2001/03/21 td and dev/ed allocation uses new pci_pool API (db)
-+ * 2001/03/07 hcca allocation uses pci_alloc_consistent (Steve Longerbeam)
-+ *
-+ * 2000/09/26 fixed races in removing the private portion of the urb
-+ * 2000/09/07 disable bulk and control lists when unlinking the last
-+ * endpoint descriptor in order to avoid unrecoverable errors on
-+ * the Lucent chips. (rwc@sgi)
-+ * 2000/08/29 use bandwidth claiming hooks (thanks Randy!), fix some
-+ * urb unlink probs, indentation fixes
-+ * 2000/08/11 various oops fixes mostly affecting iso and cleanup from
-+ * device unplugs.
-+ * 2000/06/28 use PCI hotplug framework, for better power management
-+ * and for Cardbus support (David Brownell)
-+ * 2000/earlier: fixes for NEC/Lucent chips; suspend/resume handling
-+ * when the controller loses power; handle UE; cleanup; ...
-+ *
-+ * v5.2 1999/12/07 URB 3rd preview,
-+ * v5.1 1999/11/30 URB 2nd preview, cpia, (usb-scsi)
-+ * v5.0 1999/11/22 URB Technical preview, Paul Mackerras powerbook susp/resume
-+ * i386: HUB, Keyboard, Mouse, Printer
-+ *
-+ * v4.3 1999/10/27 multiple HCs, bulk_request
-+ * v4.2 1999/09/05 ISO API alpha, new dev alloc, neg Error-codes
-+ * v4.1 1999/08/27 Randy Dunlap's - ISO API first impl.
-+ * v4.0 1999/08/18
-+ * v3.0 1999/06/25
-+ * v2.1 1999/05/09 code clean up
-+ * v2.0 1999/05/04
-+ * v1.0 1999/04/27 initial release
-+ */
-+
-+#include <linux/config.h>
-+#include <linux/module.h>
-+#include <linux/pci.h>
-+#include <linux/kernel.h>
-+#include <linux/delay.h>
-+#include <linux/ioport.h>
-+#include <linux/sched.h>
-+#include <linux/slab.h>
-+#include <linux/smp_lock.h>
-+#include <linux/errno.h>
-+#include <linux/init.h>
-+#include <linux/timer.h>
-+#include <linux/list.h>
-+#include <linux/interrupt.h> /* for in_interrupt() */
-+#undef DEBUG
-+#include <linux/usb.h>
-+
-+#include <asm/io.h>
-+#include <asm/irq.h>
-+#include <asm/system.h>
-+#include <asm/unaligned.h>
-+
-+#define OHCI_USE_NPS // force NoPowerSwitching mode
-+// #define OHCI_VERBOSE_DEBUG /* not always helpful */
-+
-+#include "usb-ohci.h"
-+
-+#include "../hcd.h"
-+
-+#ifdef CONFIG_PMAC_PBOOK
-+#include <asm/machdep.h>
-+#include <asm/pmac_feature.h>
-+#include <asm/pci-bridge.h>
-+#ifndef CONFIG_PM
-+#define CONFIG_PM
-+#endif
-+#endif
-+
-+
-+/*
-+ * Version Information
-+ */
-+#define DRIVER_VERSION "v5.3"
-+#define DRIVER_AUTHOR "Roman Weissgaerber <weissg@vienna.at>, David Brownell"
-+#define DRIVER_DESC "USB OHCI Host Controller Driver"
-+
-+/* For initializing controller (mask in an HCFS mode too) */
-+#define OHCI_CONTROL_INIT \
-+ (OHCI_CTRL_CBSR & 0x3) | OHCI_CTRL_IE | OHCI_CTRL_PLE
-+
-+#define OHCI_UNLINK_TIMEOUT (HZ / 10)
-+
-+/*-------------------------------------------------------------------------*/
-+
-+/* AMD-756 (D2 rev) reports corrupt register contents in some cases.
-+ * The erratum (#4) description is incorrect. AMD's workaround waits
-+ * till some bits (mostly reserved) are clear; ok for all revs.
-+ */
-+#define read_roothub(hc, register, mask) ({ \
-+ u32 temp = readl (&hc->regs->roothub.register); \
-+ if (hc->flags & OHCI_QUIRK_AMD756) \
-+ while (temp & mask) \
-+ temp = readl (&hc->regs->roothub.register); \
-+ temp; })
-+
-+static u32 roothub_a (struct ohci *hc)
-+ { return read_roothub (hc, a, 0xfc0fe000); }
-+static inline u32 roothub_b (struct ohci *hc)
-+ { return readl (&hc->regs->roothub.b); }
-+static inline u32 roothub_status (struct ohci *hc)
-+ { return readl (&hc->regs->roothub.status); }
-+static u32 roothub_portstatus (struct ohci *hc, int i)
-+ { return read_roothub (hc, portstatus [i], 0xffe0fce0); }
-+
-+
-+/*-------------------------------------------------------------------------*
-+ * URB support functions
-+ *-------------------------------------------------------------------------*/
-+
-+static void ohci_complete_add(struct ohci *ohci, struct urb *urb)
-+{
-+
-+ if (urb->hcpriv != NULL) {
-+ printk("completing with non-null priv!\n");
-+ return;
-+ }
-+
-+ if (ohci->complete_tail == NULL) {
-+ ohci->complete_head = urb;
-+ ohci->complete_tail = urb;
-+ } else {
-+ ohci->complete_head->hcpriv = urb;
-+ ohci->complete_tail = urb;
-+ }
-+}
-+
-+static inline struct urb *ohci_complete_get(struct ohci *ohci)
-+{
-+ struct urb *urb;
-+
-+ if ((urb = ohci->complete_head) == NULL)
-+ return NULL;
-+ if (urb == ohci->complete_tail) {
-+ ohci->complete_tail = NULL;
-+ ohci->complete_head = NULL;
-+ } else {
-+ ohci->complete_head = urb->hcpriv;
-+ }
-+ urb->hcpriv = NULL;
-+ return urb;
-+}
-+
-+static inline void ohci_complete(struct ohci *ohci)
-+{
-+ struct urb *urb;
-+
-+ spin_lock(&ohci->ohci_lock);
-+ while ((urb = ohci_complete_get(ohci)) != NULL) {
-+ spin_unlock(&ohci->ohci_lock);
-+ if (urb->dev) {
-+ usb_dec_dev_use (urb->dev);
-+ urb->dev = NULL;
-+ }
-+ if (urb->complete)
-+ (*urb->complete)(urb);
-+ spin_lock(&ohci->ohci_lock);
-+ }
-+ spin_unlock(&ohci->ohci_lock);
-+}
-+
-+/* free HCD-private data associated with this URB */
-+
-+static void urb_free_priv (struct ohci *hc, urb_priv_t * urb_priv)
-+{
-+ int i;
-+ int last = urb_priv->length - 1;
-+ int len;
-+ int dir;
-+ struct td *td;
-+
-+ if (last >= 0) {
-+
-+ /* ISOC, BULK, INTR data buffer starts at td 0
-+ * CTRL setup starts at td 0 */
-+ td = urb_priv->td [0];
-+
-+ len = td->urb->transfer_buffer_length,
-+ dir = usb_pipeout (td->urb->pipe)
-+ ? PCI_DMA_TODEVICE
-+ : PCI_DMA_FROMDEVICE;
-+
-+ /* unmap CTRL URB setup */
-+ if (usb_pipecontrol (td->urb->pipe)) {
-+ pci_unmap_single (hc->ohci_dev,
-+ td->data_dma, 8, PCI_DMA_TODEVICE);
-+
-+ /* CTRL data buffer starts at td 1 if len > 0 */
-+ if (len && last > 0)
-+ td = urb_priv->td [1];
-+ }
-+
-+ /* unmap data buffer */
-+ if (len && td->data_dma)
-+ pci_unmap_single (hc->ohci_dev, td->data_dma, len, dir);
-+
-+ for (i = 0; i <= last; i++) {
-+ td = urb_priv->td [i];
-+ if (td)
-+ td_free (hc, td);
-+ }
-+ }
-+
-+ kfree (urb_priv);
-+}
-+
-+static void urb_rm_priv_locked (struct urb * urb)
-+{
-+ urb_priv_t * urb_priv = urb->hcpriv;
-+
-+ if (urb_priv) {
-+ urb->hcpriv = NULL;
-+
-+#ifdef DO_TIMEOUTS
-+ if (urb->timeout) {
-+ list_del (&urb->urb_list);
-+ urb->timeout -= jiffies;
-+ }
-+#endif
-+
-+ /* Release int/iso bandwidth */
-+ if (urb->bandwidth) {
-+ switch (usb_pipetype(urb->pipe)) {
-+ case PIPE_INTERRUPT:
-+ usb_release_bandwidth (urb->dev, urb, 0);
-+ break;
-+ case PIPE_ISOCHRONOUS:
-+ usb_release_bandwidth (urb->dev, urb, 1);
-+ break;
-+ default:
-+ break;
-+ }
-+ }
-+
-+ urb_free_priv ((struct ohci *)urb->dev->bus->hcpriv, urb_priv);
-+ } else {
-+ if (urb->dev != NULL) {
-+ err ("Non-null dev at rm_priv time");
-+ // urb->dev = NULL;
-+ }
-+ }
-+}
-+
-+/*-------------------------------------------------------------------------*/
-+
-+#ifdef DEBUG
-+static int sohci_get_current_frame_number (struct usb_device * dev);
-+
-+/* debug| print the main components of an URB
-+ * small: 0) header + data packets 1) just header */
-+
-+static void urb_print (struct urb * urb, char * str, int small)
-+{
-+ unsigned int pipe= urb->pipe;
-+
-+ if (!urb->dev || !urb->dev->bus) {
-+ dbg("%s URB: no dev", str);
-+ return;
-+ }
-+
-+#ifndef OHCI_VERBOSE_DEBUG
-+ if (urb->status != 0)
-+#endif
-+ dbg("%s URB:[%4x] dev:%2d,ep:%2d-%c,type:%s,flags:%4x,len:%d/%d,stat:%d(%x)",
-+ str,
-+ sohci_get_current_frame_number (urb->dev),
-+ usb_pipedevice (pipe),
-+ usb_pipeendpoint (pipe),
-+ usb_pipeout (pipe)? 'O': 'I',
-+ usb_pipetype (pipe) < 2? (usb_pipeint (pipe)? "INTR": "ISOC"):
-+ (usb_pipecontrol (pipe)? "CTRL": "BULK"),
-+ urb->transfer_flags,
-+ urb->actual_length,
-+ urb->transfer_buffer_length,
-+ urb->status, urb->status);
-+#ifdef OHCI_VERBOSE_DEBUG
-+ if (!small) {
-+ int i, len;
-+
-+ if (usb_pipecontrol (pipe)) {
-+ printk (KERN_DEBUG __FILE__ ": cmd(8):");
-+ for (i = 0; i < 8 ; i++)
-+ printk (" %02x", ((__u8 *) urb->setup_packet) [i]);
-+ printk ("\n");
-+ }
-+ if (urb->transfer_buffer_length > 0 && urb->transfer_buffer) {
-+ printk (KERN_DEBUG __FILE__ ": data(%d/%d):",
-+ urb->actual_length,
-+ urb->transfer_buffer_length);
-+ len = usb_pipeout (pipe)?
-+ urb->transfer_buffer_length: urb->actual_length;
-+ for (i = 0; i < 16 && i < len; i++)
-+ printk (" %02x", ((__u8 *) urb->transfer_buffer) [i]);
-+ printk ("%s stat:%d\n", i < len? "...": "", urb->status);
-+ }
-+ }
-+#endif
-+}
-+
-+/* just for debugging; prints non-empty branches of the int ed tree inclusive iso eds*/
-+void ep_print_int_eds (ohci_t * ohci, char * str) {
-+ int i, j;
-+ __u32 * ed_p;
-+ for (i= 0; i < 32; i++) {
-+ j = 5;
-+ ed_p = &(ohci->hcca->int_table [i]);
-+ if (*ed_p == 0)
-+ continue;
-+ printk (KERN_DEBUG __FILE__ ": %s branch int %2d(%2x):", str, i, i);
-+ while (*ed_p != 0 && j--) {
-+ ed_t *ed = dma_to_ed (ohci, le32_to_cpup(ed_p));
-+ printk (" ed: %4x;", ed->hwINFO);
-+ ed_p = &ed->hwNextED;
-+ }
-+ printk ("\n");
-+ }
-+}
-+
-+
-+static void ohci_dump_intr_mask (char *label, __u32 mask)
-+{
-+ dbg ("%s: 0x%08x%s%s%s%s%s%s%s%s%s",
-+ label,
-+ mask,
-+ (mask & OHCI_INTR_MIE) ? " MIE" : "",
-+ (mask & OHCI_INTR_OC) ? " OC" : "",
-+ (mask & OHCI_INTR_RHSC) ? " RHSC" : "",
-+ (mask & OHCI_INTR_FNO) ? " FNO" : "",
-+ (mask & OHCI_INTR_UE) ? " UE" : "",
-+ (mask & OHCI_INTR_RD) ? " RD" : "",
-+ (mask & OHCI_INTR_SF) ? " SF" : "",
-+ (mask & OHCI_INTR_WDH) ? " WDH" : "",
-+ (mask & OHCI_INTR_SO) ? " SO" : ""
-+ );
-+}
-+
-+static void maybe_print_eds (char *label, __u32 value)
-+{
-+ if (value)
-+ dbg ("%s %08x", label, value);
-+}
-+
-+static char *hcfs2string (int state)
-+{
-+ switch (state) {
-+ case OHCI_USB_RESET: return "reset";
-+ case OHCI_USB_RESUME: return "resume";
-+ case OHCI_USB_OPER: return "operational";
-+ case OHCI_USB_SUSPEND: return "suspend";
-+ }
-+ return "?";
-+}
-+
-+// dump control and status registers
-+static void ohci_dump_status (ohci_t *controller)
-+{
-+ struct ohci_regs *regs = controller->regs;
-+ __u32 temp;
-+
-+ temp = readl (&regs->revision) & 0xff;
-+ if (temp != 0x10)
-+ dbg ("spec %d.%d", (temp >> 4), (temp & 0x0f));
-+
-+ temp = readl (&regs->control);
-+ dbg ("control: 0x%08x%s%s%s HCFS=%s%s%s%s%s CBSR=%d", temp,
-+ (temp & OHCI_CTRL_RWE) ? " RWE" : "",
-+ (temp & OHCI_CTRL_RWC) ? " RWC" : "",
-+ (temp & OHCI_CTRL_IR) ? " IR" : "",
-+ hcfs2string (temp & OHCI_CTRL_HCFS),
-+ (temp & OHCI_CTRL_BLE) ? " BLE" : "",
-+ (temp & OHCI_CTRL_CLE) ? " CLE" : "",
-+ (temp & OHCI_CTRL_IE) ? " IE" : "",
-+ (temp & OHCI_CTRL_PLE) ? " PLE" : "",
-+ temp & OHCI_CTRL_CBSR
-+ );
-+
-+ temp = readl (&regs->cmdstatus);
-+ dbg ("cmdstatus: 0x%08x SOC=%d%s%s%s%s", temp,
-+ (temp & OHCI_SOC) >> 16,
-+ (temp & OHCI_OCR) ? " OCR" : "",
-+ (temp & OHCI_BLF) ? " BLF" : "",
-+ (temp & OHCI_CLF) ? " CLF" : "",
-+ (temp & OHCI_HCR) ? " HCR" : ""
-+ );
-+
-+ ohci_dump_intr_mask ("intrstatus", readl (&regs->intrstatus));
-+ ohci_dump_intr_mask ("intrenable", readl (&regs->intrenable));
-+ // intrdisable always same as intrenable
-+ // ohci_dump_intr_mask ("intrdisable", readl (&regs->intrdisable));
-+
-+ maybe_print_eds ("ed_periodcurrent", readl (&regs->ed_periodcurrent));
-+
-+ maybe_print_eds ("ed_controlhead", readl (&regs->ed_controlhead));
-+ maybe_print_eds ("ed_controlcurrent", readl (&regs->ed_controlcurrent));
-+
-+ maybe_print_eds ("ed_bulkhead", readl (&regs->ed_bulkhead));
-+ maybe_print_eds ("ed_bulkcurrent", readl (&regs->ed_bulkcurrent));
-+
-+ maybe_print_eds ("donehead", readl (&regs->donehead));
-+}
-+
-+static void ohci_dump_roothub (ohci_t *controller, int verbose)
-+{
-+ __u32 temp, ndp, i;
-+
-+ temp = roothub_a (controller);
-+ if (temp == ~(u32)0)
-+ return;
-+ ndp = (temp & RH_A_NDP);
-+
-+ if (verbose) {
-+ dbg ("roothub.a: %08x POTPGT=%d%s%s%s%s%s NDP=%d", temp,
-+ ((temp & RH_A_POTPGT) >> 24) & 0xff,
-+ (temp & RH_A_NOCP) ? " NOCP" : "",
-+ (temp & RH_A_OCPM) ? " OCPM" : "",
-+ (temp & RH_A_DT) ? " DT" : "",
-+ (temp & RH_A_NPS) ? " NPS" : "",
-+ (temp & RH_A_PSM) ? " PSM" : "",
-+ ndp
-+ );
-+ temp = roothub_b (controller);
-+ dbg ("roothub.b: %08x PPCM=%04x DR=%04x",
-+ temp,
-+ (temp & RH_B_PPCM) >> 16,
-+ (temp & RH_B_DR)
-+ );
-+ temp = roothub_status (controller);
-+ dbg ("roothub.status: %08x%s%s%s%s%s%s",
-+ temp,
-+ (temp & RH_HS_CRWE) ? " CRWE" : "",
-+ (temp & RH_HS_OCIC) ? " OCIC" : "",
-+ (temp & RH_HS_LPSC) ? " LPSC" : "",
-+ (temp & RH_HS_DRWE) ? " DRWE" : "",
-+ (temp & RH_HS_OCI) ? " OCI" : "",
-+ (temp & RH_HS_LPS) ? " LPS" : ""
-+ );
-+ }
-+
-+ for (i = 0; i < ndp; i++) {
-+ temp = roothub_portstatus (controller, i);
-+ dbg ("roothub.portstatus [%d] = 0x%08x%s%s%s%s%s%s%s%s%s%s%s%s",
-+ i,
-+ temp,
-+ (temp & RH_PS_PRSC) ? " PRSC" : "",
-+ (temp & RH_PS_OCIC) ? " OCIC" : "",
-+ (temp & RH_PS_PSSC) ? " PSSC" : "",
-+ (temp & RH_PS_PESC) ? " PESC" : "",
-+ (temp & RH_PS_CSC) ? " CSC" : "",
-+
-+ (temp & RH_PS_LSDA) ? " LSDA" : "",
-+ (temp & RH_PS_PPS) ? " PPS" : "",
-+ (temp & RH_PS_PRS) ? " PRS" : "",
-+ (temp & RH_PS_POCI) ? " POCI" : "",
-+ (temp & RH_PS_PSS) ? " PSS" : "",
-+
-+ (temp & RH_PS_PES) ? " PES" : "",
-+ (temp & RH_PS_CCS) ? " CCS" : ""
-+ );
-+ }
-+}
-+
-+static void ohci_dump (ohci_t *controller, int verbose)
-+{
-+ dbg ("OHCI controller usb-%s state", controller->ohci_dev->slot_name);
-+
-+ // dumps some of the state we know about
-+ ohci_dump_status (controller);
-+ if (verbose)
-+ ep_print_int_eds (controller, "hcca");
-+ dbg ("hcca frame #%04x", controller->hcca->frame_no);
-+ ohci_dump_roothub (controller, 1);
-+}
-+
-+
-+#endif
-+
-+/*-------------------------------------------------------------------------*
-+ * Interface functions (URB)
-+ *-------------------------------------------------------------------------*/
-+
-+/* return a request to the completion handler */
-+
-+static int sohci_return_urb (struct ohci *hc, struct urb * urb)
-+{
-+ urb_priv_t * urb_priv = urb->hcpriv;
-+ struct urb * urbt;
-+ int i;
-+
-+ if (!urb_priv)
-+ return -1; /* urb already unlinked */
-+
-+ /* just to be sure */
-+ if (!urb->complete) {
-+ urb_rm_priv_locked (urb);
-+ ohci_complete_add(hc, urb); /* Just usb_dec_dev_use */
-+ return -1;
-+ }
-+
-+#ifdef DEBUG
-+ urb_print (urb, "RET", usb_pipeout (urb->pipe));
-+#endif
-+
-+ switch (usb_pipetype (urb->pipe)) {
-+ case PIPE_INTERRUPT:
-+ pci_unmap_single (hc->ohci_dev,
-+ urb_priv->td [0]->data_dma,
-+ urb->transfer_buffer_length,
-+ usb_pipeout (urb->pipe)
-+ ? PCI_DMA_TODEVICE
-+ : PCI_DMA_FROMDEVICE);
-+ if (urb->interval) {
-+ urb->complete (urb);
-+
-+ /* implicitly requeued */
-+ urb->actual_length = 0;
-+ urb->status = -EINPROGRESS;
-+ td_submit_urb (urb);
-+ } else {
-+ urb_rm_priv_locked (urb);
-+ ohci_complete_add(hc, urb);
-+ }
-+ break;
-+
-+ case PIPE_ISOCHRONOUS:
-+ for (urbt = urb->next; urbt && (urbt != urb); urbt = urbt->next);
-+ if (urbt) { /* send the reply and requeue URB */
-+ pci_unmap_single (hc->ohci_dev,
-+ urb_priv->td [0]->data_dma,
-+ urb->transfer_buffer_length,
-+ usb_pipeout (urb->pipe)
-+ ? PCI_DMA_TODEVICE
-+ : PCI_DMA_FROMDEVICE);
-+ urb->complete (urb);
-+ urb->actual_length = 0;
-+ urb->status = USB_ST_URB_PENDING;
-+ urb->start_frame = urb_priv->ed->last_iso + 1;
-+ if (urb_priv->state != URB_DEL) {
-+ for (i = 0; i < urb->number_of_packets; i++) {
-+ urb->iso_frame_desc[i].actual_length = 0;
-+ urb->iso_frame_desc[i].status = -EXDEV;
-+ }
-+ td_submit_urb (urb);
-+ }
-+
-+ } else { /* unlink URB, call complete */
-+ urb_rm_priv_locked (urb);
-+ ohci_complete_add(hc, urb);
-+ }
-+ break;
-+
-+ case PIPE_BULK:
-+ case PIPE_CONTROL: /* unlink URB, call complete */
-+ urb_rm_priv_locked (urb);
-+ ohci_complete_add(hc, urb);
-+ break;
-+ }
-+ return 0;
-+}
-+
-+/*-------------------------------------------------------------------------*/
-+
-+/* get a transfer request */
-+
-+static int sohci_submit_urb (struct urb * urb)
-+{
-+ ohci_t * ohci;
-+ ed_t * ed;
-+ urb_priv_t * urb_priv;
-+ unsigned int pipe = urb->pipe;
-+ int maxps = usb_maxpacket (urb->dev, pipe, usb_pipeout (pipe));
-+ int i, size = 0;
-+ unsigned long flags;
-+ int bustime = 0;
-+ int mem_flags = GFP_ATOMIC;
-+
-+ if (!urb->dev || !urb->dev->bus)
-+ return -ENODEV;
-+
-+ if (urb->hcpriv) /* urb already in use */
-+ return -EINVAL;
-+
-+// if(usb_endpoint_halted (urb->dev, usb_pipeendpoint (pipe), usb_pipeout (pipe)))
-+// return -EPIPE;
-+
-+ usb_inc_dev_use (urb->dev);
-+ ohci = (ohci_t *) urb->dev->bus->hcpriv;
-+
-+#ifdef DEBUG
-+ urb_print (urb, "SUB", usb_pipein (pipe));
-+#endif
-+
-+ /* handle a request to the virtual root hub */
-+ if (usb_pipedevice (pipe) == ohci->rh.devnum)
-+ return rh_submit_urb (urb);
-+
-+ spin_lock_irqsave(&ohci->ohci_lock, flags);
-+
-+ /* when controller's hung, permit only roothub cleanup attempts
-+ * such as powering down ports */
-+ if (ohci->disabled) {
-+ spin_unlock_irqrestore(&ohci->ohci_lock, flags);
-+ usb_dec_dev_use (urb->dev);
-+ return -ESHUTDOWN;
-+ }
-+
-+ /* every endpoint has a ed, locate and fill it */
-+ if (!(ed = ep_add_ed (urb->dev, pipe, urb->interval, 1, mem_flags))) {
-+ spin_unlock_irqrestore(&ohci->ohci_lock, flags);
-+ usb_dec_dev_use (urb->dev);
-+ return -ENOMEM;
-+ }
-+
-+ /* for the private part of the URB we need the number of TDs (size) */
-+ switch (usb_pipetype (pipe)) {
-+ case PIPE_BULK: /* one TD for every 4096 Byte */
-+ size = (urb->transfer_buffer_length - 1) / 4096 + 1;
-+
-+ /* If the transfer size is multiple of the pipe mtu,
-+ * we may need an extra TD to create a empty frame
-+ * Jean II */
-+ if ((urb->transfer_flags & USB_ZERO_PACKET) &&
-+ usb_pipeout (pipe) &&
-+ (urb->transfer_buffer_length != 0) &&
-+ ((urb->transfer_buffer_length % maxps) == 0))
-+ size++;
-+ break;
-+ case PIPE_ISOCHRONOUS: /* number of packets from URB */
-+ size = urb->number_of_packets;
-+ if (size <= 0) {
-+ spin_unlock_irqrestore(&ohci->ohci_lock, flags);
-+ usb_dec_dev_use (urb->dev);
-+ return -EINVAL;
-+ }
-+ for (i = 0; i < urb->number_of_packets; i++) {
-+ urb->iso_frame_desc[i].actual_length = 0;
-+ urb->iso_frame_desc[i].status = -EXDEV;
-+ }
-+ break;
-+ case PIPE_CONTROL: /* 1 TD for setup, 1 for ACK and 1 for every 4096 B */
-+ size = (urb->transfer_buffer_length == 0)? 2:
-+ (urb->transfer_buffer_length - 1) / 4096 + 3;
-+ break;
-+ case PIPE_INTERRUPT: /* one TD */
-+ size = 1;
-+ break;
-+ }
-+
-+ /* allocate the private part of the URB */
-+ urb_priv = kmalloc (sizeof (urb_priv_t) + size * sizeof (td_t *),
-+ GFP_ATOMIC);
-+ if (!urb_priv) {
-+ spin_unlock_irqrestore(&ohci->ohci_lock, flags);
-+ usb_dec_dev_use (urb->dev);
-+ return -ENOMEM;
-+ }
-+ memset (urb_priv, 0, sizeof (urb_priv_t) + size * sizeof (td_t *));
-+
-+ /* fill the private part of the URB */
-+ urb_priv->length = size;
-+ urb_priv->ed = ed;
-+
-+ /* allocate the TDs (updating hash chains) */
-+ for (i = 0; i < size; i++) {
-+ urb_priv->td[i] = td_alloc (ohci, SLAB_ATOMIC);
-+ if (!urb_priv->td[i]) {
-+ urb_priv->length = i;
-+ urb_free_priv (ohci, urb_priv);
-+ spin_unlock_irqrestore(&ohci->ohci_lock, flags);
-+ usb_dec_dev_use (urb->dev);
-+ return -ENOMEM;
-+ }
-+ }
-+
-+ if (ed->state == ED_NEW || (ed->state & ED_DEL)) {
-+ urb_free_priv (ohci, urb_priv);
-+ spin_unlock_irqrestore(&ohci->ohci_lock, flags);
-+ usb_dec_dev_use (urb->dev);
-+ return -EINVAL;
-+ }
-+
-+ /* allocate and claim bandwidth if needed; ISO
-+ * needs start frame index if it was't provided.
-+ */
-+ switch (usb_pipetype (pipe)) {
-+ case PIPE_ISOCHRONOUS:
-+ if (urb->transfer_flags & USB_ISO_ASAP) {
-+ urb->start_frame = ((ed->state == ED_OPER)
-+ ? (ed->last_iso + 1)
-+ : (le16_to_cpu (ohci->hcca->frame_no) + 10)) & 0xffff;
-+ }
-+ /* FALLTHROUGH */
-+ case PIPE_INTERRUPT:
-+ if (urb->bandwidth == 0) {
-+ bustime = usb_check_bandwidth (urb->dev, urb);
-+ }
-+ if (bustime < 0) {
-+ urb_free_priv (ohci, urb_priv);
-+ spin_unlock_irqrestore(&ohci->ohci_lock, flags);
-+ usb_dec_dev_use (urb->dev);
-+ return bustime;
-+ }
-+ usb_claim_bandwidth (urb->dev, urb, bustime, usb_pipeisoc (urb->pipe));
-+#ifdef DO_TIMEOUTS
-+ urb->timeout = 0;
-+#endif
-+ }
-+
-+ urb->actual_length = 0;
-+ urb->hcpriv = urb_priv;
-+ urb->status = USB_ST_URB_PENDING;
-+
-+ /* link the ed into a chain if is not already */
-+ if (ed->state != ED_OPER)
-+ ep_link (ohci, ed);
-+
-+ /* fill the TDs and link it to the ed */
-+ td_submit_urb (urb);
-+
-+#ifdef DO_TIMEOUTS
-+ /* maybe add to ordered list of timeouts */
-+ if (urb->timeout) {
-+ struct list_head *entry;
-+
-+ urb->timeout += jiffies;
-+
-+ list_for_each (entry, &ohci->timeout_list) {
-+ struct urb *next_urb;
-+
-+ next_urb = list_entry (entry, struct urb, urb_list);
-+ if (time_after_eq (urb->timeout, next_urb->timeout))
-+ break;
-+ }
-+ list_add (&urb->urb_list, entry);
-+
-+ /* drive timeouts by SF (messy, but works) */
-+ writel (OHCI_INTR_SF, &ohci->regs->intrenable);
-+ (void)readl (&ohci->regs->intrdisable); /* PCI posting flush */
-+ }
-+#endif
-+
-+ spin_unlock_irqrestore(&ohci->ohci_lock, flags);
-+
-+ return 0;
-+}
-+
-+/*-------------------------------------------------------------------------*/
-+
-+/* deactivate all TDs and remove the private part of the URB */
-+/* interrupt callers must use async unlink mode */
-+
-+static int sohci_unlink_urb (struct urb * urb)
-+{
-+ unsigned long flags;
-+ ohci_t * ohci;
-+
-+ if (!urb) /* just to be sure */
-+ return -EINVAL;
-+
-+ if (!urb->dev || !urb->dev->bus)
-+ return -ENODEV;
-+
-+ ohci = (ohci_t *) urb->dev->bus->hcpriv;
-+
-+#ifdef DEBUG
-+ urb_print (urb, "UNLINK", 1);
-+#endif
-+
-+ /* handle a request to the virtual root hub */
-+ if (usb_pipedevice (urb->pipe) == ohci->rh.devnum)
-+ return rh_unlink_urb (urb);
-+
-+ spin_lock_irqsave(&ohci->ohci_lock, flags);
-+ if (urb->hcpriv && (urb->status == USB_ST_URB_PENDING)) {
-+ if (!ohci->disabled) {
-+ urb_priv_t * urb_priv;
-+
-+ /* interrupt code may not sleep; it must use
-+ * async status return to unlink pending urbs.
-+ */
-+ if (!(urb->transfer_flags & USB_ASYNC_UNLINK)
-+ && in_interrupt ()) {
-+ spin_unlock_irqrestore(&ohci->ohci_lock, flags);
-+ err ("bug in call from %p; use async!",
-+ __builtin_return_address(0));
-+ return -EWOULDBLOCK;
-+ }
-+
-+ /* flag the urb and its TDs for deletion in some
-+ * upcoming SF interrupt delete list processing
-+ */
-+ urb_priv = urb->hcpriv;
-+
-+ if (!urb_priv || (urb_priv->state == URB_DEL)) {
-+ spin_unlock_irqrestore(&ohci->ohci_lock, flags);
-+ return 0;
-+ }
-+
-+ urb_priv->state = URB_DEL;
-+ ep_rm_ed (urb->dev, urb_priv->ed);
-+ urb_priv->ed->state |= ED_URB_DEL;
-+
-+ if (!(urb->transfer_flags & USB_ASYNC_UNLINK)) {
-+ DECLARE_WAIT_QUEUE_HEAD (unlink_wakeup);
-+ DECLARE_WAITQUEUE (wait, current);
-+ int timeout = OHCI_UNLINK_TIMEOUT;
-+
-+ add_wait_queue (&unlink_wakeup, &wait);
-+ urb_priv->wait = &unlink_wakeup;
-+ spin_unlock_irqrestore(&ohci->ohci_lock, flags);
-+
-+ /* wait until all TDs are deleted */
-+ set_current_state(TASK_UNINTERRUPTIBLE);
-+ while (timeout && (urb->status == USB_ST_URB_PENDING)) {
-+ timeout = schedule_timeout (timeout);
-+ set_current_state(TASK_UNINTERRUPTIBLE);
-+ }
-+ set_current_state(TASK_RUNNING);
-+ remove_wait_queue (&unlink_wakeup, &wait);
-+ if (urb->status == USB_ST_URB_PENDING) {
-+ err ("unlink URB timeout");
-+ return -ETIMEDOUT;
-+ }
-+
-+ usb_dec_dev_use (urb->dev);
-+ urb->dev = NULL;
-+ if (urb->complete)
-+ urb->complete (urb);
-+ } else {
-+ /* usb_dec_dev_use done in dl_del_list() */
-+ urb->status = -EINPROGRESS;
-+ spin_unlock_irqrestore(&ohci->ohci_lock, flags);
-+ return -EINPROGRESS;
-+ }
-+ } else {
-+ urb_rm_priv_locked (urb);
-+ spin_unlock_irqrestore(&ohci->ohci_lock, flags);
-+ usb_dec_dev_use (urb->dev);
-+ urb->dev = NULL;
-+ if (urb->transfer_flags & USB_ASYNC_UNLINK) {
-+ urb->status = -ECONNRESET;
-+ if (urb->complete)
-+ urb->complete (urb);
-+ } else
-+ urb->status = -ENOENT;
-+ }
-+ } else {
-+ spin_unlock_irqrestore(&ohci->ohci_lock, flags);
-+ }
-+ return 0;
-+}
-+
-+/*-------------------------------------------------------------------------*/
-+
-+/* allocate private data space for a usb device */
-+
-+static int sohci_alloc_dev (struct usb_device *usb_dev)
-+{
-+ struct ohci_device * dev;
-+
-+ dev = dev_alloc ((struct ohci *) usb_dev->bus->hcpriv, ALLOC_FLAGS);
-+ if (!dev)
-+ return -ENOMEM;
-+
-+ usb_dev->hcpriv = dev;
-+ return 0;
-+}
-+
-+/*-------------------------------------------------------------------------*/
-+
-+/* may be called from interrupt context */
-+/* frees private data space of usb device */
-+
-+static int sohci_free_dev (struct usb_device * usb_dev)
-+{
-+ unsigned long flags;
-+ int i, cnt = 0;
-+ ed_t * ed;
-+ struct ohci_device * dev = usb_to_ohci (usb_dev);
-+ ohci_t * ohci = usb_dev->bus->hcpriv;
-+
-+ if (!dev)
-+ return 0;
-+
-+ if (usb_dev->devnum >= 0) {
-+
-+ /* driver disconnects should have unlinked all urbs
-+ * (freeing all the TDs, unlinking EDs) but we need
-+ * to defend against bugs that prevent that.
-+ */
-+ spin_lock_irqsave(&ohci->ohci_lock, flags);
-+ for(i = 0; i < NUM_EDS; i++) {
-+ ed = &(dev->ed[i]);
-+ if (ed->state != ED_NEW) {
-+ if (ed->state == ED_OPER) {
-+ /* driver on that interface didn't unlink an urb */
-+ dbg ("driver usb-%s dev %d ed 0x%x unfreed URB",
-+ ohci->ohci_dev->slot_name, usb_dev->devnum, i);
-+ ep_unlink (ohci, ed);
-+ }
-+ ep_rm_ed (usb_dev, ed);
-+ ed->state = ED_DEL;
-+ cnt++;
-+ }
-+ }
-+ spin_unlock_irqrestore(&ohci->ohci_lock, flags);
-+
-+ /* if the controller is running, tds for those unlinked
-+ * urbs get freed by dl_del_list at the next SF interrupt
-+ */
-+ if (cnt > 0) {
-+
-+ if (ohci->disabled) {
-+ /* FIXME: Something like this should kick in,
-+ * though it's currently an exotic case ...
-+ * the controller won't ever be touching
-+ * these lists again!!
-+ dl_del_list (ohci,
-+ le16_to_cpu (ohci->hcca->frame_no) & 1);
-+ */
-+ warn ("TD leak, %d", cnt);
-+
-+ } else if (!in_interrupt ()) {
-+ DECLARE_WAIT_QUEUE_HEAD (freedev_wakeup);
-+ DECLARE_WAITQUEUE (wait, current);
-+ int timeout = OHCI_UNLINK_TIMEOUT;
-+
-+ /* SF interrupt handler calls dl_del_list */
-+ add_wait_queue (&freedev_wakeup, &wait);
-+ dev->wait = &freedev_wakeup;
-+ set_current_state(TASK_UNINTERRUPTIBLE);
-+ while (timeout && dev->ed_cnt)
-+ timeout = schedule_timeout (timeout);
-+ set_current_state(TASK_RUNNING);
-+ remove_wait_queue (&freedev_wakeup, &wait);
-+ if (dev->ed_cnt) {
-+ err ("free device %d timeout", usb_dev->devnum);
-+ return -ETIMEDOUT;
-+ }
-+ } else {
-+ /* likely some interface's driver has a refcount bug */
-+ err ("bus %s devnum %d deletion in interrupt",
-+ ohci->ohci_dev->slot_name, usb_dev->devnum);
-+ BUG ();
-+ }
-+ }
-+ }
-+
-+ /* free device, and associated EDs */
-+ dev_free (ohci, dev);
-+
-+ return 0;
-+}
-+
-+/*-------------------------------------------------------------------------*/
-+
-+/* tell us the current USB frame number */
-+
-+static int sohci_get_current_frame_number (struct usb_device *usb_dev)
-+{
-+ ohci_t * ohci = usb_dev->bus->hcpriv;
-+
-+ return le16_to_cpu (ohci->hcca->frame_no);
-+}
-+
-+/*-------------------------------------------------------------------------*/
-+
-+struct usb_operations sohci_device_operations = {
-+ sohci_alloc_dev,
-+ sohci_free_dev,
-+ sohci_get_current_frame_number,
-+ sohci_submit_urb,
-+ sohci_unlink_urb
-+};
-+
-+/*-------------------------------------------------------------------------*
-+ * ED handling functions
-+ *-------------------------------------------------------------------------*/
-+
-+/* search for the right branch to insert an interrupt ed into the int tree
-+ * do some load ballancing;
-+ * returns the branch and
-+ * sets the interval to interval = 2^integer (ld (interval)) */
-+
-+static int ep_int_ballance (ohci_t * ohci, int interval, int load)
-+{
-+ int i, branch = 0;
-+
-+ /* search for the least loaded interrupt endpoint branch of all 32 branches */
-+ for (i = 0; i < 32; i++)
-+ if (ohci->ohci_int_load [branch] > ohci->ohci_int_load [i]) branch = i;
-+
-+ branch = branch % interval;
-+ for (i = branch; i < 32; i += interval) ohci->ohci_int_load [i] += load;
-+
-+ return branch;
-+}
-+
-+/*-------------------------------------------------------------------------*/
-+
-+/* 2^int( ld (inter)) */
-+
-+static int ep_2_n_interval (int inter)
-+{
-+ int i;
-+ for (i = 0; ((inter >> i) > 1 ) && (i < 5); i++);
-+ return 1 << i;
-+}
-+
-+/*-------------------------------------------------------------------------*/
-+
-+/* the int tree is a binary tree
-+ * in order to process it sequentially the indexes of the branches have to be mapped
-+ * the mapping reverses the bits of a word of num_bits length */
-+
-+static int ep_rev (int num_bits, int word)
-+{
-+ int i, wout = 0;
-+
-+ for (i = 0; i < num_bits; i++) wout |= (((word >> i) & 1) << (num_bits - i - 1));
-+ return wout;
-+}
-+
-+/*-------------------------------------------------------------------------*/
-+
-+/* link an ed into one of the HC chains */
-+
-+static int ep_link (ohci_t * ohci, ed_t * edi)
-+{
-+ int int_branch;
-+ int i;
-+ int inter;
-+ int interval;
-+ int load;
-+ __u32 * ed_p;
-+ volatile ed_t * ed = edi;
-+
-+ ed->state = ED_OPER;
-+
-+ switch (ed->type) {
-+ case PIPE_CONTROL:
-+ ed->hwNextED = 0;
-+ if (ohci->ed_controltail == NULL) {
-+ writel (ed->dma, &ohci->regs->ed_controlhead);
-+ } else {
-+ ohci->ed_controltail->hwNextED = cpu_to_le32 (ed->dma);
-+ }
-+ ed->ed_prev = ohci->ed_controltail;
-+ if (!ohci->ed_controltail && !ohci->ed_rm_list[0] &&
-+ !ohci->ed_rm_list[1] && !ohci->sleeping) {
-+ ohci->hc_control |= OHCI_CTRL_CLE;
-+ writel (ohci->hc_control, &ohci->regs->control);
-+ }
-+ ohci->ed_controltail = edi;
-+ break;
-+
-+ case PIPE_BULK:
-+ ed->hwNextED = 0;
-+ if (ohci->ed_bulktail == NULL) {
-+ writel (ed->dma, &ohci->regs->ed_bulkhead);
-+ } else {
-+ ohci->ed_bulktail->hwNextED = cpu_to_le32 (ed->dma);
-+ }
-+ ed->ed_prev = ohci->ed_bulktail;
-+ if (!ohci->ed_bulktail && !ohci->ed_rm_list[0] &&
-+ !ohci->ed_rm_list[1] && !ohci->sleeping) {
-+ ohci->hc_control |= OHCI_CTRL_BLE;
-+ writel (ohci->hc_control, &ohci->regs->control);
-+ }
-+ ohci->ed_bulktail = edi;
-+ break;
-+
-+ case PIPE_INTERRUPT:
-+ load = ed->int_load;
-+ interval = ep_2_n_interval (ed->int_period);
-+ ed->int_interval = interval;
-+ int_branch = ep_int_ballance (ohci, interval, load);
-+ ed->int_branch = int_branch;
-+
-+ for (i = 0; i < ep_rev (6, interval); i += inter) {
-+ inter = 1;
-+ for (ed_p = &(ohci->hcca->int_table[ep_rev (5, i) + int_branch]);
-+ (*ed_p != 0) && ((dma_to_ed (ohci, le32_to_cpup (ed_p)))->int_interval >= interval);
-+ ed_p = &((dma_to_ed (ohci, le32_to_cpup (ed_p)))->hwNextED))
-+ inter = ep_rev (6, (dma_to_ed (ohci, le32_to_cpup (ed_p)))->int_interval);
-+ ed->hwNextED = *ed_p;
-+ *ed_p = cpu_to_le32 (ed->dma);
-+ }
-+#ifdef DEBUG
-+ ep_print_int_eds (ohci, "LINK_INT");
-+#endif
-+ break;
-+
-+ case PIPE_ISOCHRONOUS:
-+ ed->hwNextED = 0;
-+ ed->int_interval = 1;
-+ if (ohci->ed_isotail != NULL) {
-+ ohci->ed_isotail->hwNextED = cpu_to_le32 (ed->dma);
-+ ed->ed_prev = ohci->ed_isotail;
-+ } else {
-+ for ( i = 0; i < 32; i += inter) {
-+ inter = 1;
-+ for (ed_p = &(ohci->hcca->int_table[ep_rev (5, i)]);
-+ *ed_p != 0;
-+ ed_p = &((dma_to_ed (ohci, le32_to_cpup (ed_p)))->hwNextED))
-+ inter = ep_rev (6, (dma_to_ed (ohci, le32_to_cpup (ed_p)))->int_interval);
-+ *ed_p = cpu_to_le32 (ed->dma);
-+ }
-+ ed->ed_prev = NULL;
-+ }
-+ ohci->ed_isotail = edi;
-+#ifdef DEBUG
-+ ep_print_int_eds (ohci, "LINK_ISO");
-+#endif
-+ break;
-+ }
-+ return 0;
-+}
-+
-+/*-------------------------------------------------------------------------*/
-+
-+/* scan the periodic table to find and unlink this ED */
-+static void periodic_unlink (
-+ struct ohci *ohci,
-+ struct ed *ed,
-+ unsigned index,
-+ unsigned period
-+) {
-+ for (; index < NUM_INTS; index += period) {
-+ __u32 *ed_p = &ohci->hcca->int_table [index];
-+
-+ /* ED might have been unlinked through another path */
-+ while (*ed_p != 0) {
-+ if ((dma_to_ed (ohci, le32_to_cpup (ed_p))) == ed) {
-+ *ed_p = ed->hwNextED;
-+ break;
-+ }
-+ ed_p = & ((dma_to_ed (ohci,
-+ le32_to_cpup (ed_p)))->hwNextED);
-+ }
-+ }
-+}
-+
-+/* unlink an ed from one of the HC chains.
-+ * just the link to the ed is unlinked.
-+ * the link from the ed still points to another operational ed or 0
-+ * so the HC can eventually finish the processing of the unlinked ed */
-+
-+static int ep_unlink (ohci_t * ohci, ed_t * ed)
-+{
-+ int i;
-+
-+ ed->hwINFO |= cpu_to_le32 (OHCI_ED_SKIP);
-+
-+ switch (ed->type) {
-+ case PIPE_CONTROL:
-+ if (ed->ed_prev == NULL) {
-+ if (!ed->hwNextED) {
-+ ohci->hc_control &= ~OHCI_CTRL_CLE;
-+ writel (ohci->hc_control, &ohci->regs->control);
-+ }
-+ writel (le32_to_cpup (&ed->hwNextED), &ohci->regs->ed_controlhead);
-+ } else {
-+ ed->ed_prev->hwNextED = ed->hwNextED;
-+ }
-+ if (ohci->ed_controltail == ed) {
-+ ohci->ed_controltail = ed->ed_prev;
-+ } else {
-+ (dma_to_ed (ohci, le32_to_cpup (&ed->hwNextED)))->ed_prev = ed->ed_prev;
-+ }
-+ break;
-+
-+ case PIPE_BULK:
-+ if (ed->ed_prev == NULL) {
-+ if (!ed->hwNextED) {
-+ ohci->hc_control &= ~OHCI_CTRL_BLE;
-+ writel (ohci->hc_control, &ohci->regs->control);
-+ }
-+ writel (le32_to_cpup (&ed->hwNextED), &ohci->regs->ed_bulkhead);
-+ } else {
-+ ed->ed_prev->hwNextED = ed->hwNextED;
-+ }
-+ if (ohci->ed_bulktail == ed) {
-+ ohci->ed_bulktail = ed->ed_prev;
-+ } else {
-+ (dma_to_ed (ohci, le32_to_cpup (&ed->hwNextED)))->ed_prev = ed->ed_prev;
-+ }
-+ break;
-+
-+ case PIPE_INTERRUPT:
-+ periodic_unlink (ohci, ed, 0, 1);
-+ for (i = ed->int_branch; i < 32; i += ed->int_interval)
-+ ohci->ohci_int_load[i] -= ed->int_load;
-+#ifdef DEBUG
-+ ep_print_int_eds (ohci, "UNLINK_INT");
-+#endif
-+ break;
-+
-+ case PIPE_ISOCHRONOUS:
-+ if (ohci->ed_isotail == ed)
-+ ohci->ed_isotail = ed->ed_prev;
-+ if (ed->hwNextED != 0)
-+ (dma_to_ed (ohci, le32_to_cpup (&ed->hwNextED)))
-+ ->ed_prev = ed->ed_prev;
-+
-+ if (ed->ed_prev != NULL)
-+ ed->ed_prev->hwNextED = ed->hwNextED;
-+ else
-+ periodic_unlink (ohci, ed, 0, 1);
-+#ifdef DEBUG
-+ ep_print_int_eds (ohci, "UNLINK_ISO");
-+#endif
-+ break;
-+ }
-+ ed->state = ED_UNLINK;
-+ return 0;
-+}
-+
-+
-+/*-------------------------------------------------------------------------*/
-+
-+/* add/reinit an endpoint; this should be done once at the usb_set_configuration command,
-+ * but the USB stack is a little bit stateless so we do it at every transaction
-+ * if the state of the ed is ED_NEW then a dummy td is added and the state is changed to ED_UNLINK
-+ * in all other cases the state is left unchanged
-+ * the ed info fields are setted anyway even though most of them should not change */
-+
-+static ed_t * ep_add_ed (
-+ struct usb_device * usb_dev,
-+ unsigned int pipe,
-+ int interval,
-+ int load,
-+ int mem_flags
-+)
-+{
-+ ohci_t * ohci = usb_dev->bus->hcpriv;
-+ td_t * td;
-+ ed_t * ed_ret;
-+ volatile ed_t * ed;
-+
-+ ed = ed_ret = &(usb_to_ohci (usb_dev)->ed[(usb_pipeendpoint (pipe) << 1) |
-+ (usb_pipecontrol (pipe)? 0: usb_pipeout (pipe))]);
-+
-+ if ((ed->state & ED_DEL) || (ed->state & ED_URB_DEL)) {
-+ /* pending delete request */
-+ return NULL;
-+ }
-+
-+ if (ed->state == ED_NEW) {
-+ ed->hwINFO = cpu_to_le32 (OHCI_ED_SKIP); /* skip ed */
-+ /* dummy td; end of td list for ed */
-+ td = td_alloc (ohci, SLAB_ATOMIC);
-+ /* hash the ed for later reverse mapping */
-+ if (!td || !hash_add_ed (ohci, (ed_t *)ed)) {
-+ /* out of memory */
-+ if (td)
-+ td_free(ohci, td);
-+ return NULL;
-+ }
-+ ed->hwTailP = cpu_to_le32 (td->td_dma);
-+ ed->hwHeadP = ed->hwTailP;
-+ ed->state = ED_UNLINK;
-+ ed->type = usb_pipetype (pipe);
-+ usb_to_ohci (usb_dev)->ed_cnt++;
-+ }
-+
-+ ohci->dev[usb_pipedevice (pipe)] = usb_dev;
-+
-+ ed->hwINFO = cpu_to_le32 (usb_pipedevice (pipe)
-+ | usb_pipeendpoint (pipe) << 7
-+ | (usb_pipeisoc (pipe)? 0x8000: 0)
-+ | (usb_pipecontrol (pipe)? 0: (usb_pipeout (pipe)? 0x800: 0x1000))
-+ | usb_pipeslow (pipe) << 13
-+ | usb_maxpacket (usb_dev, pipe, usb_pipeout (pipe)) << 16);
-+
-+ if (ed->type == PIPE_INTERRUPT && ed->state == ED_UNLINK) {
-+ ed->int_period = interval;
-+ ed->int_load = load;
-+ }
-+
-+ return ed_ret;
-+}
-+
-+/*-------------------------------------------------------------------------*/
-+
-+/* request the removal of an endpoint
-+ * put the ep on the rm_list and request a stop of the bulk or ctrl list
-+ * real removal is done at the next start frame (SF) hardware interrupt */
-+
-+static void ep_rm_ed (struct usb_device * usb_dev, ed_t * ed)
-+{
-+ unsigned int frame;
-+ ohci_t * ohci = usb_dev->bus->hcpriv;
-+
-+ if ((ed->state & ED_DEL) || (ed->state & ED_URB_DEL))
-+ return;
-+
-+ ed->hwINFO |= cpu_to_le32 (OHCI_ED_SKIP);
-+
-+ if (!ohci->disabled) {
-+ switch (ed->type) {
-+ case PIPE_CONTROL: /* stop control list */
-+ ohci->hc_control &= ~OHCI_CTRL_CLE;
-+ writel (ohci->hc_control, &ohci->regs->control);
-+ break;
-+ case PIPE_BULK: /* stop bulk list */
-+ ohci->hc_control &= ~OHCI_CTRL_BLE;
-+ writel (ohci->hc_control, &ohci->regs->control);
-+ break;
-+ }
-+ }
-+
-+ frame = le16_to_cpu (ohci->hcca->frame_no) & 0x1;
-+ ed->ed_rm_list = ohci->ed_rm_list[frame];
-+ ohci->ed_rm_list[frame] = ed;
-+
-+ if (!ohci->disabled && !ohci->sleeping) {
-+ /* enable SOF interrupt */
-+ writel (OHCI_INTR_SF, &ohci->regs->intrstatus);
-+ writel (OHCI_INTR_SF, &ohci->regs->intrenable);
-+ (void)readl (&ohci->regs->intrdisable); /* PCI posting flush */
-+ }
-+}
-+
-+/*-------------------------------------------------------------------------*
-+ * TD handling functions
-+ *-------------------------------------------------------------------------*/
-+
-+/* enqueue next TD for this URB (OHCI spec 5.2.8.2) */
-+
-+static void
-+td_fill (ohci_t * ohci, unsigned int info,
-+ dma_addr_t data, int len,
-+ struct urb * urb, int index)
-+{
-+ volatile td_t * td, * td_pt;
-+ urb_priv_t * urb_priv = urb->hcpriv;
-+
-+ if (index >= urb_priv->length) {
-+ err("internal OHCI error: TD index > length");
-+ return;
-+ }
-+
-+ /* use this td as the next dummy */
-+ td_pt = urb_priv->td [index];
-+ td_pt->hwNextTD = 0;
-+
-+ /* fill the old dummy TD */
-+ td = urb_priv->td [index] = dma_to_td (ohci,
-+ le32_to_cpup (&urb_priv->ed->hwTailP) & ~0xf);
-+
-+ td->ed = urb_priv->ed;
-+ td->next_dl_td = NULL;
-+ td->index = index;
-+ td->urb = urb;
-+ td->data_dma = data;
-+ if (!len)
-+ data = 0;
-+
-+ td->hwINFO = cpu_to_le32 (info);
-+ if ((td->ed->type) == PIPE_ISOCHRONOUS) {
-+ td->hwCBP = cpu_to_le32 (data & 0xFFFFF000);
-+ td->ed->last_iso = info & 0xffff;
-+ } else {
-+ td->hwCBP = cpu_to_le32 (data);
-+ }
-+ if (data)
-+ td->hwBE = cpu_to_le32 (data + len - 1);
-+ else
-+ td->hwBE = 0;
-+ td->hwNextTD = cpu_to_le32 (td_pt->td_dma);
-+ td->hwPSW [0] = cpu_to_le16 ((data & 0x0FFF) | 0xE000);
-+
-+ /* append to queue */
-+ wmb();
-+ td->ed->hwTailP = td->hwNextTD;
-+}
-+
-+/*-------------------------------------------------------------------------*/
-+
-+/* prepare all TDs of a transfer */
-+
-+static void td_submit_urb (struct urb * urb)
-+{
-+ urb_priv_t * urb_priv = urb->hcpriv;
-+ ohci_t * ohci = (ohci_t *) urb->dev->bus->hcpriv;
-+ dma_addr_t data;
-+ int data_len = urb->transfer_buffer_length;
-+ int maxps = usb_maxpacket (urb->dev, urb->pipe, usb_pipeout (urb->pipe));
-+ int cnt = 0;
-+ __u32 info = 0;
-+ unsigned int toggle = 0;
-+
-+ /* OHCI handles the DATA-toggles itself, we just use the USB-toggle bits for reseting */
-+ if(usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe))) {
-+ toggle = TD_T_TOGGLE;
-+ } else {
-+ toggle = TD_T_DATA0;
-+ usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe), 1);
-+ }
-+
-+ urb_priv->td_cnt = 0;
-+
-+ if (data_len) {
-+ data = pci_map_single (ohci->ohci_dev,
-+ urb->transfer_buffer, data_len,
-+ usb_pipeout (urb->pipe)
-+ ? PCI_DMA_TODEVICE
-+ : PCI_DMA_FROMDEVICE
-+ );
-+ } else
-+ data = 0;
-+
-+ switch (usb_pipetype (urb->pipe)) {
-+ case PIPE_BULK:
-+ info = usb_pipeout (urb->pipe)?
-+ TD_CC | TD_DP_OUT : TD_CC | TD_DP_IN ;
-+ while(data_len > 4096) {
-+ td_fill (ohci, info | (cnt? TD_T_TOGGLE:toggle), data, 4096, urb, cnt);
-+ data += 4096; data_len -= 4096; cnt++;
-+ }
-+ info = usb_pipeout (urb->pipe)?
-+ TD_CC | TD_DP_OUT : TD_CC | TD_R | TD_DP_IN ;
-+ td_fill (ohci, info | (cnt? TD_T_TOGGLE:toggle), data, data_len, urb, cnt);
-+ cnt++;
-+
-+ /* If the transfer size is multiple of the pipe mtu,
-+ * we may need an extra TD to create a empty frame
-+ * Note : another way to check this condition is
-+ * to test if(urb_priv->length > cnt) - Jean II */
-+ if ((urb->transfer_flags & USB_ZERO_PACKET) &&
-+ usb_pipeout (urb->pipe) &&
-+ (urb->transfer_buffer_length != 0) &&
-+ ((urb->transfer_buffer_length % maxps) == 0)) {
-+ td_fill (ohci, info | (cnt? TD_T_TOGGLE:toggle), 0, 0, urb, cnt);
-+ cnt++;
-+ }
-+
-+ if (!ohci->sleeping) {
-+ wmb();
-+ writel (OHCI_BLF, &ohci->regs->cmdstatus); /* start bulk list */
-+ (void)readl (&ohci->regs->intrdisable); /* PCI posting flush */
-+ }
-+ break;
-+
-+ case PIPE_INTERRUPT:
-+ info = usb_pipeout (urb->pipe)?
-+ TD_CC | TD_DP_OUT | toggle: TD_CC | TD_R | TD_DP_IN | toggle;
-+ td_fill (ohci, info, data, data_len, urb, cnt++);
-+ break;
-+
-+ case PIPE_CONTROL:
-+ info = TD_CC | TD_DP_SETUP | TD_T_DATA0;
-+ td_fill (ohci, info,
-+ pci_map_single (ohci->ohci_dev,
-+ urb->setup_packet, 8,
-+ PCI_DMA_TODEVICE),
-+ 8, urb, cnt++);
-+ if (data_len > 0) {
-+ info = usb_pipeout (urb->pipe)?
-+ TD_CC | TD_R | TD_DP_OUT | TD_T_DATA1 : TD_CC | TD_R | TD_DP_IN | TD_T_DATA1;
-+ /* NOTE: mishandles transfers >8K, some >4K */
-+ td_fill (ohci, info, data, data_len, urb, cnt++);
-+ }
-+ info = usb_pipeout (urb->pipe)?
-+ TD_CC | TD_DP_IN | TD_T_DATA1: TD_CC | TD_DP_OUT | TD_T_DATA1;
-+ td_fill (ohci, info, data, 0, urb, cnt++);
-+ if (!ohci->sleeping) {
-+ wmb();
-+ writel (OHCI_CLF, &ohci->regs->cmdstatus); /* start Control list */
-+ (void)readl (&ohci->regs->intrdisable); /* PCI posting flush */
-+ }
-+ break;
-+
-+ case PIPE_ISOCHRONOUS:
-+ for (cnt = 0; cnt < urb->number_of_packets; cnt++) {
-+ td_fill (ohci, TD_CC|TD_ISO | ((urb->start_frame + cnt) & 0xffff),
-+ data + urb->iso_frame_desc[cnt].offset,
-+ urb->iso_frame_desc[cnt].length, urb, cnt);
-+ }
-+ break;
-+ }
-+ if (urb_priv->length != cnt)
-+ dbg("TD LENGTH %d != CNT %d", urb_priv->length, cnt);
-+}
-+
-+/*-------------------------------------------------------------------------*
-+ * Done List handling functions
-+ *-------------------------------------------------------------------------*/
-+
-+
-+/* calculate the transfer length and update the urb */
-+
-+static void dl_transfer_length(td_t * td)
-+{
-+ __u32 tdINFO, tdBE, tdCBP;
-+ __u16 tdPSW;
-+ struct urb * urb = td->urb;
-+ urb_priv_t * urb_priv = urb->hcpriv;
-+ int dlen = 0;
-+ int cc = 0;
-+
-+ tdINFO = le32_to_cpup (&td->hwINFO);
-+ tdBE = le32_to_cpup (&td->hwBE);
-+ tdCBP = le32_to_cpup (&td->hwCBP);
-+
-+
-+ if (tdINFO & TD_ISO) {
-+ tdPSW = le16_to_cpu (td->hwPSW[0]);
-+ cc = (tdPSW >> 12) & 0xF;
-+ if (cc < 0xE) {
-+ if (usb_pipeout(urb->pipe)) {
-+ dlen = urb->iso_frame_desc[td->index].length;
-+ } else {
-+ dlen = tdPSW & 0x3ff;
-+ }
-+ urb->actual_length += dlen;
-+ urb->iso_frame_desc[td->index].actual_length = dlen;
-+ if (!(urb->transfer_flags & USB_DISABLE_SPD) && (cc == TD_DATAUNDERRUN))
-+ cc = TD_CC_NOERROR;
-+
-+ urb->iso_frame_desc[td->index].status = cc_to_error[cc];
-+ }
-+ } else { /* BULK, INT, CONTROL DATA */
-+ if (!(usb_pipetype (urb->pipe) == PIPE_CONTROL &&
-+ ((td->index == 0) || (td->index == urb_priv->length - 1)))) {
-+ if (tdBE != 0) {
-+ if (td->hwCBP == 0)
-+ urb->actual_length += tdBE - td->data_dma + 1;
-+ else
-+ urb->actual_length += tdCBP - td->data_dma;
-+ }
-+ }
-+ }
-+}
-+
-+/* handle an urb that is being unlinked */
-+
-+static void dl_del_urb (ohci_t *ohci, struct urb * urb)
-+{
-+ wait_queue_head_t * wait_head = ((urb_priv_t *)(urb->hcpriv))->wait;
-+
-+ urb_rm_priv_locked (urb);
-+
-+ if (urb->transfer_flags & USB_ASYNC_UNLINK) {
-+ urb->status = -ECONNRESET;
-+ ohci_complete_add(ohci, urb);
-+ } else {
-+ urb->status = -ENOENT;
-+
-+ /* unblock sohci_unlink_urb */
-+ if (wait_head)
-+ wake_up (wait_head);
-+ }
-+}
-+
-+/*-------------------------------------------------------------------------*/
-+
-+/* replies to the request have to be on a FIFO basis so
-+ * we reverse the reversed done-list */
-+
-+static td_t * dl_reverse_done_list (ohci_t * ohci)
-+{
-+ __u32 td_list_hc;
-+ td_t * td_rev = NULL;
-+ td_t * td_list = NULL;
-+ urb_priv_t * urb_priv = NULL;
-+
-+ td_list_hc = le32_to_cpup (&ohci->hcca->done_head) & 0xfffffff0;
-+ ohci->hcca->done_head = 0;
-+
-+ while (td_list_hc) {
-+ td_list = dma_to_td (ohci, td_list_hc);
-+
-+ if (TD_CC_GET (le32_to_cpup (&td_list->hwINFO))) {
-+ urb_priv = (urb_priv_t *) td_list->urb->hcpriv;
-+ dbg(" USB-error/status: %x : %p",
-+ TD_CC_GET (le32_to_cpup (&td_list->hwINFO)), td_list);
-+ if (td_list->ed->hwHeadP & cpu_to_le32 (0x1)) {
-+ if (urb_priv && ((td_list->index + 1) < urb_priv->length)) {
-+ td_list->ed->hwHeadP =
-+ (urb_priv->td[urb_priv->length - 1]->hwNextTD & cpu_to_le32 (0xfffffff0)) |
-+ (td_list->ed->hwHeadP & cpu_to_le32 (0x2));
-+ urb_priv->td_cnt += urb_priv->length - td_list->index - 1;
-+ } else
-+ td_list->ed->hwHeadP &= cpu_to_le32 (0xfffffff2);
-+ }
-+ }
-+
-+ td_list->next_dl_td = td_rev;
-+ td_rev = td_list;
-+ td_list_hc = le32_to_cpup (&td_list->hwNextTD) & 0xfffffff0;
-+ }
-+ return td_list;
-+}
-+
-+/*-------------------------------------------------------------------------*/
-+
-+/* there are some pending requests to remove
-+ * - some of the eds (if ed->state & ED_DEL (set by sohci_free_dev)
-+ * - some URBs/TDs if urb_priv->state == URB_DEL */
-+
-+static void dl_del_list (ohci_t * ohci, unsigned int frame)
-+{
-+ ed_t * ed;
-+ __u32 edINFO;
-+ __u32 tdINFO;
-+ td_t * td = NULL, * td_next = NULL, * tdHeadP = NULL, * tdTailP;
-+ __u32 * td_p;
-+ int ctrl = 0, bulk = 0;
-+
-+ for (ed = ohci->ed_rm_list[frame]; ed != NULL; ed = ed->ed_rm_list) {
-+
-+ tdTailP = dma_to_td (ohci, le32_to_cpup (&ed->hwTailP) & 0xfffffff0);
-+ tdHeadP = dma_to_td (ohci, le32_to_cpup (&ed->hwHeadP) & 0xfffffff0);
-+ edINFO = le32_to_cpup (&ed->hwINFO);
-+ td_p = &ed->hwHeadP;
-+
-+ for (td = tdHeadP; td != tdTailP; td = td_next) {
-+ struct urb * urb = td->urb;
-+ urb_priv_t * urb_priv = td->urb->hcpriv;
-+
-+ td_next = dma_to_td (ohci, le32_to_cpup (&td->hwNextTD) & 0xfffffff0);
-+ if ((urb_priv->state == URB_DEL) || (ed->state & ED_DEL)) {
-+ tdINFO = le32_to_cpup (&td->hwINFO);
-+ if (TD_CC_GET (tdINFO) < 0xE)
-+ dl_transfer_length (td);
-+ *td_p = td->hwNextTD | (*td_p & cpu_to_le32 (0x3));
-+
-+ /* URB is done; clean up */
-+ if (++(urb_priv->td_cnt) == urb_priv->length)
-+ dl_del_urb (ohci, urb);
-+ } else {
-+ td_p = &td->hwNextTD;
-+ }
-+ }
-+
-+ if (ed->state & ED_DEL) { /* set by sohci_free_dev */
-+ struct ohci_device * dev = usb_to_ohci (ohci->dev[edINFO & 0x7F]);
-+ td_free (ohci, tdTailP); /* free dummy td */
-+ ed->hwINFO = cpu_to_le32 (OHCI_ED_SKIP);
-+ ed->state = ED_NEW;
-+ hash_free_ed(ohci, ed);
-+ /* if all eds are removed wake up sohci_free_dev */
-+ if (!--dev->ed_cnt) {
-+ wait_queue_head_t *wait_head = dev->wait;
-+
-+ dev->wait = 0;
-+ if (wait_head)
-+ wake_up (wait_head);
-+ }
-+ } else {
-+ ed->state &= ~ED_URB_DEL;
-+ tdHeadP = dma_to_td (ohci, le32_to_cpup (&ed->hwHeadP) & 0xfffffff0);
-+
-+ if (tdHeadP == tdTailP) {
-+ if (ed->state == ED_OPER)
-+ ep_unlink(ohci, ed);
-+ } else
-+ ed->hwINFO &= ~cpu_to_le32 (OHCI_ED_SKIP);
-+ }
-+
-+ switch (ed->type) {
-+ case PIPE_CONTROL:
-+ ctrl = 1;
-+ break;
-+ case PIPE_BULK:
-+ bulk = 1;
-+ break;
-+ }
-+ }
-+
-+ /* maybe reenable control and bulk lists */
-+ if (!ohci->disabled) {
-+ if (ctrl) /* reset control list */
-+ writel (0, &ohci->regs->ed_controlcurrent);
-+ if (bulk) /* reset bulk list */
-+ writel (0, &ohci->regs->ed_bulkcurrent);
-+ if (!ohci->ed_rm_list[!frame] && !ohci->sleeping) {
-+ if (ohci->ed_controltail)
-+ ohci->hc_control |= OHCI_CTRL_CLE;
-+ if (ohci->ed_bulktail)
-+ ohci->hc_control |= OHCI_CTRL_BLE;
-+ writel (ohci->hc_control, &ohci->regs->control);
-+ }
-+ }
-+
-+ ohci->ed_rm_list[frame] = NULL;
-+}
-+
-+
-+
-+/*-------------------------------------------------------------------------*/
-+
-+/* td done list */
-+
-+static void dl_done_list (ohci_t * ohci, td_t * td_list)
-+{
-+ td_t * td_list_next = NULL;
-+ ed_t * ed;
-+ int cc = 0;
-+ struct urb * urb;
-+ urb_priv_t * urb_priv;
-+ __u32 tdINFO, edHeadP, edTailP;
-+
-+ while (td_list) {
-+ td_list_next = td_list->next_dl_td;
-+
-+ urb = td_list->urb;
-+ urb_priv = urb->hcpriv;
-+ tdINFO = le32_to_cpup (&td_list->hwINFO);
-+
-+ ed = td_list->ed;
-+
-+ dl_transfer_length(td_list);
-+
-+ /* error code of transfer */
-+ cc = TD_CC_GET (tdINFO);
-+ if (cc == TD_CC_STALL)
-+ usb_endpoint_halt(urb->dev,
-+ usb_pipeendpoint(urb->pipe),
-+ usb_pipeout(urb->pipe));
-+
-+ if (!(urb->transfer_flags & USB_DISABLE_SPD)
-+ && (cc == TD_DATAUNDERRUN))
-+ cc = TD_CC_NOERROR;
-+
-+ if (++(urb_priv->td_cnt) == urb_priv->length) {
-+ if ((ed->state & (ED_OPER | ED_UNLINK))
-+ && (urb_priv->state != URB_DEL)) {
-+ urb->status = cc_to_error[cc];
-+ sohci_return_urb (ohci, urb);
-+ } else {
-+ dl_del_urb (ohci, urb);
-+ }
-+ }
-+
-+ if (ed->state != ED_NEW) {
-+ edHeadP = le32_to_cpup (&ed->hwHeadP) & 0xfffffff0;
-+ edTailP = le32_to_cpup (&ed->hwTailP);
-+
-+ /* unlink eds if they are not busy */
-+ if ((edHeadP == edTailP) && (ed->state == ED_OPER))
-+ ep_unlink (ohci, ed);
-+ }
-+
-+ td_list = td_list_next;
-+ }
-+}
-+
-+
-+
-+
-+/*-------------------------------------------------------------------------*
-+ * Virtual Root Hub
-+ *-------------------------------------------------------------------------*/
-+
-+/* Device descriptor */
-+static __u8 root_hub_dev_des[] =
-+{
-+ 0x12, /* __u8 bLength; */
-+ 0x01, /* __u8 bDescriptorType; Device */
-+ 0x10, /* __u16 bcdUSB; v1.1 */
-+ 0x01,
-+ 0x09, /* __u8 bDeviceClass; HUB_CLASSCODE */
-+ 0x00, /* __u8 bDeviceSubClass; */
-+ 0x00, /* __u8 bDeviceProtocol; */
-+ 0x08, /* __u8 bMaxPacketSize0; 8 Bytes */
-+ 0x00, /* __u16 idVendor; */
-+ 0x00,
-+ 0x00, /* __u16 idProduct; */
-+ 0x00,
-+ 0x00, /* __u16 bcdDevice; */
-+ 0x00,
-+ 0x00, /* __u8 iManufacturer; */
-+ 0x02, /* __u8 iProduct; */
-+ 0x01, /* __u8 iSerialNumber; */
-+ 0x01 /* __u8 bNumConfigurations; */
-+};
-+
-+
-+/* Configuration descriptor */
-+static __u8 root_hub_config_des[] =
-+{
-+ 0x09, /* __u8 bLength; */
-+ 0x02, /* __u8 bDescriptorType; Configuration */
-+ 0x19, /* __u16 wTotalLength; */
-+ 0x00,
-+ 0x01, /* __u8 bNumInterfaces; */
-+ 0x01, /* __u8 bConfigurationValue; */
-+ 0x00, /* __u8 iConfiguration; */
-+ 0x40, /* __u8 bmAttributes;
-+ Bit 7: Bus-powered, 6: Self-powered, 5 Remote-wakwup, 4..0: resvd */
-+ 0x00, /* __u8 MaxPower; */
-+
-+ /* interface */
-+ 0x09, /* __u8 if_bLength; */
-+ 0x04, /* __u8 if_bDescriptorType; Interface */
-+ 0x00, /* __u8 if_bInterfaceNumber; */
-+ 0x00, /* __u8 if_bAlternateSetting; */
-+ 0x01, /* __u8 if_bNumEndpoints; */
-+ 0x09, /* __u8 if_bInterfaceClass; HUB_CLASSCODE */
-+ 0x00, /* __u8 if_bInterfaceSubClass; */
-+ 0x00, /* __u8 if_bInterfaceProtocol; */
-+ 0x00, /* __u8 if_iInterface; */
-+
-+ /* endpoint */
-+ 0x07, /* __u8 ep_bLength; */
-+ 0x05, /* __u8 ep_bDescriptorType; Endpoint */
-+ 0x81, /* __u8 ep_bEndpointAddress; IN Endpoint 1 */
-+ 0x03, /* __u8 ep_bmAttributes; Interrupt */
-+ 0x02, /* __u16 ep_wMaxPacketSize; ((MAX_ROOT_PORTS + 1) / 8 */
-+ 0x00,
-+ 0xff /* __u8 ep_bInterval; 255 ms */
-+};
-+
-+/* Hub class-specific descriptor is constructed dynamically */
-+
-+
-+/*-------------------------------------------------------------------------*/
-+
-+/* prepare Interrupt pipe data; HUB INTERRUPT ENDPOINT */
-+
-+static int rh_send_irq (ohci_t * ohci, void * rh_data, int rh_len)
-+{
-+ int num_ports;
-+ int i;
-+ int ret;
-+ int len;
-+
-+ __u8 data[8];
-+
-+ num_ports = roothub_a (ohci) & RH_A_NDP;
-+ if (num_ports > MAX_ROOT_PORTS) {
-+ err ("bogus NDP=%d for OHCI usb-%s", num_ports,
-+ ohci->ohci_dev->slot_name);
-+ err ("rereads as NDP=%d",
-+ readl (&ohci->regs->roothub.a) & RH_A_NDP);
-+ /* retry later; "should not happen" */
-+ return 0;
-+ }
-+ *(__u8 *) data = (roothub_status (ohci) & (RH_HS_LPSC | RH_HS_OCIC))
-+ ? 1: 0;
-+ ret = *(__u8 *) data;
-+
-+ for ( i = 0; i < num_ports; i++) {
-+ *(__u8 *) (data + (i + 1) / 8) |=
-+ ((roothub_portstatus (ohci, i) &
-+ (RH_PS_CSC | RH_PS_PESC | RH_PS_PSSC | RH_PS_OCIC | RH_PS_PRSC))
-+ ? 1: 0) << ((i + 1) % 8);
-+ ret += *(__u8 *) (data + (i + 1) / 8);
-+ }
-+ len = i/8 + 1;
-+
-+ if (ret > 0) {
-+ memcpy(rh_data, data,
-+ min_t(unsigned int, len,
-+ min_t(unsigned int, rh_len, sizeof(data))));
-+ return len;
-+ }
-+ return 0;
-+}
-+
-+/*-------------------------------------------------------------------------*/
-+
-+/* Virtual Root Hub INTs are polled by this timer every "interval" ms */
-+
-+static void rh_int_timer_do (unsigned long ptr)
-+{
-+ int len;
-+
-+ struct urb * urb = (struct urb *) ptr;
-+ ohci_t * ohci = urb->dev->bus->hcpriv;
-+
-+ if (ohci->disabled)
-+ return;
-+
-+ /* ignore timers firing during PM suspend, etc */
-+ if ((ohci->hc_control & OHCI_CTRL_HCFS) != OHCI_USB_OPER)
-+ goto out;
-+
-+ if(ohci->rh.send) {
-+ len = rh_send_irq (ohci, urb->transfer_buffer, urb->transfer_buffer_length);
-+ if (len > 0) {
-+ urb->actual_length = len;
-+#ifdef DEBUG
-+ urb_print (urb, "RET-t(rh)", usb_pipeout (urb->pipe));
-+#endif
-+ if (urb->complete)
-+ urb->complete (urb);
-+ }
-+ }
-+ out:
-+ rh_init_int_timer (urb);
-+}
-+
-+/*-------------------------------------------------------------------------*/
-+
-+/* Root Hub INTs are polled by this timer */
-+
-+static int rh_init_int_timer (struct urb * urb)
-+{
-+ ohci_t * ohci = urb->dev->bus->hcpriv;
-+
-+ ohci->rh.interval = urb->interval;
-+ init_timer (&ohci->rh.rh_int_timer);
-+ ohci->rh.rh_int_timer.function = rh_int_timer_do;
-+ ohci->rh.rh_int_timer.data = (unsigned long) urb;
-+ ohci->rh.rh_int_timer.expires =
-+ jiffies + (HZ * (urb->interval < 30? 30: urb->interval)) / 1000;
-+ add_timer (&ohci->rh.rh_int_timer);
-+
-+ return 0;
-+}
-+
-+/*-------------------------------------------------------------------------*/
-+
-+#define OK(x) len = (x); break
-+#define WR_RH_STAT(x) writel((x), &ohci->regs->roothub.status)
-+#define WR_RH_PORTSTAT(x) writel((x), &ohci->regs->roothub.portstatus[wIndex-1])
-+#define RD_RH_STAT roothub_status(ohci)
-+#define RD_RH_PORTSTAT roothub_portstatus(ohci,wIndex-1)
-+
-+/* request to virtual root hub */
-+
-+static int rh_submit_urb (struct urb * urb)
-+{
-+ struct usb_device * usb_dev = urb->dev;
-+ ohci_t * ohci = usb_dev->bus->hcpriv;
-+ unsigned int pipe = urb->pipe;
-+ struct usb_ctrlrequest * cmd = (struct usb_ctrlrequest *) urb->setup_packet;
-+ void * data = urb->transfer_buffer;
-+ int leni = urb->transfer_buffer_length;
-+ int len = 0;
-+ int status = TD_CC_NOERROR;
-+ unsigned long flags;
-+
-+ __u32 datab[4];
-+ __u8 * data_buf = (__u8 *) datab;
-+
-+ __u16 bmRType_bReq;
-+ __u16 wValue;
-+ __u16 wIndex;
-+ __u16 wLength;
-+
-+ spin_lock_irqsave(&ohci->ohci_lock, flags);
-+
-+ if (usb_pipeint(pipe)) {
-+ ohci->rh.urb = urb;
-+ ohci->rh.send = 1;
-+ ohci->rh.interval = urb->interval;
-+ rh_init_int_timer(urb);
-+ urb->status = cc_to_error [TD_CC_NOERROR];
-+
-+ spin_unlock_irqrestore(&ohci->ohci_lock, flags);
-+ return 0;
-+ }
-+
-+ bmRType_bReq = cmd->bRequestType | (cmd->bRequest << 8);
-+ wValue = le16_to_cpu (cmd->wValue);
-+ wIndex = le16_to_cpu (cmd->wIndex);
-+ wLength = le16_to_cpu (cmd->wLength);
-+
-+ switch (bmRType_bReq) {
-+ /* Request Destination:
-+ without flags: Device,
-+ RH_INTERFACE: interface,
-+ RH_ENDPOINT: endpoint,
-+ RH_CLASS means HUB here,
-+ RH_OTHER | RH_CLASS almost ever means HUB_PORT here
-+ */
-+
-+ case RH_GET_STATUS:
-+ *(__u16 *) data_buf = cpu_to_le16 (1); OK (2);
-+ case RH_GET_STATUS | RH_INTERFACE:
-+ *(__u16 *) data_buf = cpu_to_le16 (0); OK (2);
-+ case RH_GET_STATUS | RH_ENDPOINT:
-+ *(__u16 *) data_buf = cpu_to_le16 (0); OK (2);
-+ case RH_GET_STATUS | RH_CLASS:
-+ *(__u32 *) data_buf = cpu_to_le32 (
-+ RD_RH_STAT & ~(RH_HS_CRWE | RH_HS_DRWE));
-+ OK (4);
-+ case RH_GET_STATUS | RH_OTHER | RH_CLASS:
-+ *(__u32 *) data_buf = cpu_to_le32 (RD_RH_PORTSTAT); OK (4);
-+
-+ case RH_CLEAR_FEATURE | RH_ENDPOINT:
-+ switch (wValue) {
-+ case (RH_ENDPOINT_STALL): OK (0);
-+ }
-+ break;
-+
-+ case RH_CLEAR_FEATURE | RH_CLASS:
-+ switch (wValue) {
-+ case RH_C_HUB_LOCAL_POWER:
-+ OK(0);
-+ case (RH_C_HUB_OVER_CURRENT):
-+ WR_RH_STAT(RH_HS_OCIC); OK (0);
-+ }
-+ break;
-+
-+ case RH_CLEAR_FEATURE | RH_OTHER | RH_CLASS:
-+ switch (wValue) {
-+ case (RH_PORT_ENABLE):
-+ WR_RH_PORTSTAT (RH_PS_CCS ); OK (0);
-+ case (RH_PORT_SUSPEND):
-+ WR_RH_PORTSTAT (RH_PS_POCI); OK (0);
-+ case (RH_PORT_POWER):
-+ WR_RH_PORTSTAT (RH_PS_LSDA); OK (0);
-+ case (RH_C_PORT_CONNECTION):
-+ WR_RH_PORTSTAT (RH_PS_CSC ); OK (0);
-+ case (RH_C_PORT_ENABLE):
-+ WR_RH_PORTSTAT (RH_PS_PESC); OK (0);
-+ case (RH_C_PORT_SUSPEND):
-+ WR_RH_PORTSTAT (RH_PS_PSSC); OK (0);
-+ case (RH_C_PORT_OVER_CURRENT):
-+ WR_RH_PORTSTAT (RH_PS_OCIC); OK (0);
-+ case (RH_C_PORT_RESET):
-+ WR_RH_PORTSTAT (RH_PS_PRSC); OK (0);
-+ }
-+ break;
-+
-+ case RH_SET_FEATURE | RH_OTHER | RH_CLASS:
-+ switch (wValue) {
-+ case (RH_PORT_SUSPEND):
-+ WR_RH_PORTSTAT (RH_PS_PSS ); OK (0);
-+ case (RH_PORT_RESET): /* BUG IN HUP CODE *********/
-+ if (RD_RH_PORTSTAT & RH_PS_CCS)
-+ WR_RH_PORTSTAT (RH_PS_PRS);
-+ OK (0);
-+ case (RH_PORT_POWER):
-+ WR_RH_PORTSTAT (RH_PS_PPS ); OK (0);
-+ case (RH_PORT_ENABLE): /* BUG IN HUP CODE *********/
-+ if (RD_RH_PORTSTAT & RH_PS_CCS)
-+ WR_RH_PORTSTAT (RH_PS_PES );
-+ OK (0);
-+ }
-+ break;
-+
-+ case RH_SET_ADDRESS: ohci->rh.devnum = wValue; OK(0);
-+
-+ case RH_GET_DESCRIPTOR:
-+ switch ((wValue & 0xff00) >> 8) {
-+ case (0x01): /* device descriptor */
-+ len = min_t(unsigned int,
-+ leni,
-+ min_t(unsigned int,
-+ sizeof (root_hub_dev_des),
-+ wLength));
-+ data_buf = root_hub_dev_des; OK(len);
-+ case (0x02): /* configuration descriptor */
-+ len = min_t(unsigned int,
-+ leni,
-+ min_t(unsigned int,
-+ sizeof (root_hub_config_des),
-+ wLength));
-+ data_buf = root_hub_config_des; OK(len);
-+ case (0x03): /* string descriptors */
-+ len = usb_root_hub_string (wValue & 0xff,
-+ (int)(long) ohci->regs, "OHCI",
-+ data, wLength);
-+ if (len > 0) {
-+ data_buf = data;
-+ OK(min_t(int, leni, len));
-+ }
-+ // else fallthrough
-+ default:
-+ status = TD_CC_STALL;
-+ }
-+ break;
-+
-+ case RH_GET_DESCRIPTOR | RH_CLASS:
-+ {
-+ __u32 temp = roothub_a (ohci);
-+
-+ data_buf [0] = 9; // min length;
-+ data_buf [1] = 0x29;
-+ data_buf [2] = temp & RH_A_NDP;
-+ data_buf [3] = 0;
-+ if (temp & RH_A_PSM) /* per-port power switching? */
-+ data_buf [3] |= 0x1;
-+ if (temp & RH_A_NOCP) /* no overcurrent reporting? */
-+ data_buf [3] |= 0x10;
-+ else if (temp & RH_A_OCPM) /* per-port overcurrent reporting? */
-+ data_buf [3] |= 0x8;
-+
-+ datab [1] = 0;
-+ data_buf [5] = (temp & RH_A_POTPGT) >> 24;
-+ temp = roothub_b (ohci);
-+ data_buf [7] = temp & RH_B_DR;
-+ if (data_buf [2] < 7) {
-+ data_buf [8] = 0xff;
-+ } else {
-+ data_buf [0] += 2;
-+ data_buf [8] = (temp & RH_B_DR) >> 8;
-+ data_buf [10] = data_buf [9] = 0xff;
-+ }
-+
-+ len = min_t(unsigned int, leni,
-+ min_t(unsigned int, data_buf [0], wLength));
-+ OK (len);
-+ }
-+
-+ case RH_GET_CONFIGURATION: *(__u8 *) data_buf = 0x01; OK (1);
-+
-+ case RH_SET_CONFIGURATION: WR_RH_STAT (0x10000); OK (0);
-+
-+ default:
-+ dbg ("unsupported root hub command");
-+ status = TD_CC_STALL;
-+ }
-+
-+#ifdef DEBUG
-+ // ohci_dump_roothub (ohci, 0);
-+#endif
-+
-+ len = min_t(int, len, leni);
-+ if (data != data_buf)
-+ memcpy (data, data_buf, len);
-+ urb->actual_length = len;
-+ urb->status = cc_to_error [status];
-+
-+#ifdef DEBUG
-+ urb_print (urb, "RET(rh)", usb_pipeout (urb->pipe));
-+#endif
-+
-+ urb->hcpriv = NULL;
-+ spin_unlock_irqrestore(&ohci->ohci_lock, flags);
-+ usb_dec_dev_use (usb_dev);
-+ urb->dev = NULL;
-+ if (urb->complete)
-+ urb->complete (urb);
-+ return 0;
-+}
-+
-+/*-------------------------------------------------------------------------*/
-+
-+static int rh_unlink_urb (struct urb * urb)
-+{
-+ ohci_t * ohci = urb->dev->bus->hcpriv;
-+ unsigned int flags;
-+
-+ spin_lock_irqsave(&ohci->ohci_lock, flags);
-+ if (ohci->rh.urb == urb) {
-+ ohci->rh.send = 0;
-+ del_timer (&ohci->rh.rh_int_timer);
-+ ohci->rh.urb = NULL;
-+
-+ urb->hcpriv = NULL;
-+ spin_unlock_irqrestore(&ohci->ohci_lock, flags);
-+ usb_dec_dev_use(urb->dev);
-+ urb->dev = NULL;
-+ if (urb->transfer_flags & USB_ASYNC_UNLINK) {
-+ urb->status = -ECONNRESET;
-+ if (urb->complete)
-+ urb->complete (urb);
-+ } else
-+ urb->status = -ENOENT;
-+ } else {
-+ spin_unlock_irqrestore(&ohci->ohci_lock, flags);
-+ }
-+ return 0;
-+}
-+
-+/*-------------------------------------------------------------------------*
-+ * HC functions
-+ *-------------------------------------------------------------------------*/
-+
-+/* reset the HC and BUS */
-+
-+static int hc_reset (ohci_t * ohci)
-+{
-+ int timeout = 30;
-+ int smm_timeout = 50; /* 0,5 sec */
-+
-+#ifndef __hppa__
-+ /* PA-RISC doesn't have SMM, but PDC might leave IR set */
-+ if (readl (&ohci->regs->control) & OHCI_CTRL_IR) { /* SMM owns the HC */
-+ writel (OHCI_OCR, &ohci->regs->cmdstatus); /* request ownership */
-+ dbg("USB HC TakeOver from SMM");
-+ while (readl (&ohci->regs->control) & OHCI_CTRL_IR) {
-+ wait_ms (10);
-+ if (--smm_timeout == 0) {
-+ err("USB HC TakeOver failed!");
-+ return -1;
-+ }
-+ }
-+ }
-+#endif
-+
-+ /* Disable HC interrupts */
-+ writel (OHCI_INTR_MIE, &ohci->regs->intrdisable);
-+
-+ dbg("USB HC reset_hc usb-%s: ctrl = 0x%x ;",
-+ ohci->ohci_dev->slot_name,
-+ readl (&ohci->regs->control));
-+
-+ /* Reset USB (needed by some controllers) */
-+ writel (0, &ohci->regs->control);
-+
-+ /* Force a state change from USBRESET to USBOPERATIONAL for ALi */
-+ (void) readl (&ohci->regs->control); /* PCI posting */
-+ writel (ohci->hc_control = OHCI_USB_OPER, &ohci->regs->control);
-+
-+ /* HC Reset requires max 10 ms delay */
-+ writel (OHCI_HCR, &ohci->regs->cmdstatus);
-+ while ((readl (&ohci->regs->cmdstatus) & OHCI_HCR) != 0) {
-+ if (--timeout == 0) {
-+ err("USB HC reset timed out!");
-+ return -1;
-+ }
-+ udelay (1);
-+ }
-+ return 0;
-+}
-+
-+/*-------------------------------------------------------------------------*/
-+
-+/* Start an OHCI controller, set the BUS operational
-+ * enable interrupts
-+ * connect the virtual root hub */
-+
-+static int hc_start (ohci_t * ohci)
-+{
-+ __u32 mask;
-+ unsigned int fminterval;
-+ struct usb_device * usb_dev;
-+ struct ohci_device * dev;
-+
-+ ohci->disabled = 1;
-+
-+ /* Tell the controller where the control and bulk lists are
-+ * The lists are empty now. */
-+
-+ writel (0, &ohci->regs->ed_controlhead);
-+ writel (0, &ohci->regs->ed_bulkhead);
-+
-+ writel (ohci->hcca_dma, &ohci->regs->hcca); /* a reset clears this */
-+
-+ fminterval = 0x2edf;
-+ writel ((fminterval * 9) / 10, &ohci->regs->periodicstart);
-+ fminterval |= ((((fminterval - 210) * 6) / 7) << 16);
-+ writel (fminterval, &ohci->regs->fminterval);
-+ writel (0x628, &ohci->regs->lsthresh);
-+
-+ /* start controller operations */
-+ ohci->hc_control = OHCI_CONTROL_INIT | OHCI_USB_OPER;
-+ ohci->disabled = 0;
-+ writel (ohci->hc_control, &ohci->regs->control);
-+
-+ /* Choose the interrupts we care about now, others later on demand */
-+ mask = OHCI_INTR_MIE | OHCI_INTR_UE | OHCI_INTR_WDH | OHCI_INTR_SO;
-+ writel (mask, &ohci->regs->intrenable);
-+ writel (mask, &ohci->regs->intrstatus);
-+
-+#ifdef OHCI_USE_NPS
-+ if(ohci->flags & OHCI_QUIRK_SUCKYIO)
-+ {
-+ /* NSC 87560 at least requires different setup .. */
-+ writel ((roothub_a (ohci) | RH_A_NOCP) &
-+ ~(RH_A_OCPM | RH_A_POTPGT | RH_A_PSM | RH_A_NPS),
-+ &ohci->regs->roothub.a);
-+ }
-+ else
-+ {
-+ /* required for AMD-756 and some Mac platforms */
-+ writel ((roothub_a (ohci) | RH_A_NPS) & ~RH_A_PSM,
-+ &ohci->regs->roothub.a);
-+ }
-+ writel (RH_HS_LPSC, &ohci->regs->roothub.status);
-+#endif /* OHCI_USE_NPS */
-+
-+ (void)readl (&ohci->regs->intrdisable); /* PCI posting flush */
-+
-+ // POTPGT delay is bits 24-31, in 2 ms units.
-+ mdelay ((roothub_a (ohci) >> 23) & 0x1fe);
-+
-+ /* connect the virtual root hub */
-+ ohci->rh.devnum = 0;
-+ usb_dev = usb_alloc_dev (NULL, ohci->bus);
-+ if (!usb_dev) {
-+ ohci->disabled = 1;
-+ return -ENOMEM;
-+ }
-+
-+ dev = usb_to_ohci (usb_dev);
-+ ohci->bus->root_hub = usb_dev;
-+ usb_connect (usb_dev);
-+ if (usb_new_device (usb_dev) != 0) {
-+ usb_free_dev (usb_dev);
-+ ohci->disabled = 1;
-+ return -ENODEV;
-+ }
-+
-+ return 0;
-+}
-+
-+/*-------------------------------------------------------------------------*/
-+
-+/* called only from interrupt handler */
-+
-+static void check_timeouts (struct ohci *ohci)
-+{
-+ spin_lock (&ohci->ohci_lock);
-+ while (!list_empty (&ohci->timeout_list)) {
-+ struct urb *urb;
-+
-+ urb = list_entry (ohci->timeout_list.next, struct urb, urb_list);
-+ if (time_after (jiffies, urb->timeout))
-+ break;
-+
-+ list_del_init (&urb->urb_list);
-+ if (urb->status != -EINPROGRESS)
-+ continue;
-+
-+ urb->transfer_flags |= USB_TIMEOUT_KILLED | USB_ASYNC_UNLINK;
-+ spin_unlock (&ohci->ohci_lock);
-+
-+ // outside the interrupt handler (in a timer...)
-+ // this reference would race interrupts
-+ sohci_unlink_urb (urb);
-+
-+ spin_lock (&ohci->ohci_lock);
-+ }
-+ spin_unlock (&ohci->ohci_lock);
-+}
-+
-+
-+/*-------------------------------------------------------------------------*/
-+
-+/* an interrupt happens */
-+
-+static void hc_interrupt (int irq, void * __ohci, struct pt_regs * r)
-+{
-+ ohci_t * ohci = __ohci;
-+ struct ohci_regs * regs = ohci->regs;
-+ int ints;
-+
-+ spin_lock (&ohci->ohci_lock);
-+
-+ /* avoid (slow) readl if only WDH happened */
-+ if ((ohci->hcca->done_head != 0)
-+ && !(le32_to_cpup (&ohci->hcca->done_head) & 0x01)) {
-+ ints = OHCI_INTR_WDH;
-+
-+ /* cardbus/... hardware gone before remove() */
-+ } else if ((ints = readl (&regs->intrstatus)) == ~(u32)0) {
-+ ohci->disabled++;
-+ spin_unlock (&ohci->ohci_lock);
-+ err ("%s device removed!", ohci->ohci_dev->slot_name);
-+ return;
-+
-+ /* interrupt for some other device? */
-+ } else if ((ints &= readl (&regs->intrenable)) == 0) {
-+ spin_unlock (&ohci->ohci_lock);
-+ return;
-+ }
-+
-+ // dbg("Interrupt: %x frame: %x", ints, le16_to_cpu (ohci->hcca->frame_no));
-+
-+ if (ints & OHCI_INTR_UE) {
-+ ohci->disabled++;
-+ err ("OHCI Unrecoverable Error, controller usb-%s disabled",
-+ ohci->ohci_dev->slot_name);
-+ // e.g. due to PCI Master/Target Abort
-+
-+#ifdef DEBUG
-+ ohci_dump (ohci, 1);
-+#else
-+ // FIXME: be optimistic, hope that bug won't repeat often.
-+ // Make some non-interrupt context restart the controller.
-+ // Count and limit the retries though; either hardware or
-+ // software errors can go forever...
-+#endif
-+ hc_reset (ohci);
-+ }
-+
-+ if (ints & OHCI_INTR_WDH) {
-+ writel (OHCI_INTR_WDH, &regs->intrdisable);
-+ (void)readl (&regs->intrdisable); /* PCI posting flush */
-+ dl_done_list (ohci, dl_reverse_done_list (ohci));
-+ writel (OHCI_INTR_WDH, &regs->intrenable);
-+ (void)readl (&regs->intrdisable); /* PCI posting flush */
-+ }
-+
-+ if (ints & OHCI_INTR_SO) {
-+ dbg("USB Schedule overrun");
-+ writel (OHCI_INTR_SO, &regs->intrenable);
-+ (void)readl (&regs->intrdisable); /* PCI posting flush */
-+ }
-+
-+ // FIXME: this assumes SOF (1/ms) interrupts don't get lost...
-+ if (ints & OHCI_INTR_SF) {
-+ unsigned int frame = le16_to_cpu (ohci->hcca->frame_no) & 1;
-+ writel (OHCI_INTR_SF, &regs->intrdisable);
-+ (void)readl (&regs->intrdisable); /* PCI posting flush */
-+ if (ohci->ed_rm_list[!frame] != NULL) {
-+ dl_del_list (ohci, !frame);
-+ }
-+ if (ohci->ed_rm_list[frame] != NULL) {
-+ writel (OHCI_INTR_SF, &regs->intrenable);
-+ (void)readl (&regs->intrdisable); /* PCI posting flush */
-+ }
-+ }
-+
-+ /*
-+ * Finally, we are done with trashing about our hardware lists
-+ * and other CPUs are allowed in. The festive flipping of the lock
-+ * ensues as we struggle with the check_timeouts disaster.
-+ */
-+ spin_unlock (&ohci->ohci_lock);
-+
-+ if (!list_empty (&ohci->timeout_list)) {
-+ check_timeouts (ohci);
-+// FIXME: enable SF as needed in a timer;
-+// don't make lots of 1ms interrupts
-+// On unloaded USB, think 4k ~= 4-5msec
-+ if (!list_empty (&ohci->timeout_list))
-+ writel (OHCI_INTR_SF, &regs->intrenable);
-+ }
-+
-+ writel (ints, &regs->intrstatus);
-+ writel (OHCI_INTR_MIE, &regs->intrenable);
-+ (void)readl (&regs->intrdisable); /* PCI posting flush */
-+
-+ ohci_complete(ohci);
-+}
-+
-+/*-------------------------------------------------------------------------*/
-+
-+/* allocate OHCI */
-+
-+static ohci_t * __devinit hc_alloc_ohci (struct pci_dev *dev, void * mem_base)
-+{
-+ ohci_t * ohci;
-+
-+ ohci = (ohci_t *) kmalloc (sizeof *ohci, GFP_KERNEL);
-+ if (!ohci)
-+ return NULL;
-+
-+ memset (ohci, 0, sizeof (ohci_t));
-+
-+ ohci->hcca = pci_alloc_consistent (dev, sizeof *ohci->hcca,
-+ &ohci->hcca_dma);
-+ if (!ohci->hcca) {
-+ kfree (ohci);
-+ return NULL;
-+ }
-+ memset (ohci->hcca, 0, sizeof (struct ohci_hcca));
-+
-+ ohci->disabled = 1;
-+ ohci->sleeping = 0;
-+ ohci->irq = -1;
-+ ohci->regs = mem_base;
-+
-+ ohci->ohci_dev = dev;
-+ pci_set_drvdata(dev, ohci);
-+
-+ INIT_LIST_HEAD (&ohci->timeout_list);
-+ spin_lock_init(&ohci->ohci_lock);
-+
-+ ohci->bus = usb_alloc_bus (&sohci_device_operations);
-+ if (!ohci->bus) {
-+ pci_set_drvdata (dev, NULL);
-+ pci_free_consistent (ohci->ohci_dev, sizeof *ohci->hcca,
-+ ohci->hcca, ohci->hcca_dma);
-+ kfree (ohci);
-+ return NULL;
-+ }
-+ ohci->bus->bus_name = dev->slot_name;
-+ ohci->bus->hcpriv = (void *) ohci;
-+
-+ return ohci;
-+}
-+
-+
-+/*-------------------------------------------------------------------------*/
-+
-+/* De-allocate all resources.. */
-+
-+static void hc_release_ohci (ohci_t * ohci)
-+{
-+ dbg ("USB HC release ohci usb-%s", ohci->ohci_dev->slot_name);
-+
-+ /* disconnect all devices */
-+ if (ohci->bus->root_hub)
-+ usb_disconnect (&ohci->bus->root_hub);
-+
-+ if (!ohci->disabled)
-+ hc_reset (ohci);
-+
-+ if (ohci->irq >= 0) {
-+ free_irq (ohci->irq, ohci);
-+ ohci->irq = -1;
-+ }
-+ pci_set_drvdata(ohci->ohci_dev, NULL);
-+ if (ohci->bus) {
-+ if (ohci->bus->busnum != -1)
-+ usb_deregister_bus (ohci->bus);
-+
-+ usb_free_bus (ohci->bus);
-+ }
-+
-+ ohci_mem_cleanup (ohci);
-+
-+ /* unmap the IO address space */
-+ iounmap (ohci->regs);
-+
-+ pci_free_consistent (ohci->ohci_dev, sizeof *ohci->hcca,
-+ ohci->hcca, ohci->hcca_dma);
-+ kfree (ohci);
-+}
-+
-+/*-------------------------------------------------------------------------*/
-+
-+/* Increment the module usage count, start the control thread and
-+ * return success. */
-+
-+static struct pci_driver ohci_pci_driver;
-+
-+static int __devinit
-+hc_found_ohci (struct pci_dev *dev, int irq,
-+ void *mem_base, const struct pci_device_id *id)
-+{
-+ ohci_t * ohci;
-+ char buf[8], *bufp = buf;
-+ int ret;
-+
-+#ifndef __sparc__
-+ sprintf(buf, "%d", irq);
-+#else
-+ bufp = __irq_itoa(irq);
-+#endif
-+ printk(KERN_INFO __FILE__ ": USB OHCI at membase 0x%lx, IRQ %s\n",
-+ (unsigned long) mem_base, bufp);
-+ printk(KERN_INFO __FILE__ ": usb-%s, %s\n", dev->slot_name, dev->name);
-+
-+ ohci = hc_alloc_ohci (dev, mem_base);
-+ if (!ohci) {
-+ return -ENOMEM;
-+ }
-+ if ((ret = ohci_mem_init (ohci)) < 0) {
-+ hc_release_ohci (ohci);
-+ return ret;
-+ }
-+ ohci->flags = id->driver_data;
-+
-+ /* Check for NSC87560. We have to look at the bridge (fn1) to identify
-+ the USB (fn2). This quirk might apply to more or even all NSC stuff
-+ I don't know.. */
-+
-+ if(dev->vendor == PCI_VENDOR_ID_NS)
-+ {
-+ struct pci_dev *fn1 = pci_find_slot(dev->bus->number, PCI_DEVFN(PCI_SLOT(dev->devfn), 1));
-+ if(fn1 && fn1->vendor == PCI_VENDOR_ID_NS && fn1->device == PCI_DEVICE_ID_NS_87560_LIO)
-+ ohci->flags |= OHCI_QUIRK_SUCKYIO;
-+
-+ }
-+
-+ if (ohci->flags & OHCI_QUIRK_SUCKYIO)
-+ printk (KERN_INFO __FILE__ ": Using NSC SuperIO setup\n");
-+ if (ohci->flags & OHCI_QUIRK_AMD756)
-+ printk (KERN_INFO __FILE__ ": AMD756 erratum 4 workaround\n");
-+
-+ if (hc_reset (ohci) < 0) {
-+ hc_release_ohci (ohci);
-+ return -ENODEV;
-+ }
-+
-+ /* FIXME this is a second HC reset; why?? */
-+ writel (ohci->hc_control = OHCI_USB_RESET, &ohci->regs->control);
-+ (void)readl (&ohci->regs->intrdisable); /* PCI posting flush */
-+ wait_ms (10);
-+
-+ usb_register_bus (ohci->bus);
-+
-+ if (request_irq (irq, hc_interrupt, SA_SHIRQ,
-+ ohci_pci_driver.name, ohci) != 0) {
-+ err ("request interrupt %s failed", bufp);
-+ hc_release_ohci (ohci);
-+ return -EBUSY;
-+ }
-+ ohci->irq = irq;
-+
-+ if (hc_start (ohci) < 0) {
-+ err ("can't start usb-%s", dev->slot_name);
-+ hc_release_ohci (ohci);
-+ return -EBUSY;
-+ }
-+
-+#ifdef DEBUG
-+ ohci_dump (ohci, 1);
-+#endif
-+ return 0;
-+}
-+
-+/*-------------------------------------------------------------------------*/
-+
-+#ifdef CONFIG_PM
-+
-+/* controller died; cleanup debris, then restart */
-+/* must not be called from interrupt context */
-+
-+static void hc_restart (ohci_t *ohci)
-+{
-+ int temp;
-+ int i;
-+
-+ if (ohci->pci_latency)
-+ pci_write_config_byte (ohci->ohci_dev, PCI_LATENCY_TIMER, ohci->pci_latency);
-+
-+ ohci->disabled = 1;
-+ ohci->sleeping = 0;
-+ if (ohci->bus->root_hub)
-+ usb_disconnect (&ohci->bus->root_hub);
-+
-+ /* empty the interrupt branches */
-+ for (i = 0; i < NUM_INTS; i++) ohci->ohci_int_load[i] = 0;
-+ for (i = 0; i < NUM_INTS; i++) ohci->hcca->int_table[i] = 0;
-+
-+ /* no EDs to remove */
-+ ohci->ed_rm_list [0] = NULL;
-+ ohci->ed_rm_list [1] = NULL;
-+
-+ /* empty control and bulk lists */
-+ ohci->ed_isotail = NULL;
-+ ohci->ed_controltail = NULL;
-+ ohci->ed_bulktail = NULL;
-+
-+ if ((temp = hc_reset (ohci)) < 0 || (temp = hc_start (ohci)) < 0) {
-+ err ("can't restart usb-%s, %d", ohci->ohci_dev->slot_name, temp);
-+ } else
-+ dbg ("restart usb-%s completed", ohci->ohci_dev->slot_name);
-+}
-+
-+#endif /* CONFIG_PM */
-+
-+/*-------------------------------------------------------------------------*/
-+
-+/* configured so that an OHCI device is always provided */
-+/* always called with process context; sleeping is OK */
-+
-+static int __devinit
-+ohci_pci_probe (struct pci_dev *dev, const struct pci_device_id *id)
-+{
-+ unsigned long mem_resource, mem_len;
-+ void *mem_base;
-+ int status;
-+
-+ if (pci_enable_device(dev) < 0)
-+ return -ENODEV;
-+
-+ if (!dev->irq) {
-+ err("found OHCI device with no IRQ assigned. check BIOS settings!");
-+ pci_disable_device (dev);
-+ return -ENODEV;
-+ }
-+
-+ /* we read its hardware registers as memory */
-+ mem_resource = pci_resource_start(dev, 0);
-+ mem_len = pci_resource_len(dev, 0);
-+ if (!request_mem_region (mem_resource, mem_len, ohci_pci_driver.name)) {
-+ dbg ("controller already in use");
-+ pci_disable_device (dev);
-+ return -EBUSY;
-+ }
-+
-+ mem_base = ioremap_nocache (mem_resource, mem_len);
-+ if (!mem_base) {
-+ err("Error mapping OHCI memory");
-+ release_mem_region (mem_resource, mem_len);
-+ pci_disable_device (dev);
-+ return -EFAULT;
-+ }
-+
-+ /* controller writes into our memory */
-+ pci_set_master (dev);
-+
-+ status = hc_found_ohci (dev, dev->irq, mem_base, id);
-+ if (status < 0) {
-+ iounmap (mem_base);
-+ release_mem_region (mem_resource, mem_len);
-+ pci_disable_device (dev);
-+ }
-+ return status;
-+}
-+
-+/*-------------------------------------------------------------------------*/
-+
-+/* may be called from interrupt context [interface spec] */
-+/* may be called without controller present */
-+/* may be called with controller, bus, and devices active */
-+
-+static void __devexit
-+ohci_pci_remove (struct pci_dev *dev)
-+{
-+ ohci_t *ohci = pci_get_drvdata(dev);
-+
-+ dbg ("remove %s controller usb-%s%s%s",
-+ hcfs2string (ohci->hc_control & OHCI_CTRL_HCFS),
-+ dev->slot_name,
-+ ohci->disabled ? " (disabled)" : "",
-+ in_interrupt () ? " in interrupt" : ""
-+ );
-+#ifdef DEBUG
-+ ohci_dump (ohci, 1);
-+#endif
-+
-+ /* don't wake up sleeping controllers, or block in interrupt context */
-+ if ((ohci->hc_control & OHCI_CTRL_HCFS) != OHCI_USB_OPER || in_interrupt ()) {
-+ dbg ("controller being disabled");
-+ ohci->disabled = 1;
-+ }
-+
-+ /* on return, USB will always be reset (if present) */
-+ if (ohci->disabled)
-+ writel (ohci->hc_control = OHCI_USB_RESET,
-+ &ohci->regs->control);
-+
-+ hc_release_ohci (ohci);
-+
-+ release_mem_region (pci_resource_start (dev, 0), pci_resource_len (dev, 0));
-+ pci_disable_device (dev);
-+}
-+
-+
-+#ifdef CONFIG_PM
-+
-+/*-------------------------------------------------------------------------*/
-+
-+static int
-+ohci_pci_suspend (struct pci_dev *dev, u32 state)
-+{
-+ ohci_t *ohci = pci_get_drvdata(dev);
-+ unsigned long flags;
-+ u16 cmd;
-+
-+ if ((ohci->hc_control & OHCI_CTRL_HCFS) != OHCI_USB_OPER) {
-+ dbg ("can't suspend usb-%s (state is %s)", dev->slot_name,
-+ hcfs2string (ohci->hc_control & OHCI_CTRL_HCFS));
-+ return -EIO;
-+ }
-+
-+ /* act as if usb suspend can always be used */
-+ info ("USB suspend: usb-%s", dev->slot_name);
-+ ohci->sleeping = 1;
-+
-+ /* First stop processing */
-+ spin_lock_irqsave (&ohci->ohci_lock, flags);
-+ ohci->hc_control &= ~(OHCI_CTRL_PLE|OHCI_CTRL_CLE|OHCI_CTRL_BLE|OHCI_CTRL_IE);
-+ writel (ohci->hc_control, &ohci->regs->control);
-+ writel (OHCI_INTR_SF, &ohci->regs->intrstatus);
-+ (void) readl (&ohci->regs->intrstatus);
-+ spin_unlock_irqrestore (&ohci->ohci_lock, flags);
-+
-+ /* Wait a frame or two */
-+ mdelay(1);
-+ if (!readl (&ohci->regs->intrstatus) & OHCI_INTR_SF)
-+ mdelay (1);
-+
-+#ifdef CONFIG_PMAC_PBOOK
-+ if (_machine == _MACH_Pmac)
-+ disable_irq (ohci->irq);
-+ /* else, 2.4 assumes shared irqs -- don't disable */
-+#endif
-+ /* Enable remote wakeup */
-+ writel (readl(&ohci->regs->intrenable) | OHCI_INTR_RD, &ohci->regs->intrenable);
-+
-+ /* Suspend chip and let things settle down a bit */
-+ ohci->hc_control = OHCI_USB_SUSPEND;
-+ writel (ohci->hc_control, &ohci->regs->control);
-+ (void) readl (&ohci->regs->control);
-+ mdelay (500); /* No schedule here ! */
-+ switch (readl (&ohci->regs->control) & OHCI_CTRL_HCFS) {
-+ case OHCI_USB_RESET:
-+ dbg("Bus in reset phase ???");
-+ break;
-+ case OHCI_USB_RESUME:
-+ dbg("Bus in resume phase ???");
-+ break;
-+ case OHCI_USB_OPER:
-+ dbg("Bus in operational phase ???");
-+ break;
-+ case OHCI_USB_SUSPEND:
-+ dbg("Bus suspended");
-+ break;
-+ }
-+ /* In some rare situations, Apple's OHCI have happily trashed
-+ * memory during sleep. We disable it's bus master bit during
-+ * suspend
-+ */
-+ pci_read_config_word (dev, PCI_COMMAND, &cmd);
-+ cmd &= ~PCI_COMMAND_MASTER;
-+ pci_write_config_word (dev, PCI_COMMAND, cmd);
-+#ifdef CONFIG_PMAC_PBOOK
-+ {
-+ struct device_node *of_node;
-+
-+ /* Disable USB PAD & cell clock */
-+ of_node = pci_device_to_OF_node (ohci->ohci_dev);
-+ if (of_node)
-+ pmac_call_feature(PMAC_FTR_USB_ENABLE, of_node, 0, 0);
-+ }
-+#endif
-+ return 0;
-+}
-+
-+/*-------------------------------------------------------------------------*/
-+
-+static int
-+ohci_pci_resume (struct pci_dev *dev)
-+{
-+ ohci_t *ohci = pci_get_drvdata(dev);
-+ int temp;
-+ unsigned long flags;
-+
-+ /* guard against multiple resumes */
-+ atomic_inc (&ohci->resume_count);
-+ if (atomic_read (&ohci->resume_count) != 1) {
-+ err ("concurrent PCI resumes for usb-%s", dev->slot_name);
-+ atomic_dec (&ohci->resume_count);
-+ return 0;
-+ }
-+
-+#ifdef CONFIG_PMAC_PBOOK
-+ {
-+ struct device_node *of_node;
-+
-+ /* Re-enable USB PAD & cell clock */
-+ of_node = pci_device_to_OF_node (ohci->ohci_dev);
-+ if (of_node)
-+ pmac_call_feature(PMAC_FTR_USB_ENABLE, of_node, 0, 1);
-+ }
-+#endif
-+
-+ /* did we suspend, or were we powered off? */
-+ ohci->hc_control = readl (&ohci->regs->control);
-+ temp = ohci->hc_control & OHCI_CTRL_HCFS;
-+
-+#ifdef DEBUG
-+ /* the registers may look crazy here */
-+ ohci_dump_status (ohci);
-+#endif
-+
-+ /* Re-enable bus mastering */
-+ pci_set_master(ohci->ohci_dev);
-+
-+ switch (temp) {
-+
-+ case OHCI_USB_RESET: // lost power
-+ info ("USB restart: usb-%s", dev->slot_name);
-+ hc_restart (ohci);
-+ break;
-+
-+ case OHCI_USB_SUSPEND: // host wakeup
-+ case OHCI_USB_RESUME: // remote wakeup
-+ info ("USB continue: usb-%s from %s wakeup", dev->slot_name,
-+ (temp == OHCI_USB_SUSPEND)
-+ ? "host" : "remote");
-+ ohci->hc_control = OHCI_USB_RESUME;
-+ writel (ohci->hc_control, &ohci->regs->control);
-+ (void) readl (&ohci->regs->control);
-+ mdelay (20); /* no schedule here ! */
-+ /* Some controllers (lucent) need a longer delay here */
-+ mdelay (15);
-+ temp = readl (&ohci->regs->control);
-+ temp = ohci->hc_control & OHCI_CTRL_HCFS;
-+ if (temp != OHCI_USB_RESUME) {
-+ err ("controller usb-%s won't resume", dev->slot_name);
-+ ohci->disabled = 1;
-+ return -EIO;
-+ }
-+
-+ /* Some chips likes being resumed first */
-+ writel (OHCI_USB_OPER, &ohci->regs->control);
-+ (void) readl (&ohci->regs->control);
-+ mdelay (3);
-+
-+ /* Then re-enable operations */
-+ spin_lock_irqsave (&ohci->ohci_lock, flags);
-+ ohci->disabled = 0;
-+ ohci->sleeping = 0;
-+ ohci->hc_control = OHCI_CONTROL_INIT | OHCI_USB_OPER;
-+ if (!ohci->ed_rm_list[0] && !ohci->ed_rm_list[1]) {
-+ if (ohci->ed_controltail)
-+ ohci->hc_control |= OHCI_CTRL_CLE;
-+ if (ohci->ed_bulktail)
-+ ohci->hc_control |= OHCI_CTRL_BLE;
-+ }
-+ writel (ohci->hc_control, &ohci->regs->control);
-+ writel (OHCI_INTR_SF, &ohci->regs->intrstatus);
-+ writel (OHCI_INTR_SF, &ohci->regs->intrenable);
-+ /* Check for a pending done list */
-+ writel (OHCI_INTR_WDH, &ohci->regs->intrdisable);
-+ (void) readl (&ohci->regs->intrdisable);
-+#ifdef CONFIG_PMAC_PBOOK
-+ if (_machine == _MACH_Pmac)
-+ enable_irq (ohci->irq);
-+#endif
-+ if (ohci->hcca->done_head)
-+ dl_done_list (ohci, dl_reverse_done_list (ohci));
-+ writel (OHCI_INTR_WDH, &ohci->regs->intrenable);
-+ writel (OHCI_BLF, &ohci->regs->cmdstatus); /* start bulk list */
-+ writel (OHCI_CLF, &ohci->regs->cmdstatus); /* start Control list */
-+ spin_unlock_irqrestore (&ohci->ohci_lock, flags);
-+ break;
-+
-+ default:
-+ warn ("odd PCI resume for usb-%s", dev->slot_name);
-+ }
-+
-+ /* controller is operational, extra resumes are harmless */
-+ atomic_dec (&ohci->resume_count);
-+
-+ return 0;
-+}
-+
-+#endif /* CONFIG_PM */
-+
-+
-+/*-------------------------------------------------------------------------*/
-+
-+static const struct pci_device_id __devinitdata ohci_pci_ids [] = { {
-+
-+ /*
-+ * AMD-756 [Viper] USB has a serious erratum when used with
-+ * lowspeed devices like mice.
-+ */
-+ vendor: 0x1022,
-+ device: 0x740c,
-+ subvendor: PCI_ANY_ID,
-+ subdevice: PCI_ANY_ID,
-+
-+ driver_data: OHCI_QUIRK_AMD756,
-+
-+} , {
-+
-+ /* handle any USB OHCI controller */
-+ class: ((PCI_CLASS_SERIAL_USB << 8) | 0x10),
-+ class_mask: ~0,
-+
-+ /* no matter who makes it */
-+ vendor: PCI_ANY_ID,
-+ device: PCI_ANY_ID,
-+ subvendor: PCI_ANY_ID,
-+ subdevice: PCI_ANY_ID,
-+
-+ }, { /* end: all zeroes */ }
-+};
-+
-+MODULE_DEVICE_TABLE (pci, ohci_pci_ids);
-+
-+static struct pci_driver ohci_pci_driver = {
-+ name: "usb-ohci",
-+ id_table: &ohci_pci_ids [0],
-+
-+ probe: ohci_pci_probe,
-+ remove: __devexit_p(ohci_pci_remove),
-+
-+#ifdef CONFIG_PM
-+ suspend: ohci_pci_suspend,
-+ resume: ohci_pci_resume,
-+#endif /* PM */
-+};
-+
-+
-+/*-------------------------------------------------------------------------*/
-+
-+static int __init ohci_hcd_init (void)
-+{
-+ return pci_module_init (&ohci_pci_driver);
-+}
-+
-+/*-------------------------------------------------------------------------*/
-+
-+static void __exit ohci_hcd_cleanup (void)
-+{
-+ pci_unregister_driver (&ohci_pci_driver);
-+}
-+
-+module_init (ohci_hcd_init);
-+module_exit (ohci_hcd_cleanup);
-+
-+
-+MODULE_AUTHOR( DRIVER_AUTHOR );
-+MODULE_DESCRIPTION( DRIVER_DESC );
-+MODULE_LICENSE("GPL");
diff --git a/recipes/linux/linux-mtx-1-2.4.27/09-au1000-eth-vlan.diff b/recipes/linux/linux-mtx-1-2.4.27/09-au1000-eth-vlan.diff
deleted file mode 100644
index 2f09c02d5a..0000000000
--- a/recipes/linux/linux-mtx-1-2.4.27/09-au1000-eth-vlan.diff
+++ /dev/null
@@ -1,10 +0,0 @@
---- linux/drivers/net/au1000_eth.c.orig 2004-11-18 13:44:52.163605416 +0100
-+++ linux/drivers/net/au1000_eth.c 2004-11-18 13:51:42.096286176 +0100
-@@ -1389,6 +1389,7 @@
- control |= MAC_FULL_DUPLEX;
- }
- aup->mac->control = control;
-+ aup->mac->vlan1_tag = 0x8100; /* activate vlan support */
- au_sync();
-
- spin_unlock_irqrestore(&aup->lock, flags);
diff --git a/recipes/linux/linux-mtx-1-2.4.27/10-iw-max-spy-32.diff b/recipes/linux/linux-mtx-1-2.4.27/10-iw-max-spy-32.diff
deleted file mode 100644
index e782d3d3dc..0000000000
--- a/recipes/linux/linux-mtx-1-2.4.27/10-iw-max-spy-32.diff
+++ /dev/null
@@ -1,11 +0,0 @@
---- linux-mips-2.4.24-pre2/include/linux/wireless.h 2004-11-17 18:05:09.000000000 +0100
-+++ linux/include/linux/wireless.h 2004-11-17 19:02:44.370081592 +0100
-@@ -334,7 +334,7 @@
- * a few of them in the struct iw_range. */
-
- /* Maximum of address that you may set with SPY */
--#define IW_MAX_SPY 8
-+#define IW_MAX_SPY 32
-
- /* Maximum of address that you may get in the
- list of access points in range */
diff --git a/recipes/linux/linux-mtx-1-2.4.27/11-mtd-proc-partition-rw.diff b/recipes/linux/linux-mtx-1-2.4.27/11-mtd-proc-partition-rw.diff
deleted file mode 100644
index 54ba5fff98..0000000000
--- a/recipes/linux/linux-mtx-1-2.4.27/11-mtd-proc-partition-rw.diff
+++ /dev/null
@@ -1,173 +0,0 @@
-diff -Nurb linux/drivers/mtd/mtdcore.c linux-mtd-rw/drivers/mtd/mtdcore.c
---- linux/drivers/mtd/mtdcore.c 2004-11-18 13:16:00.000000000 +0100
-+++ linux-mtd-rw/drivers/mtd/mtdcore.c 2004-11-18 15:27:13.130036616 +0100
-@@ -25,6 +25,10 @@
-
- #include <linux/mtd/mtd.h>
-
-+/* this symbol is exported by the procfs. */
-+extern struct proc_dir_entry *proc_sys_root;
-+
-+
- /* These are exported solely for the purpose of mtd_blkdevs.c. You
- should not use them for _anything_ else */
- DECLARE_MUTEX(mtd_table_mutex);
-@@ -336,8 +340,83 @@
-
- #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
- static struct proc_dir_entry *proc_mtd;
-+
-+static struct proc_dir_entry *proc_sys_mtd;
-+static struct proc_dir_entry *proc_sys_mtd_partition[MAX_MTD_DEVICES];
-+static struct proc_dir_entry *proc_sys_mtd_partition_rw[MAX_MTD_DEVICES];
- #endif
-
-+/*===================================0
-+ * mtdproc_read_partition_access
-+ */
-+static int mtdproc_read_partition_access ( char *page, char **start, off_t off,int count,
-+ int *eof, void *data
-+ )
-+{
-+ int partid = (unsigned int)data;
-+ int len = 0;
-+
-+ // NO RETURN FROM HERE UNTIL "up(&mtd_table_mutex)".
-+ down(&mtd_table_mutex);
-+
-+ if (partid < MAX_MTD_DEVICES)
-+ {
-+ struct mtd_info *this = mtd_table[partid];
-+ if (this)
-+ {
-+ page[len] = (this->flags & MTD_WRITEABLE) ? '1' : '0';
-+ len++;
-+ }
-+ }
-+
-+ up(&mtd_table_mutex);
-+
-+ if (off >= len)
-+ return 0;
-+ *start = page + off;
-+ return ((count < len-off) ? count : len-off);
-+}
-+
-+
-+static int mtdproc_write_partition_access (struct file *file, const char *buffer,
-+ unsigned long count, void *data)
-+{
-+ int partid = (unsigned int)data;
-+ int len = 0;
-+
-+ // NO RETURN FROM HERE UNTIL "up(&mtd_table_mutex)".
-+ down(&mtd_table_mutex);
-+
-+ if (partid < MAX_MTD_DEVICES)
-+ {
-+ struct mtd_info *this = mtd_table[partid];
-+ if (this && count > 0)
-+ {
-+ switch (*buffer)
-+ {
-+ case '0':
-+ this->flags &= ~(this->master_flags & MTD_WRITEABLE);
-+ break;
-+
-+ case '1':
-+ this->flags |= ~(this->master_flags & MTD_WRITEABLE);
-+ break;
-+
-+ default:
-+ break;
-+ }
-+ }
-+ }
-+
-+ up(&mtd_table_mutex);
-+
-+ return count;
-+}
-+
-+
-+
-+
-+
- static inline int mtd_proc_info (char *buf, int i)
- {
- struct mtd_info *this = mtd_table[i];
-@@ -349,6 +428,7 @@
- this->erasesize, this->name);
- }
-
-+
- static int mtd_read_proc ( char *page, char **start, off_t off,int count
- #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
- ,int *eof, void *data_unused
-@@ -404,12 +484,31 @@
- /*====================================================================*/
- /* Init code */
-
-+
- int __init init_mtd(void)
- {
- #ifdef CONFIG_PROC_FS
- #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
-+ int i;
-+
- if ((proc_mtd = create_proc_entry( "mtd", 0, 0 )))
- proc_mtd->read_proc = mtd_read_proc;
-+
-+ proc_sys_mtd = proc_mkdir("mtd", proc_sys_root);
-+ for (i=0; i<MAX_MTD_DEVICES; i++)
-+ {
-+ char partname[10];
-+ sprintf (partname, "%d", i);
-+
-+ proc_sys_mtd_partition[i] = proc_mkdir(partname, proc_sys_mtd);
-+ proc_sys_mtd_partition_rw[i] = create_proc_entry ("rw", S_IFREG | S_IRUGO, proc_sys_mtd_partition[i]);
-+ if (proc_sys_mtd_partition_rw[i])
-+ {
-+ proc_sys_mtd_partition_rw[i]->read_proc = mtdproc_read_partition_access;
-+ proc_sys_mtd_partition_rw[i]->write_proc = mtdproc_write_partition_access;
-+ proc_sys_mtd_partition_rw[i]->data = (void *)i;
-+ }
-+ }
- #else
- proc_register_dynamic(&proc_root,&mtd_proc_entry);
- #endif
-@@ -425,6 +524,8 @@
- return 0;
- }
-
-+
-+
- static void __exit cleanup_mtd(void)
- {
- #ifdef CONFIG_PM
-diff -Nurb linux/drivers/mtd/mtdpart.c linux-mtd-rw/drivers/mtd/mtdpart.c
---- linux/drivers/mtd/mtdpart.c 2004-11-18 13:16:00.000000000 +0100
-+++ linux-mtd-rw/drivers/mtd/mtdpart.c 2004-11-18 15:27:13.131036464 +0100
-@@ -341,6 +341,9 @@
- /* set up the MTD object for this partition */
- slave->mtd.type = master->type;
- slave->mtd.flags = master->flags & ~parts[i].mask_flags;
-+ slave->mtd.master_flags = master->flags;
-+ slave->mtd.mask_flags = parts[i].mask_flags;
-+
- slave->mtd.size = parts[i].size;
- slave->mtd.oobblock = master->oobblock;
- slave->mtd.oobsize = master->oobsize;
-diff -Nurb linux/include/linux/mtd/mtd.h linux-mtd-rw/include/linux/mtd/mtd.h
---- linux/include/linux/mtd/mtd.h 2004-11-18 13:16:31.000000000 +0100
-+++ linux-mtd-rw/include/linux/mtd/mtd.h 2004-11-18 15:27:13.000000000 +0100
-@@ -232,6 +232,9 @@
-
- struct module *owner;
- int usecount;
-+
-+ u_int32_t master_flags;
-+ u_int32_t mask_flags;
- };
-
-
diff --git a/recipes/linux/linux-mtx-1-2.4.27/12-openswan-2.2.0-nat-t.diff b/recipes/linux/linux-mtx-1-2.4.27/12-openswan-2.2.0-nat-t.diff
deleted file mode 100644
index 2a18d605bf..0000000000
--- a/recipes/linux/linux-mtx-1-2.4.27/12-openswan-2.2.0-nat-t.diff
+++ /dev/null
@@ -1,143 +0,0 @@
-diff -Nurb linux-08/include/net/sock.h linux/include/net/sock.h
---- linux-08/include/net/sock.h 2004-11-19 11:37:23.376715120 +0100
-+++ linux/include/net/sock.h 2004-11-19 11:39:29.874484536 +0100
-@@ -256,6 +256,13 @@
- __u32 end_seq;
- };
-
-+#if 1
-+#define UDP_OPT_IN_SOCK 1
-+struct udp_opt {
-+ __u32 esp_in_udp;
-+};
-+#endif
-+
- struct tcp_opt {
- int tcp_header_len; /* Bytes of tcp header to send */
-
-@@ -648,6 +655,9 @@
- #if defined(CONFIG_SPX) || defined (CONFIG_SPX_MODULE)
- struct spx_opt af_spx;
- #endif /* CONFIG_SPX */
-+#if 1
-+ struct udp_opt af_udp;
-+#endif
-
- } tp_pinfo;
-
-diff -Nurb linux-08/net/Config.in linux/net/Config.in
---- linux-08/net/Config.in 2004-11-19 11:37:23.770655232 +0100
-+++ linux/net/Config.in 2004-11-19 11:39:29.874484536 +0100
-@@ -102,4 +102,6 @@
- dep_tristate 'Packet Generator (USE WITH CAUTION)' CONFIG_NET_PKTGEN $CONFIG_PROC_FS
- endmenu
-
-+bool 'IPSEC NAT-Traversal' CONFIG_IPSEC_NAT_TRAVERSAL
-+
- endmenu
-diff -Nurb linux-08/net/ipv4/udp.c linux/net/ipv4/udp.c
---- linux-08/net/ipv4/udp.c 2004-11-19 11:37:23.897635928 +0100
-+++ linux/net/ipv4/udp.c 2004-11-19 11:39:29.875484384 +0100
-@@ -810,6 +810,9 @@
-
- static int udp_queue_rcv_skb(struct sock * sk, struct sk_buff *skb)
- {
-+#ifdef CONFIG_IPSEC_NAT_TRAVERSAL
-+ struct udp_opt *tp = &(sk->tp_pinfo.af_udp);
-+#endif
- /*
- * Charge it to the socket, dropping if the queue is full.
- */
-@@ -827,6 +830,40 @@
- }
- #endif
-
-+#ifdef CONFIG_IPSEC_NAT_TRAVERSAL
-+ if (tp->esp_in_udp) {
-+ /*
-+ * Set skb->sk and xmit packet to ipsec_rcv.
-+ *
-+ * If ret != 0, ipsec_rcv refused the packet (not ESPinUDP),
-+ * restore skb->sk and fall back to sock_queue_rcv_skb
-+ */
-+ struct inet_protocol *esp = NULL;
-+
-+#if defined(CONFIG_IPSEC) && !defined(CONFIG_IPSEC_MODULE)
-+ /* optomize only when we know it is statically linked */
-+ extern struct inet_protocol esp_protocol;
-+ esp = &esp_protocol;
-+#else
-+ for (esp = (struct inet_protocol *)inet_protos[IPPROTO_ESP & (MAX_INET_PROTOS - 1)];
-+ (esp) && (esp->protocol != IPPROTO_ESP);
-+ esp = esp->next);
-+#endif
-+
-+ if (esp && esp->handler) {
-+ struct sock *sav_sk = skb->sk;
-+ skb->sk = sk;
-+ if (esp->handler(skb) == 0) {
-+ skb->sk = sav_sk;
-+ /*not sure we might count ESPinUDP as UDP...*/
-+ UDP_INC_STATS_BH(UdpInDatagrams);
-+ return 0;
-+ }
-+ skb->sk = sav_sk;
-+ }
-+ }
-+#endif
-+
- if (sock_queue_rcv_skb(sk,skb)<0) {
- UDP_INC_STATS_BH(UdpInErrors);
- IP_INC_STATS_BH(IpInDiscards);
-@@ -1050,13 +1087,49 @@
- return len;
- }
-
-+static int udp_setsockopt(struct sock *sk, int level, int optname,
-+ char *optval, int optlen)
-+{
-+ struct udp_opt *tp = &(sk->tp_pinfo.af_udp);
-+ int val;
-+ int err = 0;
-+
-+ if (level != SOL_UDP)
-+ return ip_setsockopt(sk, level, optname, optval, optlen);
-+
-+ if(optlen<sizeof(int))
-+ return -EINVAL;
-+
-+ if (get_user(val, (int *)optval))
-+ return -EFAULT;
-+
-+ lock_sock(sk);
-+
-+ switch(optname) {
-+#ifdef CONFIG_IPSEC_NAT_TRAVERSAL
-+#ifndef UDP_ESPINUDP
-+#define UDP_ESPINUDP 100
-+#endif
-+ case UDP_ESPINUDP:
-+ tp->esp_in_udp = val;
-+ break;
-+#endif
-+ default:
-+ err = -ENOPROTOOPT;
-+ break;
-+ }
-+
-+ release_sock(sk);
-+ return err;
-+}
-+
- struct proto udp_prot = {
- name: "UDP",
- close: udp_close,
- connect: udp_connect,
- disconnect: udp_disconnect,
- ioctl: udp_ioctl,
-- setsockopt: ip_setsockopt,
-+ setsockopt: udp_setsockopt,
- getsockopt: ip_getsockopt,
- sendmsg: udp_sendmsg,
- recvmsg: udp_recvmsg,
-
diff --git a/recipes/linux/linux-mtx-1-2.4.27/13-openswan-2.2.0.patch b/recipes/linux/linux-mtx-1-2.4.27/13-openswan-2.2.0.patch
deleted file mode 100644
index 4995be5ef6..0000000000
--- a/recipes/linux/linux-mtx-1-2.4.27/13-openswan-2.2.0.patch
+++ /dev/null
@@ -1,61293 +0,0 @@
-make[1]: Entering directory `/data/mtx/oe/tmp/work/openswan-2.2.0-r0/openswan-2.2.0'
-packaging/utils/kernelpatch 2.4
---- linux/Documentation/Configure.help.orig Fri Dec 21 12:41:53 2001
-+++ linux/Documentation/Configure.help Mon Jul 29 16:35:32 2002
-@@ -24237,5 +24237,65 @@
-
--#
-+IP Security Protocol (IPSEC) (EXPERIMENTAL)
-+CONFIG_IPSEC
-+ This unit is experimental code.
-+ Pick 'y' for static linking, 'm' for module support or 'n' for none.
-+ This option adds support for network layer packet encryption and/or
-+ authentication with participating hosts. The standards start with:
-+ RFCs 2411, 2407 and 2401. Others are mentioned where they refer to
-+ specific features below. There are more pending which can be found
-+ at: ftp://ftp.ietf.org/internet-drafts/draft-ietf-ipsec-*.
-+ A description of each document can also be found at:
-+ http://ietf.org/ids.by.wg/ipsec.html.
-+ Their charter can be found at:
-+ http://www.ietf.org/html.charters/ipsec-charter.html
-+ Snapshots and releases of the current work can be found at:
-+ http://www.freeswan.org/
-+
-+IPSEC: IP-in-IP encapsulation
-+CONFIG_IPSEC_IPIP
-+ This option provides support for tunnel mode IPSEC. It is recommended
-+ to enable this.
-+
-+IPSEC: Authentication Header
-+CONFIG_IPSEC_AH
-+ This option provides support for the IPSEC Authentication Header
-+ (IP protocol 51) which provides packet layer sender and content
-+ authentication. It is recommended to enable this. RFC2402
-+
-+HMAC-MD5 algorithm
-+CONFIG_IPSEC_AUTH_HMAC_MD5
-+ Provides support for authentication using the HMAC MD5
-+ algorithm with 96 bits of hash used as the authenticator. RFC2403
-+
-+HMAC-SHA1 algorithm
-+CONFIG_IPSEC_AUTH_HMAC_SHA1
-+ Provides support for Authentication Header using the HMAC SHA1
-+ algorithm with 96 bits of hash used as the authenticator. RFC2404
-+
-+IPSEC: Encapsulating Security Payload
-+CONFIG_IPSEC_ESP
-+ This option provides support for the IPSEC Encapsulation Security
-+ Payload (IP protocol 50) which provides packet layer content
-+ hiding. It is recommended to enable this. RFC2406
-+
-+3DES algorithm
-+CONFIG_IPSEC_ENC_3DES
-+ Provides support for Encapsulation Security Payload protocol, using
-+ the triple DES encryption algorithm. RFC2451
-+
-+IPSEC Debugging Option
-+CONFIG_IPSEC_DEBUG
-+ Enables IPSEC kernel debugging. It is further controlled by the
-+ user space utility 'klipsdebug'.
-+
-+IPSEC Regression Testing option
-+CONFIG_IPSEC_REGRESS
-+ Enables IPSEC regression testing. Creates a number of switches in
-+ /proc/sys/net/ipsec which cause various failure modes in KLIPS.
-+ For more details see FreeSWAN source under
-+ testing/doc/regression_options.txt.
-+
-+#
- # A couple of things I keep forgetting:
- # capitalize: AppleTalk, Ethernet, DOS, DMA, FAT, FTP, Internet,
- # Intel, IRQ, ISDN, Linux, MSDOS, NetWare, NetWinder,
---- /dev/null Tue Mar 11 13:02:56 2003
-+++ linux/README.openswan-2 Mon Feb 9 13:51:03 2004
-@@ -0,0 +1,112 @@
-+*
-+* RCSID $Id: README.openswan-2,v 1.1 2003/12/10 01:07:49 mcr Exp $
-+*
-+
-+ ****************************************
-+ * IPSEC for Linux, Release 2.xx series *
-+ ****************************************
-+
-+
-+
-+1. Files
-+
-+The contents of linux/net/ipsec/ (see below) join the linux kernel source tree.
-+as provided for higher up.
-+
-+The programs/ directory contains the user-level utilities which you need
-+to run IPSEC. See the top-level top/INSTALL to compile and install them.
-+
-+The testing/ directory contains test scripts.
-+
-+The doc/ directory contains -- what else -- documentation.
-+
-+1.1. Kernel files
-+
-+The following are found in net/ipsec/:
-+
-+Makefile The Makefile
-+Config.in The configuration script for make menuconfig
-+defconfig Configuration defaults for first time.
-+
-+radij.c General-purpose radix-tree operations
-+
-+ipsec_ipcomp.c IPCOMP encapsulate/decapsulate code.
-+ipsec_ah.c Authentication Header (AH) encapsulate/decapsulate code.
-+ipsec_esp.c Encapsulated Security Payload (ESP) encap/decap code.
-+
-+pfkey_v2.c PF_KEYv2 socket interface code.
-+pfkey_v2_parser.c PF_KEYv2 message parsing and processing code.
-+
-+ipsec_init.c Initialization code, /proc interface.
-+ipsec_radij.c Interface with the radix tree code.
-+ipsec_netlink.c Interface with the netlink code.
-+ipsec_xform.c Routines and structures common to transforms.
-+ipsec_tunnel.c The outgoing packet processing code.
-+ipsec_rcv.c The incoming packet processing code.
-+ipsec_md5c.c Somewhat modified RSADSI MD5 C code.
-+ipsec_sha1.c Somewhat modified Steve Reid SHA-1 C code.
-+
-+sysctl_net_ipsec.c /proc/sys/net/ipsec/* variable definitions.
-+
-+version.c symbolic link to project version.
-+
-+radij.h Headers for radij.c
-+
-+ipcomp.h Headers used by IPCOMP code.
-+
-+ipsec_radij.h Interface with the radix tree code.
-+ipsec_netlink.h Headers used by the netlink interface.
-+ipsec_encap.h Headers defining encapsulation structures.
-+ipsec_xform.h Transform headers.
-+ipsec_tunnel.h Headers used by tunneling code.
-+ipsec_ipe4.h Headers for the IP-in-IP code.
-+ipsec_ah.h Headers common to AH transforms.
-+ipsec_md5h.h RSADSI MD5 headers.
-+ipsec_sha1.h SHA-1 headers.
-+ipsec_esp.h Headers common to ESP transfroms.
-+ipsec_rcv.h Headers for incoming packet processing code.
-+
-+1.2. User-level files.
-+
-+The following are found in utils/:
-+
-+eroute.c Create an "extended route" source code
-+spi.c Set up Security Associations source code
-+spigrp.c Link SPIs together source code.
-+tncfg.c Configure the tunneling features of the virtual interface
-+ source code
-+klipsdebug.c Set/reset klips debugging features source code.
-+version.c symbolic link to project version.
-+
-+eroute.8 Create an "extended route" manual page
-+spi.8 Set up Security Associations manual page
-+spigrp.8 Link SPIs together manual page
-+tncfg.8 Configure the tunneling features of the virtual interface
-+ manual page
-+klipsdebug.8 Set/reset klips debugging features manual page
-+
-+eroute.5 /proc/net/ipsec_eroute format manual page
-+spi.5 /proc/net/ipsec_spi format manual page
-+spigrp.5 /proc/net/ipsec_spigrp format manual page
-+tncfg.5 /proc/net/ipsec_tncfg format manual page
-+klipsdebug.5 /proc/net/ipsec_klipsdebug format manual page
-+version.5 /proc/net/ipsec_version format manual page
-+pf_key.5 /proc/net/pf_key format manual page
-+
-+Makefile Utilities makefile.
-+
-+*.8 Manpages for the respective utils.
-+
-+
-+1.3. Test files
-+
-+The test scripts are locate in testing/ and and documentation is found
-+at doc/src/umltesting.html. Automated testing via "make check" is available
-+provided that the User-Mode-Linux patches are available.
-+
-+*
-+* $Log: README.openswan-2,v $
-+* Revision 1.1 2003/12/10 01:07:49 mcr
-+* documentation for additions.
-+*
-+*
---- /dev/null Tue Mar 11 13:02:56 2003
-+++ linux/crypto/ciphers/aes/Makefile.objs Mon Feb 9 13:51:03 2004
-@@ -0,0 +1,13 @@
-+
-+ASM-$(ARCH_ASM):=1
-+ASM_X86:=$(ASM-i586)$(ASM-i686)
-+
-+ifneq ($(strip $(ASM_X86)),)
-+obj-$(CONFIG_IPSEC_ENC_AES) += aes-i586.o
-+else
-+obj-$(CONFIG_IPSEC_ENC_AES) += aes.o
-+endif
-+
-+obj-$(CONFIG_IPSEC_ENC_AES) += aes_cbc.o
-+obj-$(CONFIG_IPSEC_ENC_AES) += aes_xcbc_mac.o
-+
---- /dev/null Tue Mar 11 13:02:56 2003
-+++ linux/crypto/ciphers/aes/aes-i586.S Mon Feb 9 13:51:03 2004
-@@ -0,0 +1,892 @@
-+//
-+// Copyright (c) 2001, Dr Brian Gladman <brg@gladman.uk.net>, Worcester, UK.
-+// All rights reserved.
-+//
-+// TERMS
-+//
-+// Redistribution and use in source and binary forms, with or without
-+// modification, are permitted subject to the following conditions:
-+//
-+// 1. Redistributions of source code must retain the above copyright
-+// notice, this list of conditions and the following disclaimer.
-+//
-+// 2. Redistributions in binary form must reproduce the above copyright
-+// notice, this list of conditions and the following disclaimer in the
-+// documentation and/or other materials provided with the distribution.
-+//
-+// 3. The copyright holder's name must not be used to endorse or promote
-+// any products derived from this software without his specific prior
-+// written permission.
-+//
-+// This software is provided 'as is' with no express or implied warranties
-+// of correctness or fitness for purpose.
-+
-+// Modified by Jari Ruusu, December 24 2001
-+// - Converted syntax to GNU CPP/assembler syntax
-+// - C programming interface converted back to "old" API
-+// - Minor portability cleanups and speed optimizations
-+
-+// An AES (Rijndael) implementation for the Pentium. This version only
-+// implements the standard AES block length (128 bits, 16 bytes). This code
-+// does not preserve the eax, ecx or edx registers or the artihmetic status
-+// flags. However, the ebx, esi, edi, and ebp registers are preserved across
-+// calls.
-+
-+// void aes_set_key(aes_context *cx, const unsigned char key[], const int key_len, const int f)
-+// void aes_encrypt(const aes_context *cx, const unsigned char in_blk[], unsigned char out_blk[])
-+// void aes_decrypt(const aes_context *cx, const unsigned char in_blk[], unsigned char out_blk[])
-+
-+#if defined(USE_UNDERLINE)
-+# define aes_set_key _aes_set_key
-+# define aes_encrypt _aes_encrypt
-+# define aes_decrypt _aes_decrypt
-+#endif
-+#if !defined(ALIGN32BYTES)
-+# define ALIGN32BYTES 32
-+#endif
-+
-+ .file "aes-i586.S"
-+ .globl aes_set_key
-+ .globl aes_encrypt
-+ .globl aes_decrypt
-+
-+#define tlen 1024 // length of each of 4 'xor' arrays (256 32-bit words)
-+
-+// offsets to parameters with one register pushed onto stack
-+
-+#define ctx 8 // AES context structure
-+#define in_blk 12 // input byte array address parameter
-+#define out_blk 16 // output byte array address parameter
-+
-+// offsets in context structure
-+
-+#define nkey 0 // key length, size 4
-+#define nrnd 4 // number of rounds, size 4
-+#define ekey 8 // encryption key schedule base address, size 256
-+#define dkey 264 // decryption key schedule base address, size 256
-+
-+// This macro performs a forward encryption cycle. It is entered with
-+// the first previous round column values in %eax, %ebx, %esi and %edi and
-+// exits with the final values in the same registers.
-+
-+#define fwd_rnd(p1,p2) \
-+ mov %ebx,(%esp) ;\
-+ movzbl %al,%edx ;\
-+ mov %eax,%ecx ;\
-+ mov p2(%ebp),%eax ;\
-+ mov %edi,4(%esp) ;\
-+ mov p2+12(%ebp),%edi ;\
-+ xor p1(,%edx,4),%eax ;\
-+ movzbl %ch,%edx ;\
-+ shr $16,%ecx ;\
-+ mov p2+4(%ebp),%ebx ;\
-+ xor p1+tlen(,%edx,4),%edi ;\
-+ movzbl %cl,%edx ;\
-+ movzbl %ch,%ecx ;\
-+ xor p1+3*tlen(,%ecx,4),%ebx ;\
-+ mov %esi,%ecx ;\
-+ mov p1+2*tlen(,%edx,4),%esi ;\
-+ movzbl %cl,%edx ;\
-+ xor p1(,%edx,4),%esi ;\
-+ movzbl %ch,%edx ;\
-+ shr $16,%ecx ;\
-+ xor p1+tlen(,%edx,4),%ebx ;\
-+ movzbl %cl,%edx ;\
-+ movzbl %ch,%ecx ;\
-+ xor p1+2*tlen(,%edx,4),%eax ;\
-+ mov (%esp),%edx ;\
-+ xor p1+3*tlen(,%ecx,4),%edi ;\
-+ movzbl %dl,%ecx ;\
-+ xor p2+8(%ebp),%esi ;\
-+ xor p1(,%ecx,4),%ebx ;\
-+ movzbl %dh,%ecx ;\
-+ shr $16,%edx ;\
-+ xor p1+tlen(,%ecx,4),%eax ;\
-+ movzbl %dl,%ecx ;\
-+ movzbl %dh,%edx ;\
-+ xor p1+2*tlen(,%ecx,4),%edi ;\
-+ mov 4(%esp),%ecx ;\
-+ xor p1+3*tlen(,%edx,4),%esi ;\
-+ movzbl %cl,%edx ;\
-+ xor p1(,%edx,4),%edi ;\
-+ movzbl %ch,%edx ;\
-+ shr $16,%ecx ;\
-+ xor p1+tlen(,%edx,4),%esi ;\
-+ movzbl %cl,%edx ;\
-+ movzbl %ch,%ecx ;\
-+ xor p1+2*tlen(,%edx,4),%ebx ;\
-+ xor p1+3*tlen(,%ecx,4),%eax
-+
-+// This macro performs an inverse encryption cycle. It is entered with
-+// the first previous round column values in %eax, %ebx, %esi and %edi and
-+// exits with the final values in the same registers.
-+
-+#define inv_rnd(p1,p2) \
-+ movzbl %al,%edx ;\
-+ mov %ebx,(%esp) ;\
-+ mov %eax,%ecx ;\
-+ mov p2(%ebp),%eax ;\
-+ mov %edi,4(%esp) ;\
-+ mov p2+4(%ebp),%ebx ;\
-+ xor p1(,%edx,4),%eax ;\
-+ movzbl %ch,%edx ;\
-+ shr $16,%ecx ;\
-+ mov p2+12(%ebp),%edi ;\
-+ xor p1+tlen(,%edx,4),%ebx ;\
-+ movzbl %cl,%edx ;\
-+ movzbl %ch,%ecx ;\
-+ xor p1+3*tlen(,%ecx,4),%edi ;\
-+ mov %esi,%ecx ;\
-+ mov p1+2*tlen(,%edx,4),%esi ;\
-+ movzbl %cl,%edx ;\
-+ xor p1(,%edx,4),%esi ;\
-+ movzbl %ch,%edx ;\
-+ shr $16,%ecx ;\
-+ xor p1+tlen(,%edx,4),%edi ;\
-+ movzbl %cl,%edx ;\
-+ movzbl %ch,%ecx ;\
-+ xor p1+2*tlen(,%edx,4),%eax ;\
-+ mov (%esp),%edx ;\
-+ xor p1+3*tlen(,%ecx,4),%ebx ;\
-+ movzbl %dl,%ecx ;\
-+ xor p2+8(%ebp),%esi ;\
-+ xor p1(,%ecx,4),%ebx ;\
-+ movzbl %dh,%ecx ;\
-+ shr $16,%edx ;\
-+ xor p1+tlen(,%ecx,4),%esi ;\
-+ movzbl %dl,%ecx ;\
-+ movzbl %dh,%edx ;\
-+ xor p1+2*tlen(,%ecx,4),%edi ;\
-+ mov 4(%esp),%ecx ;\
-+ xor p1+3*tlen(,%edx,4),%eax ;\
-+ movzbl %cl,%edx ;\
-+ xor p1(,%edx,4),%edi ;\
-+ movzbl %ch,%edx ;\
-+ shr $16,%ecx ;\
-+ xor p1+tlen(,%edx,4),%eax ;\
-+ movzbl %cl,%edx ;\
-+ movzbl %ch,%ecx ;\
-+ xor p1+2*tlen(,%edx,4),%ebx ;\
-+ xor p1+3*tlen(,%ecx,4),%esi
-+
-+// AES (Rijndael) Encryption Subroutine
-+
-+ .text
-+ .align ALIGN32BYTES
-+aes_encrypt:
-+ push %ebp
-+ mov ctx(%esp),%ebp // pointer to context
-+ mov in_blk(%esp),%ecx
-+ push %ebx
-+ push %esi
-+ push %edi
-+ mov nrnd(%ebp),%edx // number of rounds
-+ lea ekey+16(%ebp),%ebp // key pointer
-+
-+// input four columns and xor in first round key
-+
-+ mov (%ecx),%eax
-+ mov 4(%ecx),%ebx
-+ mov 8(%ecx),%esi
-+ mov 12(%ecx),%edi
-+ xor -16(%ebp),%eax
-+ xor -12(%ebp),%ebx
-+ xor -8(%ebp),%esi
-+ xor -4(%ebp),%edi
-+
-+ sub $8,%esp // space for register saves on stack
-+
-+ sub $10,%edx
-+ je aes_15
-+ add $32,%ebp
-+ sub $2,%edx
-+ je aes_13
-+ add $32,%ebp
-+
-+ fwd_rnd(aes_ft_tab,-64) // 14 rounds for 256-bit key
-+ fwd_rnd(aes_ft_tab,-48)
-+aes_13: fwd_rnd(aes_ft_tab,-32) // 12 rounds for 192-bit key
-+ fwd_rnd(aes_ft_tab,-16)
-+aes_15: fwd_rnd(aes_ft_tab,0) // 10 rounds for 128-bit key
-+ fwd_rnd(aes_ft_tab,16)
-+ fwd_rnd(aes_ft_tab,32)
-+ fwd_rnd(aes_ft_tab,48)
-+ fwd_rnd(aes_ft_tab,64)
-+ fwd_rnd(aes_ft_tab,80)
-+ fwd_rnd(aes_ft_tab,96)
-+ fwd_rnd(aes_ft_tab,112)
-+ fwd_rnd(aes_ft_tab,128)
-+ fwd_rnd(aes_fl_tab,144) // last round uses a different table
-+
-+// move final values to the output array.
-+
-+ mov out_blk+20(%esp),%ebp
-+ add $8,%esp
-+ mov %eax,(%ebp)
-+ mov %ebx,4(%ebp)
-+ mov %esi,8(%ebp)
-+ mov %edi,12(%ebp)
-+ pop %edi
-+ pop %esi
-+ pop %ebx
-+ pop %ebp
-+ ret
-+
-+
-+// AES (Rijndael) Decryption Subroutine
-+
-+ .align ALIGN32BYTES
-+aes_decrypt:
-+ push %ebp
-+ mov ctx(%esp),%ebp // pointer to context
-+ mov in_blk(%esp),%ecx
-+ push %ebx
-+ push %esi
-+ push %edi
-+ mov nrnd(%ebp),%edx // number of rounds
-+ lea dkey+16(%ebp),%ebp // key pointer
-+
-+// input four columns and xor in first round key
-+
-+ mov (%ecx),%eax
-+ mov 4(%ecx),%ebx
-+ mov 8(%ecx),%esi
-+ mov 12(%ecx),%edi
-+ xor -16(%ebp),%eax
-+ xor -12(%ebp),%ebx
-+ xor -8(%ebp),%esi
-+ xor -4(%ebp),%edi
-+
-+ sub $8,%esp // space for register saves on stack
-+
-+ sub $10,%edx
-+ je aes_25
-+ add $32,%ebp
-+ sub $2,%edx
-+ je aes_23
-+ add $32,%ebp
-+
-+ inv_rnd(aes_it_tab,-64) // 14 rounds for 256-bit key
-+ inv_rnd(aes_it_tab,-48)
-+aes_23: inv_rnd(aes_it_tab,-32) // 12 rounds for 192-bit key
-+ inv_rnd(aes_it_tab,-16)
-+aes_25: inv_rnd(aes_it_tab,0) // 10 rounds for 128-bit key
-+ inv_rnd(aes_it_tab,16)
-+ inv_rnd(aes_it_tab,32)
-+ inv_rnd(aes_it_tab,48)
-+ inv_rnd(aes_it_tab,64)
-+ inv_rnd(aes_it_tab,80)
-+ inv_rnd(aes_it_tab,96)
-+ inv_rnd(aes_it_tab,112)
-+ inv_rnd(aes_it_tab,128)
-+ inv_rnd(aes_il_tab,144) // last round uses a different table
-+
-+// move final values to the output array.
-+
-+ mov out_blk+20(%esp),%ebp
-+ add $8,%esp
-+ mov %eax,(%ebp)
-+ mov %ebx,4(%ebp)
-+ mov %esi,8(%ebp)
-+ mov %edi,12(%ebp)
-+ pop %edi
-+ pop %esi
-+ pop %ebx
-+ pop %ebp
-+ ret
-+
-+// AES (Rijndael) Key Schedule Subroutine
-+
-+// input/output parameters
-+
-+#define aes_cx 12 // AES context
-+#define in_key 16 // key input array address
-+#define key_ln 20 // key length, bytes (16,24,32) or bits (128,192,256)
-+#define ed_flg 24 // 0=create both encr/decr keys, 1=create encr key only
-+
-+// offsets for locals
-+
-+#define cnt -4
-+#define kpf -8
-+#define slen 8
-+
-+// This macro performs a column mixing operation on an input 32-bit
-+// word to give a 32-bit result. It uses each of the 4 bytes in the
-+// the input column to index 4 different tables of 256 32-bit words
-+// that are xored together to form the output value.
-+
-+#define mix_col(p1) \
-+ movzbl %bl,%ecx ;\
-+ mov p1(,%ecx,4),%eax ;\
-+ movzbl %bh,%ecx ;\
-+ ror $16,%ebx ;\
-+ xor p1+tlen(,%ecx,4),%eax ;\
-+ movzbl %bl,%ecx ;\
-+ xor p1+2*tlen(,%ecx,4),%eax ;\
-+ movzbl %bh,%ecx ;\
-+ xor p1+3*tlen(,%ecx,4),%eax
-+
-+// Key Schedule Macros
-+
-+#define ksc4(p1) \
-+ rol $24,%ebx ;\
-+ mix_col(aes_fl_tab) ;\
-+ ror $8,%ebx ;\
-+ xor 4*p1+aes_rcon_tab,%eax ;\
-+ xor %eax,%esi ;\
-+ xor %esi,%ebp ;\
-+ mov %esi,16*p1(%edi) ;\
-+ mov %ebp,16*p1+4(%edi) ;\
-+ xor %ebp,%edx ;\
-+ xor %edx,%ebx ;\
-+ mov %edx,16*p1+8(%edi) ;\
-+ mov %ebx,16*p1+12(%edi)
-+
-+#define ksc6(p1) \
-+ rol $24,%ebx ;\
-+ mix_col(aes_fl_tab) ;\
-+ ror $8,%ebx ;\
-+ xor 4*p1+aes_rcon_tab,%eax ;\
-+ xor 24*p1-24(%edi),%eax ;\
-+ mov %eax,24*p1(%edi) ;\
-+ xor 24*p1-20(%edi),%eax ;\
-+ mov %eax,24*p1+4(%edi) ;\
-+ xor %eax,%esi ;\
-+ xor %esi,%ebp ;\
-+ mov %esi,24*p1+8(%edi) ;\
-+ mov %ebp,24*p1+12(%edi) ;\
-+ xor %ebp,%edx ;\
-+ xor %edx,%ebx ;\
-+ mov %edx,24*p1+16(%edi) ;\
-+ mov %ebx,24*p1+20(%edi)
-+
-+#define ksc8(p1) \
-+ rol $24,%ebx ;\
-+ mix_col(aes_fl_tab) ;\
-+ ror $8,%ebx ;\
-+ xor 4*p1+aes_rcon_tab,%eax ;\
-+ xor 32*p1-32(%edi),%eax ;\
-+ mov %eax,32*p1(%edi) ;\
-+ xor 32*p1-28(%edi),%eax ;\
-+ mov %eax,32*p1+4(%edi) ;\
-+ xor 32*p1-24(%edi),%eax ;\
-+ mov %eax,32*p1+8(%edi) ;\
-+ xor 32*p1-20(%edi),%eax ;\
-+ mov %eax,32*p1+12(%edi) ;\
-+ push %ebx ;\
-+ mov %eax,%ebx ;\
-+ mix_col(aes_fl_tab) ;\
-+ pop %ebx ;\
-+ xor %eax,%esi ;\
-+ xor %esi,%ebp ;\
-+ mov %esi,32*p1+16(%edi) ;\
-+ mov %ebp,32*p1+20(%edi) ;\
-+ xor %ebp,%edx ;\
-+ xor %edx,%ebx ;\
-+ mov %edx,32*p1+24(%edi) ;\
-+ mov %ebx,32*p1+28(%edi)
-+
-+ .align ALIGN32BYTES
-+aes_set_key:
-+ pushfl
-+ push %ebp
-+ mov %esp,%ebp
-+ sub $slen,%esp
-+ push %ebx
-+ push %esi
-+ push %edi
-+
-+ mov aes_cx(%ebp),%edx // edx -> AES context
-+
-+ mov key_ln(%ebp),%ecx // key length
-+ cmpl $128,%ecx
-+ jb aes_30
-+ shr $3,%ecx
-+aes_30: cmpl $32,%ecx
-+ je aes_32
-+ cmpl $24,%ecx
-+ je aes_32
-+ mov $16,%ecx
-+aes_32: shr $2,%ecx
-+ mov %ecx,nkey(%edx)
-+
-+ lea 6(%ecx),%eax // 10/12/14 for 4/6/8 32-bit key length
-+ mov %eax,nrnd(%edx)
-+
-+ mov in_key(%ebp),%esi // key input array
-+ lea ekey(%edx),%edi // key position in AES context
-+ cld
-+ push %ebp
-+ mov %ecx,%eax // save key length in eax
-+ rep ; movsl // words in the key schedule
-+ mov -4(%esi),%ebx // put some values in registers
-+ mov -8(%esi),%edx // to allow faster code
-+ mov -12(%esi),%ebp
-+ mov -16(%esi),%esi
-+
-+ cmpl $4,%eax // jump on key size
-+ je aes_36
-+ cmpl $6,%eax
-+ je aes_35
-+
-+ ksc8(0)
-+ ksc8(1)
-+ ksc8(2)
-+ ksc8(3)
-+ ksc8(4)
-+ ksc8(5)
-+ ksc8(6)
-+ jmp aes_37
-+aes_35: ksc6(0)
-+ ksc6(1)
-+ ksc6(2)
-+ ksc6(3)
-+ ksc6(4)
-+ ksc6(5)
-+ ksc6(6)
-+ ksc6(7)
-+ jmp aes_37
-+aes_36: ksc4(0)
-+ ksc4(1)
-+ ksc4(2)
-+ ksc4(3)
-+ ksc4(4)
-+ ksc4(5)
-+ ksc4(6)
-+ ksc4(7)
-+ ksc4(8)
-+ ksc4(9)
-+aes_37: pop %ebp
-+ mov aes_cx(%ebp),%edx // edx -> AES context
-+ cmpl $0,ed_flg(%ebp)
-+ jne aes_39
-+
-+// compile decryption key schedule from encryption schedule - reverse
-+// order and do mix_column operation on round keys except first and last
-+
-+ mov nrnd(%edx),%eax // kt = cx->d_key + nc * cx->Nrnd
-+ shl $2,%eax
-+ lea dkey(%edx,%eax,4),%edi
-+ lea ekey(%edx),%esi // kf = cx->e_key
-+
-+ movsl // copy first round key (unmodified)
-+ movsl
-+ movsl
-+ movsl
-+ sub $32,%edi
-+ movl $1,cnt(%ebp)
-+aes_38: // do mix column on each column of
-+ lodsl // each round key
-+ mov %eax,%ebx
-+ mix_col(aes_im_tab)
-+ stosl
-+ lodsl
-+ mov %eax,%ebx
-+ mix_col(aes_im_tab)
-+ stosl
-+ lodsl
-+ mov %eax,%ebx
-+ mix_col(aes_im_tab)
-+ stosl
-+ lodsl
-+ mov %eax,%ebx
-+ mix_col(aes_im_tab)
-+ stosl
-+ sub $32,%edi
-+
-+ incl cnt(%ebp)
-+ mov cnt(%ebp),%eax
-+ cmp nrnd(%edx),%eax
-+ jb aes_38
-+
-+ movsl // copy last round key (unmodified)
-+ movsl
-+ movsl
-+ movsl
-+aes_39: pop %edi
-+ pop %esi
-+ pop %ebx
-+ mov %ebp,%esp
-+ pop %ebp
-+ popfl
-+ ret
-+
-+
-+// finite field multiplies by {02}, {04} and {08}
-+
-+#define f2(x) ((x<<1)^(((x>>7)&1)*0x11b))
-+#define f4(x) ((x<<2)^(((x>>6)&1)*0x11b)^(((x>>6)&2)*0x11b))
-+#define f8(x) ((x<<3)^(((x>>5)&1)*0x11b)^(((x>>5)&2)*0x11b)^(((x>>5)&4)*0x11b))
-+
-+// finite field multiplies required in table generation
-+
-+#define f3(x) (f2(x) ^ x)
-+#define f9(x) (f8(x) ^ x)
-+#define fb(x) (f8(x) ^ f2(x) ^ x)
-+#define fd(x) (f8(x) ^ f4(x) ^ x)
-+#define fe(x) (f8(x) ^ f4(x) ^ f2(x))
-+
-+// These defines generate the forward table entries
-+
-+#define u0(x) ((f3(x) << 24) | (x << 16) | (x << 8) | f2(x))
-+#define u1(x) ((x << 24) | (x << 16) | (f2(x) << 8) | f3(x))
-+#define u2(x) ((x << 24) | (f2(x) << 16) | (f3(x) << 8) | x)
-+#define u3(x) ((f2(x) << 24) | (f3(x) << 16) | (x << 8) | x)
-+
-+// These defines generate the inverse table entries
-+
-+#define v0(x) ((fb(x) << 24) | (fd(x) << 16) | (f9(x) << 8) | fe(x))
-+#define v1(x) ((fd(x) << 24) | (f9(x) << 16) | (fe(x) << 8) | fb(x))
-+#define v2(x) ((f9(x) << 24) | (fe(x) << 16) | (fb(x) << 8) | fd(x))
-+#define v3(x) ((fe(x) << 24) | (fb(x) << 16) | (fd(x) << 8) | f9(x))
-+
-+// These defines generate entries for the last round tables
-+
-+#define w0(x) (x)
-+#define w1(x) (x << 8)
-+#define w2(x) (x << 16)
-+#define w3(x) (x << 24)
-+
-+// macro to generate inverse mix column tables (needed for the key schedule)
-+
-+#define im_data0(p1) \
-+ .long p1(0x00),p1(0x01),p1(0x02),p1(0x03),p1(0x04),p1(0x05),p1(0x06),p1(0x07) ;\
-+ .long p1(0x08),p1(0x09),p1(0x0a),p1(0x0b),p1(0x0c),p1(0x0d),p1(0x0e),p1(0x0f) ;\
-+ .long p1(0x10),p1(0x11),p1(0x12),p1(0x13),p1(0x14),p1(0x15),p1(0x16),p1(0x17) ;\
-+ .long p1(0x18),p1(0x19),p1(0x1a),p1(0x1b),p1(0x1c),p1(0x1d),p1(0x1e),p1(0x1f)
-+#define im_data1(p1) \
-+ .long p1(0x20),p1(0x21),p1(0x22),p1(0x23),p1(0x24),p1(0x25),p1(0x26),p1(0x27) ;\
-+ .long p1(0x28),p1(0x29),p1(0x2a),p1(0x2b),p1(0x2c),p1(0x2d),p1(0x2e),p1(0x2f) ;\
-+ .long p1(0x30),p1(0x31),p1(0x32),p1(0x33),p1(0x34),p1(0x35),p1(0x36),p1(0x37) ;\
-+ .long p1(0x38),p1(0x39),p1(0x3a),p1(0x3b),p1(0x3c),p1(0x3d),p1(0x3e),p1(0x3f)
-+#define im_data2(p1) \
-+ .long p1(0x40),p1(0x41),p1(0x42),p1(0x43),p1(0x44),p1(0x45),p1(0x46),p1(0x47) ;\
-+ .long p1(0x48),p1(0x49),p1(0x4a),p1(0x4b),p1(0x4c),p1(0x4d),p1(0x4e),p1(0x4f) ;\
-+ .long p1(0x50),p1(0x51),p1(0x52),p1(0x53),p1(0x54),p1(0x55),p1(0x56),p1(0x57) ;\
-+ .long p1(0x58),p1(0x59),p1(0x5a),p1(0x5b),p1(0x5c),p1(0x5d),p1(0x5e),p1(0x5f)
-+#define im_data3(p1) \
-+ .long p1(0x60),p1(0x61),p1(0x62),p1(0x63),p1(0x64),p1(0x65),p1(0x66),p1(0x67) ;\
-+ .long p1(0x68),p1(0x69),p1(0x6a),p1(0x6b),p1(0x6c),p1(0x6d),p1(0x6e),p1(0x6f) ;\
-+ .long p1(0x70),p1(0x71),p1(0x72),p1(0x73),p1(0x74),p1(0x75),p1(0x76),p1(0x77) ;\
-+ .long p1(0x78),p1(0x79),p1(0x7a),p1(0x7b),p1(0x7c),p1(0x7d),p1(0x7e),p1(0x7f)
-+#define im_data4(p1) \
-+ .long p1(0x80),p1(0x81),p1(0x82),p1(0x83),p1(0x84),p1(0x85),p1(0x86),p1(0x87) ;\
-+ .long p1(0x88),p1(0x89),p1(0x8a),p1(0x8b),p1(0x8c),p1(0x8d),p1(0x8e),p1(0x8f) ;\
-+ .long p1(0x90),p1(0x91),p1(0x92),p1(0x93),p1(0x94),p1(0x95),p1(0x96),p1(0x97) ;\
-+ .long p1(0x98),p1(0x99),p1(0x9a),p1(0x9b),p1(0x9c),p1(0x9d),p1(0x9e),p1(0x9f)
-+#define im_data5(p1) \
-+ .long p1(0xa0),p1(0xa1),p1(0xa2),p1(0xa3),p1(0xa4),p1(0xa5),p1(0xa6),p1(0xa7) ;\
-+ .long p1(0xa8),p1(0xa9),p1(0xaa),p1(0xab),p1(0xac),p1(0xad),p1(0xae),p1(0xaf) ;\
-+ .long p1(0xb0),p1(0xb1),p1(0xb2),p1(0xb3),p1(0xb4),p1(0xb5),p1(0xb6),p1(0xb7) ;\
-+ .long p1(0xb8),p1(0xb9),p1(0xba),p1(0xbb),p1(0xbc),p1(0xbd),p1(0xbe),p1(0xbf)
-+#define im_data6(p1) \
-+ .long p1(0xc0),p1(0xc1),p1(0xc2),p1(0xc3),p1(0xc4),p1(0xc5),p1(0xc6),p1(0xc7) ;\
-+ .long p1(0xc8),p1(0xc9),p1(0xca),p1(0xcb),p1(0xcc),p1(0xcd),p1(0xce),p1(0xcf) ;\
-+ .long p1(0xd0),p1(0xd1),p1(0xd2),p1(0xd3),p1(0xd4),p1(0xd5),p1(0xd6),p1(0xd7) ;\
-+ .long p1(0xd8),p1(0xd9),p1(0xda),p1(0xdb),p1(0xdc),p1(0xdd),p1(0xde),p1(0xdf)
-+#define im_data7(p1) \
-+ .long p1(0xe0),p1(0xe1),p1(0xe2),p1(0xe3),p1(0xe4),p1(0xe5),p1(0xe6),p1(0xe7) ;\
-+ .long p1(0xe8),p1(0xe9),p1(0xea),p1(0xeb),p1(0xec),p1(0xed),p1(0xee),p1(0xef) ;\
-+ .long p1(0xf0),p1(0xf1),p1(0xf2),p1(0xf3),p1(0xf4),p1(0xf5),p1(0xf6),p1(0xf7) ;\
-+ .long p1(0xf8),p1(0xf9),p1(0xfa),p1(0xfb),p1(0xfc),p1(0xfd),p1(0xfe),p1(0xff)
-+
-+// S-box data - 256 entries
-+
-+#define sb_data0(p1) \
-+ .long p1(0x63),p1(0x7c),p1(0x77),p1(0x7b),p1(0xf2),p1(0x6b),p1(0x6f),p1(0xc5) ;\
-+ .long p1(0x30),p1(0x01),p1(0x67),p1(0x2b),p1(0xfe),p1(0xd7),p1(0xab),p1(0x76) ;\
-+ .long p1(0xca),p1(0x82),p1(0xc9),p1(0x7d),p1(0xfa),p1(0x59),p1(0x47),p1(0xf0) ;\
-+ .long p1(0xad),p1(0xd4),p1(0xa2),p1(0xaf),p1(0x9c),p1(0xa4),p1(0x72),p1(0xc0)
-+#define sb_data1(p1) \
-+ .long p1(0xb7),p1(0xfd),p1(0x93),p1(0x26),p1(0x36),p1(0x3f),p1(0xf7),p1(0xcc) ;\
-+ .long p1(0x34),p1(0xa5),p1(0xe5),p1(0xf1),p1(0x71),p1(0xd8),p1(0x31),p1(0x15) ;\
-+ .long p1(0x04),p1(0xc7),p1(0x23),p1(0xc3),p1(0x18),p1(0x96),p1(0x05),p1(0x9a) ;\
-+ .long p1(0x07),p1(0x12),p1(0x80),p1(0xe2),p1(0xeb),p1(0x27),p1(0xb2),p1(0x75)
-+#define sb_data2(p1) \
-+ .long p1(0x09),p1(0x83),p1(0x2c),p1(0x1a),p1(0x1b),p1(0x6e),p1(0x5a),p1(0xa0) ;\
-+ .long p1(0x52),p1(0x3b),p1(0xd6),p1(0xb3),p1(0x29),p1(0xe3),p1(0x2f),p1(0x84) ;\
-+ .long p1(0x53),p1(0xd1),p1(0x00),p1(0xed),p1(0x20),p1(0xfc),p1(0xb1),p1(0x5b) ;\
-+ .long p1(0x6a),p1(0xcb),p1(0xbe),p1(0x39),p1(0x4a),p1(0x4c),p1(0x58),p1(0xcf)
-+#define sb_data3(p1) \
-+ .long p1(0xd0),p1(0xef),p1(0xaa),p1(0xfb),p1(0x43),p1(0x4d),p1(0x33),p1(0x85) ;\
-+ .long p1(0x45),p1(0xf9),p1(0x02),p1(0x7f),p1(0x50),p1(0x3c),p1(0x9f),p1(0xa8) ;\
-+ .long p1(0x51),p1(0xa3),p1(0x40),p1(0x8f),p1(0x92),p1(0x9d),p1(0x38),p1(0xf5) ;\
-+ .long p1(0xbc),p1(0xb6),p1(0xda),p1(0x21),p1(0x10),p1(0xff),p1(0xf3),p1(0xd2)
-+#define sb_data4(p1) \
-+ .long p1(0xcd),p1(0x0c),p1(0x13),p1(0xec),p1(0x5f),p1(0x97),p1(0x44),p1(0x17) ;\
-+ .long p1(0xc4),p1(0xa7),p1(0x7e),p1(0x3d),p1(0x64),p1(0x5d),p1(0x19),p1(0x73) ;\
-+ .long p1(0x60),p1(0x81),p1(0x4f),p1(0xdc),p1(0x22),p1(0x2a),p1(0x90),p1(0x88) ;\
-+ .long p1(0x46),p1(0xee),p1(0xb8),p1(0x14),p1(0xde),p1(0x5e),p1(0x0b),p1(0xdb)
-+#define sb_data5(p1) \
-+ .long p1(0xe0),p1(0x32),p1(0x3a),p1(0x0a),p1(0x49),p1(0x06),p1(0x24),p1(0x5c) ;\
-+ .long p1(0xc2),p1(0xd3),p1(0xac),p1(0x62),p1(0x91),p1(0x95),p1(0xe4),p1(0x79) ;\
-+ .long p1(0xe7),p1(0xc8),p1(0x37),p1(0x6d),p1(0x8d),p1(0xd5),p1(0x4e),p1(0xa9) ;\
-+ .long p1(0x6c),p1(0x56),p1(0xf4),p1(0xea),p1(0x65),p1(0x7a),p1(0xae),p1(0x08)
-+#define sb_data6(p1) \
-+ .long p1(0xba),p1(0x78),p1(0x25),p1(0x2e),p1(0x1c),p1(0xa6),p1(0xb4),p1(0xc6) ;\
-+ .long p1(0xe8),p1(0xdd),p1(0x74),p1(0x1f),p1(0x4b),p1(0xbd),p1(0x8b),p1(0x8a) ;\
-+ .long p1(0x70),p1(0x3e),p1(0xb5),p1(0x66),p1(0x48),p1(0x03),p1(0xf6),p1(0x0e) ;\
-+ .long p1(0x61),p1(0x35),p1(0x57),p1(0xb9),p1(0x86),p1(0xc1),p1(0x1d),p1(0x9e)
-+#define sb_data7(p1) \
-+ .long p1(0xe1),p1(0xf8),p1(0x98),p1(0x11),p1(0x69),p1(0xd9),p1(0x8e),p1(0x94) ;\
-+ .long p1(0x9b),p1(0x1e),p1(0x87),p1(0xe9),p1(0xce),p1(0x55),p1(0x28),p1(0xdf) ;\
-+ .long p1(0x8c),p1(0xa1),p1(0x89),p1(0x0d),p1(0xbf),p1(0xe6),p1(0x42),p1(0x68) ;\
-+ .long p1(0x41),p1(0x99),p1(0x2d),p1(0x0f),p1(0xb0),p1(0x54),p1(0xbb),p1(0x16)
-+
-+// Inverse S-box data - 256 entries
-+
-+#define ib_data0(p1) \
-+ .long p1(0x52),p1(0x09),p1(0x6a),p1(0xd5),p1(0x30),p1(0x36),p1(0xa5),p1(0x38) ;\
-+ .long p1(0xbf),p1(0x40),p1(0xa3),p1(0x9e),p1(0x81),p1(0xf3),p1(0xd7),p1(0xfb) ;\
-+ .long p1(0x7c),p1(0xe3),p1(0x39),p1(0x82),p1(0x9b),p1(0x2f),p1(0xff),p1(0x87) ;\
-+ .long p1(0x34),p1(0x8e),p1(0x43),p1(0x44),p1(0xc4),p1(0xde),p1(0xe9),p1(0xcb)
-+#define ib_data1(p1) \
-+ .long p1(0x54),p1(0x7b),p1(0x94),p1(0x32),p1(0xa6),p1(0xc2),p1(0x23),p1(0x3d) ;\
-+ .long p1(0xee),p1(0x4c),p1(0x95),p1(0x0b),p1(0x42),p1(0xfa),p1(0xc3),p1(0x4e) ;\
-+ .long p1(0x08),p1(0x2e),p1(0xa1),p1(0x66),p1(0x28),p1(0xd9),p1(0x24),p1(0xb2) ;\
-+ .long p1(0x76),p1(0x5b),p1(0xa2),p1(0x49),p1(0x6d),p1(0x8b),p1(0xd1),p1(0x25)
-+#define ib_data2(p1) \
-+ .long p1(0x72),p1(0xf8),p1(0xf6),p1(0x64),p1(0x86),p1(0x68),p1(0x98),p1(0x16) ;\
-+ .long p1(0xd4),p1(0xa4),p1(0x5c),p1(0xcc),p1(0x5d),p1(0x65),p1(0xb6),p1(0x92) ;\
-+ .long p1(0x6c),p1(0x70),p1(0x48),p1(0x50),p1(0xfd),p1(0xed),p1(0xb9),p1(0xda) ;\
-+ .long p1(0x5e),p1(0x15),p1(0x46),p1(0x57),p1(0xa7),p1(0x8d),p1(0x9d),p1(0x84)
-+#define ib_data3(p1) \
-+ .long p1(0x90),p1(0xd8),p1(0xab),p1(0x00),p1(0x8c),p1(0xbc),p1(0xd3),p1(0x0a) ;\
-+ .long p1(0xf7),p1(0xe4),p1(0x58),p1(0x05),p1(0xb8),p1(0xb3),p1(0x45),p1(0x06) ;\
-+ .long p1(0xd0),p1(0x2c),p1(0x1e),p1(0x8f),p1(0xca),p1(0x3f),p1(0x0f),p1(0x02) ;\
-+ .long p1(0xc1),p1(0xaf),p1(0xbd),p1(0x03),p1(0x01),p1(0x13),p1(0x8a),p1(0x6b)
-+#define ib_data4(p1) \
-+ .long p1(0x3a),p1(0x91),p1(0x11),p1(0x41),p1(0x4f),p1(0x67),p1(0xdc),p1(0xea) ;\
-+ .long p1(0x97),p1(0xf2),p1(0xcf),p1(0xce),p1(0xf0),p1(0xb4),p1(0xe6),p1(0x73) ;\
-+ .long p1(0x96),p1(0xac),p1(0x74),p1(0x22),p1(0xe7),p1(0xad),p1(0x35),p1(0x85) ;\
-+ .long p1(0xe2),p1(0xf9),p1(0x37),p1(0xe8),p1(0x1c),p1(0x75),p1(0xdf),p1(0x6e)
-+#define ib_data5(p1) \
-+ .long p1(0x47),p1(0xf1),p1(0x1a),p1(0x71),p1(0x1d),p1(0x29),p1(0xc5),p1(0x89) ;\
-+ .long p1(0x6f),p1(0xb7),p1(0x62),p1(0x0e),p1(0xaa),p1(0x18),p1(0xbe),p1(0x1b) ;\
-+ .long p1(0xfc),p1(0x56),p1(0x3e),p1(0x4b),p1(0xc6),p1(0xd2),p1(0x79),p1(0x20) ;\
-+ .long p1(0x9a),p1(0xdb),p1(0xc0),p1(0xfe),p1(0x78),p1(0xcd),p1(0x5a),p1(0xf4)
-+#define ib_data6(p1) \
-+ .long p1(0x1f),p1(0xdd),p1(0xa8),p1(0x33),p1(0x88),p1(0x07),p1(0xc7),p1(0x31) ;\
-+ .long p1(0xb1),p1(0x12),p1(0x10),p1(0x59),p1(0x27),p1(0x80),p1(0xec),p1(0x5f) ;\
-+ .long p1(0x60),p1(0x51),p1(0x7f),p1(0xa9),p1(0x19),p1(0xb5),p1(0x4a),p1(0x0d) ;\
-+ .long p1(0x2d),p1(0xe5),p1(0x7a),p1(0x9f),p1(0x93),p1(0xc9),p1(0x9c),p1(0xef)
-+#define ib_data7(p1) \
-+ .long p1(0xa0),p1(0xe0),p1(0x3b),p1(0x4d),p1(0xae),p1(0x2a),p1(0xf5),p1(0xb0) ;\
-+ .long p1(0xc8),p1(0xeb),p1(0xbb),p1(0x3c),p1(0x83),p1(0x53),p1(0x99),p1(0x61) ;\
-+ .long p1(0x17),p1(0x2b),p1(0x04),p1(0x7e),p1(0xba),p1(0x77),p1(0xd6),p1(0x26) ;\
-+ .long p1(0xe1),p1(0x69),p1(0x14),p1(0x63),p1(0x55),p1(0x21),p1(0x0c),p1(0x7d)
-+
-+// The rcon_table (needed for the key schedule)
-+//
-+// Here is original Dr Brian Gladman's source code:
-+// _rcon_tab:
-+// %assign x 1
-+// %rep 29
-+// dd x
-+// %assign x f2(x)
-+// %endrep
-+//
-+// Here is precomputed output (it's more portable this way):
-+
-+ .align ALIGN32BYTES
-+aes_rcon_tab:
-+ .long 0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80
-+ .long 0x1b,0x36,0x6c,0xd8,0xab,0x4d,0x9a,0x2f
-+ .long 0x5e,0xbc,0x63,0xc6,0x97,0x35,0x6a,0xd4
-+ .long 0xb3,0x7d,0xfa,0xef,0xc5
-+
-+// The forward xor tables
-+
-+ .align ALIGN32BYTES
-+aes_ft_tab:
-+ sb_data0(u0)
-+ sb_data1(u0)
-+ sb_data2(u0)
-+ sb_data3(u0)
-+ sb_data4(u0)
-+ sb_data5(u0)
-+ sb_data6(u0)
-+ sb_data7(u0)
-+
-+ sb_data0(u1)
-+ sb_data1(u1)
-+ sb_data2(u1)
-+ sb_data3(u1)
-+ sb_data4(u1)
-+ sb_data5(u1)
-+ sb_data6(u1)
-+ sb_data7(u1)
-+
-+ sb_data0(u2)
-+ sb_data1(u2)
-+ sb_data2(u2)
-+ sb_data3(u2)
-+ sb_data4(u2)
-+ sb_data5(u2)
-+ sb_data6(u2)
-+ sb_data7(u2)
-+
-+ sb_data0(u3)
-+ sb_data1(u3)
-+ sb_data2(u3)
-+ sb_data3(u3)
-+ sb_data4(u3)
-+ sb_data5(u3)
-+ sb_data6(u3)
-+ sb_data7(u3)
-+
-+ .align ALIGN32BYTES
-+aes_fl_tab:
-+ sb_data0(w0)
-+ sb_data1(w0)
-+ sb_data2(w0)
-+ sb_data3(w0)
-+ sb_data4(w0)
-+ sb_data5(w0)
-+ sb_data6(w0)
-+ sb_data7(w0)
-+
-+ sb_data0(w1)
-+ sb_data1(w1)
-+ sb_data2(w1)
-+ sb_data3(w1)
-+ sb_data4(w1)
-+ sb_data5(w1)
-+ sb_data6(w1)
-+ sb_data7(w1)
-+
-+ sb_data0(w2)
-+ sb_data1(w2)
-+ sb_data2(w2)
-+ sb_data3(w2)
-+ sb_data4(w2)
-+ sb_data5(w2)
-+ sb_data6(w2)
-+ sb_data7(w2)
-+
-+ sb_data0(w3)
-+ sb_data1(w3)
-+ sb_data2(w3)
-+ sb_data3(w3)
-+ sb_data4(w3)
-+ sb_data5(w3)
-+ sb_data6(w3)
-+ sb_data7(w3)
-+
-+// The inverse xor tables
-+
-+ .align ALIGN32BYTES
-+aes_it_tab:
-+ ib_data0(v0)
-+ ib_data1(v0)
-+ ib_data2(v0)
-+ ib_data3(v0)
-+ ib_data4(v0)
-+ ib_data5(v0)
-+ ib_data6(v0)
-+ ib_data7(v0)
-+
-+ ib_data0(v1)
-+ ib_data1(v1)
-+ ib_data2(v1)
-+ ib_data3(v1)
-+ ib_data4(v1)
-+ ib_data5(v1)
-+ ib_data6(v1)
-+ ib_data7(v1)
-+
-+ ib_data0(v2)
-+ ib_data1(v2)
-+ ib_data2(v2)
-+ ib_data3(v2)
-+ ib_data4(v2)
-+ ib_data5(v2)
-+ ib_data6(v2)
-+ ib_data7(v2)
-+
-+ ib_data0(v3)
-+ ib_data1(v3)
-+ ib_data2(v3)
-+ ib_data3(v3)
-+ ib_data4(v3)
-+ ib_data5(v3)
-+ ib_data6(v3)
-+ ib_data7(v3)
-+
-+ .align ALIGN32BYTES
-+aes_il_tab:
-+ ib_data0(w0)
-+ ib_data1(w0)
-+ ib_data2(w0)
-+ ib_data3(w0)
-+ ib_data4(w0)
-+ ib_data5(w0)
-+ ib_data6(w0)
-+ ib_data7(w0)
-+
-+ ib_data0(w1)
-+ ib_data1(w1)
-+ ib_data2(w1)
-+ ib_data3(w1)
-+ ib_data4(w1)
-+ ib_data5(w1)
-+ ib_data6(w1)
-+ ib_data7(w1)
-+
-+ ib_data0(w2)
-+ ib_data1(w2)
-+ ib_data2(w2)
-+ ib_data3(w2)
-+ ib_data4(w2)
-+ ib_data5(w2)
-+ ib_data6(w2)
-+ ib_data7(w2)
-+
-+ ib_data0(w3)
-+ ib_data1(w3)
-+ ib_data2(w3)
-+ ib_data3(w3)
-+ ib_data4(w3)
-+ ib_data5(w3)
-+ ib_data6(w3)
-+ ib_data7(w3)
-+
-+// The inverse mix column tables
-+
-+ .align ALIGN32BYTES
-+aes_im_tab:
-+ im_data0(v0)
-+ im_data1(v0)
-+ im_data2(v0)
-+ im_data3(v0)
-+ im_data4(v0)
-+ im_data5(v0)
-+ im_data6(v0)
-+ im_data7(v0)
-+
-+ im_data0(v1)
-+ im_data1(v1)
-+ im_data2(v1)
-+ im_data3(v1)
-+ im_data4(v1)
-+ im_data5(v1)
-+ im_data6(v1)
-+ im_data7(v1)
-+
-+ im_data0(v2)
-+ im_data1(v2)
-+ im_data2(v2)
-+ im_data3(v2)
-+ im_data4(v2)
-+ im_data5(v2)
-+ im_data6(v2)
-+ im_data7(v2)
-+
-+ im_data0(v3)
-+ im_data1(v3)
-+ im_data2(v3)
-+ im_data3(v3)
-+ im_data4(v3)
-+ im_data5(v3)
-+ im_data6(v3)
-+ im_data7(v3)
---- /dev/null Tue Mar 11 13:02:56 2003
-+++ linux/crypto/ciphers/aes/aes.c Mon Feb 9 13:51:03 2004
-@@ -0,0 +1,1415 @@
-+// I retain copyright in this code but I encourage its free use provided
-+// that I don't carry any responsibility for the results. I am especially
-+// happy to see it used in free and open source software. If you do use
-+// it I would appreciate an acknowledgement of its origin in the code or
-+// the product that results and I would also appreciate knowing a little
-+// about the use to which it is being put. I am grateful to Frank Yellin
-+// for some ideas that are used in this implementation.
-+//
-+// Dr B. R. Gladman <brg@gladman.uk.net> 6th April 2001.
-+//
-+// This is an implementation of the AES encryption algorithm (Rijndael)
-+// designed by Joan Daemen and Vincent Rijmen. This version is designed
-+// to provide both fixed and dynamic block and key lengths and can also
-+// run with either big or little endian internal byte order (see aes.h).
-+// It inputs block and key lengths in bytes with the legal values being
-+// 16, 24 and 32.
-+
-+/*
-+ * Modified by Jari Ruusu, May 1 2001
-+ * - Fixed some compile warnings, code was ok but gcc warned anyway.
-+ * - Changed basic types: byte -> unsigned char, word -> u_int32_t
-+ * - Major name space cleanup: Names visible to outside now begin
-+ * with "aes_" or "AES_". A lot of stuff moved from aes.h to aes.c
-+ * - Removed C++ and DLL support as part of name space cleanup.
-+ * - Eliminated unnecessary recomputation of tables. (actual bug fix)
-+ * - Merged precomputed constant tables to aes.c file.
-+ * - Removed data alignment restrictions for portability reasons.
-+ * - Made block and key lengths accept bit count (128/192/256)
-+ * as well byte count (16/24/32).
-+ * - Removed all error checks. This change also eliminated the need
-+ * to preinitialize the context struct to zero.
-+ * - Removed some totally unused constants.
-+ */
-+
-+#include "crypto/aes.h"
-+
-+// CONFIGURATION OPTIONS (see also aes.h)
-+//
-+// 1. Define UNROLL for full loop unrolling in encryption and decryption.
-+// 2. Define PARTIAL_UNROLL to unroll two loops in encryption and decryption.
-+// 3. Define FIXED_TABLES for compiled rather than dynamic tables.
-+// 4. Define FF_TABLES to use tables for field multiplies and inverses.
-+// Do not enable this without understanding stack space requirements.
-+// 5. Define ARRAYS to use arrays to hold the local state block. If this
-+// is not defined, individually declared 32-bit words are used.
-+// 6. Define FAST_VARIABLE if a high speed variable block implementation
-+// is needed (essentially three separate fixed block size code sequences)
-+// 7. Define either ONE_TABLE or FOUR_TABLES for a fast table driven
-+// version using 1 table (2 kbytes of table space) or 4 tables (8
-+// kbytes of table space) for higher speed.
-+// 8. Define either ONE_LR_TABLE or FOUR_LR_TABLES for a further speed
-+// increase by using tables for the last rounds but with more table
-+// space (2 or 8 kbytes extra).
-+// 9. If neither ONE_TABLE nor FOUR_TABLES is defined, a compact but
-+// slower version is provided.
-+// 10. If fast decryption key scheduling is needed define ONE_IM_TABLE
-+// or FOUR_IM_TABLES for higher speed (2 or 8 kbytes extra).
-+
-+#define UNROLL
-+//#define PARTIAL_UNROLL
-+
-+#define FIXED_TABLES
-+//#define FF_TABLES
-+//#define ARRAYS
-+#define FAST_VARIABLE
-+
-+//#define ONE_TABLE
-+#define FOUR_TABLES
-+
-+//#define ONE_LR_TABLE
-+#define FOUR_LR_TABLES
-+
-+//#define ONE_IM_TABLE
-+#define FOUR_IM_TABLES
-+
-+#if defined(UNROLL) && defined (PARTIAL_UNROLL)
-+#error both UNROLL and PARTIAL_UNROLL are defined
-+#endif
-+
-+#if defined(ONE_TABLE) && defined (FOUR_TABLES)
-+#error both ONE_TABLE and FOUR_TABLES are defined
-+#endif
-+
-+#if defined(ONE_LR_TABLE) && defined (FOUR_LR_TABLES)
-+#error both ONE_LR_TABLE and FOUR_LR_TABLES are defined
-+#endif
-+
-+#if defined(ONE_IM_TABLE) && defined (FOUR_IM_TABLES)
-+#error both ONE_IM_TABLE and FOUR_IM_TABLES are defined
-+#endif
-+
-+#if defined(AES_BLOCK_SIZE) && AES_BLOCK_SIZE != 16 && AES_BLOCK_SIZE != 24 && AES_BLOCK_SIZE != 32
-+#error an illegal block size has been specified
-+#endif
-+
-+// upr(x,n): rotates bytes within words by n positions, moving bytes
-+// to higher index positions with wrap around into low positions
-+// ups(x,n): moves bytes by n positions to higher index positions in
-+// words but without wrap around
-+// bval(x,n): extracts a byte from a word
-+
-+#define upr(x,n) (((x) << 8 * (n)) | ((x) >> (32 - 8 * (n))))
-+#define ups(x,n) ((x) << 8 * (n))
-+#define bval(x,n) ((unsigned char)((x) >> 8 * (n)))
-+#define bytes2word(b0, b1, b2, b3) \
-+ ((u_int32_t)(b3) << 24 | (u_int32_t)(b2) << 16 | (u_int32_t)(b1) << 8 | (b0))
-+
-+
-+/* little endian processor without data alignment restrictions: AES_LE_OK */
-+/* original code: i386 */
-+#if defined(i386) || defined(_I386) || defined(__i386__) || defined(__i386)
-+#define AES_LE_OK 1
-+/* added (tested): alpha --jjo */
-+#elif defined(__alpha__)|| defined (__alpha)
-+#define AES_LE_OK 1
-+/* added (tested): ia64 --jjo */
-+#elif defined(__ia64__)|| defined (__ia64)
-+#define AES_LE_OK 1
-+#endif
-+
-+#ifdef AES_LE_OK
-+/* little endian processor without data alignment restrictions */
-+#define word_in(x) *(u_int32_t*)(x)
-+#define const_word_in(x) *(const u_int32_t*)(x)
-+#define word_out(x,v) *(u_int32_t*)(x) = (v)
-+#define const_word_out(x,v) *(const u_int32_t*)(x) = (v)
-+#else
-+/* slower but generic big endian or with data alignment restrictions */
-+/* some additional "const" touches to stop "gcc -Wcast-qual" complains --jjo */
-+#define word_in(x) ((u_int32_t)(((unsigned char *)(x))[0])|((u_int32_t)(((unsigned char *)(x))[1])<<8)|((u_int32_t)(((unsigned char *)(x))[2])<<16)|((u_int32_t)(((unsigned char *)(x))[3])<<24))
-+#define const_word_in(x) ((const u_int32_t)(((const unsigned char *)(x))[0])|((const u_int32_t)(((const unsigned char *)(x))[1])<<8)|((const u_int32_t)(((const unsigned char *)(x))[2])<<16)|((const u_int32_t)(((const unsigned char *)(x))[3])<<24))
-+#define word_out(x,v) ((unsigned char *)(x))[0]=(v),((unsigned char *)(x))[1]=((v)>>8),((unsigned char *)(x))[2]=((v)>>16),((unsigned char *)(x))[3]=((v)>>24)
-+#define const_word_out(x,v) ((const unsigned char *)(x))[0]=(v),((const unsigned char *)(x))[1]=((v)>>8),((const unsigned char *)(x))[2]=((v)>>16),((const unsigned char *)(x))[3]=((v)>>24)
-+#endif
-+
-+// Disable at least some poor combinations of options
-+
-+#if !defined(ONE_TABLE) && !defined(FOUR_TABLES)
-+#define FIXED_TABLES
-+#undef UNROLL
-+#undef ONE_LR_TABLE
-+#undef FOUR_LR_TABLES
-+#undef ONE_IM_TABLE
-+#undef FOUR_IM_TABLES
-+#elif !defined(FOUR_TABLES)
-+#ifdef FOUR_LR_TABLES
-+#undef FOUR_LR_TABLES
-+#define ONE_LR_TABLE
-+#endif
-+#ifdef FOUR_IM_TABLES
-+#undef FOUR_IM_TABLES
-+#define ONE_IM_TABLE
-+#endif
-+#elif !defined(AES_BLOCK_SIZE)
-+#if defined(UNROLL)
-+#define PARTIAL_UNROLL
-+#undef UNROLL
-+#endif
-+#endif
-+
-+// the finite field modular polynomial and elements
-+
-+#define ff_poly 0x011b
-+#define ff_hi 0x80
-+
-+// multiply four bytes in GF(2^8) by 'x' {02} in parallel
-+
-+#define m1 0x80808080
-+#define m2 0x7f7f7f7f
-+#define m3 0x0000001b
-+#define FFmulX(x) ((((x) & m2) << 1) ^ ((((x) & m1) >> 7) * m3))
-+
-+// The following defines provide alternative definitions of FFmulX that might
-+// give improved performance if a fast 32-bit multiply is not available. Note
-+// that a temporary variable u needs to be defined where FFmulX is used.
-+
-+// #define FFmulX(x) (u = (x) & m1, u |= (u >> 1), ((x) & m2) << 1) ^ ((u >> 3) | (u >> 6))
-+// #define m4 0x1b1b1b1b
-+// #define FFmulX(x) (u = (x) & m1, ((x) & m2) << 1) ^ ((u - (u >> 7)) & m4)
-+
-+// perform column mix operation on four bytes in parallel
-+
-+#define fwd_mcol(x) (f2 = FFmulX(x), f2 ^ upr(x ^ f2,3) ^ upr(x,2) ^ upr(x,1))
-+
-+#if defined(FIXED_TABLES)
-+
-+// the S-Box table
-+
-+static const unsigned char s_box[256] =
-+{
-+ 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5,
-+ 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76,
-+ 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0,
-+ 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0,
-+ 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc,
-+ 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15,
-+ 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a,
-+ 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75,
-+ 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0,
-+ 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84,
-+ 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b,
-+ 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf,
-+ 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85,
-+ 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8,
-+ 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5,
-+ 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2,
-+ 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17,
-+ 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73,
-+ 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88,
-+ 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb,
-+ 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c,
-+ 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79,
-+ 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9,
-+ 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08,
-+ 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6,
-+ 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a,
-+ 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e,
-+ 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e,
-+ 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94,
-+ 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf,
-+ 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68,
-+ 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16
-+};
-+
-+// the inverse S-Box table
-+
-+static const unsigned char inv_s_box[256] =
-+{
-+ 0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38,
-+ 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb,
-+ 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87,
-+ 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb,
-+ 0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d,
-+ 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e,
-+ 0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2,
-+ 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25,
-+ 0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16,
-+ 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92,
-+ 0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda,
-+ 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84,
-+ 0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a,
-+ 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06,
-+ 0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02,
-+ 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b,
-+ 0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea,
-+ 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73,
-+ 0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85,
-+ 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e,
-+ 0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89,
-+ 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b,
-+ 0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20,
-+ 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4,
-+ 0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31,
-+ 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f,
-+ 0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d,
-+ 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef,
-+ 0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0,
-+ 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61,
-+ 0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26,
-+ 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d
-+};
-+
-+#define w0(p) 0x000000##p
-+
-+// Number of elements required in this table for different
-+// block and key lengths is:
-+//
-+// Nk = 4 6 8
-+// ----------
-+// Nb = 4 | 10 8 7
-+// 6 | 19 12 11
-+// 8 | 29 19 14
-+//
-+// this table can be a table of bytes if the key schedule
-+// code is adjusted accordingly
-+
-+static const u_int32_t rcon_tab[29] =
-+{
-+ w0(01), w0(02), w0(04), w0(08),
-+ w0(10), w0(20), w0(40), w0(80),
-+ w0(1b), w0(36), w0(6c), w0(d8),
-+ w0(ab), w0(4d), w0(9a), w0(2f),
-+ w0(5e), w0(bc), w0(63), w0(c6),
-+ w0(97), w0(35), w0(6a), w0(d4),
-+ w0(b3), w0(7d), w0(fa), w0(ef),
-+ w0(c5)
-+};
-+
-+#undef w0
-+
-+#define r0(p,q,r,s) 0x##p##q##r##s
-+#define r1(p,q,r,s) 0x##q##r##s##p
-+#define r2(p,q,r,s) 0x##r##s##p##q
-+#define r3(p,q,r,s) 0x##s##p##q##r
-+#define w0(p) 0x000000##p
-+#define w1(p) 0x0000##p##00
-+#define w2(p) 0x00##p##0000
-+#define w3(p) 0x##p##000000
-+
-+#if defined(FIXED_TABLES) && (defined(ONE_TABLE) || defined(FOUR_TABLES))
-+
-+// data for forward tables (other than last round)
-+
-+#define f_table \
-+ r(a5,63,63,c6), r(84,7c,7c,f8), r(99,77,77,ee), r(8d,7b,7b,f6),\
-+ r(0d,f2,f2,ff), r(bd,6b,6b,d6), r(b1,6f,6f,de), r(54,c5,c5,91),\
-+ r(50,30,30,60), r(03,01,01,02), r(a9,67,67,ce), r(7d,2b,2b,56),\
-+ r(19,fe,fe,e7), r(62,d7,d7,b5), r(e6,ab,ab,4d), r(9a,76,76,ec),\
-+ r(45,ca,ca,8f), r(9d,82,82,1f), r(40,c9,c9,89), r(87,7d,7d,fa),\
-+ r(15,fa,fa,ef), r(eb,59,59,b2), r(c9,47,47,8e), r(0b,f0,f0,fb),\
-+ r(ec,ad,ad,41), r(67,d4,d4,b3), r(fd,a2,a2,5f), r(ea,af,af,45),\
-+ r(bf,9c,9c,23), r(f7,a4,a4,53), r(96,72,72,e4), r(5b,c0,c0,9b),\
-+ r(c2,b7,b7,75), r(1c,fd,fd,e1), r(ae,93,93,3d), r(6a,26,26,4c),\
-+ r(5a,36,36,6c), r(41,3f,3f,7e), r(02,f7,f7,f5), r(4f,cc,cc,83),\
-+ r(5c,34,34,68), r(f4,a5,a5,51), r(34,e5,e5,d1), r(08,f1,f1,f9),\
-+ r(93,71,71,e2), r(73,d8,d8,ab), r(53,31,31,62), r(3f,15,15,2a),\
-+ r(0c,04,04,08), r(52,c7,c7,95), r(65,23,23,46), r(5e,c3,c3,9d),\
-+ r(28,18,18,30), r(a1,96,96,37), r(0f,05,05,0a), r(b5,9a,9a,2f),\
-+ r(09,07,07,0e), r(36,12,12,24), r(9b,80,80,1b), r(3d,e2,e2,df),\
-+ r(26,eb,eb,cd), r(69,27,27,4e), r(cd,b2,b2,7f), r(9f,75,75,ea),\
-+ r(1b,09,09,12), r(9e,83,83,1d), r(74,2c,2c,58), r(2e,1a,1a,34),\
-+ r(2d,1b,1b,36), r(b2,6e,6e,dc), r(ee,5a,5a,b4), r(fb,a0,a0,5b),\
-+ r(f6,52,52,a4), r(4d,3b,3b,76), r(61,d6,d6,b7), r(ce,b3,b3,7d),\
-+ r(7b,29,29,52), r(3e,e3,e3,dd), r(71,2f,2f,5e), r(97,84,84,13),\
-+ r(f5,53,53,a6), r(68,d1,d1,b9), r(00,00,00,00), r(2c,ed,ed,c1),\
-+ r(60,20,20,40), r(1f,fc,fc,e3), r(c8,b1,b1,79), r(ed,5b,5b,b6),\
-+ r(be,6a,6a,d4), r(46,cb,cb,8d), r(d9,be,be,67), r(4b,39,39,72),\
-+ r(de,4a,4a,94), r(d4,4c,4c,98), r(e8,58,58,b0), r(4a,cf,cf,85),\
-+ r(6b,d0,d0,bb), r(2a,ef,ef,c5), r(e5,aa,aa,4f), r(16,fb,fb,ed),\
-+ r(c5,43,43,86), r(d7,4d,4d,9a), r(55,33,33,66), r(94,85,85,11),\
-+ r(cf,45,45,8a), r(10,f9,f9,e9), r(06,02,02,04), r(81,7f,7f,fe),\
-+ r(f0,50,50,a0), r(44,3c,3c,78), r(ba,9f,9f,25), r(e3,a8,a8,4b),\
-+ r(f3,51,51,a2), r(fe,a3,a3,5d), r(c0,40,40,80), r(8a,8f,8f,05),\
-+ r(ad,92,92,3f), r(bc,9d,9d,21), r(48,38,38,70), r(04,f5,f5,f1),\
-+ r(df,bc,bc,63), r(c1,b6,b6,77), r(75,da,da,af), r(63,21,21,42),\
-+ r(30,10,10,20), r(1a,ff,ff,e5), r(0e,f3,f3,fd), r(6d,d2,d2,bf),\
-+ r(4c,cd,cd,81), r(14,0c,0c,18), r(35,13,13,26), r(2f,ec,ec,c3),\
-+ r(e1,5f,5f,be), r(a2,97,97,35), r(cc,44,44,88), r(39,17,17,2e),\
-+ r(57,c4,c4,93), r(f2,a7,a7,55), r(82,7e,7e,fc), r(47,3d,3d,7a),\
-+ r(ac,64,64,c8), r(e7,5d,5d,ba), r(2b,19,19,32), r(95,73,73,e6),\
-+ r(a0,60,60,c0), r(98,81,81,19), r(d1,4f,4f,9e), r(7f,dc,dc,a3),\
-+ r(66,22,22,44), r(7e,2a,2a,54), r(ab,90,90,3b), r(83,88,88,0b),\
-+ r(ca,46,46,8c), r(29,ee,ee,c7), r(d3,b8,b8,6b), r(3c,14,14,28),\
-+ r(79,de,de,a7), r(e2,5e,5e,bc), r(1d,0b,0b,16), r(76,db,db,ad),\
-+ r(3b,e0,e0,db), r(56,32,32,64), r(4e,3a,3a,74), r(1e,0a,0a,14),\
-+ r(db,49,49,92), r(0a,06,06,0c), r(6c,24,24,48), r(e4,5c,5c,b8),\
-+ r(5d,c2,c2,9f), r(6e,d3,d3,bd), r(ef,ac,ac,43), r(a6,62,62,c4),\
-+ r(a8,91,91,39), r(a4,95,95,31), r(37,e4,e4,d3), r(8b,79,79,f2),\
-+ r(32,e7,e7,d5), r(43,c8,c8,8b), r(59,37,37,6e), r(b7,6d,6d,da),\
-+ r(8c,8d,8d,01), r(64,d5,d5,b1), r(d2,4e,4e,9c), r(e0,a9,a9,49),\
-+ r(b4,6c,6c,d8), r(fa,56,56,ac), r(07,f4,f4,f3), r(25,ea,ea,cf),\
-+ r(af,65,65,ca), r(8e,7a,7a,f4), r(e9,ae,ae,47), r(18,08,08,10),\
-+ r(d5,ba,ba,6f), r(88,78,78,f0), r(6f,25,25,4a), r(72,2e,2e,5c),\
-+ r(24,1c,1c,38), r(f1,a6,a6,57), r(c7,b4,b4,73), r(51,c6,c6,97),\
-+ r(23,e8,e8,cb), r(7c,dd,dd,a1), r(9c,74,74,e8), r(21,1f,1f,3e),\
-+ r(dd,4b,4b,96), r(dc,bd,bd,61), r(86,8b,8b,0d), r(85,8a,8a,0f),\
-+ r(90,70,70,e0), r(42,3e,3e,7c), r(c4,b5,b5,71), r(aa,66,66,cc),\
-+ r(d8,48,48,90), r(05,03,03,06), r(01,f6,f6,f7), r(12,0e,0e,1c),\
-+ r(a3,61,61,c2), r(5f,35,35,6a), r(f9,57,57,ae), r(d0,b9,b9,69),\
-+ r(91,86,86,17), r(58,c1,c1,99), r(27,1d,1d,3a), r(b9,9e,9e,27),\
-+ r(38,e1,e1,d9), r(13,f8,f8,eb), r(b3,98,98,2b), r(33,11,11,22),\
-+ r(bb,69,69,d2), r(70,d9,d9,a9), r(89,8e,8e,07), r(a7,94,94,33),\
-+ r(b6,9b,9b,2d), r(22,1e,1e,3c), r(92,87,87,15), r(20,e9,e9,c9),\
-+ r(49,ce,ce,87), r(ff,55,55,aa), r(78,28,28,50), r(7a,df,df,a5),\
-+ r(8f,8c,8c,03), r(f8,a1,a1,59), r(80,89,89,09), r(17,0d,0d,1a),\
-+ r(da,bf,bf,65), r(31,e6,e6,d7), r(c6,42,42,84), r(b8,68,68,d0),\
-+ r(c3,41,41,82), r(b0,99,99,29), r(77,2d,2d,5a), r(11,0f,0f,1e),\
-+ r(cb,b0,b0,7b), r(fc,54,54,a8), r(d6,bb,bb,6d), r(3a,16,16,2c)
-+
-+// data for inverse tables (other than last round)
-+
-+#define i_table \
-+ r(50,a7,f4,51), r(53,65,41,7e), r(c3,a4,17,1a), r(96,5e,27,3a),\
-+ r(cb,6b,ab,3b), r(f1,45,9d,1f), r(ab,58,fa,ac), r(93,03,e3,4b),\
-+ r(55,fa,30,20), r(f6,6d,76,ad), r(91,76,cc,88), r(25,4c,02,f5),\
-+ r(fc,d7,e5,4f), r(d7,cb,2a,c5), r(80,44,35,26), r(8f,a3,62,b5),\
-+ r(49,5a,b1,de), r(67,1b,ba,25), r(98,0e,ea,45), r(e1,c0,fe,5d),\
-+ r(02,75,2f,c3), r(12,f0,4c,81), r(a3,97,46,8d), r(c6,f9,d3,6b),\
-+ r(e7,5f,8f,03), r(95,9c,92,15), r(eb,7a,6d,bf), r(da,59,52,95),\
-+ r(2d,83,be,d4), r(d3,21,74,58), r(29,69,e0,49), r(44,c8,c9,8e),\
-+ r(6a,89,c2,75), r(78,79,8e,f4), r(6b,3e,58,99), r(dd,71,b9,27),\
-+ r(b6,4f,e1,be), r(17,ad,88,f0), r(66,ac,20,c9), r(b4,3a,ce,7d),\
-+ r(18,4a,df,63), r(82,31,1a,e5), r(60,33,51,97), r(45,7f,53,62),\
-+ r(e0,77,64,b1), r(84,ae,6b,bb), r(1c,a0,81,fe), r(94,2b,08,f9),\
-+ r(58,68,48,70), r(19,fd,45,8f), r(87,6c,de,94), r(b7,f8,7b,52),\
-+ r(23,d3,73,ab), r(e2,02,4b,72), r(57,8f,1f,e3), r(2a,ab,55,66),\
-+ r(07,28,eb,b2), r(03,c2,b5,2f), r(9a,7b,c5,86), r(a5,08,37,d3),\
-+ r(f2,87,28,30), r(b2,a5,bf,23), r(ba,6a,03,02), r(5c,82,16,ed),\
-+ r(2b,1c,cf,8a), r(92,b4,79,a7), r(f0,f2,07,f3), r(a1,e2,69,4e),\
-+ r(cd,f4,da,65), r(d5,be,05,06), r(1f,62,34,d1), r(8a,fe,a6,c4),\
-+ r(9d,53,2e,34), r(a0,55,f3,a2), r(32,e1,8a,05), r(75,eb,f6,a4),\
-+ r(39,ec,83,0b), r(aa,ef,60,40), r(06,9f,71,5e), r(51,10,6e,bd),\
-+ r(f9,8a,21,3e), r(3d,06,dd,96), r(ae,05,3e,dd), r(46,bd,e6,4d),\
-+ r(b5,8d,54,91), r(05,5d,c4,71), r(6f,d4,06,04), r(ff,15,50,60),\
-+ r(24,fb,98,19), r(97,e9,bd,d6), r(cc,43,40,89), r(77,9e,d9,67),\
-+ r(bd,42,e8,b0), r(88,8b,89,07), r(38,5b,19,e7), r(db,ee,c8,79),\
-+ r(47,0a,7c,a1), r(e9,0f,42,7c), r(c9,1e,84,f8), r(00,00,00,00),\
-+ r(83,86,80,09), r(48,ed,2b,32), r(ac,70,11,1e), r(4e,72,5a,6c),\
-+ r(fb,ff,0e,fd), r(56,38,85,0f), r(1e,d5,ae,3d), r(27,39,2d,36),\
-+ r(64,d9,0f,0a), r(21,a6,5c,68), r(d1,54,5b,9b), r(3a,2e,36,24),\
-+ r(b1,67,0a,0c), r(0f,e7,57,93), r(d2,96,ee,b4), r(9e,91,9b,1b),\
-+ r(4f,c5,c0,80), r(a2,20,dc,61), r(69,4b,77,5a), r(16,1a,12,1c),\
-+ r(0a,ba,93,e2), r(e5,2a,a0,c0), r(43,e0,22,3c), r(1d,17,1b,12),\
-+ r(0b,0d,09,0e), r(ad,c7,8b,f2), r(b9,a8,b6,2d), r(c8,a9,1e,14),\
-+ r(85,19,f1,57), r(4c,07,75,af), r(bb,dd,99,ee), r(fd,60,7f,a3),\
-+ r(9f,26,01,f7), r(bc,f5,72,5c), r(c5,3b,66,44), r(34,7e,fb,5b),\
-+ r(76,29,43,8b), r(dc,c6,23,cb), r(68,fc,ed,b6), r(63,f1,e4,b8),\
-+ r(ca,dc,31,d7), r(10,85,63,42), r(40,22,97,13), r(20,11,c6,84),\
-+ r(7d,24,4a,85), r(f8,3d,bb,d2), r(11,32,f9,ae), r(6d,a1,29,c7),\
-+ r(4b,2f,9e,1d), r(f3,30,b2,dc), r(ec,52,86,0d), r(d0,e3,c1,77),\
-+ r(6c,16,b3,2b), r(99,b9,70,a9), r(fa,48,94,11), r(22,64,e9,47),\
-+ r(c4,8c,fc,a8), r(1a,3f,f0,a0), r(d8,2c,7d,56), r(ef,90,33,22),\
-+ r(c7,4e,49,87), r(c1,d1,38,d9), r(fe,a2,ca,8c), r(36,0b,d4,98),\
-+ r(cf,81,f5,a6), r(28,de,7a,a5), r(26,8e,b7,da), r(a4,bf,ad,3f),\
-+ r(e4,9d,3a,2c), r(0d,92,78,50), r(9b,cc,5f,6a), r(62,46,7e,54),\
-+ r(c2,13,8d,f6), r(e8,b8,d8,90), r(5e,f7,39,2e), r(f5,af,c3,82),\
-+ r(be,80,5d,9f), r(7c,93,d0,69), r(a9,2d,d5,6f), r(b3,12,25,cf),\
-+ r(3b,99,ac,c8), r(a7,7d,18,10), r(6e,63,9c,e8), r(7b,bb,3b,db),\
-+ r(09,78,26,cd), r(f4,18,59,6e), r(01,b7,9a,ec), r(a8,9a,4f,83),\
-+ r(65,6e,95,e6), r(7e,e6,ff,aa), r(08,cf,bc,21), r(e6,e8,15,ef),\
-+ r(d9,9b,e7,ba), r(ce,36,6f,4a), r(d4,09,9f,ea), r(d6,7c,b0,29),\
-+ r(af,b2,a4,31), r(31,23,3f,2a), r(30,94,a5,c6), r(c0,66,a2,35),\
-+ r(37,bc,4e,74), r(a6,ca,82,fc), r(b0,d0,90,e0), r(15,d8,a7,33),\
-+ r(4a,98,04,f1), r(f7,da,ec,41), r(0e,50,cd,7f), r(2f,f6,91,17),\
-+ r(8d,d6,4d,76), r(4d,b0,ef,43), r(54,4d,aa,cc), r(df,04,96,e4),\
-+ r(e3,b5,d1,9e), r(1b,88,6a,4c), r(b8,1f,2c,c1), r(7f,51,65,46),\
-+ r(04,ea,5e,9d), r(5d,35,8c,01), r(73,74,87,fa), r(2e,41,0b,fb),\
-+ r(5a,1d,67,b3), r(52,d2,db,92), r(33,56,10,e9), r(13,47,d6,6d),\
-+ r(8c,61,d7,9a), r(7a,0c,a1,37), r(8e,14,f8,59), r(89,3c,13,eb),\
-+ r(ee,27,a9,ce), r(35,c9,61,b7), r(ed,e5,1c,e1), r(3c,b1,47,7a),\
-+ r(59,df,d2,9c), r(3f,73,f2,55), r(79,ce,14,18), r(bf,37,c7,73),\
-+ r(ea,cd,f7,53), r(5b,aa,fd,5f), r(14,6f,3d,df), r(86,db,44,78),\
-+ r(81,f3,af,ca), r(3e,c4,68,b9), r(2c,34,24,38), r(5f,40,a3,c2),\
-+ r(72,c3,1d,16), r(0c,25,e2,bc), r(8b,49,3c,28), r(41,95,0d,ff),\
-+ r(71,01,a8,39), r(de,b3,0c,08), r(9c,e4,b4,d8), r(90,c1,56,64),\
-+ r(61,84,cb,7b), r(70,b6,32,d5), r(74,5c,6c,48), r(42,57,b8,d0)
-+
-+// generate the required tables in the desired endian format
-+
-+#undef r
-+#define r r0
-+
-+#if defined(ONE_TABLE)
-+static const u_int32_t ft_tab[256] =
-+ { f_table };
-+#elif defined(FOUR_TABLES)
-+static const u_int32_t ft_tab[4][256] =
-+{ { f_table },
-+#undef r
-+#define r r1
-+ { f_table },
-+#undef r
-+#define r r2
-+ { f_table },
-+#undef r
-+#define r r3
-+ { f_table }
-+};
-+#endif
-+
-+#undef r
-+#define r r0
-+#if defined(ONE_TABLE)
-+static const u_int32_t it_tab[256] =
-+ { i_table };
-+#elif defined(FOUR_TABLES)
-+static const u_int32_t it_tab[4][256] =
-+{ { i_table },
-+#undef r
-+#define r r1
-+ { i_table },
-+#undef r
-+#define r r2
-+ { i_table },
-+#undef r
-+#define r r3
-+ { i_table }
-+};
-+#endif
-+
-+#endif
-+
-+#if defined(FIXED_TABLES) && (defined(ONE_LR_TABLE) || defined(FOUR_LR_TABLES))
-+
-+// data for inverse tables (last round)
-+
-+#define li_table \
-+ w(52), w(09), w(6a), w(d5), w(30), w(36), w(a5), w(38),\
-+ w(bf), w(40), w(a3), w(9e), w(81), w(f3), w(d7), w(fb),\
-+ w(7c), w(e3), w(39), w(82), w(9b), w(2f), w(ff), w(87),\
-+ w(34), w(8e), w(43), w(44), w(c4), w(de), w(e9), w(cb),\
-+ w(54), w(7b), w(94), w(32), w(a6), w(c2), w(23), w(3d),\
-+ w(ee), w(4c), w(95), w(0b), w(42), w(fa), w(c3), w(4e),\
-+ w(08), w(2e), w(a1), w(66), w(28), w(d9), w(24), w(b2),\
-+ w(76), w(5b), w(a2), w(49), w(6d), w(8b), w(d1), w(25),\
-+ w(72), w(f8), w(f6), w(64), w(86), w(68), w(98), w(16),\
-+ w(d4), w(a4), w(5c), w(cc), w(5d), w(65), w(b6), w(92),\
-+ w(6c), w(70), w(48), w(50), w(fd), w(ed), w(b9), w(da),\
-+ w(5e), w(15), w(46), w(57), w(a7), w(8d), w(9d), w(84),\
-+ w(90), w(d8), w(ab), w(00), w(8c), w(bc), w(d3), w(0a),\
-+ w(f7), w(e4), w(58), w(05), w(b8), w(b3), w(45), w(06),\
-+ w(d0), w(2c), w(1e), w(8f), w(ca), w(3f), w(0f), w(02),\
-+ w(c1), w(af), w(bd), w(03), w(01), w(13), w(8a), w(6b),\
-+ w(3a), w(91), w(11), w(41), w(4f), w(67), w(dc), w(ea),\
-+ w(97), w(f2), w(cf), w(ce), w(f0), w(b4), w(e6), w(73),\
-+ w(96), w(ac), w(74), w(22), w(e7), w(ad), w(35), w(85),\
-+ w(e2), w(f9), w(37), w(e8), w(1c), w(75), w(df), w(6e),\
-+ w(47), w(f1), w(1a), w(71), w(1d), w(29), w(c5), w(89),\
-+ w(6f), w(b7), w(62), w(0e), w(aa), w(18), w(be), w(1b),\
-+ w(fc), w(56), w(3e), w(4b), w(c6), w(d2), w(79), w(20),\
-+ w(9a), w(db), w(c0), w(fe), w(78), w(cd), w(5a), w(f4),\
-+ w(1f), w(dd), w(a8), w(33), w(88), w(07), w(c7), w(31),\
-+ w(b1), w(12), w(10), w(59), w(27), w(80), w(ec), w(5f),\
-+ w(60), w(51), w(7f), w(a9), w(19), w(b5), w(4a), w(0d),\
-+ w(2d), w(e5), w(7a), w(9f), w(93), w(c9), w(9c), w(ef),\
-+ w(a0), w(e0), w(3b), w(4d), w(ae), w(2a), w(f5), w(b0),\
-+ w(c8), w(eb), w(bb), w(3c), w(83), w(53), w(99), w(61),\
-+ w(17), w(2b), w(04), w(7e), w(ba), w(77), w(d6), w(26),\
-+ w(e1), w(69), w(14), w(63), w(55), w(21), w(0c), w(7d),
-+
-+// generate the required tables in the desired endian format
-+
-+#undef r
-+#define r(p,q,r,s) w0(q)
-+#if defined(ONE_LR_TABLE)
-+static const u_int32_t fl_tab[256] =
-+ { f_table };
-+#elif defined(FOUR_LR_TABLES)
-+static const u_int32_t fl_tab[4][256] =
-+{ { f_table },
-+#undef r
-+#define r(p,q,r,s) w1(q)
-+ { f_table },
-+#undef r
-+#define r(p,q,r,s) w2(q)
-+ { f_table },
-+#undef r
-+#define r(p,q,r,s) w3(q)
-+ { f_table }
-+};
-+#endif
-+
-+#undef w
-+#define w w0
-+#if defined(ONE_LR_TABLE)
-+static const u_int32_t il_tab[256] =
-+ { li_table };
-+#elif defined(FOUR_LR_TABLES)
-+static const u_int32_t il_tab[4][256] =
-+{ { li_table },
-+#undef w
-+#define w w1
-+ { li_table },
-+#undef w
-+#define w w2
-+ { li_table },
-+#undef w
-+#define w w3
-+ { li_table }
-+};
-+#endif
-+
-+#endif
-+
-+#if defined(FIXED_TABLES) && (defined(ONE_IM_TABLE) || defined(FOUR_IM_TABLES))
-+
-+#define m_table \
-+ r(00,00,00,00), r(0b,0d,09,0e), r(16,1a,12,1c), r(1d,17,1b,12),\
-+ r(2c,34,24,38), r(27,39,2d,36), r(3a,2e,36,24), r(31,23,3f,2a),\
-+ r(58,68,48,70), r(53,65,41,7e), r(4e,72,5a,6c), r(45,7f,53,62),\
-+ r(74,5c,6c,48), r(7f,51,65,46), r(62,46,7e,54), r(69,4b,77,5a),\
-+ r(b0,d0,90,e0), r(bb,dd,99,ee), r(a6,ca,82,fc), r(ad,c7,8b,f2),\
-+ r(9c,e4,b4,d8), r(97,e9,bd,d6), r(8a,fe,a6,c4), r(81,f3,af,ca),\
-+ r(e8,b8,d8,90), r(e3,b5,d1,9e), r(fe,a2,ca,8c), r(f5,af,c3,82),\
-+ r(c4,8c,fc,a8), r(cf,81,f5,a6), r(d2,96,ee,b4), r(d9,9b,e7,ba),\
-+ r(7b,bb,3b,db), r(70,b6,32,d5), r(6d,a1,29,c7), r(66,ac,20,c9),\
-+ r(57,8f,1f,e3), r(5c,82,16,ed), r(41,95,0d,ff), r(4a,98,04,f1),\
-+ r(23,d3,73,ab), r(28,de,7a,a5), r(35,c9,61,b7), r(3e,c4,68,b9),\
-+ r(0f,e7,57,93), r(04,ea,5e,9d), r(19,fd,45,8f), r(12,f0,4c,81),\
-+ r(cb,6b,ab,3b), r(c0,66,a2,35), r(dd,71,b9,27), r(d6,7c,b0,29),\
-+ r(e7,5f,8f,03), r(ec,52,86,0d), r(f1,45,9d,1f), r(fa,48,94,11),\
-+ r(93,03,e3,4b), r(98,0e,ea,45), r(85,19,f1,57), r(8e,14,f8,59),\
-+ r(bf,37,c7,73), r(b4,3a,ce,7d), r(a9,2d,d5,6f), r(a2,20,dc,61),\
-+ r(f6,6d,76,ad), r(fd,60,7f,a3), r(e0,77,64,b1), r(eb,7a,6d,bf),\
-+ r(da,59,52,95), r(d1,54,5b,9b), r(cc,43,40,89), r(c7,4e,49,87),\
-+ r(ae,05,3e,dd), r(a5,08,37,d3), r(b8,1f,2c,c1), r(b3,12,25,cf),\
-+ r(82,31,1a,e5), r(89,3c,13,eb), r(94,2b,08,f9), r(9f,26,01,f7),\
-+ r(46,bd,e6,4d), r(4d,b0,ef,43), r(50,a7,f4,51), r(5b,aa,fd,5f),\
-+ r(6a,89,c2,75), r(61,84,cb,7b), r(7c,93,d0,69), r(77,9e,d9,67),\
-+ r(1e,d5,ae,3d), r(15,d8,a7,33), r(08,cf,bc,21), r(03,c2,b5,2f),\
-+ r(32,e1,8a,05), r(39,ec,83,0b), r(24,fb,98,19), r(2f,f6,91,17),\
-+ r(8d,d6,4d,76), r(86,db,44,78), r(9b,cc,5f,6a), r(90,c1,56,64),\
-+ r(a1,e2,69,4e), r(aa,ef,60,40), r(b7,f8,7b,52), r(bc,f5,72,5c),\
-+ r(d5,be,05,06), r(de,b3,0c,08), r(c3,a4,17,1a), r(c8,a9,1e,14),\
-+ r(f9,8a,21,3e), r(f2,87,28,30), r(ef,90,33,22), r(e4,9d,3a,2c),\
-+ r(3d,06,dd,96), r(36,0b,d4,98), r(2b,1c,cf,8a), r(20,11,c6,84),\
-+ r(11,32,f9,ae), r(1a,3f,f0,a0), r(07,28,eb,b2), r(0c,25,e2,bc),\
-+ r(65,6e,95,e6), r(6e,63,9c,e8), r(73,74,87,fa), r(78,79,8e,f4),\
-+ r(49,5a,b1,de), r(42,57,b8,d0), r(5f,40,a3,c2), r(54,4d,aa,cc),\
-+ r(f7,da,ec,41), r(fc,d7,e5,4f), r(e1,c0,fe,5d), r(ea,cd,f7,53),\
-+ r(db,ee,c8,79), r(d0,e3,c1,77), r(cd,f4,da,65), r(c6,f9,d3,6b),\
-+ r(af,b2,a4,31), r(a4,bf,ad,3f), r(b9,a8,b6,2d), r(b2,a5,bf,23),\
-+ r(83,86,80,09), r(88,8b,89,07), r(95,9c,92,15), r(9e,91,9b,1b),\
-+ r(47,0a,7c,a1), r(4c,07,75,af), r(51,10,6e,bd), r(5a,1d,67,b3),\
-+ r(6b,3e,58,99), r(60,33,51,97), r(7d,24,4a,85), r(76,29,43,8b),\
-+ r(1f,62,34,d1), r(14,6f,3d,df), r(09,78,26,cd), r(02,75,2f,c3),\
-+ r(33,56,10,e9), r(38,5b,19,e7), r(25,4c,02,f5), r(2e,41,0b,fb),\
-+ r(8c,61,d7,9a), r(87,6c,de,94), r(9a,7b,c5,86), r(91,76,cc,88),\
-+ r(a0,55,f3,a2), r(ab,58,fa,ac), r(b6,4f,e1,be), r(bd,42,e8,b0),\
-+ r(d4,09,9f,ea), r(df,04,96,e4), r(c2,13,8d,f6), r(c9,1e,84,f8),\
-+ r(f8,3d,bb,d2), r(f3,30,b2,dc), r(ee,27,a9,ce), r(e5,2a,a0,c0),\
-+ r(3c,b1,47,7a), r(37,bc,4e,74), r(2a,ab,55,66), r(21,a6,5c,68),\
-+ r(10,85,63,42), r(1b,88,6a,4c), r(06,9f,71,5e), r(0d,92,78,50),\
-+ r(64,d9,0f,0a), r(6f,d4,06,04), r(72,c3,1d,16), r(79,ce,14,18),\
-+ r(48,ed,2b,32), r(43,e0,22,3c), r(5e,f7,39,2e), r(55,fa,30,20),\
-+ r(01,b7,9a,ec), r(0a,ba,93,e2), r(17,ad,88,f0), r(1c,a0,81,fe),\
-+ r(2d,83,be,d4), r(26,8e,b7,da), r(3b,99,ac,c8), r(30,94,a5,c6),\
-+ r(59,df,d2,9c), r(52,d2,db,92), r(4f,c5,c0,80), r(44,c8,c9,8e),\
-+ r(75,eb,f6,a4), r(7e,e6,ff,aa), r(63,f1,e4,b8), r(68,fc,ed,b6),\
-+ r(b1,67,0a,0c), r(ba,6a,03,02), r(a7,7d,18,10), r(ac,70,11,1e),\
-+ r(9d,53,2e,34), r(96,5e,27,3a), r(8b,49,3c,28), r(80,44,35,26),\
-+ r(e9,0f,42,7c), r(e2,02,4b,72), r(ff,15,50,60), r(f4,18,59,6e),\
-+ r(c5,3b,66,44), r(ce,36,6f,4a), r(d3,21,74,58), r(d8,2c,7d,56),\
-+ r(7a,0c,a1,37), r(71,01,a8,39), r(6c,16,b3,2b), r(67,1b,ba,25),\
-+ r(56,38,85,0f), r(5d,35,8c,01), r(40,22,97,13), r(4b,2f,9e,1d),\
-+ r(22,64,e9,47), r(29,69,e0,49), r(34,7e,fb,5b), r(3f,73,f2,55),\
-+ r(0e,50,cd,7f), r(05,5d,c4,71), r(18,4a,df,63), r(13,47,d6,6d),\
-+ r(ca,dc,31,d7), r(c1,d1,38,d9), r(dc,c6,23,cb), r(d7,cb,2a,c5),\
-+ r(e6,e8,15,ef), r(ed,e5,1c,e1), r(f0,f2,07,f3), r(fb,ff,0e,fd),\
-+ r(92,b4,79,a7), r(99,b9,70,a9), r(84,ae,6b,bb), r(8f,a3,62,b5),\
-+ r(be,80,5d,9f), r(b5,8d,54,91), r(a8,9a,4f,83), r(a3,97,46,8d)
-+
-+#undef r
-+#define r r0
-+
-+#if defined(ONE_IM_TABLE)
-+static const u_int32_t im_tab[256] =
-+ { m_table };
-+#elif defined(FOUR_IM_TABLES)
-+static const u_int32_t im_tab[4][256] =
-+{ { m_table },
-+#undef r
-+#define r r1
-+ { m_table },
-+#undef r
-+#define r r2
-+ { m_table },
-+#undef r
-+#define r r3
-+ { m_table }
-+};
-+#endif
-+
-+#endif
-+
-+#else
-+
-+static int tab_gen = 0;
-+
-+static unsigned char s_box[256]; // the S box
-+static unsigned char inv_s_box[256]; // the inverse S box
-+static u_int32_t rcon_tab[AES_RC_LENGTH]; // table of round constants
-+
-+#if defined(ONE_TABLE)
-+static u_int32_t ft_tab[256];
-+static u_int32_t it_tab[256];
-+#elif defined(FOUR_TABLES)
-+static u_int32_t ft_tab[4][256];
-+static u_int32_t it_tab[4][256];
-+#endif
-+
-+#if defined(ONE_LR_TABLE)
-+static u_int32_t fl_tab[256];
-+static u_int32_t il_tab[256];
-+#elif defined(FOUR_LR_TABLES)
-+static u_int32_t fl_tab[4][256];
-+static u_int32_t il_tab[4][256];
-+#endif
-+
-+#if defined(ONE_IM_TABLE)
-+static u_int32_t im_tab[256];
-+#elif defined(FOUR_IM_TABLES)
-+static u_int32_t im_tab[4][256];
-+#endif
-+
-+// Generate the tables for the dynamic table option
-+
-+#if !defined(FF_TABLES)
-+
-+// It will generally be sensible to use tables to compute finite
-+// field multiplies and inverses but where memory is scarse this
-+// code might sometimes be better.
-+
-+// return 2 ^ (n - 1) where n is the bit number of the highest bit
-+// set in x with x in the range 1 < x < 0x00000200. This form is
-+// used so that locals within FFinv can be bytes rather than words
-+
-+static unsigned char hibit(const u_int32_t x)
-+{ unsigned char r = (unsigned char)((x >> 1) | (x >> 2));
-+
-+ r |= (r >> 2);
-+ r |= (r >> 4);
-+ return (r + 1) >> 1;
-+}
-+
-+// return the inverse of the finite field element x
-+
-+static unsigned char FFinv(const unsigned char x)
-+{ unsigned char p1 = x, p2 = 0x1b, n1 = hibit(x), n2 = 0x80, v1 = 1, v2 = 0;
-+
-+ if(x < 2) return x;
-+
-+ for(;;)
-+ {
-+ if(!n1) return v1;
-+
-+ while(n2 >= n1)
-+ {
-+ n2 /= n1; p2 ^= p1 * n2; v2 ^= v1 * n2; n2 = hibit(p2);
-+ }
-+
-+ if(!n2) return v2;
-+
-+ while(n1 >= n2)
-+ {
-+ n1 /= n2; p1 ^= p2 * n1; v1 ^= v2 * n1; n1 = hibit(p1);
-+ }
-+ }
-+}
-+
-+// define the finite field multiplies required for Rijndael
-+
-+#define FFmul02(x) ((((x) & 0x7f) << 1) ^ ((x) & 0x80 ? 0x1b : 0))
-+#define FFmul03(x) ((x) ^ FFmul02(x))
-+#define FFmul09(x) ((x) ^ FFmul02(FFmul02(FFmul02(x))))
-+#define FFmul0b(x) ((x) ^ FFmul02((x) ^ FFmul02(FFmul02(x))))
-+#define FFmul0d(x) ((x) ^ FFmul02(FFmul02((x) ^ FFmul02(x))))
-+#define FFmul0e(x) FFmul02((x) ^ FFmul02((x) ^ FFmul02(x)))
-+
-+#else
-+
-+#define FFinv(x) ((x) ? pow[255 - log[x]]: 0)
-+
-+#define FFmul02(x) (x ? pow[log[x] + 0x19] : 0)
-+#define FFmul03(x) (x ? pow[log[x] + 0x01] : 0)
-+#define FFmul09(x) (x ? pow[log[x] + 0xc7] : 0)
-+#define FFmul0b(x) (x ? pow[log[x] + 0x68] : 0)
-+#define FFmul0d(x) (x ? pow[log[x] + 0xee] : 0)
-+#define FFmul0e(x) (x ? pow[log[x] + 0xdf] : 0)
-+
-+#endif
-+
-+// The forward and inverse affine transformations used in the S-box
-+
-+#define fwd_affine(x) \
-+ (w = (u_int32_t)x, w ^= (w<<1)^(w<<2)^(w<<3)^(w<<4), 0x63^(unsigned char)(w^(w>>8)))
-+
-+#define inv_affine(x) \
-+ (w = (u_int32_t)x, w = (w<<1)^(w<<3)^(w<<6), 0x05^(unsigned char)(w^(w>>8)))
-+
-+static void gen_tabs(void)
-+{ u_int32_t i, w;
-+
-+#if defined(FF_TABLES)
-+
-+ unsigned char pow[512], log[256];
-+
-+ // log and power tables for GF(2^8) finite field with
-+ // 0x011b as modular polynomial - the simplest primitive
-+ // root is 0x03, used here to generate the tables
-+
-+ i = 0; w = 1;
-+ do
-+ {
-+ pow[i] = (unsigned char)w;
-+ pow[i + 255] = (unsigned char)w;
-+ log[w] = (unsigned char)i++;
-+ w ^= (w << 1) ^ (w & ff_hi ? ff_poly : 0);
-+ }
-+ while (w != 1);
-+
-+#endif
-+
-+ for(i = 0, w = 1; i < AES_RC_LENGTH; ++i)
-+ {
-+ rcon_tab[i] = bytes2word(w, 0, 0, 0);
-+ w = (w << 1) ^ (w & ff_hi ? ff_poly : 0);
-+ }
-+
-+ for(i = 0; i < 256; ++i)
-+ { unsigned char b;
-+
-+ s_box[i] = b = fwd_affine(FFinv((unsigned char)i));
-+
-+ w = bytes2word(b, 0, 0, 0);
-+#if defined(ONE_LR_TABLE)
-+ fl_tab[i] = w;
-+#elif defined(FOUR_LR_TABLES)
-+ fl_tab[0][i] = w;
-+ fl_tab[1][i] = upr(w,1);
-+ fl_tab[2][i] = upr(w,2);
-+ fl_tab[3][i] = upr(w,3);
-+#endif
-+ w = bytes2word(FFmul02(b), b, b, FFmul03(b));
-+#if defined(ONE_TABLE)
-+ ft_tab[i] = w;
-+#elif defined(FOUR_TABLES)
-+ ft_tab[0][i] = w;
-+ ft_tab[1][i] = upr(w,1);
-+ ft_tab[2][i] = upr(w,2);
-+ ft_tab[3][i] = upr(w,3);
-+#endif
-+ inv_s_box[i] = b = FFinv(inv_affine((unsigned char)i));
-+
-+ w = bytes2word(b, 0, 0, 0);
-+#if defined(ONE_LR_TABLE)
-+ il_tab[i] = w;
-+#elif defined(FOUR_LR_TABLES)
-+ il_tab[0][i] = w;
-+ il_tab[1][i] = upr(w,1);
-+ il_tab[2][i] = upr(w,2);
-+ il_tab[3][i] = upr(w,3);
-+#endif
-+ w = bytes2word(FFmul0e(b), FFmul09(b), FFmul0d(b), FFmul0b(b));
-+#if defined(ONE_TABLE)
-+ it_tab[i] = w;
-+#elif defined(FOUR_TABLES)
-+ it_tab[0][i] = w;
-+ it_tab[1][i] = upr(w,1);
-+ it_tab[2][i] = upr(w,2);
-+ it_tab[3][i] = upr(w,3);
-+#endif
-+#if defined(ONE_IM_TABLE)
-+ im_tab[b] = w;
-+#elif defined(FOUR_IM_TABLES)
-+ im_tab[0][b] = w;
-+ im_tab[1][b] = upr(w,1);
-+ im_tab[2][b] = upr(w,2);
-+ im_tab[3][b] = upr(w,3);
-+#endif
-+
-+ }
-+}
-+
-+#endif
-+
-+#define no_table(x,box,vf,rf,c) bytes2word( \
-+ box[bval(vf(x,0,c),rf(0,c))], \
-+ box[bval(vf(x,1,c),rf(1,c))], \
-+ box[bval(vf(x,2,c),rf(2,c))], \
-+ box[bval(vf(x,3,c),rf(3,c))])
-+
-+#define one_table(x,op,tab,vf,rf,c) \
-+ ( tab[bval(vf(x,0,c),rf(0,c))] \
-+ ^ op(tab[bval(vf(x,1,c),rf(1,c))],1) \
-+ ^ op(tab[bval(vf(x,2,c),rf(2,c))],2) \
-+ ^ op(tab[bval(vf(x,3,c),rf(3,c))],3))
-+
-+#define four_tables(x,tab,vf,rf,c) \
-+ ( tab[0][bval(vf(x,0,c),rf(0,c))] \
-+ ^ tab[1][bval(vf(x,1,c),rf(1,c))] \
-+ ^ tab[2][bval(vf(x,2,c),rf(2,c))] \
-+ ^ tab[3][bval(vf(x,3,c),rf(3,c))])
-+
-+#define vf1(x,r,c) (x)
-+#define rf1(r,c) (r)
-+#define rf2(r,c) ((r-c)&3)
-+
-+#if defined(FOUR_LR_TABLES)
-+#define ls_box(x,c) four_tables(x,fl_tab,vf1,rf2,c)
-+#elif defined(ONE_LR_TABLE)
-+#define ls_box(x,c) one_table(x,upr,fl_tab,vf1,rf2,c)
-+#else
-+#define ls_box(x,c) no_table(x,s_box,vf1,rf2,c)
-+#endif
-+
-+#if defined(FOUR_IM_TABLES)
-+#define inv_mcol(x) four_tables(x,im_tab,vf1,rf1,0)
-+#elif defined(ONE_IM_TABLE)
-+#define inv_mcol(x) one_table(x,upr,im_tab,vf1,rf1,0)
-+#else
-+#define inv_mcol(x) \
-+ (f9 = (x),f2 = FFmulX(f9), f4 = FFmulX(f2), f8 = FFmulX(f4), f9 ^= f8, \
-+ f2 ^= f4 ^ f8 ^ upr(f2 ^ f9,3) ^ upr(f4 ^ f9,2) ^ upr(f9,1))
-+#endif
-+
-+// Subroutine to set the block size (if variable) in bytes, legal
-+// values being 16, 24 and 32.
-+
-+#if defined(AES_BLOCK_SIZE)
-+#define nc (AES_BLOCK_SIZE / 4)
-+#else
-+#define nc (cx->aes_Ncol)
-+
-+void aes_set_blk(aes_context *cx, int n_bytes)
-+{
-+#if !defined(FIXED_TABLES)
-+ if(!tab_gen) { gen_tabs(); tab_gen = 1; }
-+#endif
-+
-+ switch(n_bytes) {
-+ case 32: /* bytes */
-+ case 256: /* bits */
-+ nc = 8;
-+ break;
-+ case 24: /* bytes */
-+ case 192: /* bits */
-+ nc = 6;
-+ break;
-+ case 16: /* bytes */
-+ case 128: /* bits */
-+ default:
-+ nc = 4;
-+ break;
-+ }
-+}
-+
-+#endif
-+
-+// Initialise the key schedule from the user supplied key. The key
-+// length is now specified in bytes - 16, 24 or 32 as appropriate.
-+// This corresponds to bit lengths of 128, 192 and 256 bits, and
-+// to Nk values of 4, 6 and 8 respectively.
-+
-+#define mx(t,f) (*t++ = inv_mcol(*f),f++)
-+#define cp(t,f) *t++ = *f++
-+
-+#if AES_BLOCK_SIZE == 16
-+#define cpy(d,s) cp(d,s); cp(d,s); cp(d,s); cp(d,s)
-+#define mix(d,s) mx(d,s); mx(d,s); mx(d,s); mx(d,s)
-+#elif AES_BLOCK_SIZE == 24
-+#define cpy(d,s) cp(d,s); cp(d,s); cp(d,s); cp(d,s); \
-+ cp(d,s); cp(d,s)
-+#define mix(d,s) mx(d,s); mx(d,s); mx(d,s); mx(d,s); \
-+ mx(d,s); mx(d,s)
-+#elif AES_BLOCK_SIZE == 32
-+#define cpy(d,s) cp(d,s); cp(d,s); cp(d,s); cp(d,s); \
-+ cp(d,s); cp(d,s); cp(d,s); cp(d,s)
-+#define mix(d,s) mx(d,s); mx(d,s); mx(d,s); mx(d,s); \
-+ mx(d,s); mx(d,s); mx(d,s); mx(d,s)
-+#else
-+
-+#define cpy(d,s) \
-+switch(nc) \
-+{ case 8: cp(d,s); cp(d,s); \
-+ case 6: cp(d,s); cp(d,s); \
-+ case 4: cp(d,s); cp(d,s); \
-+ cp(d,s); cp(d,s); \
-+}
-+
-+#define mix(d,s) \
-+switch(nc) \
-+{ case 8: mx(d,s); mx(d,s); \
-+ case 6: mx(d,s); mx(d,s); \
-+ case 4: mx(d,s); mx(d,s); \
-+ mx(d,s); mx(d,s); \
-+}
-+
-+#endif
-+
-+void aes_set_key(aes_context *cx, const unsigned char in_key[], int n_bytes, const int f)
-+{ u_int32_t *kf, *kt, rci;
-+
-+#if !defined(FIXED_TABLES)
-+ if(!tab_gen) { gen_tabs(); tab_gen = 1; }
-+#endif
-+
-+ switch(n_bytes) {
-+ case 32: /* bytes */
-+ case 256: /* bits */
-+ cx->aes_Nkey = 8;
-+ break;
-+ case 24: /* bytes */
-+ case 192: /* bits */
-+ cx->aes_Nkey = 6;
-+ break;
-+ case 16: /* bytes */
-+ case 128: /* bits */
-+ default:
-+ cx->aes_Nkey = 4;
-+ break;
-+ }
-+
-+ cx->aes_Nrnd = (cx->aes_Nkey > nc ? cx->aes_Nkey : nc) + 6;
-+
-+ cx->aes_e_key[0] = const_word_in(in_key );
-+ cx->aes_e_key[1] = const_word_in(in_key + 4);
-+ cx->aes_e_key[2] = const_word_in(in_key + 8);
-+ cx->aes_e_key[3] = const_word_in(in_key + 12);
-+
-+ kf = cx->aes_e_key;
-+ kt = kf + nc * (cx->aes_Nrnd + 1) - cx->aes_Nkey;
-+ rci = 0;
-+
-+ switch(cx->aes_Nkey)
-+ {
-+ case 4: do
-+ { kf[4] = kf[0] ^ ls_box(kf[3],3) ^ rcon_tab[rci++];
-+ kf[5] = kf[1] ^ kf[4];
-+ kf[6] = kf[2] ^ kf[5];
-+ kf[7] = kf[3] ^ kf[6];
-+ kf += 4;
-+ }
-+ while(kf < kt);
-+ break;
-+
-+ case 6: cx->aes_e_key[4] = const_word_in(in_key + 16);
-+ cx->aes_e_key[5] = const_word_in(in_key + 20);
-+ do
-+ { kf[ 6] = kf[0] ^ ls_box(kf[5],3) ^ rcon_tab[rci++];
-+ kf[ 7] = kf[1] ^ kf[ 6];
-+ kf[ 8] = kf[2] ^ kf[ 7];
-+ kf[ 9] = kf[3] ^ kf[ 8];
-+ kf[10] = kf[4] ^ kf[ 9];
-+ kf[11] = kf[5] ^ kf[10];
-+ kf += 6;
-+ }
-+ while(kf < kt);
-+ break;
-+
-+ case 8: cx->aes_e_key[4] = const_word_in(in_key + 16);
-+ cx->aes_e_key[5] = const_word_in(in_key + 20);
-+ cx->aes_e_key[6] = const_word_in(in_key + 24);
-+ cx->aes_e_key[7] = const_word_in(in_key + 28);
-+ do
-+ { kf[ 8] = kf[0] ^ ls_box(kf[7],3) ^ rcon_tab[rci++];
-+ kf[ 9] = kf[1] ^ kf[ 8];
-+ kf[10] = kf[2] ^ kf[ 9];
-+ kf[11] = kf[3] ^ kf[10];
-+ kf[12] = kf[4] ^ ls_box(kf[11],0);
-+ kf[13] = kf[5] ^ kf[12];
-+ kf[14] = kf[6] ^ kf[13];
-+ kf[15] = kf[7] ^ kf[14];
-+ kf += 8;
-+ }
-+ while (kf < kt);
-+ break;
-+ }
-+
-+ if(!f)
-+ { u_int32_t i;
-+
-+ kt = cx->aes_d_key + nc * cx->aes_Nrnd;
-+ kf = cx->aes_e_key;
-+
-+ cpy(kt, kf); kt -= 2 * nc;
-+
-+ for(i = 1; i < cx->aes_Nrnd; ++i)
-+ {
-+#if defined(ONE_TABLE) || defined(FOUR_TABLES)
-+#if !defined(ONE_IM_TABLE) && !defined(FOUR_IM_TABLES)
-+ u_int32_t f2, f4, f8, f9;
-+#endif
-+ mix(kt, kf);
-+#else
-+ cpy(kt, kf);
-+#endif
-+ kt -= 2 * nc;
-+ }
-+
-+ cpy(kt, kf);
-+ }
-+}
-+
-+// y = output word, x = input word, r = row, c = column
-+// for r = 0, 1, 2 and 3 = column accessed for row r
-+
-+#if defined(ARRAYS)
-+#define s(x,c) x[c]
-+#else
-+#define s(x,c) x##c
-+#endif
-+
-+// I am grateful to Frank Yellin for the following constructions
-+// which, given the column (c) of the output state variable that
-+// is being computed, return the input state variables which are
-+// needed for each row (r) of the state
-+
-+// For the fixed block size options, compilers reduce these two
-+// expressions to fixed variable references. For variable block
-+// size code conditional clauses will sometimes be returned
-+
-+#define unused 77 // Sunset Strip
-+
-+#define fwd_var(x,r,c) \
-+ ( r==0 ? \
-+ ( c==0 ? s(x,0) \
-+ : c==1 ? s(x,1) \
-+ : c==2 ? s(x,2) \
-+ : c==3 ? s(x,3) \
-+ : c==4 ? s(x,4) \
-+ : c==5 ? s(x,5) \
-+ : c==6 ? s(x,6) \
-+ : s(x,7)) \
-+ : r==1 ? \
-+ ( c==0 ? s(x,1) \
-+ : c==1 ? s(x,2) \
-+ : c==2 ? s(x,3) \
-+ : c==3 ? nc==4 ? s(x,0) : s(x,4) \
-+ : c==4 ? s(x,5) \
-+ : c==5 ? nc==8 ? s(x,6) : s(x,0) \
-+ : c==6 ? s(x,7) \
-+ : s(x,0)) \
-+ : r==2 ? \
-+ ( c==0 ? nc==8 ? s(x,3) : s(x,2) \
-+ : c==1 ? nc==8 ? s(x,4) : s(x,3) \
-+ : c==2 ? nc==4 ? s(x,0) : nc==8 ? s(x,5) : s(x,4) \
-+ : c==3 ? nc==4 ? s(x,1) : nc==8 ? s(x,6) : s(x,5) \
-+ : c==4 ? nc==8 ? s(x,7) : s(x,0) \
-+ : c==5 ? nc==8 ? s(x,0) : s(x,1) \
-+ : c==6 ? s(x,1) \
-+ : s(x,2)) \
-+ : \
-+ ( c==0 ? nc==8 ? s(x,4) : s(x,3) \
-+ : c==1 ? nc==4 ? s(x,0) : nc==8 ? s(x,5) : s(x,4) \
-+ : c==2 ? nc==4 ? s(x,1) : nc==8 ? s(x,6) : s(x,5) \
-+ : c==3 ? nc==4 ? s(x,2) : nc==8 ? s(x,7) : s(x,0) \
-+ : c==4 ? nc==8 ? s(x,0) : s(x,1) \
-+ : c==5 ? nc==8 ? s(x,1) : s(x,2) \
-+ : c==6 ? s(x,2) \
-+ : s(x,3)))
-+
-+#define inv_var(x,r,c) \
-+ ( r==0 ? \
-+ ( c==0 ? s(x,0) \
-+ : c==1 ? s(x,1) \
-+ : c==2 ? s(x,2) \
-+ : c==3 ? s(x,3) \
-+ : c==4 ? s(x,4) \
-+ : c==5 ? s(x,5) \
-+ : c==6 ? s(x,6) \
-+ : s(x,7)) \
-+ : r==1 ? \
-+ ( c==0 ? nc==4 ? s(x,3) : nc==8 ? s(x,7) : s(x,5) \
-+ : c==1 ? s(x,0) \
-+ : c==2 ? s(x,1) \
-+ : c==3 ? s(x,2) \
-+ : c==4 ? s(x,3) \
-+ : c==5 ? s(x,4) \
-+ : c==6 ? s(x,5) \
-+ : s(x,6)) \
-+ : r==2 ? \
-+ ( c==0 ? nc==4 ? s(x,2) : nc==8 ? s(x,5) : s(x,4) \
-+ : c==1 ? nc==4 ? s(x,3) : nc==8 ? s(x,6) : s(x,5) \
-+ : c==2 ? nc==8 ? s(x,7) : s(x,0) \
-+ : c==3 ? nc==8 ? s(x,0) : s(x,1) \
-+ : c==4 ? nc==8 ? s(x,1) : s(x,2) \
-+ : c==5 ? nc==8 ? s(x,2) : s(x,3) \
-+ : c==6 ? s(x,3) \
-+ : s(x,4)) \
-+ : \
-+ ( c==0 ? nc==4 ? s(x,1) : nc==8 ? s(x,4) : s(x,3) \
-+ : c==1 ? nc==4 ? s(x,2) : nc==8 ? s(x,5) : s(x,4) \
-+ : c==2 ? nc==4 ? s(x,3) : nc==8 ? s(x,6) : s(x,5) \
-+ : c==3 ? nc==8 ? s(x,7) : s(x,0) \
-+ : c==4 ? nc==8 ? s(x,0) : s(x,1) \
-+ : c==5 ? nc==8 ? s(x,1) : s(x,2) \
-+ : c==6 ? s(x,2) \
-+ : s(x,3)))
-+
-+#define si(y,x,k,c) s(y,c) = const_word_in(x + 4 * c) ^ k[c]
-+#define so(y,x,c) word_out(y + 4 * c, s(x,c))
-+
-+#if defined(FOUR_TABLES)
-+#define fwd_rnd(y,x,k,c) s(y,c)= (k)[c] ^ four_tables(x,ft_tab,fwd_var,rf1,c)
-+#define inv_rnd(y,x,k,c) s(y,c)= (k)[c] ^ four_tables(x,it_tab,inv_var,rf1,c)
-+#elif defined(ONE_TABLE)
-+#define fwd_rnd(y,x,k,c) s(y,c)= (k)[c] ^ one_table(x,upr,ft_tab,fwd_var,rf1,c)
-+#define inv_rnd(y,x,k,c) s(y,c)= (k)[c] ^ one_table(x,upr,it_tab,inv_var,rf1,c)
-+#else
-+#define fwd_rnd(y,x,k,c) s(y,c) = fwd_mcol(no_table(x,s_box,fwd_var,rf1,c)) ^ (k)[c]
-+#define inv_rnd(y,x,k,c) s(y,c) = inv_mcol(no_table(x,inv_s_box,inv_var,rf1,c) ^ (k)[c])
-+#endif
-+
-+#if defined(FOUR_LR_TABLES)
-+#define fwd_lrnd(y,x,k,c) s(y,c)= (k)[c] ^ four_tables(x,fl_tab,fwd_var,rf1,c)
-+#define inv_lrnd(y,x,k,c) s(y,c)= (k)[c] ^ four_tables(x,il_tab,inv_var,rf1,c)
-+#elif defined(ONE_LR_TABLE)
-+#define fwd_lrnd(y,x,k,c) s(y,c)= (k)[c] ^ one_table(x,ups,fl_tab,fwd_var,rf1,c)
-+#define inv_lrnd(y,x,k,c) s(y,c)= (k)[c] ^ one_table(x,ups,il_tab,inv_var,rf1,c)
-+#else
-+#define fwd_lrnd(y,x,k,c) s(y,c) = no_table(x,s_box,fwd_var,rf1,c) ^ (k)[c]
-+#define inv_lrnd(y,x,k,c) s(y,c) = no_table(x,inv_s_box,inv_var,rf1,c) ^ (k)[c]
-+#endif
-+
-+#if AES_BLOCK_SIZE == 16
-+
-+#if defined(ARRAYS)
-+#define locals(y,x) x[4],y[4]
-+#else
-+#define locals(y,x) x##0,x##1,x##2,x##3,y##0,y##1,y##2,y##3
-+// the following defines prevent the compiler requiring the declaration
-+// of generated but unused variables in the fwd_var and inv_var macros
-+#define b04 unused
-+#define b05 unused
-+#define b06 unused
-+#define b07 unused
-+#define b14 unused
-+#define b15 unused
-+#define b16 unused
-+#define b17 unused
-+#endif
-+#define l_copy(y, x) s(y,0) = s(x,0); s(y,1) = s(x,1); \
-+ s(y,2) = s(x,2); s(y,3) = s(x,3);
-+#define state_in(y,x,k) si(y,x,k,0); si(y,x,k,1); si(y,x,k,2); si(y,x,k,3)
-+#define state_out(y,x) so(y,x,0); so(y,x,1); so(y,x,2); so(y,x,3)
-+#define round(rm,y,x,k) rm(y,x,k,0); rm(y,x,k,1); rm(y,x,k,2); rm(y,x,k,3)
-+
-+#elif AES_BLOCK_SIZE == 24
-+
-+#if defined(ARRAYS)
-+#define locals(y,x) x[6],y[6]
-+#else
-+#define locals(y,x) x##0,x##1,x##2,x##3,x##4,x##5, \
-+ y##0,y##1,y##2,y##3,y##4,y##5
-+#define b06 unused
-+#define b07 unused
-+#define b16 unused
-+#define b17 unused
-+#endif
-+#define l_copy(y, x) s(y,0) = s(x,0); s(y,1) = s(x,1); \
-+ s(y,2) = s(x,2); s(y,3) = s(x,3); \
-+ s(y,4) = s(x,4); s(y,5) = s(x,5);
-+#define state_in(y,x,k) si(y,x,k,0); si(y,x,k,1); si(y,x,k,2); \
-+ si(y,x,k,3); si(y,x,k,4); si(y,x,k,5)
-+#define state_out(y,x) so(y,x,0); so(y,x,1); so(y,x,2); \
-+ so(y,x,3); so(y,x,4); so(y,x,5)
-+#define round(rm,y,x,k) rm(y,x,k,0); rm(y,x,k,1); rm(y,x,k,2); \
-+ rm(y,x,k,3); rm(y,x,k,4); rm(y,x,k,5)
-+#else
-+
-+#if defined(ARRAYS)
-+#define locals(y,x) x[8],y[8]
-+#else
-+#define locals(y,x) x##0,x##1,x##2,x##3,x##4,x##5,x##6,x##7, \
-+ y##0,y##1,y##2,y##3,y##4,y##5,y##6,y##7
-+#endif
-+#define l_copy(y, x) s(y,0) = s(x,0); s(y,1) = s(x,1); \
-+ s(y,2) = s(x,2); s(y,3) = s(x,3); \
-+ s(y,4) = s(x,4); s(y,5) = s(x,5); \
-+ s(y,6) = s(x,6); s(y,7) = s(x,7);
-+
-+#if AES_BLOCK_SIZE == 32
-+
-+#define state_in(y,x,k) si(y,x,k,0); si(y,x,k,1); si(y,x,k,2); si(y,x,k,3); \
-+ si(y,x,k,4); si(y,x,k,5); si(y,x,k,6); si(y,x,k,7)
-+#define state_out(y,x) so(y,x,0); so(y,x,1); so(y,x,2); so(y,x,3); \
-+ so(y,x,4); so(y,x,5); so(y,x,6); so(y,x,7)
-+#define round(rm,y,x,k) rm(y,x,k,0); rm(y,x,k,1); rm(y,x,k,2); rm(y,x,k,3); \
-+ rm(y,x,k,4); rm(y,x,k,5); rm(y,x,k,6); rm(y,x,k,7)
-+#else
-+
-+#define state_in(y,x,k) \
-+switch(nc) \
-+{ case 8: si(y,x,k,7); si(y,x,k,6); \
-+ case 6: si(y,x,k,5); si(y,x,k,4); \
-+ case 4: si(y,x,k,3); si(y,x,k,2); \
-+ si(y,x,k,1); si(y,x,k,0); \
-+}
-+
-+#define state_out(y,x) \
-+switch(nc) \
-+{ case 8: so(y,x,7); so(y,x,6); \
-+ case 6: so(y,x,5); so(y,x,4); \
-+ case 4: so(y,x,3); so(y,x,2); \
-+ so(y,x,1); so(y,x,0); \
-+}
-+
-+#if defined(FAST_VARIABLE)
-+
-+#define round(rm,y,x,k) \
-+switch(nc) \
-+{ case 8: rm(y,x,k,7); rm(y,x,k,6); \
-+ rm(y,x,k,5); rm(y,x,k,4); \
-+ rm(y,x,k,3); rm(y,x,k,2); \
-+ rm(y,x,k,1); rm(y,x,k,0); \
-+ break; \
-+ case 6: rm(y,x,k,5); rm(y,x,k,4); \
-+ rm(y,x,k,3); rm(y,x,k,2); \
-+ rm(y,x,k,1); rm(y,x,k,0); \
-+ break; \
-+ case 4: rm(y,x,k,3); rm(y,x,k,2); \
-+ rm(y,x,k,1); rm(y,x,k,0); \
-+ break; \
-+}
-+#else
-+
-+#define round(rm,y,x,k) \
-+switch(nc) \
-+{ case 8: rm(y,x,k,7); rm(y,x,k,6); \
-+ case 6: rm(y,x,k,5); rm(y,x,k,4); \
-+ case 4: rm(y,x,k,3); rm(y,x,k,2); \
-+ rm(y,x,k,1); rm(y,x,k,0); \
-+}
-+
-+#endif
-+
-+#endif
-+#endif
-+
-+void aes_encrypt(const aes_context *cx, const unsigned char in_blk[], unsigned char out_blk[])
-+{ u_int32_t locals(b0, b1);
-+ const u_int32_t *kp = cx->aes_e_key;
-+
-+#if !defined(ONE_TABLE) && !defined(FOUR_TABLES)
-+ u_int32_t f2;
-+#endif
-+
-+ state_in(b0, in_blk, kp); kp += nc;
-+
-+#if defined(UNROLL)
-+
-+ switch(cx->aes_Nrnd)
-+ {
-+ case 14: round(fwd_rnd, b1, b0, kp );
-+ round(fwd_rnd, b0, b1, kp + nc ); kp += 2 * nc;
-+ case 12: round(fwd_rnd, b1, b0, kp );
-+ round(fwd_rnd, b0, b1, kp + nc ); kp += 2 * nc;
-+ case 10: round(fwd_rnd, b1, b0, kp );
-+ round(fwd_rnd, b0, b1, kp + nc);
-+ round(fwd_rnd, b1, b0, kp + 2 * nc);
-+ round(fwd_rnd, b0, b1, kp + 3 * nc);
-+ round(fwd_rnd, b1, b0, kp + 4 * nc);
-+ round(fwd_rnd, b0, b1, kp + 5 * nc);
-+ round(fwd_rnd, b1, b0, kp + 6 * nc);
-+ round(fwd_rnd, b0, b1, kp + 7 * nc);
-+ round(fwd_rnd, b1, b0, kp + 8 * nc);
-+ round(fwd_lrnd, b0, b1, kp + 9 * nc);
-+ }
-+
-+#elif defined(PARTIAL_UNROLL)
-+ { u_int32_t rnd;
-+
-+ for(rnd = 0; rnd < (cx->aes_Nrnd >> 1) - 1; ++rnd)
-+ {
-+ round(fwd_rnd, b1, b0, kp);
-+ round(fwd_rnd, b0, b1, kp + nc); kp += 2 * nc;
-+ }
-+
-+ round(fwd_rnd, b1, b0, kp);
-+ round(fwd_lrnd, b0, b1, kp + nc);
-+ }
-+#else
-+ { u_int32_t rnd;
-+
-+ for(rnd = 0; rnd < cx->aes_Nrnd - 1; ++rnd)
-+ {
-+ round(fwd_rnd, b1, b0, kp);
-+ l_copy(b0, b1); kp += nc;
-+ }
-+
-+ round(fwd_lrnd, b0, b1, kp);
-+ }
-+#endif
-+
-+ state_out(out_blk, b0);
-+}
-+
-+void aes_decrypt(const aes_context *cx, const unsigned char in_blk[], unsigned char out_blk[])
-+{ u_int32_t locals(b0, b1);
-+ const u_int32_t *kp = cx->aes_d_key;
-+
-+#if !defined(ONE_TABLE) && !defined(FOUR_TABLES)
-+ u_int32_t f2, f4, f8, f9;
-+#endif
-+
-+ state_in(b0, in_blk, kp); kp += nc;
-+
-+#if defined(UNROLL)
-+
-+ switch(cx->aes_Nrnd)
-+ {
-+ case 14: round(inv_rnd, b1, b0, kp );
-+ round(inv_rnd, b0, b1, kp + nc ); kp += 2 * nc;
-+ case 12: round(inv_rnd, b1, b0, kp );
-+ round(inv_rnd, b0, b1, kp + nc ); kp += 2 * nc;
-+ case 10: round(inv_rnd, b1, b0, kp );
-+ round(inv_rnd, b0, b1, kp + nc);
-+ round(inv_rnd, b1, b0, kp + 2 * nc);
-+ round(inv_rnd, b0, b1, kp + 3 * nc);
-+ round(inv_rnd, b1, b0, kp + 4 * nc);
-+ round(inv_rnd, b0, b1, kp + 5 * nc);
-+ round(inv_rnd, b1, b0, kp + 6 * nc);
-+ round(inv_rnd, b0, b1, kp + 7 * nc);
-+ round(inv_rnd, b1, b0, kp + 8 * nc);
-+ round(inv_lrnd, b0, b1, kp + 9 * nc);
-+ }
-+
-+#elif defined(PARTIAL_UNROLL)
-+ { u_int32_t rnd;
-+
-+ for(rnd = 0; rnd < (cx->aes_Nrnd >> 1) - 1; ++rnd)
-+ {
-+ round(inv_rnd, b1, b0, kp);
-+ round(inv_rnd, b0, b1, kp + nc); kp += 2 * nc;
-+ }
-+
-+ round(inv_rnd, b1, b0, kp);
-+ round(inv_lrnd, b0, b1, kp + nc);
-+ }
-+#else
-+ { u_int32_t rnd;
-+
-+ for(rnd = 0; rnd < cx->aes_Nrnd - 1; ++rnd)
-+ {
-+ round(inv_rnd, b1, b0, kp);
-+ l_copy(b0, b1); kp += nc;
-+ }
-+
-+ round(inv_lrnd, b0, b1, kp);
-+ }
-+#endif
-+
-+ state_out(out_blk, b0);
-+}
---- /dev/null Tue Mar 11 13:02:56 2003
-+++ linux/crypto/ciphers/aes/aes_cbc.c Mon Feb 9 13:51:03 2004
-@@ -0,0 +1,43 @@
-+/*
-+// I retain copyright in this code but I encourage its free use provided
-+// that I don't carry any responsibility for the results. I am especially
-+// happy to see it used in free and open source software. If you do use
-+// it I would appreciate an acknowledgement of its origin in the code or
-+// the product that results and I would also appreciate knowing a little
-+// about the use to which it is being put. I am grateful to Frank Yellin
-+// for some ideas that are used in this implementation.
-+//
-+// Dr B. R. Gladman <brg@gladman.uk.net> 6th April 2001.
-+//
-+// This is an implementation of the AES encryption algorithm (Rijndael)
-+// designed by Joan Daemen and Vincent Rijmen. This version is designed
-+// to provide both fixed and dynamic block and key lengths and can also
-+// run with either big or little endian internal byte order (see aes.h).
-+// It inputs block and key lengths in bytes with the legal values being
-+// 16, 24 and 32.
-+*
-+*/
-+
-+#ifdef __KERNEL__
-+#include <linux/types.h>
-+#else
-+#include <sys/types.h>
-+#endif
-+#include "crypto/aes_cbc.h"
-+#include "crypto/cbc_generic.h"
-+
-+/* returns bool success */
-+int AES_set_key(aes_context *aes_ctx, const u_int8_t *key, int keysize) {
-+ aes_set_key(aes_ctx, key, keysize, 0);
-+ return 1;
-+}
-+CBC_IMPL_BLK16(AES_cbc_encrypt, aes_context, u_int8_t *, aes_encrypt, aes_decrypt);
-+
-+
-+/*
-+ * $Log: aes_cbc.c,v $
-+ * Revision 1.1 2004/04/06 02:48:12 mcr
-+ * pullup of AES cipher from alg-branch.
-+ *
-+ *
-+ */
---- /dev/null Tue Mar 11 13:02:56 2003
-+++ linux/crypto/ciphers/aes/aes_xcbc_mac.c Mon Feb 9 13:51:03 2004
-@@ -0,0 +1,67 @@
-+#ifdef __KERNEL__
-+#include <linux/types.h>
-+#include <linux/kernel.h>
-+#define DEBUG(x)
-+#else
-+#include <stdio.h>
-+#include <sys/types.h>
-+#define DEBUG(x) x
-+#endif
-+
-+#include "crypto/aes.h"
-+#include "crypto/aes_xcbc_mac.h"
-+
-+int AES_xcbc_mac_set_key(aes_context_mac *ctxm, const u_int8_t *key, int keylen)
-+{
-+ int ret=1;
-+ aes_block kn[3] = {
-+ { 0x01010101, 0x01010101, 0x01010101, 0x01010101 },
-+ { 0x02020202, 0x02020202, 0x02020202, 0x02020202 },
-+ { 0x03030303, 0x03030303, 0x03030303, 0x03030303 },
-+ };
-+ aes_set_key(&ctxm->ctx_k1, key, keylen, 0);
-+ aes_encrypt(&ctxm->ctx_k1, (u_int8_t *) kn[0], (u_int8_t *) kn[0]);
-+ aes_encrypt(&ctxm->ctx_k1, (u_int8_t *) kn[1], (u_int8_t *) ctxm->k2);
-+ aes_encrypt(&ctxm->ctx_k1, (u_int8_t *) kn[2], (u_int8_t *) ctxm->k3);
-+ aes_set_key(&ctxm->ctx_k1, (u_int8_t *) kn[0], 16, 0);
-+ return ret;
-+}
-+static void do_pad_xor(u_int8_t *out, const u_int8_t *in, int len) {
-+ int pos=0;
-+ for (pos=1; pos <= 16; pos++, in++, out++) {
-+ if (pos <= len)
-+ *out ^= *in;
-+ if (pos > len) {
-+ DEBUG(printf("put 0x80 at pos=%d\n", pos));
-+ *out ^= 0x80;
-+ break;
-+ }
-+ }
-+}
-+static void xor_block(aes_block res, const aes_block op) {
-+ res[0] ^= op[0];
-+ res[1] ^= op[1];
-+ res[2] ^= op[2];
-+ res[3] ^= op[3];
-+}
-+int AES_xcbc_mac_hash(const aes_context_mac *ctxm, const u_int8_t * in, int ilen, u_int8_t hash[16]) {
-+ int ret=ilen;
-+ u_int32_t out[4] = { 0, 0, 0, 0 };
-+ for (; ilen > 16 ; ilen-=16) {
-+ xor_block(out, (const u_int32_t*) &in[0]);
-+ aes_encrypt(&ctxm->ctx_k1, in, (u_int8_t *)&out[0]);
-+ in+=16;
-+ }
-+ do_pad_xor((u_int8_t *)&out, in, ilen);
-+ if (ilen==16) {
-+ DEBUG(printf("using k3\n"));
-+ xor_block(out, ctxm->k3);
-+ }
-+ else
-+ {
-+ DEBUG(printf("using k2\n"));
-+ xor_block(out, ctxm->k2);
-+ }
-+ aes_encrypt(&ctxm->ctx_k1, (u_int8_t *)out, hash);
-+ return ret;
-+}
---- /dev/null Tue Mar 11 13:02:56 2003
-+++ linux/crypto/ciphers/aes/test_main.c Mon Feb 9 13:51:03 2004
-@@ -0,0 +1,41 @@
-+#include <stdio.h>
-+#include <string.h>
-+#include <sys/types.h>
-+#include "aes_cbc.h"
-+#define AES_BLOCK_SIZE 16
-+#define KEY_SIZE 128 /* bits */
-+#define KEY "1234567890123456"
-+#define STR "hola guaso como estaisss ... 012"
-+#define STRSZ (sizeof(STR)-1)
-+
-+#define EMT_AESCBC_BLKLEN AES_BLOCK_SIZE
-+#define AES_CONTEXT_T aes_context
-+#define EMT_ESPAES_KEY_SZ 16
-+int pretty_print(const unsigned char *buf, int count) {
-+ int i=0;
-+ for (;i<count;i++) {
-+ if (i%8==0) putchar(' ');
-+ if (i%16==0) putchar('\n');
-+ printf ("%02hhx ", buf[i]);
-+ }
-+ putchar('\n');
-+ return i;
-+}
-+//#define SIZE STRSZ/2
-+#define SIZE STRSZ
-+int main() {
-+ int ret;
-+ char buf0[SIZE+1], buf1[SIZE+1];
-+ char IV[AES_BLOCK_SIZE]="\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0";
-+ aes_context ac;
-+ AES_set_key(&ac, KEY, KEY_SIZE);
-+ //pretty_print((char *)&ac.aes_e_key, sizeof(ac.aes_e_key));
-+ memset(buf0, 0, sizeof (buf0));
-+ memset(buf1, 0, sizeof (buf1));
-+ ret=AES_cbc_encrypt(&ac, STR, buf0, SIZE, IV, 1);
-+ pretty_print(buf0, SIZE);
-+ printf("size=%d ret=%d\n%s\n", SIZE, ret, buf0);
-+ ret=AES_cbc_encrypt(&ac, buf0, buf1, SIZE, IV, 0);
-+ printf("size=%d ret=%d\n%s\n", SIZE, ret, buf1);
-+ return 0;
-+}
---- /dev/null Tue Mar 11 13:02:56 2003
-+++ linux/crypto/ciphers/aes/test_main_mac.c Mon Feb 9 13:51:03 2004
-@@ -0,0 +1,30 @@
-+#include <stdio.h>
-+#include <sys/types.h>
-+#include <string.h>
-+#include "aes.h"
-+#include "aes_xcbc_mac.h"
-+#define STR "Hola guasssso c|mo estais ...012"
-+void print_hash(const __u8 *hash) {
-+ printf("%08x %08x %08x %08x\n",
-+ *(__u32*)(&hash[0]),
-+ *(__u32*)(&hash[4]),
-+ *(__u32*)(&hash[8]),
-+ *(__u32*)(&hash[12]));
-+}
-+int main(int argc, char *argv[]) {
-+ aes_block key= { 0xdeadbeef, 0xceedcaca, 0xcafebabe, 0xff010204 };
-+ __u8 hash[16];
-+ char *str = argv[1];
-+ aes_context_mac ctx;
-+ if (str==NULL) {
-+ fprintf(stderr, "pasame el str\n");
-+ return 255;
-+ }
-+ AES_xcbc_mac_set_key(&ctx, (__u8 *)&key, sizeof(key));
-+ AES_xcbc_mac_hash(&ctx, str, strlen(str), hash);
-+ print_hash(hash);
-+ str[2]='x';
-+ AES_xcbc_mac_hash(&ctx, str, strlen(str), hash);
-+ print_hash(hash);
-+ return 0;
-+}
---- /dev/null Tue Mar 11 13:02:56 2003
-+++ linux/crypto/ciphers/des/COPYRIGHT Mon Feb 9 13:51:03 2004
-@@ -0,0 +1,50 @@
-+Copyright (C) 1995-1997 Eric Young (eay@cryptsoft.com)
-+All rights reserved.
-+
-+This package is an DES implementation written by Eric Young (eay@cryptsoft.com).
-+The implementation was written so as to conform with MIT's libdes.
-+
-+This library is free for commercial and non-commercial use as long as
-+the following conditions are aheared to. The following conditions
-+apply to all code found in this distribution.
-+
-+Copyright remains Eric Young's, and as such any Copyright notices in
-+the code are not to be removed.
-+If this package is used in a product, Eric Young should be given attribution
-+as the author of that the SSL library. This can be in the form of a textual
-+message at program startup or in documentation (online or textual) provided
-+with the package.
-+
-+Redistribution and use in source and binary forms, with or without
-+modification, are permitted provided that the following conditions
-+are met:
-+1. Redistributions of source code must retain the copyright
-+ notice, this list of conditions and the following disclaimer.
-+2. Redistributions in binary form must reproduce the above copyright
-+ notice, this list of conditions and the following disclaimer in the
-+ documentation and/or other materials provided with the distribution.
-+3. All advertising materials mentioning features or use of this software
-+ must display the following acknowledgement:
-+ This product includes software developed by Eric Young (eay@cryptsoft.com)
-+
-+THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``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 OR CONTRIBUTORS 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.
-+
-+The license and distribution terms for any publically available version or
-+derivative of this code cannot be changed. i.e. this code cannot simply be
-+copied and put under another distrubution license
-+[including the GNU Public License.]
-+
-+The reason behind this being stated in this direct manner is past
-+experience in code simply being copied and the attribution removed
-+from it and then being distributed as part of other packages. This
-+implementation was a non-trivial and unpaid effort.
---- /dev/null Tue Mar 11 13:02:56 2003
-+++ linux/crypto/ciphers/des/INSTALL Mon Feb 9 13:51:03 2004
-@@ -0,0 +1,69 @@
-+Check the CC and CFLAGS lines in the makefile
-+
-+If your C library does not support the times(3) function, change the
-+#define TIMES to
-+#undef TIMES in speed.c
-+If it does, check the HZ value for the times(3) function.
-+If your system does not define CLK_TCK it will be assumed to
-+be 100.0.
-+
-+If possible use gcc v 2.7.?
-+Turn on the maximum optimising (normally '-O3 -fomit-frame-pointer' for gcc)
-+In recent times, some system compilers give better performace.
-+
-+type 'make'
-+
-+run './destest' to check things are ok.
-+run './rpw' to check the tty code for reading passwords works.
-+run './speed' to see how fast those optimisations make the library run :-)
-+run './des_opts' to determin the best compile time options.
-+
-+The output from des_opts should be put in the makefile options and des_enc.c
-+should be rebuilt. For 64 bit computers, do not use the DES_PTR option.
-+For the DEC Alpha, edit des.h and change DES_LONG to 'unsigned int'
-+and then you can use the 'DES_PTR' option.
-+
-+The file options.txt has the options listed for best speed on quite a
-+few systems. Look and the options (UNROLL, PTR, RISC2 etc) and then
-+turn on the relevent option in the Makefile
-+
-+There are some special Makefile targets that make life easier.
-+make cc - standard cc build
-+make gcc - standard gcc build
-+make x86-elf - x86 assembler (elf), linux-elf.
-+make x86-out - x86 assembler (a.out), FreeBSD
-+make x86-solaris- x86 assembler
-+make x86-bsdi - x86 assembler (a.out with primative assembler).
-+
-+If at all possible use the assembler (for Windows NT/95, use
-+asm/win32.obj to link with). The x86 assembler is very very fast.
-+
-+A make install will by default install
-+libdes.a in /usr/local/lib/libdes.a
-+des in /usr/local/bin/des
-+des_crypt.man in /usr/local/man/man3/des_crypt.3
-+des.man in /usr/local/man/man1/des.1
-+des.h in /usr/include/des.h
-+
-+des(1) should be compatible with sunOS's but I have been unable to
-+test it.
-+
-+These routines should compile on MSDOS, most 32bit and 64bit version
-+of Unix (BSD and SYSV) and VMS, without modification.
-+The only problems should be #include files that are in the wrong places.
-+
-+These routines can be compiled under MSDOS.
-+I have successfully encrypted files using des(1) under MSDOS and then
-+decrypted the files on a SparcStation.
-+I have been able to compile and test the routines with
-+Microsoft C v 5.1 and Turbo C v 2.0.
-+The code in this library is in no way optimised for the 16bit
-+operation of MSDOS.
-+
-+When building for glibc, ignore all of the above and just unpack into
-+glibc-1.??/des and then gmake as per normal.
-+
-+As a final note on performace. Certain CPUs like sparcs and Alpha often give
-+a %10 speed difference depending on the link order. It is rather anoying
-+when one program reports 'x' DES encrypts a second and another reports
-+'x*0.9' the speed.
---- /dev/null Tue Mar 11 13:02:56 2003
-+++ linux/crypto/ciphers/des/Makefile.objs Mon Feb 9 13:51:03 2004
-@@ -0,0 +1,20 @@
-+obj-$(CONFIG_IPSEC_ENC_3DES) += cbc_enc.o
-+#obj-$(CONFIG_IPSEC_ENC_3DES) += des_opts.o
-+obj-$(CONFIG_IPSEC_ENC_3DES) += ecb_enc.o
-+#obj-$(CONFIG_IPSEC_ENC_3DES) += fcrypt.o
-+obj-$(CONFIG_IPSEC_ENC_3DES) += set_key.o
-+
-+ifeq ($(strip ${SUBARCH}),)
-+SUBARCH:=${ARCH}
-+endif
-+
-+ifeq (${SUBARCH},i386)
-+obj-$(CONFIG_IPSEC_ENC_3DES) += dx86unix.o
-+else
-+obj-$(CONFIG_IPSEC_ENC_3DES) += des_enc.o
-+endif
-+
-+
-+
-+
-+
---- /dev/null Tue Mar 11 13:02:56 2003
-+++ linux/crypto/ciphers/des/README Mon Feb 9 13:51:03 2004
-@@ -0,0 +1,54 @@
-+
-+ libdes, Version 4.01 10-Jan-97
-+
-+ Copyright (c) 1997, Eric Young
-+ All rights reserved.
-+
-+ This program is free software; you can redistribute it and/or modify
-+ it under the terms specified in COPYRIGHT.
-+
-+--
-+The primary ftp site for this library is
-+ftp://ftp.psy.uq.oz.au/pub/Crypto/DES/libdes-x.xx.tar.gz
-+libdes is now also shipped with SSLeay. Primary ftp site of
-+ftp://ftp.psy.uq.oz.au/pub/Crypto/SSL/SSLeay-x.x.x.tar.gz
-+
-+The best way to build this library is to build it as part of SSLeay.
-+
-+This kit builds a DES encryption library and a DES encryption program.
-+It supports ecb, cbc, ofb, cfb, triple ecb, triple cbc, triple ofb,
-+triple cfb, desx, and MIT's pcbc encryption modes and also has a fast
-+implementation of crypt(3).
-+It contains support routines to read keys from a terminal,
-+generate a random key, generate a key from an arbitrary length string,
-+read/write encrypted data from/to a file descriptor.
-+
-+The implementation was written so as to conform with the manual entry
-+for the des_crypt(3) library routines from MIT's project Athena.
-+
-+destest should be run after compilation to test the des routines.
-+rpw should be run after compilation to test the read password routines.
-+The des program is a replacement for the sun des command. I believe it
-+conforms to the sun version.
-+
-+The Imakefile is setup for use in the kerberos distribution.
-+
-+These routines are best compiled with gcc or any other good
-+optimising compiler.
-+Just turn you optimiser up to the highest settings and run destest
-+after the build to make sure everything works.
-+
-+I believe these routines are close to the fastest and most portable DES
-+routines that use small lookup tables (4.5k) that are publicly available.
-+The fcrypt routine is faster than ufc's fcrypt (when compiling with
-+gcc2 -O2) on the sparc 2 (1410 vs 1270) but is not so good on other machines
-+(on a sun3/260 168 vs 336). It is a function of CPU on chip cache size.
-+[ 10-Jan-97 and a function of an incorrect speed testing program in
-+ ufc which gave much better test figures that reality ].
-+
-+It is worth noting that on sparc and Alpha CPUs, performance of the DES
-+library can vary by upto %10 due to the positioning of files after application
-+linkage.
-+
-+Eric Young (eay@cryptsoft.com)
-+
---- /dev/null Tue Mar 11 13:02:56 2003
-+++ linux/crypto/ciphers/des/README.freeswan Mon Feb 9 13:51:03 2004
-@@ -0,0 +1,33 @@
-+The only changes the FreeS/WAN project has made to libdes-lite 4.04b are:
-+
-+We #ifdef-ed the declaration of DES_LONG in des.h, so it's more efficient
-+on the Alpha, instead of just noting the issue in a comment.
-+
-+We #ifdef-ed out the des_options() function in ecb_enc.c, because we don't
-+use it, and its call to sprintf() can cause subtle difficulties when KLIPS
-+is built as a module (depending on details of Linux configuration options).
-+
-+We changed some instances of CC=$(CC) in the Makefile to CC='$(CC)' to make
-+it cope better with Linux kernel Makefile stupidities, and took out an
-+explicit CC=gcc (unwise on systems with strange compilers).
-+
-+We deleted some references to <stdio.h> and <stdlib.h>, and a declaration
-+of one function found only in the full libdes (not in libdes-lite), to
-+avoid dragging in bits of stdio/stdlib unnecessarily. (Our thanks to Hans
-+Schultz for spotting this and pointing out the fixes.)
-+
-+We deleted a couple of .obj files in the asm subdirectory, which appear to
-+have been included in the original library by accident.
-+
-+We have added an include of our Makefile.inc file, to permit overriding
-+things like choice of compiler (although the libdes Makefile would
-+probably need some work to make this effective).
-+
-+
-+
-+Note that Eric Young is no longer at the email address listed in these
-+files, and is (alas) no longer working on free crypto software.
-+
-+
-+
-+This file is RCSID $Id: README.freeswan,v 1.11 2002/04/24 07:36:37 mcr Exp $
---- /dev/null Tue Mar 11 13:02:56 2003
-+++ linux/crypto/ciphers/des/VERSION Mon Feb 9 13:51:03 2004
-@@ -0,0 +1,406 @@
-+Version 4.04
-+ Fixed a few tests in destest. Also added x86 assember for
-+ des_ncbc_encrypt() which is the standard cbc mode function.
-+ This makes a very very large performace difference.
-+ Ariel Glenn ariel@columbia.edu reports that the terminal
-+ 'turn echo off' can return (errno == EINVAL) under solaris
-+ when redirection is used. So I now catch that as well as ENOTTY.
-+
-+
-+Version 4.03
-+ Left a static out of enc_write.c, which caused to buffer to be
-+ continiously malloc()ed. Does anyone use these functions? I keep
-+ on feeling like removing them since I only had these in there
-+ for a version of kerberised login. Anyway, this was pointed out
-+ by Theo de Raadt <deraadt@cvs.openbsd.org>
-+ The 'n' bit ofb code was wrong, it was not shifting the shift
-+ register. It worked correctly for n == 64. Thanks to
-+ Gigi Ankeny <Gigi.Ankeny@Eng.Sun.COM> for pointing this one out.
-+
-+Version 4.02
-+ I was doing 'if (memcmp(weak_keys[i],key,sizeof(key)) == 0)'
-+ when checking for weak keys which is wrong :-(, pointed out by
-+ Markus F.X.J. Oberhumer <markus.oberhumer@jk.uni-linz.ac.at>.
-+
-+Version 4.01
-+ Even faster inner loop in the DES assembler for x86 and a modification
-+ for IP/FP which is faster on x86. Both of these changes are
-+ from Svend Olaf Mikkelsen <svolaf@inet.uni-c.dk>. His
-+ changes make the assembler run %40 faster on a pentium. This is just
-+ a case of getting the instruction sequence 'just right'.
-+ All credit to 'Svend' :-)
-+ Quite a few special x86 'make' targets.
-+ A libdes-l (lite) distribution.
-+
-+Version 4.00
-+ After a bit of a pause, I'll up the major version number since this
-+ is mostly a performace release. I've added x86 assembler and
-+ added more options for performance. A %28 speedup for gcc
-+ on a pentium and the assembler is a %50 speedup.
-+ MIPS CPU's, sparc and Alpha are the main CPU's with speedups.
-+ Run des_opts to work out which options should be used.
-+ DES_RISC1/DES_RISC2 use alternative inner loops which use
-+ more registers but should give speedups on any CPU that does
-+ dual issue (pentium). DES_UNROLL unrolls the inner loop,
-+ which costs in code size.
-+
-+Version 3.26
-+ I've finally removed one of the shifts in D_ENCRYPT. This
-+ meant I've changed the des_SPtrans table (spr.h), the set_key()
-+ function and some things in des_enc.c. This has definitly
-+ made things faster :-). I've known about this one for some
-+ time but I've been too lazy to follow it up :-).
-+ Noticed that in the D_ENCRYPT() macro, we can just do L^=(..)^(..)^..
-+ instead of L^=((..)|(..)|(..).. This should save a register at
-+ least.
-+ Assember for x86. The file to replace is des_enc.c, which is replaced
-+ by one of the assembler files found in asm. Look at des/asm/readme
-+ for more info.
-+
-+ /* Modification to fcrypt so it can be compiled to support
-+ HPUX 10.x's long password format, define -DLONGCRYPT to use this.
-+ Thanks to Jens Kupferschmidt <bt1cu@hpboot.rz.uni-leipzig.de>. */
-+
-+ SIGWINCH case put in des_read_passwd() so the function does not
-+ 'exit' if this function is recieved.
-+
-+Version 3.25 17/07/96
-+ Modified read_pwd.c so that stdin can be read if not a tty.
-+ Thanks to Jeff Barber <jeffb@issl.atl.hp.com> for the patches.
-+ des_init_random_number_generator() shortened due to VMS linker
-+ limits.
-+ Added RSA's DESX cbc mode. It is a form of cbc encryption, with 2
-+ 8 byte quantites xored before and after encryption.
-+ des_xcbc_encryption() - the name is funny to preserve the des_
-+ prefix on all functions.
-+
-+Version 3.24 20/04/96
-+ The DES_PTR macro option checked and used by SSLeay configuration
-+
-+Version 3.23 11/04/96
-+ Added DES_LONG. If defined to 'unsigned int' on the DEC Alpha,
-+ it gives a %20 speedup :-)
-+ Fixed the problem with des.pl under perl5. The patches were
-+ sent by Ed Kubaitis (ejk@uiuc.edu).
-+ if fcrypt.c, changed values to handle illegal salt values the way
-+ normal crypt() implementations do. Some programs apparently use
-+ them :-(. The patch was sent by Bjorn Gronvall <bg@sics.se>
-+
-+Version 3.22 29/11/95
-+ Bug in des(1), an error with the uuencoding stuff when the
-+ 'data' is small, thanks to Geoff Keating <keagchon@mehta.anu.edu.au>
-+ for the patch.
-+
-+Version 3.21 22/11/95
-+ After some emailing back and forth with
-+ Colin Plumb <colin@nyx10.cs.du.edu>, I've tweaked a few things
-+ and in a future version I will probably put in some of the
-+ optimisation he suggested for use with the DES_USE_PTR option.
-+ Extra routines from Mark Murray <mark@grondar.za> for use in
-+ freeBSD. They mostly involve random number generation for use
-+ with kerberos. They involve evil machine specific system calls
-+ etc so I would normally suggest pushing this stuff into the
-+ application and/or using RAND_seed()/RAND_bytes() if you are
-+ using this DES library as part of SSLeay.
-+ Redone the read_pw() function so that it is cleaner and
-+ supports termios, thanks to Sameer Parekh <sameer@c2.org>
-+ for the initial patches for this.
-+ Renamed 3ecb_encrypt() to ecb3_encrypt(). This has been
-+ done just to make things more consistent.
-+ I have also now added triple DES versions of cfb and ofb.
-+
-+Version 3.20
-+ Damn, Damn, Damn, as pointed out by Mike_Spreitzer.PARC@xerox.com,
-+ my des_random_seed() function was only copying 4 bytes of the
-+ passed seed into the init structure. It is now fixed to copy 8.
-+ My own suggestion is to used something like MD5 :-)
-+
-+Version 3.19
-+ While looking at my code one day, I though, why do I keep on
-+ calling des_encrypt(in,out,ks,enc) when every function that
-+ calls it has in and out the same. So I dropped the 'out'
-+ parameter, people should not be using this function.
-+
-+Version 3.18 30/08/95
-+ Fixed a few bit with the distribution and the filenames.
-+ 3.17 had been munged via a move to DOS and back again.
-+ NO CODE CHANGES
-+
-+Version 3.17 14/07/95
-+ Fixed ede3 cbc which I had broken in 3.16. I have also
-+ removed some unneeded variables in 7-8 of the routines.
-+
-+Version 3.16 26/06/95
-+ Added des_encrypt2() which does not use IP/FP, used by triple
-+ des routines. Tweaked things a bit elsewhere. %13 speedup on
-+ sparc and %6 on a R4400 for ede3 cbc mode.
-+
-+Version 3.15 06/06/95
-+ Added des_ncbc_encrypt(), it is des_cbc mode except that it is
-+ 'normal' and copies the new iv value back over the top of the
-+ passed parameter.
-+ CHANGED des_ede3_cbc_encrypt() so that it too now overwrites
-+ the iv. THIS WILL BREAK EXISTING CODE, but since this function
-+ only new, I feel I can change it, not so with des_cbc_encrypt :-(.
-+ I need to update the documentation.
-+
-+Version 3.14 31/05/95
-+ New release upon the world, as part of my SSL implementation.
-+ New copyright and usage stuff. Basically free for all to use
-+ as long as you say it came from me :-)
-+
-+Version 3.13 31/05/95
-+ A fix in speed.c, if HZ is not defined, I set it to 100.0
-+ which is reasonable for most unixes except SunOS 4.x.
-+ I now have a #ifdef sun but timing for SunOS 4.x looked very
-+ good :-(. At my last job where I used SunOS 4.x, it was
-+ defined to be 60.0 (look at the old INSTALL documentation), at
-+ the last release had it changed to 100.0 since I now work with
-+ Solaris2 and SVR4 boxes.
-+ Thanks to Rory Chisholm <rchishol@math.ethz.ch> for pointing this
-+ one out.
-+
-+Version 3.12 08/05/95
-+ As pointed out by The Crypt Keeper <tck@bend.UCSD.EDU>,
-+ my D_ENCRYPT macro in crypt() had an un-necessary variable.
-+ It has been removed.
-+
-+Version 3.11 03/05/95
-+ Added des_ede3_cbc_encrypt() which is cbc mode des with 3 keys
-+ and one iv. It is a standard and I needed it for my SSL code.
-+ It makes more sense to use this for triple DES than
-+ 3cbc_encrypt(). I have also added (or should I say tested :-)
-+ cfb64_encrypt() which is cfb64 but it will encrypt a partial
-+ number of bytes - 3 bytes in 3 bytes out. Again this is for
-+ my SSL library, as a form of encryption to use with SSL
-+ telnet.
-+
-+Version 3.10 22/03/95
-+ Fixed a bug in 3cbc_encrypt() :-(. When making repeated calls
-+ to cbc3_encrypt, the 2 iv values that were being returned to
-+ be used in the next call were reversed :-(.
-+ Many thanks to Bill Wade <wade@Stoner.COM> for pointing out
-+ this error.
-+
-+Version 3.09 01/02/95
-+ Fixed des_random_key to far more random, it was rather feeble
-+ with regards to picking the initial seed. The problem was
-+ pointed out by Olaf Kirch <okir@monad.swb.de>.
-+
-+Version 3.08 14/12/94
-+ Added Makefile.PL so libdes can be built into perl5.
-+ Changed des_locl.h so RAND is always defined.
-+
-+Version 3.07 05/12/94
-+ Added GNUmake and stuff so the library can be build with
-+ glibc.
-+
-+Version 3.06 30/08/94
-+ Added rpc_enc.c which contains _des_crypt. This is for use in
-+ secure_rpc v 4.0
-+ Finally fixed the cfb_enc problems.
-+ Fixed a few parameter parsing bugs in des (-3 and -b), thanks
-+ to Rob McMillan <R.McMillan@its.gu.edu.au>
-+
-+Version 3.05 21/04/94
-+ for unsigned long l; gcc does not produce ((l>>34) == 0)
-+ This causes bugs in cfb_enc.
-+ Thanks to Hadmut Danisch <danisch@ira.uka.de>
-+
-+Version 3.04 20/04/94
-+ Added a version number to des.c and libdes.a
-+
-+Version 3.03 12/01/94
-+ Fixed a bug in non zero iv in 3cbc_enc.
-+
-+Version 3.02 29/10/93
-+ I now work in a place where there are 6+ architectures and 14+
-+ OS versions :-).
-+ Fixed TERMIO definition so the most sys V boxes will work :-)
-+
-+Release upon comp.sources.misc
-+Version 3.01 08/10/93
-+ Added des_3cbc_encrypt()
-+
-+Version 3.00 07/10/93
-+ Fixed up documentation.
-+ quad_cksum definitely compatible with MIT's now.
-+
-+Version 2.30 24/08/93
-+ Triple DES now defaults to triple cbc but can do triple ecb
-+ with the -b flag.
-+ Fixed some MSDOS uuen/uudecoding problems, thanks to
-+ Added prototypes.
-+
-+Version 2.22 29/06/93
-+ Fixed a bug in des_is_weak_key() which stopped it working :-(
-+ thanks to engineering@MorningStar.Com.
-+
-+Version 2.21 03/06/93
-+ des(1) with no arguments gives quite a bit of help.
-+ Added -c (generate ckecksum) flag to des(1).
-+ Added -3 (triple DES) flag to des(1).
-+ Added cfb and ofb routines to the library.
-+
-+Version 2.20 11/03/93
-+ Added -u (uuencode) flag to des(1).
-+ I have been playing with byte order in quad_cksum to make it
-+ compatible with MIT's version. All I can say is avid this
-+ function if possible since MIT's output is endian dependent.
-+
-+Version 2.12 14/10/92
-+ Added MSDOS specific macro in ecb_encrypt which gives a %70
-+ speed up when the code is compiled with turbo C.
-+
-+Version 2.11 12/10/92
-+ Speedup in set_key (recoding of PC-1)
-+ I now do it in 47 simple operations, down from 60.
-+ Thanks to John Fletcher (john_fletcher@lccmail.ocf.llnl.gov)
-+ for motivating me to look for a faster system :-)
-+ The speedup is probably less that 1% but it is still 13
-+ instructions less :-).
-+
-+Version 2.10 06/10/92
-+ The code now works on the 64bit ETA10 and CRAY without modifications or
-+ #defines. I believe the code should work on any machine that
-+ defines long, int or short to be 8 bytes long.
-+ Thanks to Shabbir J. Safdar (shabby@mentor.cc.purdue.edu)
-+ for helping me fix the code to run on 64bit machines (he had
-+ access to an ETA10).
-+ Thanks also to John Fletcher <john_fletcher@lccmail.ocf.llnl.gov>
-+ for testing the routines on a CRAY.
-+ read_password.c has been renamed to read_passwd.c
-+ string_to_key.c has been renamed to string2key.c
-+
-+Version 2.00 14/09/92
-+ Made mods so that the library should work on 64bit CPU's.
-+ Removed all my uchar and ulong defs. To many different
-+ versions of unix define them in their header files in too many
-+ different combinations :-)
-+ IRIX - Sillicon Graphics mods (mostly in read_password.c).
-+ Thanks to Andrew Daviel (advax@erich.triumf.ca)
-+
-+Version 1.99 26/08/92
-+ Fixed a bug or 2 in enc_read.c
-+ Fixed a bug in enc_write.c
-+ Fixed a pseudo bug in fcrypt.c (very obscure).
-+
-+Version 1.98 31/07/92
-+ Support for the ETA10. This is a strange machine that defines
-+ longs and ints as 8 bytes and shorts as 4 bytes.
-+ Since I do evil things with long * that assume that they are 4
-+ bytes. Look in the Makefile for the option to compile for
-+ this machine. quad_cksum appears to have problems but I
-+ will don't have the time to fix it right now, and this is not
-+ a function that uses DES and so will not effect the main uses
-+ of the library.
-+
-+Version 1.97 20/05/92 eay
-+ Fixed the Imakefile and made some changes to des.h to fix some
-+ problems when building this package with Kerberos v 4.
-+
-+Version 1.96 18/05/92 eay
-+ Fixed a small bug in string_to_key() where problems could
-+ occur if des_check_key was set to true and the string
-+ generated a weak key.
-+
-+Patch2 posted to comp.sources.misc
-+Version 1.95 13/05/92 eay
-+ Added an alternative version of the D_ENCRYPT macro in
-+ ecb_encrypt and fcrypt. Depending on the compiler, one version or the
-+ other will be faster. This was inspired by
-+ Dana How <how@isl.stanford.edu>, and her pointers about doing the
-+ *(ulong *)((uchar *)ptr+(value&0xfc))
-+ vs
-+ ptr[value&0x3f]
-+ to stop the C compiler doing a <<2 to convert the long array index.
-+
-+Version 1.94 05/05/92 eay
-+ Fixed an incompatibility between my string_to_key and the MIT
-+ version. When the key is longer than 8 chars, I was wrapping
-+ with a different method. To use the old version, define
-+ OLD_STR_TO_KEY in the makefile. Thanks to
-+ viktor@newsu.shearson.com (Viktor Dukhovni).
-+
-+Version 1.93 28/04/92 eay
-+ Fixed the VMS mods so that echo is now turned off in
-+ read_password. Thanks again to brennan@coco.cchs.su.oz.AU.
-+ MSDOS support added. The routines can be compiled with
-+ Turbo C (v2.0) and MSC (v5.1). Make sure MSDOS is defined.
-+
-+Patch1 posted to comp.sources.misc
-+Version 1.92 13/04/92 eay
-+ Changed D_ENCRYPT so that the rotation of R occurs outside of
-+ the loop. This required rotating all the longs in sp.h (now
-+ called spr.h). Thanks to Richard Outerbridge <71755.204@CompuServe.COM>
-+ speed.c has been changed so it will work without SIGALRM. If
-+ times(3) is not present it will try to use ftime() instead.
-+
-+Version 1.91 08/04/92 eay
-+ Added -E/-D options to des(1) so it can use string_to_key.
-+ Added SVR4 mods suggested by witr@rwwa.COM
-+ Added VMS mods suggested by brennan@coco.cchs.su.oz.AU. If
-+ anyone knows how to turn of tty echo in VMS please tell me or
-+ implement it yourself :-).
-+ Changed FILE *IN/*OUT to *DES_IN/*DES_OUT since it appears VMS
-+ does not like IN/OUT being used.
-+
-+Libdes posted to comp.sources.misc
-+Version 1.9 24/03/92 eay
-+ Now contains a fast small crypt replacement.
-+ Added des(1) command.
-+ Added des_rw_mode so people can use cbc encryption with
-+ enc_read and enc_write.
-+
-+Version 1.8 15/10/91 eay
-+ Bug in cbc_cksum.
-+ Many thanks to Keith Reynolds (keithr@sco.COM) for pointing this
-+ one out.
-+
-+Version 1.7 24/09/91 eay
-+ Fixed set_key :-)
-+ set_key is 4 times faster and takes less space.
-+ There are a few minor changes that could be made.
-+
-+Version 1.6 19/09/1991 eay
-+ Finally go IP and FP finished.
-+ Now I need to fix set_key.
-+ This version is quite a bit faster that 1.51
-+
-+Version 1.52 15/06/1991 eay
-+ 20% speedup in ecb_encrypt by changing the E bit selection
-+ to use 2 32bit words. This also required modification of the
-+ sp table. There is still a way to speedup the IP and IP-1
-+ (hints from outer@sq.com) still working on this one :-(.
-+
-+Version 1.51 07/06/1991 eay
-+ Faster des_encrypt by loop unrolling
-+ Fixed bug in quad_cksum.c (thanks to hughes@logos.ucs.indiana.edu)
-+
-+Version 1.50 28/05/1991 eay
-+ Optimised the code a bit more for the sparc. I have improved the
-+ speed of the inner des_encrypt by speeding up the initial and
-+ final permutations.
-+
-+Version 1.40 23/10/1990 eay
-+ Fixed des_random_key, it did not produce a random key :-(
-+
-+Version 1.30 2/10/1990 eay
-+ Have made des_quad_cksum the same as MIT's, the full package
-+ should be compatible with MIT's
-+ Have tested on a DECstation 3100
-+ Still need to fix des_set_key (make it faster).
-+ Does des_cbc_encrypts at 70.5k/sec on a 3100.
-+
-+Version 1.20 18/09/1990 eay
-+ Fixed byte order dependencies.
-+ Fixed (I hope) all the word alignment problems.
-+ Speedup in des_ecb_encrypt.
-+
-+Version 1.10 11/09/1990 eay
-+ Added des_enc_read and des_enc_write.
-+ Still need to fix des_quad_cksum.
-+ Still need to document des_enc_read and des_enc_write.
-+
-+Version 1.00 27/08/1990 eay
-+
---- /dev/null Tue Mar 11 13:02:56 2003
-+++ linux/crypto/ciphers/des/asm/crypt586.pl Mon Feb 9 13:51:03 2004
-@@ -0,0 +1,204 @@
-+#!/usr/bin/perl
-+#
-+# The inner loop instruction sequence and the IP/FP modifications are from
-+# Svend Olaf Mikkelsen <svolaf@inet.uni-c.dk>
-+# I've added the stuff needed for crypt() but I've not worried about making
-+# things perfect.
-+#
-+
-+push(@INC,"perlasm","../../perlasm");
-+require "x86asm.pl";
-+
-+&asm_init($ARGV[0],"crypt586.pl");
-+
-+$L="edi";
-+$R="esi";
-+
-+&external_label("des_SPtrans");
-+&fcrypt_body("fcrypt_body");
-+&asm_finish();
-+
-+sub fcrypt_body
-+ {
-+ local($name,$do_ip)=@_;
-+
-+ &function_begin($name,"EXTRN _des_SPtrans:DWORD");
-+
-+ &comment("");
-+ &comment("Load the 2 words");
-+ $ks="ebp";
-+
-+ &xor( $L, $L);
-+ &xor( $R, $R);
-+ &mov($ks,&wparam(1));
-+
-+ &push(25); # add a variable
-+
-+ &set_label("start");
-+ for ($i=0; $i<16; $i+=2)
-+ {
-+ &comment("");
-+ &comment("Round $i");
-+ &D_ENCRYPT($i,$L,$R,$i*2,$ks,"des_SPtrans","eax","ebx","ecx","edx");
-+
-+ &comment("");
-+ &comment("Round ".sprintf("%d",$i+1));
-+ &D_ENCRYPT($i+1,$R,$L,($i+1)*2,$ks,"des_SPtrans","eax","ebx","ecx","edx");
-+ }
-+ &mov("ebx", &swtmp(0));
-+ &mov("eax", $L);
-+ &dec("ebx");
-+ &mov($L, $R);
-+ &mov($R, "eax");
-+ &mov(&swtmp(0), "ebx");
-+ &jnz(&label("start"));
-+
-+ &comment("");
-+ &comment("FP");
-+ &mov("edx",&wparam(0));
-+
-+ &FP_new($R,$L,"eax",3);
-+ &mov(&DWP(0,"edx","",0),"eax");
-+ &mov(&DWP(4,"edx","",0),$L);
-+
-+ &pop("ecx"); # remove variable
-+
-+ &function_end($name);
-+ }
-+
-+sub D_ENCRYPT
-+ {
-+ local($r,$L,$R,$S,$ks,$desSP,$u,$tmp1,$tmp2,$t)=@_;
-+
-+ &mov( $u, &wparam(2)); # 2
-+ &mov( $t, $R);
-+ &shr( $t, 16); # 1
-+ &mov( $tmp2, &wparam(3)); # 2
-+ &xor( $t, $R); # 1
-+
-+ &and( $u, $t); # 2
-+ &and( $t, $tmp2); # 2
-+
-+ &mov( $tmp1, $u);
-+ &shl( $tmp1, 16); # 1
-+ &mov( $tmp2, $t);
-+ &shl( $tmp2, 16); # 1
-+ &xor( $u, $tmp1); # 2
-+ &xor( $t, $tmp2); # 2
-+ &mov( $tmp1, &DWP(&n2a($S*4),$ks,"",0)); # 2
-+ &xor( $u, $tmp1);
-+ &mov( $tmp2, &DWP(&n2a(($S+1)*4),$ks,"",0)); # 2
-+ &xor( $u, $R);
-+ &xor( $t, $R);
-+ &xor( $t, $tmp2);
-+
-+ &and( $u, "0xfcfcfcfc" ); # 2
-+ &xor( $tmp1, $tmp1); # 1
-+ &and( $t, "0xcfcfcfcf" ); # 2
-+ &xor( $tmp2, $tmp2);
-+ &movb( &LB($tmp1), &LB($u) );
-+ &movb( &LB($tmp2), &HB($u) );
-+ &rotr( $t, 4 );
-+ &mov( $ks, &DWP(" $desSP",$tmp1,"",0));
-+ &movb( &LB($tmp1), &LB($t) );
-+ &xor( $L, $ks);
-+ &mov( $ks, &DWP("0x200+$desSP",$tmp2,"",0));
-+ &xor( $L, $ks);
-+ &movb( &LB($tmp2), &HB($t) );
-+ &shr( $u, 16);
-+ &mov( $ks, &DWP("0x100+$desSP",$tmp1,"",0));
-+ &xor( $L, $ks);
-+ &movb( &LB($tmp1), &HB($u) );
-+ &shr( $t, 16);
-+ &mov( $ks, &DWP("0x300+$desSP",$tmp2,"",0));
-+ &xor( $L, $ks);
-+ &mov( $ks, &wparam(1));
-+ &movb( &LB($tmp2), &HB($t) );
-+ &and( $u, "0xff" );
-+ &and( $t, "0xff" );
-+ &mov( $tmp1, &DWP("0x600+$desSP",$tmp1,"",0));
-+ &xor( $L, $tmp1);
-+ &mov( $tmp1, &DWP("0x700+$desSP",$tmp2,"",0));
-+ &xor( $L, $tmp1);
-+ &mov( $tmp1, &DWP("0x400+$desSP",$u,"",0));
-+ &xor( $L, $tmp1);
-+ &mov( $tmp1, &DWP("0x500+$desSP",$t,"",0));
-+ &xor( $L, $tmp1);
-+ }
-+
-+sub n2a
-+ {
-+ sprintf("%d",$_[0]);
-+ }
-+
-+# now has a side affect of rotating $a by $shift
-+sub R_PERM_OP
-+ {
-+ local($a,$b,$tt,$shift,$mask,$last)=@_;
-+
-+ &rotl( $a, $shift ) if ($shift != 0);
-+ &mov( $tt, $a );
-+ &xor( $a, $b );
-+ &and( $a, $mask );
-+ if ($notlast eq $b)
-+ {
-+ &xor( $b, $a );
-+ &xor( $tt, $a );
-+ }
-+ else
-+ {
-+ &xor( $tt, $a );
-+ &xor( $b, $a );
-+ }
-+ &comment("");
-+ }
-+
-+sub IP_new
-+ {
-+ local($l,$r,$tt,$lr)=@_;
-+
-+ &R_PERM_OP($l,$r,$tt, 4,"0xf0f0f0f0",$l);
-+ &R_PERM_OP($r,$tt,$l,20,"0xfff0000f",$l);
-+ &R_PERM_OP($l,$tt,$r,14,"0x33333333",$r);
-+ &R_PERM_OP($tt,$r,$l,22,"0x03fc03fc",$r);
-+ &R_PERM_OP($l,$r,$tt, 9,"0xaaaaaaaa",$r);
-+
-+ if ($lr != 3)
-+ {
-+ if (($lr-3) < 0)
-+ { &rotr($tt, 3-$lr); }
-+ else { &rotl($tt, $lr-3); }
-+ }
-+ if ($lr != 2)
-+ {
-+ if (($lr-2) < 0)
-+ { &rotr($r, 2-$lr); }
-+ else { &rotl($r, $lr-2); }
-+ }
-+ }
-+
-+sub FP_new
-+ {
-+ local($l,$r,$tt,$lr)=@_;
-+
-+ if ($lr != 2)
-+ {
-+ if (($lr-2) < 0)
-+ { &rotl($r, 2-$lr); }
-+ else { &rotr($r, $lr-2); }
-+ }
-+ if ($lr != 3)
-+ {
-+ if (($lr-3) < 0)
-+ { &rotl($l, 3-$lr); }
-+ else { &rotr($l, $lr-3); }
-+ }
-+
-+ &R_PERM_OP($l,$r,$tt, 0,"0xaaaaaaaa",$r);
-+ &R_PERM_OP($tt,$r,$l,23,"0x03fc03fc",$r);
-+ &R_PERM_OP($l,$r,$tt,10,"0x33333333",$l);
-+ &R_PERM_OP($r,$tt,$l,18,"0xfff0000f",$l);
-+ &R_PERM_OP($l,$tt,$r,12,"0xf0f0f0f0",$r);
-+ &rotr($tt , 4);
-+ }
-+
---- /dev/null Tue Mar 11 13:02:56 2003
-+++ linux/crypto/ciphers/des/asm/des-586.pl Mon Feb 9 13:51:03 2004
-@@ -0,0 +1,251 @@
-+#!/usr/bin/perl
-+#
-+# The inner loop instruction sequence and the IP/FP modifications are from
-+# Svend Olaf Mikkelsen <svolaf@inet.uni-c.dk>
-+#
-+
-+push(@INC,"perlasm","../../perlasm");
-+require "x86asm.pl";
-+require "cbc.pl";
-+require "desboth.pl";
-+
-+# base code is in microsft
-+# op dest, source
-+# format.
-+#
-+
-+&asm_init($ARGV[0],"des-586.pl");
-+
-+$L="edi";
-+$R="esi";
-+
-+&external_label("des_SPtrans");
-+&des_encrypt("des_encrypt",1);
-+&des_encrypt("des_encrypt2",0);
-+&des_encrypt3("des_encrypt3",1);
-+&des_encrypt3("des_decrypt3",0);
-+&cbc("des_ncbc_encrypt","des_encrypt","des_encrypt",0,4,5,3,5,-1);
-+&cbc("des_ede3_cbc_encrypt","des_encrypt3","des_decrypt3",0,6,7,3,4,5);
-+
-+&asm_finish();
-+
-+sub des_encrypt
-+ {
-+ local($name,$do_ip)=@_;
-+
-+ &function_begin_B($name,"EXTRN _des_SPtrans:DWORD");
-+
-+ &push("esi");
-+ &push("edi");
-+
-+ &comment("");
-+ &comment("Load the 2 words");
-+ $ks="ebp";
-+
-+ if ($do_ip)
-+ {
-+ &mov($R,&wparam(0));
-+ &xor( "ecx", "ecx" );
-+
-+ &push("ebx");
-+ &push("ebp");
-+
-+ &mov("eax",&DWP(0,$R,"",0));
-+ &mov("ebx",&wparam(2)); # get encrypt flag
-+ &mov($L,&DWP(4,$R,"",0));
-+ &comment("");
-+ &comment("IP");
-+ &IP_new("eax",$L,$R,3);
-+ }
-+ else
-+ {
-+ &mov("eax",&wparam(0));
-+ &xor( "ecx", "ecx" );
-+
-+ &push("ebx");
-+ &push("ebp");
-+
-+ &mov($R,&DWP(0,"eax","",0));
-+ &mov("ebx",&wparam(2)); # get encrypt flag
-+ &rotl($R,3);
-+ &mov($L,&DWP(4,"eax","",0));
-+ &rotl($L,3);
-+ }
-+
-+ &mov( $ks, &wparam(1) );
-+ &cmp("ebx","0");
-+ &je(&label("start_decrypt"));
-+
-+ for ($i=0; $i<16; $i+=2)
-+ {
-+ &comment("");
-+ &comment("Round $i");
-+ &D_ENCRYPT($i,$L,$R,$i*2,$ks,"des_SPtrans","eax","ebx","ecx","edx");
-+
-+ &comment("");
-+ &comment("Round ".sprintf("%d",$i+1));
-+ &D_ENCRYPT($i+1,$R,$L,($i+1)*2,$ks,"des_SPtrans","eax","ebx","ecx","edx");
-+ }
-+ &jmp(&label("end"));
-+
-+ &set_label("start_decrypt");
-+
-+ for ($i=15; $i>0; $i-=2)
-+ {
-+ &comment("");
-+ &comment("Round $i");
-+ &D_ENCRYPT(15-$i,$L,$R,$i*2,$ks,"des_SPtrans","eax","ebx","ecx","edx");
-+ &comment("");
-+ &comment("Round ".sprintf("%d",$i-1));
-+ &D_ENCRYPT(15-$i+1,$R,$L,($i-1)*2,$ks,"des_SPtrans","eax","ebx","ecx","edx");
-+ }
-+
-+ &set_label("end");
-+
-+ if ($do_ip)
-+ {
-+ &comment("");
-+ &comment("FP");
-+ &mov("edx",&wparam(0));
-+ &FP_new($L,$R,"eax",3);
-+
-+ &mov(&DWP(0,"edx","",0),"eax");
-+ &mov(&DWP(4,"edx","",0),$R);
-+ }
-+ else
-+ {
-+ &comment("");
-+ &comment("Fixup");
-+ &rotr($L,3); # r
-+ &mov("eax",&wparam(0));
-+ &rotr($R,3); # l
-+ &mov(&DWP(0,"eax","",0),$L);
-+ &mov(&DWP(4,"eax","",0),$R);
-+ }
-+
-+ &pop("ebp");
-+ &pop("ebx");
-+ &pop("edi");
-+ &pop("esi");
-+ &ret();
-+
-+ &function_end_B($name);
-+ }
-+
-+sub D_ENCRYPT
-+ {
-+ local($r,$L,$R,$S,$ks,$desSP,$u,$tmp1,$tmp2,$t)=@_;
-+
-+ &mov( $u, &DWP(&n2a($S*4),$ks,"",0));
-+ &xor( $tmp1, $tmp1);
-+ &mov( $t, &DWP(&n2a(($S+1)*4),$ks,"",0));
-+ &xor( $u, $R);
-+ &xor( $t, $R);
-+ &and( $u, "0xfcfcfcfc" );
-+ &and( $t, "0xcfcfcfcf" );
-+ &movb( &LB($tmp1), &LB($u) );
-+ &movb( &LB($tmp2), &HB($u) );
-+ &rotr( $t, 4 );
-+ &mov( $ks, &DWP(" $desSP",$tmp1,"",0));
-+ &movb( &LB($tmp1), &LB($t) );
-+ &xor( $L, $ks);
-+ &mov( $ks, &DWP("0x200+$desSP",$tmp2,"",0));
-+ &xor( $L, $ks); ######
-+ &movb( &LB($tmp2), &HB($t) );
-+ &shr( $u, 16);
-+ &mov( $ks, &DWP("0x100+$desSP",$tmp1,"",0));
-+ &xor( $L, $ks); ######
-+ &movb( &LB($tmp1), &HB($u) );
-+ &shr( $t, 16);
-+ &mov( $ks, &DWP("0x300+$desSP",$tmp2,"",0));
-+ &xor( $L, $ks);
-+ &mov( $ks, &wparam(1) );
-+ &movb( &LB($tmp2), &HB($t) );
-+ &and( $u, "0xff" );
-+ &and( $t, "0xff" );
-+ &mov( $tmp1, &DWP("0x600+$desSP",$tmp1,"",0));
-+ &xor( $L, $tmp1);
-+ &mov( $tmp1, &DWP("0x700+$desSP",$tmp2,"",0));
-+ &xor( $L, $tmp1);
-+ &mov( $tmp1, &DWP("0x400+$desSP",$u,"",0));
-+ &xor( $L, $tmp1);
-+ &mov( $tmp1, &DWP("0x500+$desSP",$t,"",0));
-+ &xor( $L, $tmp1);
-+ }
-+
-+sub n2a
-+ {
-+ sprintf("%d",$_[0]);
-+ }
-+
-+# now has a side affect of rotating $a by $shift
-+sub R_PERM_OP
-+ {
-+ local($a,$b,$tt,$shift,$mask,$last)=@_;
-+
-+ &rotl( $a, $shift ) if ($shift != 0);
-+ &mov( $tt, $a );
-+ &xor( $a, $b );
-+ &and( $a, $mask );
-+ if (!$last eq $b)
-+ {
-+ &xor( $b, $a );
-+ &xor( $tt, $a );
-+ }
-+ else
-+ {
-+ &xor( $tt, $a );
-+ &xor( $b, $a );
-+ }
-+ &comment("");
-+ }
-+
-+sub IP_new
-+ {
-+ local($l,$r,$tt,$lr)=@_;
-+
-+ &R_PERM_OP($l,$r,$tt, 4,"0xf0f0f0f0",$l);
-+ &R_PERM_OP($r,$tt,$l,20,"0xfff0000f",$l);
-+ &R_PERM_OP($l,$tt,$r,14,"0x33333333",$r);
-+ &R_PERM_OP($tt,$r,$l,22,"0x03fc03fc",$r);
-+ &R_PERM_OP($l,$r,$tt, 9,"0xaaaaaaaa",$r);
-+
-+ if ($lr != 3)
-+ {
-+ if (($lr-3) < 0)
-+ { &rotr($tt, 3-$lr); }
-+ else { &rotl($tt, $lr-3); }
-+ }
-+ if ($lr != 2)
-+ {
-+ if (($lr-2) < 0)
-+ { &rotr($r, 2-$lr); }
-+ else { &rotl($r, $lr-2); }
-+ }
-+ }
-+
-+sub FP_new
-+ {
-+ local($l,$r,$tt,$lr)=@_;
-+
-+ if ($lr != 2)
-+ {
-+ if (($lr-2) < 0)
-+ { &rotl($r, 2-$lr); }
-+ else { &rotr($r, $lr-2); }
-+ }
-+ if ($lr != 3)
-+ {
-+ if (($lr-3) < 0)
-+ { &rotl($l, 3-$lr); }
-+ else { &rotr($l, $lr-3); }
-+ }
-+
-+ &R_PERM_OP($l,$r,$tt, 0,"0xaaaaaaaa",$r);
-+ &R_PERM_OP($tt,$r,$l,23,"0x03fc03fc",$r);
-+ &R_PERM_OP($l,$r,$tt,10,"0x33333333",$l);
-+ &R_PERM_OP($r,$tt,$l,18,"0xfff0000f",$l);
-+ &R_PERM_OP($l,$tt,$r,12,"0xf0f0f0f0",$r);
-+ &rotr($tt , 4);
-+ }
-+
---- /dev/null Tue Mar 11 13:02:56 2003
-+++ linux/crypto/ciphers/des/asm/des686.pl Mon Feb 9 13:51:03 2004
-@@ -0,0 +1,230 @@
-+#!/usr/bin/perl
-+
-+$prog="des686.pl";
-+
-+# base code is in microsft
-+# op dest, source
-+# format.
-+#
-+
-+# WILL NOT WORK ANYMORE WITH desboth.pl
-+require "desboth.pl";
-+
-+if ( ($ARGV[0] eq "elf"))
-+ { require "x86unix.pl"; }
-+elsif ( ($ARGV[0] eq "a.out"))
-+ { $aout=1; require "x86unix.pl"; }
-+elsif ( ($ARGV[0] eq "sol"))
-+ { $sol=1; require "x86unix.pl"; }
-+elsif ( ($ARGV[0] eq "cpp"))
-+ { $cpp=1; require "x86unix.pl"; }
-+elsif ( ($ARGV[0] eq "win32"))
-+ { require "x86ms.pl"; }
-+else
-+ {
-+ print STDERR <<"EOF";
-+Pick one target type from
-+ elf - linux, FreeBSD etc
-+ a.out - old linux
-+ sol - x86 solaris
-+ cpp - format so x86unix.cpp can be used
-+ win32 - Windows 95/Windows NT
-+EOF
-+ exit(1);
-+ }
-+
-+&comment("Don't even think of reading this code");
-+&comment("It was automatically generated by $prog");
-+&comment("Which is a perl program used to generate the x86 assember for");
-+&comment("any of elf, a.out, Win32, or Solaris");
-+&comment("It can be found in SSLeay 0.6.5+ or in libdes 3.26+");
-+&comment("eric <eay\@cryptsoft.com>");
-+&comment("");
-+
-+&file("dx86xxxx");
-+
-+$L="edi";
-+$R="esi";
-+
-+&des_encrypt("des_encrypt",1);
-+&des_encrypt("des_encrypt2",0);
-+
-+&des_encrypt3("des_encrypt3",1);
-+&des_encrypt3("des_decrypt3",0);
-+
-+&file_end();
-+
-+sub des_encrypt
-+ {
-+ local($name,$do_ip)=@_;
-+
-+ &function_begin($name,"EXTRN _des_SPtrans:DWORD");
-+
-+ &comment("");
-+ &comment("Load the 2 words");
-+ &mov("eax",&wparam(0));
-+ &mov($L,&DWP(0,"eax","",0));
-+ &mov($R,&DWP(4,"eax","",0));
-+
-+ $ksp=&wparam(1);
-+
-+ if ($do_ip)
-+ {
-+ &comment("");
-+ &comment("IP");
-+ &IP_new($L,$R,"eax");
-+ }
-+
-+ &comment("");
-+ &comment("fixup rotate");
-+ &rotl($R,3);
-+ &rotl($L,3);
-+ &exch($L,$R);
-+
-+ &comment("");
-+ &comment("load counter, key_schedule and enc flag");
-+ &mov("eax",&wparam(2)); # get encrypt flag
-+ &mov("ebp",&wparam(1)); # get ks
-+ &cmp("eax","0");
-+ &je(&label("start_decrypt"));
-+
-+ # encrypting part
-+
-+ for ($i=0; $i<16; $i+=2)
-+ {
-+ &comment("");
-+ &comment("Round $i");
-+ &D_ENCRYPT($L,$R,$i*2,"ebp","des_SPtrans","ecx","edx","eax","ebx");
-+
-+ &comment("");
-+ &comment("Round ".sprintf("%d",$i+1));
-+ &D_ENCRYPT($R,$L,($i+1)*2,"ebp","des_SPtrans","ecx","edx","eax","ebx");
-+ }
-+ &jmp(&label("end"));
-+
-+ &set_label("start_decrypt");
-+
-+ for ($i=15; $i>0; $i-=2)
-+ {
-+ &comment("");
-+ &comment("Round $i");
-+ &D_ENCRYPT($L,$R,$i*2,"ebp","des_SPtrans","ecx","edx","eax","ebx");
-+ &comment("");
-+ &comment("Round ".sprintf("%d",$i-1));
-+ &D_ENCRYPT($R,$L,($i-1)*2,"ebp","des_SPtrans","ecx","edx","eax","ebx");
-+ }
-+
-+ &set_label("end");
-+
-+ &comment("");
-+ &comment("Fixup");
-+ &rotr($L,3); # r
-+ &rotr($R,3); # l
-+
-+ if ($do_ip)
-+ {
-+ &comment("");
-+ &comment("FP");
-+ &FP_new($R,$L,"eax");
-+ }
-+
-+ &mov("eax",&wparam(0));
-+ &mov(&DWP(0,"eax","",0),$L);
-+ &mov(&DWP(4,"eax","",0),$R);
-+
-+ &function_end($name);
-+ }
-+
-+
-+# The logic is to load R into 2 registers and operate on both at the same time.
-+# We also load the 2 R's into 2 more registers so we can do the 'move word down a byte'
-+# while also masking the other copy and doing a lookup. We then also accumulate the
-+# L value in 2 registers then combine them at the end.
-+sub D_ENCRYPT
-+ {
-+ local($L,$R,$S,$ks,$desSP,$u,$t,$tmp1,$tmp2,$tmp3)=@_;
-+
-+ &mov( $u, &DWP(&n2a($S*4),$ks,"",0));
-+ &mov( $t, &DWP(&n2a(($S+1)*4),$ks,"",0));
-+ &xor( $u, $R );
-+ &xor( $t, $R );
-+ &rotr( $t, 4 );
-+
-+ # the numbers at the end of the line are origional instruction order
-+ &mov( $tmp2, $u ); # 1 2
-+ &mov( $tmp1, $t ); # 1 1
-+ &and( $tmp2, "0xfc" ); # 1 4
-+ &and( $tmp1, "0xfc" ); # 1 3
-+ &shr( $t, 8 ); # 1 5
-+ &xor( $L, &DWP("0x100+$desSP",$tmp1,"",0)); # 1 7
-+ &shr( $u, 8 ); # 1 6
-+ &mov( $tmp1, &DWP(" $desSP",$tmp2,"",0)); # 1 8
-+
-+ &mov( $tmp2, $u ); # 2 2
-+ &xor( $L, $tmp1 ); # 1 9
-+ &and( $tmp2, "0xfc" ); # 2 4
-+ &mov( $tmp1, $t ); # 2 1
-+ &and( $tmp1, "0xfc" ); # 2 3
-+ &shr( $t, 8 ); # 2 5
-+ &xor( $L, &DWP("0x300+$desSP",$tmp1,"",0)); # 2 7
-+ &shr( $u, 8 ); # 2 6
-+ &mov( $tmp1, &DWP("0x200+$desSP",$tmp2,"",0)); # 2 8
-+ &mov( $tmp2, $u ); # 3 2
-+
-+ &xor( $L, $tmp1 ); # 2 9
-+ &and( $tmp2, "0xfc" ); # 3 4
-+
-+ &mov( $tmp1, $t ); # 3 1
-+ &shr( $u, 8 ); # 3 6
-+ &and( $tmp1, "0xfc" ); # 3 3
-+ &shr( $t, 8 ); # 3 5
-+ &xor( $L, &DWP("0x500+$desSP",$tmp1,"",0)); # 3 7
-+ &mov( $tmp1, &DWP("0x400+$desSP",$tmp2,"",0)); # 3 8
-+
-+ &and( $t, "0xfc" ); # 4 1
-+ &xor( $L, $tmp1 ); # 3 9
-+
-+ &and( $u, "0xfc" ); # 4 2
-+ &xor( $L, &DWP("0x700+$desSP",$t,"",0)); # 4 3
-+ &xor( $L, &DWP("0x600+$desSP",$u,"",0)); # 4 4
-+ }
-+
-+sub PERM_OP
-+ {
-+ local($a,$b,$tt,$shift,$mask)=@_;
-+
-+ &mov( $tt, $a );
-+ &shr( $tt, $shift );
-+ &xor( $tt, $b );
-+ &and( $tt, $mask );
-+ &xor( $b, $tt );
-+ &shl( $tt, $shift );
-+ &xor( $a, $tt );
-+ }
-+
-+sub IP_new
-+ {
-+ local($l,$r,$tt)=@_;
-+
-+ &PERM_OP($r,$l,$tt, 4,"0x0f0f0f0f");
-+ &PERM_OP($l,$r,$tt,16,"0x0000ffff");
-+ &PERM_OP($r,$l,$tt, 2,"0x33333333");
-+ &PERM_OP($l,$r,$tt, 8,"0x00ff00ff");
-+ &PERM_OP($r,$l,$tt, 1,"0x55555555");
-+ }
-+
-+sub FP_new
-+ {
-+ local($l,$r,$tt)=@_;
-+
-+ &PERM_OP($l,$r,$tt, 1,"0x55555555");
-+ &PERM_OP($r,$l,$tt, 8,"0x00ff00ff");
-+ &PERM_OP($l,$r,$tt, 2,"0x33333333");
-+ &PERM_OP($r,$l,$tt,16,"0x0000ffff");
-+ &PERM_OP($l,$r,$tt, 4,"0x0f0f0f0f");
-+ }
-+
-+sub n2a
-+ {
-+ sprintf("%d",$_[0]);
-+ }
---- /dev/null Tue Mar 11 13:02:56 2003
-+++ linux/crypto/ciphers/des/asm/desboth.pl Mon Feb 9 13:51:03 2004
-@@ -0,0 +1,79 @@
-+#!/usr/bin/perl
-+
-+$L="edi";
-+$R="esi";
-+
-+sub des_encrypt3
-+ {
-+ local($name,$enc)=@_;
-+
-+ &function_begin_B($name,"");
-+ &push("ebx");
-+ &mov("ebx",&wparam(0));
-+
-+ &push("ebp");
-+ &push("esi");
-+
-+ &push("edi");
-+
-+ &comment("");
-+ &comment("Load the data words");
-+ &mov($L,&DWP(0,"ebx","",0));
-+ &mov($R,&DWP(4,"ebx","",0));
-+ &stack_push(3);
-+
-+ &comment("");
-+ &comment("IP");
-+ &IP_new($L,$R,"edx",0);
-+
-+ # put them back
-+
-+ if ($enc)
-+ {
-+ &mov(&DWP(4,"ebx","",0),$R);
-+ &mov("eax",&wparam(1));
-+ &mov(&DWP(0,"ebx","",0),"edx");
-+ &mov("edi",&wparam(2));
-+ &mov("esi",&wparam(3));
-+ }
-+ else
-+ {
-+ &mov(&DWP(4,"ebx","",0),$R);
-+ &mov("esi",&wparam(1));
-+ &mov(&DWP(0,"ebx","",0),"edx");
-+ &mov("edi",&wparam(2));
-+ &mov("eax",&wparam(3));
-+ }
-+ &mov(&swtmp(2), (($enc)?"1":"0"));
-+ &mov(&swtmp(1), "eax");
-+ &mov(&swtmp(0), "ebx");
-+ &call("des_encrypt2");
-+ &mov(&swtmp(2), (($enc)?"0":"1"));
-+ &mov(&swtmp(1), "edi");
-+ &mov(&swtmp(0), "ebx");
-+ &call("des_encrypt2");
-+ &mov(&swtmp(2), (($enc)?"1":"0"));
-+ &mov(&swtmp(1), "esi");
-+ &mov(&swtmp(0), "ebx");
-+ &call("des_encrypt2");
-+
-+ &stack_pop(3);
-+ &mov($L,&DWP(0,"ebx","",0));
-+ &mov($R,&DWP(4,"ebx","",0));
-+
-+ &comment("");
-+ &comment("FP");
-+ &FP_new($L,$R,"eax",0);
-+
-+ &mov(&DWP(0,"ebx","",0),"eax");
-+ &mov(&DWP(4,"ebx","",0),$R);
-+
-+ &pop("edi");
-+ &pop("esi");
-+ &pop("ebp");
-+ &pop("ebx");
-+ &ret();
-+ &function_end_B($name);
-+ }
-+
-+
---- /dev/null Tue Mar 11 13:02:56 2003
-+++ linux/crypto/ciphers/des/asm/perlasm/cbc.pl Mon Feb 9 13:51:03 2004
-@@ -0,0 +1,342 @@
-+#!/usr/bin/perl
-+
-+# void des_ncbc_encrypt(input, output, length, schedule, ivec, enc)
-+# des_cblock (*input);
-+# des_cblock (*output);
-+# long length;
-+# des_key_schedule schedule;
-+# des_cblock (*ivec);
-+# int enc;
-+#
-+# calls
-+# des_encrypt((DES_LONG *)tin,schedule,DES_ENCRYPT);
-+#
-+
-+#&cbc("des_ncbc_encrypt","des_encrypt",0);
-+#&cbc("BF_cbc_encrypt","BF_encrypt","BF_encrypt",
-+# 1,4,5,3,5,-1);
-+#&cbc("des_ncbc_encrypt","des_encrypt","des_encrypt",
-+# 0,4,5,3,5,-1);
-+#&cbc("des_ede3_cbc_encrypt","des_encrypt3","des_decrypt3",
-+# 0,6,7,3,4,5);
-+#
-+# When doing a cipher that needs bigendian order,
-+# for encrypt, the iv is kept in bigendian form,
-+# while for decrypt, it is kept in little endian.
-+sub cbc
-+ {
-+ local($name,$enc_func,$dec_func,$swap,$iv_off,$enc_off,$p1,$p2,$p3)=@_;
-+ # name is the function name
-+ # enc_func and dec_func and the functions to call for encrypt/decrypt
-+ # swap is true if byte order needs to be reversed
-+ # iv_off is parameter number for the iv
-+ # enc_off is parameter number for the encrypt/decrypt flag
-+ # p1,p2,p3 are the offsets for parameters to be passed to the
-+ # underlying calls.
-+
-+ &function_begin_B($name,"");
-+ &comment("");
-+
-+ $in="esi";
-+ $out="edi";
-+ $count="ebp";
-+
-+ &push("ebp");
-+ &push("ebx");
-+ &push("esi");
-+ &push("edi");
-+
-+ $data_off=4;
-+ $data_off+=4 if ($p1 > 0);
-+ $data_off+=4 if ($p2 > 0);
-+ $data_off+=4 if ($p3 > 0);
-+
-+ &mov($count, &wparam(2)); # length
-+
-+ &comment("getting iv ptr from parameter $iv_off");
-+ &mov("ebx", &wparam($iv_off)); # Get iv ptr
-+
-+ &mov($in, &DWP(0,"ebx","",0));# iv[0]
-+ &mov($out, &DWP(4,"ebx","",0));# iv[1]
-+
-+ &push($out);
-+ &push($in);
-+ &push($out); # used in decrypt for iv[1]
-+ &push($in); # used in decrypt for iv[0]
-+
-+ &mov("ebx", "esp"); # This is the address of tin[2]
-+
-+ &mov($in, &wparam(0)); # in
-+ &mov($out, &wparam(1)); # out
-+
-+ # We have loaded them all, how lets push things
-+ &comment("getting encrypt flag from parameter $enc_off");
-+ &mov("ecx", &wparam($enc_off)); # Get enc flag
-+ if ($p3 > 0)
-+ {
-+ &comment("get and push parameter $p3");
-+ if ($enc_off != $p3)
-+ { &mov("eax", &wparam($p3)); &push("eax"); }
-+ else { &push("ecx"); }
-+ }
-+ if ($p2 > 0)
-+ {
-+ &comment("get and push parameter $p2");
-+ if ($enc_off != $p2)
-+ { &mov("eax", &wparam($p2)); &push("eax"); }
-+ else { &push("ecx"); }
-+ }
-+ if ($p1 > 0)
-+ {
-+ &comment("get and push parameter $p1");
-+ if ($enc_off != $p1)
-+ { &mov("eax", &wparam($p1)); &push("eax"); }
-+ else { &push("ecx"); }
-+ }
-+ &push("ebx"); # push data/iv
-+
-+ &cmp("ecx",0);
-+ &jz(&label("decrypt"));
-+
-+ &and($count,0xfffffff8);
-+ &mov("eax", &DWP($data_off,"esp","",0)); # load iv[0]
-+ &mov("ebx", &DWP($data_off+4,"esp","",0)); # load iv[1]
-+
-+ &jz(&label("encrypt_finish"));
-+
-+ #############################################################
-+
-+ &set_label("encrypt_loop");
-+ # encrypt start
-+ # "eax" and "ebx" hold iv (or the last cipher text)
-+
-+ &mov("ecx", &DWP(0,$in,"",0)); # load first 4 bytes
-+ &mov("edx", &DWP(4,$in,"",0)); # second 4 bytes
-+
-+ &xor("eax", "ecx");
-+ &xor("ebx", "edx");
-+
-+ &bswap("eax") if $swap;
-+ &bswap("ebx") if $swap;
-+
-+ &mov(&DWP($data_off,"esp","",0), "eax"); # put in array for call
-+ &mov(&DWP($data_off+4,"esp","",0), "ebx"); #
-+
-+ &call($enc_func);
-+
-+ &mov("eax", &DWP($data_off,"esp","",0));
-+ &mov("ebx", &DWP($data_off+4,"esp","",0));
-+
-+ &bswap("eax") if $swap;
-+ &bswap("ebx") if $swap;
-+
-+ &mov(&DWP(0,$out,"",0),"eax");
-+ &mov(&DWP(4,$out,"",0),"ebx");
-+
-+ # eax and ebx are the next iv.
-+
-+ &add($in, 8);
-+ &add($out, 8);
-+
-+ &sub($count, 8);
-+ &jnz(&label("encrypt_loop"));
-+
-+###################################################################3
-+ &set_label("encrypt_finish");
-+ &mov($count, &wparam(2)); # length
-+ &and($count, 7);
-+ &jz(&label("finish"));
-+ &xor("ecx","ecx");
-+ &xor("edx","edx");
-+ &mov($count,&DWP(&label("cbc_enc_jmp_table"),"",$count,4));
-+ &jmp_ptr($count);
-+
-+&set_label("ej7");
-+ &xor("edx", "edx") if $ppro; # ppro friendly
-+ &movb(&HB("edx"), &BP(6,$in,"",0));
-+ &shl("edx",8);
-+&set_label("ej6");
-+ &movb(&HB("edx"), &BP(5,$in,"",0));
-+&set_label("ej5");
-+ &movb(&LB("edx"), &BP(4,$in,"",0));
-+&set_label("ej4");
-+ &mov("ecx", &DWP(0,$in,"",0));
-+ &jmp(&label("ejend"));
-+&set_label("ej3");
-+ &movb(&HB("ecx"), &BP(2,$in,"",0));
-+ &xor("ecx", "ecx") if $ppro; # ppro friendly
-+ &shl("ecx",8);
-+&set_label("ej2");
-+ &movb(&HB("ecx"), &BP(1,$in,"",0));
-+&set_label("ej1");
-+ &movb(&LB("ecx"), &BP(0,$in,"",0));
-+&set_label("ejend");
-+
-+ &xor("eax", "ecx");
-+ &xor("ebx", "edx");
-+
-+ &bswap("eax") if $swap;
-+ &bswap("ebx") if $swap;
-+
-+ &mov(&DWP($data_off,"esp","",0), "eax"); # put in array for call
-+ &mov(&DWP($data_off+4,"esp","",0), "ebx"); #
-+
-+ &call($enc_func);
-+
-+ &mov("eax", &DWP($data_off,"esp","",0));
-+ &mov("ebx", &DWP($data_off+4,"esp","",0));
-+
-+ &bswap("eax") if $swap;
-+ &bswap("ebx") if $swap;
-+
-+ &mov(&DWP(0,$out,"",0),"eax");
-+ &mov(&DWP(4,$out,"",0),"ebx");
-+
-+ &jmp(&label("finish"));
-+
-+ #############################################################
-+ #############################################################
-+ &set_label("decrypt",1);
-+ # decrypt start
-+ &and($count,0xfffffff8);
-+ # The next 2 instructions are only for if the jz is taken
-+ &mov("eax", &DWP($data_off+8,"esp","",0)); # get iv[0]
-+ &mov("ebx", &DWP($data_off+12,"esp","",0)); # get iv[1]
-+ &jz(&label("decrypt_finish"));
-+
-+ &set_label("decrypt_loop");
-+ &mov("eax", &DWP(0,$in,"",0)); # load first 4 bytes
-+ &mov("ebx", &DWP(4,$in,"",0)); # second 4 bytes
-+
-+ &bswap("eax") if $swap;
-+ &bswap("ebx") if $swap;
-+
-+ &mov(&DWP($data_off,"esp","",0), "eax"); # put back
-+ &mov(&DWP($data_off+4,"esp","",0), "ebx"); #
-+
-+ &call($dec_func);
-+
-+ &mov("eax", &DWP($data_off,"esp","",0)); # get return
-+ &mov("ebx", &DWP($data_off+4,"esp","",0)); #
-+
-+ &bswap("eax") if $swap;
-+ &bswap("ebx") if $swap;
-+
-+ &mov("ecx", &DWP($data_off+8,"esp","",0)); # get iv[0]
-+ &mov("edx", &DWP($data_off+12,"esp","",0)); # get iv[1]
-+
-+ &xor("ecx", "eax");
-+ &xor("edx", "ebx");
-+
-+ &mov("eax", &DWP(0,$in,"",0)); # get old cipher text,
-+ &mov("ebx", &DWP(4,$in,"",0)); # next iv actually
-+
-+ &mov(&DWP(0,$out,"",0),"ecx");
-+ &mov(&DWP(4,$out,"",0),"edx");
-+
-+ &mov(&DWP($data_off+8,"esp","",0), "eax"); # save iv
-+ &mov(&DWP($data_off+12,"esp","",0), "ebx"); #
-+
-+ &add($in, 8);
-+ &add($out, 8);
-+
-+ &sub($count, 8);
-+ &jnz(&label("decrypt_loop"));
-+############################ ENDIT #######################3
-+ &set_label("decrypt_finish");
-+ &mov($count, &wparam(2)); # length
-+ &and($count, 7);
-+ &jz(&label("finish"));
-+
-+ &mov("eax", &DWP(0,$in,"",0)); # load first 4 bytes
-+ &mov("ebx", &DWP(4,$in,"",0)); # second 4 bytes
-+
-+ &bswap("eax") if $swap;
-+ &bswap("ebx") if $swap;
-+
-+ &mov(&DWP($data_off,"esp","",0), "eax"); # put back
-+ &mov(&DWP($data_off+4,"esp","",0), "ebx"); #
-+
-+ &call($dec_func);
-+
-+ &mov("eax", &DWP($data_off,"esp","",0)); # get return
-+ &mov("ebx", &DWP($data_off+4,"esp","",0)); #
-+
-+ &bswap("eax") if $swap;
-+ &bswap("ebx") if $swap;
-+
-+ &mov("ecx", &DWP($data_off+8,"esp","",0)); # get iv[0]
-+ &mov("edx", &DWP($data_off+12,"esp","",0)); # get iv[1]
-+
-+ &xor("ecx", "eax");
-+ &xor("edx", "ebx");
-+
-+ # this is for when we exit
-+ &mov("eax", &DWP(0,$in,"",0)); # get old cipher text,
-+ &mov("ebx", &DWP(4,$in,"",0)); # next iv actually
-+
-+&set_label("dj7");
-+ &rotr("edx", 16);
-+ &movb(&BP(6,$out,"",0), &LB("edx"));
-+ &shr("edx",16);
-+&set_label("dj6");
-+ &movb(&BP(5,$out,"",0), &HB("edx"));
-+&set_label("dj5");
-+ &movb(&BP(4,$out,"",0), &LB("edx"));
-+&set_label("dj4");
-+ &mov(&DWP(0,$out,"",0), "ecx");
-+ &jmp(&label("djend"));
-+&set_label("dj3");
-+ &rotr("ecx", 16);
-+ &movb(&BP(2,$out,"",0), &LB("ecx"));
-+ &shl("ecx",16);
-+&set_label("dj2");
-+ &movb(&BP(1,$in,"",0), &HB("ecx"));
-+&set_label("dj1");
-+ &movb(&BP(0,$in,"",0), &LB("ecx"));
-+&set_label("djend");
-+
-+ # final iv is still in eax:ebx
-+ &jmp(&label("finish"));
-+
-+
-+############################ FINISH #######################3
-+ &set_label("finish",1);
-+ &mov("ecx", &wparam($iv_off)); # Get iv ptr
-+
-+ #################################################
-+ $total=16+4;
-+ $total+=4 if ($p1 > 0);
-+ $total+=4 if ($p2 > 0);
-+ $total+=4 if ($p3 > 0);
-+ &add("esp",$total);
-+
-+ &mov(&DWP(0,"ecx","",0), "eax"); # save iv
-+ &mov(&DWP(4,"ecx","",0), "ebx"); # save iv
-+
-+ &function_end_A($name);
-+
-+ &set_label("cbc_enc_jmp_table",1);
-+ &data_word("0");
-+ &data_word(&label("ej1"));
-+ &data_word(&label("ej2"));
-+ &data_word(&label("ej3"));
-+ &data_word(&label("ej4"));
-+ &data_word(&label("ej5"));
-+ &data_word(&label("ej6"));
-+ &data_word(&label("ej7"));
-+ &set_label("cbc_dec_jmp_table",1);
-+ &data_word("0");
-+ &data_word(&label("dj1"));
-+ &data_word(&label("dj2"));
-+ &data_word(&label("dj3"));
-+ &data_word(&label("dj4"));
-+ &data_word(&label("dj5"));
-+ &data_word(&label("dj6"));
-+ &data_word(&label("dj7"));
-+
-+ &function_end_B($name);
-+
-+ }
-+
-+1;
---- /dev/null Tue Mar 11 13:02:56 2003
-+++ linux/crypto/ciphers/des/asm/perlasm/readme Mon Feb 9 13:51:03 2004
-@@ -0,0 +1,124 @@
-+The perl scripts in this directory are my 'hack' to generate
-+multiple different assembler formats via the one origional script.
-+
-+The way to use this library is to start with adding the path to this directory
-+and then include it.
-+
-+push(@INC,"perlasm","../../perlasm");
-+require "x86asm.pl";
-+
-+The first thing we do is setup the file and type of assember
-+
-+&asm_init($ARGV[0],$0);
-+
-+The first argument is the 'type'. Currently
-+'cpp', 'sol', 'a.out', 'elf' or 'win32'.
-+Argument 2 is the file name.
-+
-+The reciprocal function is
-+&asm_finish() which should be called at the end.
-+
-+There are 2 main 'packages'. x86ms.pl, which is the microsoft assembler,
-+and x86unix.pl which is the unix (gas) version.
-+
-+Functions of interest are:
-+&external_label("des_SPtrans"); declare and external variable
-+&LB(reg); Low byte for a register
-+&HB(reg); High byte for a register
-+&BP(off,base,index,scale) Byte pointer addressing
-+&DWP(off,base,index,scale) Word pointer addressing
-+&stack_push(num) Basically a 'sub esp, num*4' with extra
-+&stack_pop(num) inverse of stack_push
-+&function_begin(name,extra) Start a function with pushing of
-+ edi, esi, ebx and ebp. extra is extra win32
-+ external info that may be required.
-+&function_begin_B(name,extra) Same as norma function_begin but no pushing.
-+&function_end(name) Call at end of function.
-+&function_end_A(name) Standard pop and ret, for use inside functions
-+&function_end_B(name) Call at end but with poping or 'ret'.
-+&swtmp(num) Address on stack temp word.
-+&wparam(num) Parameter number num, that was push
-+ in C convention. This all works over pushes
-+ and pops.
-+&comment("hello there") Put in a comment.
-+&label("loop") Refer to a label, normally a jmp target.
-+&set_label("loop") Set a label at this point.
-+&data_word(word) Put in a word of data.
-+
-+So how does this all hold together? Given
-+
-+int calc(int len, int *data)
-+ {
-+ int i,j=0;
-+
-+ for (i=0; i<len; i++)
-+ {
-+ j+=other(data[i]);
-+ }
-+ }
-+
-+So a very simple version of this function could be coded as
-+
-+ push(@INC,"perlasm","../../perlasm");
-+ require "x86asm.pl";
-+
-+ &asm_init($ARGV[0],"cacl.pl");
-+
-+ &external_label("other");
-+
-+ $tmp1= "eax";
-+ $j= "edi";
-+ $data= "esi";
-+ $i= "ebp";
-+
-+ &comment("a simple function");
-+ &function_begin("calc");
-+ &mov( $data, &wparam(1)); # data
-+ &xor( $j, $j);
-+ &xor( $i, $i);
-+
-+ &set_label("loop");
-+ &cmp( $i, &wparam(0));
-+ &jge( &label("end"));
-+
-+ &mov( $tmp1, &DWP(0,$data,$i,4));
-+ &push( $tmp1);
-+ &call( "other");
-+ &add( $j, "eax");
-+ &pop( $tmp1);
-+ &inc( $i);
-+ &jmp( &label("loop"));
-+
-+ &set_label("end");
-+ &mov( "eax", $j);
-+
-+ &function_end("calc");
-+
-+ &asm_finish();
-+
-+The above example is very very unoptimised but gives an idea of how
-+things work.
-+
-+There is also a cbc mode function generator in cbc.pl
-+
-+&cbc( $name,
-+ $encrypt_function_name,
-+ $decrypt_function_name,
-+ $true_if_byte_swap_needed,
-+ $parameter_number_for_iv,
-+ $parameter_number_for_encrypt_flag,
-+ $first_parameter_to_pass,
-+ $second_parameter_to_pass,
-+ $third_parameter_to_pass);
-+
-+So for example, given
-+void BF_encrypt(BF_LONG *data,BF_KEY *key);
-+void BF_decrypt(BF_LONG *data,BF_KEY *key);
-+void BF_cbc_encrypt(unsigned char *in, unsigned char *out, long length,
-+ BF_KEY *ks, unsigned char *iv, int enc);
-+
-+&cbc("BF_cbc_encrypt","BF_encrypt","BF_encrypt",1,4,5,3,-1,-1);
-+
-+&cbc("des_ncbc_encrypt","des_encrypt","des_encrypt",0,4,5,3,5,-1);
-+&cbc("des_ede3_cbc_encrypt","des_encrypt3","des_decrypt3",0,6,7,3,4,5);
-+
---- /dev/null Tue Mar 11 13:02:56 2003
-+++ linux/crypto/ciphers/des/asm/perlasm/x86asm.pl Mon Feb 9 13:51:03 2004
-@@ -0,0 +1,111 @@
-+#!/usr/bin/perl
-+
-+# require 'x86asm.pl';
-+# &asm_init("cpp","des-586.pl");
-+# XXX
-+# XXX
-+# main'asm_finish
-+
-+sub main'asm_finish
-+ {
-+ &file_end();
-+ &asm_finish_cpp() if $cpp;
-+ print &asm_get_output();
-+ }
-+
-+sub main'asm_init
-+ {
-+ ($type,$fn)=@_;
-+ $filename=$fn;
-+
-+ $cpp=$sol=$aout=$win32=0;
-+ if ( ($type eq "elf"))
-+ { require "x86unix.pl"; }
-+ elsif ( ($type eq "a.out"))
-+ { $aout=1; require "x86unix.pl"; }
-+ elsif ( ($type eq "sol"))
-+ { $sol=1; require "x86unix.pl"; }
-+ elsif ( ($type eq "cpp"))
-+ { $cpp=1; require "x86unix.pl"; }
-+ elsif ( ($type eq "win32"))
-+ { $win32=1; require "x86ms.pl"; }
-+ else
-+ {
-+ print STDERR <<"EOF";
-+Pick one target type from
-+ elf - linux, FreeBSD etc
-+ a.out - old linux
-+ sol - x86 solaris
-+ cpp - format so x86unix.cpp can be used
-+ win32 - Windows 95/Windows NT
-+EOF
-+ exit(1);
-+ }
-+
-+ &asm_init_output();
-+
-+&comment("Don't even think of reading this code");
-+&comment("It was automatically generated by $filename");
-+&comment("Which is a perl program used to generate the x86 assember for");
-+&comment("any of elf, a.out, BSDI,Win32, or Solaris");
-+&comment("eric <eay\@cryptsoft.com>");
-+&comment("");
-+
-+ $filename =~ s/\.pl$//;
-+ &file($filename);
-+ }
-+
-+sub asm_finish_cpp
-+ {
-+ return unless $cpp;
-+
-+ local($tmp,$i);
-+ foreach $i (&get_labels())
-+ {
-+ $tmp.="#define $i _$i\n";
-+ }
-+ print <<"EOF";
-+/* Run the C pre-processor over this file with one of the following defined
-+ * ELF - elf object files,
-+ * OUT - a.out object files,
-+ * BSDI - BSDI style a.out object files
-+ * SOL - Solaris style elf
-+ */
-+
-+#define TYPE(a,b) .type a,b
-+#define SIZE(a,b) .size a,b
-+
-+#if defined(OUT) || defined(BSDI)
-+$tmp
-+#endif
-+
-+#ifdef OUT
-+#define OK 1
-+#define ALIGN 4
-+#endif
-+
-+#ifdef BSDI
-+#define OK 1
-+#define ALIGN 4
-+#undef SIZE
-+#undef TYPE
-+#endif
-+
-+#if defined(ELF) || defined(SOL)
-+#define OK 1
-+#define ALIGN 16
-+#endif
-+
-+#ifndef OK
-+You need to define one of
-+ELF - elf systems - linux-elf, NetBSD and DG-UX
-+OUT - a.out systems - linux-a.out and FreeBSD
-+SOL - solaris systems, which are elf with strange comment lines
-+BSDI - a.out with a very primative version of as.
-+#endif
-+
-+/* Let the Assembler begin :-) */
-+EOF
-+ }
-+
-+1;
---- /dev/null Tue Mar 11 13:02:56 2003
-+++ linux/crypto/ciphers/des/asm/perlasm/x86ms.pl Mon Feb 9 13:51:03 2004
-@@ -0,0 +1,345 @@
-+#!/usr/bin/perl
-+
-+package x86ms;
-+
-+$label="L000";
-+
-+%lb=( 'eax', 'al',
-+ 'ebx', 'bl',
-+ 'ecx', 'cl',
-+ 'edx', 'dl',
-+ 'ax', 'al',
-+ 'bx', 'bl',
-+ 'cx', 'cl',
-+ 'dx', 'dl',
-+ );
-+
-+%hb=( 'eax', 'ah',
-+ 'ebx', 'bh',
-+ 'ecx', 'ch',
-+ 'edx', 'dh',
-+ 'ax', 'ah',
-+ 'bx', 'bh',
-+ 'cx', 'ch',
-+ 'dx', 'dh',
-+ );
-+
-+sub main'asm_init_output { @out=(); }
-+sub main'asm_get_output { return(@out); }
-+sub main'get_labels { return(@labels); }
-+sub main'external_label { push(@labels,@_); }
-+
-+sub main'LB
-+ {
-+ (defined($lb{$_[0]})) || die "$_[0] does not have a 'low byte'\n";
-+ return($lb{$_[0]});
-+ }
-+
-+sub main'HB
-+ {
-+ (defined($hb{$_[0]})) || die "$_[0] does not have a 'high byte'\n";
-+ return($hb{$_[0]});
-+ }
-+
-+sub main'BP
-+ {
-+ &get_mem("BYTE",@_);
-+ }
-+
-+sub main'DWP
-+ {
-+ &get_mem("DWORD",@_);
-+ }
-+
-+sub main'stack_push
-+ {
-+ local($num)=@_;
-+ $stack+=$num*4;
-+ &main'sub("esp",$num*4);
-+ }
-+
-+sub main'stack_pop
-+ {
-+ local($num)=@_;
-+ $stack-=$num*4;
-+ &main'add("esp",$num*4);
-+ }
-+
-+sub get_mem
-+ {
-+ local($size,$addr,$reg1,$reg2,$idx)=@_;
-+ local($t,$post);
-+ local($ret)="$size PTR ";
-+
-+ $addr =~ s/^\s+//;
-+ if ($addr =~ /^(.+)\+(.+)$/)
-+ {
-+ $reg2=&conv($1);
-+ $addr="_$2";
-+ }
-+ elsif ($addr =~ /^[_a-zA-Z]/)
-+ {
-+ $addr="_$addr";
-+ }
-+
-+ $reg1="$regs{$reg1}" if defined($regs{$reg1});
-+ $reg2="$regs{$reg2}" if defined($regs{$reg2});
-+ if (($addr ne "") && ($addr ne 0))
-+ {
-+ if ($addr !~ /^-/)
-+ { $ret.=$addr; }
-+ else { $post=$addr; }
-+ }
-+ if ($reg2 ne "")
-+ {
-+ $t="";
-+ $t="*$idx" if ($idx != 0);
-+ $reg1="+".$reg1 if ("$reg1$post" ne "");
-+ $ret.="[$reg2$t$reg1$post]";
-+ }
-+ else
-+ {
-+ $ret.="[$reg1$post]"
-+ }
-+ return($ret);
-+ }
-+
-+sub main'mov { &out2("mov",@_); }
-+sub main'movb { &out2("mov",@_); }
-+sub main'and { &out2("and",@_); }
-+sub main'or { &out2("or",@_); }
-+sub main'shl { &out2("shl",@_); }
-+sub main'shr { &out2("shr",@_); }
-+sub main'xor { &out2("xor",@_); }
-+sub main'xorb { &out2("xor",@_); }
-+sub main'add { &out2("add",@_); }
-+sub main'adc { &out2("adc",@_); }
-+sub main'sub { &out2("sub",@_); }
-+sub main'rotl { &out2("rol",@_); }
-+sub main'rotr { &out2("ror",@_); }
-+sub main'exch { &out2("xchg",@_); }
-+sub main'cmp { &out2("cmp",@_); }
-+sub main'lea { &out2("lea",@_); }
-+sub main'mul { &out1("mul",@_); }
-+sub main'div { &out1("div",@_); }
-+sub main'dec { &out1("dec",@_); }
-+sub main'inc { &out1("inc",@_); }
-+sub main'jmp { &out1("jmp",@_); }
-+sub main'jmp_ptr { &out1p("jmp",@_); }
-+sub main'je { &out1("je",@_); }
-+sub main'jle { &out1("jle",@_); }
-+sub main'jz { &out1("jz",@_); }
-+sub main'jge { &out1("jge",@_); }
-+sub main'jl { &out1("jl",@_); }
-+sub main'jb { &out1("jb",@_); }
-+sub main'jnz { &out1("jnz",@_); }
-+sub main'jne { &out1("jne",@_); }
-+sub main'push { &out1("push",@_); $stack+=4; }
-+sub main'pop { &out1("pop",@_); $stack-=4; }
-+sub main'bswap { &out1("bswap",@_); &using486(); }
-+sub main'not { &out1("not",@_); }
-+sub main'call { &out1("call",'_'.$_[0]); }
-+sub main'ret { &out0("ret"); }
-+sub main'nop { &out0("nop"); }
-+
-+sub out2
-+ {
-+ local($name,$p1,$p2)=@_;
-+ local($l,$t);
-+
-+ push(@out,"\t$name\t");
-+ $t=&conv($p1).",";
-+ $l=length($t);
-+ push(@out,$t);
-+ $l=4-($l+9)/8;
-+ push(@out,"\t" x $l);
-+ push(@out,&conv($p2));
-+ push(@out,"\n");
-+ }
-+
-+sub out0
-+ {
-+ local($name)=@_;
-+
-+ push(@out,"\t$name\n");
-+ }
-+
-+sub out1
-+ {
-+ local($name,$p1)=@_;
-+ local($l,$t);
-+
-+ push(@out,"\t$name\t".&conv($p1)."\n");
-+ }
-+
-+sub conv
-+ {
-+ local($p)=@_;
-+
-+ $p =~ s/0x([0-9A-Fa-f]+)/0$1h/;
-+ return $p;
-+ }
-+
-+sub using486
-+ {
-+ return if $using486;
-+ $using486++;
-+ grep(s/\.386/\.486/,@out);
-+ }
-+
-+sub main'file
-+ {
-+ local($file)=@_;
-+
-+ local($tmp)=<<"EOF";
-+ TITLE $file.asm
-+ .386
-+.model FLAT
-+EOF
-+ push(@out,$tmp);
-+ }
-+
-+sub main'function_begin
-+ {
-+ local($func,$extra)=@_;
-+
-+ push(@labels,$func);
-+
-+ local($tmp)=<<"EOF";
-+_TEXT SEGMENT
-+PUBLIC _$func
-+$extra
-+_$func PROC NEAR
-+ push ebp
-+ push ebx
-+ push esi
-+ push edi
-+EOF
-+ push(@out,$tmp);
-+ $stack=20;
-+ }
-+
-+sub main'function_begin_B
-+ {
-+ local($func,$extra)=@_;
-+
-+ local($tmp)=<<"EOF";
-+_TEXT SEGMENT
-+PUBLIC _$func
-+$extra
-+_$func PROC NEAR
-+EOF
-+ push(@out,$tmp);
-+ $stack=4;
-+ }
-+
-+sub main'function_end
-+ {
-+ local($func)=@_;
-+
-+ local($tmp)=<<"EOF";
-+ pop edi
-+ pop esi
-+ pop ebx
-+ pop ebp
-+ ret
-+_$func ENDP
-+_TEXT ENDS
-+EOF
-+ push(@out,$tmp);
-+ $stack=0;
-+ %label=();
-+ }
-+
-+sub main'function_end_B
-+ {
-+ local($func)=@_;
-+
-+ local($tmp)=<<"EOF";
-+_$func ENDP
-+_TEXT ENDS
-+EOF
-+ push(@out,$tmp);
-+ $stack=0;
-+ %label=();
-+ }
-+
-+sub main'function_end_A
-+ {
-+ local($func)=@_;
-+
-+ local($tmp)=<<"EOF";
-+ pop edi
-+ pop esi
-+ pop ebx
-+ pop ebp
-+ ret
-+EOF
-+ push(@out,$tmp);
-+ }
-+
-+sub main'file_end
-+ {
-+ push(@out,"END\n");
-+ }
-+
-+sub main'wparam
-+ {
-+ local($num)=@_;
-+
-+ return(&main'DWP($stack+$num*4,"esp","",0));
-+ }
-+
-+sub main'swtmp
-+ {
-+ return(&main'DWP($_[0]*4,"esp","",0));
-+ }
-+
-+# Should use swtmp, which is above esp. Linix can trash the stack above esp
-+#sub main'wtmp
-+# {
-+# local($num)=@_;
-+#
-+# return(&main'DWP(-(($num+1)*4),"esp","",0));
-+# }
-+
-+sub main'comment
-+ {
-+ foreach (@_)
-+ {
-+ push(@out,"\t; $_\n");
-+ }
-+ }
-+
-+sub main'label
-+ {
-+ if (!defined($label{$_[0]}))
-+ {
-+ $label{$_[0]}="\$${label}${_[0]}";
-+ $label++;
-+ }
-+ return($label{$_[0]});
-+ }
-+
-+sub main'set_label
-+ {
-+ if (!defined($label{$_[0]}))
-+ {
-+ $label{$_[0]}="${label}${_[0]}";
-+ $label++;
-+ }
-+ push(@out,"$label{$_[0]}:\n");
-+ }
-+
-+sub main'data_word
-+ {
-+ push(@out,"\tDD\t$_[0]\n");
-+ }
-+
-+sub out1p
-+ {
-+ local($name,$p1)=@_;
-+ local($l,$t);
-+
-+ push(@out,"\t$name\t ".&conv($p1)."\n");
-+ }
---- /dev/null Tue Mar 11 13:02:56 2003
-+++ linux/crypto/ciphers/des/asm/perlasm/x86unix.pl Mon Feb 9 13:51:03 2004
-@@ -0,0 +1,403 @@
-+#!/usr/bin/perl
-+
-+package x86unix;
-+
-+$label="L000";
-+
-+$align=($main'aout)?"4":"16";
-+$under=($main'aout)?"_":"";
-+$com_start=($main'sol)?"/":"#";
-+
-+sub main'asm_init_output { @out=(); }
-+sub main'asm_get_output { return(@out); }
-+sub main'get_labels { return(@labels); }
-+sub main'external_label { push(@labels,@_); }
-+
-+if ($main'cpp)
-+ {
-+ $align="ALIGN";
-+ $under="";
-+ $com_start='/*';
-+ $com_end='*/';
-+ }
-+
-+%lb=( 'eax', '%al',
-+ 'ebx', '%bl',
-+ 'ecx', '%cl',
-+ 'edx', '%dl',
-+ 'ax', '%al',
-+ 'bx', '%bl',
-+ 'cx', '%cl',
-+ 'dx', '%dl',
-+ );
-+
-+%hb=( 'eax', '%ah',
-+ 'ebx', '%bh',
-+ 'ecx', '%ch',
-+ 'edx', '%dh',
-+ 'ax', '%ah',
-+ 'bx', '%bh',
-+ 'cx', '%ch',
-+ 'dx', '%dh',
-+ );
-+
-+%regs=( 'eax', '%eax',
-+ 'ebx', '%ebx',
-+ 'ecx', '%ecx',
-+ 'edx', '%edx',
-+ 'esi', '%esi',
-+ 'edi', '%edi',
-+ 'ebp', '%ebp',
-+ 'esp', '%esp',
-+ );
-+
-+%reg_val=(
-+ 'eax', 0x00,
-+ 'ebx', 0x03,
-+ 'ecx', 0x01,
-+ 'edx', 0x02,
-+ 'esi', 0x06,
-+ 'edi', 0x07,
-+ 'ebp', 0x05,
-+ 'esp', 0x04,
-+ );
-+
-+sub main'LB
-+ {
-+ (defined($lb{$_[0]})) || die "$_[0] does not have a 'low byte'\n";
-+ return($lb{$_[0]});
-+ }
-+
-+sub main'HB
-+ {
-+ (defined($hb{$_[0]})) || die "$_[0] does not have a 'high byte'\n";
-+ return($hb{$_[0]});
-+ }
-+
-+sub main'DWP
-+ {
-+ local($addr,$reg1,$reg2,$idx)=@_;
-+
-+ $ret="";
-+ $addr =~ s/(^|[+ \t])([A-Za-z_]+)($|[+ \t])/$1$under$2$3/;
-+ $reg1="$regs{$reg1}" if defined($regs{$reg1});
-+ $reg2="$regs{$reg2}" if defined($regs{$reg2});
-+ $ret.=$addr if ($addr ne "") && ($addr ne 0);
-+ if ($reg2 ne "")
-+ { $ret.="($reg1,$reg2,$idx)"; }
-+ else
-+ { $ret.="($reg1)" }
-+ return($ret);
-+ }
-+
-+sub main'BP
-+ {
-+ return(&main'DWP(@_));
-+ }
-+
-+#sub main'BP
-+# {
-+# local($addr,$reg1,$reg2,$idx)=@_;
-+#
-+# $ret="";
-+#
-+# $addr =~ s/(^|[+ \t])([A-Za-z_]+)($|[+ \t])/$1$under$2$3/;
-+# $reg1="$regs{$reg1}" if defined($regs{$reg1});
-+# $reg2="$regs{$reg2}" if defined($regs{$reg2});
-+# $ret.=$addr if ($addr ne "") && ($addr ne 0);
-+# if ($reg2 ne "")
-+# { $ret.="($reg1,$reg2,$idx)"; }
-+# else
-+# { $ret.="($reg1)" }
-+# return($ret);
-+# }
-+
-+sub main'mov { &out2("movl",@_); }
-+sub main'movb { &out2("movb",@_); }
-+sub main'and { &out2("andl",@_); }
-+sub main'or { &out2("orl",@_); }
-+sub main'shl { &out2("sall",@_); }
-+sub main'shr { &out2("shrl",@_); }
-+sub main'xor { &out2("xorl",@_); }
-+sub main'xorb { &out2("xorb",@_); }
-+sub main'add { &out2("addl",@_); }
-+sub main'adc { &out2("adcl",@_); }
-+sub main'sub { &out2("subl",@_); }
-+sub main'rotl { &out2("roll",@_); }
-+sub main'rotr { &out2("rorl",@_); }
-+sub main'exch { &out2("xchg",@_); }
-+sub main'cmp { &out2("cmpl",@_); }
-+sub main'lea { &out2("leal",@_); }
-+sub main'mul { &out1("mull",@_); }
-+sub main'div { &out1("divl",@_); }
-+sub main'jmp { &out1("jmp",@_); }
-+sub main'jmp_ptr { &out1p("jmp",@_); }
-+sub main'je { &out1("je",@_); }
-+sub main'jle { &out1("jle",@_); }
-+sub main'jne { &out1("jne",@_); }
-+sub main'jnz { &out1("jnz",@_); }
-+sub main'jz { &out1("jz",@_); }
-+sub main'jge { &out1("jge",@_); }
-+sub main'jl { &out1("jl",@_); }
-+sub main'jb { &out1("jb",@_); }
-+sub main'dec { &out1("decl",@_); }
-+sub main'inc { &out1("incl",@_); }
-+sub main'push { &out1("pushl",@_); $stack+=4; }
-+sub main'pop { &out1("popl",@_); $stack-=4; }
-+sub main'bswap { &out1("bswapl",@_); }
-+sub main'not { &out1("notl",@_); }
-+sub main'call { &out1("call",$under.$_[0]); }
-+sub main'ret { &out0("ret"); }
-+sub main'nop { &out0("nop"); }
-+
-+sub out2
-+ {
-+ local($name,$p1,$p2)=@_;
-+ local($l,$ll,$t);
-+ local(%special)=( "roll",0xD1C0,"rorl",0xD1C8,
-+ "rcll",0xD1D0,"rcrl",0xD1D8,
-+ "shll",0xD1E0,"shrl",0xD1E8,
-+ "sarl",0xD1F8);
-+
-+ if ((defined($special{$name})) && defined($regs{$p1}) && ($p2 == 1))
-+ {
-+ $op=$special{$name}|$reg_val{$p1};
-+ $tmp1=sprintf ".byte %d\n",($op>>8)&0xff;
-+ $tmp2=sprintf ".byte %d\t",$op &0xff;
-+ push(@out,$tmp1);
-+ push(@out,$tmp2);
-+
-+ $p2=&conv($p2);
-+ $p1=&conv($p1);
-+ &main'comment("$name $p2 $p1");
-+ return;
-+ }
-+
-+ push(@out,"\t$name\t");
-+ $t=&conv($p2).",";
-+ $l=length($t);
-+ push(@out,$t);
-+ $ll=4-($l+9)/8;
-+ $tmp1=sprintf "\t" x $ll;
-+ push(@out,$tmp1);
-+ push(@out,&conv($p1)."\n");
-+ }
-+
-+sub out1
-+ {
-+ local($name,$p1)=@_;
-+ local($l,$t);
-+
-+ push(@out,"\t$name\t".&conv($p1)."\n");
-+ }
-+
-+sub out1p
-+ {
-+ local($name,$p1)=@_;
-+ local($l,$t);
-+
-+ push(@out,"\t$name\t*".&conv($p1)."\n");
-+ }
-+
-+sub out0
-+ {
-+ push(@out,"\t$_[0]\n");
-+ }
-+
-+sub conv
-+ {
-+ local($p)=@_;
-+
-+# $p =~ s/0x([0-9A-Fa-f]+)/0$1h/;
-+
-+ $p=$regs{$p} if (defined($regs{$p}));
-+
-+ $p =~ s/^(-{0,1}[0-9A-Fa-f]+)$/\$$1/;
-+ $p =~ s/^(0x[0-9A-Fa-f]+)$/\$$1/;
-+ return $p;
-+ }
-+
-+sub main'file
-+ {
-+ local($file)=@_;
-+
-+ local($tmp)=<<"EOF";
-+ .file "$file.s"
-+ .version "01.01"
-+gcc2_compiled.:
-+EOF
-+ push(@out,$tmp);
-+ }
-+
-+sub main'function_begin
-+ {
-+ local($func)=@_;
-+
-+ $func=$under.$func;
-+
-+ local($tmp)=<<"EOF";
-+.text
-+ .align $align
-+.globl $func
-+EOF
-+ push(@out,$tmp);
-+ if ($main'cpp)
-+ { $tmp=push(@out,"\tTYPE($func,\@function)\n"); }
-+ else { $tmp=push(@out,"\t.type\t$func,\@function\n"); }
-+ push(@out,"$func:\n");
-+ $tmp=<<"EOF";
-+ pushl %ebp
-+ pushl %ebx
-+ pushl %esi
-+ pushl %edi
-+
-+EOF
-+ push(@out,$tmp);
-+ $stack=20;
-+ }
-+
-+sub main'function_begin_B
-+ {
-+ local($func,$extra)=@_;
-+
-+ $func=$under.$func;
-+
-+ local($tmp)=<<"EOF";
-+.text
-+ .align $align
-+.globl $func
-+EOF
-+ push(@out,$tmp);
-+ if ($main'cpp)
-+ { push(@out,"\tTYPE($func,\@function)\n"); }
-+ else { push(@out,"\t.type $func,\@function\n"); }
-+ push(@out,"$func:\n");
-+ $stack=4;
-+ }
-+
-+sub main'function_end
-+ {
-+ local($func)=@_;
-+
-+ $func=$under.$func;
-+
-+ local($tmp)=<<"EOF";
-+ popl %edi
-+ popl %esi
-+ popl %ebx
-+ popl %ebp
-+ ret
-+.${func}_end:
-+EOF
-+ push(@out,$tmp);
-+ if ($main'cpp)
-+ { push(@out,"\tSIZE($func,.${func}_end-$func)\n"); }
-+ else { push(@out,"\t.size\t$func,.${func}_end-$func\n"); }
-+ push(@out,".ident \"$func\"\n");
-+ $stack=0;
-+ %label=();
-+ }
-+
-+sub main'function_end_A
-+ {
-+ local($func)=@_;
-+
-+ local($tmp)=<<"EOF";
-+ popl %edi
-+ popl %esi
-+ popl %ebx
-+ popl %ebp
-+ ret
-+EOF
-+ push(@out,$tmp);
-+ }
-+
-+sub main'function_end_B
-+ {
-+ local($func)=@_;
-+
-+ $func=$under.$func;
-+
-+ push(@out,".${func}_end:\n");
-+ if ($main'cpp)
-+ { push(@out,"\tSIZE($func,.${func}_end-$func)\n"); }
-+ else { push(@out,"\t.size\t$func,.${func}_end-$func\n"); }
-+ push(@out,".ident \"desasm.pl\"\n");
-+ $stack=0;
-+ %label=();
-+ }
-+
-+sub main'wparam
-+ {
-+ local($num)=@_;
-+
-+ return(&main'DWP($stack+$num*4,"esp","",0));
-+ }
-+
-+sub main'stack_push
-+ {
-+ local($num)=@_;
-+ $stack+=$num*4;
-+ &main'sub("esp",$num*4);
-+ }
-+
-+sub main'stack_pop
-+ {
-+ local($num)=@_;
-+ $stack-=$num*4;
-+ &main'add("esp",$num*4);
-+ }
-+
-+sub main'swtmp
-+ {
-+ return(&main'DWP($_[0]*4,"esp","",0));
-+ }
-+
-+# Should use swtmp, which is above esp. Linix can trash the stack above esp
-+#sub main'wtmp
-+# {
-+# local($num)=@_;
-+#
-+# return(&main'DWP(-($num+1)*4,"esp","",0));
-+# }
-+
-+sub main'comment
-+ {
-+ foreach (@_)
-+ {
-+ if (/^\s*$/)
-+ { push(@out,"\n"); }
-+ else
-+ { push(@out,"\t$com_start $_ $com_end\n"); }
-+ }
-+ }
-+
-+sub main'label
-+ {
-+ if (!defined($label{$_[0]}))
-+ {
-+ $label{$_[0]}=".${label}${_[0]}";
-+ $label++;
-+ }
-+ return($label{$_[0]});
-+ }
-+
-+sub main'set_label
-+ {
-+ if (!defined($label{$_[0]}))
-+ {
-+ $label{$_[0]}=".${label}${_[0]}";
-+ $label++;
-+ }
-+ push(@out,".align $align\n") if ($_[1] != 0);
-+ push(@out,"$label{$_[0]}:\n");
-+ }
-+
-+sub main'file_end
-+ {
-+ }
-+
-+sub main'data_word
-+ {
-+ push(@out,"\t.long $_[0]\n");
-+ }
---- /dev/null Tue Mar 11 13:02:56 2003
-+++ linux/crypto/ciphers/des/asm/readme Mon Feb 9 13:51:03 2004
-@@ -0,0 +1,131 @@
-+First up, let me say I don't like writing in assembler. It is not portable,
-+dependant on the particular CPU architecture release and is generally a pig
-+to debug and get right. Having said that, the x86 architecture is probably
-+the most important for speed due to number of boxes and since
-+it appears to be the worst architecture to to get
-+good C compilers for. So due to this, I have lowered myself to do
-+assembler for the inner DES routines in libdes :-).
-+
-+The file to implement in assembler is des_enc.c. Replace the following
-+4 functions
-+des_encrypt(DES_LONG data[2],des_key_schedule ks, int encrypt);
-+des_encrypt2(DES_LONG data[2],des_key_schedule ks, int encrypt);
-+des_encrypt3(DES_LONG data[2],des_key_schedule ks1,ks2,ks3);
-+des_decrypt3(DES_LONG data[2],des_key_schedule ks1,ks2,ks3);
-+
-+They encrypt/decrypt the 64 bits held in 'data' using
-+the 'ks' key schedules. The only difference between the 4 functions is that
-+des_encrypt2() does not perform IP() or FP() on the data (this is an
-+optimization for when doing triple DES and des_encrypt3() and des_decrypt3()
-+perform triple des. The triple DES routines are in here because it does
-+make a big difference to have them located near the des_encrypt2 function
-+at link time..
-+
-+Now as we all know, there are lots of different operating systems running on
-+x86 boxes, and unfortunately they normally try to make sure their assembler
-+formating is not the same as the other peoples.
-+The 4 main formats I know of are
-+Microsoft Windows 95/Windows NT
-+Elf Includes Linux and FreeBSD(?).
-+a.out The older Linux.
-+Solaris Same as Elf but different comments :-(.
-+
-+Now I was not overly keen to write 4 different copies of the same code,
-+so I wrote a few perl routines to output the correct assembler, given
-+a target assembler type. This code is ugly and is just a hack.
-+The libraries are x86unix.pl and x86ms.pl.
-+des586.pl, des686.pl and des-som[23].pl are the programs to actually
-+generate the assembler.
-+
-+So to generate elf assembler
-+perl des-som3.pl elf >dx86-elf.s
-+For Windows 95/NT
-+perl des-som2.pl win32 >win32.asm
-+
-+[ update 4 Jan 1996 ]
-+I have added another way to do things.
-+perl des-som3.pl cpp >dx86-cpp.s
-+generates a file that will be included by dx86unix.cpp when it is compiled.
-+To build for elf, a.out, solaris, bsdi etc,
-+cc -E -DELF asm/dx86unix.cpp | as -o asm/dx86-elf.o
-+cc -E -DSOL asm/dx86unix.cpp | as -o asm/dx86-sol.o
-+cc -E -DOUT asm/dx86unix.cpp | as -o asm/dx86-out.o
-+cc -E -DBSDI asm/dx86unix.cpp | as -o asm/dx86bsdi.o
-+This was done to cut down the number of files in the distribution.
-+
-+Now the ugly part. I acquired my copy of Intels
-+"Optimization's For Intel's 32-Bit Processors" and found a few interesting
-+things. First, the aim of the exersize is to 'extract' one byte at a time
-+from a word and do an array lookup. This involves getting the byte from
-+the 4 locations in the word and moving it to a new word and doing the lookup.
-+The most obvious way to do this is
-+xor eax, eax # clear word
-+movb al, cl # get low byte
-+xor edi DWORD PTR 0x100+des_SP[eax] # xor in word
-+movb al, ch # get next byte
-+xor edi DWORD PTR 0x300+des_SP[eax] # xor in word
-+shr ecx 16
-+which seems ok. For the pentium, this system appears to be the best.
-+One has to do instruction interleaving to keep both functional units
-+operating, but it is basically very efficient.
-+
-+Now the crunch. When a full register is used after a partial write, eg.
-+mov al, cl
-+xor edi, DWORD PTR 0x100+des_SP[eax]
-+386 - 1 cycle stall
-+486 - 1 cycle stall
-+586 - 0 cycle stall
-+686 - at least 7 cycle stall (page 22 of the above mentioned document).
-+
-+So the technique that produces the best results on a pentium, according to
-+the documentation, will produce hideous results on a pentium pro.
-+
-+To get around this, des686.pl will generate code that is not as fast on
-+a pentium, should be very good on a pentium pro.
-+mov eax, ecx # copy word
-+shr ecx, 8 # line up next byte
-+and eax, 0fch # mask byte
-+xor edi DWORD PTR 0x100+des_SP[eax] # xor in array lookup
-+mov eax, ecx # get word
-+shr ecx 8 # line up next byte
-+and eax, 0fch # mask byte
-+xor edi DWORD PTR 0x300+des_SP[eax] # xor in array lookup
-+
-+Due to the execution units in the pentium, this actually works quite well.
-+For a pentium pro it should be very good. This is the type of output
-+Visual C++ generates.
-+
-+There is a third option. instead of using
-+mov al, ch
-+which is bad on the pentium pro, one may be able to use
-+movzx eax, ch
-+which may not incur the partial write penalty. On the pentium,
-+this instruction takes 4 cycles so is not worth using but on the
-+pentium pro it appears it may be worth while. I need access to one to
-+experiment :-).
-+
-+eric (20 Oct 1996)
-+
-+22 Nov 1996 - I have asked people to run the 2 different version on pentium
-+pros and it appears that the intel documentation is wrong. The
-+mov al,bh is still faster on a pentium pro, so just use the des586.pl
-+install des686.pl
-+
-+3 Dec 1996 - I added des_encrypt3/des_decrypt3 because I have moved these
-+functions into des_enc.c because it does make a massive performance
-+difference on some boxes to have the functions code located close to
-+the des_encrypt2() function.
-+
-+9 Jan 1997 - des-som2.pl is now the correct perl script to use for
-+pentiums. It contains an inner loop from
-+Svend Olaf Mikkelsen <svolaf@inet.uni-c.dk> which does raw ecb DES calls at
-+273,000 per second. He had a previous version at 250,000 and the best
-+I was able to get was 203,000. The content has not changed, this is all
-+due to instruction sequencing (and actual instructions choice) which is able
-+to keep both functional units of the pentium going.
-+We may have lost the ugly register usage restrictions when x86 went 32 bit
-+but for the pentium it has been replaced by evil instruction ordering tricks.
-+
-+13 Jan 1997 - des-som3.pl, more optimizations from Svend Olaf.
-+raw DES at 281,000 per second on a pentium 100.
-+
---- /dev/null Tue Mar 11 13:02:56 2003
-+++ linux/crypto/ciphers/des/cbc_enc.c Mon Feb 9 13:51:03 2004
-@@ -0,0 +1,135 @@
-+/* crypto/des/cbc_enc.c */
-+/* Copyright (C) 1995-1997 Eric Young (eay@cryptsoft.com)
-+ * All rights reserved.
-+ *
-+ * This package is an SSL implementation written
-+ * by Eric Young (eay@cryptsoft.com).
-+ * The implementation was written so as to conform with Netscapes SSL.
-+ *
-+ * This library is free for commercial and non-commercial use as long as
-+ * the following conditions are aheared to. The following conditions
-+ * apply to all code found in this distribution, be it the RC4, RSA,
-+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
-+ * included with this distribution is covered by the same copyright terms
-+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
-+ *
-+ * Copyright remains Eric Young's, and as such any Copyright notices in
-+ * the code are not to be removed.
-+ * If this package is used in a product, Eric Young should be given attribution
-+ * as the author of the parts of the library used.
-+ * This can be in the form of a textual message at program startup or
-+ * in documentation (online or textual) provided with the package.
-+ *
-+ * Redistribution and use in source and binary forms, with or without
-+ * modification, are permitted provided that the following conditions
-+ * are met:
-+ * 1. Redistributions of source code must retain the copyright
-+ * notice, this list of conditions and the following disclaimer.
-+ * 2. Redistributions in binary form must reproduce the above copyright
-+ * notice, this list of conditions and the following disclaimer in the
-+ * documentation and/or other materials provided with the distribution.
-+ * 3. All advertising materials mentioning features or use of this software
-+ * must display the following acknowledgement:
-+ * "This product includes cryptographic software written by
-+ * Eric Young (eay@cryptsoft.com)"
-+ * The word 'cryptographic' can be left out if the rouines from the library
-+ * being used are not cryptographic related :-).
-+ * 4. If you include any Windows specific code (or a derivative thereof) from
-+ * the apps directory (application code) you must include an acknowledgement:
-+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``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 OR CONTRIBUTORS 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.
-+ *
-+ * The licence and distribution terms for any publically available version or
-+ * derivative of this code cannot be changed. i.e. this code cannot simply be
-+ * copied and put under another distribution licence
-+ * [including the GNU Public Licence.]
-+ */
-+
-+#include "des_locl.h"
-+
-+void des_cbc_encrypt(input, output, length, schedule, ivec, enc)
-+des_cblock (*input);
-+des_cblock (*output);
-+long length;
-+des_key_schedule schedule;
-+des_cblock (*ivec);
-+int enc;
-+ {
-+ register DES_LONG tin0,tin1;
-+ register DES_LONG tout0,tout1,xor0,xor1;
-+ register unsigned char *in,*out;
-+ register long l=length;
-+ DES_LONG tin[2];
-+ unsigned char *iv;
-+
-+ in=(unsigned char *)input;
-+ out=(unsigned char *)output;
-+ iv=(unsigned char *)ivec;
-+
-+ if (enc)
-+ {
-+ c2l(iv,tout0);
-+ c2l(iv,tout1);
-+ for (l-=8; l>=0; l-=8)
-+ {
-+ c2l(in,tin0);
-+ c2l(in,tin1);
-+ tin0^=tout0; tin[0]=tin0;
-+ tin1^=tout1; tin[1]=tin1;
-+ des_encrypt((DES_LONG *)tin,schedule,DES_ENCRYPT);
-+ tout0=tin[0]; l2c(tout0,out);
-+ tout1=tin[1]; l2c(tout1,out);
-+ }
-+ if (l != -8)
-+ {
-+ c2ln(in,tin0,tin1,l+8);
-+ tin0^=tout0; tin[0]=tin0;
-+ tin1^=tout1; tin[1]=tin1;
-+ des_encrypt((DES_LONG *)tin,schedule,DES_ENCRYPT);
-+ tout0=tin[0]; l2c(tout0,out);
-+ tout1=tin[1]; l2c(tout1,out);
-+ }
-+ }
-+ else
-+ {
-+ c2l(iv,xor0);
-+ c2l(iv,xor1);
-+ for (l-=8; l>=0; l-=8)
-+ {
-+ c2l(in,tin0); tin[0]=tin0;
-+ c2l(in,tin1); tin[1]=tin1;
-+ des_encrypt((DES_LONG *)tin,schedule,DES_DECRYPT);
-+ tout0=tin[0]^xor0;
-+ tout1=tin[1]^xor1;
-+ l2c(tout0,out);
-+ l2c(tout1,out);
-+ xor0=tin0;
-+ xor1=tin1;
-+ }
-+ if (l != -8)
-+ {
-+ c2l(in,tin0); tin[0]=tin0;
-+ c2l(in,tin1); tin[1]=tin1;
-+ des_encrypt((DES_LONG *)tin,schedule,DES_DECRYPT);
-+ tout0=tin[0]^xor0;
-+ tout1=tin[1]^xor1;
-+ l2cn(tout0,tout1,out,l+8);
-+ /* xor0=tin0;
-+ xor1=tin1; */
-+ }
-+ }
-+ tin0=tin1=tout0=tout1=xor0=xor1=0;
-+ tin[0]=tin[1]=0;
-+ }
-+
---- /dev/null Tue Mar 11 13:02:56 2003
-+++ linux/crypto/ciphers/des/des.doc Mon Feb 9 13:51:03 2004
-@@ -0,0 +1,505 @@
-+The DES library.
-+
-+Please note that this library was originally written to operate with
-+eBones, a version of Kerberos that had had encryption removed when it left
-+the USA and then put back in. As such there are some routines that I will
-+advise not using but they are still in the library for historical reasons.
-+For all calls that have an 'input' and 'output' variables, they can be the
-+same.
-+
-+This library requires the inclusion of 'des.h'.
-+
-+All of the encryption functions take what is called a des_key_schedule as an
-+argument. A des_key_schedule is an expanded form of the des key.
-+A des_key is 8 bytes of odd parity, the type used to hold the key is a
-+des_cblock. A des_cblock is an array of 8 bytes, often in this library
-+description I will refer to input bytes when the function specifies
-+des_cblock's as input or output, this just means that the variable should
-+be a multiple of 8 bytes.
-+
-+The define DES_ENCRYPT is passed to specify encryption, DES_DECRYPT to
-+specify decryption. The functions and global variable are as follows:
-+
-+int des_check_key;
-+ DES keys are supposed to be odd parity. If this variable is set to
-+ a non-zero value, des_set_key() will check that the key has odd
-+ parity and is not one of the known weak DES keys. By default this
-+ variable is turned off;
-+
-+void des_set_odd_parity(
-+des_cblock *key );
-+ This function takes a DES key (8 bytes) and sets the parity to odd.
-+
-+int des_is_weak_key(
-+des_cblock *key );
-+ This function returns a non-zero value if the DES key passed is a
-+ weak, DES key. If it is a weak key, don't use it, try a different
-+ one. If you are using 'random' keys, the chances of hitting a weak
-+ key are 1/2^52 so it is probably not worth checking for them.
-+
-+int des_set_key(
-+des_cblock *key,
-+des_key_schedule schedule);
-+ Des_set_key converts an 8 byte DES key into a des_key_schedule.
-+ A des_key_schedule is an expanded form of the key which is used to
-+ perform actual encryption. It can be regenerated from the DES key
-+ so it only needs to be kept when encryption or decryption is about
-+ to occur. Don't save or pass around des_key_schedule's since they
-+ are CPU architecture dependent, DES keys are not. If des_check_key
-+ is non zero, zero is returned if the key has the wrong parity or
-+ the key is a weak key, else 1 is returned.
-+
-+int des_key_sched(
-+des_cblock *key,
-+des_key_schedule schedule);
-+ An alternative name for des_set_key().
-+
-+int des_rw_mode; /* defaults to DES_PCBC_MODE */
-+ This flag holds either DES_CBC_MODE or DES_PCBC_MODE (default).
-+ This specifies the function to use in the enc_read() and enc_write()
-+ functions.
-+
-+void des_encrypt(
-+unsigned long *data,
-+des_key_schedule ks,
-+int enc);
-+ This is the DES encryption function that gets called by just about
-+ every other DES routine in the library. You should not use this
-+ function except to implement 'modes' of DES. I say this because the
-+ functions that call this routine do the conversion from 'char *' to
-+ long, and this needs to be done to make sure 'non-aligned' memory
-+ access do not occur. The characters are loaded 'little endian',
-+ have a look at my source code for more details on how I use this
-+ function.
-+ Data is a pointer to 2 unsigned long's and ks is the
-+ des_key_schedule to use. enc, is non zero specifies encryption,
-+ zero if decryption.
-+
-+void des_encrypt2(
-+unsigned long *data,
-+des_key_schedule ks,
-+int enc);
-+ This functions is the same as des_encrypt() except that the DES
-+ initial permutation (IP) and final permutation (FP) have been left
-+ out. As for des_encrypt(), you should not use this function.
-+ It is used by the routines in my library that implement triple DES.
-+ IP() des_encrypt2() des_encrypt2() des_encrypt2() FP() is the same
-+ as des_encrypt() des_encrypt() des_encrypt() except faster :-).
-+
-+void des_ecb_encrypt(
-+des_cblock *input,
-+des_cblock *output,
-+des_key_schedule ks,
-+int enc);
-+ This is the basic Electronic Code Book form of DES, the most basic
-+ form. Input is encrypted into output using the key represented by
-+ ks. If enc is non zero (DES_ENCRYPT), encryption occurs, otherwise
-+ decryption occurs. Input is 8 bytes long and output is 8 bytes.
-+ (the des_cblock structure is 8 chars).
-+
-+void des_ecb3_encrypt(
-+des_cblock *input,
-+des_cblock *output,
-+des_key_schedule ks1,
-+des_key_schedule ks2,
-+des_key_schedule ks3,
-+int enc);
-+ This is the 3 key EDE mode of ECB DES. What this means is that
-+ the 8 bytes of input is encrypted with ks1, decrypted with ks2 and
-+ then encrypted again with ks3, before being put into output;
-+ C=E(ks3,D(ks2,E(ks1,M))). There is a macro, des_ecb2_encrypt()
-+ that only takes 2 des_key_schedules that implements,
-+ C=E(ks1,D(ks2,E(ks1,M))) in that the final encrypt is done with ks1.
-+
-+void des_cbc_encrypt(
-+des_cblock *input,
-+des_cblock *output,
-+long length,
-+des_key_schedule ks,
-+des_cblock *ivec,
-+int enc);
-+ This routine implements DES in Cipher Block Chaining mode.
-+ Input, which should be a multiple of 8 bytes is encrypted
-+ (or decrypted) to output which will also be a multiple of 8 bytes.
-+ The number of bytes is in length (and from what I've said above,
-+ should be a multiple of 8). If length is not a multiple of 8, I'm
-+ not being held responsible :-). ivec is the initialisation vector.
-+ This function does not modify this variable. To correctly implement
-+ cbc mode, you need to do one of 2 things; copy the last 8 bytes of
-+ cipher text for use as the next ivec in your application,
-+ or use des_ncbc_encrypt().
-+ Only this routine has this problem with updating the ivec, all
-+ other routines that are implementing cbc mode update ivec.
-+
-+void des_ncbc_encrypt(
-+des_cblock *input,
-+des_cblock *output,
-+long length,
-+des_key_schedule sk,
-+des_cblock *ivec,
-+int enc);
-+ For historical reasons, des_cbc_encrypt() did not update the
-+ ivec with the value requires so that subsequent calls to
-+ des_cbc_encrypt() would 'chain'. This was needed so that the same
-+ 'length' values would not need to be used when decrypting.
-+ des_ncbc_encrypt() does the right thing. It is the same as
-+ des_cbc_encrypt accept that ivec is updates with the correct value
-+ to pass in subsequent calls to des_ncbc_encrypt(). I advise using
-+ des_ncbc_encrypt() instead of des_cbc_encrypt();
-+
-+void des_xcbc_encrypt(
-+des_cblock *input,
-+des_cblock *output,
-+long length,
-+des_key_schedule sk,
-+des_cblock *ivec,
-+des_cblock *inw,
-+des_cblock *outw,
-+int enc);
-+ This is RSA's DESX mode of DES. It uses inw and outw to
-+ 'whiten' the encryption. inw and outw are secret (unlike the iv)
-+ and are as such, part of the key. So the key is sort of 24 bytes.
-+ This is much better than cbc des.
-+
-+void des_3cbc_encrypt(
-+des_cblock *input,
-+des_cblock *output,
-+long length,
-+des_key_schedule sk1,
-+des_key_schedule sk2,
-+des_cblock *ivec1,
-+des_cblock *ivec2,
-+int enc);
-+ This function is flawed, do not use it. I have left it in the
-+ library because it is used in my des(1) program and will function
-+ correctly when used by des(1). If I removed the function, people
-+ could end up unable to decrypt files.
-+ This routine implements outer triple cbc encryption using 2 ks and
-+ 2 ivec's. Use des_ede2_cbc_encrypt() instead.
-+
-+void des_ede3_cbc_encrypt(
-+des_cblock *input,
-+des_cblock *output,
-+long length,
-+des_key_schedule ks1,
-+des_key_schedule ks2,
-+des_key_schedule ks3,
-+des_cblock *ivec,
-+int enc);
-+ This function implements inner triple CBC DES encryption with 3
-+ keys. What this means is that each 'DES' operation
-+ inside the cbc mode is really an C=E(ks3,D(ks2,E(ks1,M))).
-+ Again, this is cbc mode so an ivec is requires.
-+ This mode is used by SSL.
-+ There is also a des_ede2_cbc_encrypt() that only uses 2
-+ des_key_schedule's, the first being reused for the final
-+ encryption. C=E(ks1,D(ks2,E(ks1,M))). This form of triple DES
-+ is used by the RSAref library.
-+
-+void des_pcbc_encrypt(
-+des_cblock *input,
-+des_cblock *output,
-+long length,
-+des_key_schedule ks,
-+des_cblock *ivec,
-+int enc);
-+ This is Propagating Cipher Block Chaining mode of DES. It is used
-+ by Kerberos v4. It's parameters are the same as des_ncbc_encrypt().
-+
-+void des_cfb_encrypt(
-+unsigned char *in,
-+unsigned char *out,
-+int numbits,
-+long length,
-+des_key_schedule ks,
-+des_cblock *ivec,
-+int enc);
-+ Cipher Feedback Back mode of DES. This implementation 'feeds back'
-+ in numbit blocks. The input (and output) is in multiples of numbits
-+ bits. numbits should to be a multiple of 8 bits. Length is the
-+ number of bytes input. If numbits is not a multiple of 8 bits,
-+ the extra bits in the bytes will be considered padding. So if
-+ numbits is 12, for each 2 input bytes, the 4 high bits of the
-+ second byte will be ignored. So to encode 72 bits when using
-+ a numbits of 12 take 12 bytes. To encode 72 bits when using
-+ numbits of 9 will take 16 bytes. To encode 80 bits when using
-+ numbits of 16 will take 10 bytes. etc, etc. This padding will
-+ apply to both input and output.
-+
-+
-+void des_cfb64_encrypt(
-+unsigned char *in,
-+unsigned char *out,
-+long length,
-+des_key_schedule ks,
-+des_cblock *ivec,
-+int *num,
-+int enc);
-+ This is one of the more useful functions in this DES library, it
-+ implements CFB mode of DES with 64bit feedback. Why is this
-+ useful you ask? Because this routine will allow you to encrypt an
-+ arbitrary number of bytes, no 8 byte padding. Each call to this
-+ routine will encrypt the input bytes to output and then update ivec
-+ and num. num contains 'how far' we are though ivec. If this does
-+ not make much sense, read more about cfb mode of DES :-).
-+
-+void des_ede3_cfb64_encrypt(
-+unsigned char *in,
-+unsigned char *out,
-+long length,
-+des_key_schedule ks1,
-+des_key_schedule ks2,
-+des_key_schedule ks3,
-+des_cblock *ivec,
-+int *num,
-+int enc);
-+ Same as des_cfb64_encrypt() accept that the DES operation is
-+ triple DES. As usual, there is a macro for
-+ des_ede2_cfb64_encrypt() which reuses ks1.
-+
-+void des_ofb_encrypt(
-+unsigned char *in,
-+unsigned char *out,
-+int numbits,
-+long length,
-+des_key_schedule ks,
-+des_cblock *ivec);
-+ This is a implementation of Output Feed Back mode of DES. It is
-+ the same as des_cfb_encrypt() in that numbits is the size of the
-+ units dealt with during input and output (in bits).
-+
-+void des_ofb64_encrypt(
-+unsigned char *in,
-+unsigned char *out,
-+long length,
-+des_key_schedule ks,
-+des_cblock *ivec,
-+int *num);
-+ The same as des_cfb64_encrypt() except that it is Output Feed Back
-+ mode.
-+
-+void des_ede3_ofb64_encrypt(
-+unsigned char *in,
-+unsigned char *out,
-+long length,
-+des_key_schedule ks1,
-+des_key_schedule ks2,
-+des_key_schedule ks3,
-+des_cblock *ivec,
-+int *num);
-+ Same as des_ofb64_encrypt() accept that the DES operation is
-+ triple DES. As usual, there is a macro for
-+ des_ede2_ofb64_encrypt() which reuses ks1.
-+
-+int des_read_pw_string(
-+char *buf,
-+int length,
-+char *prompt,
-+int verify);
-+ This routine is used to get a password from the terminal with echo
-+ turned off. Buf is where the string will end up and length is the
-+ size of buf. Prompt is a string presented to the 'user' and if
-+ verify is set, the key is asked for twice and unless the 2 copies
-+ match, an error is returned. A return code of -1 indicates a
-+ system error, 1 failure due to use interaction, and 0 is success.
-+
-+unsigned long des_cbc_cksum(
-+des_cblock *input,
-+des_cblock *output,
-+long length,
-+des_key_schedule ks,
-+des_cblock *ivec);
-+ This function produces an 8 byte checksum from input that it puts in
-+ output and returns the last 4 bytes as a long. The checksum is
-+ generated via cbc mode of DES in which only the last 8 byes are
-+ kept. I would recommend not using this function but instead using
-+ the EVP_Digest routines, or at least using MD5 or SHA. This
-+ function is used by Kerberos v4 so that is why it stays in the
-+ library.
-+
-+char *des_fcrypt(
-+const char *buf,
-+const char *salt
-+char *ret);
-+ This is my fast version of the unix crypt(3) function. This version
-+ takes only a small amount of space relative to other fast
-+ crypt() implementations. This is different to the normal crypt
-+ in that the third parameter is the buffer that the return value
-+ is written into. It needs to be at least 14 bytes long. This
-+ function is thread safe, unlike the normal crypt.
-+
-+char *crypt(
-+const char *buf,
-+const char *salt);
-+ This function calls des_fcrypt() with a static array passed as the
-+ third parameter. This emulates the normal non-thread safe semantics
-+ of crypt(3).
-+
-+void des_string_to_key(
-+char *str,
-+des_cblock *key);
-+ This function takes str and converts it into a DES key. I would
-+ recommend using MD5 instead and use the first 8 bytes of output.
-+ When I wrote the first version of these routines back in 1990, MD5
-+ did not exist but I feel these routines are still sound. This
-+ routines is compatible with the one in MIT's libdes.
-+
-+void des_string_to_2keys(
-+char *str,
-+des_cblock *key1,
-+des_cblock *key2);
-+ This function takes str and converts it into 2 DES keys.
-+ I would recommend using MD5 and using the 16 bytes as the 2 keys.
-+ I have nothing against these 2 'string_to_key' routines, it's just
-+ that if you say that your encryption key is generated by using the
-+ 16 bytes of an MD5 hash, every-one knows how you generated your
-+ keys.
-+
-+int des_read_password(
-+des_cblock *key,
-+char *prompt,
-+int verify);
-+ This routine combines des_read_pw_string() with des_string_to_key().
-+
-+int des_read_2passwords(
-+des_cblock *key1,
-+des_cblock *key2,
-+char *prompt,
-+int verify);
-+ This routine combines des_read_pw_string() with des_string_to_2key().
-+
-+void des_random_seed(
-+des_cblock key);
-+ This routine sets a starting point for des_random_key().
-+
-+void des_random_key(
-+des_cblock ret);
-+ This function return a random key. Make sure to 'seed' the random
-+ number generator (with des_random_seed()) before using this function.
-+ I personally now use a MD5 based random number system.
-+
-+int des_enc_read(
-+int fd,
-+char *buf,
-+int len,
-+des_key_schedule ks,
-+des_cblock *iv);
-+ This function will write to a file descriptor the encrypted data
-+ from buf. This data will be preceded by a 4 byte 'byte count' and
-+ will be padded out to 8 bytes. The encryption is either CBC of
-+ PCBC depending on the value of des_rw_mode. If it is DES_PCBC_MODE,
-+ pcbc is used, if DES_CBC_MODE, cbc is used. The default is to use
-+ DES_PCBC_MODE.
-+
-+int des_enc_write(
-+int fd,
-+char *buf,
-+int len,
-+des_key_schedule ks,
-+des_cblock *iv);
-+ This routines read stuff written by des_enc_read() and decrypts it.
-+ I have used these routines quite a lot but I don't believe they are
-+ suitable for non-blocking io. If you are after a full
-+ authentication/encryption over networks, have a look at SSL instead.
-+
-+unsigned long des_quad_cksum(
-+des_cblock *input,
-+des_cblock *output,
-+long length,
-+int out_count,
-+des_cblock *seed);
-+ This is a function from Kerberos v4 that is not anything to do with
-+ DES but was needed. It is a cksum that is quicker to generate than
-+ des_cbc_cksum(); I personally would use MD5 routines now.
-+=====
-+Modes of DES
-+Quite a bit of the following information has been taken from
-+ AS 2805.5.2
-+ Australian Standard
-+ Electronic funds transfer - Requirements for interfaces,
-+ Part 5.2: Modes of operation for an n-bit block cipher algorithm
-+ Appendix A
-+
-+There are several different modes in which DES can be used, they are
-+as follows.
-+
-+Electronic Codebook Mode (ECB) (des_ecb_encrypt())
-+- 64 bits are enciphered at a time.
-+- The order of the blocks can be rearranged without detection.
-+- The same plaintext block always produces the same ciphertext block
-+ (for the same key) making it vulnerable to a 'dictionary attack'.
-+- An error will only affect one ciphertext block.
-+
-+Cipher Block Chaining Mode (CBC) (des_cbc_encrypt())
-+- a multiple of 64 bits are enciphered at a time.
-+- The CBC mode produces the same ciphertext whenever the same
-+ plaintext is encrypted using the same key and starting variable.
-+- The chaining operation makes the ciphertext blocks dependent on the
-+ current and all preceding plaintext blocks and therefore blocks can not
-+ be rearranged.
-+- The use of different starting variables prevents the same plaintext
-+ enciphering to the same ciphertext.
-+- An error will affect the current and the following ciphertext blocks.
-+
-+Cipher Feedback Mode (CFB) (des_cfb_encrypt())
-+- a number of bits (j) <= 64 are enciphered at a time.
-+- The CFB mode produces the same ciphertext whenever the same
-+ plaintext is encrypted using the same key and starting variable.
-+- The chaining operation makes the ciphertext variables dependent on the
-+ current and all preceding variables and therefore j-bit variables are
-+ chained together and can not be rearranged.
-+- The use of different starting variables prevents the same plaintext
-+ enciphering to the same ciphertext.
-+- The strength of the CFB mode depends on the size of k (maximal if
-+ j == k). In my implementation this is always the case.
-+- Selection of a small value for j will require more cycles through
-+ the encipherment algorithm per unit of plaintext and thus cause
-+ greater processing overheads.
-+- Only multiples of j bits can be enciphered.
-+- An error will affect the current and the following ciphertext variables.
-+
-+Output Feedback Mode (OFB) (des_ofb_encrypt())
-+- a number of bits (j) <= 64 are enciphered at a time.
-+- The OFB mode produces the same ciphertext whenever the same
-+ plaintext enciphered using the same key and starting variable. More
-+ over, in the OFB mode the same key stream is produced when the same
-+ key and start variable are used. Consequently, for security reasons
-+ a specific start variable should be used only once for a given key.
-+- The absence of chaining makes the OFB more vulnerable to specific attacks.
-+- The use of different start variables values prevents the same
-+ plaintext enciphering to the same ciphertext, by producing different
-+ key streams.
-+- Selection of a small value for j will require more cycles through
-+ the encipherment algorithm per unit of plaintext and thus cause
-+ greater processing overheads.
-+- Only multiples of j bits can be enciphered.
-+- OFB mode of operation does not extend ciphertext errors in the
-+ resultant plaintext output. Every bit error in the ciphertext causes
-+ only one bit to be in error in the deciphered plaintext.
-+- OFB mode is not self-synchronising. If the two operation of
-+ encipherment and decipherment get out of synchronism, the system needs
-+ to be re-initialised.
-+- Each re-initialisation should use a value of the start variable
-+ different from the start variable values used before with the same
-+ key. The reason for this is that an identical bit stream would be
-+ produced each time from the same parameters. This would be
-+ susceptible to a ' known plaintext' attack.
-+
-+Triple ECB Mode (des_ecb3_encrypt())
-+- Encrypt with key1, decrypt with key2 and encrypt with key3 again.
-+- As for ECB encryption but increases the key length to 168 bits.
-+ There are theoretic attacks that can be used that make the effective
-+ key length 112 bits, but this attack also requires 2^56 blocks of
-+ memory, not very likely, even for the NSA.
-+- If both keys are the same it is equivalent to encrypting once with
-+ just one key.
-+- If the first and last key are the same, the key length is 112 bits.
-+ There are attacks that could reduce the key space to 55 bit's but it
-+ requires 2^56 blocks of memory.
-+- If all 3 keys are the same, this is effectively the same as normal
-+ ecb mode.
-+
-+Triple CBC Mode (des_ede3_cbc_encrypt())
-+- Encrypt with key1, decrypt with key2 and then encrypt with key3.
-+- As for CBC encryption but increases the key length to 168 bits with
-+ the same restrictions as for triple ecb mode.
---- /dev/null Tue Mar 11 13:02:56 2003
-+++ linux/crypto/ciphers/des/des_crypt.man Mon Feb 9 13:51:03 2004
-@@ -0,0 +1,508 @@
-+.TH DES_CRYPT 3
-+.SH NAME
-+des_read_password, des_read_2password,
-+des_string_to_key, des_string_to_2key, des_read_pw_string,
-+des_random_key, des_set_key,
-+des_key_sched, des_ecb_encrypt, des_ecb3_encrypt, des_cbc_encrypt,
-+des_3cbc_encrypt,
-+des_pcbc_encrypt, des_cfb_encrypt, des_ofb_encrypt,
-+des_cbc_cksum, des_quad_cksum,
-+des_enc_read, des_enc_write, des_set_odd_parity,
-+des_is_weak_key, crypt \- (non USA) DES encryption
-+.SH SYNOPSIS
-+.nf
-+.nj
-+.ft B
-+#include <des.h>
-+.PP
-+.B int des_read_password(key,prompt,verify)
-+des_cblock *key;
-+char *prompt;
-+int verify;
-+.PP
-+.B int des_read_2password(key1,key2,prompt,verify)
-+des_cblock *key1,*key2;
-+char *prompt;
-+int verify;
-+.PP
-+.B int des_string_to_key(str,key)
-+char *str;
-+des_cblock *key;
-+.PP
-+.B int des_string_to_2keys(str,key1,key2)
-+char *str;
-+des_cblock *key1,*key2;
-+.PP
-+.B int des_read_pw_string(buf,length,prompt,verify)
-+char *buf;
-+int length;
-+char *prompt;
-+int verify;
-+.PP
-+.B int des_random_key(key)
-+des_cblock *key;
-+.PP
-+.B int des_set_key(key,schedule)
-+des_cblock *key;
-+des_key_schedule schedule;
-+.PP
-+.B int des_key_sched(key,schedule)
-+des_cblock *key;
-+des_key_schedule schedule;
-+.PP
-+.B int des_ecb_encrypt(input,output,schedule,encrypt)
-+des_cblock *input;
-+des_cblock *output;
-+des_key_schedule schedule;
-+int encrypt;
-+.PP
-+.B int des_ecb3_encrypt(input,output,ks1,ks2,encrypt)
-+des_cblock *input;
-+des_cblock *output;
-+des_key_schedule ks1,ks2;
-+int encrypt;
-+.PP
-+.B int des_cbc_encrypt(input,output,length,schedule,ivec,encrypt)
-+des_cblock *input;
-+des_cblock *output;
-+long length;
-+des_key_schedule schedule;
-+des_cblock *ivec;
-+int encrypt;
-+.PP
-+.B int des_3cbc_encrypt(input,output,length,sk1,sk2,ivec1,ivec2,encrypt)
-+des_cblock *input;
-+des_cblock *output;
-+long length;
-+des_key_schedule sk1;
-+des_key_schedule sk2;
-+des_cblock *ivec1;
-+des_cblock *ivec2;
-+int encrypt;
-+.PP
-+.B int des_pcbc_encrypt(input,output,length,schedule,ivec,encrypt)
-+des_cblock *input;
-+des_cblock *output;
-+long length;
-+des_key_schedule schedule;
-+des_cblock *ivec;
-+int encrypt;
-+.PP
-+.B int des_cfb_encrypt(input,output,numbits,length,schedule,ivec,encrypt)
-+unsigned char *input;
-+unsigned char *output;
-+int numbits;
-+long length;
-+des_key_schedule schedule;
-+des_cblock *ivec;
-+int encrypt;
-+.PP
-+.B int des_ofb_encrypt(input,output,numbits,length,schedule,ivec)
-+unsigned char *input,*output;
-+int numbits;
-+long length;
-+des_key_schedule schedule;
-+des_cblock *ivec;
-+.PP
-+.B unsigned long des_cbc_cksum(input,output,length,schedule,ivec)
-+des_cblock *input;
-+des_cblock *output;
-+long length;
-+des_key_schedule schedule;
-+des_cblock *ivec;
-+.PP
-+.B unsigned long des_quad_cksum(input,output,length,out_count,seed)
-+des_cblock *input;
-+des_cblock *output;
-+long length;
-+int out_count;
-+des_cblock *seed;
-+.PP
-+.B int des_check_key;
-+.PP
-+.B int des_enc_read(fd,buf,len,sched,iv)
-+int fd;
-+char *buf;
-+int len;
-+des_key_schedule sched;
-+des_cblock *iv;
-+.PP
-+.B int des_enc_write(fd,buf,len,sched,iv)
-+int fd;
-+char *buf;
-+int len;
-+des_key_schedule sched;
-+des_cblock *iv;
-+.PP
-+.B extern int des_rw_mode;
-+.PP
-+.B void des_set_odd_parity(key)
-+des_cblock *key;
-+.PP
-+.B int des_is_weak_key(key)
-+des_cblock *key;
-+.PP
-+.B char *crypt(passwd,salt)
-+char *passwd;
-+char *salt;
-+.PP
-+.fi
-+.SH DESCRIPTION
-+This library contains a fast implementation of the DES encryption
-+algorithm.
-+.PP
-+There are two phases to the use of DES encryption.
-+The first is the generation of a
-+.I des_key_schedule
-+from a key,
-+the second is the actual encryption.
-+A des key is of type
-+.I des_cblock.
-+This type is made from 8 characters with odd parity.
-+The least significant bit in the character is the parity bit.
-+The key schedule is an expanded form of the key; it is used to speed the
-+encryption process.
-+.PP
-+.I des_read_password
-+writes the string specified by prompt to the standard output,
-+turns off echo and reads an input string from standard input
-+until terminated with a newline.
-+If verify is non-zero, it prompts and reads the input again and verifies
-+that both entered passwords are the same.
-+The entered string is converted into a des key by using the
-+.I des_string_to_key
-+routine.
-+The new key is placed in the
-+.I des_cblock
-+that was passed (by reference) to the routine.
-+If there were no errors,
-+.I des_read_password
-+returns 0,
-+-1 is returned if there was a terminal error and 1 is returned for
-+any other error.
-+.PP
-+.I des_read_2password
-+operates in the same way as
-+.I des_read_password
-+except that it generates 2 keys by using the
-+.I des_string_to_2key
-+function.
-+.PP
-+.I des_read_pw_string
-+is called by
-+.I des_read_password
-+to read and verify a string from a terminal device.
-+The string is returned in
-+.I buf.
-+The size of
-+.I buf
-+is passed to the routine via the
-+.I length
-+parameter.
-+.PP
-+.I des_string_to_key
-+converts a string into a valid des key.
-+.PP
-+.I des_string_to_2key
-+converts a string into 2 valid des keys.
-+This routine is best suited for used to generate keys for use with
-+.I des_ecb3_encrypt.
-+.PP
-+.I des_random_key
-+returns a random key that is made of a combination of process id,
-+time and an increasing counter.
-+.PP
-+Before a des key can be used it is converted into a
-+.I des_key_schedule
-+via the
-+.I des_set_key
-+routine.
-+If the
-+.I des_check_key
-+flag is non-zero,
-+.I des_set_key
-+will check that the key passed is of odd parity and is not a week or
-+semi-weak key.
-+If the parity is wrong,
-+then -1 is returned.
-+If the key is a weak key,
-+then -2 is returned.
-+If an error is returned,
-+the key schedule is not generated.
-+.PP
-+.I des_key_sched
-+is another name for the
-+.I des_set_key
-+function.
-+.PP
-+The following routines mostly operate on an input and output stream of
-+.I des_cblock's.
-+.PP
-+.I des_ecb_encrypt
-+is the basic DES encryption routine that encrypts or decrypts a single 8-byte
-+.I des_cblock
-+in
-+.I electronic code book
-+mode.
-+It always transforms the input data, pointed to by
-+.I input,
-+into the output data,
-+pointed to by the
-+.I output
-+argument.
-+If the
-+.I encrypt
-+argument is non-zero (DES_ENCRYPT),
-+the
-+.I input
-+(cleartext) is encrypted in to the
-+.I output
-+(ciphertext) using the key_schedule specified by the
-+.I schedule
-+argument,
-+previously set via
-+.I des_set_key.
-+If
-+.I encrypt
-+is zero (DES_DECRYPT),
-+the
-+.I input
-+(now ciphertext)
-+is decrypted into the
-+.I output
-+(now cleartext).
-+Input and output may overlap.
-+No meaningful value is returned.
-+.PP
-+.I des_ecb3_encrypt
-+encrypts/decrypts the
-+.I input
-+block by using triple ecb DES encryption.
-+This involves encrypting the input with
-+.I ks1,
-+decryption with the key schedule
-+.I ks2,
-+and then encryption with the first again.
-+This routine greatly reduces the chances of brute force breaking of
-+DES and has the advantage of if
-+.I ks1
-+and
-+.I ks2
-+are the same, it is equivalent to just encryption using ecb mode and
-+.I ks1
-+as the key.
-+.PP
-+.I des_cbc_encrypt
-+encrypts/decrypts using the
-+.I cipher-block-chaining
-+mode of DES.
-+If the
-+.I encrypt
-+argument is non-zero,
-+the routine cipher-block-chain encrypts the cleartext data pointed to by the
-+.I input
-+argument into the ciphertext pointed to by the
-+.I output
-+argument,
-+using the key schedule provided by the
-+.I schedule
-+argument,
-+and initialisation vector provided by the
-+.I ivec
-+argument.
-+If the
-+.I length
-+argument is not an integral multiple of eight bytes,
-+the last block is copied to a temporary area and zero filled.
-+The output is always
-+an integral multiple of eight bytes.
-+To make multiple cbc encrypt calls on a large amount of data appear to
-+be one
-+.I des_cbc_encrypt
-+call, the
-+.I ivec
-+of subsequent calls should be the last 8 bytes of the output.
-+.PP
-+.I des_3cbc_encrypt
-+encrypts/decrypts the
-+.I input
-+block by using triple cbc DES encryption.
-+This involves encrypting the input with key schedule
-+.I ks1,
-+decryption with the key schedule
-+.I ks2,
-+and then encryption with the first again.
-+2 initialisation vectors are required,
-+.I ivec1
-+and
-+.I ivec2.
-+Unlike
-+.I des_cbc_encrypt,
-+these initialisation vectors are modified by the subroutine.
-+This routine greatly reduces the chances of brute force breaking of
-+DES and has the advantage of if
-+.I ks1
-+and
-+.I ks2
-+are the same, it is equivalent to just encryption using cbc mode and
-+.I ks1
-+as the key.
-+.PP
-+.I des_pcbc_encrypt
-+encrypt/decrypts using a modified block chaining mode.
-+It provides better error propagation characteristics than cbc
-+encryption.
-+.PP
-+.I des_cfb_encrypt
-+encrypt/decrypts using cipher feedback mode. This method takes an
-+array of characters as input and outputs and array of characters. It
-+does not require any padding to 8 character groups. Note: the ivec
-+variable is changed and the new changed value needs to be passed to
-+the next call to this function. Since this function runs a complete
-+DES ecb encryption per numbits, this function is only suggested for
-+use when sending small numbers of characters.
-+.PP
-+.I des_ofb_encrypt
-+encrypt using output feedback mode. This method takes an
-+array of characters as input and outputs and array of characters. It
-+does not require any padding to 8 character groups. Note: the ivec
-+variable is changed and the new changed value needs to be passed to
-+the next call to this function. Since this function runs a complete
-+DES ecb encryption per numbits, this function is only suggested for
-+use when sending small numbers of characters.
-+.PP
-+.I des_cbc_cksum
-+produces an 8 byte checksum based on the input stream (via cbc encryption).
-+The last 4 bytes of the checksum is returned and the complete 8 bytes is
-+placed in
-+.I output.
-+.PP
-+.I des_quad_cksum
-+returns a 4 byte checksum from the input bytes.
-+The algorithm can be iterated over the input,
-+depending on
-+.I out_count,
-+1, 2, 3 or 4 times.
-+If
-+.I output
-+is non-NULL,
-+the 8 bytes generated by each pass are written into
-+.I output.
-+.PP
-+.I des_enc_write
-+is used to write
-+.I len
-+bytes
-+to file descriptor
-+.I fd
-+from buffer
-+.I buf.
-+The data is encrypted via
-+.I pcbc_encrypt
-+(default) using
-+.I sched
-+for the key and
-+.I iv
-+as a starting vector.
-+The actual data send down
-+.I fd
-+consists of 4 bytes (in network byte order) containing the length of the
-+following encrypted data. The encrypted data then follows, padded with random
-+data out to a multiple of 8 bytes.
-+.PP
-+.I des_enc_read
-+is used to read
-+.I len
-+bytes
-+from file descriptor
-+.I fd
-+into buffer
-+.I buf.
-+The data being read from
-+.I fd
-+is assumed to have come from
-+.I des_enc_write
-+and is decrypted using
-+.I sched
-+for the key schedule and
-+.I iv
-+for the initial vector.
-+The
-+.I des_enc_read/des_enc_write
-+pair can be used to read/write to files, pipes and sockets.
-+I have used them in implementing a version of rlogin in which all
-+data is encrypted.
-+.PP
-+.I des_rw_mode
-+is used to specify the encryption mode to use with
-+.I des_enc_read
-+and
-+.I des_end_write.
-+If set to
-+.I DES_PCBC_MODE
-+(the default), des_pcbc_encrypt is used.
-+If set to
-+.I DES_CBC_MODE
-+des_cbc_encrypt is used.
-+These two routines and the variable are not part of the normal MIT library.
-+.PP
-+.I des_set_odd_parity
-+sets the parity of the passed
-+.I key
-+to odd. This routine is not part of the standard MIT library.
-+.PP
-+.I des_is_weak_key
-+returns 1 is the passed key is a weak key (pick again :-),
-+0 if it is ok.
-+This routine is not part of the standard MIT library.
-+.PP
-+.I crypt
-+is a replacement for the normal system crypt.
-+It is much faster than the system crypt.
-+.PP
-+.SH FILES
-+/usr/include/des.h
-+.br
-+/usr/lib/libdes.a
-+.PP
-+The encryption routines have been tested on 16bit, 32bit and 64bit
-+machines of various endian and even works under VMS.
-+.PP
-+.SH BUGS
-+.PP
-+If you think this manual is sparse,
-+read the des_crypt(3) manual from the MIT kerberos (or bones outside
-+of the USA) distribution.
-+.PP
-+.I des_cfb_encrypt
-+and
-+.I des_ofb_encrypt
-+operates on input of 8 bits. What this means is that if you set
-+numbits to 12, and length to 2, the first 12 bits will come from the 1st
-+input byte and the low half of the second input byte. The second 12
-+bits will have the low 8 bits taken from the 3rd input byte and the
-+top 4 bits taken from the 4th input byte. The same holds for output.
-+This function has been implemented this way because most people will
-+be using a multiple of 8 and because once you get into pulling bytes input
-+bytes apart things get ugly!
-+.PP
-+.I des_read_pw_string
-+is the most machine/OS dependent function and normally generates the
-+most problems when porting this code.
-+.PP
-+.I des_string_to_key
-+is probably different from the MIT version since there are lots
-+of fun ways to implement one-way encryption of a text string.
-+.PP
-+The routines are optimised for 32 bit machines and so are not efficient
-+on IBM PCs.
-+.PP
-+NOTE: extensive work has been done on this library since this document
-+was origionally written. Please try to read des.doc from the libdes
-+distribution since it is far more upto date and documents more of the
-+functions. Libdes is now also being shipped as part of SSLeay, a
-+general cryptographic library that amonst other things implements
-+netscapes SSL protocoll. The most recent version can be found in
-+SSLeay distributions.
-+.SH AUTHOR
-+Eric Young (eay@cryptsoft.com)
---- /dev/null Tue Mar 11 13:02:56 2003
-+++ linux/crypto/ciphers/des/des_enc.c Mon Feb 9 13:51:03 2004
-@@ -0,0 +1,502 @@
-+/* crypto/des/des_enc.c */
-+/* Copyright (C) 1995-1997 Eric Young (eay@cryptsoft.com)
-+ * All rights reserved.
-+ *
-+ * This package is an SSL implementation written
-+ * by Eric Young (eay@cryptsoft.com).
-+ * The implementation was written so as to conform with Netscapes SSL.
-+ *
-+ * This library is free for commercial and non-commercial use as long as
-+ * the following conditions are aheared to. The following conditions
-+ * apply to all code found in this distribution, be it the RC4, RSA,
-+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
-+ * included with this distribution is covered by the same copyright terms
-+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
-+ *
-+ * Copyright remains Eric Young's, and as such any Copyright notices in
-+ * the code are not to be removed.
-+ * If this package is used in a product, Eric Young should be given attribution
-+ * as the author of the parts of the library used.
-+ * This can be in the form of a textual message at program startup or
-+ * in documentation (online or textual) provided with the package.
-+ *
-+ * Redistribution and use in source and binary forms, with or without
-+ * modification, are permitted provided that the following conditions
-+ * are met:
-+ * 1. Redistributions of source code must retain the copyright
-+ * notice, this list of conditions and the following disclaimer.
-+ * 2. Redistributions in binary form must reproduce the above copyright
-+ * notice, this list of conditions and the following disclaimer in the
-+ * documentation and/or other materials provided with the distribution.
-+ * 3. All advertising materials mentioning features or use of this software
-+ * must display the following acknowledgement:
-+ * "This product includes cryptographic software written by
-+ * Eric Young (eay@cryptsoft.com)"
-+ * The word 'cryptographic' can be left out if the rouines from the library
-+ * being used are not cryptographic related :-).
-+ * 4. If you include any Windows specific code (or a derivative thereof) from
-+ * the apps directory (application code) you must include an acknowledgement:
-+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``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 OR CONTRIBUTORS 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.
-+ *
-+ * The licence and distribution terms for any publically available version or
-+ * derivative of this code cannot be changed. i.e. this code cannot simply be
-+ * copied and put under another distribution licence
-+ * [including the GNU Public Licence.]
-+ */
-+
-+#include "des_locl.h"
-+
-+void des_encrypt(data, ks, enc)
-+DES_LONG *data;
-+des_key_schedule ks;
-+int enc;
-+ {
-+ register DES_LONG l,r,t,u;
-+#ifdef DES_PTR
-+ register unsigned char *des_SP=(unsigned char *)des_SPtrans;
-+#endif
-+#ifndef DES_UNROLL
-+ register int i;
-+#endif
-+ register DES_LONG *s;
-+
-+ r=data[0];
-+ l=data[1];
-+
-+ IP(r,l);
-+ /* Things have been modified so that the initial rotate is
-+ * done outside the loop. This required the
-+ * des_SPtrans values in sp.h to be rotated 1 bit to the right.
-+ * One perl script later and things have a 5% speed up on a sparc2.
-+ * Thanks to Richard Outerbridge <71755.204@CompuServe.COM>
-+ * for pointing this out. */
-+ /* clear the top bits on machines with 8byte longs */
-+ /* shift left by 2 */
-+ r=ROTATE(r,29)&0xffffffffL;
-+ l=ROTATE(l,29)&0xffffffffL;
-+
-+ s=(DES_LONG *)ks;
-+ /* I don't know if it is worth the effort of loop unrolling the
-+ * inner loop */
-+ if (enc)
-+ {
-+#ifdef DES_UNROLL
-+ D_ENCRYPT(l,r, 0); /* 1 */
-+ D_ENCRYPT(r,l, 2); /* 2 */
-+ D_ENCRYPT(l,r, 4); /* 3 */
-+ D_ENCRYPT(r,l, 6); /* 4 */
-+ D_ENCRYPT(l,r, 8); /* 5 */
-+ D_ENCRYPT(r,l,10); /* 6 */
-+ D_ENCRYPT(l,r,12); /* 7 */
-+ D_ENCRYPT(r,l,14); /* 8 */
-+ D_ENCRYPT(l,r,16); /* 9 */
-+ D_ENCRYPT(r,l,18); /* 10 */
-+ D_ENCRYPT(l,r,20); /* 11 */
-+ D_ENCRYPT(r,l,22); /* 12 */
-+ D_ENCRYPT(l,r,24); /* 13 */
-+ D_ENCRYPT(r,l,26); /* 14 */
-+ D_ENCRYPT(l,r,28); /* 15 */
-+ D_ENCRYPT(r,l,30); /* 16 */
-+#else
-+ for (i=0; i<32; i+=8)
-+ {
-+ D_ENCRYPT(l,r,i+0); /* 1 */
-+ D_ENCRYPT(r,l,i+2); /* 2 */
-+ D_ENCRYPT(l,r,i+4); /* 3 */
-+ D_ENCRYPT(r,l,i+6); /* 4 */
-+ }
-+#endif
-+ }
-+ else
-+ {
-+#ifdef DES_UNROLL
-+ D_ENCRYPT(l,r,30); /* 16 */
-+ D_ENCRYPT(r,l,28); /* 15 */
-+ D_ENCRYPT(l,r,26); /* 14 */
-+ D_ENCRYPT(r,l,24); /* 13 */
-+ D_ENCRYPT(l,r,22); /* 12 */
-+ D_ENCRYPT(r,l,20); /* 11 */
-+ D_ENCRYPT(l,r,18); /* 10 */
-+ D_ENCRYPT(r,l,16); /* 9 */
-+ D_ENCRYPT(l,r,14); /* 8 */
-+ D_ENCRYPT(r,l,12); /* 7 */
-+ D_ENCRYPT(l,r,10); /* 6 */
-+ D_ENCRYPT(r,l, 8); /* 5 */
-+ D_ENCRYPT(l,r, 6); /* 4 */
-+ D_ENCRYPT(r,l, 4); /* 3 */
-+ D_ENCRYPT(l,r, 2); /* 2 */
-+ D_ENCRYPT(r,l, 0); /* 1 */
-+#else
-+ for (i=30; i>0; i-=8)
-+ {
-+ D_ENCRYPT(l,r,i-0); /* 16 */
-+ D_ENCRYPT(r,l,i-2); /* 15 */
-+ D_ENCRYPT(l,r,i-4); /* 14 */
-+ D_ENCRYPT(r,l,i-6); /* 13 */
-+ }
-+#endif
-+ }
-+
-+ /* rotate and clear the top bits on machines with 8byte longs */
-+ l=ROTATE(l,3)&0xffffffffL;
-+ r=ROTATE(r,3)&0xffffffffL;
-+
-+ FP(r,l);
-+ data[0]=l;
-+ data[1]=r;
-+ l=r=t=u=0;
-+ }
-+
-+void des_encrypt2(data, ks, enc)
-+DES_LONG *data;
-+des_key_schedule ks;
-+int enc;
-+ {
-+ register DES_LONG l,r,t,u;
-+#ifdef DES_PTR
-+ register unsigned char *des_SP=(unsigned char *)des_SPtrans;
-+#endif
-+#ifndef DES_UNROLL
-+ register int i;
-+#endif
-+ register DES_LONG *s;
-+
-+ r=data[0];
-+ l=data[1];
-+
-+ /* Things have been modified so that the initial rotate is
-+ * done outside the loop. This required the
-+ * des_SPtrans values in sp.h to be rotated 1 bit to the right.
-+ * One perl script later and things have a 5% speed up on a sparc2.
-+ * Thanks to Richard Outerbridge <71755.204@CompuServe.COM>
-+ * for pointing this out. */
-+ /* clear the top bits on machines with 8byte longs */
-+ r=ROTATE(r,29)&0xffffffffL;
-+ l=ROTATE(l,29)&0xffffffffL;
-+
-+ s=(DES_LONG *)ks;
-+ /* I don't know if it is worth the effort of loop unrolling the
-+ * inner loop */
-+ if (enc)
-+ {
-+#ifdef DES_UNROLL
-+ D_ENCRYPT(l,r, 0); /* 1 */
-+ D_ENCRYPT(r,l, 2); /* 2 */
-+ D_ENCRYPT(l,r, 4); /* 3 */
-+ D_ENCRYPT(r,l, 6); /* 4 */
-+ D_ENCRYPT(l,r, 8); /* 5 */
-+ D_ENCRYPT(r,l,10); /* 6 */
-+ D_ENCRYPT(l,r,12); /* 7 */
-+ D_ENCRYPT(r,l,14); /* 8 */
-+ D_ENCRYPT(l,r,16); /* 9 */
-+ D_ENCRYPT(r,l,18); /* 10 */
-+ D_ENCRYPT(l,r,20); /* 11 */
-+ D_ENCRYPT(r,l,22); /* 12 */
-+ D_ENCRYPT(l,r,24); /* 13 */
-+ D_ENCRYPT(r,l,26); /* 14 */
-+ D_ENCRYPT(l,r,28); /* 15 */
-+ D_ENCRYPT(r,l,30); /* 16 */
-+#else
-+ for (i=0; i<32; i+=8)
-+ {
-+ D_ENCRYPT(l,r,i+0); /* 1 */
-+ D_ENCRYPT(r,l,i+2); /* 2 */
-+ D_ENCRYPT(l,r,i+4); /* 3 */
-+ D_ENCRYPT(r,l,i+6); /* 4 */
-+ }
-+#endif
-+ }
-+ else
-+ {
-+#ifdef DES_UNROLL
-+ D_ENCRYPT(l,r,30); /* 16 */
-+ D_ENCRYPT(r,l,28); /* 15 */
-+ D_ENCRYPT(l,r,26); /* 14 */
-+ D_ENCRYPT(r,l,24); /* 13 */
-+ D_ENCRYPT(l,r,22); /* 12 */
-+ D_ENCRYPT(r,l,20); /* 11 */
-+ D_ENCRYPT(l,r,18); /* 10 */
-+ D_ENCRYPT(r,l,16); /* 9 */
-+ D_ENCRYPT(l,r,14); /* 8 */
-+ D_ENCRYPT(r,l,12); /* 7 */
-+ D_ENCRYPT(l,r,10); /* 6 */
-+ D_ENCRYPT(r,l, 8); /* 5 */
-+ D_ENCRYPT(l,r, 6); /* 4 */
-+ D_ENCRYPT(r,l, 4); /* 3 */
-+ D_ENCRYPT(l,r, 2); /* 2 */
-+ D_ENCRYPT(r,l, 0); /* 1 */
-+#else
-+ for (i=30; i>0; i-=8)
-+ {
-+ D_ENCRYPT(l,r,i-0); /* 16 */
-+ D_ENCRYPT(r,l,i-2); /* 15 */
-+ D_ENCRYPT(l,r,i-4); /* 14 */
-+ D_ENCRYPT(r,l,i-6); /* 13 */
-+ }
-+#endif
-+ }
-+ /* rotate and clear the top bits on machines with 8byte longs */
-+ data[0]=ROTATE(l,3)&0xffffffffL;
-+ data[1]=ROTATE(r,3)&0xffffffffL;
-+ l=r=t=u=0;
-+ }
-+
-+void des_encrypt3(data,ks1,ks2,ks3)
-+DES_LONG *data;
-+des_key_schedule ks1;
-+des_key_schedule ks2;
-+des_key_schedule ks3;
-+ {
-+ register DES_LONG l,r;
-+
-+ l=data[0];
-+ r=data[1];
-+ IP(l,r);
-+ data[0]=l;
-+ data[1]=r;
-+ des_encrypt2((DES_LONG *)data,ks1,DES_ENCRYPT);
-+ des_encrypt2((DES_LONG *)data,ks2,DES_DECRYPT);
-+ des_encrypt2((DES_LONG *)data,ks3,DES_ENCRYPT);
-+ l=data[0];
-+ r=data[1];
-+ FP(r,l);
-+ data[0]=l;
-+ data[1]=r;
-+ }
-+
-+void des_decrypt3(data,ks1,ks2,ks3)
-+DES_LONG *data;
-+des_key_schedule ks1;
-+des_key_schedule ks2;
-+des_key_schedule ks3;
-+ {
-+ register DES_LONG l,r;
-+
-+ l=data[0];
-+ r=data[1];
-+ IP(l,r);
-+ data[0]=l;
-+ data[1]=r;
-+ des_encrypt2((DES_LONG *)data,ks3,DES_DECRYPT);
-+ des_encrypt2((DES_LONG *)data,ks2,DES_ENCRYPT);
-+ des_encrypt2((DES_LONG *)data,ks1,DES_DECRYPT);
-+ l=data[0];
-+ r=data[1];
-+ FP(r,l);
-+ data[0]=l;
-+ data[1]=r;
-+ }
-+
-+#ifndef DES_DEFAULT_OPTIONS
-+
-+void des_ncbc_encrypt(input, output, length, schedule, ivec, enc)
-+des_cblock (*input);
-+des_cblock (*output);
-+long length;
-+des_key_schedule schedule;
-+des_cblock (*ivec);
-+int enc;
-+ {
-+ register DES_LONG tin0,tin1;
-+ register DES_LONG tout0,tout1,xor0,xor1;
-+ register unsigned char *in,*out;
-+ register long l=length;
-+ DES_LONG tin[2];
-+ unsigned char *iv;
-+
-+ in=(unsigned char *)input;
-+ out=(unsigned char *)output;
-+ iv=(unsigned char *)ivec;
-+
-+ if (enc)
-+ {
-+ c2l(iv,tout0);
-+ c2l(iv,tout1);
-+ for (l-=8; l>=0; l-=8)
-+ {
-+ c2l(in,tin0);
-+ c2l(in,tin1);
-+ tin0^=tout0; tin[0]=tin0;
-+ tin1^=tout1; tin[1]=tin1;
-+ des_encrypt((DES_LONG *)tin,schedule,DES_ENCRYPT);
-+ tout0=tin[0]; l2c(tout0,out);
-+ tout1=tin[1]; l2c(tout1,out);
-+ }
-+ if (l != -8)
-+ {
-+ c2ln(in,tin0,tin1,l+8);
-+ tin0^=tout0; tin[0]=tin0;
-+ tin1^=tout1; tin[1]=tin1;
-+ des_encrypt((DES_LONG *)tin,schedule,DES_ENCRYPT);
-+ tout0=tin[0]; l2c(tout0,out);
-+ tout1=tin[1]; l2c(tout1,out);
-+ }
-+ iv=(unsigned char *)ivec;
-+ l2c(tout0,iv);
-+ l2c(tout1,iv);
-+ }
-+ else
-+ {
-+ c2l(iv,xor0);
-+ c2l(iv,xor1);
-+ for (l-=8; l>=0; l-=8)
-+ {
-+ c2l(in,tin0); tin[0]=tin0;
-+ c2l(in,tin1); tin[1]=tin1;
-+ des_encrypt((DES_LONG *)tin,schedule,DES_DECRYPT);
-+ tout0=tin[0]^xor0;
-+ tout1=tin[1]^xor1;
-+ l2c(tout0,out);
-+ l2c(tout1,out);
-+ xor0=tin0;
-+ xor1=tin1;
-+ }
-+ if (l != -8)
-+ {
-+ c2l(in,tin0); tin[0]=tin0;
-+ c2l(in,tin1); tin[1]=tin1;
-+ des_encrypt((DES_LONG *)tin,schedule,DES_DECRYPT);
-+ tout0=tin[0]^xor0;
-+ tout1=tin[1]^xor1;
-+ l2cn(tout0,tout1,out,l+8);
-+ xor0=tin0;
-+ xor1=tin1;
-+ }
-+
-+ iv=(unsigned char *)ivec;
-+ l2c(xor0,iv);
-+ l2c(xor1,iv);
-+ }
-+ tin0=tin1=tout0=tout1=xor0=xor1=0;
-+ tin[0]=tin[1]=0;
-+ }
-+
-+void des_ede3_cbc_encrypt(input, output, length, ks1, ks2, ks3, ivec, enc)
-+des_cblock (*input);
-+des_cblock (*output);
-+long length;
-+des_key_schedule ks1;
-+des_key_schedule ks2;
-+des_key_schedule ks3;
-+des_cblock (*ivec);
-+int enc;
-+ {
-+ register DES_LONG tin0,tin1;
-+ register DES_LONG tout0,tout1,xor0,xor1;
-+ register unsigned char *in,*out;
-+ register long l=length;
-+ DES_LONG tin[2];
-+ unsigned char *iv;
-+
-+ in=(unsigned char *)input;
-+ out=(unsigned char *)output;
-+ iv=(unsigned char *)ivec;
-+
-+ if (enc)
-+ {
-+ c2l(iv,tout0);
-+ c2l(iv,tout1);
-+ for (l-=8; l>=0; l-=8)
-+ {
-+ c2l(in,tin0);
-+ c2l(in,tin1);
-+ tin0^=tout0;
-+ tin1^=tout1;
-+
-+ tin[0]=tin0;
-+ tin[1]=tin1;
-+ des_encrypt3((DES_LONG *)tin,ks1,ks2,ks3);
-+ tout0=tin[0];
-+ tout1=tin[1];
-+
-+ l2c(tout0,out);
-+ l2c(tout1,out);
-+ }
-+ if (l != -8)
-+ {
-+ c2ln(in,tin0,tin1,l+8);
-+ tin0^=tout0;
-+ tin1^=tout1;
-+
-+ tin[0]=tin0;
-+ tin[1]=tin1;
-+ des_encrypt3((DES_LONG *)tin,ks1,ks2,ks3);
-+ tout0=tin[0];
-+ tout1=tin[1];
-+
-+ l2c(tout0,out);
-+ l2c(tout1,out);
-+ }
-+ iv=(unsigned char *)ivec;
-+ l2c(tout0,iv);
-+ l2c(tout1,iv);
-+ }
-+ else
-+ {
-+ register DES_LONG t0,t1;
-+
-+ c2l(iv,xor0);
-+ c2l(iv,xor1);
-+ for (l-=8; l>=0; l-=8)
-+ {
-+ c2l(in,tin0);
-+ c2l(in,tin1);
-+
-+ t0=tin0;
-+ t1=tin1;
-+
-+ tin[0]=tin0;
-+ tin[1]=tin1;
-+ des_decrypt3((DES_LONG *)tin,ks1,ks2,ks3);
-+ tout0=tin[0];
-+ tout1=tin[1];
-+
-+ tout0^=xor0;
-+ tout1^=xor1;
-+ l2c(tout0,out);
-+ l2c(tout1,out);
-+ xor0=t0;
-+ xor1=t1;
-+ }
-+ if (l != -8)
-+ {
-+ c2l(in,tin0);
-+ c2l(in,tin1);
-+
-+ t0=tin0;
-+ t1=tin1;
-+
-+ tin[0]=tin0;
-+ tin[1]=tin1;
-+ des_decrypt3((DES_LONG *)tin,ks1,ks2,ks3);
-+ tout0=tin[0];
-+ tout1=tin[1];
-+
-+ tout0^=xor0;
-+ tout1^=xor1;
-+ l2cn(tout0,tout1,out,l+8);
-+ xor0=t0;
-+ xor1=t1;
-+ }
-+
-+ iv=(unsigned char *)ivec;
-+ l2c(xor0,iv);
-+ l2c(xor1,iv);
-+ }
-+ tin0=tin1=tout0=tout1=xor0=xor1=0;
-+ tin[0]=tin[1]=0;
-+ }
-+
-+#endif /* DES_DEFAULT_OPTIONS */
---- /dev/null Tue Mar 11 13:02:56 2003
-+++ linux/crypto/ciphers/des/des_locl.h Mon Feb 9 13:51:03 2004
-@@ -0,0 +1,515 @@
-+/* crypto/des/des_locl.org */
-+/* Copyright (C) 1995-1997 Eric Young (eay@cryptsoft.com)
-+ * All rights reserved.
-+ *
-+ * This package is an SSL implementation written
-+ * by Eric Young (eay@cryptsoft.com).
-+ * The implementation was written so as to conform with Netscapes SSL.
-+ *
-+ * This library is free for commercial and non-commercial use as long as
-+ * the following conditions are aheared to. The following conditions
-+ * apply to all code found in this distribution, be it the RC4, RSA,
-+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
-+ * included with this distribution is covered by the same copyright terms
-+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
-+ *
-+ * Copyright remains Eric Young's, and as such any Copyright notices in
-+ * the code are not to be removed.
-+ * If this package is used in a product, Eric Young should be given attribution
-+ * as the author of the parts of the library used.
-+ * This can be in the form of a textual message at program startup or
-+ * in documentation (online or textual) provided with the package.
-+ *
-+ * Redistribution and use in source and binary forms, with or without
-+ * modification, are permitted provided that the following conditions
-+ * are met:
-+ * 1. Redistributions of source code must retain the copyright
-+ * notice, this list of conditions and the following disclaimer.
-+ * 2. Redistributions in binary form must reproduce the above copyright
-+ * notice, this list of conditions and the following disclaimer in the
-+ * documentation and/or other materials provided with the distribution.
-+ * 3. All advertising materials mentioning features or use of this software
-+ * must display the following acknowledgement:
-+ * "This product includes cryptographic software written by
-+ * Eric Young (eay@cryptsoft.com)"
-+ * The word 'cryptographic' can be left out if the rouines from the library
-+ * being used are not cryptographic related :-).
-+ * 4. If you include any Windows specific code (or a derivative thereof) from
-+ * the apps directory (application code) you must include an acknowledgement:
-+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``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 OR CONTRIBUTORS 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.
-+ *
-+ * The licence and distribution terms for any publically available version or
-+ * derivative of this code cannot be changed. i.e. this code cannot simply be
-+ * copied and put under another distribution licence
-+ * [including the GNU Public Licence.]
-+ */
-+
-+/* WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
-+ *
-+ * Always modify des_locl.org since des_locl.h is automatically generated from
-+ * it during SSLeay configuration.
-+ *
-+ * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
-+ */
-+
-+#ifndef HEADER_DES_LOCL_H
-+#define HEADER_DES_LOCL_H
-+
-+#if defined(WIN32) || defined(WIN16)
-+#ifndef MSDOS
-+#define MSDOS
-+#endif
-+#endif
-+
-+#include "crypto/des.h"
-+
-+#ifndef DES_DEFAULT_OPTIONS
-+/* the following is tweaked from a config script, that is why it is a
-+ * protected undef/define */
-+#ifndef DES_PTR
-+#define DES_PTR
-+#endif
-+
-+/* This helps C compiler generate the correct code for multiple functional
-+ * units. It reduces register dependancies at the expense of 2 more
-+ * registers */
-+#ifndef DES_RISC1
-+#define DES_RISC1
-+#endif
-+
-+#ifndef DES_RISC2
-+#undef DES_RISC2
-+#endif
-+
-+#if defined(DES_RISC1) && defined(DES_RISC2)
-+YOU SHOULD NOT HAVE BOTH DES_RISC1 AND DES_RISC2 DEFINED!!!!!
-+#endif
-+
-+/* Unroll the inner loop, this sometimes helps, sometimes hinders.
-+ * Very mucy CPU dependant */
-+#ifndef DES_UNROLL
-+#define DES_UNROLL
-+#endif
-+
-+/* These default values were supplied by
-+ * Peter Gutman <pgut001@cs.auckland.ac.nz>
-+ * They are only used if nothing else has been defined */
-+#if !defined(DES_PTR) && !defined(DES_RISC1) && !defined(DES_RISC2) && !defined(DES_UNROLL)
-+/* Special defines which change the way the code is built depending on the
-+ CPU and OS. For SGI machines you can use _MIPS_SZLONG (32 or 64) to find
-+ even newer MIPS CPU's, but at the moment one size fits all for
-+ optimization options. Older Sparc's work better with only UNROLL, but
-+ there's no way to tell at compile time what it is you're running on */
-+
-+#if defined( sun ) /* Newer Sparc's */
-+ #define DES_PTR
-+ #define DES_RISC1
-+ #define DES_UNROLL
-+#elif defined( __ultrix ) /* Older MIPS */
-+ #define DES_PTR
-+ #define DES_RISC2
-+ #define DES_UNROLL
-+#elif defined( __osf1__ ) /* Alpha */
-+ #define DES_PTR
-+ #define DES_RISC2
-+#elif defined ( _AIX ) /* RS6000 */
-+ /* Unknown */
-+#elif defined( __hpux ) /* HP-PA */
-+ /* Unknown */
-+#elif defined( __aux ) /* 68K */
-+ /* Unknown */
-+#elif defined( __dgux ) /* 88K (but P6 in latest boxes) */
-+ #define DES_UNROLL
-+#elif defined( __sgi ) /* Newer MIPS */
-+ #define DES_PTR
-+ #define DES_RISC2
-+ #define DES_UNROLL
-+#elif defined( i386 ) /* x86 boxes, should be gcc */
-+ #define DES_PTR
-+ #define DES_RISC1
-+ #define DES_UNROLL
-+#endif /* Systems-specific speed defines */
-+#endif
-+
-+#endif /* DES_DEFAULT_OPTIONS */
-+
-+#ifdef MSDOS /* Visual C++ 2.1 (Windows NT/95) */
-+#include <stdlib.h>
-+#include <errno.h>
-+#include <time.h>
-+#include <io.h>
-+#ifndef RAND
-+#define RAND
-+#endif
-+#undef NOPROTO
-+#endif
-+
-+#if defined(__STDC__) || defined(VMS) || defined(M_XENIX) || defined(MSDOS)
-+#ifndef __KERNEL__
-+#include <string.h>
-+#else
-+#include <linux/string.h>
-+#endif
-+#endif
-+
-+#ifndef RAND
-+#define RAND
-+#endif
-+
-+#ifdef linux
-+#undef RAND
-+#endif
-+
-+#ifdef MSDOS
-+#define getpid() 2
-+#define RAND
-+#undef NOPROTO
-+#endif
-+
-+#if defined(NOCONST)
-+#define const
-+#endif
-+
-+#ifdef __STDC__
-+#undef NOPROTO
-+#endif
-+
-+#ifdef RAND
-+#define srandom(s) srand(s)
-+#define random rand
-+#endif
-+
-+#define ITERATIONS 16
-+#define HALF_ITERATIONS 8
-+
-+/* used in des_read and des_write */
-+#define MAXWRITE (1024*16)
-+#define BSIZE (MAXWRITE+4)
-+
-+#define c2l(c,l) (l =((DES_LONG)(*((c)++))) , \
-+ l|=((DES_LONG)(*((c)++)))<< 8L, \
-+ l|=((DES_LONG)(*((c)++)))<<16L, \
-+ l|=((DES_LONG)(*((c)++)))<<24L)
-+
-+/* NOTE - c is not incremented as per c2l */
-+#define c2ln(c,l1,l2,n) { \
-+ c+=n; \
-+ l1=l2=0; \
-+ switch (n) { \
-+ case 8: l2 =((DES_LONG)(*(--(c))))<<24L; \
-+ case 7: l2|=((DES_LONG)(*(--(c))))<<16L; \
-+ case 6: l2|=((DES_LONG)(*(--(c))))<< 8L; \
-+ case 5: l2|=((DES_LONG)(*(--(c)))); \
-+ case 4: l1 =((DES_LONG)(*(--(c))))<<24L; \
-+ case 3: l1|=((DES_LONG)(*(--(c))))<<16L; \
-+ case 2: l1|=((DES_LONG)(*(--(c))))<< 8L; \
-+ case 1: l1|=((DES_LONG)(*(--(c)))); \
-+ } \
-+ }
-+
-+#define l2c(l,c) (*((c)++)=(unsigned char)(((l) )&0xff), \
-+ *((c)++)=(unsigned char)(((l)>> 8L)&0xff), \
-+ *((c)++)=(unsigned char)(((l)>>16L)&0xff), \
-+ *((c)++)=(unsigned char)(((l)>>24L)&0xff))
-+
-+/* replacements for htonl and ntohl since I have no idea what to do
-+ * when faced with machines with 8 byte longs. */
-+#define HDRSIZE 4
-+
-+#define n2l(c,l) (l =((DES_LONG)(*((c)++)))<<24L, \
-+ l|=((DES_LONG)(*((c)++)))<<16L, \
-+ l|=((DES_LONG)(*((c)++)))<< 8L, \
-+ l|=((DES_LONG)(*((c)++))))
-+
-+#define l2n(l,c) (*((c)++)=(unsigned char)(((l)>>24L)&0xff), \
-+ *((c)++)=(unsigned char)(((l)>>16L)&0xff), \
-+ *((c)++)=(unsigned char)(((l)>> 8L)&0xff), \
-+ *((c)++)=(unsigned char)(((l) )&0xff))
-+
-+/* NOTE - c is not incremented as per l2c */
-+#define l2cn(l1,l2,c,n) { \
-+ c+=n; \
-+ switch (n) { \
-+ case 8: *(--(c))=(unsigned char)(((l2)>>24L)&0xff); \
-+ case 7: *(--(c))=(unsigned char)(((l2)>>16L)&0xff); \
-+ case 6: *(--(c))=(unsigned char)(((l2)>> 8L)&0xff); \
-+ case 5: *(--(c))=(unsigned char)(((l2) )&0xff); \
-+ case 4: *(--(c))=(unsigned char)(((l1)>>24L)&0xff); \
-+ case 3: *(--(c))=(unsigned char)(((l1)>>16L)&0xff); \
-+ case 2: *(--(c))=(unsigned char)(((l1)>> 8L)&0xff); \
-+ case 1: *(--(c))=(unsigned char)(((l1) )&0xff); \
-+ } \
-+ }
-+
-+#if defined(WIN32)
-+#define ROTATE(a,n) (_lrotr(a,n))
-+#else
-+#define ROTATE(a,n) (((a)>>(n))+((a)<<(32-(n))))
-+#endif
-+
-+/* Don't worry about the LOAD_DATA() stuff, that is used by
-+ * fcrypt() to add it's little bit to the front */
-+
-+#ifdef DES_FCRYPT
-+
-+#define LOAD_DATA_tmp(R,S,u,t,E0,E1) \
-+ { DES_LONG tmp; LOAD_DATA(R,S,u,t,E0,E1,tmp); }
-+
-+#define LOAD_DATA(R,S,u,t,E0,E1,tmp) \
-+ t=R^(R>>16L); \
-+ u=t&E0; t&=E1; \
-+ tmp=(u<<16); u^=R^s[S ]; u^=tmp; \
-+ tmp=(t<<16); t^=R^s[S+1]; t^=tmp
-+#else
-+#define LOAD_DATA_tmp(a,b,c,d,e,f) LOAD_DATA(a,b,c,d,e,f,g)
-+#define LOAD_DATA(R,S,u,t,E0,E1,tmp) \
-+ u=R^s[S ]; \
-+ t=R^s[S+1]
-+#endif
-+
-+/* The changes to this macro may help or hinder, depending on the
-+ * compiler and the achitecture. gcc2 always seems to do well :-).
-+ * Inspired by Dana How <how@isl.stanford.edu>
-+ * DO NOT use the alternative version on machines with 8 byte longs.
-+ * It does not seem to work on the Alpha, even when DES_LONG is 4
-+ * bytes, probably an issue of accessing non-word aligned objects :-( */
-+#ifdef DES_PTR
-+
-+/* It recently occured to me that 0^0^0^0^0^0^0 == 0, so there
-+ * is no reason to not xor all the sub items together. This potentially
-+ * saves a register since things can be xored directly into L */
-+
-+#if defined(DES_RISC1) || defined(DES_RISC2)
-+#ifdef DES_RISC1
-+#define D_ENCRYPT(LL,R,S) { \
-+ unsigned int u1,u2,u3; \
-+ LOAD_DATA(R,S,u,t,E0,E1,u1); \
-+ u2=(int)u>>8L; \
-+ u1=(int)u&0xfc; \
-+ u2&=0xfc; \
-+ t=ROTATE(t,4); \
-+ u>>=16L; \
-+ LL^= *(DES_LONG *)((unsigned char *)des_SP +u1); \
-+ LL^= *(DES_LONG *)((unsigned char *)des_SP+0x200+u2); \
-+ u3=(int)(u>>8L); \
-+ u1=(int)u&0xfc; \
-+ u3&=0xfc; \
-+ LL^= *(DES_LONG *)((unsigned char *)des_SP+0x400+u1); \
-+ LL^= *(DES_LONG *)((unsigned char *)des_SP+0x600+u3); \
-+ u2=(int)t>>8L; \
-+ u1=(int)t&0xfc; \
-+ u2&=0xfc; \
-+ t>>=16L; \
-+ LL^= *(DES_LONG *)((unsigned char *)des_SP+0x100+u1); \
-+ LL^= *(DES_LONG *)((unsigned char *)des_SP+0x300+u2); \
-+ u3=(int)t>>8L; \
-+ u1=(int)t&0xfc; \
-+ u3&=0xfc; \
-+ LL^= *(DES_LONG *)((unsigned char *)des_SP+0x500+u1); \
-+ LL^= *(DES_LONG *)((unsigned char *)des_SP+0x700+u3); }
-+#endif
-+#ifdef DES_RISC2
-+#define D_ENCRYPT(LL,R,S) { \
-+ unsigned int u1,u2,s1,s2; \
-+ LOAD_DATA(R,S,u,t,E0,E1,u1); \
-+ u2=(int)u>>8L; \
-+ u1=(int)u&0xfc; \
-+ u2&=0xfc; \
-+ t=ROTATE(t,4); \
-+ LL^= *(DES_LONG *)((unsigned char *)des_SP +u1); \
-+ LL^= *(DES_LONG *)((unsigned char *)des_SP+0x200+u2); \
-+ s1=(int)(u>>16L); \
-+ s2=(int)(u>>24L); \
-+ s1&=0xfc; \
-+ s2&=0xfc; \
-+ LL^= *(DES_LONG *)((unsigned char *)des_SP+0x400+s1); \
-+ LL^= *(DES_LONG *)((unsigned char *)des_SP+0x600+s2); \
-+ u2=(int)t>>8L; \
-+ u1=(int)t&0xfc; \
-+ u2&=0xfc; \
-+ LL^= *(DES_LONG *)((unsigned char *)des_SP+0x100+u1); \
-+ LL^= *(DES_LONG *)((unsigned char *)des_SP+0x300+u2); \
-+ s1=(int)(t>>16L); \
-+ s2=(int)(t>>24L); \
-+ s1&=0xfc; \
-+ s2&=0xfc; \
-+ LL^= *(DES_LONG *)((unsigned char *)des_SP+0x500+s1); \
-+ LL^= *(DES_LONG *)((unsigned char *)des_SP+0x700+s2); }
-+#endif
-+#else
-+#define D_ENCRYPT(LL,R,S) { \
-+ LOAD_DATA_tmp(R,S,u,t,E0,E1); \
-+ t=ROTATE(t,4); \
-+ LL^= \
-+ *(DES_LONG *)((unsigned char *)des_SP +((u )&0xfc))^ \
-+ *(DES_LONG *)((unsigned char *)des_SP+0x200+((u>> 8L)&0xfc))^ \
-+ *(DES_LONG *)((unsigned char *)des_SP+0x400+((u>>16L)&0xfc))^ \
-+ *(DES_LONG *)((unsigned char *)des_SP+0x600+((u>>24L)&0xfc))^ \
-+ *(DES_LONG *)((unsigned char *)des_SP+0x100+((t )&0xfc))^ \
-+ *(DES_LONG *)((unsigned char *)des_SP+0x300+((t>> 8L)&0xfc))^ \
-+ *(DES_LONG *)((unsigned char *)des_SP+0x500+((t>>16L)&0xfc))^ \
-+ *(DES_LONG *)((unsigned char *)des_SP+0x700+((t>>24L)&0xfc)); }
-+#endif
-+
-+#else /* original version */
-+
-+#if defined(DES_RISC1) || defined(DES_RISC2)
-+#ifdef DES_RISC1
-+#define D_ENCRYPT(LL,R,S) {\
-+ unsigned int u1,u2,u3; \
-+ LOAD_DATA(R,S,u,t,E0,E1,u1); \
-+ u>>=2L; \
-+ t=ROTATE(t,6); \
-+ u2=(int)u>>8L; \
-+ u1=(int)u&0x3f; \
-+ u2&=0x3f; \
-+ u>>=16L; \
-+ LL^=des_SPtrans[0][u1]; \
-+ LL^=des_SPtrans[2][u2]; \
-+ u3=(int)u>>8L; \
-+ u1=(int)u&0x3f; \
-+ u3&=0x3f; \
-+ LL^=des_SPtrans[4][u1]; \
-+ LL^=des_SPtrans[6][u3]; \
-+ u2=(int)t>>8L; \
-+ u1=(int)t&0x3f; \
-+ u2&=0x3f; \
-+ t>>=16L; \
-+ LL^=des_SPtrans[1][u1]; \
-+ LL^=des_SPtrans[3][u2]; \
-+ u3=(int)t>>8L; \
-+ u1=(int)t&0x3f; \
-+ u3&=0x3f; \
-+ LL^=des_SPtrans[5][u1]; \
-+ LL^=des_SPtrans[7][u3]; }
-+#endif
-+#ifdef DES_RISC2
-+#define D_ENCRYPT(LL,R,S) {\
-+ unsigned int u1,u2,s1,s2; \
-+ LOAD_DATA(R,S,u,t,E0,E1,u1); \
-+ u>>=2L; \
-+ t=ROTATE(t,6); \
-+ u2=(int)u>>8L; \
-+ u1=(int)u&0x3f; \
-+ u2&=0x3f; \
-+ LL^=des_SPtrans[0][u1]; \
-+ LL^=des_SPtrans[2][u2]; \
-+ s1=(int)u>>16L; \
-+ s2=(int)u>>24L; \
-+ s1&=0x3f; \
-+ s2&=0x3f; \
-+ LL^=des_SPtrans[4][s1]; \
-+ LL^=des_SPtrans[6][s2]; \
-+ u2=(int)t>>8L; \
-+ u1=(int)t&0x3f; \
-+ u2&=0x3f; \
-+ LL^=des_SPtrans[1][u1]; \
-+ LL^=des_SPtrans[3][u2]; \
-+ s1=(int)t>>16; \
-+ s2=(int)t>>24L; \
-+ s1&=0x3f; \
-+ s2&=0x3f; \
-+ LL^=des_SPtrans[5][s1]; \
-+ LL^=des_SPtrans[7][s2]; }
-+#endif
-+
-+#else
-+
-+#define D_ENCRYPT(LL,R,S) {\
-+ LOAD_DATA_tmp(R,S,u,t,E0,E1); \
-+ t=ROTATE(t,4); \
-+ LL^=\
-+ des_SPtrans[0][(u>> 2L)&0x3f]^ \
-+ des_SPtrans[2][(u>>10L)&0x3f]^ \
-+ des_SPtrans[4][(u>>18L)&0x3f]^ \
-+ des_SPtrans[6][(u>>26L)&0x3f]^ \
-+ des_SPtrans[1][(t>> 2L)&0x3f]^ \
-+ des_SPtrans[3][(t>>10L)&0x3f]^ \
-+ des_SPtrans[5][(t>>18L)&0x3f]^ \
-+ des_SPtrans[7][(t>>26L)&0x3f]; }
-+#endif
-+#endif
-+
-+ /* IP and FP
-+ * The problem is more of a geometric problem that random bit fiddling.
-+ 0 1 2 3 4 5 6 7 62 54 46 38 30 22 14 6
-+ 8 9 10 11 12 13 14 15 60 52 44 36 28 20 12 4
-+ 16 17 18 19 20 21 22 23 58 50 42 34 26 18 10 2
-+ 24 25 26 27 28 29 30 31 to 56 48 40 32 24 16 8 0
-+
-+ 32 33 34 35 36 37 38 39 63 55 47 39 31 23 15 7
-+ 40 41 42 43 44 45 46 47 61 53 45 37 29 21 13 5
-+ 48 49 50 51 52 53 54 55 59 51 43 35 27 19 11 3
-+ 56 57 58 59 60 61 62 63 57 49 41 33 25 17 9 1
-+
-+ The output has been subject to swaps of the form
-+ 0 1 -> 3 1 but the odd and even bits have been put into
-+ 2 3 2 0
-+ different words. The main trick is to remember that
-+ t=((l>>size)^r)&(mask);
-+ r^=t;
-+ l^=(t<<size);
-+ can be used to swap and move bits between words.
-+
-+ So l = 0 1 2 3 r = 16 17 18 19
-+ 4 5 6 7 20 21 22 23
-+ 8 9 10 11 24 25 26 27
-+ 12 13 14 15 28 29 30 31
-+ becomes (for size == 2 and mask == 0x3333)
-+ t = 2^16 3^17 -- -- l = 0 1 16 17 r = 2 3 18 19
-+ 6^20 7^21 -- -- 4 5 20 21 6 7 22 23
-+ 10^24 11^25 -- -- 8 9 24 25 10 11 24 25
-+ 14^28 15^29 -- -- 12 13 28 29 14 15 28 29
-+
-+ Thanks for hints from Richard Outerbridge - he told me IP&FP
-+ could be done in 15 xor, 10 shifts and 5 ands.
-+ When I finally started to think of the problem in 2D
-+ I first got ~42 operations without xors. When I remembered
-+ how to use xors :-) I got it to its final state.
-+ */
-+#define PERM_OP(a,b,t,n,m) ((t)=((((a)>>(n))^(b))&(m)),\
-+ (b)^=(t),\
-+ (a)^=((t)<<(n)))
-+
-+#define IP(l,r) \
-+ { \
-+ register DES_LONG tt; \
-+ PERM_OP(r,l,tt, 4,0x0f0f0f0fL); \
-+ PERM_OP(l,r,tt,16,0x0000ffffL); \
-+ PERM_OP(r,l,tt, 2,0x33333333L); \
-+ PERM_OP(l,r,tt, 8,0x00ff00ffL); \
-+ PERM_OP(r,l,tt, 1,0x55555555L); \
-+ }
-+
-+#define FP(l,r) \
-+ { \
-+ register DES_LONG tt; \
-+ PERM_OP(l,r,tt, 1,0x55555555L); \
-+ PERM_OP(r,l,tt, 8,0x00ff00ffL); \
-+ PERM_OP(l,r,tt, 2,0x33333333L); \
-+ PERM_OP(r,l,tt,16,0x0000ffffL); \
-+ PERM_OP(l,r,tt, 4,0x0f0f0f0fL); \
-+ }
-+
-+extern const DES_LONG des_SPtrans[8][64];
-+
-+#ifndef NOPROTO
-+void fcrypt_body(DES_LONG *out,des_key_schedule ks,
-+ DES_LONG Eswap0, DES_LONG Eswap1);
-+#else
-+void fcrypt_body();
-+#endif
-+
-+#endif
---- /dev/null Tue Mar 11 13:02:56 2003
-+++ linux/crypto/ciphers/des/des_opts.c Mon Feb 9 13:51:03 2004
-@@ -0,0 +1,620 @@
-+/* crypto/des/des_opts.c */
-+/* Copyright (C) 1995-1997 Eric Young (eay@cryptsoft.com)
-+ * All rights reserved.
-+ *
-+ * This package is an SSL implementation written
-+ * by Eric Young (eay@cryptsoft.com).
-+ * The implementation was written so as to conform with Netscapes SSL.
-+ *
-+ * This library is free for commercial and non-commercial use as long as
-+ * the following conditions are aheared to. The following conditions
-+ * apply to all code found in this distribution, be it the RC4, RSA,
-+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
-+ * included with this distribution is covered by the same copyright terms
-+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
-+ *
-+ * Copyright remains Eric Young's, and as such any Copyright notices in
-+ * the code are not to be removed.
-+ * If this package is used in a product, Eric Young should be given attribution
-+ * as the author of the parts of the library used.
-+ * This can be in the form of a textual message at program startup or
-+ * in documentation (online or textual) provided with the package.
-+ *
-+ * Redistribution and use in source and binary forms, with or without
-+ * modification, are permitted provided that the following conditions
-+ * are met:
-+ * 1. Redistributions of source code must retain the copyright
-+ * notice, this list of conditions and the following disclaimer.
-+ * 2. Redistributions in binary form must reproduce the above copyright
-+ * notice, this list of conditions and the following disclaimer in the
-+ * documentation and/or other materials provided with the distribution.
-+ * 3. All advertising materials mentioning features or use of this software
-+ * must display the following acknowledgement:
-+ * "This product includes cryptographic software written by
-+ * Eric Young (eay@cryptsoft.com)"
-+ * The word 'cryptographic' can be left out if the rouines from the library
-+ * being used are not cryptographic related :-).
-+ * 4. If you include any Windows specific code (or a derivative thereof) from
-+ * the apps directory (application code) you must include an acknowledgement:
-+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``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 OR CONTRIBUTORS 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.
-+ *
-+ * The licence and distribution terms for any publically available version or
-+ * derivative of this code cannot be changed. i.e. this code cannot simply be
-+ * copied and put under another distribution licence
-+ * [including the GNU Public Licence.]
-+ */
-+
-+/* define PART1, PART2, PART3 or PART4 to build only with a few of the options.
-+ * This is for machines with 64k code segment size restrictions. */
-+
-+#ifndef MSDOS
-+#define TIMES
-+#endif
-+
-+#include <stdio.h>
-+#ifndef MSDOS
-+#include <unistd.h>
-+#else
-+#include <io.h>
-+extern void exit();
-+#endif
-+#include <signal.h>
-+#ifndef VMS
-+#ifndef _IRIX
-+#include <time.h>
-+#endif
-+#ifdef TIMES
-+#include <sys/types.h>
-+#include <sys/times.h>
-+#endif
-+#else /* VMS */
-+#include <types.h>
-+struct tms {
-+ time_t tms_utime;
-+ time_t tms_stime;
-+ time_t tms_uchild; /* I dunno... */
-+ time_t tms_uchildsys; /* so these names are a guess :-) */
-+ }
-+#endif
-+#ifndef TIMES
-+#include <sys/timeb.h>
-+#endif
-+
-+#ifdef sun
-+#include <limits.h>
-+#include <sys/param.h>
-+#endif
-+
-+#include "des_locl.h"
-+#include "spr.h"
-+
-+#define DES_DEFAULT_OPTIONS
-+
-+#if !defined(PART1) && !defined(PART2) && !defined(PART3) && !defined(PART4)
-+#define PART1
-+#define PART2
-+#define PART3
-+#define PART4
-+#endif
-+
-+#ifdef PART1
-+
-+#undef DES_UNROLL
-+#undef DES_RISC1
-+#undef DES_RISC2
-+#undef DES_PTR
-+#undef D_ENCRYPT
-+#define des_encrypt des_encrypt_u4_cisc_idx
-+#define des_encrypt2 des_encrypt2_u4_cisc_idx
-+#define des_encrypt3 des_encrypt3_u4_cisc_idx
-+#define des_decrypt3 des_decrypt3_u4_cisc_idx
-+#undef HEADER_DES_LOCL_H
-+#include "des_enc.c"
-+
-+#define DES_UNROLL
-+#undef DES_RISC1
-+#undef DES_RISC2
-+#undef DES_PTR
-+#undef D_ENCRYPT
-+#undef des_encrypt
-+#undef des_encrypt2
-+#undef des_encrypt3
-+#undef des_decrypt3
-+#define des_encrypt des_encrypt_u16_cisc_idx
-+#define des_encrypt2 des_encrypt2_u16_cisc_idx
-+#define des_encrypt3 des_encrypt3_u16_cisc_idx
-+#define des_decrypt3 des_decrypt3_u16_cisc_idx
-+#undef HEADER_DES_LOCL_H
-+#include "des_enc.c"
-+
-+#undef DES_UNROLL
-+#define DES_RISC1
-+#undef DES_RISC2
-+#undef DES_PTR
-+#undef D_ENCRYPT
-+#undef des_encrypt
-+#undef des_encrypt2
-+#undef des_encrypt3
-+#undef des_decrypt3
-+#define des_encrypt des_encrypt_u4_risc1_idx
-+#define des_encrypt2 des_encrypt2_u4_risc1_idx
-+#define des_encrypt3 des_encrypt3_u4_risc1_idx
-+#define des_decrypt3 des_decrypt3_u4_risc1_idx
-+#undef HEADER_DES_LOCL_H
-+#include "des_enc.c"
-+
-+#endif
-+
-+#ifdef PART2
-+
-+#undef DES_UNROLL
-+#undef DES_RISC1
-+#define DES_RISC2
-+#undef DES_PTR
-+#undef D_ENCRYPT
-+#undef des_encrypt
-+#undef des_encrypt2
-+#undef des_encrypt3
-+#undef des_decrypt3
-+#define des_encrypt des_encrypt_u4_risc2_idx
-+#define des_encrypt2 des_encrypt2_u4_risc2_idx
-+#define des_encrypt3 des_encrypt3_u4_risc2_idx
-+#define des_decrypt3 des_decrypt3_u4_risc2_idx
-+#undef HEADER_DES_LOCL_H
-+#include "des_enc.c"
-+
-+#define DES_UNROLL
-+#define DES_RISC1
-+#undef DES_RISC2
-+#undef DES_PTR
-+#undef D_ENCRYPT
-+#undef des_encrypt
-+#undef des_encrypt2
-+#undef des_encrypt3
-+#undef des_decrypt3
-+#define des_encrypt des_encrypt_u16_risc1_idx
-+#define des_encrypt2 des_encrypt2_u16_risc1_idx
-+#define des_encrypt3 des_encrypt3_u16_risc1_idx
-+#define des_decrypt3 des_decrypt3_u16_risc1_idx
-+#undef HEADER_DES_LOCL_H
-+#include "des_enc.c"
-+
-+#define DES_UNROLL
-+#undef DES_RISC1
-+#define DES_RISC2
-+#undef DES_PTR
-+#undef D_ENCRYPT
-+#undef des_encrypt
-+#undef des_encrypt2
-+#undef des_encrypt3
-+#undef des_decrypt3
-+#define des_encrypt des_encrypt_u16_risc2_idx
-+#define des_encrypt2 des_encrypt2_u16_risc2_idx
-+#define des_encrypt3 des_encrypt3_u16_risc2_idx
-+#define des_decrypt3 des_decrypt3_u16_risc2_idx
-+#undef HEADER_DES_LOCL_H
-+#include "des_enc.c"
-+
-+#endif
-+
-+#ifdef PART3
-+
-+#undef DES_UNROLL
-+#undef DES_RISC1
-+#undef DES_RISC2
-+#define DES_PTR
-+#undef D_ENCRYPT
-+#undef des_encrypt
-+#undef des_encrypt2
-+#undef des_encrypt3
-+#undef des_decrypt3
-+#define des_encrypt des_encrypt_u4_cisc_ptr
-+#define des_encrypt2 des_encrypt2_u4_cisc_ptr
-+#define des_encrypt3 des_encrypt3_u4_cisc_ptr
-+#define des_decrypt3 des_decrypt3_u4_cisc_ptr
-+#undef HEADER_DES_LOCL_H
-+#include "des_enc.c"
-+
-+#define DES_UNROLL
-+#undef DES_RISC1
-+#undef DES_RISC2
-+#define DES_PTR
-+#undef D_ENCRYPT
-+#undef des_encrypt
-+#undef des_encrypt2
-+#undef des_encrypt3
-+#undef des_decrypt3
-+#define des_encrypt des_encrypt_u16_cisc_ptr
-+#define des_encrypt2 des_encrypt2_u16_cisc_ptr
-+#define des_encrypt3 des_encrypt3_u16_cisc_ptr
-+#define des_decrypt3 des_decrypt3_u16_cisc_ptr
-+#undef HEADER_DES_LOCL_H
-+#include "des_enc.c"
-+
-+#undef DES_UNROLL
-+#define DES_RISC1
-+#undef DES_RISC2
-+#define DES_PTR
-+#undef D_ENCRYPT
-+#undef des_encrypt
-+#undef des_encrypt2
-+#undef des_encrypt3
-+#undef des_decrypt3
-+#define des_encrypt des_encrypt_u4_risc1_ptr
-+#define des_encrypt2 des_encrypt2_u4_risc1_ptr
-+#define des_encrypt3 des_encrypt3_u4_risc1_ptr
-+#define des_decrypt3 des_decrypt3_u4_risc1_ptr
-+#undef HEADER_DES_LOCL_H
-+#include "des_enc.c"
-+
-+#endif
-+
-+#ifdef PART4
-+
-+#undef DES_UNROLL
-+#undef DES_RISC1
-+#define DES_RISC2
-+#define DES_PTR
-+#undef D_ENCRYPT
-+#undef des_encrypt
-+#undef des_encrypt2
-+#undef des_encrypt3
-+#undef des_decrypt3
-+#define des_encrypt des_encrypt_u4_risc2_ptr
-+#define des_encrypt2 des_encrypt2_u4_risc2_ptr
-+#define des_encrypt3 des_encrypt3_u4_risc2_ptr
-+#define des_decrypt3 des_decrypt3_u4_risc2_ptr
-+#undef HEADER_DES_LOCL_H
-+#include "des_enc.c"
-+
-+#define DES_UNROLL
-+#define DES_RISC1
-+#undef DES_RISC2
-+#define DES_PTR
-+#undef D_ENCRYPT
-+#undef des_encrypt
-+#undef des_encrypt2
-+#undef des_encrypt3
-+#undef des_decrypt3
-+#define des_encrypt des_encrypt_u16_risc1_ptr
-+#define des_encrypt2 des_encrypt2_u16_risc1_ptr
-+#define des_encrypt3 des_encrypt3_u16_risc1_ptr
-+#define des_decrypt3 des_decrypt3_u16_risc1_ptr
-+#undef HEADER_DES_LOCL_H
-+#include "des_enc.c"
-+
-+#define DES_UNROLL
-+#undef DES_RISC1
-+#define DES_RISC2
-+#define DES_PTR
-+#undef D_ENCRYPT
-+#undef des_encrypt
-+#undef des_encrypt2
-+#undef des_encrypt3
-+#undef des_decrypt3
-+#define des_encrypt des_encrypt_u16_risc2_ptr
-+#define des_encrypt2 des_encrypt2_u16_risc2_ptr
-+#define des_encrypt3 des_encrypt3_u16_risc2_ptr
-+#define des_decrypt3 des_decrypt3_u16_risc2_ptr
-+#undef HEADER_DES_LOCL_H
-+#include "des_enc.c"
-+
-+#endif
-+
-+/* The following if from times(3) man page. It may need to be changed */
-+#ifndef HZ
-+# ifndef CLK_TCK
-+# ifndef _BSD_CLK_TCK_ /* FreeBSD fix */
-+# ifndef VMS
-+# define HZ 100.0
-+# else /* VMS */
-+# define HZ 100.0
-+# endif
-+# else /* _BSD_CLK_TCK_ */
-+# define HZ ((double)_BSD_CLK_TCK_)
-+# endif
-+# else /* CLK_TCK */
-+# define HZ ((double)CLK_TCK)
-+# endif
-+#endif
-+
-+#define BUFSIZE ((long)1024)
-+long run=0;
-+
-+#ifndef NOPROTO
-+double Time_F(int s);
-+#else
-+double Time_F();
-+#endif
-+
-+#ifdef SIGALRM
-+#if defined(__STDC__) || defined(sgi)
-+#define SIGRETTYPE void
-+#else
-+#define SIGRETTYPE int
-+#endif
-+
-+#ifndef NOPROTO
-+SIGRETTYPE sig_done(int sig);
-+#else
-+SIGRETTYPE sig_done();
-+#endif
-+
-+SIGRETTYPE sig_done(sig)
-+int sig;
-+ {
-+ signal(SIGALRM,sig_done);
-+ run=0;
-+#ifdef LINT
-+ sig=sig;
-+#endif
-+ }
-+#endif
-+
-+#define START 0
-+#define STOP 1
-+
-+double Time_F(s)
-+int s;
-+ {
-+ double ret;
-+#ifdef TIMES
-+ static struct tms tstart,tend;
-+
-+ if (s == START)
-+ {
-+ times(&tstart);
-+ return(0);
-+ }
-+ else
-+ {
-+ times(&tend);
-+ ret=((double)(tend.tms_utime-tstart.tms_utime))/HZ;
-+ return((ret == 0.0)?1e-6:ret);
-+ }
-+#else /* !times() */
-+ static struct timeb tstart,tend;
-+ long i;
-+
-+ if (s == START)
-+ {
-+ ftime(&tstart);
-+ return(0);
-+ }
-+ else
-+ {
-+ ftime(&tend);
-+ i=(long)tend.millitm-(long)tstart.millitm;
-+ ret=((double)(tend.time-tstart.time))+((double)i)/1000.0;
-+ return((ret == 0.0)?1e-6:ret);
-+ }
-+#endif
-+ }
-+
-+#ifdef SIGALRM
-+#define print_name(name) fprintf(stderr,"Doing %s's for 10 seconds\n",name); alarm(10);
-+#else
-+#define print_name(name) fprintf(stderr,"Doing %s %ld times\n",name,cb);
-+#endif
-+
-+#define time_it(func,name,index) \
-+ print_name(name); \
-+ Time_F(START); \
-+ for (count=0,run=1; COND(cb); count++) \
-+ { \
-+ unsigned long d[2]; \
-+ func(d,&(sch[0]),DES_ENCRYPT); \
-+ } \
-+ tm[index]=Time_F(STOP); \
-+ fprintf(stderr,"%ld %s's in %.2f second\n",count,name,tm[index]); \
-+ tm[index]=((double)COUNT(cb))/tm[index];
-+
-+#define print_it(name,index) \
-+ fprintf(stderr,"%s bytes per sec = %12.2f (%5.1fuS)\n",name, \
-+ tm[index]*8,1.0e6/tm[index]);
-+
-+int main(argc,argv)
-+int argc;
-+char **argv;
-+ {
-+ long count;
-+ static unsigned char buf[BUFSIZE];
-+ static des_cblock key ={0x12,0x34,0x56,0x78,0x9a,0xbc,0xde,0xf0};
-+ static des_cblock key2={0x34,0x56,0x78,0x9a,0xbc,0xde,0xf0,0x12};
-+ static des_cblock key3={0x56,0x78,0x9a,0xbc,0xde,0xf0,0x12,0x34};
-+ des_key_schedule sch,sch2,sch3;
-+ double d,tm[16],max=0;
-+ int rank[16];
-+ char *str[16];
-+ int max_idx=0,i,num=0,j;
-+#ifndef SIGALARM
-+ long ca,cb,cc,cd,ce;
-+#endif
-+
-+ for (i=0; i<12; i++)
-+ {
-+ tm[i]=0.0;
-+ rank[i]=0;
-+ }
-+
-+#ifndef TIMES
-+ fprintf(stderr,"To get the most acurate results, try to run this\n");
-+ fprintf(stderr,"program when this computer is idle.\n");
-+#endif
-+
-+ des_set_key((C_Block *)key,sch);
-+ des_set_key((C_Block *)key2,sch2);
-+ des_set_key((C_Block *)key3,sch3);
-+
-+#ifndef SIGALRM
-+ fprintf(stderr,"First we calculate the approximate speed ...\n");
-+ des_set_key((C_Block *)key,sch);
-+ count=10;
-+ do {
-+ long i;
-+ unsigned long data[2];
-+
-+ count*=2;
-+ Time_F(START);
-+ for (i=count; i; i--)
-+ des_encrypt(data,&(sch[0]),DES_ENCRYPT);
-+ d=Time_F(STOP);
-+ } while (d < 3.0);
-+ ca=count;
-+ cb=count*3;
-+ cc=count*3*8/BUFSIZE+1;
-+ cd=count*8/BUFSIZE+1;
-+
-+ ce=count/20+1;
-+#define COND(d) (count != (d))
-+#define COUNT(d) (d)
-+#else
-+#define COND(c) (run)
-+#define COUNT(d) (count)
-+ signal(SIGALRM,sig_done);
-+ alarm(10);
-+#endif
-+
-+#ifdef PART1
-+ time_it(des_encrypt_u4_cisc_idx, "des_encrypt_u4_cisc_idx ", 0);
-+ time_it(des_encrypt_u16_cisc_idx, "des_encrypt_u16_cisc_idx ", 1);
-+ time_it(des_encrypt_u4_risc1_idx, "des_encrypt_u4_risc1_idx ", 2);
-+ num+=3;
-+#endif
-+#ifdef PART2
-+ time_it(des_encrypt_u16_risc1_idx,"des_encrypt_u16_risc1_idx", 3);
-+ time_it(des_encrypt_u4_risc2_idx, "des_encrypt_u4_risc2_idx ", 4);
-+ time_it(des_encrypt_u16_risc2_idx,"des_encrypt_u16_risc2_idx", 5);
-+ num+=3;
-+#endif
-+#ifdef PART3
-+ time_it(des_encrypt_u4_cisc_ptr, "des_encrypt_u4_cisc_ptr ", 6);
-+ time_it(des_encrypt_u16_cisc_ptr, "des_encrypt_u16_cisc_ptr ", 7);
-+ time_it(des_encrypt_u4_risc1_ptr, "des_encrypt_u4_risc1_ptr ", 8);
-+ num+=3;
-+#endif
-+#ifdef PART4
-+ time_it(des_encrypt_u16_risc1_ptr,"des_encrypt_u16_risc1_ptr", 9);
-+ time_it(des_encrypt_u4_risc2_ptr, "des_encrypt_u4_risc2_ptr ",10);
-+ time_it(des_encrypt_u16_risc2_ptr,"des_encrypt_u16_risc2_ptr",11);
-+ num+=3;
-+#endif
-+
-+#ifdef PART1
-+ str[0]=" 4 c i";
-+ print_it("des_encrypt_u4_cisc_idx ",0);
-+ max=tm[0];
-+ max_idx=0;
-+ str[1]="16 c i";
-+ print_it("des_encrypt_u16_cisc_idx ",1);
-+ if (max < tm[1]) { max=tm[1]; max_idx=1; }
-+ str[2]=" 4 r1 i";
-+ print_it("des_encrypt_u4_risc1_idx ",2);
-+ if (max < tm[2]) { max=tm[2]; max_idx=2; }
-+#endif
-+#ifdef PART2
-+ str[3]="16 r1 i";
-+ print_it("des_encrypt_u16_risc1_idx",3);
-+ if (max < tm[3]) { max=tm[3]; max_idx=3; }
-+ str[4]=" 4 r2 i";
-+ print_it("des_encrypt_u4_risc2_idx ",4);
-+ if (max < tm[4]) { max=tm[4]; max_idx=4; }
-+ str[5]="16 r2 i";
-+ print_it("des_encrypt_u16_risc2_idx",5);
-+ if (max < tm[5]) { max=tm[5]; max_idx=5; }
-+#endif
-+#ifdef PART3
-+ str[6]=" 4 c p";
-+ print_it("des_encrypt_u4_cisc_ptr ",6);
-+ if (max < tm[6]) { max=tm[6]; max_idx=6; }
-+ str[7]="16 c p";
-+ print_it("des_encrypt_u16_cisc_ptr ",7);
-+ if (max < tm[7]) { max=tm[7]; max_idx=7; }
-+ str[8]=" 4 r1 p";
-+ print_it("des_encrypt_u4_risc1_ptr ",8);
-+ if (max < tm[8]) { max=tm[8]; max_idx=8; }
-+#endif
-+#ifdef PART4
-+ str[9]="16 r1 p";
-+ print_it("des_encrypt_u16_risc1_ptr",9);
-+ if (max < tm[9]) { max=tm[9]; max_idx=9; }
-+ str[10]=" 4 r2 p";
-+ print_it("des_encrypt_u4_risc2_ptr ",10);
-+ if (max < tm[10]) { max=tm[10]; max_idx=10; }
-+ str[11]="16 r2 p";
-+ print_it("des_encrypt_u16_risc2_ptr",11);
-+ if (max < tm[11]) { max=tm[11]; max_idx=11; }
-+#endif
-+ printf("options des ecb/s\n");
-+ printf("%s %12.2f 100.0%%\n",str[max_idx],tm[max_idx]);
-+ d=tm[max_idx];
-+ tm[max_idx]= -2.0;
-+ max= -1.0;
-+ for (;;)
-+ {
-+ for (i=0; i<12; i++)
-+ {
-+ if (max < tm[i]) { max=tm[i]; j=i; }
-+ }
-+ if (max < 0.0) break;
-+ printf("%s %12.2f %4.1f%%\n",str[j],tm[j],tm[j]/d*100.0);
-+ tm[j]= -2.0;
-+ max= -1.0;
-+ }
-+
-+ switch (max_idx)
-+ {
-+ case 0:
-+ printf("-DDES_DEFAULT_OPTIONS\n");
-+ break;
-+ case 1:
-+ printf("-DDES_UNROLL\n");
-+ break;
-+ case 2:
-+ printf("-DDES_RISC1\n");
-+ break;
-+ case 3:
-+ printf("-DDES_UNROLL -DDES_RISC1\n");
-+ break;
-+ case 4:
-+ printf("-DDES_RISC2\n");
-+ break;
-+ case 5:
-+ printf("-DDES_UNROLL -DDES_RISC2\n");
-+ break;
-+ case 6:
-+ printf("-DDES_PTR\n");
-+ break;
-+ case 7:
-+ printf("-DDES_UNROLL -DDES_PTR\n");
-+ break;
-+ case 8:
-+ printf("-DDES_RISC1 -DDES_PTR\n");
-+ break;
-+ case 9:
-+ printf("-DDES_UNROLL -DDES_RISC1 -DDES_PTR\n");
-+ break;
-+ case 10:
-+ printf("-DDES_RISC2 -DDES_PTR\n");
-+ break;
-+ case 11:
-+ printf("-DDES_UNROLL -DDES_RISC2 -DDES_PTR\n");
-+ break;
-+ }
-+ exit(0);
-+#if defined(LINT) || defined(MSDOS)
-+ return(0);
-+#endif
-+ }
---- /dev/null Tue Mar 11 13:02:56 2003
-+++ linux/crypto/ciphers/des/des_ver.h Mon Feb 9 13:51:03 2004
-@@ -0,0 +1,60 @@
-+/* crypto/des/des_ver.h */
-+/* Copyright (C) 1995-1997 Eric Young (eay@cryptsoft.com)
-+ * All rights reserved.
-+ *
-+ * This package is an SSL implementation written
-+ * by Eric Young (eay@cryptsoft.com).
-+ * The implementation was written so as to conform with Netscapes SSL.
-+ *
-+ * This library is free for commercial and non-commercial use as long as
-+ * the following conditions are aheared to. The following conditions
-+ * apply to all code found in this distribution, be it the RC4, RSA,
-+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
-+ * included with this distribution is covered by the same copyright terms
-+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
-+ *
-+ * Copyright remains Eric Young's, and as such any Copyright notices in
-+ * the code are not to be removed.
-+ * If this package is used in a product, Eric Young should be given attribution
-+ * as the author of the parts of the library used.
-+ * This can be in the form of a textual message at program startup or
-+ * in documentation (online or textual) provided with the package.
-+ *
-+ * Redistribution and use in source and binary forms, with or without
-+ * modification, are permitted provided that the following conditions
-+ * are met:
-+ * 1. Redistributions of source code must retain the copyright
-+ * notice, this list of conditions and the following disclaimer.
-+ * 2. Redistributions in binary form must reproduce the above copyright
-+ * notice, this list of conditions and the following disclaimer in the
-+ * documentation and/or other materials provided with the distribution.
-+ * 3. All advertising materials mentioning features or use of this software
-+ * must display the following acknowledgement:
-+ * "This product includes cryptographic software written by
-+ * Eric Young (eay@cryptsoft.com)"
-+ * The word 'cryptographic' can be left out if the rouines from the library
-+ * being used are not cryptographic related :-).
-+ * 4. If you include any Windows specific code (or a derivative thereof) from
-+ * the apps directory (application code) you must include an acknowledgement:
-+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``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 OR CONTRIBUTORS 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.
-+ *
-+ * The licence and distribution terms for any publically available version or
-+ * derivative of this code cannot be changed. i.e. this code cannot simply be
-+ * copied and put under another distribution licence
-+ * [including the GNU Public Licence.]
-+ */
-+
-+extern char *DES_version; /* SSLeay version string */
-+extern char *libdes_version; /* old libdes version string */
---- /dev/null Tue Mar 11 13:02:56 2003
-+++ linux/crypto/ciphers/des/destest.c Mon Feb 9 13:51:03 2004
-@@ -0,0 +1,871 @@
-+/* crypto/des/destest.c */
-+/* Copyright (C) 1995-1997 Eric Young (eay@cryptsoft.com)
-+ * All rights reserved.
-+ *
-+ * This package is an SSL implementation written
-+ * by Eric Young (eay@cryptsoft.com).
-+ * The implementation was written so as to conform with Netscapes SSL.
-+ *
-+ * This library is free for commercial and non-commercial use as long as
-+ * the following conditions are aheared to. The following conditions
-+ * apply to all code found in this distribution, be it the RC4, RSA,
-+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
-+ * included with this distribution is covered by the same copyright terms
-+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
-+ *
-+ * Copyright remains Eric Young's, and as such any Copyright notices in
-+ * the code are not to be removed.
-+ * If this package is used in a product, Eric Young should be given attribution
-+ * as the author of the parts of the library used.
-+ * This can be in the form of a textual message at program startup or
-+ * in documentation (online or textual) provided with the package.
-+ *
-+ * Redistribution and use in source and binary forms, with or without
-+ * modification, are permitted provided that the following conditions
-+ * are met:
-+ * 1. Redistributions of source code must retain the copyright
-+ * notice, this list of conditions and the following disclaimer.
-+ * 2. Redistributions in binary form must reproduce the above copyright
-+ * notice, this list of conditions and the following disclaimer in the
-+ * documentation and/or other materials provided with the distribution.
-+ * 3. All advertising materials mentioning features or use of this software
-+ * must display the following acknowledgement:
-+ * "This product includes cryptographic software written by
-+ * Eric Young (eay@cryptsoft.com)"
-+ * The word 'cryptographic' can be left out if the rouines from the library
-+ * being used are not cryptographic related :-).
-+ * 4. If you include any Windows specific code (or a derivative thereof) from
-+ * the apps directory (application code) you must include an acknowledgement:
-+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``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 OR CONTRIBUTORS 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.
-+ *
-+ * The licence and distribution terms for any publically available version or
-+ * derivative of this code cannot be changed. i.e. this code cannot simply be
-+ * copied and put under another distribution licence
-+ * [including the GNU Public Licence.]
-+ */
-+
-+#if defined(WIN32) || defined(WIN16) || defined(WINDOWS)
-+#ifndef MSDOS
-+#define MSDOS
-+#endif
-+#endif
-+
-+#include <stdio.h>
-+#include <stdlib.h>
-+#ifndef MSDOS
-+#include <unistd.h>
-+#else
-+#include <io.h>
-+#endif
-+#include <string.h>
-+#include "des_locl.h"
-+
-+/* tisk tisk - the test keys don't all have odd parity :-( */
-+/* test data */
-+#define NUM_TESTS 34
-+static unsigned char key_data[NUM_TESTS][8]={
-+ {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
-+ {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF},
-+ {0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
-+ {0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11},
-+ {0x01,0x23,0x45,0x67,0x89,0xAB,0xCD,0xEF},
-+ {0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11},
-+ {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
-+ {0xFE,0xDC,0xBA,0x98,0x76,0x54,0x32,0x10},
-+ {0x7C,0xA1,0x10,0x45,0x4A,0x1A,0x6E,0x57},
-+ {0x01,0x31,0xD9,0x61,0x9D,0xC1,0x37,0x6E},
-+ {0x07,0xA1,0x13,0x3E,0x4A,0x0B,0x26,0x86},
-+ {0x38,0x49,0x67,0x4C,0x26,0x02,0x31,0x9E},
-+ {0x04,0xB9,0x15,0xBA,0x43,0xFE,0xB5,0xB6},
-+ {0x01,0x13,0xB9,0x70,0xFD,0x34,0xF2,0xCE},
-+ {0x01,0x70,0xF1,0x75,0x46,0x8F,0xB5,0xE6},
-+ {0x43,0x29,0x7F,0xAD,0x38,0xE3,0x73,0xFE},
-+ {0x07,0xA7,0x13,0x70,0x45,0xDA,0x2A,0x16},
-+ {0x04,0x68,0x91,0x04,0xC2,0xFD,0x3B,0x2F},
-+ {0x37,0xD0,0x6B,0xB5,0x16,0xCB,0x75,0x46},
-+ {0x1F,0x08,0x26,0x0D,0x1A,0xC2,0x46,0x5E},
-+ {0x58,0x40,0x23,0x64,0x1A,0xBA,0x61,0x76},
-+ {0x02,0x58,0x16,0x16,0x46,0x29,0xB0,0x07},
-+ {0x49,0x79,0x3E,0xBC,0x79,0xB3,0x25,0x8F},
-+ {0x4F,0xB0,0x5E,0x15,0x15,0xAB,0x73,0xA7},
-+ {0x49,0xE9,0x5D,0x6D,0x4C,0xA2,0x29,0xBF},
-+ {0x01,0x83,0x10,0xDC,0x40,0x9B,0x26,0xD6},
-+ {0x1C,0x58,0x7F,0x1C,0x13,0x92,0x4F,0xEF},
-+ {0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01},
-+ {0x1F,0x1F,0x1F,0x1F,0x0E,0x0E,0x0E,0x0E},
-+ {0xE0,0xFE,0xE0,0xFE,0xF1,0xFE,0xF1,0xFE},
-+ {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
-+ {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF},
-+ {0x01,0x23,0x45,0x67,0x89,0xAB,0xCD,0xEF},
-+ {0xFE,0xDC,0xBA,0x98,0x76,0x54,0x32,0x10}};
-+
-+static unsigned char plain_data[NUM_TESTS][8]={
-+ {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
-+ {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF},
-+ {0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x01},
-+ {0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11},
-+ {0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11},
-+ {0x01,0x23,0x45,0x67,0x89,0xAB,0xCD,0xEF},
-+ {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
-+ {0x01,0x23,0x45,0x67,0x89,0xAB,0xCD,0xEF},
-+ {0x01,0xA1,0xD6,0xD0,0x39,0x77,0x67,0x42},
-+ {0x5C,0xD5,0x4C,0xA8,0x3D,0xEF,0x57,0xDA},
-+ {0x02,0x48,0xD4,0x38,0x06,0xF6,0x71,0x72},
-+ {0x51,0x45,0x4B,0x58,0x2D,0xDF,0x44,0x0A},
-+ {0x42,0xFD,0x44,0x30,0x59,0x57,0x7F,0xA2},
-+ {0x05,0x9B,0x5E,0x08,0x51,0xCF,0x14,0x3A},
-+ {0x07,0x56,0xD8,0xE0,0x77,0x47,0x61,0xD2},
-+ {0x76,0x25,0x14,0xB8,0x29,0xBF,0x48,0x6A},
-+ {0x3B,0xDD,0x11,0x90,0x49,0x37,0x28,0x02},
-+ {0x26,0x95,0x5F,0x68,0x35,0xAF,0x60,0x9A},
-+ {0x16,0x4D,0x5E,0x40,0x4F,0x27,0x52,0x32},
-+ {0x6B,0x05,0x6E,0x18,0x75,0x9F,0x5C,0xCA},
-+ {0x00,0x4B,0xD6,0xEF,0x09,0x17,0x60,0x62},
-+ {0x48,0x0D,0x39,0x00,0x6E,0xE7,0x62,0xF2},
-+ {0x43,0x75,0x40,0xC8,0x69,0x8F,0x3C,0xFA},
-+ {0x07,0x2D,0x43,0xA0,0x77,0x07,0x52,0x92},
-+ {0x02,0xFE,0x55,0x77,0x81,0x17,0xF1,0x2A},
-+ {0x1D,0x9D,0x5C,0x50,0x18,0xF7,0x28,0xC2},
-+ {0x30,0x55,0x32,0x28,0x6D,0x6F,0x29,0x5A},
-+ {0x01,0x23,0x45,0x67,0x89,0xAB,0xCD,0xEF},
-+ {0x01,0x23,0x45,0x67,0x89,0xAB,0xCD,0xEF},
-+ {0x01,0x23,0x45,0x67,0x89,0xAB,0xCD,0xEF},
-+ {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF},
-+ {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
-+ {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
-+ {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF}};
-+
-+static unsigned char cipher_data[NUM_TESTS][8]={
-+ {0x8C,0xA6,0x4D,0xE9,0xC1,0xB1,0x23,0xA7},
-+ {0x73,0x59,0xB2,0x16,0x3E,0x4E,0xDC,0x58},
-+ {0x95,0x8E,0x6E,0x62,0x7A,0x05,0x55,0x7B},
-+ {0xF4,0x03,0x79,0xAB,0x9E,0x0E,0xC5,0x33},
-+ {0x17,0x66,0x8D,0xFC,0x72,0x92,0x53,0x2D},
-+ {0x8A,0x5A,0xE1,0xF8,0x1A,0xB8,0xF2,0xDD},
-+ {0x8C,0xA6,0x4D,0xE9,0xC1,0xB1,0x23,0xA7},
-+ {0xED,0x39,0xD9,0x50,0xFA,0x74,0xBC,0xC4},
-+ {0x69,0x0F,0x5B,0x0D,0x9A,0x26,0x93,0x9B},
-+ {0x7A,0x38,0x9D,0x10,0x35,0x4B,0xD2,0x71},
-+ {0x86,0x8E,0xBB,0x51,0xCA,0xB4,0x59,0x9A},
-+ {0x71,0x78,0x87,0x6E,0x01,0xF1,0x9B,0x2A},
-+ {0xAF,0x37,0xFB,0x42,0x1F,0x8C,0x40,0x95},
-+ {0x86,0xA5,0x60,0xF1,0x0E,0xC6,0xD8,0x5B},
-+ {0x0C,0xD3,0xDA,0x02,0x00,0x21,0xDC,0x09},
-+ {0xEA,0x67,0x6B,0x2C,0xB7,0xDB,0x2B,0x7A},
-+ {0xDF,0xD6,0x4A,0x81,0x5C,0xAF,0x1A,0x0F},
-+ {0x5C,0x51,0x3C,0x9C,0x48,0x86,0xC0,0x88},
-+ {0x0A,0x2A,0xEE,0xAE,0x3F,0xF4,0xAB,0x77},
-+ {0xEF,0x1B,0xF0,0x3E,0x5D,0xFA,0x57,0x5A},
-+ {0x88,0xBF,0x0D,0xB6,0xD7,0x0D,0xEE,0x56},
-+ {0xA1,0xF9,0x91,0x55,0x41,0x02,0x0B,0x56},
-+ {0x6F,0xBF,0x1C,0xAF,0xCF,0xFD,0x05,0x56},
-+ {0x2F,0x22,0xE4,0x9B,0xAB,0x7C,0xA1,0xAC},
-+ {0x5A,0x6B,0x61,0x2C,0xC2,0x6C,0xCE,0x4A},
-+ {0x5F,0x4C,0x03,0x8E,0xD1,0x2B,0x2E,0x41},
-+ {0x63,0xFA,0xC0,0xD0,0x34,0xD9,0xF7,0x93},
-+ {0x61,0x7B,0x3A,0x0C,0xE8,0xF0,0x71,0x00},
-+ {0xDB,0x95,0x86,0x05,0xF8,0xC8,0xC6,0x06},
-+ {0xED,0xBF,0xD1,0xC6,0x6C,0x29,0xCC,0xC7},
-+ {0x35,0x55,0x50,0xB2,0x15,0x0E,0x24,0x51},
-+ {0xCA,0xAA,0xAF,0x4D,0xEA,0xF1,0xDB,0xAE},
-+ {0xD5,0xD4,0x4F,0xF7,0x20,0x68,0x3D,0x0D},
-+ {0x2A,0x2B,0xB0,0x08,0xDF,0x97,0xC2,0xF2}};
-+
-+static unsigned char cipher_ecb2[NUM_TESTS-1][8]={
-+ {0x92,0x95,0xB5,0x9B,0xB3,0x84,0x73,0x6E},
-+ {0x19,0x9E,0x9D,0x6D,0xF3,0x9A,0xA8,0x16},
-+ {0x2A,0x4B,0x4D,0x24,0x52,0x43,0x84,0x27},
-+ {0x35,0x84,0x3C,0x01,0x9D,0x18,0xC5,0xB6},
-+ {0x4A,0x5B,0x2F,0x42,0xAA,0x77,0x19,0x25},
-+ {0xA0,0x6B,0xA9,0xB8,0xCA,0x5B,0x17,0x8A},
-+ {0xAB,0x9D,0xB7,0xFB,0xED,0x95,0xF2,0x74},
-+ {0x3D,0x25,0x6C,0x23,0xA7,0x25,0x2F,0xD6},
-+ {0xB7,0x6F,0xAB,0x4F,0xBD,0xBD,0xB7,0x67},
-+ {0x8F,0x68,0x27,0xD6,0x9C,0xF4,0x1A,0x10},
-+ {0x82,0x57,0xA1,0xD6,0x50,0x5E,0x81,0x85},
-+ {0xA2,0x0F,0x0A,0xCD,0x80,0x89,0x7D,0xFA},
-+ {0xCD,0x2A,0x53,0x3A,0xDB,0x0D,0x7E,0xF3},
-+ {0xD2,0xC2,0xBE,0x27,0xE8,0x1B,0x68,0xE3},
-+ {0xE9,0x24,0xCF,0x4F,0x89,0x3C,0x5B,0x0A},
-+ {0xA7,0x18,0xC3,0x9F,0xFA,0x9F,0xD7,0x69},
-+ {0x77,0x2C,0x79,0xB1,0xD2,0x31,0x7E,0xB1},
-+ {0x49,0xAB,0x92,0x7F,0xD0,0x22,0x00,0xB7},
-+ {0xCE,0x1C,0x6C,0x7D,0x85,0xE3,0x4A,0x6F},
-+ {0xBE,0x91,0xD6,0xE1,0x27,0xB2,0xE9,0x87},
-+ {0x70,0x28,0xAE,0x8F,0xD1,0xF5,0x74,0x1A},
-+ {0xAA,0x37,0x80,0xBB,0xF3,0x22,0x1D,0xDE},
-+ {0xA6,0xC4,0xD2,0x5E,0x28,0x93,0xAC,0xB3},
-+ {0x22,0x07,0x81,0x5A,0xE4,0xB7,0x1A,0xAD},
-+ {0xDC,0xCE,0x05,0xE7,0x07,0xBD,0xF5,0x84},
-+ {0x26,0x1D,0x39,0x2C,0xB3,0xBA,0xA5,0x85},
-+ {0xB4,0xF7,0x0F,0x72,0xFB,0x04,0xF0,0xDC},
-+ {0x95,0xBA,0xA9,0x4E,0x87,0x36,0xF2,0x89},
-+ {0xD4,0x07,0x3A,0xF1,0x5A,0x17,0x82,0x0E},
-+ {0xEF,0x6F,0xAF,0xA7,0x66,0x1A,0x7E,0x89},
-+ {0xC1,0x97,0xF5,0x58,0x74,0x8A,0x20,0xE7},
-+ {0x43,0x34,0xCF,0xDA,0x22,0xC4,0x86,0xC8},
-+ {0x08,0xD7,0xB4,0xFB,0x62,0x9D,0x08,0x85}};
-+
-+static unsigned char cbc_key [8]={0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef};
-+static unsigned char cbc2_key[8]={0xf0,0xe1,0xd2,0xc3,0xb4,0xa5,0x96,0x87};
-+static unsigned char cbc3_key[8]={0xfe,0xdc,0xba,0x98,0x76,0x54,0x32,0x10};
-+static unsigned char cbc_iv [8]={0xfe,0xdc,0xba,0x98,0x76,0x54,0x32,0x10};
-+static char cbc_data[40]="7654321 Now is the time for \0001";
-+
-+static unsigned char cbc_ok[32]={
-+ 0xcc,0xd1,0x73,0xff,0xab,0x20,0x39,0xf4,
-+ 0xac,0xd8,0xae,0xfd,0xdf,0xd8,0xa1,0xeb,
-+ 0x46,0x8e,0x91,0x15,0x78,0x88,0xba,0x68,
-+ 0x1d,0x26,0x93,0x97,0xf7,0xfe,0x62,0xb4};
-+
-+static unsigned char xcbc_ok[32]={
-+ 0x86,0x74,0x81,0x0D,0x61,0xA4,0xA5,0x48,
-+ 0xB9,0x93,0x03,0xE1,0xB8,0xBB,0xBD,0xBD,
-+ 0x64,0x30,0x0B,0xB9,0x06,0x65,0x81,0x76,
-+ 0x04,0x1D,0x77,0x62,0x17,0xCA,0x2B,0xD2,
-+ };
-+
-+static unsigned char cbc3_ok[32]={
-+ 0x3F,0xE3,0x01,0xC9,0x62,0xAC,0x01,0xD0,
-+ 0x22,0x13,0x76,0x3C,0x1C,0xBD,0x4C,0xDC,
-+ 0x79,0x96,0x57,0xC0,0x64,0xEC,0xF5,0xD4,
-+ 0x1C,0x67,0x38,0x12,0xCF,0xDE,0x96,0x75};
-+
-+static unsigned char pcbc_ok[32]={
-+ 0xcc,0xd1,0x73,0xff,0xab,0x20,0x39,0xf4,
-+ 0x6d,0xec,0xb4,0x70,0xa0,0xe5,0x6b,0x15,
-+ 0xae,0xa6,0xbf,0x61,0xed,0x7d,0x9c,0x9f,
-+ 0xf7,0x17,0x46,0x3b,0x8a,0xb3,0xcc,0x88};
-+
-+static unsigned char cfb_key[8]={0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef};
-+static unsigned char cfb_iv[8]={0x12,0x34,0x56,0x78,0x90,0xab,0xcd,0xef};
-+static unsigned char cfb_buf1[40],cfb_buf2[40],cfb_tmp[8];
-+static unsigned char plain[24]=
-+ {
-+ 0x4e,0x6f,0x77,0x20,0x69,0x73,
-+ 0x20,0x74,0x68,0x65,0x20,0x74,
-+ 0x69,0x6d,0x65,0x20,0x66,0x6f,
-+ 0x72,0x20,0x61,0x6c,0x6c,0x20
-+ };
-+static unsigned char cfb_cipher8[24]= {
-+ 0xf3,0x1f,0xda,0x07,0x01,0x14, 0x62,0xee,0x18,0x7f,0x43,0xd8,
-+ 0x0a,0x7c,0xd9,0xb5,0xb0,0xd2, 0x90,0xda,0x6e,0x5b,0x9a,0x87 };
-+static unsigned char cfb_cipher16[24]={
-+ 0xF3,0x09,0x87,0x87,0x7F,0x57, 0xF7,0x3C,0x36,0xB6,0xDB,0x70,
-+ 0xD8,0xD5,0x34,0x19,0xD3,0x86, 0xB2,0x23,0xB7,0xB2,0xAD,0x1B };
-+static unsigned char cfb_cipher32[24]={
-+ 0xF3,0x09,0x62,0x49,0xA4,0xDF, 0xA4,0x9F,0x33,0xDC,0x7B,0xAD,
-+ 0x4C,0xC8,0x9F,0x64,0xE4,0x53, 0xE5,0xEC,0x67,0x20,0xDA,0xB6 };
-+static unsigned char cfb_cipher48[24]={
-+ 0xF3,0x09,0x62,0x49,0xC7,0xF4, 0x30,0xB5,0x15,0xEC,0xBB,0x85,
-+ 0x97,0x5A,0x13,0x8C,0x68,0x60, 0xE2,0x38,0x34,0x3C,0xDC,0x1F };
-+static unsigned char cfb_cipher64[24]={
-+ 0xF3,0x09,0x62,0x49,0xC7,0xF4, 0x6E,0x51,0xA6,0x9E,0x83,0x9B,
-+ 0x1A,0x92,0xF7,0x84,0x03,0x46, 0x71,0x33,0x89,0x8E,0xA6,0x22 };
-+
-+static unsigned char ofb_key[8]={0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef};
-+static unsigned char ofb_iv[8]={0x12,0x34,0x56,0x78,0x90,0xab,0xcd,0xef};
-+static unsigned char ofb_buf1[24],ofb_buf2[24],ofb_tmp[8];
-+static unsigned char ofb_cipher[24]=
-+ {
-+ 0xf3,0x09,0x62,0x49,0xc7,0xf4,0x6e,0x51,
-+ 0x35,0xf2,0x4a,0x24,0x2e,0xeb,0x3d,0x3f,
-+ 0x3d,0x6d,0x5b,0xe3,0x25,0x5a,0xf8,0xc3
-+ };
-+
-+DES_LONG cbc_cksum_ret=0xB462FEF7L;
-+unsigned char cbc_cksum_data[8]={0x1D,0x26,0x93,0x97,0xf7,0xfe,0x62,0xb4};
-+
-+#ifndef NOPROTO
-+static char *pt(unsigned char *p);
-+static int cfb_test(int bits, unsigned char *cfb_cipher);
-+static int cfb64_test(unsigned char *cfb_cipher);
-+static int ede_cfb64_test(unsigned char *cfb_cipher);
-+#else
-+static char *pt();
-+static int cfb_test();
-+static int cfb64_test();
-+static int ede_cfb64_test();
-+#endif
-+
-+int main(argc,argv)
-+int argc;
-+char *argv[];
-+ {
-+ int i,j,err=0;
-+ des_cblock in,out,outin,iv3;
-+ des_key_schedule ks,ks2,ks3;
-+ unsigned char cbc_in[40];
-+ unsigned char cbc_out[40];
-+ DES_LONG cs;
-+ unsigned char qret[4][4],cret[8];
-+ DES_LONG lqret[4];
-+ int num;
-+ char *str;
-+
-+ printf("Doing ecb\n");
-+ for (i=0; i<NUM_TESTS; i++)
-+ {
-+ if ((j=des_key_sched((C_Block *)(key_data[i]),ks)) != 0)
-+ {
-+ printf("Key error %2d:%d\n",i+1,j);
-+ err=1;
-+ }
-+ memcpy(in,plain_data[i],8);
-+ memset(out,0,8);
-+ memset(outin,0,8);
-+ des_ecb_encrypt((C_Block *)in,(C_Block *)out,ks,DES_ENCRYPT);
-+ des_ecb_encrypt((C_Block *)out,(C_Block *)outin,ks,DES_DECRYPT);
-+
-+ if (memcmp(out,cipher_data[i],8) != 0)
-+ {
-+ printf("Encryption error %2d\nk=%s p=%s o=%s act=%s\n",
-+ i+1,pt(key_data[i]),pt(in),pt(cipher_data[i]),
-+ pt(out));
-+ err=1;
-+ }
-+ if (memcmp(in,outin,8) != 0)
-+ {
-+ printf("Decryption error %2d\nk=%s p=%s o=%s act=%s\n",
-+ i+1,pt(key_data[i]),pt(out),pt(in),pt(outin));
-+ err=1;
-+ }
-+ }
-+
-+#ifndef LIBDES_LIT
-+ printf("Doing ede ecb\n");
-+ for (i=0; i<(NUM_TESTS-1); i++)
-+ {
-+ if ((j=des_key_sched((C_Block *)(key_data[i]),ks)) != 0)
-+ {
-+ err=1;
-+ printf("Key error %2d:%d\n",i+1,j);
-+ }
-+ if ((j=des_key_sched((C_Block *)(key_data[i+1]),ks2)) != 0)
-+ {
-+ printf("Key error %2d:%d\n",i+2,j);
-+ err=1;
-+ }
-+ if ((j=des_key_sched((C_Block *)(key_data[i+2]),ks3)) != 0)
-+ {
-+ printf("Key error %2d:%d\n",i+3,j);
-+ err=1;
-+ }
-+ memcpy(in,plain_data[i],8);
-+ memset(out,0,8);
-+ memset(outin,0,8);
-+ des_ecb2_encrypt((C_Block *)in,(C_Block *)out,ks,ks2,
-+ DES_ENCRYPT);
-+ des_ecb2_encrypt((C_Block *)out,(C_Block *)outin,ks,ks2,
-+ DES_DECRYPT);
-+
-+ if (memcmp(out,cipher_ecb2[i],8) != 0)
-+ {
-+ printf("Encryption error %2d\nk=%s p=%s o=%s act=%s\n",
-+ i+1,pt(key_data[i]),pt(in),pt(cipher_ecb2[i]),
-+ pt(out));
-+ err=1;
-+ }
-+ if (memcmp(in,outin,8) != 0)
-+ {
-+ printf("Decryption error %2d\nk=%s p=%s o=%s act=%s\n",
-+ i+1,pt(key_data[i]),pt(out),pt(in),pt(outin));
-+ err=1;
-+ }
-+ }
-+#endif
-+
-+ printf("Doing cbc\n");
-+ if ((j=des_key_sched((C_Block *)cbc_key,ks)) != 0)
-+ {
-+ printf("Key error %d\n",j);
-+ err=1;
-+ }
-+ memset(cbc_out,0,40);
-+ memset(cbc_in,0,40);
-+ memcpy(iv3,cbc_iv,sizeof(cbc_iv));
-+ des_ncbc_encrypt((C_Block *)cbc_data,(C_Block *)cbc_out,
-+ (long)strlen((char *)cbc_data)+1,ks,
-+ (C_Block *)iv3,DES_ENCRYPT);
-+ if (memcmp(cbc_out,cbc_ok,32) != 0)
-+ printf("cbc_encrypt encrypt error\n");
-+
-+ memcpy(iv3,cbc_iv,sizeof(cbc_iv));
-+ des_ncbc_encrypt((C_Block *)cbc_out,(C_Block *)cbc_in,
-+ (long)strlen((char *)cbc_data)+1,ks,
-+ (C_Block *)iv3,DES_DECRYPT);
-+ if (memcmp(cbc_in,cbc_data,strlen((char *)cbc_data)) != 0)
-+ {
-+ printf("cbc_encrypt decrypt error\n");
-+ err=1;
-+ }
-+
-+#ifndef LIBDES_LIT
-+ printf("Doing desx cbc\n");
-+ if ((j=des_key_sched((C_Block *)cbc_key,ks)) != 0)
-+ {
-+ printf("Key error %d\n",j);
-+ err=1;
-+ }
-+ memset(cbc_out,0,40);
-+ memset(cbc_in,0,40);
-+ memcpy(iv3,cbc_iv,sizeof(cbc_iv));
-+ des_xcbc_encrypt((C_Block *)cbc_data,(C_Block *)cbc_out,
-+ (long)strlen((char *)cbc_data)+1,ks,
-+ (C_Block *)iv3,
-+ (C_Block *)cbc2_key, (C_Block *)cbc3_key, DES_ENCRYPT);
-+ if (memcmp(cbc_out,xcbc_ok,32) != 0)
-+ {
-+ printf("des_xcbc_encrypt encrypt error\n");
-+ }
-+ memcpy(iv3,cbc_iv,sizeof(cbc_iv));
-+ des_xcbc_encrypt((C_Block *)cbc_out,(C_Block *)cbc_in,
-+ (long)strlen((char *)cbc_data)+1,ks,
-+ (C_Block *)iv3,
-+ (C_Block *)cbc2_key, (C_Block *)cbc3_key, DES_DECRYPT);
-+ if (memcmp(cbc_in,cbc_data,strlen((char *)cbc_data)+1) != 0)
-+ {
-+ printf("des_xcbc_encrypt decrypt error\n");
-+ err=1;
-+ }
-+#endif
-+
-+ printf("Doing ede cbc\n");
-+ if ((j=des_key_sched((C_Block *)cbc_key,ks)) != 0)
-+ {
-+ printf("Key error %d\n",j);
-+ err=1;
-+ }
-+ if ((j=des_key_sched((C_Block *)cbc2_key,ks2)) != 0)
-+ {
-+ printf("Key error %d\n",j);
-+ err=1;
-+ }
-+ if ((j=des_key_sched((C_Block *)cbc3_key,ks3)) != 0)
-+ {
-+ printf("Key error %d\n",j);
-+ err=1;
-+ }
-+ memset(cbc_out,0,40);
-+ memset(cbc_in,0,40);
-+ i=strlen((char *)cbc_data)+1;
-+ /* i=((i+7)/8)*8; */
-+ memcpy(iv3,cbc_iv,sizeof(cbc_iv));
-+
-+ des_ede3_cbc_encrypt((C_Block *)cbc_data,(C_Block *)cbc_out,
-+ 16L,ks,ks2,ks3,(C_Block *)iv3,DES_ENCRYPT);
-+ des_ede3_cbc_encrypt((C_Block *)&(cbc_data[16]),
-+ (C_Block *)&(cbc_out[16]),
-+ (long)i-16,ks,ks2,ks3,(C_Block *)iv3,DES_ENCRYPT);
-+ if (memcmp(cbc_out,cbc3_ok,
-+ (unsigned int)(strlen((char *)cbc_data)+1+7)/8*8) != 0)
-+ {
-+ printf("des_ede3_cbc_encrypt encrypt error\n");
-+ err=1;
-+ }
-+
-+ memcpy(iv3,cbc_iv,sizeof(cbc_iv));
-+ des_ede3_cbc_encrypt((C_Block *)cbc_out,(C_Block *)cbc_in,
-+ (long)i,ks,ks2,ks3,(C_Block *)iv3,DES_DECRYPT);
-+ if (memcmp(cbc_in,cbc_data,strlen(cbc_data)+1) != 0)
-+ {
-+ printf("des_ede3_cbc_encrypt decrypt error\n");
-+ err=1;
-+ }
-+
-+#ifndef LIBDES_LIT
-+ printf("Doing pcbc\n");
-+ if ((j=des_key_sched((C_Block *)cbc_key,ks)) != 0)
-+ {
-+ printf("Key error %d\n",j);
-+ err=1;
-+ }
-+ memset(cbc_out,0,40);
-+ memset(cbc_in,0,40);
-+ des_pcbc_encrypt((C_Block *)cbc_data,(C_Block *)cbc_out,
-+ (long)strlen(cbc_data)+1,ks,(C_Block *)cbc_iv,DES_ENCRYPT);
-+ if (memcmp(cbc_out,pcbc_ok,32) != 0)
-+ {
-+ printf("pcbc_encrypt encrypt error\n");
-+ err=1;
-+ }
-+ des_pcbc_encrypt((C_Block *)cbc_out,(C_Block *)cbc_in,
-+ (long)strlen(cbc_data)+1,ks,(C_Block *)cbc_iv,DES_DECRYPT);
-+ if (memcmp(cbc_in,cbc_data,strlen(cbc_data)+1) != 0)
-+ {
-+ printf("pcbc_encrypt decrypt error\n");
-+ err=1;
-+ }
-+
-+ printf("Doing ");
-+ printf("cfb8 ");
-+ err+=cfb_test(8,cfb_cipher8);
-+ printf("cfb16 ");
-+ err+=cfb_test(16,cfb_cipher16);
-+ printf("cfb32 ");
-+ err+=cfb_test(32,cfb_cipher32);
-+ printf("cfb48 ");
-+ err+=cfb_test(48,cfb_cipher48);
-+ printf("cfb64 ");
-+ err+=cfb_test(64,cfb_cipher64);
-+
-+ printf("cfb64() ");
-+ err+=cfb64_test(cfb_cipher64);
-+
-+ memcpy(cfb_tmp,cfb_iv,sizeof(cfb_iv));
-+ for (i=0; i<sizeof(plain); i++)
-+ des_cfb_encrypt(&(plain[i]),&(cfb_buf1[i]),
-+ 8,(long)1,ks,(C_Block *)cfb_tmp,DES_ENCRYPT);
-+ if (memcmp(cfb_cipher8,cfb_buf1,sizeof(plain)) != 0)
-+ {
-+ printf("cfb_encrypt small encrypt error\n");
-+ err=1;
-+ }
-+
-+ memcpy(cfb_tmp,cfb_iv,sizeof(cfb_iv));
-+ for (i=0; i<sizeof(plain); i++)
-+ des_cfb_encrypt(&(cfb_buf1[i]),&(cfb_buf2[i]),
-+ 8,(long)1,ks,(C_Block *)cfb_tmp,DES_DECRYPT);
-+ if (memcmp(plain,cfb_buf2,sizeof(plain)) != 0)
-+ {
-+ printf("cfb_encrypt small decrypt error\n");
-+ err=1;
-+ }
-+
-+ printf("ede_cfb64() ");
-+ err+=ede_cfb64_test(cfb_cipher64);
-+
-+ printf("done\n");
-+
-+ printf("Doing ofb\n");
-+ des_key_sched((C_Block *)ofb_key,ks);
-+ memcpy(ofb_tmp,ofb_iv,sizeof(ofb_iv));
-+ des_ofb_encrypt(plain,ofb_buf1,64,(long)sizeof(plain)/8,ks,
-+ (C_Block *)ofb_tmp);
-+ if (memcmp(ofb_cipher,ofb_buf1,sizeof(ofb_buf1)) != 0)
-+ {
-+ printf("ofb_encrypt encrypt error\n");
-+printf("%02X %02X %02X %02X %02X %02X %02X %02X\n",
-+ofb_buf1[8+0], ofb_buf1[8+1], ofb_buf1[8+2], ofb_buf1[8+3],
-+ofb_buf1[8+4], ofb_buf1[8+5], ofb_buf1[8+6], ofb_buf1[8+7]);
-+printf("%02X %02X %02X %02X %02X %02X %02X %02X\n",
-+ofb_buf1[8+0], ofb_cipher[8+1], ofb_cipher[8+2], ofb_cipher[8+3],
-+ofb_buf1[8+4], ofb_cipher[8+5], ofb_cipher[8+6], ofb_cipher[8+7]);
-+ err=1;
-+ }
-+ memcpy(ofb_tmp,ofb_iv,sizeof(ofb_iv));
-+ des_ofb_encrypt(ofb_buf1,ofb_buf2,64,(long)sizeof(ofb_buf1)/8,ks,
-+ (C_Block *)ofb_tmp);
-+ if (memcmp(plain,ofb_buf2,sizeof(ofb_buf2)) != 0)
-+ {
-+ printf("ofb_encrypt decrypt error\n");
-+printf("%02X %02X %02X %02X %02X %02X %02X %02X\n",
-+ofb_buf2[8+0], ofb_buf2[8+1], ofb_buf2[8+2], ofb_buf2[8+3],
-+ofb_buf2[8+4], ofb_buf2[8+5], ofb_buf2[8+6], ofb_buf2[8+7]);
-+printf("%02X %02X %02X %02X %02X %02X %02X %02X\n",
-+plain[8+0], plain[8+1], plain[8+2], plain[8+3],
-+plain[8+4], plain[8+5], plain[8+6], plain[8+7]);
-+ err=1;
-+ }
-+
-+ printf("Doing ofb64\n");
-+ des_key_sched((C_Block *)ofb_key,ks);
-+ memcpy(ofb_tmp,ofb_iv,sizeof(ofb_iv));
-+ memset(ofb_buf1,0,sizeof(ofb_buf1));
-+ memset(ofb_buf2,0,sizeof(ofb_buf1));
-+ num=0;
-+ for (i=0; i<sizeof(plain); i++)
-+ {
-+ des_ofb64_encrypt(&(plain[i]),&(ofb_buf1[i]),1,ks,
-+ (C_Block *)ofb_tmp,&num);
-+ }
-+ if (memcmp(ofb_cipher,ofb_buf1,sizeof(ofb_buf1)) != 0)
-+ {
-+ printf("ofb64_encrypt encrypt error\n");
-+ err=1;
-+ }
-+ memcpy(ofb_tmp,ofb_iv,sizeof(ofb_iv));
-+ num=0;
-+ des_ofb64_encrypt(ofb_buf1,ofb_buf2,(long)sizeof(ofb_buf1),ks,
-+ (C_Block *)ofb_tmp,&num);
-+ if (memcmp(plain,ofb_buf2,sizeof(ofb_buf2)) != 0)
-+ {
-+ printf("ofb64_encrypt decrypt error\n");
-+ err=1;
-+ }
-+
-+ printf("Doing ede_ofb64\n");
-+ des_key_sched((C_Block *)ofb_key,ks);
-+ memcpy(ofb_tmp,ofb_iv,sizeof(ofb_iv));
-+ memset(ofb_buf1,0,sizeof(ofb_buf1));
-+ memset(ofb_buf2,0,sizeof(ofb_buf1));
-+ num=0;
-+ for (i=0; i<sizeof(plain); i++)
-+ {
-+ des_ede3_ofb64_encrypt(&(plain[i]),&(ofb_buf1[i]),1,ks,ks,ks,
-+ (C_Block *)ofb_tmp,&num);
-+ }
-+ if (memcmp(ofb_cipher,ofb_buf1,sizeof(ofb_buf1)) != 0)
-+ {
-+ printf("ede_ofb64_encrypt encrypt error\n");
-+ err=1;
-+ }
-+ memcpy(ofb_tmp,ofb_iv,sizeof(ofb_iv));
-+ num=0;
-+ des_ede3_ofb64_encrypt(ofb_buf1,ofb_buf2,(long)sizeof(ofb_buf1),ks,
-+ ks,ks,(C_Block *)ofb_tmp,&num);
-+ if (memcmp(plain,ofb_buf2,sizeof(ofb_buf2)) != 0)
-+ {
-+ printf("ede_ofb64_encrypt decrypt error\n");
-+ err=1;
-+ }
-+
-+ printf("Doing cbc_cksum\n");
-+ des_key_sched((C_Block *)cbc_key,ks);
-+ cs=des_cbc_cksum((C_Block *)cbc_data,(C_Block *)cret,
-+ (long)strlen(cbc_data),ks,(C_Block *)cbc_iv);
-+ if (cs != cbc_cksum_ret)
-+ {
-+ printf("bad return value (%08lX), should be %08lX\n",
-+ (unsigned long)cs,(unsigned long)cbc_cksum_ret);
-+ err=1;
-+ }
-+ if (memcmp(cret,cbc_cksum_data,8) != 0)
-+ {
-+ printf("bad cbc_cksum block returned\n");
-+ err=1;
-+ }
-+
-+ printf("Doing quad_cksum\n");
-+ cs=quad_cksum((C_Block *)cbc_data,(C_Block *)qret,
-+ (long)strlen(cbc_data),2,(C_Block *)cbc_iv);
-+ for (i=0; i<4; i++)
-+ {
-+ lqret[i]=0;
-+ memcpy(&(lqret[i]),&(qret[i][0]),4);
-+ }
-+ { /* Big-endian fix */
-+ static DES_LONG l=1;
-+ static unsigned char *c=(unsigned char *)&l;
-+ DES_LONG ll;
-+
-+ if (!c[0])
-+ {
-+ ll=lqret[0]^lqret[3];
-+ lqret[0]^=ll;
-+ lqret[3]^=ll;
-+ ll=lqret[1]^lqret[2];
-+ lqret[1]^=ll;
-+ lqret[2]^=ll;
-+ }
-+ }
-+ if (cs != 0x70d7a63aL)
-+ {
-+ printf("quad_cksum error, ret %08lx should be 70d7a63a\n",
-+ (unsigned long)cs);
-+ err=1;
-+ }
-+ if (lqret[0] != 0x327eba8dL)
-+ {
-+ printf("quad_cksum error, out[0] %08lx is not %08lx\n",
-+ (unsigned long)lqret[0],0x327eba8dL);
-+ err=1;
-+ }
-+ if (lqret[1] != 0x201a49ccL)
-+ {
-+ printf("quad_cksum error, out[1] %08lx is not %08lx\n",
-+ (unsigned long)lqret[1],0x201a49ccL);
-+ err=1;
-+ }
-+ if (lqret[2] != 0x70d7a63aL)
-+ {
-+ printf("quad_cksum error, out[2] %08lx is not %08lx\n",
-+ (unsigned long)lqret[2],0x70d7a63aL);
-+ err=1;
-+ }
-+ if (lqret[3] != 0x501c2c26L)
-+ {
-+ printf("quad_cksum error, out[3] %08lx is not %08lx\n",
-+ (unsigned long)lqret[3],0x501c2c26L);
-+ err=1;
-+ }
-+#endif
-+
-+ printf("input word alignment test");
-+ for (i=0; i<4; i++)
-+ {
-+ printf(" %d",i);
-+ des_ncbc_encrypt((C_Block *)&(cbc_out[i]),(C_Block *)cbc_in,
-+ (long)strlen(cbc_data)+1,ks,(C_Block *)cbc_iv,
-+ DES_ENCRYPT);
-+ }
-+ printf("\noutput word alignment test");
-+ for (i=0; i<4; i++)
-+ {
-+ printf(" %d",i);
-+ des_ncbc_encrypt((C_Block *)cbc_out,(C_Block *)&(cbc_in[i]),
-+ (long)strlen(cbc_data)+1,ks,(C_Block *)cbc_iv,
-+ DES_ENCRYPT);
-+ }
-+ printf("\n");
-+ printf("fast crypt test ");
-+ str=crypt("testing","ef");
-+ if (strcmp("efGnQx2725bI2",str) != 0)
-+ {
-+ printf("fast crypt error, %s should be efGnQx2725bI2\n",str);
-+ err=1;
-+ }
-+ str=crypt("bca76;23","yA");
-+ if (strcmp("yA1Rp/1hZXIJk",str) != 0)
-+ {
-+ printf("fast crypt error, %s should be yA1Rp/1hZXIJk\n",str);
-+ err=1;
-+ }
-+ printf("\n");
-+ exit(err);
-+ return(0);
-+ }
-+
-+static char *pt(p)
-+unsigned char *p;
-+ {
-+ static char bufs[10][20];
-+ static int bnum=0;
-+ char *ret;
-+ int i;
-+ static char *f="0123456789ABCDEF";
-+
-+ ret= &(bufs[bnum++][0]);
-+ bnum%=10;
-+ for (i=0; i<8; i++)
-+ {
-+ ret[i*2]=f[(p[i]>>4)&0xf];
-+ ret[i*2+1]=f[p[i]&0xf];
-+ }
-+ ret[16]='\0';
-+ return(ret);
-+ }
-+
-+#ifndef LIBDES_LIT
-+
-+static int cfb_test(bits, cfb_cipher)
-+int bits;
-+unsigned char *cfb_cipher;
-+ {
-+ des_key_schedule ks;
-+ int i,err=0;
-+
-+ des_key_sched((C_Block *)cfb_key,ks);
-+ memcpy(cfb_tmp,cfb_iv,sizeof(cfb_iv));
-+ des_cfb_encrypt(plain,cfb_buf1,bits,(long)sizeof(plain),ks,
-+ (C_Block *)cfb_tmp,DES_ENCRYPT);
-+ if (memcmp(cfb_cipher,cfb_buf1,sizeof(plain)) != 0)
-+ {
-+ err=1;
-+ printf("cfb_encrypt encrypt error\n");
-+ for (i=0; i<24; i+=8)
-+ printf("%s\n",pt(&(cfb_buf1[i])));
-+ }
-+ memcpy(cfb_tmp,cfb_iv,sizeof(cfb_iv));
-+ des_cfb_encrypt(cfb_buf1,cfb_buf2,bits,(long)sizeof(plain),ks,
-+ (C_Block *)cfb_tmp,DES_DECRYPT);
-+ if (memcmp(plain,cfb_buf2,sizeof(plain)) != 0)
-+ {
-+ err=1;
-+ printf("cfb_encrypt decrypt error\n");
-+ for (i=0; i<24; i+=8)
-+ printf("%s\n",pt(&(cfb_buf1[i])));
-+ }
-+ return(err);
-+ }
-+
-+static int cfb64_test(cfb_cipher)
-+unsigned char *cfb_cipher;
-+ {
-+ des_key_schedule ks;
-+ int err=0,i,n;
-+
-+ des_key_sched((C_Block *)cfb_key,ks);
-+ memcpy(cfb_tmp,cfb_iv,sizeof(cfb_iv));
-+ n=0;
-+ des_cfb64_encrypt(plain,cfb_buf1,(long)12,ks,
-+ (C_Block *)cfb_tmp,&n,DES_ENCRYPT);
-+ des_cfb64_encrypt(&(plain[12]),&(cfb_buf1[12]),
-+ (long)sizeof(plain)-12,ks,
-+ (C_Block *)cfb_tmp,&n,DES_ENCRYPT);
-+ if (memcmp(cfb_cipher,cfb_buf1,sizeof(plain)) != 0)
-+ {
-+ err=1;
-+ printf("cfb_encrypt encrypt error\n");
-+ for (i=0; i<24; i+=8)
-+ printf("%s\n",pt(&(cfb_buf1[i])));
-+ }
-+ memcpy(cfb_tmp,cfb_iv,sizeof(cfb_iv));
-+ n=0;
-+ des_cfb64_encrypt(cfb_buf1,cfb_buf2,(long)17,ks,
-+ (C_Block *)cfb_tmp,&n,DES_DECRYPT);
-+ des_cfb64_encrypt(&(cfb_buf1[17]),&(cfb_buf2[17]),
-+ (long)sizeof(plain)-17,ks,
-+ (C_Block *)cfb_tmp,&n,DES_DECRYPT);
-+ if (memcmp(plain,cfb_buf2,sizeof(plain)) != 0)
-+ {
-+ err=1;
-+ printf("cfb_encrypt decrypt error\n");
-+ for (i=0; i<24; i+=8)
-+ printf("%s\n",pt(&(cfb_buf2[i])));
-+ }
-+ return(err);
-+ }
-+
-+static int ede_cfb64_test(cfb_cipher)
-+unsigned char *cfb_cipher;
-+ {
-+ des_key_schedule ks;
-+ int err=0,i,n;
-+
-+ des_key_sched((C_Block *)cfb_key,ks);
-+ memcpy(cfb_tmp,cfb_iv,sizeof(cfb_iv));
-+ n=0;
-+ des_ede3_cfb64_encrypt(plain,cfb_buf1,(long)12,ks,ks,ks,
-+ (C_Block *)cfb_tmp,&n,DES_ENCRYPT);
-+ des_ede3_cfb64_encrypt(&(plain[12]),&(cfb_buf1[12]),
-+ (long)sizeof(plain)-12,ks,ks,ks,
-+ (C_Block *)cfb_tmp,&n,DES_ENCRYPT);
-+ if (memcmp(cfb_cipher,cfb_buf1,sizeof(plain)) != 0)
-+ {
-+ err=1;
-+ printf("ede_cfb_encrypt encrypt error\n");
-+ for (i=0; i<24; i+=8)
-+ printf("%s\n",pt(&(cfb_buf1[i])));
-+ }
-+ memcpy(cfb_tmp,cfb_iv,sizeof(cfb_iv));
-+ n=0;
-+ des_ede3_cfb64_encrypt(cfb_buf1,cfb_buf2,(long)17,ks,ks,ks,
-+ (C_Block *)cfb_tmp,&n,DES_DECRYPT);
-+ des_ede3_cfb64_encrypt(&(cfb_buf1[17]),&(cfb_buf2[17]),
-+ (long)sizeof(plain)-17,ks,ks,ks,
-+ (C_Block *)cfb_tmp,&n,DES_DECRYPT);
-+ if (memcmp(plain,cfb_buf2,sizeof(plain)) != 0)
-+ {
-+ err=1;
-+ printf("ede_cfb_encrypt decrypt error\n");
-+ for (i=0; i<24; i+=8)
-+ printf("%s\n",pt(&(cfb_buf2[i])));
-+ }
-+ return(err);
-+ }
-+
-+#endif
-+
---- /dev/null Tue Mar 11 13:02:56 2003
-+++ linux/crypto/ciphers/des/dx86unix.S Mon Feb 9 13:51:03 2004
-@@ -0,0 +1,3160 @@
-+/*
-+ * This file was originally generated by Michael Richardson <mcr@freeswan.org>
-+ * via the perl scripts found in the ASM subdir. It remains copyright of
-+ * Eric Young, see the file COPYRIGHT.
-+ *
-+ * This was last done on October 9, 2002.
-+ *
-+ * While this file does not need to go through cpp, we pass it through
-+ * CPP by naming it dx86unix.S instead of dx86unix.s because there is
-+ * a bug in Rules.make for .s builds - specifically it references EXTRA_CFLAGS
-+ * which may contain stuff that AS doesn't understand instead of
-+ * referencing EXTRA_AFLAGS.
-+ */
-+
-+ .file "dx86unix.S"
-+ .version "01.01"
-+.text
-+ .align 16
-+.globl des_encrypt
-+ .type des_encrypt , @function
-+des_encrypt:
-+ pushl %esi
-+ pushl %edi
-+
-+
-+ movl 12(%esp), %esi
-+ xorl %ecx, %ecx
-+ pushl %ebx
-+ pushl %ebp
-+ movl (%esi), %eax
-+ movl 28(%esp), %ebx
-+ movl 4(%esi), %edi
-+
-+
-+ roll $4, %eax
-+ movl %eax, %esi
-+ xorl %edi, %eax
-+ andl $0xf0f0f0f0, %eax
-+ xorl %eax, %esi
-+ xorl %eax, %edi
-+
-+ roll $20, %edi
-+ movl %edi, %eax
-+ xorl %esi, %edi
-+ andl $0xfff0000f, %edi
-+ xorl %edi, %eax
-+ xorl %edi, %esi
-+
-+ roll $14, %eax
-+ movl %eax, %edi
-+ xorl %esi, %eax
-+ andl $0x33333333, %eax
-+ xorl %eax, %edi
-+ xorl %eax, %esi
-+
-+ roll $22, %esi
-+ movl %esi, %eax
-+ xorl %edi, %esi
-+ andl $0x03fc03fc, %esi
-+ xorl %esi, %eax
-+ xorl %esi, %edi
-+
-+ roll $9, %eax
-+ movl %eax, %esi
-+ xorl %edi, %eax
-+ andl $0xaaaaaaaa, %eax
-+ xorl %eax, %esi
-+ xorl %eax, %edi
-+
-+.byte 209
-+.byte 199
-+ movl 24(%esp), %ebp
-+ cmpl $0, %ebx
-+ je .L000start_decrypt
-+
-+
-+ movl (%ebp), %eax
-+ xorl %ebx, %ebx
-+ movl 4(%ebp), %edx
-+ xorl %esi, %eax
-+ xorl %esi, %edx
-+ andl $0xfcfcfcfc, %eax
-+ andl $0xcfcfcfcf, %edx
-+ movb %al, %bl
-+ movb %ah, %cl
-+ rorl $4, %edx
-+ movl des_SPtrans(%ebx),%ebp
-+ movb %dl, %bl
-+ xorl %ebp, %edi
-+ movl 0x200+des_SPtrans(%ecx),%ebp
-+ xorl %ebp, %edi
-+ movb %dh, %cl
-+ shrl $16, %eax
-+ movl 0x100+des_SPtrans(%ebx),%ebp
-+ xorl %ebp, %edi
-+ movb %ah, %bl
-+ shrl $16, %edx
-+ movl 0x300+des_SPtrans(%ecx),%ebp
-+ xorl %ebp, %edi
-+ movl 24(%esp), %ebp
-+ movb %dh, %cl
-+ andl $0xff, %eax
-+ andl $0xff, %edx
-+ movl 0x600+des_SPtrans(%ebx),%ebx
-+ xorl %ebx, %edi
-+ movl 0x700+des_SPtrans(%ecx),%ebx
-+ xorl %ebx, %edi
-+ movl 0x400+des_SPtrans(%eax),%ebx
-+ xorl %ebx, %edi
-+ movl 0x500+des_SPtrans(%edx),%ebx
-+ xorl %ebx, %edi
-+
-+
-+ movl 8(%ebp), %eax
-+ xorl %ebx, %ebx
-+ movl 12(%ebp), %edx
-+ xorl %edi, %eax
-+ xorl %edi, %edx
-+ andl $0xfcfcfcfc, %eax
-+ andl $0xcfcfcfcf, %edx
-+ movb %al, %bl
-+ movb %ah, %cl
-+ rorl $4, %edx
-+ movl des_SPtrans(%ebx),%ebp
-+ movb %dl, %bl
-+ xorl %ebp, %esi
-+ movl 0x200+des_SPtrans(%ecx),%ebp
-+ xorl %ebp, %esi
-+ movb %dh, %cl
-+ shrl $16, %eax
-+ movl 0x100+des_SPtrans(%ebx),%ebp
-+ xorl %ebp, %esi
-+ movb %ah, %bl
-+ shrl $16, %edx
-+ movl 0x300+des_SPtrans(%ecx),%ebp
-+ xorl %ebp, %esi
-+ movl 24(%esp), %ebp
-+ movb %dh, %cl
-+ andl $0xff, %eax
-+ andl $0xff, %edx
-+ movl 0x600+des_SPtrans(%ebx),%ebx
-+ xorl %ebx, %esi
-+ movl 0x700+des_SPtrans(%ecx),%ebx
-+ xorl %ebx, %esi
-+ movl 0x400+des_SPtrans(%eax),%ebx
-+ xorl %ebx, %esi
-+ movl 0x500+des_SPtrans(%edx),%ebx
-+ xorl %ebx, %esi
-+
-+
-+ movl 16(%ebp), %eax
-+ xorl %ebx, %ebx
-+ movl 20(%ebp), %edx
-+ xorl %esi, %eax
-+ xorl %esi, %edx
-+ andl $0xfcfcfcfc, %eax
-+ andl $0xcfcfcfcf, %edx
-+ movb %al, %bl
-+ movb %ah, %cl
-+ rorl $4, %edx
-+ movl des_SPtrans(%ebx),%ebp
-+ movb %dl, %bl
-+ xorl %ebp, %edi
-+ movl 0x200+des_SPtrans(%ecx),%ebp
-+ xorl %ebp, %edi
-+ movb %dh, %cl
-+ shrl $16, %eax
-+ movl 0x100+des_SPtrans(%ebx),%ebp
-+ xorl %ebp, %edi
-+ movb %ah, %bl
-+ shrl $16, %edx
-+ movl 0x300+des_SPtrans(%ecx),%ebp
-+ xorl %ebp, %edi
-+ movl 24(%esp), %ebp
-+ movb %dh, %cl
-+ andl $0xff, %eax
-+ andl $0xff, %edx
-+ movl 0x600+des_SPtrans(%ebx),%ebx
-+ xorl %ebx, %edi
-+ movl 0x700+des_SPtrans(%ecx),%ebx
-+ xorl %ebx, %edi
-+ movl 0x400+des_SPtrans(%eax),%ebx
-+ xorl %ebx, %edi
-+ movl 0x500+des_SPtrans(%edx),%ebx
-+ xorl %ebx, %edi
-+
-+
-+ movl 24(%ebp), %eax
-+ xorl %ebx, %ebx
-+ movl 28(%ebp), %edx
-+ xorl %edi, %eax
-+ xorl %edi, %edx
-+ andl $0xfcfcfcfc, %eax
-+ andl $0xcfcfcfcf, %edx
-+ movb %al, %bl
-+ movb %ah, %cl
-+ rorl $4, %edx
-+ movl des_SPtrans(%ebx),%ebp
-+ movb %dl, %bl
-+ xorl %ebp, %esi
-+ movl 0x200+des_SPtrans(%ecx),%ebp
-+ xorl %ebp, %esi
-+ movb %dh, %cl
-+ shrl $16, %eax
-+ movl 0x100+des_SPtrans(%ebx),%ebp
-+ xorl %ebp, %esi
-+ movb %ah, %bl
-+ shrl $16, %edx
-+ movl 0x300+des_SPtrans(%ecx),%ebp
-+ xorl %ebp, %esi
-+ movl 24(%esp), %ebp
-+ movb %dh, %cl
-+ andl $0xff, %eax
-+ andl $0xff, %edx
-+ movl 0x600+des_SPtrans(%ebx),%ebx
-+ xorl %ebx, %esi
-+ movl 0x700+des_SPtrans(%ecx),%ebx
-+ xorl %ebx, %esi
-+ movl 0x400+des_SPtrans(%eax),%ebx
-+ xorl %ebx, %esi
-+ movl 0x500+des_SPtrans(%edx),%ebx
-+ xorl %ebx, %esi
-+
-+
-+ movl 32(%ebp), %eax
-+ xorl %ebx, %ebx
-+ movl 36(%ebp), %edx
-+ xorl %esi, %eax
-+ xorl %esi, %edx
-+ andl $0xfcfcfcfc, %eax
-+ andl $0xcfcfcfcf, %edx
-+ movb %al, %bl
-+ movb %ah, %cl
-+ rorl $4, %edx
-+ movl des_SPtrans(%ebx),%ebp
-+ movb %dl, %bl
-+ xorl %ebp, %edi
-+ movl 0x200+des_SPtrans(%ecx),%ebp
-+ xorl %ebp, %edi
-+ movb %dh, %cl
-+ shrl $16, %eax
-+ movl 0x100+des_SPtrans(%ebx),%ebp
-+ xorl %ebp, %edi
-+ movb %ah, %bl
-+ shrl $16, %edx
-+ movl 0x300+des_SPtrans(%ecx),%ebp
-+ xorl %ebp, %edi
-+ movl 24(%esp), %ebp
-+ movb %dh, %cl
-+ andl $0xff, %eax
-+ andl $0xff, %edx
-+ movl 0x600+des_SPtrans(%ebx),%ebx
-+ xorl %ebx, %edi
-+ movl 0x700+des_SPtrans(%ecx),%ebx
-+ xorl %ebx, %edi
-+ movl 0x400+des_SPtrans(%eax),%ebx
-+ xorl %ebx, %edi
-+ movl 0x500+des_SPtrans(%edx),%ebx
-+ xorl %ebx, %edi
-+
-+
-+ movl 40(%ebp), %eax
-+ xorl %ebx, %ebx
-+ movl 44(%ebp), %edx
-+ xorl %edi, %eax
-+ xorl %edi, %edx
-+ andl $0xfcfcfcfc, %eax
-+ andl $0xcfcfcfcf, %edx
-+ movb %al, %bl
-+ movb %ah, %cl
-+ rorl $4, %edx
-+ movl des_SPtrans(%ebx),%ebp
-+ movb %dl, %bl
-+ xorl %ebp, %esi
-+ movl 0x200+des_SPtrans(%ecx),%ebp
-+ xorl %ebp, %esi
-+ movb %dh, %cl
-+ shrl $16, %eax
-+ movl 0x100+des_SPtrans(%ebx),%ebp
-+ xorl %ebp, %esi
-+ movb %ah, %bl
-+ shrl $16, %edx
-+ movl 0x300+des_SPtrans(%ecx),%ebp
-+ xorl %ebp, %esi
-+ movl 24(%esp), %ebp
-+ movb %dh, %cl
-+ andl $0xff, %eax
-+ andl $0xff, %edx
-+ movl 0x600+des_SPtrans(%ebx),%ebx
-+ xorl %ebx, %esi
-+ movl 0x700+des_SPtrans(%ecx),%ebx
-+ xorl %ebx, %esi
-+ movl 0x400+des_SPtrans(%eax),%ebx
-+ xorl %ebx, %esi
-+ movl 0x500+des_SPtrans(%edx),%ebx
-+ xorl %ebx, %esi
-+
-+
-+ movl 48(%ebp), %eax
-+ xorl %ebx, %ebx
-+ movl 52(%ebp), %edx
-+ xorl %esi, %eax
-+ xorl %esi, %edx
-+ andl $0xfcfcfcfc, %eax
-+ andl $0xcfcfcfcf, %edx
-+ movb %al, %bl
-+ movb %ah, %cl
-+ rorl $4, %edx
-+ movl des_SPtrans(%ebx),%ebp
-+ movb %dl, %bl
-+ xorl %ebp, %edi
-+ movl 0x200+des_SPtrans(%ecx),%ebp
-+ xorl %ebp, %edi
-+ movb %dh, %cl
-+ shrl $16, %eax
-+ movl 0x100+des_SPtrans(%ebx),%ebp
-+ xorl %ebp, %edi
-+ movb %ah, %bl
-+ shrl $16, %edx
-+ movl 0x300+des_SPtrans(%ecx),%ebp
-+ xorl %ebp, %edi
-+ movl 24(%esp), %ebp
-+ movb %dh, %cl
-+ andl $0xff, %eax
-+ andl $0xff, %edx
-+ movl 0x600+des_SPtrans(%ebx),%ebx
-+ xorl %ebx, %edi
-+ movl 0x700+des_SPtrans(%ecx),%ebx
-+ xorl %ebx, %edi
-+ movl 0x400+des_SPtrans(%eax),%ebx
-+ xorl %ebx, %edi
-+ movl 0x500+des_SPtrans(%edx),%ebx
-+ xorl %ebx, %edi
-+
-+
-+ movl 56(%ebp), %eax
-+ xorl %ebx, %ebx
-+ movl 60(%ebp), %edx
-+ xorl %edi, %eax
-+ xorl %edi, %edx
-+ andl $0xfcfcfcfc, %eax
-+ andl $0xcfcfcfcf, %edx
-+ movb %al, %bl
-+ movb %ah, %cl
-+ rorl $4, %edx
-+ movl des_SPtrans(%ebx),%ebp
-+ movb %dl, %bl
-+ xorl %ebp, %esi
-+ movl 0x200+des_SPtrans(%ecx),%ebp
-+ xorl %ebp, %esi
-+ movb %dh, %cl
-+ shrl $16, %eax
-+ movl 0x100+des_SPtrans(%ebx),%ebp
-+ xorl %ebp, %esi
-+ movb %ah, %bl
-+ shrl $16, %edx
-+ movl 0x300+des_SPtrans(%ecx),%ebp
-+ xorl %ebp, %esi
-+ movl 24(%esp), %ebp
-+ movb %dh, %cl
-+ andl $0xff, %eax
-+ andl $0xff, %edx
-+ movl 0x600+des_SPtrans(%ebx),%ebx
-+ xorl %ebx, %esi
-+ movl 0x700+des_SPtrans(%ecx),%ebx
-+ xorl %ebx, %esi
-+ movl 0x400+des_SPtrans(%eax),%ebx
-+ xorl %ebx, %esi
-+ movl 0x500+des_SPtrans(%edx),%ebx
-+ xorl %ebx, %esi
-+
-+
-+ movl 64(%ebp), %eax
-+ xorl %ebx, %ebx
-+ movl 68(%ebp), %edx
-+ xorl %esi, %eax
-+ xorl %esi, %edx
-+ andl $0xfcfcfcfc, %eax
-+ andl $0xcfcfcfcf, %edx
-+ movb %al, %bl
-+ movb %ah, %cl
-+ rorl $4, %edx
-+ movl des_SPtrans(%ebx),%ebp
-+ movb %dl, %bl
-+ xorl %ebp, %edi
-+ movl 0x200+des_SPtrans(%ecx),%ebp
-+ xorl %ebp, %edi
-+ movb %dh, %cl
-+ shrl $16, %eax
-+ movl 0x100+des_SPtrans(%ebx),%ebp
-+ xorl %ebp, %edi
-+ movb %ah, %bl
-+ shrl $16, %edx
-+ movl 0x300+des_SPtrans(%ecx),%ebp
-+ xorl %ebp, %edi
-+ movl 24(%esp), %ebp
-+ movb %dh, %cl
-+ andl $0xff, %eax
-+ andl $0xff, %edx
-+ movl 0x600+des_SPtrans(%ebx),%ebx
-+ xorl %ebx, %edi
-+ movl 0x700+des_SPtrans(%ecx),%ebx
-+ xorl %ebx, %edi
-+ movl 0x400+des_SPtrans(%eax),%ebx
-+ xorl %ebx, %edi
-+ movl 0x500+des_SPtrans(%edx),%ebx
-+ xorl %ebx, %edi
-+
-+
-+ movl 72(%ebp), %eax
-+ xorl %ebx, %ebx
-+ movl 76(%ebp), %edx
-+ xorl %edi, %eax
-+ xorl %edi, %edx
-+ andl $0xfcfcfcfc, %eax
-+ andl $0xcfcfcfcf, %edx
-+ movb %al, %bl
-+ movb %ah, %cl
-+ rorl $4, %edx
-+ movl des_SPtrans(%ebx),%ebp
-+ movb %dl, %bl
-+ xorl %ebp, %esi
-+ movl 0x200+des_SPtrans(%ecx),%ebp
-+ xorl %ebp, %esi
-+ movb %dh, %cl
-+ shrl $16, %eax
-+ movl 0x100+des_SPtrans(%ebx),%ebp
-+ xorl %ebp, %esi
-+ movb %ah, %bl
-+ shrl $16, %edx
-+ movl 0x300+des_SPtrans(%ecx),%ebp
-+ xorl %ebp, %esi
-+ movl 24(%esp), %ebp
-+ movb %dh, %cl
-+ andl $0xff, %eax
-+ andl $0xff, %edx
-+ movl 0x600+des_SPtrans(%ebx),%ebx
-+ xorl %ebx, %esi
-+ movl 0x700+des_SPtrans(%ecx),%ebx
-+ xorl %ebx, %esi
-+ movl 0x400+des_SPtrans(%eax),%ebx
-+ xorl %ebx, %esi
-+ movl 0x500+des_SPtrans(%edx),%ebx
-+ xorl %ebx, %esi
-+
-+
-+ movl 80(%ebp), %eax
-+ xorl %ebx, %ebx
-+ movl 84(%ebp), %edx
-+ xorl %esi, %eax
-+ xorl %esi, %edx
-+ andl $0xfcfcfcfc, %eax
-+ andl $0xcfcfcfcf, %edx
-+ movb %al, %bl
-+ movb %ah, %cl
-+ rorl $4, %edx
-+ movl des_SPtrans(%ebx),%ebp
-+ movb %dl, %bl
-+ xorl %ebp, %edi
-+ movl 0x200+des_SPtrans(%ecx),%ebp
-+ xorl %ebp, %edi
-+ movb %dh, %cl
-+ shrl $16, %eax
-+ movl 0x100+des_SPtrans(%ebx),%ebp
-+ xorl %ebp, %edi
-+ movb %ah, %bl
-+ shrl $16, %edx
-+ movl 0x300+des_SPtrans(%ecx),%ebp
-+ xorl %ebp, %edi
-+ movl 24(%esp), %ebp
-+ movb %dh, %cl
-+ andl $0xff, %eax
-+ andl $0xff, %edx
-+ movl 0x600+des_SPtrans(%ebx),%ebx
-+ xorl %ebx, %edi
-+ movl 0x700+des_SPtrans(%ecx),%ebx
-+ xorl %ebx, %edi
-+ movl 0x400+des_SPtrans(%eax),%ebx
-+ xorl %ebx, %edi
-+ movl 0x500+des_SPtrans(%edx),%ebx
-+ xorl %ebx, %edi
-+
-+
-+ movl 88(%ebp), %eax
-+ xorl %ebx, %ebx
-+ movl 92(%ebp), %edx
-+ xorl %edi, %eax
-+ xorl %edi, %edx
-+ andl $0xfcfcfcfc, %eax
-+ andl $0xcfcfcfcf, %edx
-+ movb %al, %bl
-+ movb %ah, %cl
-+ rorl $4, %edx
-+ movl des_SPtrans(%ebx),%ebp
-+ movb %dl, %bl
-+ xorl %ebp, %esi
-+ movl 0x200+des_SPtrans(%ecx),%ebp
-+ xorl %ebp, %esi
-+ movb %dh, %cl
-+ shrl $16, %eax
-+ movl 0x100+des_SPtrans(%ebx),%ebp
-+ xorl %ebp, %esi
-+ movb %ah, %bl
-+ shrl $16, %edx
-+ movl 0x300+des_SPtrans(%ecx),%ebp
-+ xorl %ebp, %esi
-+ movl 24(%esp), %ebp
-+ movb %dh, %cl
-+ andl $0xff, %eax
-+ andl $0xff, %edx
-+ movl 0x600+des_SPtrans(%ebx),%ebx
-+ xorl %ebx, %esi
-+ movl 0x700+des_SPtrans(%ecx),%ebx
-+ xorl %ebx, %esi
-+ movl 0x400+des_SPtrans(%eax),%ebx
-+ xorl %ebx, %esi
-+ movl 0x500+des_SPtrans(%edx),%ebx
-+ xorl %ebx, %esi
-+
-+
-+ movl 96(%ebp), %eax
-+ xorl %ebx, %ebx
-+ movl 100(%ebp), %edx
-+ xorl %esi, %eax
-+ xorl %esi, %edx
-+ andl $0xfcfcfcfc, %eax
-+ andl $0xcfcfcfcf, %edx
-+ movb %al, %bl
-+ movb %ah, %cl
-+ rorl $4, %edx
-+ movl des_SPtrans(%ebx),%ebp
-+ movb %dl, %bl
-+ xorl %ebp, %edi
-+ movl 0x200+des_SPtrans(%ecx),%ebp
-+ xorl %ebp, %edi
-+ movb %dh, %cl
-+ shrl $16, %eax
-+ movl 0x100+des_SPtrans(%ebx),%ebp
-+ xorl %ebp, %edi
-+ movb %ah, %bl
-+ shrl $16, %edx
-+ movl 0x300+des_SPtrans(%ecx),%ebp
-+ xorl %ebp, %edi
-+ movl 24(%esp), %ebp
-+ movb %dh, %cl
-+ andl $0xff, %eax
-+ andl $0xff, %edx
-+ movl 0x600+des_SPtrans(%ebx),%ebx
-+ xorl %ebx, %edi
-+ movl 0x700+des_SPtrans(%ecx),%ebx
-+ xorl %ebx, %edi
-+ movl 0x400+des_SPtrans(%eax),%ebx
-+ xorl %ebx, %edi
-+ movl 0x500+des_SPtrans(%edx),%ebx
-+ xorl %ebx, %edi
-+
-+
-+ movl 104(%ebp), %eax
-+ xorl %ebx, %ebx
-+ movl 108(%ebp), %edx
-+ xorl %edi, %eax
-+ xorl %edi, %edx
-+ andl $0xfcfcfcfc, %eax
-+ andl $0xcfcfcfcf, %edx
-+ movb %al, %bl
-+ movb %ah, %cl
-+ rorl $4, %edx
-+ movl des_SPtrans(%ebx),%ebp
-+ movb %dl, %bl
-+ xorl %ebp, %esi
-+ movl 0x200+des_SPtrans(%ecx),%ebp
-+ xorl %ebp, %esi
-+ movb %dh, %cl
-+ shrl $16, %eax
-+ movl 0x100+des_SPtrans(%ebx),%ebp
-+ xorl %ebp, %esi
-+ movb %ah, %bl
-+ shrl $16, %edx
-+ movl 0x300+des_SPtrans(%ecx),%ebp
-+ xorl %ebp, %esi
-+ movl 24(%esp), %ebp
-+ movb %dh, %cl
-+ andl $0xff, %eax
-+ andl $0xff, %edx
-+ movl 0x600+des_SPtrans(%ebx),%ebx
-+ xorl %ebx, %esi
-+ movl 0x700+des_SPtrans(%ecx),%ebx
-+ xorl %ebx, %esi
-+ movl 0x400+des_SPtrans(%eax),%ebx
-+ xorl %ebx, %esi
-+ movl 0x500+des_SPtrans(%edx),%ebx
-+ xorl %ebx, %esi
-+
-+
-+ movl 112(%ebp), %eax
-+ xorl %ebx, %ebx
-+ movl 116(%ebp), %edx
-+ xorl %esi, %eax
-+ xorl %esi, %edx
-+ andl $0xfcfcfcfc, %eax
-+ andl $0xcfcfcfcf, %edx
-+ movb %al, %bl
-+ movb %ah, %cl
-+ rorl $4, %edx
-+ movl des_SPtrans(%ebx),%ebp
-+ movb %dl, %bl
-+ xorl %ebp, %edi
-+ movl 0x200+des_SPtrans(%ecx),%ebp
-+ xorl %ebp, %edi
-+ movb %dh, %cl
-+ shrl $16, %eax
-+ movl 0x100+des_SPtrans(%ebx),%ebp
-+ xorl %ebp, %edi
-+ movb %ah, %bl
-+ shrl $16, %edx
-+ movl 0x300+des_SPtrans(%ecx),%ebp
-+ xorl %ebp, %edi
-+ movl 24(%esp), %ebp
-+ movb %dh, %cl
-+ andl $0xff, %eax
-+ andl $0xff, %edx
-+ movl 0x600+des_SPtrans(%ebx),%ebx
-+ xorl %ebx, %edi
-+ movl 0x700+des_SPtrans(%ecx),%ebx
-+ xorl %ebx, %edi
-+ movl 0x400+des_SPtrans(%eax),%ebx
-+ xorl %ebx, %edi
-+ movl 0x500+des_SPtrans(%edx),%ebx
-+ xorl %ebx, %edi
-+
-+
-+ movl 120(%ebp), %eax
-+ xorl %ebx, %ebx
-+ movl 124(%ebp), %edx
-+ xorl %edi, %eax
-+ xorl %edi, %edx
-+ andl $0xfcfcfcfc, %eax
-+ andl $0xcfcfcfcf, %edx
-+ movb %al, %bl
-+ movb %ah, %cl
-+ rorl $4, %edx
-+ movl des_SPtrans(%ebx),%ebp
-+ movb %dl, %bl
-+ xorl %ebp, %esi
-+ movl 0x200+des_SPtrans(%ecx),%ebp
-+ xorl %ebp, %esi
-+ movb %dh, %cl
-+ shrl $16, %eax
-+ movl 0x100+des_SPtrans(%ebx),%ebp
-+ xorl %ebp, %esi
-+ movb %ah, %bl
-+ shrl $16, %edx
-+ movl 0x300+des_SPtrans(%ecx),%ebp
-+ xorl %ebp, %esi
-+ movl 24(%esp), %ebp
-+ movb %dh, %cl
-+ andl $0xff, %eax
-+ andl $0xff, %edx
-+ movl 0x600+des_SPtrans(%ebx),%ebx
-+ xorl %ebx, %esi
-+ movl 0x700+des_SPtrans(%ecx),%ebx
-+ xorl %ebx, %esi
-+ movl 0x400+des_SPtrans(%eax),%ebx
-+ xorl %ebx, %esi
-+ movl 0x500+des_SPtrans(%edx),%ebx
-+ xorl %ebx, %esi
-+ jmp .L001end
-+.L000start_decrypt:
-+
-+
-+ movl 120(%ebp), %eax
-+ xorl %ebx, %ebx
-+ movl 124(%ebp), %edx
-+ xorl %esi, %eax
-+ xorl %esi, %edx
-+ andl $0xfcfcfcfc, %eax
-+ andl $0xcfcfcfcf, %edx
-+ movb %al, %bl
-+ movb %ah, %cl
-+ rorl $4, %edx
-+ movl des_SPtrans(%ebx),%ebp
-+ movb %dl, %bl
-+ xorl %ebp, %edi
-+ movl 0x200+des_SPtrans(%ecx),%ebp
-+ xorl %ebp, %edi
-+ movb %dh, %cl
-+ shrl $16, %eax
-+ movl 0x100+des_SPtrans(%ebx),%ebp
-+ xorl %ebp, %edi
-+ movb %ah, %bl
-+ shrl $16, %edx
-+ movl 0x300+des_SPtrans(%ecx),%ebp
-+ xorl %ebp, %edi
-+ movl 24(%esp), %ebp
-+ movb %dh, %cl
-+ andl $0xff, %eax
-+ andl $0xff, %edx
-+ movl 0x600+des_SPtrans(%ebx),%ebx
-+ xorl %ebx, %edi
-+ movl 0x700+des_SPtrans(%ecx),%ebx
-+ xorl %ebx, %edi
-+ movl 0x400+des_SPtrans(%eax),%ebx
-+ xorl %ebx, %edi
-+ movl 0x500+des_SPtrans(%edx),%ebx
-+ xorl %ebx, %edi
-+
-+
-+ movl 112(%ebp), %eax
-+ xorl %ebx, %ebx
-+ movl 116(%ebp), %edx
-+ xorl %edi, %eax
-+ xorl %edi, %edx
-+ andl $0xfcfcfcfc, %eax
-+ andl $0xcfcfcfcf, %edx
-+ movb %al, %bl
-+ movb %ah, %cl
-+ rorl $4, %edx
-+ movl des_SPtrans(%ebx),%ebp
-+ movb %dl, %bl
-+ xorl %ebp, %esi
-+ movl 0x200+des_SPtrans(%ecx),%ebp
-+ xorl %ebp, %esi
-+ movb %dh, %cl
-+ shrl $16, %eax
-+ movl 0x100+des_SPtrans(%ebx),%ebp
-+ xorl %ebp, %esi
-+ movb %ah, %bl
-+ shrl $16, %edx
-+ movl 0x300+des_SPtrans(%ecx),%ebp
-+ xorl %ebp, %esi
-+ movl 24(%esp), %ebp
-+ movb %dh, %cl
-+ andl $0xff, %eax
-+ andl $0xff, %edx
-+ movl 0x600+des_SPtrans(%ebx),%ebx
-+ xorl %ebx, %esi
-+ movl 0x700+des_SPtrans(%ecx),%ebx
-+ xorl %ebx, %esi
-+ movl 0x400+des_SPtrans(%eax),%ebx
-+ xorl %ebx, %esi
-+ movl 0x500+des_SPtrans(%edx),%ebx
-+ xorl %ebx, %esi
-+
-+
-+ movl 104(%ebp), %eax
-+ xorl %ebx, %ebx
-+ movl 108(%ebp), %edx
-+ xorl %esi, %eax
-+ xorl %esi, %edx
-+ andl $0xfcfcfcfc, %eax
-+ andl $0xcfcfcfcf, %edx
-+ movb %al, %bl
-+ movb %ah, %cl
-+ rorl $4, %edx
-+ movl des_SPtrans(%ebx),%ebp
-+ movb %dl, %bl
-+ xorl %ebp, %edi
-+ movl 0x200+des_SPtrans(%ecx),%ebp
-+ xorl %ebp, %edi
-+ movb %dh, %cl
-+ shrl $16, %eax
-+ movl 0x100+des_SPtrans(%ebx),%ebp
-+ xorl %ebp, %edi
-+ movb %ah, %bl
-+ shrl $16, %edx
-+ movl 0x300+des_SPtrans(%ecx),%ebp
-+ xorl %ebp, %edi
-+ movl 24(%esp), %ebp
-+ movb %dh, %cl
-+ andl $0xff, %eax
-+ andl $0xff, %edx
-+ movl 0x600+des_SPtrans(%ebx),%ebx
-+ xorl %ebx, %edi
-+ movl 0x700+des_SPtrans(%ecx),%ebx
-+ xorl %ebx, %edi
-+ movl 0x400+des_SPtrans(%eax),%ebx
-+ xorl %ebx, %edi
-+ movl 0x500+des_SPtrans(%edx),%ebx
-+ xorl %ebx, %edi
-+
-+
-+ movl 96(%ebp), %eax
-+ xorl %ebx, %ebx
-+ movl 100(%ebp), %edx
-+ xorl %edi, %eax
-+ xorl %edi, %edx
-+ andl $0xfcfcfcfc, %eax
-+ andl $0xcfcfcfcf, %edx
-+ movb %al, %bl
-+ movb %ah, %cl
-+ rorl $4, %edx
-+ movl des_SPtrans(%ebx),%ebp
-+ movb %dl, %bl
-+ xorl %ebp, %esi
-+ movl 0x200+des_SPtrans(%ecx),%ebp
-+ xorl %ebp, %esi
-+ movb %dh, %cl
-+ shrl $16, %eax
-+ movl 0x100+des_SPtrans(%ebx),%ebp
-+ xorl %ebp, %esi
-+ movb %ah, %bl
-+ shrl $16, %edx
-+ movl 0x300+des_SPtrans(%ecx),%ebp
-+ xorl %ebp, %esi
-+ movl 24(%esp), %ebp
-+ movb %dh, %cl
-+ andl $0xff, %eax
-+ andl $0xff, %edx
-+ movl 0x600+des_SPtrans(%ebx),%ebx
-+ xorl %ebx, %esi
-+ movl 0x700+des_SPtrans(%ecx),%ebx
-+ xorl %ebx, %esi
-+ movl 0x400+des_SPtrans(%eax),%ebx
-+ xorl %ebx, %esi
-+ movl 0x500+des_SPtrans(%edx),%ebx
-+ xorl %ebx, %esi
-+
-+
-+ movl 88(%ebp), %eax
-+ xorl %ebx, %ebx
-+ movl 92(%ebp), %edx
-+ xorl %esi, %eax
-+ xorl %esi, %edx
-+ andl $0xfcfcfcfc, %eax
-+ andl $0xcfcfcfcf, %edx
-+ movb %al, %bl
-+ movb %ah, %cl
-+ rorl $4, %edx
-+ movl des_SPtrans(%ebx),%ebp
-+ movb %dl, %bl
-+ xorl %ebp, %edi
-+ movl 0x200+des_SPtrans(%ecx),%ebp
-+ xorl %ebp, %edi
-+ movb %dh, %cl
-+ shrl $16, %eax
-+ movl 0x100+des_SPtrans(%ebx),%ebp
-+ xorl %ebp, %edi
-+ movb %ah, %bl
-+ shrl $16, %edx
-+ movl 0x300+des_SPtrans(%ecx),%ebp
-+ xorl %ebp, %edi
-+ movl 24(%esp), %ebp
-+ movb %dh, %cl
-+ andl $0xff, %eax
-+ andl $0xff, %edx
-+ movl 0x600+des_SPtrans(%ebx),%ebx
-+ xorl %ebx, %edi
-+ movl 0x700+des_SPtrans(%ecx),%ebx
-+ xorl %ebx, %edi
-+ movl 0x400+des_SPtrans(%eax),%ebx
-+ xorl %ebx, %edi
-+ movl 0x500+des_SPtrans(%edx),%ebx
-+ xorl %ebx, %edi
-+
-+
-+ movl 80(%ebp), %eax
-+ xorl %ebx, %ebx
-+ movl 84(%ebp), %edx
-+ xorl %edi, %eax
-+ xorl %edi, %edx
-+ andl $0xfcfcfcfc, %eax
-+ andl $0xcfcfcfcf, %edx
-+ movb %al, %bl
-+ movb %ah, %cl
-+ rorl $4, %edx
-+ movl des_SPtrans(%ebx),%ebp
-+ movb %dl, %bl
-+ xorl %ebp, %esi
-+ movl 0x200+des_SPtrans(%ecx),%ebp
-+ xorl %ebp, %esi
-+ movb %dh, %cl
-+ shrl $16, %eax
-+ movl 0x100+des_SPtrans(%ebx),%ebp
-+ xorl %ebp, %esi
-+ movb %ah, %bl
-+ shrl $16, %edx
-+ movl 0x300+des_SPtrans(%ecx),%ebp
-+ xorl %ebp, %esi
-+ movl 24(%esp), %ebp
-+ movb %dh, %cl
-+ andl $0xff, %eax
-+ andl $0xff, %edx
-+ movl 0x600+des_SPtrans(%ebx),%ebx
-+ xorl %ebx, %esi
-+ movl 0x700+des_SPtrans(%ecx),%ebx
-+ xorl %ebx, %esi
-+ movl 0x400+des_SPtrans(%eax),%ebx
-+ xorl %ebx, %esi
-+ movl 0x500+des_SPtrans(%edx),%ebx
-+ xorl %ebx, %esi
-+
-+
-+ movl 72(%ebp), %eax
-+ xorl %ebx, %ebx
-+ movl 76(%ebp), %edx
-+ xorl %esi, %eax
-+ xorl %esi, %edx
-+ andl $0xfcfcfcfc, %eax
-+ andl $0xcfcfcfcf, %edx
-+ movb %al, %bl
-+ movb %ah, %cl
-+ rorl $4, %edx
-+ movl des_SPtrans(%ebx),%ebp
-+ movb %dl, %bl
-+ xorl %ebp, %edi
-+ movl 0x200+des_SPtrans(%ecx),%ebp
-+ xorl %ebp, %edi
-+ movb %dh, %cl
-+ shrl $16, %eax
-+ movl 0x100+des_SPtrans(%ebx),%ebp
-+ xorl %ebp, %edi
-+ movb %ah, %bl
-+ shrl $16, %edx
-+ movl 0x300+des_SPtrans(%ecx),%ebp
-+ xorl %ebp, %edi
-+ movl 24(%esp), %ebp
-+ movb %dh, %cl
-+ andl $0xff, %eax
-+ andl $0xff, %edx
-+ movl 0x600+des_SPtrans(%ebx),%ebx
-+ xorl %ebx, %edi
-+ movl 0x700+des_SPtrans(%ecx),%ebx
-+ xorl %ebx, %edi
-+ movl 0x400+des_SPtrans(%eax),%ebx
-+ xorl %ebx, %edi
-+ movl 0x500+des_SPtrans(%edx),%ebx
-+ xorl %ebx, %edi
-+
-+
-+ movl 64(%ebp), %eax
-+ xorl %ebx, %ebx
-+ movl 68(%ebp), %edx
-+ xorl %edi, %eax
-+ xorl %edi, %edx
-+ andl $0xfcfcfcfc, %eax
-+ andl $0xcfcfcfcf, %edx
-+ movb %al, %bl
-+ movb %ah, %cl
-+ rorl $4, %edx
-+ movl des_SPtrans(%ebx),%ebp
-+ movb %dl, %bl
-+ xorl %ebp, %esi
-+ movl 0x200+des_SPtrans(%ecx),%ebp
-+ xorl %ebp, %esi
-+ movb %dh, %cl
-+ shrl $16, %eax
-+ movl 0x100+des_SPtrans(%ebx),%ebp
-+ xorl %ebp, %esi
-+ movb %ah, %bl
-+ shrl $16, %edx
-+ movl 0x300+des_SPtrans(%ecx),%ebp
-+ xorl %ebp, %esi
-+ movl 24(%esp), %ebp
-+ movb %dh, %cl
-+ andl $0xff, %eax
-+ andl $0xff, %edx
-+ movl 0x600+des_SPtrans(%ebx),%ebx
-+ xorl %ebx, %esi
-+ movl 0x700+des_SPtrans(%ecx),%ebx
-+ xorl %ebx, %esi
-+ movl 0x400+des_SPtrans(%eax),%ebx
-+ xorl %ebx, %esi
-+ movl 0x500+des_SPtrans(%edx),%ebx
-+ xorl %ebx, %esi
-+
-+
-+ movl 56(%ebp), %eax
-+ xorl %ebx, %ebx
-+ movl 60(%ebp), %edx
-+ xorl %esi, %eax
-+ xorl %esi, %edx
-+ andl $0xfcfcfcfc, %eax
-+ andl $0xcfcfcfcf, %edx
-+ movb %al, %bl
-+ movb %ah, %cl
-+ rorl $4, %edx
-+ movl des_SPtrans(%ebx),%ebp
-+ movb %dl, %bl
-+ xorl %ebp, %edi
-+ movl 0x200+des_SPtrans(%ecx),%ebp
-+ xorl %ebp, %edi
-+ movb %dh, %cl
-+ shrl $16, %eax
-+ movl 0x100+des_SPtrans(%ebx),%ebp
-+ xorl %ebp, %edi
-+ movb %ah, %bl
-+ shrl $16, %edx
-+ movl 0x300+des_SPtrans(%ecx),%ebp
-+ xorl %ebp, %edi
-+ movl 24(%esp), %ebp
-+ movb %dh, %cl
-+ andl $0xff, %eax
-+ andl $0xff, %edx
-+ movl 0x600+des_SPtrans(%ebx),%ebx
-+ xorl %ebx, %edi
-+ movl 0x700+des_SPtrans(%ecx),%ebx
-+ xorl %ebx, %edi
-+ movl 0x400+des_SPtrans(%eax),%ebx
-+ xorl %ebx, %edi
-+ movl 0x500+des_SPtrans(%edx),%ebx
-+ xorl %ebx, %edi
-+
-+
-+ movl 48(%ebp), %eax
-+ xorl %ebx, %ebx
-+ movl 52(%ebp), %edx
-+ xorl %edi, %eax
-+ xorl %edi, %edx
-+ andl $0xfcfcfcfc, %eax
-+ andl $0xcfcfcfcf, %edx
-+ movb %al, %bl
-+ movb %ah, %cl
-+ rorl $4, %edx
-+ movl des_SPtrans(%ebx),%ebp
-+ movb %dl, %bl
-+ xorl %ebp, %esi
-+ movl 0x200+des_SPtrans(%ecx),%ebp
-+ xorl %ebp, %esi
-+ movb %dh, %cl
-+ shrl $16, %eax
-+ movl 0x100+des_SPtrans(%ebx),%ebp
-+ xorl %ebp, %esi
-+ movb %ah, %bl
-+ shrl $16, %edx
-+ movl 0x300+des_SPtrans(%ecx),%ebp
-+ xorl %ebp, %esi
-+ movl 24(%esp), %ebp
-+ movb %dh, %cl
-+ andl $0xff, %eax
-+ andl $0xff, %edx
-+ movl 0x600+des_SPtrans(%ebx),%ebx
-+ xorl %ebx, %esi
-+ movl 0x700+des_SPtrans(%ecx),%ebx
-+ xorl %ebx, %esi
-+ movl 0x400+des_SPtrans(%eax),%ebx
-+ xorl %ebx, %esi
-+ movl 0x500+des_SPtrans(%edx),%ebx
-+ xorl %ebx, %esi
-+
-+
-+ movl 40(%ebp), %eax
-+ xorl %ebx, %ebx
-+ movl 44(%ebp), %edx
-+ xorl %esi, %eax
-+ xorl %esi, %edx
-+ andl $0xfcfcfcfc, %eax
-+ andl $0xcfcfcfcf, %edx
-+ movb %al, %bl
-+ movb %ah, %cl
-+ rorl $4, %edx
-+ movl des_SPtrans(%ebx),%ebp
-+ movb %dl, %bl
-+ xorl %ebp, %edi
-+ movl 0x200+des_SPtrans(%ecx),%ebp
-+ xorl %ebp, %edi
-+ movb %dh, %cl
-+ shrl $16, %eax
-+ movl 0x100+des_SPtrans(%ebx),%ebp
-+ xorl %ebp, %edi
-+ movb %ah, %bl
-+ shrl $16, %edx
-+ movl 0x300+des_SPtrans(%ecx),%ebp
-+ xorl %ebp, %edi
-+ movl 24(%esp), %ebp
-+ movb %dh, %cl
-+ andl $0xff, %eax
-+ andl $0xff, %edx
-+ movl 0x600+des_SPtrans(%ebx),%ebx
-+ xorl %ebx, %edi
-+ movl 0x700+des_SPtrans(%ecx),%ebx
-+ xorl %ebx, %edi
-+ movl 0x400+des_SPtrans(%eax),%ebx
-+ xorl %ebx, %edi
-+ movl 0x500+des_SPtrans(%edx),%ebx
-+ xorl %ebx, %edi
-+
-+
-+ movl 32(%ebp), %eax
-+ xorl %ebx, %ebx
-+ movl 36(%ebp), %edx
-+ xorl %edi, %eax
-+ xorl %edi, %edx
-+ andl $0xfcfcfcfc, %eax
-+ andl $0xcfcfcfcf, %edx
-+ movb %al, %bl
-+ movb %ah, %cl
-+ rorl $4, %edx
-+ movl des_SPtrans(%ebx),%ebp
-+ movb %dl, %bl
-+ xorl %ebp, %esi
-+ movl 0x200+des_SPtrans(%ecx),%ebp
-+ xorl %ebp, %esi
-+ movb %dh, %cl
-+ shrl $16, %eax
-+ movl 0x100+des_SPtrans(%ebx),%ebp
-+ xorl %ebp, %esi
-+ movb %ah, %bl
-+ shrl $16, %edx
-+ movl 0x300+des_SPtrans(%ecx),%ebp
-+ xorl %ebp, %esi
-+ movl 24(%esp), %ebp
-+ movb %dh, %cl
-+ andl $0xff, %eax
-+ andl $0xff, %edx
-+ movl 0x600+des_SPtrans(%ebx),%ebx
-+ xorl %ebx, %esi
-+ movl 0x700+des_SPtrans(%ecx),%ebx
-+ xorl %ebx, %esi
-+ movl 0x400+des_SPtrans(%eax),%ebx
-+ xorl %ebx, %esi
-+ movl 0x500+des_SPtrans(%edx),%ebx
-+ xorl %ebx, %esi
-+
-+
-+ movl 24(%ebp), %eax
-+ xorl %ebx, %ebx
-+ movl 28(%ebp), %edx
-+ xorl %esi, %eax
-+ xorl %esi, %edx
-+ andl $0xfcfcfcfc, %eax
-+ andl $0xcfcfcfcf, %edx
-+ movb %al, %bl
-+ movb %ah, %cl
-+ rorl $4, %edx
-+ movl des_SPtrans(%ebx),%ebp
-+ movb %dl, %bl
-+ xorl %ebp, %edi
-+ movl 0x200+des_SPtrans(%ecx),%ebp
-+ xorl %ebp, %edi
-+ movb %dh, %cl
-+ shrl $16, %eax
-+ movl 0x100+des_SPtrans(%ebx),%ebp
-+ xorl %ebp, %edi
-+ movb %ah, %bl
-+ shrl $16, %edx
-+ movl 0x300+des_SPtrans(%ecx),%ebp
-+ xorl %ebp, %edi
-+ movl 24(%esp), %ebp
-+ movb %dh, %cl
-+ andl $0xff, %eax
-+ andl $0xff, %edx
-+ movl 0x600+des_SPtrans(%ebx),%ebx
-+ xorl %ebx, %edi
-+ movl 0x700+des_SPtrans(%ecx),%ebx
-+ xorl %ebx, %edi
-+ movl 0x400+des_SPtrans(%eax),%ebx
-+ xorl %ebx, %edi
-+ movl 0x500+des_SPtrans(%edx),%ebx
-+ xorl %ebx, %edi
-+
-+
-+ movl 16(%ebp), %eax
-+ xorl %ebx, %ebx
-+ movl 20(%ebp), %edx
-+ xorl %edi, %eax
-+ xorl %edi, %edx
-+ andl $0xfcfcfcfc, %eax
-+ andl $0xcfcfcfcf, %edx
-+ movb %al, %bl
-+ movb %ah, %cl
-+ rorl $4, %edx
-+ movl des_SPtrans(%ebx),%ebp
-+ movb %dl, %bl
-+ xorl %ebp, %esi
-+ movl 0x200+des_SPtrans(%ecx),%ebp
-+ xorl %ebp, %esi
-+ movb %dh, %cl
-+ shrl $16, %eax
-+ movl 0x100+des_SPtrans(%ebx),%ebp
-+ xorl %ebp, %esi
-+ movb %ah, %bl
-+ shrl $16, %edx
-+ movl 0x300+des_SPtrans(%ecx),%ebp
-+ xorl %ebp, %esi
-+ movl 24(%esp), %ebp
-+ movb %dh, %cl
-+ andl $0xff, %eax
-+ andl $0xff, %edx
-+ movl 0x600+des_SPtrans(%ebx),%ebx
-+ xorl %ebx, %esi
-+ movl 0x700+des_SPtrans(%ecx),%ebx
-+ xorl %ebx, %esi
-+ movl 0x400+des_SPtrans(%eax),%ebx
-+ xorl %ebx, %esi
-+ movl 0x500+des_SPtrans(%edx),%ebx
-+ xorl %ebx, %esi
-+
-+
-+ movl 8(%ebp), %eax
-+ xorl %ebx, %ebx
-+ movl 12(%ebp), %edx
-+ xorl %esi, %eax
-+ xorl %esi, %edx
-+ andl $0xfcfcfcfc, %eax
-+ andl $0xcfcfcfcf, %edx
-+ movb %al, %bl
-+ movb %ah, %cl
-+ rorl $4, %edx
-+ movl des_SPtrans(%ebx),%ebp
-+ movb %dl, %bl
-+ xorl %ebp, %edi
-+ movl 0x200+des_SPtrans(%ecx),%ebp
-+ xorl %ebp, %edi
-+ movb %dh, %cl
-+ shrl $16, %eax
-+ movl 0x100+des_SPtrans(%ebx),%ebp
-+ xorl %ebp, %edi
-+ movb %ah, %bl
-+ shrl $16, %edx
-+ movl 0x300+des_SPtrans(%ecx),%ebp
-+ xorl %ebp, %edi
-+ movl 24(%esp), %ebp
-+ movb %dh, %cl
-+ andl $0xff, %eax
-+ andl $0xff, %edx
-+ movl 0x600+des_SPtrans(%ebx),%ebx
-+ xorl %ebx, %edi
-+ movl 0x700+des_SPtrans(%ecx),%ebx
-+ xorl %ebx, %edi
-+ movl 0x400+des_SPtrans(%eax),%ebx
-+ xorl %ebx, %edi
-+ movl 0x500+des_SPtrans(%edx),%ebx
-+ xorl %ebx, %edi
-+
-+
-+ movl (%ebp), %eax
-+ xorl %ebx, %ebx
-+ movl 4(%ebp), %edx
-+ xorl %edi, %eax
-+ xorl %edi, %edx
-+ andl $0xfcfcfcfc, %eax
-+ andl $0xcfcfcfcf, %edx
-+ movb %al, %bl
-+ movb %ah, %cl
-+ rorl $4, %edx
-+ movl des_SPtrans(%ebx),%ebp
-+ movb %dl, %bl
-+ xorl %ebp, %esi
-+ movl 0x200+des_SPtrans(%ecx),%ebp
-+ xorl %ebp, %esi
-+ movb %dh, %cl
-+ shrl $16, %eax
-+ movl 0x100+des_SPtrans(%ebx),%ebp
-+ xorl %ebp, %esi
-+ movb %ah, %bl
-+ shrl $16, %edx
-+ movl 0x300+des_SPtrans(%ecx),%ebp
-+ xorl %ebp, %esi
-+ movl 24(%esp), %ebp
-+ movb %dh, %cl
-+ andl $0xff, %eax
-+ andl $0xff, %edx
-+ movl 0x600+des_SPtrans(%ebx),%ebx
-+ xorl %ebx, %esi
-+ movl 0x700+des_SPtrans(%ecx),%ebx
-+ xorl %ebx, %esi
-+ movl 0x400+des_SPtrans(%eax),%ebx
-+ xorl %ebx, %esi
-+ movl 0x500+des_SPtrans(%edx),%ebx
-+ xorl %ebx, %esi
-+.L001end:
-+
-+
-+ movl 20(%esp), %edx
-+.byte 209
-+.byte 206
-+ movl %edi, %eax
-+ xorl %esi, %edi
-+ andl $0xaaaaaaaa, %edi
-+ xorl %edi, %eax
-+ xorl %edi, %esi
-+
-+ roll $23, %eax
-+ movl %eax, %edi
-+ xorl %esi, %eax
-+ andl $0x03fc03fc, %eax
-+ xorl %eax, %edi
-+ xorl %eax, %esi
-+
-+ roll $10, %edi
-+ movl %edi, %eax
-+ xorl %esi, %edi
-+ andl $0x33333333, %edi
-+ xorl %edi, %eax
-+ xorl %edi, %esi
-+
-+ roll $18, %esi
-+ movl %esi, %edi
-+ xorl %eax, %esi
-+ andl $0xfff0000f, %esi
-+ xorl %esi, %edi
-+ xorl %esi, %eax
-+
-+ roll $12, %edi
-+ movl %edi, %esi
-+ xorl %eax, %edi
-+ andl $0xf0f0f0f0, %edi
-+ xorl %edi, %esi
-+ xorl %edi, %eax
-+
-+ rorl $4, %eax
-+ movl %eax, (%edx)
-+ movl %esi, 4(%edx)
-+ popl %ebp
-+ popl %ebx
-+ popl %edi
-+ popl %esi
-+ ret
-+.des_encrypt_end:
-+ .size des_encrypt , .des_encrypt_end-des_encrypt
-+.ident "desasm.pl"
-+.text
-+ .align 16
-+.globl des_encrypt2
-+ .type des_encrypt2 , @function
-+des_encrypt2:
-+ pushl %esi
-+ pushl %edi
-+
-+
-+ movl 12(%esp), %eax
-+ xorl %ecx, %ecx
-+ pushl %ebx
-+ pushl %ebp
-+ movl (%eax), %esi
-+ movl 28(%esp), %ebx
-+ roll $3, %esi
-+ movl 4(%eax), %edi
-+ roll $3, %edi
-+ movl 24(%esp), %ebp
-+ cmpl $0, %ebx
-+ je .L002start_decrypt
-+
-+
-+ movl (%ebp), %eax
-+ xorl %ebx, %ebx
-+ movl 4(%ebp), %edx
-+ xorl %esi, %eax
-+ xorl %esi, %edx
-+ andl $0xfcfcfcfc, %eax
-+ andl $0xcfcfcfcf, %edx
-+ movb %al, %bl
-+ movb %ah, %cl
-+ rorl $4, %edx
-+ movl des_SPtrans(%ebx),%ebp
-+ movb %dl, %bl
-+ xorl %ebp, %edi
-+ movl 0x200+des_SPtrans(%ecx),%ebp
-+ xorl %ebp, %edi
-+ movb %dh, %cl
-+ shrl $16, %eax
-+ movl 0x100+des_SPtrans(%ebx),%ebp
-+ xorl %ebp, %edi
-+ movb %ah, %bl
-+ shrl $16, %edx
-+ movl 0x300+des_SPtrans(%ecx),%ebp
-+ xorl %ebp, %edi
-+ movl 24(%esp), %ebp
-+ movb %dh, %cl
-+ andl $0xff, %eax
-+ andl $0xff, %edx
-+ movl 0x600+des_SPtrans(%ebx),%ebx
-+ xorl %ebx, %edi
-+ movl 0x700+des_SPtrans(%ecx),%ebx
-+ xorl %ebx, %edi
-+ movl 0x400+des_SPtrans(%eax),%ebx
-+ xorl %ebx, %edi
-+ movl 0x500+des_SPtrans(%edx),%ebx
-+ xorl %ebx, %edi
-+
-+
-+ movl 8(%ebp), %eax
-+ xorl %ebx, %ebx
-+ movl 12(%ebp), %edx
-+ xorl %edi, %eax
-+ xorl %edi, %edx
-+ andl $0xfcfcfcfc, %eax
-+ andl $0xcfcfcfcf, %edx
-+ movb %al, %bl
-+ movb %ah, %cl
-+ rorl $4, %edx
-+ movl des_SPtrans(%ebx),%ebp
-+ movb %dl, %bl
-+ xorl %ebp, %esi
-+ movl 0x200+des_SPtrans(%ecx),%ebp
-+ xorl %ebp, %esi
-+ movb %dh, %cl
-+ shrl $16, %eax
-+ movl 0x100+des_SPtrans(%ebx),%ebp
-+ xorl %ebp, %esi
-+ movb %ah, %bl
-+ shrl $16, %edx
-+ movl 0x300+des_SPtrans(%ecx),%ebp
-+ xorl %ebp, %esi
-+ movl 24(%esp), %ebp
-+ movb %dh, %cl
-+ andl $0xff, %eax
-+ andl $0xff, %edx
-+ movl 0x600+des_SPtrans(%ebx),%ebx
-+ xorl %ebx, %esi
-+ movl 0x700+des_SPtrans(%ecx),%ebx
-+ xorl %ebx, %esi
-+ movl 0x400+des_SPtrans(%eax),%ebx
-+ xorl %ebx, %esi
-+ movl 0x500+des_SPtrans(%edx),%ebx
-+ xorl %ebx, %esi
-+
-+
-+ movl 16(%ebp), %eax
-+ xorl %ebx, %ebx
-+ movl 20(%ebp), %edx
-+ xorl %esi, %eax
-+ xorl %esi, %edx
-+ andl $0xfcfcfcfc, %eax
-+ andl $0xcfcfcfcf, %edx
-+ movb %al, %bl
-+ movb %ah, %cl
-+ rorl $4, %edx
-+ movl des_SPtrans(%ebx),%ebp
-+ movb %dl, %bl
-+ xorl %ebp, %edi
-+ movl 0x200+des_SPtrans(%ecx),%ebp
-+ xorl %ebp, %edi
-+ movb %dh, %cl
-+ shrl $16, %eax
-+ movl 0x100+des_SPtrans(%ebx),%ebp
-+ xorl %ebp, %edi
-+ movb %ah, %bl
-+ shrl $16, %edx
-+ movl 0x300+des_SPtrans(%ecx),%ebp
-+ xorl %ebp, %edi
-+ movl 24(%esp), %ebp
-+ movb %dh, %cl
-+ andl $0xff, %eax
-+ andl $0xff, %edx
-+ movl 0x600+des_SPtrans(%ebx),%ebx
-+ xorl %ebx, %edi
-+ movl 0x700+des_SPtrans(%ecx),%ebx
-+ xorl %ebx, %edi
-+ movl 0x400+des_SPtrans(%eax),%ebx
-+ xorl %ebx, %edi
-+ movl 0x500+des_SPtrans(%edx),%ebx
-+ xorl %ebx, %edi
-+
-+
-+ movl 24(%ebp), %eax
-+ xorl %ebx, %ebx
-+ movl 28(%ebp), %edx
-+ xorl %edi, %eax
-+ xorl %edi, %edx
-+ andl $0xfcfcfcfc, %eax
-+ andl $0xcfcfcfcf, %edx
-+ movb %al, %bl
-+ movb %ah, %cl
-+ rorl $4, %edx
-+ movl des_SPtrans(%ebx),%ebp
-+ movb %dl, %bl
-+ xorl %ebp, %esi
-+ movl 0x200+des_SPtrans(%ecx),%ebp
-+ xorl %ebp, %esi
-+ movb %dh, %cl
-+ shrl $16, %eax
-+ movl 0x100+des_SPtrans(%ebx),%ebp
-+ xorl %ebp, %esi
-+ movb %ah, %bl
-+ shrl $16, %edx
-+ movl 0x300+des_SPtrans(%ecx),%ebp
-+ xorl %ebp, %esi
-+ movl 24(%esp), %ebp
-+ movb %dh, %cl
-+ andl $0xff, %eax
-+ andl $0xff, %edx
-+ movl 0x600+des_SPtrans(%ebx),%ebx
-+ xorl %ebx, %esi
-+ movl 0x700+des_SPtrans(%ecx),%ebx
-+ xorl %ebx, %esi
-+ movl 0x400+des_SPtrans(%eax),%ebx
-+ xorl %ebx, %esi
-+ movl 0x500+des_SPtrans(%edx),%ebx
-+ xorl %ebx, %esi
-+
-+
-+ movl 32(%ebp), %eax
-+ xorl %ebx, %ebx
-+ movl 36(%ebp), %edx
-+ xorl %esi, %eax
-+ xorl %esi, %edx
-+ andl $0xfcfcfcfc, %eax
-+ andl $0xcfcfcfcf, %edx
-+ movb %al, %bl
-+ movb %ah, %cl
-+ rorl $4, %edx
-+ movl des_SPtrans(%ebx),%ebp
-+ movb %dl, %bl
-+ xorl %ebp, %edi
-+ movl 0x200+des_SPtrans(%ecx),%ebp
-+ xorl %ebp, %edi
-+ movb %dh, %cl
-+ shrl $16, %eax
-+ movl 0x100+des_SPtrans(%ebx),%ebp
-+ xorl %ebp, %edi
-+ movb %ah, %bl
-+ shrl $16, %edx
-+ movl 0x300+des_SPtrans(%ecx),%ebp
-+ xorl %ebp, %edi
-+ movl 24(%esp), %ebp
-+ movb %dh, %cl
-+ andl $0xff, %eax
-+ andl $0xff, %edx
-+ movl 0x600+des_SPtrans(%ebx),%ebx
-+ xorl %ebx, %edi
-+ movl 0x700+des_SPtrans(%ecx),%ebx
-+ xorl %ebx, %edi
-+ movl 0x400+des_SPtrans(%eax),%ebx
-+ xorl %ebx, %edi
-+ movl 0x500+des_SPtrans(%edx),%ebx
-+ xorl %ebx, %edi
-+
-+
-+ movl 40(%ebp), %eax
-+ xorl %ebx, %ebx
-+ movl 44(%ebp), %edx
-+ xorl %edi, %eax
-+ xorl %edi, %edx
-+ andl $0xfcfcfcfc, %eax
-+ andl $0xcfcfcfcf, %edx
-+ movb %al, %bl
-+ movb %ah, %cl
-+ rorl $4, %edx
-+ movl des_SPtrans(%ebx),%ebp
-+ movb %dl, %bl
-+ xorl %ebp, %esi
-+ movl 0x200+des_SPtrans(%ecx),%ebp
-+ xorl %ebp, %esi
-+ movb %dh, %cl
-+ shrl $16, %eax
-+ movl 0x100+des_SPtrans(%ebx),%ebp
-+ xorl %ebp, %esi
-+ movb %ah, %bl
-+ shrl $16, %edx
-+ movl 0x300+des_SPtrans(%ecx),%ebp
-+ xorl %ebp, %esi
-+ movl 24(%esp), %ebp
-+ movb %dh, %cl
-+ andl $0xff, %eax
-+ andl $0xff, %edx
-+ movl 0x600+des_SPtrans(%ebx),%ebx
-+ xorl %ebx, %esi
-+ movl 0x700+des_SPtrans(%ecx),%ebx
-+ xorl %ebx, %esi
-+ movl 0x400+des_SPtrans(%eax),%ebx
-+ xorl %ebx, %esi
-+ movl 0x500+des_SPtrans(%edx),%ebx
-+ xorl %ebx, %esi
-+
-+
-+ movl 48(%ebp), %eax
-+ xorl %ebx, %ebx
-+ movl 52(%ebp), %edx
-+ xorl %esi, %eax
-+ xorl %esi, %edx
-+ andl $0xfcfcfcfc, %eax
-+ andl $0xcfcfcfcf, %edx
-+ movb %al, %bl
-+ movb %ah, %cl
-+ rorl $4, %edx
-+ movl des_SPtrans(%ebx),%ebp
-+ movb %dl, %bl
-+ xorl %ebp, %edi
-+ movl 0x200+des_SPtrans(%ecx),%ebp
-+ xorl %ebp, %edi
-+ movb %dh, %cl
-+ shrl $16, %eax
-+ movl 0x100+des_SPtrans(%ebx),%ebp
-+ xorl %ebp, %edi
-+ movb %ah, %bl
-+ shrl $16, %edx
-+ movl 0x300+des_SPtrans(%ecx),%ebp
-+ xorl %ebp, %edi
-+ movl 24(%esp), %ebp
-+ movb %dh, %cl
-+ andl $0xff, %eax
-+ andl $0xff, %edx
-+ movl 0x600+des_SPtrans(%ebx),%ebx
-+ xorl %ebx, %edi
-+ movl 0x700+des_SPtrans(%ecx),%ebx
-+ xorl %ebx, %edi
-+ movl 0x400+des_SPtrans(%eax),%ebx
-+ xorl %ebx, %edi
-+ movl 0x500+des_SPtrans(%edx),%ebx
-+ xorl %ebx, %edi
-+
-+
-+ movl 56(%ebp), %eax
-+ xorl %ebx, %ebx
-+ movl 60(%ebp), %edx
-+ xorl %edi, %eax
-+ xorl %edi, %edx
-+ andl $0xfcfcfcfc, %eax
-+ andl $0xcfcfcfcf, %edx
-+ movb %al, %bl
-+ movb %ah, %cl
-+ rorl $4, %edx
-+ movl des_SPtrans(%ebx),%ebp
-+ movb %dl, %bl
-+ xorl %ebp, %esi
-+ movl 0x200+des_SPtrans(%ecx),%ebp
-+ xorl %ebp, %esi
-+ movb %dh, %cl
-+ shrl $16, %eax
-+ movl 0x100+des_SPtrans(%ebx),%ebp
-+ xorl %ebp, %esi
-+ movb %ah, %bl
-+ shrl $16, %edx
-+ movl 0x300+des_SPtrans(%ecx),%ebp
-+ xorl %ebp, %esi
-+ movl 24(%esp), %ebp
-+ movb %dh, %cl
-+ andl $0xff, %eax
-+ andl $0xff, %edx
-+ movl 0x600+des_SPtrans(%ebx),%ebx
-+ xorl %ebx, %esi
-+ movl 0x700+des_SPtrans(%ecx),%ebx
-+ xorl %ebx, %esi
-+ movl 0x400+des_SPtrans(%eax),%ebx
-+ xorl %ebx, %esi
-+ movl 0x500+des_SPtrans(%edx),%ebx
-+ xorl %ebx, %esi
-+
-+
-+ movl 64(%ebp), %eax
-+ xorl %ebx, %ebx
-+ movl 68(%ebp), %edx
-+ xorl %esi, %eax
-+ xorl %esi, %edx
-+ andl $0xfcfcfcfc, %eax
-+ andl $0xcfcfcfcf, %edx
-+ movb %al, %bl
-+ movb %ah, %cl
-+ rorl $4, %edx
-+ movl des_SPtrans(%ebx),%ebp
-+ movb %dl, %bl
-+ xorl %ebp, %edi
-+ movl 0x200+des_SPtrans(%ecx),%ebp
-+ xorl %ebp, %edi
-+ movb %dh, %cl
-+ shrl $16, %eax
-+ movl 0x100+des_SPtrans(%ebx),%ebp
-+ xorl %ebp, %edi
-+ movb %ah, %bl
-+ shrl $16, %edx
-+ movl 0x300+des_SPtrans(%ecx),%ebp
-+ xorl %ebp, %edi
-+ movl 24(%esp), %ebp
-+ movb %dh, %cl
-+ andl $0xff, %eax
-+ andl $0xff, %edx
-+ movl 0x600+des_SPtrans(%ebx),%ebx
-+ xorl %ebx, %edi
-+ movl 0x700+des_SPtrans(%ecx),%ebx
-+ xorl %ebx, %edi
-+ movl 0x400+des_SPtrans(%eax),%ebx
-+ xorl %ebx, %edi
-+ movl 0x500+des_SPtrans(%edx),%ebx
-+ xorl %ebx, %edi
-+
-+
-+ movl 72(%ebp), %eax
-+ xorl %ebx, %ebx
-+ movl 76(%ebp), %edx
-+ xorl %edi, %eax
-+ xorl %edi, %edx
-+ andl $0xfcfcfcfc, %eax
-+ andl $0xcfcfcfcf, %edx
-+ movb %al, %bl
-+ movb %ah, %cl
-+ rorl $4, %edx
-+ movl des_SPtrans(%ebx),%ebp
-+ movb %dl, %bl
-+ xorl %ebp, %esi
-+ movl 0x200+des_SPtrans(%ecx),%ebp
-+ xorl %ebp, %esi
-+ movb %dh, %cl
-+ shrl $16, %eax
-+ movl 0x100+des_SPtrans(%ebx),%ebp
-+ xorl %ebp, %esi
-+ movb %ah, %bl
-+ shrl $16, %edx
-+ movl 0x300+des_SPtrans(%ecx),%ebp
-+ xorl %ebp, %esi
-+ movl 24(%esp), %ebp
-+ movb %dh, %cl
-+ andl $0xff, %eax
-+ andl $0xff, %edx
-+ movl 0x600+des_SPtrans(%ebx),%ebx
-+ xorl %ebx, %esi
-+ movl 0x700+des_SPtrans(%ecx),%ebx
-+ xorl %ebx, %esi
-+ movl 0x400+des_SPtrans(%eax),%ebx
-+ xorl %ebx, %esi
-+ movl 0x500+des_SPtrans(%edx),%ebx
-+ xorl %ebx, %esi
-+
-+
-+ movl 80(%ebp), %eax
-+ xorl %ebx, %ebx
-+ movl 84(%ebp), %edx
-+ xorl %esi, %eax
-+ xorl %esi, %edx
-+ andl $0xfcfcfcfc, %eax
-+ andl $0xcfcfcfcf, %edx
-+ movb %al, %bl
-+ movb %ah, %cl
-+ rorl $4, %edx
-+ movl des_SPtrans(%ebx),%ebp
-+ movb %dl, %bl
-+ xorl %ebp, %edi
-+ movl 0x200+des_SPtrans(%ecx),%ebp
-+ xorl %ebp, %edi
-+ movb %dh, %cl
-+ shrl $16, %eax
-+ movl 0x100+des_SPtrans(%ebx),%ebp
-+ xorl %ebp, %edi
-+ movb %ah, %bl
-+ shrl $16, %edx
-+ movl 0x300+des_SPtrans(%ecx),%ebp
-+ xorl %ebp, %edi
-+ movl 24(%esp), %ebp
-+ movb %dh, %cl
-+ andl $0xff, %eax
-+ andl $0xff, %edx
-+ movl 0x600+des_SPtrans(%ebx),%ebx
-+ xorl %ebx, %edi
-+ movl 0x700+des_SPtrans(%ecx),%ebx
-+ xorl %ebx, %edi
-+ movl 0x400+des_SPtrans(%eax),%ebx
-+ xorl %ebx, %edi
-+ movl 0x500+des_SPtrans(%edx),%ebx
-+ xorl %ebx, %edi
-+
-+
-+ movl 88(%ebp), %eax
-+ xorl %ebx, %ebx
-+ movl 92(%ebp), %edx
-+ xorl %edi, %eax
-+ xorl %edi, %edx
-+ andl $0xfcfcfcfc, %eax
-+ andl $0xcfcfcfcf, %edx
-+ movb %al, %bl
-+ movb %ah, %cl
-+ rorl $4, %edx
-+ movl des_SPtrans(%ebx),%ebp
-+ movb %dl, %bl
-+ xorl %ebp, %esi
-+ movl 0x200+des_SPtrans(%ecx),%ebp
-+ xorl %ebp, %esi
-+ movb %dh, %cl
-+ shrl $16, %eax
-+ movl 0x100+des_SPtrans(%ebx),%ebp
-+ xorl %ebp, %esi
-+ movb %ah, %bl
-+ shrl $16, %edx
-+ movl 0x300+des_SPtrans(%ecx),%ebp
-+ xorl %ebp, %esi
-+ movl 24(%esp), %ebp
-+ movb %dh, %cl
-+ andl $0xff, %eax
-+ andl $0xff, %edx
-+ movl 0x600+des_SPtrans(%ebx),%ebx
-+ xorl %ebx, %esi
-+ movl 0x700+des_SPtrans(%ecx),%ebx
-+ xorl %ebx, %esi
-+ movl 0x400+des_SPtrans(%eax),%ebx
-+ xorl %ebx, %esi
-+ movl 0x500+des_SPtrans(%edx),%ebx
-+ xorl %ebx, %esi
-+
-+
-+ movl 96(%ebp), %eax
-+ xorl %ebx, %ebx
-+ movl 100(%ebp), %edx
-+ xorl %esi, %eax
-+ xorl %esi, %edx
-+ andl $0xfcfcfcfc, %eax
-+ andl $0xcfcfcfcf, %edx
-+ movb %al, %bl
-+ movb %ah, %cl
-+ rorl $4, %edx
-+ movl des_SPtrans(%ebx),%ebp
-+ movb %dl, %bl
-+ xorl %ebp, %edi
-+ movl 0x200+des_SPtrans(%ecx),%ebp
-+ xorl %ebp, %edi
-+ movb %dh, %cl
-+ shrl $16, %eax
-+ movl 0x100+des_SPtrans(%ebx),%ebp
-+ xorl %ebp, %edi
-+ movb %ah, %bl
-+ shrl $16, %edx
-+ movl 0x300+des_SPtrans(%ecx),%ebp
-+ xorl %ebp, %edi
-+ movl 24(%esp), %ebp
-+ movb %dh, %cl
-+ andl $0xff, %eax
-+ andl $0xff, %edx
-+ movl 0x600+des_SPtrans(%ebx),%ebx
-+ xorl %ebx, %edi
-+ movl 0x700+des_SPtrans(%ecx),%ebx
-+ xorl %ebx, %edi
-+ movl 0x400+des_SPtrans(%eax),%ebx
-+ xorl %ebx, %edi
-+ movl 0x500+des_SPtrans(%edx),%ebx
-+ xorl %ebx, %edi
-+
-+
-+ movl 104(%ebp), %eax
-+ xorl %ebx, %ebx
-+ movl 108(%ebp), %edx
-+ xorl %edi, %eax
-+ xorl %edi, %edx
-+ andl $0xfcfcfcfc, %eax
-+ andl $0xcfcfcfcf, %edx
-+ movb %al, %bl
-+ movb %ah, %cl
-+ rorl $4, %edx
-+ movl des_SPtrans(%ebx),%ebp
-+ movb %dl, %bl
-+ xorl %ebp, %esi
-+ movl 0x200+des_SPtrans(%ecx),%ebp
-+ xorl %ebp, %esi
-+ movb %dh, %cl
-+ shrl $16, %eax
-+ movl 0x100+des_SPtrans(%ebx),%ebp
-+ xorl %ebp, %esi
-+ movb %ah, %bl
-+ shrl $16, %edx
-+ movl 0x300+des_SPtrans(%ecx),%ebp
-+ xorl %ebp, %esi
-+ movl 24(%esp), %ebp
-+ movb %dh, %cl
-+ andl $0xff, %eax
-+ andl $0xff, %edx
-+ movl 0x600+des_SPtrans(%ebx),%ebx
-+ xorl %ebx, %esi
-+ movl 0x700+des_SPtrans(%ecx),%ebx
-+ xorl %ebx, %esi
-+ movl 0x400+des_SPtrans(%eax),%ebx
-+ xorl %ebx, %esi
-+ movl 0x500+des_SPtrans(%edx),%ebx
-+ xorl %ebx, %esi
-+
-+
-+ movl 112(%ebp), %eax
-+ xorl %ebx, %ebx
-+ movl 116(%ebp), %edx
-+ xorl %esi, %eax
-+ xorl %esi, %edx
-+ andl $0xfcfcfcfc, %eax
-+ andl $0xcfcfcfcf, %edx
-+ movb %al, %bl
-+ movb %ah, %cl
-+ rorl $4, %edx
-+ movl des_SPtrans(%ebx),%ebp
-+ movb %dl, %bl
-+ xorl %ebp, %edi
-+ movl 0x200+des_SPtrans(%ecx),%ebp
-+ xorl %ebp, %edi
-+ movb %dh, %cl
-+ shrl $16, %eax
-+ movl 0x100+des_SPtrans(%ebx),%ebp
-+ xorl %ebp, %edi
-+ movb %ah, %bl
-+ shrl $16, %edx
-+ movl 0x300+des_SPtrans(%ecx),%ebp
-+ xorl %ebp, %edi
-+ movl 24(%esp), %ebp
-+ movb %dh, %cl
-+ andl $0xff, %eax
-+ andl $0xff, %edx
-+ movl 0x600+des_SPtrans(%ebx),%ebx
-+ xorl %ebx, %edi
-+ movl 0x700+des_SPtrans(%ecx),%ebx
-+ xorl %ebx, %edi
-+ movl 0x400+des_SPtrans(%eax),%ebx
-+ xorl %ebx, %edi
-+ movl 0x500+des_SPtrans(%edx),%ebx
-+ xorl %ebx, %edi
-+
-+
-+ movl 120(%ebp), %eax
-+ xorl %ebx, %ebx
-+ movl 124(%ebp), %edx
-+ xorl %edi, %eax
-+ xorl %edi, %edx
-+ andl $0xfcfcfcfc, %eax
-+ andl $0xcfcfcfcf, %edx
-+ movb %al, %bl
-+ movb %ah, %cl
-+ rorl $4, %edx
-+ movl des_SPtrans(%ebx),%ebp
-+ movb %dl, %bl
-+ xorl %ebp, %esi
-+ movl 0x200+des_SPtrans(%ecx),%ebp
-+ xorl %ebp, %esi
-+ movb %dh, %cl
-+ shrl $16, %eax
-+ movl 0x100+des_SPtrans(%ebx),%ebp
-+ xorl %ebp, %esi
-+ movb %ah, %bl
-+ shrl $16, %edx
-+ movl 0x300+des_SPtrans(%ecx),%ebp
-+ xorl %ebp, %esi
-+ movl 24(%esp), %ebp
-+ movb %dh, %cl
-+ andl $0xff, %eax
-+ andl $0xff, %edx
-+ movl 0x600+des_SPtrans(%ebx),%ebx
-+ xorl %ebx, %esi
-+ movl 0x700+des_SPtrans(%ecx),%ebx
-+ xorl %ebx, %esi
-+ movl 0x400+des_SPtrans(%eax),%ebx
-+ xorl %ebx, %esi
-+ movl 0x500+des_SPtrans(%edx),%ebx
-+ xorl %ebx, %esi
-+ jmp .L003end
-+.L002start_decrypt:
-+
-+
-+ movl 120(%ebp), %eax
-+ xorl %ebx, %ebx
-+ movl 124(%ebp), %edx
-+ xorl %esi, %eax
-+ xorl %esi, %edx
-+ andl $0xfcfcfcfc, %eax
-+ andl $0xcfcfcfcf, %edx
-+ movb %al, %bl
-+ movb %ah, %cl
-+ rorl $4, %edx
-+ movl des_SPtrans(%ebx),%ebp
-+ movb %dl, %bl
-+ xorl %ebp, %edi
-+ movl 0x200+des_SPtrans(%ecx),%ebp
-+ xorl %ebp, %edi
-+ movb %dh, %cl
-+ shrl $16, %eax
-+ movl 0x100+des_SPtrans(%ebx),%ebp
-+ xorl %ebp, %edi
-+ movb %ah, %bl
-+ shrl $16, %edx
-+ movl 0x300+des_SPtrans(%ecx),%ebp
-+ xorl %ebp, %edi
-+ movl 24(%esp), %ebp
-+ movb %dh, %cl
-+ andl $0xff, %eax
-+ andl $0xff, %edx
-+ movl 0x600+des_SPtrans(%ebx),%ebx
-+ xorl %ebx, %edi
-+ movl 0x700+des_SPtrans(%ecx),%ebx
-+ xorl %ebx, %edi
-+ movl 0x400+des_SPtrans(%eax),%ebx
-+ xorl %ebx, %edi
-+ movl 0x500+des_SPtrans(%edx),%ebx
-+ xorl %ebx, %edi
-+
-+
-+ movl 112(%ebp), %eax
-+ xorl %ebx, %ebx
-+ movl 116(%ebp), %edx
-+ xorl %edi, %eax
-+ xorl %edi, %edx
-+ andl $0xfcfcfcfc, %eax
-+ andl $0xcfcfcfcf, %edx
-+ movb %al, %bl
-+ movb %ah, %cl
-+ rorl $4, %edx
-+ movl des_SPtrans(%ebx),%ebp
-+ movb %dl, %bl
-+ xorl %ebp, %esi
-+ movl 0x200+des_SPtrans(%ecx),%ebp
-+ xorl %ebp, %esi
-+ movb %dh, %cl
-+ shrl $16, %eax
-+ movl 0x100+des_SPtrans(%ebx),%ebp
-+ xorl %ebp, %esi
-+ movb %ah, %bl
-+ shrl $16, %edx
-+ movl 0x300+des_SPtrans(%ecx),%ebp
-+ xorl %ebp, %esi
-+ movl 24(%esp), %ebp
-+ movb %dh, %cl
-+ andl $0xff, %eax
-+ andl $0xff, %edx
-+ movl 0x600+des_SPtrans(%ebx),%ebx
-+ xorl %ebx, %esi
-+ movl 0x700+des_SPtrans(%ecx),%ebx
-+ xorl %ebx, %esi
-+ movl 0x400+des_SPtrans(%eax),%ebx
-+ xorl %ebx, %esi
-+ movl 0x500+des_SPtrans(%edx),%ebx
-+ xorl %ebx, %esi
-+
-+
-+ movl 104(%ebp), %eax
-+ xorl %ebx, %ebx
-+ movl 108(%ebp), %edx
-+ xorl %esi, %eax
-+ xorl %esi, %edx
-+ andl $0xfcfcfcfc, %eax
-+ andl $0xcfcfcfcf, %edx
-+ movb %al, %bl
-+ movb %ah, %cl
-+ rorl $4, %edx
-+ movl des_SPtrans(%ebx),%ebp
-+ movb %dl, %bl
-+ xorl %ebp, %edi
-+ movl 0x200+des_SPtrans(%ecx),%ebp
-+ xorl %ebp, %edi
-+ movb %dh, %cl
-+ shrl $16, %eax
-+ movl 0x100+des_SPtrans(%ebx),%ebp
-+ xorl %ebp, %edi
-+ movb %ah, %bl
-+ shrl $16, %edx
-+ movl 0x300+des_SPtrans(%ecx),%ebp
-+ xorl %ebp, %edi
-+ movl 24(%esp), %ebp
-+ movb %dh, %cl
-+ andl $0xff, %eax
-+ andl $0xff, %edx
-+ movl 0x600+des_SPtrans(%ebx),%ebx
-+ xorl %ebx, %edi
-+ movl 0x700+des_SPtrans(%ecx),%ebx
-+ xorl %ebx, %edi
-+ movl 0x400+des_SPtrans(%eax),%ebx
-+ xorl %ebx, %edi
-+ movl 0x500+des_SPtrans(%edx),%ebx
-+ xorl %ebx, %edi
-+
-+
-+ movl 96(%ebp), %eax
-+ xorl %ebx, %ebx
-+ movl 100(%ebp), %edx
-+ xorl %edi, %eax
-+ xorl %edi, %edx
-+ andl $0xfcfcfcfc, %eax
-+ andl $0xcfcfcfcf, %edx
-+ movb %al, %bl
-+ movb %ah, %cl
-+ rorl $4, %edx
-+ movl des_SPtrans(%ebx),%ebp
-+ movb %dl, %bl
-+ xorl %ebp, %esi
-+ movl 0x200+des_SPtrans(%ecx),%ebp
-+ xorl %ebp, %esi
-+ movb %dh, %cl
-+ shrl $16, %eax
-+ movl 0x100+des_SPtrans(%ebx),%ebp
-+ xorl %ebp, %esi
-+ movb %ah, %bl
-+ shrl $16, %edx
-+ movl 0x300+des_SPtrans(%ecx),%ebp
-+ xorl %ebp, %esi
-+ movl 24(%esp), %ebp
-+ movb %dh, %cl
-+ andl $0xff, %eax
-+ andl $0xff, %edx
-+ movl 0x600+des_SPtrans(%ebx),%ebx
-+ xorl %ebx, %esi
-+ movl 0x700+des_SPtrans(%ecx),%ebx
-+ xorl %ebx, %esi
-+ movl 0x400+des_SPtrans(%eax),%ebx
-+ xorl %ebx, %esi
-+ movl 0x500+des_SPtrans(%edx),%ebx
-+ xorl %ebx, %esi
-+
-+
-+ movl 88(%ebp), %eax
-+ xorl %ebx, %ebx
-+ movl 92(%ebp), %edx
-+ xorl %esi, %eax
-+ xorl %esi, %edx
-+ andl $0xfcfcfcfc, %eax
-+ andl $0xcfcfcfcf, %edx
-+ movb %al, %bl
-+ movb %ah, %cl
-+ rorl $4, %edx
-+ movl des_SPtrans(%ebx),%ebp
-+ movb %dl, %bl
-+ xorl %ebp, %edi
-+ movl 0x200+des_SPtrans(%ecx),%ebp
-+ xorl %ebp, %edi
-+ movb %dh, %cl
-+ shrl $16, %eax
-+ movl 0x100+des_SPtrans(%ebx),%ebp
-+ xorl %ebp, %edi
-+ movb %ah, %bl
-+ shrl $16, %edx
-+ movl 0x300+des_SPtrans(%ecx),%ebp
-+ xorl %ebp, %edi
-+ movl 24(%esp), %ebp
-+ movb %dh, %cl
-+ andl $0xff, %eax
-+ andl $0xff, %edx
-+ movl 0x600+des_SPtrans(%ebx),%ebx
-+ xorl %ebx, %edi
-+ movl 0x700+des_SPtrans(%ecx),%ebx
-+ xorl %ebx, %edi
-+ movl 0x400+des_SPtrans(%eax),%ebx
-+ xorl %ebx, %edi
-+ movl 0x500+des_SPtrans(%edx),%ebx
-+ xorl %ebx, %edi
-+
-+
-+ movl 80(%ebp), %eax
-+ xorl %ebx, %ebx
-+ movl 84(%ebp), %edx
-+ xorl %edi, %eax
-+ xorl %edi, %edx
-+ andl $0xfcfcfcfc, %eax
-+ andl $0xcfcfcfcf, %edx
-+ movb %al, %bl
-+ movb %ah, %cl
-+ rorl $4, %edx
-+ movl des_SPtrans(%ebx),%ebp
-+ movb %dl, %bl
-+ xorl %ebp, %esi
-+ movl 0x200+des_SPtrans(%ecx),%ebp
-+ xorl %ebp, %esi
-+ movb %dh, %cl
-+ shrl $16, %eax
-+ movl 0x100+des_SPtrans(%ebx),%ebp
-+ xorl %ebp, %esi
-+ movb %ah, %bl
-+ shrl $16, %edx
-+ movl 0x300+des_SPtrans(%ecx),%ebp
-+ xorl %ebp, %esi
-+ movl 24(%esp), %ebp
-+ movb %dh, %cl
-+ andl $0xff, %eax
-+ andl $0xff, %edx
-+ movl 0x600+des_SPtrans(%ebx),%ebx
-+ xorl %ebx, %esi
-+ movl 0x700+des_SPtrans(%ecx),%ebx
-+ xorl %ebx, %esi
-+ movl 0x400+des_SPtrans(%eax),%ebx
-+ xorl %ebx, %esi
-+ movl 0x500+des_SPtrans(%edx),%ebx
-+ xorl %ebx, %esi
-+
-+
-+ movl 72(%ebp), %eax
-+ xorl %ebx, %ebx
-+ movl 76(%ebp), %edx
-+ xorl %esi, %eax
-+ xorl %esi, %edx
-+ andl $0xfcfcfcfc, %eax
-+ andl $0xcfcfcfcf, %edx
-+ movb %al, %bl
-+ movb %ah, %cl
-+ rorl $4, %edx
-+ movl des_SPtrans(%ebx),%ebp
-+ movb %dl, %bl
-+ xorl %ebp, %edi
-+ movl 0x200+des_SPtrans(%ecx),%ebp
-+ xorl %ebp, %edi
-+ movb %dh, %cl
-+ shrl $16, %eax
-+ movl 0x100+des_SPtrans(%ebx),%ebp
-+ xorl %ebp, %edi
-+ movb %ah, %bl
-+ shrl $16, %edx
-+ movl 0x300+des_SPtrans(%ecx),%ebp
-+ xorl %ebp, %edi
-+ movl 24(%esp), %ebp
-+ movb %dh, %cl
-+ andl $0xff, %eax
-+ andl $0xff, %edx
-+ movl 0x600+des_SPtrans(%ebx),%ebx
-+ xorl %ebx, %edi
-+ movl 0x700+des_SPtrans(%ecx),%ebx
-+ xorl %ebx, %edi
-+ movl 0x400+des_SPtrans(%eax),%ebx
-+ xorl %ebx, %edi
-+ movl 0x500+des_SPtrans(%edx),%ebx
-+ xorl %ebx, %edi
-+
-+
-+ movl 64(%ebp), %eax
-+ xorl %ebx, %ebx
-+ movl 68(%ebp), %edx
-+ xorl %edi, %eax
-+ xorl %edi, %edx
-+ andl $0xfcfcfcfc, %eax
-+ andl $0xcfcfcfcf, %edx
-+ movb %al, %bl
-+ movb %ah, %cl
-+ rorl $4, %edx
-+ movl des_SPtrans(%ebx),%ebp
-+ movb %dl, %bl
-+ xorl %ebp, %esi
-+ movl 0x200+des_SPtrans(%ecx),%ebp
-+ xorl %ebp, %esi
-+ movb %dh, %cl
-+ shrl $16, %eax
-+ movl 0x100+des_SPtrans(%ebx),%ebp
-+ xorl %ebp, %esi
-+ movb %ah, %bl
-+ shrl $16, %edx
-+ movl 0x300+des_SPtrans(%ecx),%ebp
-+ xorl %ebp, %esi
-+ movl 24(%esp), %ebp
-+ movb %dh, %cl
-+ andl $0xff, %eax
-+ andl $0xff, %edx
-+ movl 0x600+des_SPtrans(%ebx),%ebx
-+ xorl %ebx, %esi
-+ movl 0x700+des_SPtrans(%ecx),%ebx
-+ xorl %ebx, %esi
-+ movl 0x400+des_SPtrans(%eax),%ebx
-+ xorl %ebx, %esi
-+ movl 0x500+des_SPtrans(%edx),%ebx
-+ xorl %ebx, %esi
-+
-+
-+ movl 56(%ebp), %eax
-+ xorl %ebx, %ebx
-+ movl 60(%ebp), %edx
-+ xorl %esi, %eax
-+ xorl %esi, %edx
-+ andl $0xfcfcfcfc, %eax
-+ andl $0xcfcfcfcf, %edx
-+ movb %al, %bl
-+ movb %ah, %cl
-+ rorl $4, %edx
-+ movl des_SPtrans(%ebx),%ebp
-+ movb %dl, %bl
-+ xorl %ebp, %edi
-+ movl 0x200+des_SPtrans(%ecx),%ebp
-+ xorl %ebp, %edi
-+ movb %dh, %cl
-+ shrl $16, %eax
-+ movl 0x100+des_SPtrans(%ebx),%ebp
-+ xorl %ebp, %edi
-+ movb %ah, %bl
-+ shrl $16, %edx
-+ movl 0x300+des_SPtrans(%ecx),%ebp
-+ xorl %ebp, %edi
-+ movl 24(%esp), %ebp
-+ movb %dh, %cl
-+ andl $0xff, %eax
-+ andl $0xff, %edx
-+ movl 0x600+des_SPtrans(%ebx),%ebx
-+ xorl %ebx, %edi
-+ movl 0x700+des_SPtrans(%ecx),%ebx
-+ xorl %ebx, %edi
-+ movl 0x400+des_SPtrans(%eax),%ebx
-+ xorl %ebx, %edi
-+ movl 0x500+des_SPtrans(%edx),%ebx
-+ xorl %ebx, %edi
-+
-+
-+ movl 48(%ebp), %eax
-+ xorl %ebx, %ebx
-+ movl 52(%ebp), %edx
-+ xorl %edi, %eax
-+ xorl %edi, %edx
-+ andl $0xfcfcfcfc, %eax
-+ andl $0xcfcfcfcf, %edx
-+ movb %al, %bl
-+ movb %ah, %cl
-+ rorl $4, %edx
-+ movl des_SPtrans(%ebx),%ebp
-+ movb %dl, %bl
-+ xorl %ebp, %esi
-+ movl 0x200+des_SPtrans(%ecx),%ebp
-+ xorl %ebp, %esi
-+ movb %dh, %cl
-+ shrl $16, %eax
-+ movl 0x100+des_SPtrans(%ebx),%ebp
-+ xorl %ebp, %esi
-+ movb %ah, %bl
-+ shrl $16, %edx
-+ movl 0x300+des_SPtrans(%ecx),%ebp
-+ xorl %ebp, %esi
-+ movl 24(%esp), %ebp
-+ movb %dh, %cl
-+ andl $0xff, %eax
-+ andl $0xff, %edx
-+ movl 0x600+des_SPtrans(%ebx),%ebx
-+ xorl %ebx, %esi
-+ movl 0x700+des_SPtrans(%ecx),%ebx
-+ xorl %ebx, %esi
-+ movl 0x400+des_SPtrans(%eax),%ebx
-+ xorl %ebx, %esi
-+ movl 0x500+des_SPtrans(%edx),%ebx
-+ xorl %ebx, %esi
-+
-+
-+ movl 40(%ebp), %eax
-+ xorl %ebx, %ebx
-+ movl 44(%ebp), %edx
-+ xorl %esi, %eax
-+ xorl %esi, %edx
-+ andl $0xfcfcfcfc, %eax
-+ andl $0xcfcfcfcf, %edx
-+ movb %al, %bl
-+ movb %ah, %cl
-+ rorl $4, %edx
-+ movl des_SPtrans(%ebx),%ebp
-+ movb %dl, %bl
-+ xorl %ebp, %edi
-+ movl 0x200+des_SPtrans(%ecx),%ebp
-+ xorl %ebp, %edi
-+ movb %dh, %cl
-+ shrl $16, %eax
-+ movl 0x100+des_SPtrans(%ebx),%ebp
-+ xorl %ebp, %edi
-+ movb %ah, %bl
-+ shrl $16, %edx
-+ movl 0x300+des_SPtrans(%ecx),%ebp
-+ xorl %ebp, %edi
-+ movl 24(%esp), %ebp
-+ movb %dh, %cl
-+ andl $0xff, %eax
-+ andl $0xff, %edx
-+ movl 0x600+des_SPtrans(%ebx),%ebx
-+ xorl %ebx, %edi
-+ movl 0x700+des_SPtrans(%ecx),%ebx
-+ xorl %ebx, %edi
-+ movl 0x400+des_SPtrans(%eax),%ebx
-+ xorl %ebx, %edi
-+ movl 0x500+des_SPtrans(%edx),%ebx
-+ xorl %ebx, %edi
-+
-+
-+ movl 32(%ebp), %eax
-+ xorl %ebx, %ebx
-+ movl 36(%ebp), %edx
-+ xorl %edi, %eax
-+ xorl %edi, %edx
-+ andl $0xfcfcfcfc, %eax
-+ andl $0xcfcfcfcf, %edx
-+ movb %al, %bl
-+ movb %ah, %cl
-+ rorl $4, %edx
-+ movl des_SPtrans(%ebx),%ebp
-+ movb %dl, %bl
-+ xorl %ebp, %esi
-+ movl 0x200+des_SPtrans(%ecx),%ebp
-+ xorl %ebp, %esi
-+ movb %dh, %cl
-+ shrl $16, %eax
-+ movl 0x100+des_SPtrans(%ebx),%ebp
-+ xorl %ebp, %esi
-+ movb %ah, %bl
-+ shrl $16, %edx
-+ movl 0x300+des_SPtrans(%ecx),%ebp
-+ xorl %ebp, %esi
-+ movl 24(%esp), %ebp
-+ movb %dh, %cl
-+ andl $0xff, %eax
-+ andl $0xff, %edx
-+ movl 0x600+des_SPtrans(%ebx),%ebx
-+ xorl %ebx, %esi
-+ movl 0x700+des_SPtrans(%ecx),%ebx
-+ xorl %ebx, %esi
-+ movl 0x400+des_SPtrans(%eax),%ebx
-+ xorl %ebx, %esi
-+ movl 0x500+des_SPtrans(%edx),%ebx
-+ xorl %ebx, %esi
-+
-+
-+ movl 24(%ebp), %eax
-+ xorl %ebx, %ebx
-+ movl 28(%ebp), %edx
-+ xorl %esi, %eax
-+ xorl %esi, %edx
-+ andl $0xfcfcfcfc, %eax
-+ andl $0xcfcfcfcf, %edx
-+ movb %al, %bl
-+ movb %ah, %cl
-+ rorl $4, %edx
-+ movl des_SPtrans(%ebx),%ebp
-+ movb %dl, %bl
-+ xorl %ebp, %edi
-+ movl 0x200+des_SPtrans(%ecx),%ebp
-+ xorl %ebp, %edi
-+ movb %dh, %cl
-+ shrl $16, %eax
-+ movl 0x100+des_SPtrans(%ebx),%ebp
-+ xorl %ebp, %edi
-+ movb %ah, %bl
-+ shrl $16, %edx
-+ movl 0x300+des_SPtrans(%ecx),%ebp
-+ xorl %ebp, %edi
-+ movl 24(%esp), %ebp
-+ movb %dh, %cl
-+ andl $0xff, %eax
-+ andl $0xff, %edx
-+ movl 0x600+des_SPtrans(%ebx),%ebx
-+ xorl %ebx, %edi
-+ movl 0x700+des_SPtrans(%ecx),%ebx
-+ xorl %ebx, %edi
-+ movl 0x400+des_SPtrans(%eax),%ebx
-+ xorl %ebx, %edi
-+ movl 0x500+des_SPtrans(%edx),%ebx
-+ xorl %ebx, %edi
-+
-+
-+ movl 16(%ebp), %eax
-+ xorl %ebx, %ebx
-+ movl 20(%ebp), %edx
-+ xorl %edi, %eax
-+ xorl %edi, %edx
-+ andl $0xfcfcfcfc, %eax
-+ andl $0xcfcfcfcf, %edx
-+ movb %al, %bl
-+ movb %ah, %cl
-+ rorl $4, %edx
-+ movl des_SPtrans(%ebx),%ebp
-+ movb %dl, %bl
-+ xorl %ebp, %esi
-+ movl 0x200+des_SPtrans(%ecx),%ebp
-+ xorl %ebp, %esi
-+ movb %dh, %cl
-+ shrl $16, %eax
-+ movl 0x100+des_SPtrans(%ebx),%ebp
-+ xorl %ebp, %esi
-+ movb %ah, %bl
-+ shrl $16, %edx
-+ movl 0x300+des_SPtrans(%ecx),%ebp
-+ xorl %ebp, %esi
-+ movl 24(%esp), %ebp
-+ movb %dh, %cl
-+ andl $0xff, %eax
-+ andl $0xff, %edx
-+ movl 0x600+des_SPtrans(%ebx),%ebx
-+ xorl %ebx, %esi
-+ movl 0x700+des_SPtrans(%ecx),%ebx
-+ xorl %ebx, %esi
-+ movl 0x400+des_SPtrans(%eax),%ebx
-+ xorl %ebx, %esi
-+ movl 0x500+des_SPtrans(%edx),%ebx
-+ xorl %ebx, %esi
-+
-+
-+ movl 8(%ebp), %eax
-+ xorl %ebx, %ebx
-+ movl 12(%ebp), %edx
-+ xorl %esi, %eax
-+ xorl %esi, %edx
-+ andl $0xfcfcfcfc, %eax
-+ andl $0xcfcfcfcf, %edx
-+ movb %al, %bl
-+ movb %ah, %cl
-+ rorl $4, %edx
-+ movl des_SPtrans(%ebx),%ebp
-+ movb %dl, %bl
-+ xorl %ebp, %edi
-+ movl 0x200+des_SPtrans(%ecx),%ebp
-+ xorl %ebp, %edi
-+ movb %dh, %cl
-+ shrl $16, %eax
-+ movl 0x100+des_SPtrans(%ebx),%ebp
-+ xorl %ebp, %edi
-+ movb %ah, %bl
-+ shrl $16, %edx
-+ movl 0x300+des_SPtrans(%ecx),%ebp
-+ xorl %ebp, %edi
-+ movl 24(%esp), %ebp
-+ movb %dh, %cl
-+ andl $0xff, %eax
-+ andl $0xff, %edx
-+ movl 0x600+des_SPtrans(%ebx),%ebx
-+ xorl %ebx, %edi
-+ movl 0x700+des_SPtrans(%ecx),%ebx
-+ xorl %ebx, %edi
-+ movl 0x400+des_SPtrans(%eax),%ebx
-+ xorl %ebx, %edi
-+ movl 0x500+des_SPtrans(%edx),%ebx
-+ xorl %ebx, %edi
-+
-+
-+ movl (%ebp), %eax
-+ xorl %ebx, %ebx
-+ movl 4(%ebp), %edx
-+ xorl %edi, %eax
-+ xorl %edi, %edx
-+ andl $0xfcfcfcfc, %eax
-+ andl $0xcfcfcfcf, %edx
-+ movb %al, %bl
-+ movb %ah, %cl
-+ rorl $4, %edx
-+ movl des_SPtrans(%ebx),%ebp
-+ movb %dl, %bl
-+ xorl %ebp, %esi
-+ movl 0x200+des_SPtrans(%ecx),%ebp
-+ xorl %ebp, %esi
-+ movb %dh, %cl
-+ shrl $16, %eax
-+ movl 0x100+des_SPtrans(%ebx),%ebp
-+ xorl %ebp, %esi
-+ movb %ah, %bl
-+ shrl $16, %edx
-+ movl 0x300+des_SPtrans(%ecx),%ebp
-+ xorl %ebp, %esi
-+ movl 24(%esp), %ebp
-+ movb %dh, %cl
-+ andl $0xff, %eax
-+ andl $0xff, %edx
-+ movl 0x600+des_SPtrans(%ebx),%ebx
-+ xorl %ebx, %esi
-+ movl 0x700+des_SPtrans(%ecx),%ebx
-+ xorl %ebx, %esi
-+ movl 0x400+des_SPtrans(%eax),%ebx
-+ xorl %ebx, %esi
-+ movl 0x500+des_SPtrans(%edx),%ebx
-+ xorl %ebx, %esi
-+.L003end:
-+
-+
-+ rorl $3, %edi
-+ movl 20(%esp), %eax
-+ rorl $3, %esi
-+ movl %edi, (%eax)
-+ movl %esi, 4(%eax)
-+ popl %ebp
-+ popl %ebx
-+ popl %edi
-+ popl %esi
-+ ret
-+.des_encrypt2_end:
-+ .size des_encrypt2 , .des_encrypt2_end-des_encrypt2
-+.ident "desasm.pl"
-+.text
-+ .align 16
-+.globl des_encrypt3
-+ .type des_encrypt3 , @function
-+des_encrypt3:
-+ pushl %ebx
-+ movl 8(%esp), %ebx
-+ pushl %ebp
-+ pushl %esi
-+ pushl %edi
-+
-+
-+ movl (%ebx), %edi
-+ movl 4(%ebx), %esi
-+ subl $12, %esp
-+
-+
-+ roll $4, %edi
-+ movl %edi, %edx
-+ xorl %esi, %edi
-+ andl $0xf0f0f0f0, %edi
-+ xorl %edi, %edx
-+ xorl %edi, %esi
-+
-+ roll $20, %esi
-+ movl %esi, %edi
-+ xorl %edx, %esi
-+ andl $0xfff0000f, %esi
-+ xorl %esi, %edi
-+ xorl %esi, %edx
-+
-+ roll $14, %edi
-+ movl %edi, %esi
-+ xorl %edx, %edi
-+ andl $0x33333333, %edi
-+ xorl %edi, %esi
-+ xorl %edi, %edx
-+
-+ roll $22, %edx
-+ movl %edx, %edi
-+ xorl %esi, %edx
-+ andl $0x03fc03fc, %edx
-+ xorl %edx, %edi
-+ xorl %edx, %esi
-+
-+ roll $9, %edi
-+ movl %edi, %edx
-+ xorl %esi, %edi
-+ andl $0xaaaaaaaa, %edi
-+ xorl %edi, %edx
-+ xorl %edi, %esi
-+
-+ rorl $3, %edx
-+ rorl $2, %esi
-+ movl %esi, 4(%ebx)
-+ movl 36(%esp), %eax
-+ movl %edx, (%ebx)
-+ movl 40(%esp), %edi
-+ movl 44(%esp), %esi
-+ movl $1, 8(%esp)
-+ movl %eax, 4(%esp)
-+ movl %ebx, (%esp)
-+ call des_encrypt2
-+ movl $0, 8(%esp)
-+ movl %edi, 4(%esp)
-+ movl %ebx, (%esp)
-+ call des_encrypt2
-+ movl $1, 8(%esp)
-+ movl %esi, 4(%esp)
-+ movl %ebx, (%esp)
-+ call des_encrypt2
-+ addl $12, %esp
-+ movl (%ebx), %edi
-+ movl 4(%ebx), %esi
-+
-+
-+ roll $2, %esi
-+ roll $3, %edi
-+ movl %edi, %eax
-+ xorl %esi, %edi
-+ andl $0xaaaaaaaa, %edi
-+ xorl %edi, %eax
-+ xorl %edi, %esi
-+
-+ roll $23, %eax
-+ movl %eax, %edi
-+ xorl %esi, %eax
-+ andl $0x03fc03fc, %eax
-+ xorl %eax, %edi
-+ xorl %eax, %esi
-+
-+ roll $10, %edi
-+ movl %edi, %eax
-+ xorl %esi, %edi
-+ andl $0x33333333, %edi
-+ xorl %edi, %eax
-+ xorl %edi, %esi
-+
-+ roll $18, %esi
-+ movl %esi, %edi
-+ xorl %eax, %esi
-+ andl $0xfff0000f, %esi
-+ xorl %esi, %edi
-+ xorl %esi, %eax
-+
-+ roll $12, %edi
-+ movl %edi, %esi
-+ xorl %eax, %edi
-+ andl $0xf0f0f0f0, %edi
-+ xorl %edi, %esi
-+ xorl %edi, %eax
-+
-+ rorl $4, %eax
-+ movl %eax, (%ebx)
-+ movl %esi, 4(%ebx)
-+ popl %edi
-+ popl %esi
-+ popl %ebp
-+ popl %ebx
-+ ret
-+.des_encrypt3_end:
-+ .size des_encrypt3 , .des_encrypt3_end-des_encrypt3
-+.ident "desasm.pl"
-+.text
-+ .align 16
-+.globl des_decrypt3
-+ .type des_decrypt3 , @function
-+des_decrypt3:
-+ pushl %ebx
-+ movl 8(%esp), %ebx
-+ pushl %ebp
-+ pushl %esi
-+ pushl %edi
-+
-+
-+ movl (%ebx), %edi
-+ movl 4(%ebx), %esi
-+ subl $12, %esp
-+
-+
-+ roll $4, %edi
-+ movl %edi, %edx
-+ xorl %esi, %edi
-+ andl $0xf0f0f0f0, %edi
-+ xorl %edi, %edx
-+ xorl %edi, %esi
-+
-+ roll $20, %esi
-+ movl %esi, %edi
-+ xorl %edx, %esi
-+ andl $0xfff0000f, %esi
-+ xorl %esi, %edi
-+ xorl %esi, %edx
-+
-+ roll $14, %edi
-+ movl %edi, %esi
-+ xorl %edx, %edi
-+ andl $0x33333333, %edi
-+ xorl %edi, %esi
-+ xorl %edi, %edx
-+
-+ roll $22, %edx
-+ movl %edx, %edi
-+ xorl %esi, %edx
-+ andl $0x03fc03fc, %edx
-+ xorl %edx, %edi
-+ xorl %edx, %esi
-+
-+ roll $9, %edi
-+ movl %edi, %edx
-+ xorl %esi, %edi
-+ andl $0xaaaaaaaa, %edi
-+ xorl %edi, %edx
-+ xorl %edi, %esi
-+
-+ rorl $3, %edx
-+ rorl $2, %esi
-+ movl %esi, 4(%ebx)
-+ movl 36(%esp), %esi
-+ movl %edx, (%ebx)
-+ movl 40(%esp), %edi
-+ movl 44(%esp), %eax
-+ movl $0, 8(%esp)
-+ movl %eax, 4(%esp)
-+ movl %ebx, (%esp)
-+ call des_encrypt2
-+ movl $1, 8(%esp)
-+ movl %edi, 4(%esp)
-+ movl %ebx, (%esp)
-+ call des_encrypt2
-+ movl $0, 8(%esp)
-+ movl %esi, 4(%esp)
-+ movl %ebx, (%esp)
-+ call des_encrypt2
-+ addl $12, %esp
-+ movl (%ebx), %edi
-+ movl 4(%ebx), %esi
-+
-+
-+ roll $2, %esi
-+ roll $3, %edi
-+ movl %edi, %eax
-+ xorl %esi, %edi
-+ andl $0xaaaaaaaa, %edi
-+ xorl %edi, %eax
-+ xorl %edi, %esi
-+
-+ roll $23, %eax
-+ movl %eax, %edi
-+ xorl %esi, %eax
-+ andl $0x03fc03fc, %eax
-+ xorl %eax, %edi
-+ xorl %eax, %esi
-+
-+ roll $10, %edi
-+ movl %edi, %eax
-+ xorl %esi, %edi
-+ andl $0x33333333, %edi
-+ xorl %edi, %eax
-+ xorl %edi, %esi
-+
-+ roll $18, %esi
-+ movl %esi, %edi
-+ xorl %eax, %esi
-+ andl $0xfff0000f, %esi
-+ xorl %esi, %edi
-+ xorl %esi, %eax
-+
-+ roll $12, %edi
-+ movl %edi, %esi
-+ xorl %eax, %edi
-+ andl $0xf0f0f0f0, %edi
-+ xorl %edi, %esi
-+ xorl %edi, %eax
-+
-+ rorl $4, %eax
-+ movl %eax, (%ebx)
-+ movl %esi, 4(%ebx)
-+ popl %edi
-+ popl %esi
-+ popl %ebp
-+ popl %ebx
-+ ret
-+.des_decrypt3_end:
-+ .size des_decrypt3 , .des_decrypt3_end-des_decrypt3
-+.ident "desasm.pl"
-+.text
-+ .align 16
-+.globl des_ncbc_encrypt
-+ .type des_ncbc_encrypt , @function
-+des_ncbc_encrypt:
-+
-+ pushl %ebp
-+ pushl %ebx
-+ pushl %esi
-+ pushl %edi
-+ movl 28(%esp), %ebp
-+
-+ movl 36(%esp), %ebx
-+ movl (%ebx), %esi
-+ movl 4(%ebx), %edi
-+ pushl %edi
-+ pushl %esi
-+ pushl %edi
-+ pushl %esi
-+ movl %esp, %ebx
-+ movl 36(%esp), %esi
-+ movl 40(%esp), %edi
-+
-+ movl 56(%esp), %ecx
-+
-+ pushl %ecx
-+
-+ movl 52(%esp), %eax
-+ pushl %eax
-+ pushl %ebx
-+ cmpl $0, %ecx
-+ jz .L004decrypt
-+ andl $4294967288, %ebp
-+ movl 12(%esp), %eax
-+ movl 16(%esp), %ebx
-+ jz .L005encrypt_finish
-+.L006encrypt_loop:
-+ movl (%esi), %ecx
-+ movl 4(%esi), %edx
-+ xorl %ecx, %eax
-+ xorl %edx, %ebx
-+ movl %eax, 12(%esp)
-+ movl %ebx, 16(%esp)
-+ call des_encrypt
-+ movl 12(%esp), %eax
-+ movl 16(%esp), %ebx
-+ movl %eax, (%edi)
-+ movl %ebx, 4(%edi)
-+ addl $8, %esi
-+ addl $8, %edi
-+ subl $8, %ebp
-+ jnz .L006encrypt_loop
-+.L005encrypt_finish:
-+ movl 56(%esp), %ebp
-+ andl $7, %ebp
-+ jz .L007finish
-+ xorl %ecx, %ecx
-+ xorl %edx, %edx
-+ movl .L008cbc_enc_jmp_table(,%ebp,4),%ebp
-+ jmp *%ebp
-+.L009ej7:
-+ movb 6(%esi), %dh
-+ sall $8, %edx
-+.L010ej6:
-+ movb 5(%esi), %dh
-+.L011ej5:
-+ movb 4(%esi), %dl
-+.L012ej4:
-+ movl (%esi), %ecx
-+ jmp .L013ejend
-+.L014ej3:
-+ movb 2(%esi), %ch
-+ sall $8, %ecx
-+.L015ej2:
-+ movb 1(%esi), %ch
-+.L016ej1:
-+ movb (%esi), %cl
-+.L013ejend:
-+ xorl %ecx, %eax
-+ xorl %edx, %ebx
-+ movl %eax, 12(%esp)
-+ movl %ebx, 16(%esp)
-+ call des_encrypt
-+ movl 12(%esp), %eax
-+ movl 16(%esp), %ebx
-+ movl %eax, (%edi)
-+ movl %ebx, 4(%edi)
-+ jmp .L007finish
-+.align 16
-+.L004decrypt:
-+ andl $4294967288, %ebp
-+ movl 20(%esp), %eax
-+ movl 24(%esp), %ebx
-+ jz .L017decrypt_finish
-+.L018decrypt_loop:
-+ movl (%esi), %eax
-+ movl 4(%esi), %ebx
-+ movl %eax, 12(%esp)
-+ movl %ebx, 16(%esp)
-+ call des_encrypt
-+ movl 12(%esp), %eax
-+ movl 16(%esp), %ebx
-+ movl 20(%esp), %ecx
-+ movl 24(%esp), %edx
-+ xorl %eax, %ecx
-+ xorl %ebx, %edx
-+ movl (%esi), %eax
-+ movl 4(%esi), %ebx
-+ movl %ecx, (%edi)
-+ movl %edx, 4(%edi)
-+ movl %eax, 20(%esp)
-+ movl %ebx, 24(%esp)
-+ addl $8, %esi
-+ addl $8, %edi
-+ subl $8, %ebp
-+ jnz .L018decrypt_loop
-+.L017decrypt_finish:
-+ movl 56(%esp), %ebp
-+ andl $7, %ebp
-+ jz .L007finish
-+ movl (%esi), %eax
-+ movl 4(%esi), %ebx
-+ movl %eax, 12(%esp)
-+ movl %ebx, 16(%esp)
-+ call des_encrypt
-+ movl 12(%esp), %eax
-+ movl 16(%esp), %ebx
-+ movl 20(%esp), %ecx
-+ movl 24(%esp), %edx
-+ xorl %eax, %ecx
-+ xorl %ebx, %edx
-+ movl (%esi), %eax
-+ movl 4(%esi), %ebx
-+.L019dj7:
-+ rorl $16, %edx
-+ movb %dl, 6(%edi)
-+ shrl $16, %edx
-+.L020dj6:
-+ movb %dh, 5(%edi)
-+.L021dj5:
-+ movb %dl, 4(%edi)
-+.L022dj4:
-+ movl %ecx, (%edi)
-+ jmp .L023djend
-+.L024dj3:
-+ rorl $16, %ecx
-+ movb %cl, 2(%edi)
-+ sall $16, %ecx
-+.L025dj2:
-+ movb %ch, 1(%esi)
-+.L026dj1:
-+ movb %cl, (%esi)
-+.L023djend:
-+ jmp .L007finish
-+.align 16
-+.L007finish:
-+ movl 64(%esp), %ecx
-+ addl $28, %esp
-+ movl %eax, (%ecx)
-+ movl %ebx, 4(%ecx)
-+ popl %edi
-+ popl %esi
-+ popl %ebx
-+ popl %ebp
-+ ret
-+.align 16
-+.L008cbc_enc_jmp_table:
-+ .long 0
-+ .long .L016ej1
-+ .long .L015ej2
-+ .long .L014ej3
-+ .long .L012ej4
-+ .long .L011ej5
-+ .long .L010ej6
-+ .long .L009ej7
-+.align 16
-+.L027cbc_dec_jmp_table:
-+ .long 0
-+ .long .L026dj1
-+ .long .L025dj2
-+ .long .L024dj3
-+ .long .L022dj4
-+ .long .L021dj5
-+ .long .L020dj6
-+ .long .L019dj7
-+.des_ncbc_encrypt_end:
-+ .size des_ncbc_encrypt , .des_ncbc_encrypt_end-des_ncbc_encrypt
-+.ident "desasm.pl"
-+.text
-+ .align 16
-+.globl des_ede3_cbc_encrypt
-+ .type des_ede3_cbc_encrypt , @function
-+des_ede3_cbc_encrypt:
-+
-+ pushl %ebp
-+ pushl %ebx
-+ pushl %esi
-+ pushl %edi
-+ movl 28(%esp), %ebp
-+
-+ movl 44(%esp), %ebx
-+ movl (%ebx), %esi
-+ movl 4(%ebx), %edi
-+ pushl %edi
-+ pushl %esi
-+ pushl %edi
-+ pushl %esi
-+ movl %esp, %ebx
-+ movl 36(%esp), %esi
-+ movl 40(%esp), %edi
-+
-+ movl 64(%esp), %ecx
-+
-+ movl 56(%esp), %eax
-+ pushl %eax
-+
-+ movl 56(%esp), %eax
-+ pushl %eax
-+
-+ movl 56(%esp), %eax
-+ pushl %eax
-+ pushl %ebx
-+ cmpl $0, %ecx
-+ jz .L028decrypt
-+ andl $4294967288, %ebp
-+ movl 16(%esp), %eax
-+ movl 20(%esp), %ebx
-+ jz .L029encrypt_finish
-+.L030encrypt_loop:
-+ movl (%esi), %ecx
-+ movl 4(%esi), %edx
-+ xorl %ecx, %eax
-+ xorl %edx, %ebx
-+ movl %eax, 16(%esp)
-+ movl %ebx, 20(%esp)
-+ call des_encrypt3
-+ movl 16(%esp), %eax
-+ movl 20(%esp), %ebx
-+ movl %eax, (%edi)
-+ movl %ebx, 4(%edi)
-+ addl $8, %esi
-+ addl $8, %edi
-+ subl $8, %ebp
-+ jnz .L030encrypt_loop
-+.L029encrypt_finish:
-+ movl 60(%esp), %ebp
-+ andl $7, %ebp
-+ jz .L031finish
-+ xorl %ecx, %ecx
-+ xorl %edx, %edx
-+ movl .L032cbc_enc_jmp_table(,%ebp,4),%ebp
-+ jmp *%ebp
-+.L033ej7:
-+ movb 6(%esi), %dh
-+ sall $8, %edx
-+.L034ej6:
-+ movb 5(%esi), %dh
-+.L035ej5:
-+ movb 4(%esi), %dl
-+.L036ej4:
-+ movl (%esi), %ecx
-+ jmp .L037ejend
-+.L038ej3:
-+ movb 2(%esi), %ch
-+ sall $8, %ecx
-+.L039ej2:
-+ movb 1(%esi), %ch
-+.L040ej1:
-+ movb (%esi), %cl
-+.L037ejend:
-+ xorl %ecx, %eax
-+ xorl %edx, %ebx
-+ movl %eax, 16(%esp)
-+ movl %ebx, 20(%esp)
-+ call des_encrypt3
-+ movl 16(%esp), %eax
-+ movl 20(%esp), %ebx
-+ movl %eax, (%edi)
-+ movl %ebx, 4(%edi)
-+ jmp .L031finish
-+.align 16
-+.L028decrypt:
-+ andl $4294967288, %ebp
-+ movl 24(%esp), %eax
-+ movl 28(%esp), %ebx
-+ jz .L041decrypt_finish
-+.L042decrypt_loop:
-+ movl (%esi), %eax
-+ movl 4(%esi), %ebx
-+ movl %eax, 16(%esp)
-+ movl %ebx, 20(%esp)
-+ call des_decrypt3
-+ movl 16(%esp), %eax
-+ movl 20(%esp), %ebx
-+ movl 24(%esp), %ecx
-+ movl 28(%esp), %edx
-+ xorl %eax, %ecx
-+ xorl %ebx, %edx
-+ movl (%esi), %eax
-+ movl 4(%esi), %ebx
-+ movl %ecx, (%edi)
-+ movl %edx, 4(%edi)
-+ movl %eax, 24(%esp)
-+ movl %ebx, 28(%esp)
-+ addl $8, %esi
-+ addl $8, %edi
-+ subl $8, %ebp
-+ jnz .L042decrypt_loop
-+.L041decrypt_finish:
-+ movl 60(%esp), %ebp
-+ andl $7, %ebp
-+ jz .L031finish
-+ movl (%esi), %eax
-+ movl 4(%esi), %ebx
-+ movl %eax, 16(%esp)
-+ movl %ebx, 20(%esp)
-+ call des_decrypt3
-+ movl 16(%esp), %eax
-+ movl 20(%esp), %ebx
-+ movl 24(%esp), %ecx
-+ movl 28(%esp), %edx
-+ xorl %eax, %ecx
-+ xorl %ebx, %edx
-+ movl (%esi), %eax
-+ movl 4(%esi), %ebx
-+.L043dj7:
-+ rorl $16, %edx
-+ movb %dl, 6(%edi)
-+ shrl $16, %edx
-+.L044dj6:
-+ movb %dh, 5(%edi)
-+.L045dj5:
-+ movb %dl, 4(%edi)
-+.L046dj4:
-+ movl %ecx, (%edi)
-+ jmp .L047djend
-+.L048dj3:
-+ rorl $16, %ecx
-+ movb %cl, 2(%edi)
-+ sall $16, %ecx
-+.L049dj2:
-+ movb %ch, 1(%esi)
-+.L050dj1:
-+ movb %cl, (%esi)
-+.L047djend:
-+ jmp .L031finish
-+.align 16
-+.L031finish:
-+ movl 76(%esp), %ecx
-+ addl $32, %esp
-+ movl %eax, (%ecx)
-+ movl %ebx, 4(%ecx)
-+ popl %edi
-+ popl %esi
-+ popl %ebx
-+ popl %ebp
-+ ret
-+.align 16
-+.L032cbc_enc_jmp_table:
-+ .long 0
-+ .long .L040ej1
-+ .long .L039ej2
-+ .long .L038ej3
-+ .long .L036ej4
-+ .long .L035ej5
-+ .long .L034ej6
-+ .long .L033ej7
-+.align 16
-+.L051cbc_dec_jmp_table:
-+ .long 0
-+ .long .L050dj1
-+ .long .L049dj2
-+ .long .L048dj3
-+ .long .L046dj4
-+ .long .L045dj5
-+ .long .L044dj6
-+ .long .L043dj7
-+.des_ede3_cbc_encrypt_end:
-+ .size des_ede3_cbc_encrypt , .des_ede3_cbc_encrypt_end-des_ede3_cbc_encrypt
-+.ident "desasm.pl"
---- /dev/null Tue Mar 11 13:02:56 2003
-+++ linux/crypto/ciphers/des/ecb_enc.c Mon Feb 9 13:51:03 2004
-@@ -0,0 +1,128 @@
-+/* crypto/des/ecb_enc.c */
-+/* Copyright (C) 1995-1997 Eric Young (eay@cryptsoft.com)
-+ * All rights reserved.
-+ *
-+ * This package is an SSL implementation written
-+ * by Eric Young (eay@cryptsoft.com).
-+ * The implementation was written so as to conform with Netscapes SSL.
-+ *
-+ * This library is free for commercial and non-commercial use as long as
-+ * the following conditions are aheared to. The following conditions
-+ * apply to all code found in this distribution, be it the RC4, RSA,
-+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
-+ * included with this distribution is covered by the same copyright terms
-+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
-+ *
-+ * Copyright remains Eric Young's, and as such any Copyright notices in
-+ * the code are not to be removed.
-+ * If this package is used in a product, Eric Young should be given attribution
-+ * as the author of the parts of the library used.
-+ * This can be in the form of a textual message at program startup or
-+ * in documentation (online or textual) provided with the package.
-+ *
-+ * Redistribution and use in source and binary forms, with or without
-+ * modification, are permitted provided that the following conditions
-+ * are met:
-+ * 1. Redistributions of source code must retain the copyright
-+ * notice, this list of conditions and the following disclaimer.
-+ * 2. Redistributions in binary form must reproduce the above copyright
-+ * notice, this list of conditions and the following disclaimer in the
-+ * documentation and/or other materials provided with the distribution.
-+ * 3. All advertising materials mentioning features or use of this software
-+ * must display the following acknowledgement:
-+ * "This product includes cryptographic software written by
-+ * Eric Young (eay@cryptsoft.com)"
-+ * The word 'cryptographic' can be left out if the rouines from the library
-+ * being used are not cryptographic related :-).
-+ * 4. If you include any Windows specific code (or a derivative thereof) from
-+ * the apps directory (application code) you must include an acknowledgement:
-+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``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 OR CONTRIBUTORS 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.
-+ *
-+ * The licence and distribution terms for any publically available version or
-+ * derivative of this code cannot be changed. i.e. this code cannot simply be
-+ * copied and put under another distribution licence
-+ * [including the GNU Public Licence.]
-+ */
-+
-+#include "des_locl.h"
-+#include "spr.h"
-+
-+char *libdes_version="libdes v 3.24 - 20-Apr-1996 - eay";
-+char *DES_version="DES part of SSLeay 0.8.2b 08-Jan-1998";
-+
-+/* RCSID $Id: ecb_enc.c,v 1.6 2002/04/24 07:36:38 mcr Exp $ */
-+/* This function ifdef'ed out for FreeS/WAN project. */
-+#ifdef notdef
-+char *des_options()
-+ {
-+ static int init=1;
-+ static char buf[32];
-+
-+ if (init)
-+ {
-+ char *ptr,*unroll,*risc,*size;
-+
-+ init=0;
-+#ifdef DES_PTR
-+ ptr="ptr";
-+#else
-+ ptr="idx";
-+#endif
-+#if defined(DES_RISC1) || defined(DES_RISC2)
-+#ifdef DES_RISC1
-+ risc="risc1";
-+#endif
-+#ifdef DES_RISC2
-+ risc="risc2";
-+#endif
-+#else
-+ risc="cisc";
-+#endif
-+#ifdef DES_UNROLL
-+ unroll="16";
-+#else
-+ unroll="4";
-+#endif
-+ if (sizeof(DES_LONG) != sizeof(long))
-+ size="int";
-+ else
-+ size="long";
-+ sprintf(buf,"des(%s,%s,%s,%s)",ptr,risc,unroll,size);
-+ }
-+ return(buf);
-+ }
-+#endif
-+
-+
-+void des_ecb_encrypt(input, output, ks, enc)
-+des_cblock (*input);
-+des_cblock (*output);
-+des_key_schedule ks;
-+int enc;
-+ {
-+ register DES_LONG l;
-+ register unsigned char *in,*out;
-+ DES_LONG ll[2];
-+
-+ in=(unsigned char *)input;
-+ out=(unsigned char *)output;
-+ c2l(in,l); ll[0]=l;
-+ c2l(in,l); ll[1]=l;
-+ des_encrypt(ll,ks,enc);
-+ l=ll[0]; l2c(l,out);
-+ l=ll[1]; l2c(l,out);
-+ l=ll[0]=ll[1]=0;
-+ }
-+
---- /dev/null Tue Mar 11 13:02:56 2003
-+++ linux/crypto/ciphers/des/fcrypt.c Mon Feb 9 13:51:03 2004
-@@ -0,0 +1,152 @@
-+/* NOCW */
-+
-+/* This version of crypt has been developed from my MIT compatable
-+ * DES library.
-+ * The library is available at pub/Crypto/DES at ftp.psy.uq.oz.au
-+ * Eric Young (eay@cryptsoft.com)
-+ */
-+
-+/* Modification by Jens Kupferschmidt (Cu)
-+ * I have included directive PARA for shared memory computers.
-+ * I have included a directive LONGCRYPT to using this routine to cipher
-+ * passwords with more then 8 bytes like HP-UX 10.x it used. The MAXPLEN
-+ * definition is the maximum of lenght of password and can changed. I have
-+ * defined 24.
-+ */
-+
-+#include "des_locl.h"
-+
-+/* Added more values to handle illegal salt values the way normal
-+ * crypt() implementations do. The patch was sent by
-+ * Bjorn Gronvall <bg@sics.se>
-+ */
-+static unsigned const char con_salt[128]={
-+0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,
-+0xDA,0xDB,0xDC,0xDD,0xDE,0xDF,0xE0,0xE1,
-+0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,
-+0xEA,0xEB,0xEC,0xED,0xEE,0xEF,0xF0,0xF1,
-+0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,
-+0xFA,0xFB,0xFC,0xFD,0xFE,0xFF,0x00,0x01,
-+0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,
-+0x0A,0x0B,0x05,0x06,0x07,0x08,0x09,0x0A,
-+0x0B,0x0C,0x0D,0x0E,0x0F,0x10,0x11,0x12,
-+0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,
-+0x1B,0x1C,0x1D,0x1E,0x1F,0x20,0x21,0x22,
-+0x23,0x24,0x25,0x20,0x21,0x22,0x23,0x24,
-+0x25,0x26,0x27,0x28,0x29,0x2A,0x2B,0x2C,
-+0x2D,0x2E,0x2F,0x30,0x31,0x32,0x33,0x34,
-+0x35,0x36,0x37,0x38,0x39,0x3A,0x3B,0x3C,
-+0x3D,0x3E,0x3F,0x40,0x41,0x42,0x43,0x44,
-+};
-+
-+static unsigned const char cov_2char[64]={
-+0x2E,0x2F,0x30,0x31,0x32,0x33,0x34,0x35,
-+0x36,0x37,0x38,0x39,0x41,0x42,0x43,0x44,
-+0x45,0x46,0x47,0x48,0x49,0x4A,0x4B,0x4C,
-+0x4D,0x4E,0x4F,0x50,0x51,0x52,0x53,0x54,
-+0x55,0x56,0x57,0x58,0x59,0x5A,0x61,0x62,
-+0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6A,
-+0x6B,0x6C,0x6D,0x6E,0x6F,0x70,0x71,0x72,
-+0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7A
-+};
-+
-+#ifndef NOPROTO
-+void fcrypt_body(DES_LONG *out,des_key_schedule ks,
-+ DES_LONG Eswap0, DES_LONG Eswap1);
-+
-+#ifdef PERL5
-+char *des_crypt(const char *buf,const char *salt);
-+#else
-+char *crypt(const char *buf,const char *salt);
-+#endif
-+#else
-+void fcrypt_body();
-+#ifdef PERL5
-+char *des_crypt();
-+#else
-+char *crypt();
-+#endif
-+#endif
-+
-+#ifdef PERL5
-+char *des_crypt(buf,salt)
-+#else
-+char *crypt(buf,salt)
-+#endif
-+const char *buf;
-+const char *salt;
-+ {
-+ static char buff[14];
-+
-+ return(des_fcrypt(buf,salt,buff));
-+ }
-+
-+
-+char *des_fcrypt(buf,salt,ret)
-+const char *buf;
-+const char *salt;
-+char *ret;
-+ {
-+ unsigned int i,j,x,y;
-+ DES_LONG Eswap0,Eswap1;
-+ DES_LONG out[2],ll;
-+ des_cblock key;
-+ des_key_schedule ks;
-+ unsigned char bb[9];
-+ unsigned char *b=bb;
-+ unsigned char c,u;
-+
-+ /* eay 25/08/92
-+ * If you call crypt("pwd","*") as often happens when you
-+ * have * as the pwd field in /etc/passwd, the function
-+ * returns *\0XXXXXXXXX
-+ * The \0 makes the string look like * so the pwd "*" would
-+ * crypt to "*". This was found when replacing the crypt in
-+ * our shared libraries. People found that the disbled
-+ * accounts effectivly had no passwd :-(. */
-+ x=ret[0]=((salt[0] == '\0')?'A':salt[0]);
-+ Eswap0=con_salt[x]<<2;
-+ x=ret[1]=((salt[1] == '\0')?'A':salt[1]);
-+ Eswap1=con_salt[x]<<6;
-+
-+/* EAY
-+r=strlen(buf);
-+r=(r+7)/8;
-+*/
-+ for (i=0; i<8; i++)
-+ {
-+ c= *(buf++);
-+ if (!c) break;
-+ key[i]=(c<<1);
-+ }
-+ for (; i<8; i++)
-+ key[i]=0;
-+
-+ des_set_key((des_cblock *)(key),ks);
-+ fcrypt_body(&(out[0]),ks,Eswap0,Eswap1);
-+
-+ ll=out[0]; l2c(ll,b);
-+ ll=out[1]; l2c(ll,b);
-+ y=0;
-+ u=0x80;
-+ bb[8]=0;
-+ for (i=2; i<13; i++)
-+ {
-+ c=0;
-+ for (j=0; j<6; j++)
-+ {
-+ c<<=1;
-+ if (bb[y] & u) c|=1;
-+ u>>=1;
-+ if (!u)
-+ {
-+ y++;
-+ u=0x80;
-+ }
-+ }
-+ ret[i]=cov_2char[c];
-+ }
-+ ret[13]='\0';
-+ return(ret);
-+ }
-+
---- /dev/null Tue Mar 11 13:02:56 2003
-+++ linux/crypto/ciphers/des/fcrypt_b.c Mon Feb 9 13:51:03 2004
-@@ -0,0 +1,148 @@
-+/* crypto/des/fcrypt_b.c */
-+/* Copyright (C) 1995-1997 Eric Young (eay@cryptsoft.com)
-+ * All rights reserved.
-+ *
-+ * This package is an SSL implementation written
-+ * by Eric Young (eay@cryptsoft.com).
-+ * The implementation was written so as to conform with Netscapes SSL.
-+ *
-+ * This library is free for commercial and non-commercial use as long as
-+ * the following conditions are aheared to. The following conditions
-+ * apply to all code found in this distribution, be it the RC4, RSA,
-+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
-+ * included with this distribution is covered by the same copyright terms
-+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
-+ *
-+ * Copyright remains Eric Young's, and as such any Copyright notices in
-+ * the code are not to be removed.
-+ * If this package is used in a product, Eric Young should be given attribution
-+ * as the author of the parts of the library used.
-+ * This can be in the form of a textual message at program startup or
-+ * in documentation (online or textual) provided with the package.
-+ *
-+ * Redistribution and use in source and binary forms, with or without
-+ * modification, are permitted provided that the following conditions
-+ * are met:
-+ * 1. Redistributions of source code must retain the copyright
-+ * notice, this list of conditions and the following disclaimer.
-+ * 2. Redistributions in binary form must reproduce the above copyright
-+ * notice, this list of conditions and the following disclaimer in the
-+ * documentation and/or other materials provided with the distribution.
-+ * 3. All advertising materials mentioning features or use of this software
-+ * must display the following acknowledgement:
-+ * "This product includes cryptographic software written by
-+ * Eric Young (eay@cryptsoft.com)"
-+ * The word 'cryptographic' can be left out if the rouines from the library
-+ * being used are not cryptographic related :-).
-+ * 4. If you include any Windows specific code (or a derivative thereof) from
-+ * the apps directory (application code) you must include an acknowledgement:
-+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``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 OR CONTRIBUTORS 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.
-+ *
-+ * The licence and distribution terms for any publically available version or
-+ * derivative of this code cannot be changed. i.e. this code cannot simply be
-+ * copied and put under another distribution licence
-+ * [including the GNU Public Licence.]
-+ */
-+
-+/* #include <stdio.h> */
-+
-+/* This version of crypt has been developed from my MIT compatable
-+ * DES library.
-+ * The library is available at pub/Crypto/DES at ftp.psy.uq.oz.au
-+ * Eric Young (eay@cryptsoft.com)
-+ */
-+
-+#define DES_FCRYPT
-+#include "des_locl.h"
-+#undef DES_FCRYPT
-+
-+#undef PERM_OP
-+#define PERM_OP(a,b,t,n,m) ((t)=((((a)>>(n))^(b))&(m)),\
-+ (b)^=(t),\
-+ (a)^=((t)<<(n)))
-+
-+#undef HPERM_OP
-+#define HPERM_OP(a,t,n,m) ((t)=((((a)<<(16-(n)))^(a))&(m)),\
-+ (a)=(a)^(t)^(t>>(16-(n))))\
-+
-+void fcrypt_body(out, ks, Eswap0, Eswap1)
-+DES_LONG *out;
-+des_key_schedule ks;
-+DES_LONG Eswap0;
-+DES_LONG Eswap1;
-+ {
-+ register DES_LONG l,r,t,u;
-+#ifdef DES_PTR
-+ register unsigned char *des_SP=(unsigned char *)des_SPtrans;
-+#endif
-+ register DES_LONG *s;
-+ register int j;
-+ register DES_LONG E0,E1;
-+
-+ l=0;
-+ r=0;
-+
-+ s=(DES_LONG *)ks;
-+ E0=Eswap0;
-+ E1=Eswap1;
-+
-+ for (j=0; j<25; j++)
-+ {
-+#ifdef DES_UNROLL
-+ register int i;
-+
-+ for (i=0; i<32; i+=8)
-+ {
-+ D_ENCRYPT(l,r,i+0); /* 1 */
-+ D_ENCRYPT(r,l,i+2); /* 2 */
-+ D_ENCRYPT(l,r,i+4); /* 1 */
-+ D_ENCRYPT(r,l,i+6); /* 2 */
-+ }
-+#else
-+ D_ENCRYPT(l,r, 0); /* 1 */
-+ D_ENCRYPT(r,l, 2); /* 2 */
-+ D_ENCRYPT(l,r, 4); /* 3 */
-+ D_ENCRYPT(r,l, 6); /* 4 */
-+ D_ENCRYPT(l,r, 8); /* 5 */
-+ D_ENCRYPT(r,l,10); /* 6 */
-+ D_ENCRYPT(l,r,12); /* 7 */
-+ D_ENCRYPT(r,l,14); /* 8 */
-+ D_ENCRYPT(l,r,16); /* 9 */
-+ D_ENCRYPT(r,l,18); /* 10 */
-+ D_ENCRYPT(l,r,20); /* 11 */
-+ D_ENCRYPT(r,l,22); /* 12 */
-+ D_ENCRYPT(l,r,24); /* 13 */
-+ D_ENCRYPT(r,l,26); /* 14 */
-+ D_ENCRYPT(l,r,28); /* 15 */
-+ D_ENCRYPT(r,l,30); /* 16 */
-+#endif
-+
-+ t=l;
-+ l=r;
-+ r=t;
-+ }
-+ l=ROTATE(l,3)&0xffffffffL;
-+ r=ROTATE(r,3)&0xffffffffL;
-+
-+ PERM_OP(l,r,t, 1,0x55555555L);
-+ PERM_OP(r,l,t, 8,0x00ff00ffL);
-+ PERM_OP(l,r,t, 2,0x33333333L);
-+ PERM_OP(r,l,t,16,0x0000ffffL);
-+ PERM_OP(l,r,t, 4,0x0f0f0f0fL);
-+
-+ out[0]=r;
-+ out[1]=l;
-+ }
-+
---- /dev/null Tue Mar 11 13:02:56 2003
-+++ linux/crypto/ciphers/des/options.txt Mon Feb 9 13:51:03 2004
-@@ -0,0 +1,39 @@
-+Note that the UNROLL option makes the 'inner' des loop unroll all 16 rounds
-+instead of the default 4.
-+RISC1 and RISC2 are 2 alternatives for the inner loop and
-+PTR means to use pointers arithmatic instead of arrays.
-+
-+FreeBSD - Pentium Pro 200mhz - gcc 2.7.2.2 - assembler 577,000 4620k/s
-+IRIX 6.2 - R10000 195mhz - cc (-O3 -n32) - UNROLL RISC2 PTR 496,000 3968k/s
-+solaris 2.5.1 usparc 167mhz?? - SC4.0 - UNROLL RISC1 PTR [1] 459,400 3672k/s
-+FreeBSD - Pentium Pro 200mhz - gcc 2.7.2.2 - UNROLL RISC1 433,000 3468k/s
-+solaris 2.5.1 usparc 167mhz?? - gcc 2.7.2 - UNROLL 380,000 3041k/s
-+linux - pentium 100mhz - gcc 2.7.0 - assembler 281,000 2250k/s
-+NT 4.0 - pentium 100mhz - VC 4.2 - assembler 281,000 2250k/s
-+AIX 4.1? - PPC604 100mhz - cc - UNROLL 275,000 2200k/s
-+IRIX 5.3 - R4400 200mhz - gcc 2.6.3 - UNROLL RISC2 PTR 235,300 1882k/s
-+IRIX 5.3 - R4400 200mhz - cc - UNROLL RISC2 PTR 233,700 1869k/s
-+NT 4.0 - pentium 100mhz - VC 4.2 - UNROLL RISC1 PTR 191,000 1528k/s
-+DEC Alpha 165mhz?? - cc - RISC2 PTR [2] 181,000 1448k/s
-+linux - pentium 100mhz - gcc 2.7.0 - UNROLL RISC1 PTR 158,500 1268k/s
-+HPUX 10 - 9000/887 - cc - UNROLL [3] 148,000 1190k/s
-+solaris 2.5.1 - sparc 10 50mhz - gcc 2.7.2 - UNROLL 123,600 989k/s
-+IRIX 5.3 - R4000 100mhz - cc - UNROLL RISC2 PTR 101,000 808k/s
-+DGUX - 88100 50mhz(?) - gcc 2.6.3 - UNROLL 81,000 648k/s
-+solaris 2.4 486 50mhz - gcc 2.6.3 - assembler 65,000 522k/s
-+HPUX 10 - 9000/887 - k&r cc (default compiler) - UNROLL PTR 76,000 608k/s
-+solaris 2.4 486 50mhz - gcc 2.6.3 - UNROLL RISC2 43,500 344k/s
-+AIX - old slow one :-) - cc - 39,000 312k/s
-+
-+Notes.
-+[1] For the ultra sparc, SunC 4.0
-+ cc -xtarget=ultra -xarch=v8plus -Xa -xO5, running 'des_opts'
-+ gives a speed of 344,000 des/s while 'speed' gives 459,000 des/s.
-+ I'll record the higher since it is coming from the library but it
-+ is all rather weird.
-+[2] Similar to the ultra sparc ([1]), 181,000 for 'des_opts' vs 175,000.
-+[3] I was unable to get access to this machine when it was not heavily loaded.
-+ As such, my timing program was never able to get more that %30 of the CPU.
-+ This would cause the program to give much lower speed numbers because
-+ it would be 'fighting' to stay in the cache with the other CPU burning
-+ processes.
---- /dev/null Tue Mar 11 13:02:56 2003
-+++ linux/crypto/ciphers/des/podd.h Mon Feb 9 13:51:03 2004
-@@ -0,0 +1,75 @@
-+/* crypto/des/podd.h */
-+/* Copyright (C) 1995-1997 Eric Young (eay@cryptsoft.com)
-+ * All rights reserved.
-+ *
-+ * This package is an SSL implementation written
-+ * by Eric Young (eay@cryptsoft.com).
-+ * The implementation was written so as to conform with Netscapes SSL.
-+ *
-+ * This library is free for commercial and non-commercial use as long as
-+ * the following conditions are aheared to. The following conditions
-+ * apply to all code found in this distribution, be it the RC4, RSA,
-+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
-+ * included with this distribution is covered by the same copyright terms
-+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
-+ *
-+ * Copyright remains Eric Young's, and as such any Copyright notices in
-+ * the code are not to be removed.
-+ * If this package is used in a product, Eric Young should be given attribution
-+ * as the author of the parts of the library used.
-+ * This can be in the form of a textual message at program startup or
-+ * in documentation (online or textual) provided with the package.
-+ *
-+ * Redistribution and use in source and binary forms, with or without
-+ * modification, are permitted provided that the following conditions
-+ * are met:
-+ * 1. Redistributions of source code must retain the copyright
-+ * notice, this list of conditions and the following disclaimer.
-+ * 2. Redistributions in binary form must reproduce the above copyright
-+ * notice, this list of conditions and the following disclaimer in the
-+ * documentation and/or other materials provided with the distribution.
-+ * 3. All advertising materials mentioning features or use of this software
-+ * must display the following acknowledgement:
-+ * "This product includes cryptographic software written by
-+ * Eric Young (eay@cryptsoft.com)"
-+ * The word 'cryptographic' can be left out if the rouines from the library
-+ * being used are not cryptographic related :-).
-+ * 4. If you include any Windows specific code (or a derivative thereof) from
-+ * the apps directory (application code) you must include an acknowledgement:
-+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``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 OR CONTRIBUTORS 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.
-+ *
-+ * The licence and distribution terms for any publically available version or
-+ * derivative of this code cannot be changed. i.e. this code cannot simply be
-+ * copied and put under another distribution licence
-+ * [including the GNU Public Licence.]
-+ */
-+
-+static const unsigned char odd_parity[256]={
-+ 1, 1, 2, 2, 4, 4, 7, 7, 8, 8, 11, 11, 13, 13, 14, 14,
-+ 16, 16, 19, 19, 21, 21, 22, 22, 25, 25, 26, 26, 28, 28, 31, 31,
-+ 32, 32, 35, 35, 37, 37, 38, 38, 41, 41, 42, 42, 44, 44, 47, 47,
-+ 49, 49, 50, 50, 52, 52, 55, 55, 56, 56, 59, 59, 61, 61, 62, 62,
-+ 64, 64, 67, 67, 69, 69, 70, 70, 73, 73, 74, 74, 76, 76, 79, 79,
-+ 81, 81, 82, 82, 84, 84, 87, 87, 88, 88, 91, 91, 93, 93, 94, 94,
-+ 97, 97, 98, 98,100,100,103,103,104,104,107,107,109,109,110,110,
-+112,112,115,115,117,117,118,118,121,121,122,122,124,124,127,127,
-+128,128,131,131,133,133,134,134,137,137,138,138,140,140,143,143,
-+145,145,146,146,148,148,151,151,152,152,155,155,157,157,158,158,
-+161,161,162,162,164,164,167,167,168,168,171,171,173,173,174,174,
-+176,176,179,179,181,181,182,182,185,185,186,186,188,188,191,191,
-+193,193,194,194,196,196,199,199,200,200,203,203,205,205,206,206,
-+208,208,211,211,213,213,214,214,217,217,218,218,220,220,223,223,
-+224,224,227,227,229,229,230,230,233,233,234,234,236,236,239,239,
-+241,241,242,242,244,244,247,247,248,248,251,251,253,253,254,254};
---- /dev/null Tue Mar 11 13:02:56 2003
-+++ linux/crypto/ciphers/des/set_key.c Mon Feb 9 13:51:03 2004
-@@ -0,0 +1,246 @@
-+/* crypto/des/set_key.c */
-+/* Copyright (C) 1995-1997 Eric Young (eay@cryptsoft.com)
-+ * All rights reserved.
-+ *
-+ * This package is an SSL implementation written
-+ * by Eric Young (eay@cryptsoft.com).
-+ * The implementation was written so as to conform with Netscapes SSL.
-+ *
-+ * This library is free for commercial and non-commercial use as long as
-+ * the following conditions are aheared to. The following conditions
-+ * apply to all code found in this distribution, be it the RC4, RSA,
-+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
-+ * included with this distribution is covered by the same copyright terms
-+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
-+ *
-+ * Copyright remains Eric Young's, and as such any Copyright notices in
-+ * the code are not to be removed.
-+ * If this package is used in a product, Eric Young should be given attribution
-+ * as the author of the parts of the library used.
-+ * This can be in the form of a textual message at program startup or
-+ * in documentation (online or textual) provided with the package.
-+ *
-+ * Redistribution and use in source and binary forms, with or without
-+ * modification, are permitted provided that the following conditions
-+ * are met:
-+ * 1. Redistributions of source code must retain the copyright
-+ * notice, this list of conditions and the following disclaimer.
-+ * 2. Redistributions in binary form must reproduce the above copyright
-+ * notice, this list of conditions and the following disclaimer in the
-+ * documentation and/or other materials provided with the distribution.
-+ * 3. All advertising materials mentioning features or use of this software
-+ * must display the following acknowledgement:
-+ * "This product includes cryptographic software written by
-+ * Eric Young (eay@cryptsoft.com)"
-+ * The word 'cryptographic' can be left out if the rouines from the library
-+ * being used are not cryptographic related :-).
-+ * 4. If you include any Windows specific code (or a derivative thereof) from
-+ * the apps directory (application code) you must include an acknowledgement:
-+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``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 OR CONTRIBUTORS 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.
-+ *
-+ * The licence and distribution terms for any publically available version or
-+ * derivative of this code cannot be changed. i.e. this code cannot simply be
-+ * copied and put under another distribution licence
-+ * [including the GNU Public Licence.]
-+ */
-+
-+/* set_key.c v 1.4 eay 24/9/91
-+ * 1.4 Speed up by 400% :-)
-+ * 1.3 added register declarations.
-+ * 1.2 unrolled make_key_sched a bit more
-+ * 1.1 added norm_expand_bits
-+ * 1.0 First working version
-+ */
-+#include "des_locl.h"
-+#include "podd.h"
-+#include "sk.h"
-+
-+#ifndef NOPROTO
-+static int check_parity(des_cblock (*key));
-+#else
-+static int check_parity();
-+#endif
-+
-+int des_check_key=0;
-+
-+void des_set_odd_parity(key)
-+des_cblock (*key);
-+ {
-+ int i;
-+
-+ for (i=0; i<DES_KEY_SZ; i++)
-+ (*key)[i]=odd_parity[(*key)[i]];
-+ }
-+
-+static int check_parity(key)
-+des_cblock (*key);
-+ {
-+ int i;
-+
-+ for (i=0; i<DES_KEY_SZ; i++)
-+ {
-+ if ((*key)[i] != odd_parity[(*key)[i]])
-+ return(0);
-+ }
-+ return(1);
-+ }
-+
-+/* Weak and semi week keys as take from
-+ * %A D.W. Davies
-+ * %A W.L. Price
-+ * %T Security for Computer Networks
-+ * %I John Wiley & Sons
-+ * %D 1984
-+ * Many thanks to smb@ulysses.att.com (Steven Bellovin) for the reference
-+ * (and actual cblock values).
-+ */
-+#define NUM_WEAK_KEY 16
-+static des_cblock weak_keys[NUM_WEAK_KEY]={
-+ /* weak keys */
-+ {0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01},
-+ {0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE},
-+ {0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F},
-+ {0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0},
-+ /* semi-weak keys */
-+ {0x01,0xFE,0x01,0xFE,0x01,0xFE,0x01,0xFE},
-+ {0xFE,0x01,0xFE,0x01,0xFE,0x01,0xFE,0x01},
-+ {0x1F,0xE0,0x1F,0xE0,0x0E,0xF1,0x0E,0xF1},
-+ {0xE0,0x1F,0xE0,0x1F,0xF1,0x0E,0xF1,0x0E},
-+ {0x01,0xE0,0x01,0xE0,0x01,0xF1,0x01,0xF1},
-+ {0xE0,0x01,0xE0,0x01,0xF1,0x01,0xF1,0x01},
-+ {0x1F,0xFE,0x1F,0xFE,0x0E,0xFE,0x0E,0xFE},
-+ {0xFE,0x1F,0xFE,0x1F,0xFE,0x0E,0xFE,0x0E},
-+ {0x01,0x1F,0x01,0x1F,0x01,0x0E,0x01,0x0E},
-+ {0x1F,0x01,0x1F,0x01,0x0E,0x01,0x0E,0x01},
-+ {0xE0,0xFE,0xE0,0xFE,0xF1,0xFE,0xF1,0xFE},
-+ {0xFE,0xE0,0xFE,0xE0,0xFE,0xF1,0xFE,0xF1}};
-+
-+int des_is_weak_key(key)
-+des_cblock (*key);
-+ {
-+ int i;
-+
-+ for (i=0; i<NUM_WEAK_KEY; i++)
-+ /* Added == 0 to comparision, I obviously don't run
-+ * this section very often :-(, thanks to
-+ * engineering@MorningStar.Com for the fix
-+ * eay 93/06/29
-+ * Another problem, I was comparing only the first 4
-+ * bytes, 97/03/18 */
-+ if (memcmp(weak_keys[i],key,sizeof(des_cblock)) == 0) return(1);
-+ return(0);
-+ }
-+
-+/* NOW DEFINED IN des_local.h
-+ * See ecb_encrypt.c for a pseudo description of these macros.
-+ * #define PERM_OP(a,b,t,n,m) ((t)=((((a)>>(n))^(b))&(m)),\
-+ * (b)^=(t),\
-+ * (a)=((a)^((t)<<(n))))
-+ */
-+
-+#define HPERM_OP(a,t,n,m) ((t)=((((a)<<(16-(n)))^(a))&(m)),\
-+ (a)=(a)^(t)^(t>>(16-(n))))
-+
-+/* return 0 if key parity is odd (correct),
-+ * return -1 if key parity error,
-+ * return -2 if illegal weak key.
-+ */
-+int des_set_key(key, schedule)
-+des_cblock (*key);
-+des_key_schedule schedule;
-+ {
-+ static int shifts2[16]={0,0,1,1,1,1,1,1,0,1,1,1,1,1,1,0};
-+ register DES_LONG c,d,t,s,t2;
-+ register unsigned char *in;
-+ register DES_LONG *k;
-+ register int i;
-+
-+ if (des_check_key)
-+ {
-+ if (!check_parity(key))
-+ return(-1);
-+
-+ if (des_is_weak_key(key))
-+ return(-2);
-+ }
-+
-+ k=(DES_LONG *)schedule;
-+ in=(unsigned char *)key;
-+
-+ c2l(in,c);
-+ c2l(in,d);
-+
-+ /* do PC1 in 60 simple operations */
-+/* PERM_OP(d,c,t,4,0x0f0f0f0fL);
-+ HPERM_OP(c,t,-2, 0xcccc0000L);
-+ HPERM_OP(c,t,-1, 0xaaaa0000L);
-+ HPERM_OP(c,t, 8, 0x00ff0000L);
-+ HPERM_OP(c,t,-1, 0xaaaa0000L);
-+ HPERM_OP(d,t,-8, 0xff000000L);
-+ HPERM_OP(d,t, 8, 0x00ff0000L);
-+ HPERM_OP(d,t, 2, 0x33330000L);
-+ d=((d&0x00aa00aaL)<<7L)|((d&0x55005500L)>>7L)|(d&0xaa55aa55L);
-+ d=(d>>8)|((c&0xf0000000L)>>4);
-+ c&=0x0fffffffL; */
-+
-+ /* I now do it in 47 simple operations :-)
-+ * Thanks to John Fletcher (john_fletcher@lccmail.ocf.llnl.gov)
-+ * for the inspiration. :-) */
-+ PERM_OP (d,c,t,4,0x0f0f0f0fL);
-+ HPERM_OP(c,t,-2,0xcccc0000L);
-+ HPERM_OP(d,t,-2,0xcccc0000L);
-+ PERM_OP (d,c,t,1,0x55555555L);
-+ PERM_OP (c,d,t,8,0x00ff00ffL);
-+ PERM_OP (d,c,t,1,0x55555555L);
-+ d= (((d&0x000000ffL)<<16L)| (d&0x0000ff00L) |
-+ ((d&0x00ff0000L)>>16L)|((c&0xf0000000L)>>4L));
-+ c&=0x0fffffffL;
-+
-+ for (i=0; i<ITERATIONS; i++)
-+ {
-+ if (shifts2[i])
-+ { c=((c>>2L)|(c<<26L)); d=((d>>2L)|(d<<26L)); }
-+ else
-+ { c=((c>>1L)|(c<<27L)); d=((d>>1L)|(d<<27L)); }
-+ c&=0x0fffffffL;
-+ d&=0x0fffffffL;
-+ /* could be a few less shifts but I am to lazy at this
-+ * point in time to investigate */
-+ s= des_skb[0][ (c )&0x3f ]|
-+ des_skb[1][((c>> 6)&0x03)|((c>> 7L)&0x3c)]|
-+ des_skb[2][((c>>13)&0x0f)|((c>>14L)&0x30)]|
-+ des_skb[3][((c>>20)&0x01)|((c>>21L)&0x06) |
-+ ((c>>22L)&0x38)];
-+ t= des_skb[4][ (d )&0x3f ]|
-+ des_skb[5][((d>> 7L)&0x03)|((d>> 8L)&0x3c)]|
-+ des_skb[6][ (d>>15L)&0x3f ]|
-+ des_skb[7][((d>>21L)&0x0f)|((d>>22L)&0x30)];
-+
-+ /* table contained 0213 4657 */
-+ t2=((t<<16L)|(s&0x0000ffffL))&0xffffffffL;
-+ *(k++)=ROTATE(t2,30)&0xffffffffL;
-+
-+ t2=((s>>16L)|(t&0xffff0000L));
-+ *(k++)=ROTATE(t2,26)&0xffffffffL;
-+ }
-+ return(0);
-+ }
-+
-+int des_key_sched(key, schedule)
-+des_cblock (*key);
-+des_key_schedule schedule;
-+ {
-+ return(des_set_key(key,schedule));
-+ }
---- /dev/null Tue Mar 11 13:02:56 2003
-+++ linux/crypto/ciphers/des/sk.h Mon Feb 9 13:51:03 2004
-@@ -0,0 +1,204 @@
-+/* crypto/des/sk.h */
-+/* Copyright (C) 1995-1997 Eric Young (eay@cryptsoft.com)
-+ * All rights reserved.
-+ *
-+ * This package is an SSL implementation written
-+ * by Eric Young (eay@cryptsoft.com).
-+ * The implementation was written so as to conform with Netscapes SSL.
-+ *
-+ * This library is free for commercial and non-commercial use as long as
-+ * the following conditions are aheared to. The following conditions
-+ * apply to all code found in this distribution, be it the RC4, RSA,
-+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
-+ * included with this distribution is covered by the same copyright terms
-+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
-+ *
-+ * Copyright remains Eric Young's, and as such any Copyright notices in
-+ * the code are not to be removed.
-+ * If this package is used in a product, Eric Young should be given attribution
-+ * as the author of the parts of the library used.
-+ * This can be in the form of a textual message at program startup or
-+ * in documentation (online or textual) provided with the package.
-+ *
-+ * Redistribution and use in source and binary forms, with or without
-+ * modification, are permitted provided that the following conditions
-+ * are met:
-+ * 1. Redistributions of source code must retain the copyright
-+ * notice, this list of conditions and the following disclaimer.
-+ * 2. Redistributions in binary form must reproduce the above copyright
-+ * notice, this list of conditions and the following disclaimer in the
-+ * documentation and/or other materials provided with the distribution.
-+ * 3. All advertising materials mentioning features or use of this software
-+ * must display the following acknowledgement:
-+ * "This product includes cryptographic software written by
-+ * Eric Young (eay@cryptsoft.com)"
-+ * The word 'cryptographic' can be left out if the rouines from the library
-+ * being used are not cryptographic related :-).
-+ * 4. If you include any Windows specific code (or a derivative thereof) from
-+ * the apps directory (application code) you must include an acknowledgement:
-+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``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 OR CONTRIBUTORS 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.
-+ *
-+ * The licence and distribution terms for any publically available version or
-+ * derivative of this code cannot be changed. i.e. this code cannot simply be
-+ * copied and put under another distribution licence
-+ * [including the GNU Public Licence.]
-+ */
-+
-+static const DES_LONG des_skb[8][64]={
-+{
-+/* for C bits (numbered as per FIPS 46) 1 2 3 4 5 6 */
-+0x00000000L,0x00000010L,0x20000000L,0x20000010L,
-+0x00010000L,0x00010010L,0x20010000L,0x20010010L,
-+0x00000800L,0x00000810L,0x20000800L,0x20000810L,
-+0x00010800L,0x00010810L,0x20010800L,0x20010810L,
-+0x00000020L,0x00000030L,0x20000020L,0x20000030L,
-+0x00010020L,0x00010030L,0x20010020L,0x20010030L,
-+0x00000820L,0x00000830L,0x20000820L,0x20000830L,
-+0x00010820L,0x00010830L,0x20010820L,0x20010830L,
-+0x00080000L,0x00080010L,0x20080000L,0x20080010L,
-+0x00090000L,0x00090010L,0x20090000L,0x20090010L,
-+0x00080800L,0x00080810L,0x20080800L,0x20080810L,
-+0x00090800L,0x00090810L,0x20090800L,0x20090810L,
-+0x00080020L,0x00080030L,0x20080020L,0x20080030L,
-+0x00090020L,0x00090030L,0x20090020L,0x20090030L,
-+0x00080820L,0x00080830L,0x20080820L,0x20080830L,
-+0x00090820L,0x00090830L,0x20090820L,0x20090830L,
-+},{
-+/* for C bits (numbered as per FIPS 46) 7 8 10 11 12 13 */
-+0x00000000L,0x02000000L,0x00002000L,0x02002000L,
-+0x00200000L,0x02200000L,0x00202000L,0x02202000L,
-+0x00000004L,0x02000004L,0x00002004L,0x02002004L,
-+0x00200004L,0x02200004L,0x00202004L,0x02202004L,
-+0x00000400L,0x02000400L,0x00002400L,0x02002400L,
-+0x00200400L,0x02200400L,0x00202400L,0x02202400L,
-+0x00000404L,0x02000404L,0x00002404L,0x02002404L,
-+0x00200404L,0x02200404L,0x00202404L,0x02202404L,
-+0x10000000L,0x12000000L,0x10002000L,0x12002000L,
-+0x10200000L,0x12200000L,0x10202000L,0x12202000L,
-+0x10000004L,0x12000004L,0x10002004L,0x12002004L,
-+0x10200004L,0x12200004L,0x10202004L,0x12202004L,
-+0x10000400L,0x12000400L,0x10002400L,0x12002400L,
-+0x10200400L,0x12200400L,0x10202400L,0x12202400L,
-+0x10000404L,0x12000404L,0x10002404L,0x12002404L,
-+0x10200404L,0x12200404L,0x10202404L,0x12202404L,
-+},{
-+/* for C bits (numbered as per FIPS 46) 14 15 16 17 19 20 */
-+0x00000000L,0x00000001L,0x00040000L,0x00040001L,
-+0x01000000L,0x01000001L,0x01040000L,0x01040001L,
-+0x00000002L,0x00000003L,0x00040002L,0x00040003L,
-+0x01000002L,0x01000003L,0x01040002L,0x01040003L,
-+0x00000200L,0x00000201L,0x00040200L,0x00040201L,
-+0x01000200L,0x01000201L,0x01040200L,0x01040201L,
-+0x00000202L,0x00000203L,0x00040202L,0x00040203L,
-+0x01000202L,0x01000203L,0x01040202L,0x01040203L,
-+0x08000000L,0x08000001L,0x08040000L,0x08040001L,
-+0x09000000L,0x09000001L,0x09040000L,0x09040001L,
-+0x08000002L,0x08000003L,0x08040002L,0x08040003L,
-+0x09000002L,0x09000003L,0x09040002L,0x09040003L,
-+0x08000200L,0x08000201L,0x08040200L,0x08040201L,
-+0x09000200L,0x09000201L,0x09040200L,0x09040201L,
-+0x08000202L,0x08000203L,0x08040202L,0x08040203L,
-+0x09000202L,0x09000203L,0x09040202L,0x09040203L,
-+},{
-+/* for C bits (numbered as per FIPS 46) 21 23 24 26 27 28 */
-+0x00000000L,0x00100000L,0x00000100L,0x00100100L,
-+0x00000008L,0x00100008L,0x00000108L,0x00100108L,
-+0x00001000L,0x00101000L,0x00001100L,0x00101100L,
-+0x00001008L,0x00101008L,0x00001108L,0x00101108L,
-+0x04000000L,0x04100000L,0x04000100L,0x04100100L,
-+0x04000008L,0x04100008L,0x04000108L,0x04100108L,
-+0x04001000L,0x04101000L,0x04001100L,0x04101100L,
-+0x04001008L,0x04101008L,0x04001108L,0x04101108L,
-+0x00020000L,0x00120000L,0x00020100L,0x00120100L,
-+0x00020008L,0x00120008L,0x00020108L,0x00120108L,
-+0x00021000L,0x00121000L,0x00021100L,0x00121100L,
-+0x00021008L,0x00121008L,0x00021108L,0x00121108L,
-+0x04020000L,0x04120000L,0x04020100L,0x04120100L,
-+0x04020008L,0x04120008L,0x04020108L,0x04120108L,
-+0x04021000L,0x04121000L,0x04021100L,0x04121100L,
-+0x04021008L,0x04121008L,0x04021108L,0x04121108L,
-+},{
-+/* for D bits (numbered as per FIPS 46) 1 2 3 4 5 6 */
-+0x00000000L,0x10000000L,0x00010000L,0x10010000L,
-+0x00000004L,0x10000004L,0x00010004L,0x10010004L,
-+0x20000000L,0x30000000L,0x20010000L,0x30010000L,
-+0x20000004L,0x30000004L,0x20010004L,0x30010004L,
-+0x00100000L,0x10100000L,0x00110000L,0x10110000L,
-+0x00100004L,0x10100004L,0x00110004L,0x10110004L,
-+0x20100000L,0x30100000L,0x20110000L,0x30110000L,
-+0x20100004L,0x30100004L,0x20110004L,0x30110004L,
-+0x00001000L,0x10001000L,0x00011000L,0x10011000L,
-+0x00001004L,0x10001004L,0x00011004L,0x10011004L,
-+0x20001000L,0x30001000L,0x20011000L,0x30011000L,
-+0x20001004L,0x30001004L,0x20011004L,0x30011004L,
-+0x00101000L,0x10101000L,0x00111000L,0x10111000L,
-+0x00101004L,0x10101004L,0x00111004L,0x10111004L,
-+0x20101000L,0x30101000L,0x20111000L,0x30111000L,
-+0x20101004L,0x30101004L,0x20111004L,0x30111004L,
-+},{
-+/* for D bits (numbered as per FIPS 46) 8 9 11 12 13 14 */
-+0x00000000L,0x08000000L,0x00000008L,0x08000008L,
-+0x00000400L,0x08000400L,0x00000408L,0x08000408L,
-+0x00020000L,0x08020000L,0x00020008L,0x08020008L,
-+0x00020400L,0x08020400L,0x00020408L,0x08020408L,
-+0x00000001L,0x08000001L,0x00000009L,0x08000009L,
-+0x00000401L,0x08000401L,0x00000409L,0x08000409L,
-+0x00020001L,0x08020001L,0x00020009L,0x08020009L,
-+0x00020401L,0x08020401L,0x00020409L,0x08020409L,
-+0x02000000L,0x0A000000L,0x02000008L,0x0A000008L,
-+0x02000400L,0x0A000400L,0x02000408L,0x0A000408L,
-+0x02020000L,0x0A020000L,0x02020008L,0x0A020008L,
-+0x02020400L,0x0A020400L,0x02020408L,0x0A020408L,
-+0x02000001L,0x0A000001L,0x02000009L,0x0A000009L,
-+0x02000401L,0x0A000401L,0x02000409L,0x0A000409L,
-+0x02020001L,0x0A020001L,0x02020009L,0x0A020009L,
-+0x02020401L,0x0A020401L,0x02020409L,0x0A020409L,
-+},{
-+/* for D bits (numbered as per FIPS 46) 16 17 18 19 20 21 */
-+0x00000000L,0x00000100L,0x00080000L,0x00080100L,
-+0x01000000L,0x01000100L,0x01080000L,0x01080100L,
-+0x00000010L,0x00000110L,0x00080010L,0x00080110L,
-+0x01000010L,0x01000110L,0x01080010L,0x01080110L,
-+0x00200000L,0x00200100L,0x00280000L,0x00280100L,
-+0x01200000L,0x01200100L,0x01280000L,0x01280100L,
-+0x00200010L,0x00200110L,0x00280010L,0x00280110L,
-+0x01200010L,0x01200110L,0x01280010L,0x01280110L,
-+0x00000200L,0x00000300L,0x00080200L,0x00080300L,
-+0x01000200L,0x01000300L,0x01080200L,0x01080300L,
-+0x00000210L,0x00000310L,0x00080210L,0x00080310L,
-+0x01000210L,0x01000310L,0x01080210L,0x01080310L,
-+0x00200200L,0x00200300L,0x00280200L,0x00280300L,
-+0x01200200L,0x01200300L,0x01280200L,0x01280300L,
-+0x00200210L,0x00200310L,0x00280210L,0x00280310L,
-+0x01200210L,0x01200310L,0x01280210L,0x01280310L,
-+},{
-+/* for D bits (numbered as per FIPS 46) 22 23 24 25 27 28 */
-+0x00000000L,0x04000000L,0x00040000L,0x04040000L,
-+0x00000002L,0x04000002L,0x00040002L,0x04040002L,
-+0x00002000L,0x04002000L,0x00042000L,0x04042000L,
-+0x00002002L,0x04002002L,0x00042002L,0x04042002L,
-+0x00000020L,0x04000020L,0x00040020L,0x04040020L,
-+0x00000022L,0x04000022L,0x00040022L,0x04040022L,
-+0x00002020L,0x04002020L,0x00042020L,0x04042020L,
-+0x00002022L,0x04002022L,0x00042022L,0x04042022L,
-+0x00000800L,0x04000800L,0x00040800L,0x04040800L,
-+0x00000802L,0x04000802L,0x00040802L,0x04040802L,
-+0x00002800L,0x04002800L,0x00042800L,0x04042800L,
-+0x00002802L,0x04002802L,0x00042802L,0x04042802L,
-+0x00000820L,0x04000820L,0x00040820L,0x04040820L,
-+0x00000822L,0x04000822L,0x00040822L,0x04040822L,
-+0x00002820L,0x04002820L,0x00042820L,0x04042820L,
-+0x00002822L,0x04002822L,0x00042822L,0x04042822L,
-+}};
---- /dev/null Tue Mar 11 13:02:56 2003
-+++ linux/crypto/ciphers/des/speed.c Mon Feb 9 13:51:03 2004
-@@ -0,0 +1,329 @@
-+/* crypto/des/speed.c */
-+/* Copyright (C) 1995-1997 Eric Young (eay@cryptsoft.com)
-+ * All rights reserved.
-+ *
-+ * This package is an SSL implementation written
-+ * by Eric Young (eay@cryptsoft.com).
-+ * The implementation was written so as to conform with Netscapes SSL.
-+ *
-+ * This library is free for commercial and non-commercial use as long as
-+ * the following conditions are aheared to. The following conditions
-+ * apply to all code found in this distribution, be it the RC4, RSA,
-+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
-+ * included with this distribution is covered by the same copyright terms
-+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
-+ *
-+ * Copyright remains Eric Young's, and as such any Copyright notices in
-+ * the code are not to be removed.
-+ * If this package is used in a product, Eric Young should be given attribution
-+ * as the author of the parts of the library used.
-+ * This can be in the form of a textual message at program startup or
-+ * in documentation (online or textual) provided with the package.
-+ *
-+ * Redistribution and use in source and binary forms, with or without
-+ * modification, are permitted provided that the following conditions
-+ * are met:
-+ * 1. Redistributions of source code must retain the copyright
-+ * notice, this list of conditions and the following disclaimer.
-+ * 2. Redistributions in binary form must reproduce the above copyright
-+ * notice, this list of conditions and the following disclaimer in the
-+ * documentation and/or other materials provided with the distribution.
-+ * 3. All advertising materials mentioning features or use of this software
-+ * must display the following acknowledgement:
-+ * "This product includes cryptographic software written by
-+ * Eric Young (eay@cryptsoft.com)"
-+ * The word 'cryptographic' can be left out if the rouines from the library
-+ * being used are not cryptographic related :-).
-+ * 4. If you include any Windows specific code (or a derivative thereof) from
-+ * the apps directory (application code) you must include an acknowledgement:
-+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``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 OR CONTRIBUTORS 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.
-+ *
-+ * The licence and distribution terms for any publically available version or
-+ * derivative of this code cannot be changed. i.e. this code cannot simply be
-+ * copied and put under another distribution licence
-+ * [including the GNU Public Licence.]
-+ */
-+
-+/* 11-Sep-92 Andrew Daviel Support for Silicon Graphics IRIX added */
-+/* 06-Apr-92 Luke Brennan Support for VMS and add extra signal calls */
-+
-+#ifndef MSDOS
-+#define TIMES
-+#endif
-+
-+#include <stdio.h>
-+#ifndef MSDOS
-+#include <unistd.h>
-+#else
-+#include <io.h>
-+extern int exit();
-+#endif
-+#include <signal.h>
-+#ifndef VMS
-+#ifndef _IRIX
-+#include <time.h>
-+#endif
-+#ifdef TIMES
-+#include <sys/types.h>
-+#include <sys/times.h>
-+#endif
-+#else /* VMS */
-+#include <types.h>
-+struct tms {
-+ time_t tms_utime;
-+ time_t tms_stime;
-+ time_t tms_uchild; /* I dunno... */
-+ time_t tms_uchildsys; /* so these names are a guess :-) */
-+ }
-+#endif
-+#ifndef TIMES
-+#include <sys/timeb.h>
-+#endif
-+
-+#ifdef sun
-+#include <limits.h>
-+#include <sys/param.h>
-+#endif
-+
-+#include "des_locl.h"
-+
-+/* The following if from times(3) man page. It may need to be changed */
-+#ifndef HZ
-+# ifndef CLK_TCK
-+# ifndef _BSD_CLK_TCK_ /* FreeBSD fix */
-+# ifndef VMS
-+# define HZ 100.0
-+# else /* VMS */
-+# define HZ 100.0
-+# endif
-+# else /* _BSD_CLK_TCK_ */
-+# define HZ ((double)_BSD_CLK_TCK_)
-+# endif
-+# else /* CLK_TCK */
-+# define HZ ((double)CLK_TCK)
-+# endif
-+#endif
-+
-+#define BUFSIZE ((long)1024)
-+long run=0;
-+
-+#ifndef NOPROTO
-+double Time_F(int s);
-+#else
-+double Time_F();
-+#endif
-+
-+#ifdef SIGALRM
-+#if defined(__STDC__) || defined(sgi) || defined(_AIX)
-+#define SIGRETTYPE void
-+#else
-+#define SIGRETTYPE int
-+#endif
-+
-+#ifndef NOPROTO
-+SIGRETTYPE sig_done(int sig);
-+#else
-+SIGRETTYPE sig_done();
-+#endif
-+
-+SIGRETTYPE sig_done(sig)
-+int sig;
-+ {
-+ signal(SIGALRM,sig_done);
-+ run=0;
-+#ifdef LINT
-+ sig=sig;
-+#endif
-+ }
-+#endif
-+
-+#define START 0
-+#define STOP 1
-+
-+double Time_F(s)
-+int s;
-+ {
-+ double ret;
-+#ifdef TIMES
-+ static struct tms tstart,tend;
-+
-+ if (s == START)
-+ {
-+ times(&tstart);
-+ return(0);
-+ }
-+ else
-+ {
-+ times(&tend);
-+ ret=((double)(tend.tms_utime-tstart.tms_utime))/HZ;
-+ return((ret == 0.0)?1e-6:ret);
-+ }
-+#else /* !times() */
-+ static struct timeb tstart,tend;
-+ long i;
-+
-+ if (s == START)
-+ {
-+ ftime(&tstart);
-+ return(0);
-+ }
-+ else
-+ {
-+ ftime(&tend);
-+ i=(long)tend.millitm-(long)tstart.millitm;
-+ ret=((double)(tend.time-tstart.time))+((double)i)/1e3;
-+ return((ret == 0.0)?1e-6:ret);
-+ }
-+#endif
-+ }
-+
-+int main(argc,argv)
-+int argc;
-+char **argv;
-+ {
-+ long count;
-+ static unsigned char buf[BUFSIZE];
-+ static des_cblock key ={0x12,0x34,0x56,0x78,0x9a,0xbc,0xde,0xf0};
-+ static des_cblock key2={0x34,0x56,0x78,0x9a,0xbc,0xde,0xf0,0x12};
-+ static des_cblock key3={0x56,0x78,0x9a,0xbc,0xde,0xf0,0x12,0x34};
-+ des_key_schedule sch,sch2,sch3;
-+ double a,b,c,d,e;
-+#ifndef SIGALRM
-+ long ca,cb,cc,cd,ce;
-+#endif
-+
-+#ifndef TIMES
-+ printf("To get the most acurate results, try to run this\n");
-+ printf("program when this computer is idle.\n");
-+#endif
-+
-+ des_set_key((C_Block *)key2,sch2);
-+ des_set_key((C_Block *)key3,sch3);
-+
-+#ifndef SIGALRM
-+ printf("First we calculate the approximate speed ...\n");
-+ des_set_key((C_Block *)key,sch);
-+ count=10;
-+ do {
-+ long i;
-+ DES_LONG data[2];
-+
-+ count*=2;
-+ Time_F(START);
-+ for (i=count; i; i--)
-+ des_encrypt(data,&(sch[0]),DES_ENCRYPT);
-+ d=Time_F(STOP);
-+ } while (d < 3.0);
-+ ca=count;
-+ cb=count*3;
-+ cc=count*3*8/BUFSIZE+1;
-+ cd=count*8/BUFSIZE+1;
-+ ce=count/20+1;
-+ printf("Doing set_key %ld times\n",ca);
-+#define COND(d) (count != (d))
-+#define COUNT(d) (d)
-+#else
-+#define COND(c) (run)
-+#define COUNT(d) (count)
-+ signal(SIGALRM,sig_done);
-+ printf("Doing set_key for 10 seconds\n");
-+ alarm(10);
-+#endif
-+
-+ Time_F(START);
-+ for (count=0,run=1; COND(ca); count++)
-+ des_set_key((C_Block *)key,sch);
-+ d=Time_F(STOP);
-+ printf("%ld set_key's in %.2f seconds\n",count,d);
-+ a=((double)COUNT(ca))/d;
-+
-+#ifdef SIGALRM
-+ printf("Doing des_encrypt's for 10 seconds\n");
-+ alarm(10);
-+#else
-+ printf("Doing des_encrypt %ld times\n",cb);
-+#endif
-+ Time_F(START);
-+ for (count=0,run=1; COND(cb); count++)
-+ {
-+ DES_LONG data[2];
-+
-+ des_encrypt(data,&(sch[0]),DES_ENCRYPT);
-+ }
-+ d=Time_F(STOP);
-+ printf("%ld des_encrypt's in %.2f second\n",count,d);
-+ b=((double)COUNT(cb)*8)/d;
-+
-+#ifdef SIGALRM
-+ printf("Doing des_cbc_encrypt on %ld byte blocks for 10 seconds\n",
-+ BUFSIZE);
-+ alarm(10);
-+#else
-+ printf("Doing des_cbc_encrypt %ld times on %ld byte blocks\n",cc,
-+ BUFSIZE);
-+#endif
-+ Time_F(START);
-+ for (count=0,run=1; COND(cc); count++)
-+ des_ncbc_encrypt((C_Block *)buf,(C_Block *)buf,BUFSIZE,&(sch[0]),
-+ (C_Block *)&(key[0]),DES_ENCRYPT);
-+ d=Time_F(STOP);
-+ printf("%ld des_cbc_encrypt's of %ld byte blocks in %.2f second\n",
-+ count,BUFSIZE,d);
-+ c=((double)COUNT(cc)*BUFSIZE)/d;
-+
-+#ifdef SIGALRM
-+ printf("Doing des_ede_cbc_encrypt on %ld byte blocks for 10 seconds\n",
-+ BUFSIZE);
-+ alarm(10);
-+#else
-+ printf("Doing des_ede_cbc_encrypt %ld times on %ld byte blocks\n",cd,
-+ BUFSIZE);
-+#endif
-+ Time_F(START);
-+ for (count=0,run=1; COND(cd); count++)
-+ des_ede3_cbc_encrypt((C_Block *)buf,(C_Block *)buf,BUFSIZE,
-+ &(sch[0]),
-+ &(sch2[0]),
-+ &(sch3[0]),
-+ (C_Block *)&(key[0]),
-+ DES_ENCRYPT);
-+ d=Time_F(STOP);
-+ printf("%ld des_ede_cbc_encrypt's of %ld byte blocks in %.2f second\n",
-+ count,BUFSIZE,d);
-+ d=((double)COUNT(cd)*BUFSIZE)/d;
-+
-+#ifdef SIGALRM
-+ printf("Doing crypt for 10 seconds\n");
-+ alarm(10);
-+#else
-+ printf("Doing crypt %ld times\n",ce);
-+#endif
-+ Time_F(START);
-+ for (count=0,run=1; COND(ce); count++)
-+ crypt("testing1","ef");
-+ e=Time_F(STOP);
-+ printf("%ld crypts in %.2f second\n",count,e);
-+ e=((double)COUNT(ce))/e;
-+
-+ printf("set_key per sec = %12.2f (%9.3fuS)\n",a,1.0e6/a);
-+ printf("DES raw ecb bytes per sec = %12.2f (%9.3fuS)\n",b,8.0e6/b);
-+ printf("DES cbc bytes per sec = %12.2f (%9.3fuS)\n",c,8.0e6/c);
-+ printf("DES ede cbc bytes per sec = %12.2f (%9.3fuS)\n",d,8.0e6/d);
-+ printf("crypt per sec = %12.2f (%9.3fuS)\n",e,1.0e6/e);
-+ exit(0);
-+#if defined(LINT) || defined(MSDOS)
-+ return(0);
-+#endif
-+ }
---- /dev/null Tue Mar 11 13:02:56 2003
-+++ linux/crypto/ciphers/des/spr.h Mon Feb 9 13:51:03 2004
-@@ -0,0 +1,204 @@
-+/* crypto/des/spr.h */
-+/* Copyright (C) 1995-1997 Eric Young (eay@cryptsoft.com)
-+ * All rights reserved.
-+ *
-+ * This package is an SSL implementation written
-+ * by Eric Young (eay@cryptsoft.com).
-+ * The implementation was written so as to conform with Netscapes SSL.
-+ *
-+ * This library is free for commercial and non-commercial use as long as
-+ * the following conditions are aheared to. The following conditions
-+ * apply to all code found in this distribution, be it the RC4, RSA,
-+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
-+ * included with this distribution is covered by the same copyright terms
-+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
-+ *
-+ * Copyright remains Eric Young's, and as such any Copyright notices in
-+ * the code are not to be removed.
-+ * If this package is used in a product, Eric Young should be given attribution
-+ * as the author of the parts of the library used.
-+ * This can be in the form of a textual message at program startup or
-+ * in documentation (online or textual) provided with the package.
-+ *
-+ * Redistribution and use in source and binary forms, with or without
-+ * modification, are permitted provided that the following conditions
-+ * are met:
-+ * 1. Redistributions of source code must retain the copyright
-+ * notice, this list of conditions and the following disclaimer.
-+ * 2. Redistributions in binary form must reproduce the above copyright
-+ * notice, this list of conditions and the following disclaimer in the
-+ * documentation and/or other materials provided with the distribution.
-+ * 3. All advertising materials mentioning features or use of this software
-+ * must display the following acknowledgement:
-+ * "This product includes cryptographic software written by
-+ * Eric Young (eay@cryptsoft.com)"
-+ * The word 'cryptographic' can be left out if the rouines from the library
-+ * being used are not cryptographic related :-).
-+ * 4. If you include any Windows specific code (or a derivative thereof) from
-+ * the apps directory (application code) you must include an acknowledgement:
-+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``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 OR CONTRIBUTORS 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.
-+ *
-+ * The licence and distribution terms for any publically available version or
-+ * derivative of this code cannot be changed. i.e. this code cannot simply be
-+ * copied and put under another distribution licence
-+ * [including the GNU Public Licence.]
-+ */
-+
-+const DES_LONG des_SPtrans[8][64]={
-+{
-+/* nibble 0 */
-+0x02080800L, 0x00080000L, 0x02000002L, 0x02080802L,
-+0x02000000L, 0x00080802L, 0x00080002L, 0x02000002L,
-+0x00080802L, 0x02080800L, 0x02080000L, 0x00000802L,
-+0x02000802L, 0x02000000L, 0x00000000L, 0x00080002L,
-+0x00080000L, 0x00000002L, 0x02000800L, 0x00080800L,
-+0x02080802L, 0x02080000L, 0x00000802L, 0x02000800L,
-+0x00000002L, 0x00000800L, 0x00080800L, 0x02080002L,
-+0x00000800L, 0x02000802L, 0x02080002L, 0x00000000L,
-+0x00000000L, 0x02080802L, 0x02000800L, 0x00080002L,
-+0x02080800L, 0x00080000L, 0x00000802L, 0x02000800L,
-+0x02080002L, 0x00000800L, 0x00080800L, 0x02000002L,
-+0x00080802L, 0x00000002L, 0x02000002L, 0x02080000L,
-+0x02080802L, 0x00080800L, 0x02080000L, 0x02000802L,
-+0x02000000L, 0x00000802L, 0x00080002L, 0x00000000L,
-+0x00080000L, 0x02000000L, 0x02000802L, 0x02080800L,
-+0x00000002L, 0x02080002L, 0x00000800L, 0x00080802L,
-+},{
-+/* nibble 1 */
-+0x40108010L, 0x00000000L, 0x00108000L, 0x40100000L,
-+0x40000010L, 0x00008010L, 0x40008000L, 0x00108000L,
-+0x00008000L, 0x40100010L, 0x00000010L, 0x40008000L,
-+0x00100010L, 0x40108000L, 0x40100000L, 0x00000010L,
-+0x00100000L, 0x40008010L, 0x40100010L, 0x00008000L,
-+0x00108010L, 0x40000000L, 0x00000000L, 0x00100010L,
-+0x40008010L, 0x00108010L, 0x40108000L, 0x40000010L,
-+0x40000000L, 0x00100000L, 0x00008010L, 0x40108010L,
-+0x00100010L, 0x40108000L, 0x40008000L, 0x00108010L,
-+0x40108010L, 0x00100010L, 0x40000010L, 0x00000000L,
-+0x40000000L, 0x00008010L, 0x00100000L, 0x40100010L,
-+0x00008000L, 0x40000000L, 0x00108010L, 0x40008010L,
-+0x40108000L, 0x00008000L, 0x00000000L, 0x40000010L,
-+0x00000010L, 0x40108010L, 0x00108000L, 0x40100000L,
-+0x40100010L, 0x00100000L, 0x00008010L, 0x40008000L,
-+0x40008010L, 0x00000010L, 0x40100000L, 0x00108000L,
-+},{
-+/* nibble 2 */
-+0x04000001L, 0x04040100L, 0x00000100L, 0x04000101L,
-+0x00040001L, 0x04000000L, 0x04000101L, 0x00040100L,
-+0x04000100L, 0x00040000L, 0x04040000L, 0x00000001L,
-+0x04040101L, 0x00000101L, 0x00000001L, 0x04040001L,
-+0x00000000L, 0x00040001L, 0x04040100L, 0x00000100L,
-+0x00000101L, 0x04040101L, 0x00040000L, 0x04000001L,
-+0x04040001L, 0x04000100L, 0x00040101L, 0x04040000L,
-+0x00040100L, 0x00000000L, 0x04000000L, 0x00040101L,
-+0x04040100L, 0x00000100L, 0x00000001L, 0x00040000L,
-+0x00000101L, 0x00040001L, 0x04040000L, 0x04000101L,
-+0x00000000L, 0x04040100L, 0x00040100L, 0x04040001L,
-+0x00040001L, 0x04000000L, 0x04040101L, 0x00000001L,
-+0x00040101L, 0x04000001L, 0x04000000L, 0x04040101L,
-+0x00040000L, 0x04000100L, 0x04000101L, 0x00040100L,
-+0x04000100L, 0x00000000L, 0x04040001L, 0x00000101L,
-+0x04000001L, 0x00040101L, 0x00000100L, 0x04040000L,
-+},{
-+/* nibble 3 */
-+0x00401008L, 0x10001000L, 0x00000008L, 0x10401008L,
-+0x00000000L, 0x10400000L, 0x10001008L, 0x00400008L,
-+0x10401000L, 0x10000008L, 0x10000000L, 0x00001008L,
-+0x10000008L, 0x00401008L, 0x00400000L, 0x10000000L,
-+0x10400008L, 0x00401000L, 0x00001000L, 0x00000008L,
-+0x00401000L, 0x10001008L, 0x10400000L, 0x00001000L,
-+0x00001008L, 0x00000000L, 0x00400008L, 0x10401000L,
-+0x10001000L, 0x10400008L, 0x10401008L, 0x00400000L,
-+0x10400008L, 0x00001008L, 0x00400000L, 0x10000008L,
-+0x00401000L, 0x10001000L, 0x00000008L, 0x10400000L,
-+0x10001008L, 0x00000000L, 0x00001000L, 0x00400008L,
-+0x00000000L, 0x10400008L, 0x10401000L, 0x00001000L,
-+0x10000000L, 0x10401008L, 0x00401008L, 0x00400000L,
-+0x10401008L, 0x00000008L, 0x10001000L, 0x00401008L,
-+0x00400008L, 0x00401000L, 0x10400000L, 0x10001008L,
-+0x00001008L, 0x10000000L, 0x10000008L, 0x10401000L,
-+},{
-+/* nibble 4 */
-+0x08000000L, 0x00010000L, 0x00000400L, 0x08010420L,
-+0x08010020L, 0x08000400L, 0x00010420L, 0x08010000L,
-+0x00010000L, 0x00000020L, 0x08000020L, 0x00010400L,
-+0x08000420L, 0x08010020L, 0x08010400L, 0x00000000L,
-+0x00010400L, 0x08000000L, 0x00010020L, 0x00000420L,
-+0x08000400L, 0x00010420L, 0x00000000L, 0x08000020L,
-+0x00000020L, 0x08000420L, 0x08010420L, 0x00010020L,
-+0x08010000L, 0x00000400L, 0x00000420L, 0x08010400L,
-+0x08010400L, 0x08000420L, 0x00010020L, 0x08010000L,
-+0x00010000L, 0x00000020L, 0x08000020L, 0x08000400L,
-+0x08000000L, 0x00010400L, 0x08010420L, 0x00000000L,
-+0x00010420L, 0x08000000L, 0x00000400L, 0x00010020L,
-+0x08000420L, 0x00000400L, 0x00000000L, 0x08010420L,
-+0x08010020L, 0x08010400L, 0x00000420L, 0x00010000L,
-+0x00010400L, 0x08010020L, 0x08000400L, 0x00000420L,
-+0x00000020L, 0x00010420L, 0x08010000L, 0x08000020L,
-+},{
-+/* nibble 5 */
-+0x80000040L, 0x00200040L, 0x00000000L, 0x80202000L,
-+0x00200040L, 0x00002000L, 0x80002040L, 0x00200000L,
-+0x00002040L, 0x80202040L, 0x00202000L, 0x80000000L,
-+0x80002000L, 0x80000040L, 0x80200000L, 0x00202040L,
-+0x00200000L, 0x80002040L, 0x80200040L, 0x00000000L,
-+0x00002000L, 0x00000040L, 0x80202000L, 0x80200040L,
-+0x80202040L, 0x80200000L, 0x80000000L, 0x00002040L,
-+0x00000040L, 0x00202000L, 0x00202040L, 0x80002000L,
-+0x00002040L, 0x80000000L, 0x80002000L, 0x00202040L,
-+0x80202000L, 0x00200040L, 0x00000000L, 0x80002000L,
-+0x80000000L, 0x00002000L, 0x80200040L, 0x00200000L,
-+0x00200040L, 0x80202040L, 0x00202000L, 0x00000040L,
-+0x80202040L, 0x00202000L, 0x00200000L, 0x80002040L,
-+0x80000040L, 0x80200000L, 0x00202040L, 0x00000000L,
-+0x00002000L, 0x80000040L, 0x80002040L, 0x80202000L,
-+0x80200000L, 0x00002040L, 0x00000040L, 0x80200040L,
-+},{
-+/* nibble 6 */
-+0x00004000L, 0x00000200L, 0x01000200L, 0x01000004L,
-+0x01004204L, 0x00004004L, 0x00004200L, 0x00000000L,
-+0x01000000L, 0x01000204L, 0x00000204L, 0x01004000L,
-+0x00000004L, 0x01004200L, 0x01004000L, 0x00000204L,
-+0x01000204L, 0x00004000L, 0x00004004L, 0x01004204L,
-+0x00000000L, 0x01000200L, 0x01000004L, 0x00004200L,
-+0x01004004L, 0x00004204L, 0x01004200L, 0x00000004L,
-+0x00004204L, 0x01004004L, 0x00000200L, 0x01000000L,
-+0x00004204L, 0x01004000L, 0x01004004L, 0x00000204L,
-+0x00004000L, 0x00000200L, 0x01000000L, 0x01004004L,
-+0x01000204L, 0x00004204L, 0x00004200L, 0x00000000L,
-+0x00000200L, 0x01000004L, 0x00000004L, 0x01000200L,
-+0x00000000L, 0x01000204L, 0x01000200L, 0x00004200L,
-+0x00000204L, 0x00004000L, 0x01004204L, 0x01000000L,
-+0x01004200L, 0x00000004L, 0x00004004L, 0x01004204L,
-+0x01000004L, 0x01004200L, 0x01004000L, 0x00004004L,
-+},{
-+/* nibble 7 */
-+0x20800080L, 0x20820000L, 0x00020080L, 0x00000000L,
-+0x20020000L, 0x00800080L, 0x20800000L, 0x20820080L,
-+0x00000080L, 0x20000000L, 0x00820000L, 0x00020080L,
-+0x00820080L, 0x20020080L, 0x20000080L, 0x20800000L,
-+0x00020000L, 0x00820080L, 0x00800080L, 0x20020000L,
-+0x20820080L, 0x20000080L, 0x00000000L, 0x00820000L,
-+0x20000000L, 0x00800000L, 0x20020080L, 0x20800080L,
-+0x00800000L, 0x00020000L, 0x20820000L, 0x00000080L,
-+0x00800000L, 0x00020000L, 0x20000080L, 0x20820080L,
-+0x00020080L, 0x20000000L, 0x00000000L, 0x00820000L,
-+0x20800080L, 0x20020080L, 0x20020000L, 0x00800080L,
-+0x20820000L, 0x00000080L, 0x00800080L, 0x20020000L,
-+0x20820080L, 0x00800000L, 0x20800000L, 0x20000080L,
-+0x00820000L, 0x00020080L, 0x20020080L, 0x20800000L,
-+0x00000080L, 0x20820000L, 0x00820080L, 0x00000000L,
-+0x20000000L, 0x20800080L, 0x00020000L, 0x00820080L,
-+}};
---- /dev/null Tue Mar 11 13:02:56 2003
-+++ linux/include/crypto/aes.h Mon Feb 9 13:51:03 2004
-@@ -0,0 +1,97 @@
-+// I retain copyright in this code but I encourage its free use provided
-+// that I don't carry any responsibility for the results. I am especially
-+// happy to see it used in free and open source software. If you do use
-+// it I would appreciate an acknowledgement of its origin in the code or
-+// the product that results and I would also appreciate knowing a little
-+// about the use to which it is being put. I am grateful to Frank Yellin
-+// for some ideas that are used in this implementation.
-+//
-+// Dr B. R. Gladman <brg@gladman.uk.net> 6th April 2001.
-+//
-+// This is an implementation of the AES encryption algorithm (Rijndael)
-+// designed by Joan Daemen and Vincent Rijmen. This version is designed
-+// to provide both fixed and dynamic block and key lengths and can also
-+// run with either big or little endian internal byte order (see aes.h).
-+// It inputs block and key lengths in bytes with the legal values being
-+// 16, 24 and 32.
-+
-+/*
-+ * Modified by Jari Ruusu, May 1 2001
-+ * - Fixed some compile warnings, code was ok but gcc warned anyway.
-+ * - Changed basic types: byte -> unsigned char, word -> u_int32_t
-+ * - Major name space cleanup: Names visible to outside now begin
-+ * with "aes_" or "AES_". A lot of stuff moved from aes.h to aes.c
-+ * - Removed C++ and DLL support as part of name space cleanup.
-+ * - Eliminated unnecessary recomputation of tables. (actual bug fix)
-+ * - Merged precomputed constant tables to aes.c file.
-+ * - Removed data alignment restrictions for portability reasons.
-+ * - Made block and key lengths accept bit count (128/192/256)
-+ * as well byte count (16/24/32).
-+ * - Removed all error checks. This change also eliminated the need
-+ * to preinitialize the context struct to zero.
-+ * - Removed some totally unused constants.
-+ */
-+
-+#ifndef _AES_H
-+#define _AES_H
-+
-+#if defined(__linux__) && defined(__KERNEL__)
-+# include <linux/types.h>
-+#else
-+# include <sys/types.h>
-+#endif
-+
-+// CONFIGURATION OPTIONS (see also aes.c)
-+//
-+// Define AES_BLOCK_SIZE to set the cipher block size (16, 24 or 32) or
-+// leave this undefined for dynamically variable block size (this will
-+// result in much slower code).
-+// IMPORTANT NOTE: AES_BLOCK_SIZE is in BYTES (16, 24, 32 or undefined). If
-+// left undefined a slower version providing variable block length is compiled
-+
-+#define AES_BLOCK_SIZE 16
-+
-+// The number of key schedule words for different block and key lengths
-+// allowing for method of computation which requires the length to be a
-+// multiple of the key length
-+//
-+// Nk = 4 6 8
-+// -------------
-+// Nb = 4 | 60 60 64
-+// 6 | 96 90 96
-+// 8 | 120 120 120
-+
-+#if !defined(AES_BLOCK_SIZE) || (AES_BLOCK_SIZE == 32)
-+#define AES_KS_LENGTH 120
-+#define AES_RC_LENGTH 29
-+#else
-+#define AES_KS_LENGTH 4 * AES_BLOCK_SIZE
-+#define AES_RC_LENGTH (9 * AES_BLOCK_SIZE) / 8 - 8
-+#endif
-+
-+typedef struct
-+{
-+ u_int32_t aes_Nkey; // the number of words in the key input block
-+ u_int32_t aes_Nrnd; // the number of cipher rounds
-+ u_int32_t aes_e_key[AES_KS_LENGTH]; // the encryption key schedule
-+ u_int32_t aes_d_key[AES_KS_LENGTH]; // the decryption key schedule
-+#if !defined(AES_BLOCK_SIZE)
-+ u_int32_t aes_Ncol; // the number of columns in the cipher state
-+#endif
-+} aes_context;
-+
-+// THE CIPHER INTERFACE
-+
-+#if !defined(AES_BLOCK_SIZE)
-+extern void aes_set_blk(aes_context *, const int);
-+#endif
-+extern void aes_set_key(aes_context *, const unsigned char [], const int, const int);
-+extern void aes_encrypt(const aes_context *, const unsigned char [], unsigned char []);
-+extern void aes_decrypt(const aes_context *, const unsigned char [], unsigned char []);
-+
-+// The block length inputs to aes_set_block and aes_set_key are in numbers
-+// of bytes or bits. The calls to subroutines must be made in the above
-+// order but multiple calls can be made without repeating earlier calls
-+// if their parameters have not changed.
-+
-+#endif // _AES_H
---- /dev/null Tue Mar 11 13:02:56 2003
-+++ linux/include/crypto/aes_cbc.h Mon Feb 9 13:51:03 2004
-@@ -0,0 +1,4 @@
-+/* Glue header */
-+#include "aes.h"
-+int AES_set_key(aes_context *aes_ctx, const u_int8_t * key, int keysize);
-+int AES_cbc_encrypt(aes_context *ctx, const u_int8_t * in, u_int8_t * out, int ilen, const u_int8_t * iv, int encrypt);
---- /dev/null Tue Mar 11 13:02:56 2003
-+++ linux/include/crypto/aes_xcbc_mac.h Mon Feb 9 13:51:03 2004
-@@ -0,0 +1,12 @@
-+#ifndef _AES_XCBC_MAC_H
-+#define _AES_XCBC_MAC_H
-+
-+typedef u_int32_t aes_block[4];
-+typedef struct {
-+ aes_context ctx_k1;
-+ aes_block k2;
-+ aes_block k3;
-+} aes_context_mac;
-+int AES_xcbc_mac_set_key(aes_context_mac *ctxm, const u_int8_t *key, int keylen);
-+int AES_xcbc_mac_hash(const aes_context_mac *ctxm, const u_int8_t * in, int ilen, u_int8_t hash[16]);
-+#endif /* _AES_XCBC_MAC_H */
---- /dev/null Tue Mar 11 13:02:56 2003
-+++ linux/include/crypto/cbc_generic.h Mon Feb 9 13:51:03 2004
-@@ -0,0 +1,110 @@
-+#ifndef _CBC_GENERIC_H
-+#define _CBC_GENERIC_H
-+/*
-+ * CBC macro helpers
-+ *
-+ * Author: JuanJo Ciarlante <jjo-ipsec@mendoza.gov.ar>
-+ *
-+ * 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. See <http://www.fsf.org/copyleft/gpl.txt>.
-+ *
-+ * 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.
-+ *
-+ */
-+
-+/*
-+ * Heavily inspired in loop_AES
-+ */
-+#define CBC_IMPL_BLK16(name, ctx_type, addr_type, enc_func, dec_func) \
-+int name(ctx_type *ctx, const u_int8_t * in, u_int8_t * out, int ilen, const u_int8_t * iv, int encrypt) { \
-+ int ret=ilen, pos; \
-+ const u_int32_t *iv_i; \
-+ if ((ilen) % 16) return 0; \
-+ if (encrypt) { \
-+ pos=0; \
-+ while(pos<ilen) { \
-+ if (pos==0) \
-+ iv_i=(const u_int32_t*) iv; \
-+ else \
-+ iv_i=(const u_int32_t*) (out-16); \
-+ *((u_int32_t *)(&out[ 0])) = iv_i[0]^*((const u_int32_t *)(&in[ 0])); \
-+ *((u_int32_t *)(&out[ 4])) = iv_i[1]^*((const u_int32_t *)(&in[ 4])); \
-+ *((u_int32_t *)(&out[ 8])) = iv_i[2]^*((const u_int32_t *)(&in[ 8])); \
-+ *((u_int32_t *)(&out[12])) = iv_i[3]^*((const u_int32_t *)(&in[12])); \
-+ enc_func(ctx, (addr_type) out, (addr_type) out); \
-+ in+=16; \
-+ out+=16; \
-+ pos+=16; \
-+ } \
-+ } else { \
-+ pos=ilen-16; \
-+ in+=pos; \
-+ out+=pos; \
-+ while(pos>=0) { \
-+ dec_func(ctx, (const addr_type) in, (addr_type) out); \
-+ if (pos==0) \
-+ iv_i=(const u_int32_t*) (iv); \
-+ else \
-+ iv_i=(const u_int32_t*) (in-16); \
-+ *((u_int32_t *)(&out[ 0])) ^= iv_i[0]; \
-+ *((u_int32_t *)(&out[ 4])) ^= iv_i[1]; \
-+ *((u_int32_t *)(&out[ 8])) ^= iv_i[2]; \
-+ *((u_int32_t *)(&out[12])) ^= iv_i[3]; \
-+ in-=16; \
-+ out-=16; \
-+ pos-=16; \
-+ } \
-+ } \
-+ return ret; \
-+}
-+#define CBC_IMPL_BLK8(name, ctx_type, addr_type, enc_func, dec_func) \
-+int name(ctx_type *ctx, u_int8_t * in, u_int8_t * out, int ilen, const u_int8_t * iv, int encrypt) { \
-+ int ret=ilen, pos; \
-+ const u_int32_t *iv_i; \
-+ if ((ilen) % 8) return 0; \
-+ if (encrypt) { \
-+ pos=0; \
-+ while(pos<ilen) { \
-+ if (pos==0) \
-+ iv_i=(const u_int32_t*) iv; \
-+ else \
-+ iv_i=(const u_int32_t*) (out-8); \
-+ *((u_int32_t *)(&out[ 0])) = iv_i[0]^*((const u_int32_t *)(&in[ 0])); \
-+ *((u_int32_t *)(&out[ 4])) = iv_i[1]^*((const u_int32_t *)(&in[ 4])); \
-+ enc_func(ctx, (addr_type)out, (addr_type)out); \
-+ in+=8; \
-+ out+=8; \
-+ pos+=8; \
-+ } \
-+ } else { \
-+ pos=ilen-8; \
-+ in+=pos; \
-+ out+=pos; \
-+ while(pos>=0) { \
-+ dec_func(ctx, (const addr_type)in, (addr_type)out); \
-+ if (pos==0) \
-+ iv_i=(const u_int32_t*) (iv); \
-+ else \
-+ iv_i=(const u_int32_t*) (in-8); \
-+ *((u_int32_t *)(&out[ 0])) ^= iv_i[0]; \
-+ *((u_int32_t *)(&out[ 4])) ^= iv_i[1]; \
-+ in-=8; \
-+ out-=8; \
-+ pos-=8; \
-+ } \
-+ } \
-+ return ret; \
-+}
-+#define CBC_DECL(name, ctx_type) \
-+int name(ctx_type *ctx, u_int8_t * in, u_int8_t * out, int ilen, const u_int8_t * iv, int encrypt)
-+/*
-+Eg.:
-+CBC_IMPL_BLK16(AES_cbc_encrypt, aes_context, u_int8_t *, aes_encrypt, aes_decrypt);
-+CBC_DECL(AES_cbc_encrypt, aes_context);
-+*/
-+#endif /* _CBC_GENERIC_H */
---- /dev/null Tue Mar 11 13:02:56 2003
-+++ linux/include/crypto/des.h Mon Feb 9 13:51:03 2004
-@@ -0,0 +1,298 @@
-+/* crypto/des/des.org */
-+/* Copyright (C) 1995-1997 Eric Young (eay@cryptsoft.com)
-+ * All rights reserved.
-+ *
-+ * This package is an SSL implementation written
-+ * by Eric Young (eay@cryptsoft.com).
-+ * The implementation was written so as to conform with Netscapes SSL.
-+ *
-+ * This library is free for commercial and non-commercial use as long as
-+ * the following conditions are aheared to. The following conditions
-+ * apply to all code found in this distribution, be it the RC4, RSA,
-+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
-+ * included with this distribution is covered by the same copyright terms
-+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
-+ *
-+ * Copyright remains Eric Young's, and as such any Copyright notices in
-+ * the code are not to be removed.
-+ * If this package is used in a product, Eric Young should be given attribution
-+ * as the author of the parts of the library used.
-+ * This can be in the form of a textual message at program startup or
-+ * in documentation (online or textual) provided with the package.
-+ *
-+ * Redistribution and use in source and binary forms, with or without
-+ * modification, are permitted provided that the following conditions
-+ * are met:
-+ * 1. Redistributions of source code must retain the copyright
-+ * notice, this list of conditions and the following disclaimer.
-+ * 2. Redistributions in binary form must reproduce the above copyright
-+ * notice, this list of conditions and the following disclaimer in the
-+ * documentation and/or other materials provided with the distribution.
-+ * 3. All advertising materials mentioning features or use of this software
-+ * must display the following acknowledgement:
-+ * "This product includes cryptographic software written by
-+ * Eric Young (eay@cryptsoft.com)"
-+ * The word 'cryptographic' can be left out if the rouines from the library
-+ * being used are not cryptographic related :-).
-+ * 4. If you include any Windows specific code (or a derivative thereof) from
-+ * the apps directory (application code) you must include an acknowledgement:
-+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``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 OR CONTRIBUTORS 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.
-+ *
-+ * The licence and distribution terms for any publically available version or
-+ * derivative of this code cannot be changed. i.e. this code cannot simply be
-+ * copied and put under another distribution licence
-+ * [including the GNU Public Licence.]
-+ */
-+
-+/* WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
-+ *
-+ * Always modify des.org since des.h is automatically generated from
-+ * it during SSLeay configuration.
-+ *
-+ * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
-+ */
-+
-+#ifndef HEADER_DES_H
-+#define HEADER_DES_H
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+
-+/* If this is set to 'unsigned int' on a DEC Alpha, this gives about a
-+ * %20 speed up (longs are 8 bytes, int's are 4). */
-+/* Must be unsigned int on ia64/Itanium or DES breaks badly */
-+
-+#ifdef __KERNEL__
-+#include <linux/types.h>
-+#else
-+#include <sys/types.h>
-+#endif
-+
-+#ifndef DES_LONG
-+#define DES_LONG u_int32_t
-+#endif
-+
-+typedef unsigned char des_cblock[8];
-+typedef struct { des_cblock ks; } des_key_schedule[16];
-+
-+#define DES_KEY_SZ (sizeof(des_cblock))
-+#define DES_SCHEDULE_SZ (sizeof(des_key_schedule))
-+
-+#define DES_ENCRYPT 1
-+#define DES_DECRYPT 0
-+
-+#define DES_CBC_MODE 0
-+#define DES_PCBC_MODE 1
-+
-+#define des_ecb2_encrypt(i,o,k1,k2,e) \
-+ des_ecb3_encrypt((i),(o),(k1),(k2),(k1),(e))
-+
-+#define des_ede2_cbc_encrypt(i,o,l,k1,k2,iv,e) \
-+ des_ede3_cbc_encrypt((i),(o),(l),(k1),(k2),(k1),(iv),(e))
-+
-+#define des_ede2_cfb64_encrypt(i,o,l,k1,k2,iv,n,e) \
-+ des_ede3_cfb64_encrypt((i),(o),(l),(k1),(k2),(k1),(iv),(n),(e))
-+
-+#define des_ede2_ofb64_encrypt(i,o,l,k1,k2,iv,n) \
-+ des_ede3_ofb64_encrypt((i),(o),(l),(k1),(k2),(k1),(iv),(n))
-+
-+#define C_Block des_cblock
-+#define Key_schedule des_key_schedule
-+#ifdef KERBEROS
-+#define ENCRYPT DES_ENCRYPT
-+#define DECRYPT DES_DECRYPT
-+#endif
-+#define KEY_SZ DES_KEY_SZ
-+#define string_to_key des_string_to_key
-+#define read_pw_string des_read_pw_string
-+#define random_key des_random_key
-+#define pcbc_encrypt des_pcbc_encrypt
-+#define set_key des_set_key
-+#define key_sched des_key_sched
-+#define ecb_encrypt des_ecb_encrypt
-+#define cbc_encrypt des_cbc_encrypt
-+#define ncbc_encrypt des_ncbc_encrypt
-+#define xcbc_encrypt des_xcbc_encrypt
-+#define cbc_cksum des_cbc_cksum
-+#define quad_cksum des_quad_cksum
-+
-+/* For compatibility with the MIT lib - eay 20/05/92 */
-+typedef des_key_schedule bit_64;
-+#define des_fixup_key_parity des_set_odd_parity
-+#define des_check_key_parity check_parity
-+
-+extern int des_check_key; /* defaults to false */
-+extern int des_rw_mode; /* defaults to DES_PCBC_MODE */
-+
-+/* The next line is used to disable full ANSI prototypes, if your
-+ * compiler has problems with the prototypes, make sure this line always
-+ * evaluates to true :-) */
-+#if defined(MSDOS) || defined(__STDC__)
-+#undef NOPROTO
-+#endif
-+#ifndef NOPROTO
-+char *des_options(void);
-+void des_ecb3_encrypt(des_cblock *input,des_cblock *output,
-+ des_key_schedule ks1,des_key_schedule ks2,
-+ des_key_schedule ks3, int enc);
-+DES_LONG des_cbc_cksum(des_cblock *input,des_cblock *output,
-+ long length,des_key_schedule schedule,des_cblock *ivec);
-+void des_cbc_encrypt(des_cblock *input,des_cblock *output,long length,
-+ des_key_schedule schedule,des_cblock *ivec,int enc);
-+void des_ncbc_encrypt(des_cblock *input,des_cblock *output,long length,
-+ des_key_schedule schedule,des_cblock *ivec,int enc);
-+void des_xcbc_encrypt(des_cblock *input,des_cblock *output,long length,
-+ des_key_schedule schedule,des_cblock *ivec,
-+ des_cblock *inw,des_cblock *outw,int enc);
-+void des_cfb_encrypt(unsigned char *in,unsigned char *out,int numbits,
-+ long length,des_key_schedule schedule,des_cblock *ivec,int enc);
-+void des_ecb_encrypt(des_cblock *input,des_cblock *output,
-+ des_key_schedule ks,int enc);
-+void des_encrypt(DES_LONG *data,des_key_schedule ks, int enc);
-+void des_encrypt2(DES_LONG *data,des_key_schedule ks, int enc);
-+void des_encrypt3(DES_LONG *data, des_key_schedule ks1,
-+ des_key_schedule ks2, des_key_schedule ks3);
-+void des_decrypt3(DES_LONG *data, des_key_schedule ks1,
-+ des_key_schedule ks2, des_key_schedule ks3);
-+void des_ede3_cbc_encrypt(des_cblock *input, des_cblock *output,
-+ long length, des_key_schedule ks1, des_key_schedule ks2,
-+ des_key_schedule ks3, des_cblock *ivec, int enc);
-+void des_ede3_cfb64_encrypt(unsigned char *in, unsigned char *out,
-+ long length, des_key_schedule ks1, des_key_schedule ks2,
-+ des_key_schedule ks3, des_cblock *ivec, int *num, int enc);
-+void des_ede3_ofb64_encrypt(unsigned char *in, unsigned char *out,
-+ long length, des_key_schedule ks1, des_key_schedule ks2,
-+ des_key_schedule ks3, des_cblock *ivec, int *num);
-+
-+void des_xwhite_in2out(des_cblock (*des_key), des_cblock (*in_white),
-+ des_cblock (*out_white));
-+
-+int des_enc_read(int fd,char *buf,int len,des_key_schedule sched,
-+ des_cblock *iv);
-+int des_enc_write(int fd,char *buf,int len,des_key_schedule sched,
-+ des_cblock *iv);
-+char *des_fcrypt(const char *buf,const char *salt, char *ret);
-+#ifdef PERL5
-+char *des_crypt(const char *buf,const char *salt);
-+#else
-+/* some stupid compilers complain because I have declared char instead
-+ * of const char */
-+#ifndef __KERNEL__
-+#ifdef HEADER_DES_LOCL_H
-+char *crypt(const char *buf,const char *salt);
-+#else /* HEADER_DES_LOCL_H */
-+char *crypt(void);
-+#endif /* HEADER_DES_LOCL_H */
-+#endif /* __KERNEL__ */
-+#endif /* PERL5 */
-+void des_ofb_encrypt(unsigned char *in,unsigned char *out,
-+ int numbits,long length,des_key_schedule schedule,des_cblock *ivec);
-+void des_pcbc_encrypt(des_cblock *input,des_cblock *output,long length,
-+ des_key_schedule schedule,des_cblock *ivec,int enc);
-+DES_LONG des_quad_cksum(des_cblock *input,des_cblock *output,
-+ long length,int out_count,des_cblock *seed);
-+void des_random_seed(des_cblock key);
-+void des_random_key(des_cblock ret);
-+int des_read_password(des_cblock *key,char *prompt,int verify);
-+int des_read_2passwords(des_cblock *key1,des_cblock *key2,
-+ char *prompt,int verify);
-+int des_read_pw_string(char *buf,int length,char *prompt,int verify);
-+void des_set_odd_parity(des_cblock *key);
-+int des_is_weak_key(des_cblock *key);
-+int des_set_key(des_cblock *key,des_key_schedule schedule);
-+int des_key_sched(des_cblock *key,des_key_schedule schedule);
-+void des_string_to_key(char *str,des_cblock *key);
-+void des_string_to_2keys(char *str,des_cblock *key1,des_cblock *key2);
-+void des_cfb64_encrypt(unsigned char *in, unsigned char *out, long length,
-+ des_key_schedule schedule, des_cblock *ivec, int *num, int enc);
-+void des_ofb64_encrypt(unsigned char *in, unsigned char *out, long length,
-+ des_key_schedule schedule, des_cblock *ivec, int *num);
-+int des_read_pw(char *buf, char *buff, int size, char *prompt, int verify);
-+
-+/* Extra functions from Mark Murray <mark@grondar.za> */
-+/* The following functions are not in the normal unix build or the
-+ * SSLeay build. When using the SSLeay build, use RAND_seed()
-+ * and RAND_bytes() instead. */
-+int des_new_random_key(des_cblock *key);
-+void des_init_random_number_generator(des_cblock *key);
-+void des_set_random_generator_seed(des_cblock *key);
-+void des_set_sequence_number(des_cblock new_sequence_number);
-+void des_generate_random_block(des_cblock *block);
-+
-+#else
-+
-+char *des_options();
-+void des_ecb3_encrypt();
-+DES_LONG des_cbc_cksum();
-+void des_cbc_encrypt();
-+void des_ncbc_encrypt();
-+void des_xcbc_encrypt();
-+void des_cfb_encrypt();
-+void des_ede3_cfb64_encrypt();
-+void des_ede3_ofb64_encrypt();
-+void des_ecb_encrypt();
-+void des_encrypt();
-+void des_encrypt2();
-+void des_encrypt3();
-+void des_decrypt3();
-+void des_ede3_cbc_encrypt();
-+int des_enc_read();
-+int des_enc_write();
-+char *des_fcrypt();
-+#ifdef PERL5
-+char *des_crypt();
-+#else
-+char *crypt();
-+#endif
-+void des_ofb_encrypt();
-+void des_pcbc_encrypt();
-+DES_LONG des_quad_cksum();
-+void des_random_seed();
-+void des_random_key();
-+int des_read_password();
-+int des_read_2passwords();
-+int des_read_pw_string();
-+void des_set_odd_parity();
-+int des_is_weak_key();
-+int des_set_key();
-+int des_key_sched();
-+void des_string_to_key();
-+void des_string_to_2keys();
-+void des_cfb64_encrypt();
-+void des_ofb64_encrypt();
-+int des_read_pw();
-+void des_xwhite_in2out();
-+
-+/* Extra functions from Mark Murray <mark@grondar.za> */
-+/* The following functions are not in the normal unix build or the
-+ * SSLeay build. When using the SSLeay build, use RAND_seed()
-+ * and RAND_bytes() instead. */
-+#ifdef FreeBSD
-+int des_new_random_key();
-+void des_init_random_number_generator();
-+void des_set_random_generator_seed();
-+void des_set_sequence_number();
-+void des_generate_random_block();
-+#endif
-+
-+#endif
-+
-+#ifdef __cplusplus
-+}
-+#endif
-+
-+#endif
---- /dev/null Tue Mar 11 13:02:56 2003
-+++ linux/include/mast.h Mon Feb 9 13:51:03 2004
-@@ -0,0 +1,33 @@
-+struct mast_callbacks {
-+ int (*packet_encap)(struct device *mast, void *context,
-+ struct sk_buff *skb, int flowref);
-+ int (*link_inquire)(struct device *mast, void *context);
-+};
-+
-+
-+struct device *mast_init (int family,
-+ struct mast_callbacks *callbacks,
-+ unsigned int flags,
-+ unsigned int desired_unit,
-+ unsigned int max_flowref,
-+ void *context);
-+
-+int mast_destroy(struct device *mast);
-+
-+int mast_recv(struct device *mast, struct sk_buff *skb, int flowref);
-+
-+/* free this skb as being useless, increment failure count. */
-+int mast_toast(struct device *mast, struct sk_buff *skb, int flowref);
-+
-+int mast_linkstat (struct device *mast, int flowref,
-+ int status);
-+
-+int mast_setreference (struct device *mast,
-+ int defaultSA);
-+
-+int mast_setneighbor (struct device *mast,
-+ struct sockaddr *source,
-+ struct sockaddr *destination,
-+ int flowref);
-+
-+
---- /dev/null Tue Mar 11 13:02:56 2003
-+++ linux/include/openswan.h Mon Feb 9 13:51:03 2004
-@@ -0,0 +1,513 @@
-+#ifndef _OPENSWAN_H
-+/*
-+ * header file for FreeS/WAN library functions
-+ * Copyright (C) 1998, 1999, 2000 Henry Spencer.
-+ * Copyright (C) 1999, 2000, 2001 Richard Guy Briggs
-+ *
-+ * This library is free software; you can redistribute it and/or modify it
-+ * under the terms of the GNU Library General Public License as published by
-+ * the Free Software Foundation; either version 2 of the License, or (at your
-+ * option) any later version. See <http://www.fsf.org/copyleft/lgpl.txt>.
-+ *
-+ * This library 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 Library General Public
-+ * License for more details.
-+ *
-+ * RCSID $Id: openswan.h,v 1.89 2004/06/08 00:53:13 mcr Exp $
-+ */
-+#define _OPENSWAN_H /* seen it, no need to see it again */
-+
-+
-+
-+/*
-+ * We've just got to have some datatypes defined... And annoyingly, just
-+ * where we get them depends on whether we're in userland or not.
-+ */
-+/* things that need to come from one place or the other, depending */
-+#ifdef __KERNEL__
-+#include <linux/types.h>
-+#include <linux/socket.h>
-+#include <linux/in.h>
-+#include <linux/string.h>
-+#include <linux/ctype.h>
-+#define assert(foo) /* nothing */
-+#else
-+#include <sys/types.h>
-+#include <netinet/in.h>
-+#include <string.h>
-+#include <ctype.h>
-+#include <assert.h>
-+#include <stdio.h>
-+
-+# define uint8_t u_int8_t
-+# define uint16_t u_int16_t
-+# define uint32_t u_int32_t
-+# define uint64_t u_int64_t
-+
-+
-+# define DEBUG_NO_STATIC static
-+
-+#endif
-+
-+#include <openswan/ipsec_param.h>
-+
-+
-+/*
-+ * Grab the kernel version to see if we have NET_21, and therefore
-+ * IPv6. Some of this is repeated from ipsec_kversions.h. Of course,
-+ * we aren't really testing if the kernel has IPv6, but rather if the
-+ * the include files do.
-+ */
-+#include <linux/version.h>
-+#ifndef KERNEL_VERSION
-+#define KERNEL_VERSION(x,y,z) (((x)<<16)+((y)<<8)+(z))
-+#endif
-+
-+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0)
-+#define NET_21
-+#endif
-+
-+#ifndef IPPROTO_COMP
-+# define IPPROTO_COMP 108
-+#endif /* !IPPROTO_COMP */
-+
-+#ifndef IPPROTO_INT
-+# define IPPROTO_INT 61
-+#endif /* !IPPROTO_INT */
-+
-+#ifdef CONFIG_IPSEC_DEBUG
-+#ifndef DEBUG_NO_STATIC
-+# define DEBUG_NO_STATIC
-+#endif
-+#else /* CONFIG_IPSEC_DEBUG */
-+#ifndef DEBUG_NO_STATIC
-+# define DEBUG_NO_STATIC static
-+#endif
-+#endif /* CONFIG_IPSEC_DEBUG */
-+
-+#ifdef CONFIG_IPSEC_NAT_TRAVERSAL /* KERNEL ifdef */
-+#ifndef NAT_TRAVERSAL
-+#define NAT_TRAVERSAL
-+#endif
-+#endif
-+#ifdef NAT_TRAVERSAL
-+#define ESPINUDP_WITH_NON_IKE 1 /* draft-ietf-ipsec-nat-t-ike-00/01 */
-+#define ESPINUDP_WITH_NON_ESP 2 /* draft-ietf-ipsec-nat-t-ike-02 */
-+#endif
-+
-+/*
-+ * Basic data types for the address-handling functions.
-+ * ip_address and ip_subnet are supposed to be opaque types; do not
-+ * use their definitions directly, they are subject to change!
-+ */
-+
-+/* first, some quick fakes in case we're on an old system with no IPv6 */
-+#ifndef s6_addr16
-+struct in6_addr {
-+ union
-+ {
-+ __u8 u6_addr8[16];
-+ __u16 u6_addr16[8];
-+ __u32 u6_addr32[4];
-+ } in6_u;
-+#define s6_addr in6_u.u6_addr8
-+#define s6_addr16 in6_u.u6_addr16
-+#define s6_addr32 in6_u.u6_addr32
-+};
-+struct sockaddr_in6 {
-+ unsigned short int sin6_family; /* AF_INET6 */
-+ __u16 sin6_port; /* Transport layer port # */
-+ __u32 sin6_flowinfo; /* IPv6 flow information */
-+ struct in6_addr sin6_addr; /* IPv6 address */
-+ __u32 sin6_scope_id; /* scope id (new in RFC2553) */
-+};
-+#endif /* !s6_addr16 */
-+
-+/* then the main types */
-+typedef struct {
-+ union {
-+ struct sockaddr_in v4;
-+ struct sockaddr_in6 v6;
-+ } u;
-+} ip_address;
-+typedef struct {
-+ ip_address addr;
-+ int maskbits;
-+} ip_subnet;
-+
-+/* and the SA ID stuff */
-+#ifdef __KERNEL__
-+typedef __u32 ipsec_spi_t;
-+#else
-+typedef u_int32_t ipsec_spi_t;
-+#endif
-+typedef struct { /* to identify an SA, we need: */
-+ ip_address dst; /* A. destination host */
-+ ipsec_spi_t spi; /* B. 32-bit SPI, assigned by dest. host */
-+# define SPI_PASS 256 /* magic values... */
-+# define SPI_DROP 257 /* ...for use... */
-+# define SPI_REJECT 258 /* ...with SA_INT */
-+# define SPI_HOLD 259
-+# define SPI_TRAP 260
-+# define SPI_TRAPSUBNET 261
-+ int proto; /* C. protocol */
-+# define SA_ESP 50 /* IPPROTO_ESP */
-+# define SA_AH 51 /* IPPROTO_AH */
-+# define SA_IPIP 4 /* IPPROTO_IPIP */
-+# define SA_COMP 108 /* IPPROTO_COMP */
-+# define SA_INT 61 /* IANA reserved for internal use */
-+} ip_said;
-+
-+/* misc */
-+typedef const char *err_t; /* error message, or NULL for success */
-+struct prng { /* pseudo-random-number-generator guts */
-+ unsigned char sbox[256];
-+ int i, j;
-+ unsigned long count;
-+};
-+
-+
-+/*
-+ * definitions for user space, taken from freeswan/ipsec_sa.h
-+ */
-+typedef uint32_t IPsecSAref_t;
-+
-+#define IPSEC_SA_REF_FIELD_WIDTH (8 * sizeof(IPsecSAref_t))
-+
-+#define IPsecSAref2NFmark(x) ((x) << (IPSEC_SA_REF_FIELD_WIDTH - IPSEC_SA_REF_TABLE_IDX_WIDTH))
-+#define NFmark2IPsecSAref(x) ((x) >> (IPSEC_SA_REF_FIELD_WIDTH - IPSEC_SA_REF_TABLE_IDX_WIDTH))
-+
-+#define IPSEC_SAREF_NULL (~((IPsecSAref_t)0))
-+
-+/* GCC magic for use in function definitions! */
-+#ifdef GCC_LINT
-+# define PRINTF_LIKE(n) __attribute__ ((format(printf, n, n+1)))
-+# define NEVER_RETURNS __attribute__ ((noreturn))
-+# define UNUSED __attribute__ ((unused))
-+# define BLANK_FORMAT " " /* GCC_LINT whines about empty formats */
-+#else
-+# define PRINTF_LIKE(n) /* ignore */
-+# define NEVER_RETURNS /* ignore */
-+# define UNUSED /* ignore */
-+# define BLANK_FORMAT ""
-+#endif
-+
-+
-+
-+
-+
-+/*
-+ * new IPv6-compatible functions
-+ */
-+
-+/* text conversions */
-+err_t ttoul(const char *src, size_t srclen, int format, unsigned long *dst);
-+size_t ultot(unsigned long src, int format, char *buf, size_t buflen);
-+#define ULTOT_BUF (22+1) /* holds 64 bits in octal */
-+err_t ttoaddr(const char *src, size_t srclen, int af, ip_address *dst);
-+err_t tnatoaddr(const char *src, size_t srclen, int af, ip_address *dst);
-+size_t addrtot(const ip_address *src, int format, char *buf, size_t buflen);
-+/* RFC 1886 old IPv6 reverse-lookup format is the bulkiest */
-+#define ADDRTOT_BUF (32*2 + 3 + 1 + 3 + 1 + 1)
-+err_t ttosubnet(const char *src, size_t srclen, int af, ip_subnet *dst);
-+size_t subnettot(const ip_subnet *src, int format, char *buf, size_t buflen);
-+#define SUBNETTOT_BUF (ADDRTOT_BUF + 1 + 3)
-+size_t subnetporttot(const ip_subnet *src, int format, char *buf, size_t buflen);
-+#define SUBNETPROTOTOT_BUF (SUBNETTOTO_BUF + ULTOT_BUF)
-+err_t ttosa(const char *src, size_t srclen, ip_said *dst);
-+size_t satot(const ip_said *src, int format, char *bufptr, size_t buflen);
-+#define SATOT_BUF (5 + ULTOA_BUF + 1 + ADDRTOT_BUF)
-+err_t ttodata(const char *src, size_t srclen, int base, char *buf,
-+ size_t buflen, size_t *needed);
-+err_t ttodatav(const char *src, size_t srclen, int base,
-+ char *buf, size_t buflen, size_t *needed,
-+ char *errp, size_t errlen, unsigned int flags);
-+#define TTODATAV_BUF 40 /* ttodatav's largest non-literal message */
-+#define TTODATAV_IGNORESPACE (1<<1) /* ignore spaces in base64 encodings*/
-+#define TTODATAV_SPACECOUNTS 0 /* do not ignore spaces in base64 */
-+
-+size_t datatot(const char *src, size_t srclen, int format, char *buf,
-+ size_t buflen);
-+size_t keyblobtoid(const unsigned char *src, size_t srclen, char *dst,
-+ size_t dstlen);
-+size_t splitkeytoid(const unsigned char *e, size_t elen, const unsigned char *m,
-+ size_t mlen, char *dst, size_t dstlen);
-+#define KEYID_BUF 10 /* up to 9 text digits plus NUL */
-+err_t ttoprotoport(char *src, size_t src_len, u_int8_t *proto, u_int16_t *port,
-+ int *has_port_wildcard);
-+
-+/* initializations */
-+void initsaid(const ip_address *addr, ipsec_spi_t spi, int proto, ip_said *dst);
-+err_t loopbackaddr(int af, ip_address *dst);
-+err_t unspecaddr(int af, ip_address *dst);
-+err_t anyaddr(int af, ip_address *dst);
-+err_t initaddr(const unsigned char *src, size_t srclen, int af, ip_address *dst);
-+err_t initsubnet(const ip_address *addr, int maskbits, int clash, ip_subnet *dst);
-+err_t addrtosubnet(const ip_address *addr, ip_subnet *dst);
-+
-+/* misc. conversions and related */
-+err_t rangetosubnet(const ip_address *from, const ip_address *to, ip_subnet *dst);
-+int addrtypeof(const ip_address *src);
-+int subnettypeof(const ip_subnet *src);
-+size_t addrlenof(const ip_address *src);
-+size_t addrbytesptr(const ip_address *src, const unsigned char **dst);
-+size_t addrbytesof(const ip_address *src, unsigned char *dst, size_t dstlen);
-+int masktocount(const ip_address *src);
-+void networkof(const ip_subnet *src, ip_address *dst);
-+void maskof(const ip_subnet *src, ip_address *dst);
-+
-+/* tests */
-+int sameaddr(const ip_address *a, const ip_address *b);
-+int addrcmp(const ip_address *a, const ip_address *b);
-+int samesubnet(const ip_subnet *a, const ip_subnet *b);
-+int addrinsubnet(const ip_address *a, const ip_subnet *s);
-+int subnetinsubnet(const ip_subnet *a, const ip_subnet *b);
-+int subnetishost(const ip_subnet *s);
-+int samesaid(const ip_said *a, const ip_said *b);
-+int sameaddrtype(const ip_address *a, const ip_address *b);
-+int samesubnettype(const ip_subnet *a, const ip_subnet *b);
-+int isanyaddr(const ip_address *src);
-+int isunspecaddr(const ip_address *src);
-+int isloopbackaddr(const ip_address *src);
-+
-+/* low-level grot */
-+int portof(const ip_address *src);
-+void setportof(int port, ip_address *dst);
-+struct sockaddr *sockaddrof(ip_address *src);
-+size_t sockaddrlenof(const ip_address *src);
-+
-+/* PRNG */
-+void prng_init(struct prng *prng, const unsigned char *key, size_t keylen);
-+void prng_bytes(struct prng *prng, unsigned char *dst, size_t dstlen);
-+unsigned long prng_count(struct prng *prng);
-+void prng_final(struct prng *prng);
-+
-+/* odds and ends */
-+const char *ipsec_version_code(void);
-+const char *ipsec_version_string(void);
-+const char **ipsec_copyright_notice(void);
-+
-+const char *dns_string_rr(int rr, char *buf, int bufsize);
-+const char *dns_string_datetime(time_t seconds,
-+ char *buf,
-+ int bufsize);
-+
-+
-+/*
-+ * old functions, to be deleted eventually
-+ */
-+
-+/* unsigned long */
-+const char * /* NULL for success, else string literal */
-+atoul(
-+ const char *src,
-+ size_t srclen, /* 0 means strlen(src) */
-+ int base, /* 0 means figure it out */
-+ unsigned long *resultp
-+);
-+size_t /* space needed for full conversion */
-+ultoa(
-+ unsigned long n,
-+ int base,
-+ char *dst,
-+ size_t dstlen
-+);
-+#define ULTOA_BUF 21 /* just large enough for largest result, */
-+ /* assuming 64-bit unsigned long! */
-+
-+/* Internet addresses */
-+const char * /* NULL for success, else string literal */
-+atoaddr(
-+ const char *src,
-+ size_t srclen, /* 0 means strlen(src) */
-+ struct in_addr *addr
-+);
-+size_t /* space needed for full conversion */
-+addrtoa(
-+ struct in_addr addr,
-+ int format, /* character; 0 means default */
-+ char *dst,
-+ size_t dstlen
-+);
-+#define ADDRTOA_BUF 16 /* just large enough for largest result */
-+
-+/* subnets */
-+const char * /* NULL for success, else string literal */
-+atosubnet(
-+ const char *src,
-+ size_t srclen, /* 0 means strlen(src) */
-+ struct in_addr *addr,
-+ struct in_addr *mask
-+);
-+size_t /* space needed for full conversion */
-+subnettoa(
-+ struct in_addr addr,
-+ struct in_addr mask,
-+ int format, /* character; 0 means default */
-+ char *dst,
-+ size_t dstlen
-+);
-+#define SUBNETTOA_BUF 32 /* large enough for worst case result */
-+
-+/* ranges */
-+const char * /* NULL for success, else string literal */
-+atoasr(
-+ const char *src,
-+ size_t srclen, /* 0 means strlen(src) */
-+ char *type, /* 'a', 's', 'r' */
-+ struct in_addr *addrs /* two-element array */
-+);
-+size_t /* space needed for full conversion */
-+rangetoa(
-+ struct in_addr *addrs, /* two-element array */
-+ int format, /* character; 0 means default */
-+ char *dst,
-+ size_t dstlen
-+);
-+#define RANGETOA_BUF 34 /* large enough for worst case result */
-+
-+/* data types for SA conversion functions */
-+
-+/* generic data, e.g. keys */
-+const char * /* NULL for success, else string literal */
-+atobytes(
-+ const char *src,
-+ size_t srclen, /* 0 means strlen(src) */
-+ char *dst,
-+ size_t dstlen,
-+ size_t *lenp /* NULL means don't bother telling me */
-+);
-+size_t /* 0 failure, else true size */
-+bytestoa(
-+ const char *src,
-+ size_t srclen,
-+ int format, /* character; 0 means default */
-+ char *dst,
-+ size_t dstlen
-+);
-+
-+/* old versions of generic-data functions; deprecated */
-+size_t /* 0 failure, else true size */
-+atodata(
-+ const char *src,
-+ size_t srclen, /* 0 means strlen(src) */
-+ char *dst,
-+ size_t dstlen
-+);
-+size_t /* 0 failure, else true size */
-+datatoa(
-+ const char *src,
-+ size_t srclen,
-+ int format, /* character; 0 means default */
-+ char *dst,
-+ size_t dstlen
-+);
-+
-+/* part extraction and special addresses */
-+struct in_addr
-+subnetof(
-+ struct in_addr addr,
-+ struct in_addr mask
-+);
-+struct in_addr
-+hostof(
-+ struct in_addr addr,
-+ struct in_addr mask
-+);
-+struct in_addr
-+broadcastof(
-+ struct in_addr addr,
-+ struct in_addr mask
-+);
-+
-+/* mask handling */
-+int
-+goodmask(
-+ struct in_addr mask
-+);
-+int
-+masktobits(
-+ struct in_addr mask
-+);
-+struct in_addr
-+bitstomask(
-+ int n
-+);
-+
-+
-+
-+/*
-+ * general utilities
-+ */
-+
-+#ifndef __KERNEL__
-+/* option pickup from files (userland only because of use of FILE) */
-+const char *optionsfrom(const char *filename, int *argcp, char ***argvp,
-+ int optind, FILE *errorreport);
-+
-+/* sanitize a string */
-+extern size_t sanitize_string(char *buf, size_t size);
-+
-+#endif
-+
-+
-+/*
-+ * ENUM of klips debugging values. Not currently used in klips.
-+ * debug flag is actually 32 -bits, but only one bit is ever used,
-+ * so we can actually pack it all into a single 32-bit word.
-+ */
-+enum klips_debug_flags {
-+ KDF_VERBOSE = 0,
-+ KDF_XMIT = 1,
-+ KDF_NETLINK = 2, /* obsolete */
-+ KDF_XFORM = 3,
-+ KDF_EROUTE = 4,
-+ KDF_SPI = 5,
-+ KDF_RADIJ = 6,
-+ KDF_ESP = 7,
-+ KDF_AH = 8, /* obsolete */
-+ KDF_RCV = 9,
-+ KDF_TUNNEL = 10,
-+ KDF_PFKEY = 11,
-+ KDF_COMP = 12
-+};
-+
-+
-+/*
-+ * Debugging levels for pfkey_lib_debug
-+ */
-+#define PF_KEY_DEBUG_PARSE_NONE 0
-+#define PF_KEY_DEBUG_PARSE_PROBLEM 1
-+#define PF_KEY_DEBUG_PARSE_STRUCT 2
-+#define PF_KEY_DEBUG_PARSE_FLOW 4
-+#define PF_KEY_DEBUG_BUILD 8
-+#define PF_KEY_DEBUG_PARSE_MAX 15
-+
-+extern unsigned int pfkey_lib_debug; /* bits selecting what to report */
-+
-+/*
-+ * pluto and lwdnsq need to know the maximum size of the commands to,
-+ * and replies from lwdnsq.
-+ */
-+
-+#define LWDNSQ_CMDBUF_LEN 1024
-+#define LWDNSQ_RESULT_LEN_MAX 4096
-+
-+
-+/* syntax for passthrough SA */
-+#ifndef PASSTHROUGHNAME
-+#define PASSTHROUGHNAME "%passthrough"
-+#define PASSTHROUGH4NAME "%passthrough4"
-+#define PASSTHROUGH6NAME "%passthrough6"
-+#define PASSTHROUGHIS "tun0@0.0.0.0"
-+#define PASSTHROUGH4IS "tun0@0.0.0.0"
-+#define PASSTHROUGH6IS "tun0@::"
-+#define PASSTHROUGHTYPE "tun"
-+#define PASSTHROUGHSPI 0
-+#define PASSTHROUGHDST 0
-+#endif
-+
-+
-+
-+#endif /* _OPENSWAN_H */
---- /dev/null Tue Mar 11 13:02:56 2003
-+++ linux/include/openswan/ipcomp.h Mon Feb 9 13:51:03 2004
-@@ -0,0 +1,61 @@
-+/*
-+ * IPCOMP zlib interface code.
-+ * Copyright (C) 2000 Svenning Soerensen <svenning@post5.tele.dk>
-+ * Copyright (C) 2000, 2001 Richard Guy Briggs <rgb@conscoop.ottawa.on.ca>
-+ *
-+ * 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. See <http://www.fsf.org/copyleft/gpl.txt>.
-+ *
-+ * 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.
-+
-+ RCSID $Id: ipcomp.h,v 1.13 2004/04/05 19:55:04 mcr Exp $
-+
-+ */
-+
-+/* SSS */
-+
-+#ifndef _IPCOMP_H
-+#define _IPCOMP_H
-+
-+/* Prefix all global deflate symbols with "ipcomp_" to avoid collisions with ppp_deflate & ext2comp */
-+#ifndef IPCOMP_PREFIX
-+#define IPCOMP_PREFIX
-+#endif /* IPCOMP_PREFIX */
-+
-+#ifndef IPPROTO_COMP
-+#define IPPROTO_COMP 108
-+#endif /* IPPROTO_COMP */
-+
-+#ifdef CONFIG_IPSEC_DEBUG
-+extern int sysctl_ipsec_debug_ipcomp;
-+#endif /* CONFIG_IPSEC_DEBUG */
-+
-+struct ipcomphdr { /* IPCOMP header */
-+ __u8 ipcomp_nh; /* Next header (protocol) */
-+ __u8 ipcomp_flags; /* Reserved, must be 0 */
-+ __u16 ipcomp_cpi; /* Compression Parameter Index */
-+};
-+
-+extern struct inet_protocol comp_protocol;
-+extern int sysctl_ipsec_debug_ipcomp;
-+
-+#define IPCOMP_UNCOMPRESSABLE 0x000000001
-+#define IPCOMP_COMPRESSIONERROR 0x000000002
-+#define IPCOMP_PARMERROR 0x000000004
-+#define IPCOMP_DECOMPRESSIONERROR 0x000000008
-+
-+#define IPCOMP_ADAPT_INITIAL_TRIES 8
-+#define IPCOMP_ADAPT_INITIAL_SKIP 4
-+#define IPCOMP_ADAPT_SUBSEQ_TRIES 2
-+#define IPCOMP_ADAPT_SUBSEQ_SKIP 8
-+
-+/* Function prototypes */
-+struct sk_buff *skb_compress(struct sk_buff *skb, struct ipsec_sa *ips, unsigned int *flags);
-+struct sk_buff *skb_decompress(struct sk_buff *skb, struct ipsec_sa *ips, unsigned int *flags);
-+
-+#endif /* _IPCOMP_H */
---- /dev/null Tue Mar 11 13:02:56 2003
-+++ linux/include/openswan/ipsec_ah.h Mon Feb 9 13:51:03 2004
-@@ -0,0 +1,190 @@
-+/*
-+ * Authentication Header declarations
-+ * Copyright (C) 1996, 1997 John Ioannidis.
-+ * Copyright (C) 1998, 1999, 2000, 2001 Richard Guy Briggs.
-+ *
-+ * 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. See <http://www.fsf.org/copyleft/gpl.txt>.
-+ *
-+ * 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.
-+ *
-+ * RCSID $Id: ipsec_ah.h,v 1.23 2004/04/05 19:55:04 mcr Exp $
-+ */
-+
-+#include "ipsec_md5h.h"
-+#include "ipsec_sha1.h"
-+
-+#ifndef IPPROTO_AH
-+#define IPPROTO_AH 51
-+#endif /* IPPROTO_AH */
-+
-+#include "ipsec_auth.h"
-+
-+#ifdef __KERNEL__
-+
-+extern struct inet_protocol ah_protocol;
-+
-+struct options;
-+
-+struct ahhdr /* Generic AH header */
-+{
-+ __u8 ah_nh; /* Next header (protocol) */
-+ __u8 ah_hl; /* AH length, in 32-bit words */
-+ __u16 ah_rv; /* reserved, must be 0 */
-+ __u32 ah_spi; /* Security Parameters Index */
-+ __u32 ah_rpl; /* Replay prevention */
-+ __u8 ah_data[AHHMAC_HASHLEN];/* Authentication hash */
-+};
-+#define AH_BASIC_LEN 8 /* basic AH header is 8 bytes, nh,hl,rv,spi
-+ * and the ah_hl, says how many bytes after that
-+ * to cover. */
-+
-+extern struct xform_functions ah_xform_funcs[];
-+
-+#ifdef CONFIG_IPSEC_DEBUG
-+extern int debug_ah;
-+#endif /* CONFIG_IPSEC_DEBUG */
-+#endif /* __KERNEL__ */
-+
-+/*
-+ * $Log: ipsec_ah.h,v $
-+ * Revision 1.23 2004/04/05 19:55:04 mcr
-+ * Moved from linux/include/freeswan/ipsec_ah.h,v
-+ *
-+ * Revision 1.22 2004/04/05 19:41:05 mcr
-+ * merged alg-branch code.
-+ *
-+ * Revision 1.21 2003/12/13 19:10:16 mcr
-+ * refactored rcv and xmit code - same as FS 2.05.
-+ *
-+ * Revision 1.22 2003/12/11 20:14:58 mcr
-+ * refactored the xmit code, to move all encapsulation
-+ * code into protocol functions. Note that all functions
-+ * are essentially done by a single function, which is probably
-+ * wrong.
-+ * the rcv_functions structures are renamed xform_functions.
-+ *
-+ * Revision 1.21 2003/12/06 21:21:19 mcr
-+ * split up receive path into per-transform files, for
-+ * easier later removal.
-+ *
-+ * Revision 1.20.8.1 2003/12/22 15:25:52 jjo
-+ * Merged algo-0.8.1-rc11-test1 into alg-branch
-+ *
-+ * Revision 1.20 2003/02/06 02:21:34 rgb
-+ *
-+ * Moved "struct auth_alg" from ipsec_rcv.c to ipsec_ah.h .
-+ * Changed "struct ah" to "struct ahhdr" and "struct esp" to "struct esphdr".
-+ * Removed "#ifdef INBOUND_POLICY_CHECK_eroute" dead code.
-+ *
-+ * Revision 1.19 2002/09/16 21:19:13 mcr
-+ * fixes for west-ah-icmp-01 - length of AH header must be
-+ * calculated properly, and next_header field properly copied.
-+ *
-+ * Revision 1.18 2002/05/14 02:37:02 rgb
-+ * Change reference from _TDB to _IPSA.
-+ *
-+ * Revision 1.17 2002/04/24 07:36:46 mcr
-+ * Moved from ./klips/net/ipsec/ipsec_ah.h,v
-+ *
-+ * Revision 1.16 2002/02/20 01:27:06 rgb
-+ * Ditched a pile of structs only used by the old Netlink interface.
-+ *
-+ * Revision 1.15 2001/12/11 02:35:57 rgb
-+ * Change "struct net_device" to "struct device" for 2.2 compatibility.
-+ *
-+ * Revision 1.14 2001/11/26 09:23:47 rgb
-+ * Merge MCR's ipsec_sa, eroute, proc and struct lifetime changes.
-+ *
-+ * Revision 1.13.2.1 2001/09/25 02:18:24 mcr
-+ * replace "struct device" with "struct netdevice"
-+ *
-+ * Revision 1.13 2001/06/14 19:35:08 rgb
-+ * Update copyright date.
-+ *
-+ * Revision 1.12 2000/09/12 03:21:20 rgb
-+ * Cleared out unused htonq.
-+ *
-+ * Revision 1.11 2000/09/08 19:12:55 rgb
-+ * Change references from DEBUG_IPSEC to CONFIG_IPSEC_DEBUG.
-+ *
-+ * Revision 1.10 2000/01/21 06:13:10 rgb
-+ * Tidied up spacing.
-+ * Added macros for HMAC padding magic numbers.(kravietz)
-+ *
-+ * Revision 1.9 1999/12/07 18:16:23 rgb
-+ * Fixed comments at end of #endif lines.
-+ *
-+ * Revision 1.8 1999/04/11 00:28:56 henry
-+ * GPL boilerplate
-+ *
-+ * Revision 1.7 1999/04/06 04:54:25 rgb
-+ * Fix/Add RCSID Id: and Log: bits to make PHMDs happy. This includes
-+ * patch shell fixes.
-+ *
-+ * Revision 1.6 1999/01/26 02:06:01 rgb
-+ * Removed CONFIG_IPSEC_ALGO_SWITCH macro.
-+ *
-+ * Revision 1.5 1999/01/22 06:17:49 rgb
-+ * Updated macro comments.
-+ * Added context types to support algorithm switch code.
-+ * 64-bit clean-up -- converting 'u long long' to __u64.
-+ *
-+ * Revision 1.4 1998/07/14 15:54:56 rgb
-+ * Add #ifdef __KERNEL__ to protect kernel-only structures.
-+ *
-+ * Revision 1.3 1998/06/30 18:05:16 rgb
-+ * Comment out references to htonq.
-+ *
-+ * Revision 1.2 1998/06/25 19:33:46 rgb
-+ * Add prototype for protocol receive function.
-+ * Rearrange for more logical layout.
-+ *
-+ * Revision 1.1 1998/06/18 21:27:43 henry
-+ * move sources from klips/src to klips/net/ipsec, to keep stupid
-+ * kernel-build scripts happier in the presence of symlinks
-+ *
-+ * Revision 1.4 1998/05/18 22:28:43 rgb
-+ * Disable key printing facilities from /proc/net/ipsec_*.
-+ *
-+ * Revision 1.3 1998/04/21 21:29:07 rgb
-+ * Rearrange debug switches to change on the fly debug output from user
-+ * space. Only kernel changes checked in at this time. radij.c was also
-+ * changed to temporarily remove buggy debugging code in rj_delete causing
-+ * an OOPS and hence, netlink device open errors.
-+ *
-+ * Revision 1.2 1998/04/12 22:03:17 rgb
-+ * Updated ESP-3DES-HMAC-MD5-96,
-+ * ESP-DES-HMAC-MD5-96,
-+ * AH-HMAC-MD5-96,
-+ * AH-HMAC-SHA1-96 since Henry started freeswan cvs repository
-+ * from old standards (RFC182[5-9] to new (as of March 1998) drafts.
-+ *
-+ * Fixed eroute references in /proc/net/ipsec*.
-+ *
-+ * Started to patch module unloading memory leaks in ipsec_netlink and
-+ * radij tree unloading.
-+ *
-+ * Revision 1.1 1998/04/09 03:05:55 henry
-+ * sources moved up from linux/net/ipsec
-+ *
-+ * Revision 1.1.1.1 1998/04/08 05:35:02 henry
-+ * RGB's ipsec-0.8pre2.tar.gz ipsec-0.8
-+ *
-+ * Revision 0.4 1997/01/15 01:28:15 ji
-+ * Added definitions for new AH transforms.
-+ *
-+ * Revision 0.3 1996/11/20 14:35:48 ji
-+ * Minor Cleanup.
-+ * Rationalized debugging code.
-+ *
-+ * Revision 0.2 1996/11/02 00:18:33 ji
-+ * First limited release.
-+ *
-+ *
-+ */
---- /dev/null Tue Mar 11 13:02:56 2003
-+++ linux/include/openswan/ipsec_alg.h Mon Feb 9 13:51:03 2004
-@@ -0,0 +1,260 @@
-+/*
-+ * Modular extensions service and registration functions interface
-+ *
-+ * Author: JuanJo Ciarlante <jjo-ipsec@mendoza.gov.ar>
-+ *
-+ * ipsec_alg.h,v 1.1.2.1 2003/11/21 18:12:23 jjo Exp
-+ *
-+ */
-+/*
-+ * 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. See <http://www.fsf.org/copyleft/gpl.txt>.
-+ *
-+ * 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.
-+ *
-+ */
-+#ifndef IPSEC_ALG_H
-+#define IPSEC_ALG_H
-+
-+/*
-+ * gcc >= 3.2 has removed __FUNCTION__, replaced by C99 __func__
-+ * *BUT* its a compiler variable.
-+ */
-+#if (__GNUC__ >= 3)
-+#ifndef __FUNCTION__
-+#define __FUNCTION__ __func__
-+#endif
-+#endif
-+
-+/* Version 0.8.1-0 */
-+#define IPSEC_ALG_VERSION 0x00080100
-+
-+#include <linux/types.h>
-+#include <linux/list.h>
-+#include <asm/atomic.h>
-+/*
-+ * The following structs are used via pointers in ipsec_alg object to
-+ * avoid ipsec_alg.h coupling with freeswan headers, thus simplifying
-+ * module development
-+ */
-+struct ipsec_sa;
-+struct esp;
-+
-+/**************************************
-+ *
-+ * Main registration object
-+ *
-+ *************************************/
-+#define IPSEC_ALG_VERSION_QUAD(v) \
-+ (v>>24),((v>>16)&0xff),((v>>8)&0xff),(v&0xff)
-+/*
-+ * Main ipsec_alg objects: "OOPrograming wannabe"
-+ * Hierachy (carefully handled with _minimal_ cast'ing):
-+ *
-+ * ipsec_alg+
-+ * +->ipsec_alg_enc (ixt_alg_type=SADB_EXT_SUPPORTED_ENCRYPT)
-+ * +->ipsec_alg_auth (ixt_alg_type=SADB_EXT_SUPPORTED_AUTH)
-+ */
-+
-+/***************************************************************
-+ *
-+ * INTERFACE object: struct ipsec_alg
-+ *
-+ ***************************************************************/
-+
-+/*
-+ * common part for every struct ipsec_alg_*
-+ * (sortof poor's man OOP)
-+ */
-+#define IPSEC_ALG_STRUCT_COMMON \
-+ unsigned ixt_version; /* only allow this version (or 'near')*/ \
-+ struct list_head ixt_list; /* dlinked list */ \
-+ struct module *ixt_module; /* THIS_MODULE */ \
-+ unsigned ixt_state; /* state flags */ \
-+ atomic_t ixt_refcnt; /* ref. count when pointed from ipsec_sa */ \
-+ char ixt_name[16]; /* descriptive short name, eg. "3des" */ \
-+ void *ixt_data; /* private for algo implementation */ \
-+ uint8_t ixt_blocksize; /* blocksize in bytes */ \
-+ \
-+ /* THIS IS A COPY of struct supported (lib/pfkey.h) \
-+ * please keep in sync until we migrate 'supported' stuff \
-+ * to ipsec_alg \
-+ */ \
-+ uint16_t ixt_alg_type; /* correspond to IPSEC_ALG_{ENCRYPT,AUTH} */ \
-+ uint8_t ixt_alg_id; /* enc. alg. number, eg. ESP_3DES */ \
-+ uint8_t ixt_ivlen; /* ivlen in bits, expected to be multiple of 8! */ \
-+ uint16_t ixt_keyminbits;/* min. keybits (of entropy) */ \
-+ uint16_t ixt_keymaxbits;/* max. keybits (of entropy) */
-+
-+#define ixt_support ixt_alg_type
-+
-+#define IPSEC_ALG_ST_SUPP 0x01
-+#define IPSEC_ALG_ST_REGISTERED 0x02
-+#define IPSEC_ALG_ST_EXCL 0x04
-+struct ipsec_alg {
-+ IPSEC_ALG_STRUCT_COMMON
-+};
-+/*
-+ * Note the const in cbc_encrypt IV arg:
-+ * some ciphers like to toast passed IV (eg. 3DES): make a local IV copy
-+ */
-+struct ipsec_alg_enc {
-+ IPSEC_ALG_STRUCT_COMMON
-+ unsigned ixt_e_keylen; /* raw key length in bytes */
-+ unsigned ixt_e_ctx_size; /* sa_p->key_e_size */
-+ int (*ixt_e_set_key)(struct ipsec_alg_enc *alg, __u8 *key_e, const __u8 *key, size_t keysize);
-+ __u8 *(*ixt_e_new_key)(struct ipsec_alg_enc *alg, const __u8 *key, size_t keysize);
-+ void (*ixt_e_destroy_key)(struct ipsec_alg_enc *alg, __u8 *key_e);
-+ int (*ixt_e_cbc_encrypt)(struct ipsec_alg_enc *alg, __u8 *key_e, __u8 *in, int ilen, const __u8 *iv, int encrypt);
-+};
-+struct ipsec_alg_auth {
-+ IPSEC_ALG_STRUCT_COMMON
-+ unsigned ixt_a_keylen; /* raw key length in bytes */
-+ unsigned ixt_a_ctx_size; /* sa_p->key_a_size */
-+ unsigned ixt_a_authlen; /* 'natural' auth. hash len (bytes) */
-+ int (*ixt_a_hmac_set_key)(struct ipsec_alg_auth *alg, __u8 *key_a, const __u8 *key, int keylen);
-+ int (*ixt_a_hmac_hash)(struct ipsec_alg_auth *alg, __u8 *key_a, const __u8 *dat, int len, __u8 *hash, int hashlen);
-+};
-+/*
-+ * These are _copies_ of SADB_EXT_SUPPORTED_{AUTH,ENCRYPT},
-+ * to avoid header coupling for true constants
-+ * about headers ... "cp is your friend" --Linus
-+ */
-+#define IPSEC_ALG_TYPE_AUTH 14
-+#define IPSEC_ALG_TYPE_ENCRYPT 15
-+
-+/***************************************************************
-+ *
-+ * INTERFACE for module loading,testing, and unloading
-+ *
-+ ***************************************************************/
-+/* - registration calls */
-+int register_ipsec_alg(struct ipsec_alg *);
-+int unregister_ipsec_alg(struct ipsec_alg *);
-+/* - optional (simple test) for algos */
-+int ipsec_alg_test(unsigned alg_type, unsigned alg_id, int testparm);
-+/* inline wrappers (usefull for type validation */
-+static inline int register_ipsec_alg_enc(struct ipsec_alg_enc *ixt) {
-+ return register_ipsec_alg((struct ipsec_alg*)ixt);
-+}
-+static inline int unregister_ipsec_alg_enc(struct ipsec_alg_enc *ixt) {
-+ return unregister_ipsec_alg((struct ipsec_alg*)ixt);
-+}
-+static inline int register_ipsec_alg_auth(struct ipsec_alg_auth *ixt) {
-+ return register_ipsec_alg((struct ipsec_alg*)ixt);
-+}
-+static inline int unregister_ipsec_alg_auth(struct ipsec_alg_auth *ixt) {
-+ return unregister_ipsec_alg((struct ipsec_alg*)ixt);
-+}
-+
-+/*****************************************************************
-+ *
-+ * INTERFACE for ENC services: key creation, encrypt function
-+ *
-+ *****************************************************************/
-+
-+#define IPSEC_ALG_ENCRYPT 1
-+#define IPSEC_ALG_DECRYPT 0
-+
-+/* encryption key context creation function */
-+int ipsec_alg_enc_key_create(struct ipsec_sa *sa_p);
-+/*
-+ * ipsec_alg_esp_encrypt(): encrypt ilen bytes in idat returns
-+ * 0 or ERR<0
-+ */
-+int ipsec_alg_esp_encrypt(struct ipsec_sa *sa_p, __u8 *idat, int ilen, const __u8 *iv, int action);
-+
-+/***************************************************************
-+ *
-+ * INTERFACE for AUTH services: key creation, hash functions
-+ *
-+ ***************************************************************/
-+int ipsec_alg_auth_key_create(struct ipsec_sa *sa_p);
-+int ipsec_alg_sa_esp_hash(const struct ipsec_sa *sa_p, const __u8 *espp, int len, __u8 *hash, int hashlen) ;
-+#define ipsec_alg_sa_esp_update(c,k,l) ipsec_alg_sa_esp_hash(c,k,l,NULL,0)
-+
-+/* only called from ipsec_init.c */
-+int ipsec_alg_init(void);
-+
-+/* algo module glue for static algos */
-+void ipsec_alg_static_init(void);
-+typedef int (*ipsec_alg_init_func_t) (void);
-+
-+/**********************************************
-+ *
-+ * INTERFACE for ipsec_sa init and wipe
-+ *
-+ **********************************************/
-+
-+/* returns true if ipsec_sa has ipsec_alg obj attached */
-+/*
-+ * Initializes ipsec_sa's ipsec_alg object, using already loaded
-+ * proto, authalg, encalg.; links ipsec_alg objects (enc, auth)
-+ */
-+int ipsec_alg_sa_init(struct ipsec_sa *sa_p);
-+/*
-+ * Destroys ipsec_sa's ipsec_alg object
-+ * unlinking ipsec_alg objects
-+ */
-+int ipsec_alg_sa_wipe(struct ipsec_sa *sa_p);
-+
-+#define IPSEC_ALG_MODULE_INIT_MOD( func_name ) \
-+ static int func_name(void); \
-+ module_init(func_name); \
-+ static int __init func_name(void)
-+#define IPSEC_ALG_MODULE_EXIT_MOD( func_name ) \
-+ static void func_name(void); \
-+ module_exit(func_name); \
-+ static void __exit func_name(void)
-+
-+#define IPSEC_ALG_MODULE_INIT_STATIC( func_name ) \
-+ extern int func_name(void); \
-+ int func_name(void)
-+#define IPSEC_ALG_MODULE_EXIT_STATIC( func_name ) \
-+ extern void func_name(void); \
-+ void func_name(void)
-+
-+/**********************************************
-+ *
-+ * 2.2 backport for some 2.4 useful module stuff
-+ *
-+ **********************************************/
-+#ifdef MODULE
-+#ifndef THIS_MODULE
-+#define THIS_MODULE (&__this_module)
-+#endif
-+#ifndef module_init
-+typedef int (*__init_module_func_t)(void);
-+typedef void (*__cleanup_module_func_t)(void);
-+
-+#define module_init(x) \
-+ int init_module(void) __attribute__((alias(#x))); \
-+ static inline __init_module_func_t __init_module_inline(void) \
-+ { return x; }
-+#define module_exit(x) \
-+ void cleanup_module(void) __attribute__((alias(#x))); \
-+ static inline __cleanup_module_func_t __cleanup_module_inline(void) \
-+ { return x; }
-+#endif
-+#define IPSEC_ALG_MODULE_INIT( func_name ) IPSEC_ALG_MODULE_INIT_MOD( func_name )
-+#define IPSEC_ALG_MODULE_EXIT( func_name ) IPSEC_ALG_MODULE_EXIT_MOD( func_name )
-+
-+#else /* not MODULE */
-+#ifndef THIS_MODULE
-+#define THIS_MODULE NULL
-+#endif
-+/*
-+ * I only want module_init() magic
-+ * when algo.c file *is THE MODULE*, in all other
-+ * cases, initialization is called explicitely from ipsec_alg_init()
-+ */
-+#define IPSEC_ALG_MODULE_INIT( func_name ) IPSEC_ALG_MODULE_INIT_STATIC(func_name)
-+#define IPSEC_ALG_MODULE_EXIT( func_name ) IPSEC_ALG_MODULE_EXIT_STATIC(func_name)
-+#endif
-+
-+#endif /* IPSEC_ALG_H */
---- /dev/null Tue Mar 11 13:02:56 2003
-+++ linux/include/openswan/ipsec_auth.h Mon Feb 9 13:51:03 2004
-@@ -0,0 +1,100 @@
-+/*
-+ * Authentication Header declarations
-+ * Copyright (C) 2003 Michael Richardson <mcr@sandelman.ottawa.on.ca>
-+ *
-+ * 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. See <http://www.fsf.org/copyleft/gpl.txt>.
-+ *
-+ * 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.
-+ *
-+ * RCSID $Id: ipsec_auth.h,v 1.3 2004/04/06 02:49:08 mcr Exp $
-+ */
-+
-+#include "ipsec_md5h.h"
-+#include "ipsec_sha1.h"
-+
-+#ifndef IPSEC_AUTH_H
-+#define IPSEC_AUTH_H
-+
-+#define AH_FLENGTH 12 /* size of fixed part */
-+#define AHMD5_KMAX 64 /* MD5 max 512 bits key */
-+#define AHMD5_AMAX 12 /* MD5 96 bits of authenticator */
-+
-+#define AHMD596_KLEN 16 /* MD5 128 bits key */
-+#define AHSHA196_KLEN 20 /* SHA1 160 bits key */
-+
-+#define AHMD596_ALEN 16 /* MD5 128 bits authentication length */
-+#define AHSHA196_ALEN 20 /* SHA1 160 bits authentication length */
-+
-+#define AHMD596_BLKLEN 64 /* MD5 block length */
-+#define AHSHA196_BLKLEN 64 /* SHA1 block length */
-+#define AHSHA2_256_BLKLEN 64 /* SHA2-256 block length */
-+#define AHSHA2_384_BLKLEN 128 /* SHA2-384 block length (?) */
-+#define AHSHA2_512_BLKLEN 128 /* SHA2-512 block length */
-+
-+#define AH_BLKLEN_MAX 128 /* keep up to date! */
-+
-+
-+#define AH_AMAX AHSHA196_ALEN /* keep up to date! */
-+#define AHHMAC_HASHLEN 12 /* authenticator length of 96bits */
-+#define AHHMAC_RPLLEN 4 /* 32 bit replay counter */
-+
-+#define DB_AH_PKTRX 0x0001
-+#define DB_AH_PKTRX2 0x0002
-+#define DB_AH_DMP 0x0004
-+#define DB_AH_IPSA 0x0010
-+#define DB_AH_XF 0x0020
-+#define DB_AH_INAU 0x0040
-+#define DB_AH_REPLAY 0x0100
-+
-+#ifdef __KERNEL__
-+
-+/* General HMAC algorithm is described in RFC 2104 */
-+
-+#define HMAC_IPAD 0x36
-+#define HMAC_OPAD 0x5C
-+
-+struct md5_ctx {
-+ MD5_CTX ictx; /* context after H(K XOR ipad) */
-+ MD5_CTX octx; /* context after H(K XOR opad) */
-+};
-+
-+struct sha1_ctx {
-+ SHA1_CTX ictx; /* context after H(K XOR ipad) */
-+ SHA1_CTX octx; /* context after H(K XOR opad) */
-+};
-+
-+struct auth_alg {
-+ void (*init)(void *ctx);
-+ void (*update)(void *ctx, unsigned char *bytes, __u32 len);
-+ void (*final)(unsigned char *hash, void *ctx);
-+ int hashlen;
-+};
-+
-+struct options;
-+
-+#endif /* __KERNEL__ */
-+#endif /* IPSEC_AUTH_H */
-+
-+/*
-+ * $Log: ipsec_auth.h,v $
-+ * Revision 1.3 2004/04/06 02:49:08 mcr
-+ * pullup of algo code from alg-branch.
-+ *
-+ * Revision 1.2 2004/04/05 19:55:04 mcr
-+ * Moved from linux/include/freeswan/ipsec_auth.h,v
-+ *
-+ * Revision 1.1 2003/12/13 19:10:16 mcr
-+ * refactored rcv and xmit code - same as FS 2.05.
-+ *
-+ * Revision 1.1 2003/12/06 21:21:19 mcr
-+ * split up receive path into per-transform files, for
-+ * easier later removal.
-+ *
-+ *
-+ */
---- /dev/null Tue Mar 11 13:02:56 2003
-+++ linux/include/openswan/ipsec_encap.h Mon Feb 9 13:51:03 2004
-@@ -0,0 +1,149 @@
-+/*
-+ * declarations relevant to encapsulation-like operations
-+ * Copyright (C) 1996, 1997 John Ioannidis.
-+ * Copyright (C) 1998, 1999, 2000, 2001 Richard Guy Briggs.
-+ *
-+ * 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. See <http://www.fsf.org/copyleft/gpl.txt>.
-+ *
-+ * 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.
-+ *
-+ * RCSID $Id: ipsec_encap.h,v 1.19 2004/04/05 19:55:04 mcr Exp $
-+ */
-+
-+#ifndef _IPSEC_ENCAP_H_
-+
-+#define SENT_IP4 16 /* data is two struct in_addr + proto + ports*/
-+ /* (2 * sizeof(struct in_addr)) */
-+ /* sizeof(struct sockaddr_encap)
-+ - offsetof(struct sockaddr_encap, Sen.Sip4.Src) */
-+
-+struct sockaddr_encap
-+{
-+ __u8 sen_len; /* length */
-+ __u8 sen_family; /* AF_ENCAP */
-+ __u16 sen_type; /* see SENT_* */
-+ union
-+ {
-+ struct /* SENT_IP4 */
-+ {
-+ struct in_addr Src;
-+ struct in_addr Dst;
-+ __u8 Proto;
-+ __u16 Sport;
-+ __u16 Dport;
-+ } Sip4;
-+ } Sen;
-+};
-+
-+#define sen_ip_src Sen.Sip4.Src
-+#define sen_ip_dst Sen.Sip4.Dst
-+#define sen_proto Sen.Sip4.Proto
-+#define sen_sport Sen.Sip4.Sport
-+#define sen_dport Sen.Sip4.Dport
-+
-+#ifndef AF_ENCAP
-+#define AF_ENCAP 26
-+#endif /* AF_ENCAP */
-+
-+#define _IPSEC_ENCAP_H_
-+#endif /* _IPSEC_ENCAP_H_ */
-+
-+/*
-+ * $Log: ipsec_encap.h,v $
-+ * Revision 1.19 2004/04/05 19:55:04 mcr
-+ * Moved from linux/include/freeswan/ipsec_encap.h,v
-+ *
-+ * Revision 1.18 2003/10/31 02:27:05 mcr
-+ * pulled up port-selector patches and sa_id elimination.
-+ *
-+ * Revision 1.17.30.1 2003/09/21 13:59:38 mcr
-+ * pre-liminary X.509 patch - does not yet pass tests.
-+ *
-+ * Revision 1.17 2002/04/24 07:36:46 mcr
-+ * Moved from ./klips/net/ipsec/ipsec_encap.h,v
-+ *
-+ * Revision 1.16 2001/11/26 09:23:47 rgb
-+ * Merge MCR's ipsec_sa, eroute, proc and struct lifetime changes.
-+ *
-+ * Revision 1.15.2.1 2001/09/25 02:18:54 mcr
-+ * struct eroute moved to ipsec_eroute.h
-+ *
-+ * Revision 1.15 2001/09/14 16:58:36 rgb
-+ * Added support for storing the first and last packets through a HOLD.
-+ *
-+ * Revision 1.14 2001/09/08 21:13:31 rgb
-+ * Added pfkey ident extension support for ISAKMPd. (NetCelo)
-+ *
-+ * Revision 1.13 2001/06/14 19:35:08 rgb
-+ * Update copyright date.
-+ *
-+ * Revision 1.12 2001/05/27 06:12:10 rgb
-+ * Added structures for pid, packet count and last access time to eroute.
-+ * Added packet count to beginning of /proc/net/ipsec_eroute.
-+ *
-+ * Revision 1.11 2000/09/08 19:12:56 rgb
-+ * Change references from DEBUG_IPSEC to CONFIG_IPSEC_DEBUG.
-+ *
-+ * Revision 1.10 2000/03/22 16:15:36 rgb
-+ * Fixed renaming of dev_get (MB).
-+ *
-+ * Revision 1.9 2000/01/21 06:13:26 rgb
-+ * Added a macro for AF_ENCAP
-+ *
-+ * Revision 1.8 1999/12/31 14:56:55 rgb
-+ * MB fix for 2.3 dev-use-count.
-+ *
-+ * Revision 1.7 1999/11/18 04:09:18 rgb
-+ * Replaced all kernel version macros to shorter, readable form.
-+ *
-+ * Revision 1.6 1999/09/24 00:34:13 rgb
-+ * Add Marc Boucher's support for 2.3.xx+.
-+ *
-+ * Revision 1.5 1999/04/11 00:28:57 henry
-+ * GPL boilerplate
-+ *
-+ * Revision 1.4 1999/04/06 04:54:25 rgb
-+ * Fix/Add RCSID Id: and Log: bits to make PHMDs happy. This includes
-+ * patch shell fixes.
-+ *
-+ * Revision 1.3 1998/10/19 14:44:28 rgb
-+ * Added inclusion of freeswan.h.
-+ * sa_id structure implemented and used: now includes protocol.
-+ *
-+ * Revision 1.2 1998/07/14 18:19:33 rgb
-+ * Added #ifdef __KERNEL__ directives to restrict scope of header.
-+ *
-+ * Revision 1.1 1998/06/18 21:27:44 henry
-+ * move sources from klips/src to klips/net/ipsec, to keep stupid
-+ * kernel-build scripts happier in the presence of symlinks
-+ *
-+ * Revision 1.2 1998/04/21 21:29:10 rgb
-+ * Rearrange debug switches to change on the fly debug output from user
-+ * space. Only kernel changes checked in at this time. radij.c was also
-+ * changed to temporarily remove buggy debugging code in rj_delete causing
-+ * an OOPS and hence, netlink device open errors.
-+ *
-+ * Revision 1.1 1998/04/09 03:05:58 henry
-+ * sources moved up from linux/net/ipsec
-+ *
-+ * Revision 1.1.1.1 1998/04/08 05:35:02 henry
-+ * RGB's ipsec-0.8pre2.tar.gz ipsec-0.8
-+ *
-+ * Revision 0.4 1997/01/15 01:28:15 ji
-+ * Minor cosmetic changes.
-+ *
-+ * Revision 0.3 1996/11/20 14:35:48 ji
-+ * Minor Cleanup.
-+ * Rationalized debugging code.
-+ *
-+ * Revision 0.2 1996/11/02 00:18:33 ji
-+ * First limited release.
-+ *
-+ *
-+ */
---- /dev/null Tue Mar 11 13:02:56 2003
-+++ linux/include/openswan/ipsec_eroute.h Mon Feb 9 13:51:03 2004
-@@ -0,0 +1,112 @@
-+/*
-+ * @(#) declarations of eroute structures
-+ *
-+ * Copyright (C) 1996, 1997 John Ioannidis.
-+ * Copyright (C) 1998, 1999, 2000, 2001 Richard Guy Briggs <rgb@freeswan.org>
-+ * Copyright (C) 2001 Michael Richardson <mcr@freeswan.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. See <http://www.fsf.org/copyleft/gpl.txt>.
-+ *
-+ * 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.
-+ *
-+ * RCSID $Id: ipsec_eroute.h,v 1.5 2004/04/05 19:55:05 mcr Exp $
-+ *
-+ * derived from ipsec_encap.h 1.15 on 2001/9/18 by mcr.
-+ *
-+ */
-+
-+#ifndef _IPSEC_EROUTE_H_
-+
-+#include "radij.h"
-+#include "ipsec_encap.h"
-+#include "ipsec_radij.h"
-+
-+/*
-+ * The "type" is really part of the address as far as the routing
-+ * system is concerned. By using only one bit in the type field
-+ * for each type, we sort-of make sure that different types of
-+ * encapsulation addresses won't be matched against the wrong type.
-+ */
-+
-+/*
-+ * An entry in the radix tree
-+ */
-+
-+struct rjtentry
-+{
-+ struct radij_node rd_nodes[2]; /* tree glue, and other values */
-+#define rd_key(r) ((struct sockaddr_encap *)((r)->rd_nodes->rj_key))
-+#define rd_mask(r) ((struct sockaddr_encap *)((r)->rd_nodes->rj_mask))
-+ short rd_flags;
-+ short rd_count;
-+};
-+
-+struct ident
-+{
-+ __u16 type; /* identity type */
-+ __u64 id; /* identity id */
-+ __u8 len; /* identity len */
-+ caddr_t data; /* identity data */
-+};
-+
-+/*
-+ * An encapsulation route consists of a pointer to a
-+ * radix tree entry and a SAID (a destination_address/SPI/protocol triple).
-+ */
-+
-+struct eroute
-+{
-+ struct rjtentry er_rjt;
-+ ip_said er_said;
-+ uint32_t er_pid;
-+ uint32_t er_count;
-+ uint64_t er_lasttime;
-+ struct sockaddr_encap er_eaddr; /* MCR get rid of _encap, it is silly*/
-+ struct sockaddr_encap er_emask;
-+ struct ident er_ident_s;
-+ struct ident er_ident_d;
-+ struct sk_buff* er_first;
-+ struct sk_buff* er_last;
-+};
-+
-+#define er_dst er_said.dst
-+#define er_spi er_said.spi
-+
-+#define _IPSEC_EROUTE_H_
-+#endif /* _IPSEC_EROUTE_H_ */
-+
-+/*
-+ * $Log: ipsec_eroute.h,v $
-+ * Revision 1.5 2004/04/05 19:55:05 mcr
-+ * Moved from linux/include/freeswan/ipsec_eroute.h,v
-+ *
-+ * Revision 1.4 2003/10/31 02:27:05 mcr
-+ * pulled up port-selector patches and sa_id elimination.
-+ *
-+ * Revision 1.3.30.2 2003/10/29 01:10:19 mcr
-+ * elimited "struct sa_id"
-+ *
-+ * Revision 1.3.30.1 2003/09/21 13:59:38 mcr
-+ * pre-liminary X.509 patch - does not yet pass tests.
-+ *
-+ * Revision 1.3 2002/04/24 07:36:46 mcr
-+ * Moved from ./klips/net/ipsec/ipsec_eroute.h,v
-+ *
-+ * Revision 1.2 2001/11/26 09:16:13 rgb
-+ * Merge MCR's ipsec_sa, eroute, proc and struct lifetime changes.
-+ *
-+ * Revision 1.1.2.1 2001/09/25 02:18:54 mcr
-+ * struct eroute moved to ipsec_eroute.h
-+ *
-+ *
-+ * Local variables:
-+ * c-file-style: "linux"
-+ * End:
-+ *
-+ */
---- /dev/null Tue Mar 11 13:02:56 2003
-+++ linux/include/openswan/ipsec_errs.h Mon Feb 9 13:51:03 2004
-@@ -0,0 +1,53 @@
-+/*
-+ * @(#) definition of ipsec_errs structure
-+ *
-+ * Copyright (C) 2001 Richard Guy Briggs <rgb@freeswan.org>
-+ * and Michael Richardson <mcr@freeswan.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. See <http://www.fsf.org/copyleft/gpl.txt>.
-+ *
-+ * 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.
-+ *
-+ * RCSID $Id: ipsec_errs.h,v 1.4 2004/04/05 19:55:05 mcr Exp $
-+ *
-+ */
-+
-+/*
-+ * This file describes the errors/statistics that FreeSWAN collects.
-+ *
-+ */
-+
-+struct ipsec_errs {
-+ __u32 ips_alg_errs; /* number of algorithm errors */
-+ __u32 ips_auth_errs; /* # of authentication errors */
-+ __u32 ips_encsize_errs; /* # of encryption size errors*/
-+ __u32 ips_encpad_errs; /* # of encryption pad errors*/
-+ __u32 ips_replaywin_errs; /* # of pkt sequence errors */
-+};
-+
-+/*
-+ * $Log: ipsec_errs.h,v $
-+ * Revision 1.4 2004/04/05 19:55:05 mcr
-+ * Moved from linux/include/freeswan/ipsec_errs.h,v
-+ *
-+ * Revision 1.3 2002/04/24 07:36:46 mcr
-+ * Moved from ./klips/net/ipsec/ipsec_errs.h,v
-+ *
-+ * Revision 1.2 2001/11/26 09:16:13 rgb
-+ * Merge MCR's ipsec_sa, eroute, proc and struct lifetime changes.
-+ *
-+ * Revision 1.1.2.1 2001/09/25 02:25:57 mcr
-+ * lifetime structure created and common functions created.
-+ *
-+ *
-+ * Local variables:
-+ * c-file-style: "linux"
-+ * End:
-+ *
-+ */
---- /dev/null Tue Mar 11 13:02:56 2003
-+++ linux/include/openswan/ipsec_esp.h Mon Feb 9 13:51:03 2004
-@@ -0,0 +1,147 @@
-+/*
-+ * Copyright (C) 1996, 1997 John Ioannidis.
-+ * Copyright (C) 1998, 1999, 2000, 2001 Richard Guy Briggs.
-+ *
-+ * 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. See <http://www.fsf.org/copyleft/gpl.txt>.
-+ *
-+ * 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.
-+ *
-+ * RCSID $Id: ipsec_esp.h,v 1.25 2004/04/06 02:49:08 mcr Exp $
-+ */
-+
-+#include "openswan/ipsec_md5h.h"
-+#include "openswan/ipsec_sha1.h"
-+
-+#include "crypto/des.h"
-+
-+#ifndef IPPROTO_ESP
-+#define IPPROTO_ESP 50
-+#endif /* IPPROTO_ESP */
-+
-+#define ESP_HEADER_LEN 8 /* 64 bits header (spi+rpl)*/
-+
-+#define EMT_ESPDESCBC_ULEN 20 /* coming from user mode */
-+#define EMT_ESPDES_KMAX 64 /* 512 bit secret key enough? */
-+#define EMT_ESPDES_KEY_SZ 8 /* 56 bit secret key with parity = 64 bits */
-+#define EMT_ESP3DES_KEY_SZ 24 /* 168 bit secret key with parity = 192 bits */
-+#define EMT_ESPDES_IV_SZ 8 /* IV size */
-+#define ESP_DESCBC_BLKLEN 8 /* DES-CBC block size */
-+
-+#define ESP_IV_MAXSZ 16 /* This is _critical_ */
-+#define ESP_IV_MAXSZ_INT (ESP_IV_MAXSZ/sizeof(int))
-+
-+#define DB_ES_PKTRX 0x0001
-+#define DB_ES_PKTRX2 0x0002
-+#define DB_ES_IPSA 0x0010
-+#define DB_ES_XF 0x0020
-+#define DB_ES_IPAD 0x0040
-+#define DB_ES_INAU 0x0080
-+#define DB_ES_OINFO 0x0100
-+#define DB_ES_OINFO2 0x0200
-+#define DB_ES_OH 0x0400
-+#define DB_ES_REPLAY 0x0800
-+
-+#ifdef __KERNEL__
-+struct des_eks {
-+ des_key_schedule ks;
-+};
-+
-+extern struct inet_protocol esp_protocol;
-+
-+struct options;
-+
-+struct esphdr
-+{
-+ __u32 esp_spi; /* Security Parameters Index */
-+ __u32 esp_rpl; /* Replay counter */
-+ __u8 esp_iv[8]; /* iv */
-+};
-+
-+extern struct xform_functions esp_xform_funcs[];
-+
-+#ifdef CONFIG_IPSEC_DEBUG
-+extern int debug_esp;
-+#endif /* CONFIG_IPSEC_DEBUG */
-+#endif /* __KERNEL__ */
-+
-+/*
-+ * $Log: ipsec_esp.h,v $
-+ * Revision 1.25 2004/04/06 02:49:08 mcr
-+ * pullup of algo code from alg-branch.
-+ *
-+ * Revision 1.24 2004/04/05 19:55:05 mcr
-+ * Moved from linux/include/freeswan/ipsec_esp.h,v
-+ *
-+ * Revision 1.23 2004/04/05 19:41:05 mcr
-+ * merged alg-branch code.
-+ *
-+ * Revision 1.22 2003/12/13 19:10:16 mcr
-+ * refactored rcv and xmit code - same as FS 2.05.
-+ *
-+ * Revision 1.23 2003/12/11 20:14:58 mcr
-+ * refactored the xmit code, to move all encapsulation
-+ * code into protocol functions. Note that all functions
-+ * are essentially done by a single function, which is probably
-+ * wrong.
-+ * the rcv_functions structures are renamed xform_functions.
-+ *
-+ * Revision 1.22 2003/12/06 21:21:19 mcr
-+ * split up receive path into per-transform files, for
-+ * easier later removal.
-+ *
-+ * Revision 1.21.8.1 2003/12/22 15:25:52 jjo
-+ * Merged algo-0.8.1-rc11-test1 into alg-branch
-+ *
-+ * Revision 1.21 2003/02/06 02:21:34 rgb
-+ *
-+ * Moved "struct auth_alg" from ipsec_rcv.c to ipsec_ah.h .
-+ * Changed "struct ah" to "struct ahhdr" and "struct esp" to "struct esphdr".
-+ * Removed "#ifdef INBOUND_POLICY_CHECK_eroute" dead code.
-+ *
-+ * Revision 1.20 2002/05/14 02:37:02 rgb
-+ * Change reference from _TDB to _IPSA.
-+ *
-+ * Revision 1.19 2002/04/24 07:55:32 mcr
-+ * #include patches and Makefiles for post-reorg compilation.
-+ *
-+ * Revision 1.18 2002/04/24 07:36:46 mcr
-+ * Moved from ./klips/net/ipsec/ipsec_esp.h,v
-+ *
-+ * Revision 1.17 2002/02/20 01:27:07 rgb
-+ * Ditched a pile of structs only used by the old Netlink interface.
-+ *
-+ * Revision 1.16 2001/12/11 02:35:57 rgb
-+ * Change "struct net_device" to "struct device" for 2.2 compatibility.
-+ *
-+ * Revision 1.15 2001/11/26 09:23:48 rgb
-+ * Merge MCR's ipsec_sa, eroute, proc and struct lifetime changes.
-+ *
-+ * Revision 1.14.2.3 2001/10/23 04:16:42 mcr
-+ * get definition of des_key_schedule from des.h
-+ *
-+ * Revision 1.14.2.2 2001/10/22 20:33:13 mcr
-+ * use "des_key_schedule" structure instead of cooking our own.
-+ *
-+ * Revision 1.14.2.1 2001/09/25 02:18:25 mcr
-+ * replace "struct device" with "struct netdevice"
-+ *
-+ * Revision 1.14 2001/06/14 19:35:08 rgb
-+ * Update copyright date.
-+ *
-+ * Revision 1.13 2000/09/08 19:12:56 rgb
-+ * Change references from DEBUG_IPSEC to CONFIG_IPSEC_DEBUG.
-+ *
-+ * Revision 1.12 2000/08/01 14:51:50 rgb
-+ * Removed _all_ remaining traces of DES.
-+ *
-+ * Revision 1.11 2000/01/10 16:36:20 rgb
-+ * Ditch last of EME option flags, including initiator.
-+ *
-+ *
-+ */
---- /dev/null Tue Mar 11 13:02:56 2003
-+++ linux/include/openswan/ipsec_ipcomp.h Mon Feb 9 13:51:03 2004
-@@ -0,0 +1,91 @@
-+/*
-+ * IP compression header declations
-+ *
-+ * Copyright (C) 2003 Michael Richardson <mcr@sandelman.ottawa.on.ca>
-+ *
-+ * 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. See <http://www.fsf.org/copyleft/gpl.txt>.
-+ *
-+ * 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.
-+ *
-+ * RCSID $Id: ipsec_ipcomp.h,v 1.3 2004/04/06 02:49:08 mcr Exp $
-+ */
-+
-+#ifndef IPSEC_IPCOMP_H
-+#define IPSEC_IPCOMP_H
-+
-+#include "openswan/ipsec_auth.h"
-+
-+/* Prefix all global deflate symbols with "ipcomp_" to avoid collisions with ppp_deflate & ext2comp */
-+#ifndef IPCOMP_PREFIX
-+#define IPCOMP_PREFIX
-+#endif /* IPCOMP_PREFIX */
-+
-+#ifndef IPPROTO_COMP
-+#define IPPROTO_COMP 108
-+#endif /* IPPROTO_COMP */
-+
-+#ifdef CONFIG_IPSEC_DEBUG
-+extern int sysctl_ipsec_debug_ipcomp;
-+#endif /* CONFIG_IPSEC_DEBUG */
-+
-+struct ipcomphdr { /* IPCOMP header */
-+ __u8 ipcomp_nh; /* Next header (protocol) */
-+ __u8 ipcomp_flags; /* Reserved, must be 0 */
-+ __u16 ipcomp_cpi; /* Compression Parameter Index */
-+};
-+
-+extern struct inet_protocol comp_protocol;
-+extern int sysctl_ipsec_debug_ipcomp;
-+
-+#define IPCOMP_UNCOMPRESSABLE 0x000000001
-+#define IPCOMP_COMPRESSIONERROR 0x000000002
-+#define IPCOMP_PARMERROR 0x000000004
-+#define IPCOMP_DECOMPRESSIONERROR 0x000000008
-+
-+#define IPCOMP_ADAPT_INITIAL_TRIES 8
-+#define IPCOMP_ADAPT_INITIAL_SKIP 4
-+#define IPCOMP_ADAPT_SUBSEQ_TRIES 2
-+#define IPCOMP_ADAPT_SUBSEQ_SKIP 8
-+
-+/* Function prototypes */
-+struct sk_buff *skb_compress(struct sk_buff *skb, struct ipsec_sa *ips, unsigned int *flags);
-+struct sk_buff *skb_decompress(struct sk_buff *skb, struct ipsec_sa *ips, unsigned int *flags);
-+
-+extern struct xform_functions ipcomp_xform_funcs[];
-+
-+#endif /* IPSEC_IPCOMP_H */
-+
-+/*
-+ * $Log: ipsec_ipcomp.h,v $
-+ * Revision 1.3 2004/04/06 02:49:08 mcr
-+ * pullup of algo code from alg-branch.
-+ *
-+ * Revision 1.2 2004/04/05 19:55:05 mcr
-+ * Moved from linux/include/freeswan/ipsec_ipcomp.h,v
-+ *
-+ * Revision 1.1 2003/12/13 19:10:16 mcr
-+ * refactored rcv and xmit code - same as FS 2.05.
-+ *
-+ * Revision 1.2 2003/12/11 20:14:58 mcr
-+ * refactored the xmit code, to move all encapsulation
-+ * code into protocol functions. Note that all functions
-+ * are essentially done by a single function, which is probably
-+ * wrong.
-+ * the rcv_functions structures are renamed xform_functions.
-+ *
-+ * Revision 1.1 2003/12/06 21:21:19 mcr
-+ * split up receive path into per-transform files, for
-+ * easier later removal.
-+ *
-+ *
-+ *
-+ */
-+
-+
-+
---- /dev/null Tue Mar 11 13:02:56 2003
-+++ linux/include/openswan/ipsec_ipe4.h Mon Feb 9 13:51:03 2004
-@@ -0,0 +1,68 @@
-+/*
-+ * IP-in-IP Header declarations
-+ * Copyright (C) 1996, 1997 John Ioannidis.
-+ * Copyright (C) 1998, 1999, 2000, 2001 Richard Guy Briggs.
-+ *
-+ * 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. See <http://www.fsf.org/copyleft/gpl.txt>.
-+ *
-+ * 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.
-+ *
-+ * RCSID $Id: ipsec_ipe4.h,v 1.6 2004/04/05 19:55:05 mcr Exp $
-+ */
-+
-+/* The packet header is an IP header! */
-+
-+struct ipe4_xdata /* transform table data */
-+{
-+ struct in_addr i4_src;
-+ struct in_addr i4_dst;
-+};
-+
-+#define EMT_IPE4_ULEN 8 /* coming from user mode */
-+
-+
-+/*
-+ * $Log: ipsec_ipe4.h,v $
-+ * Revision 1.6 2004/04/05 19:55:05 mcr
-+ * Moved from linux/include/freeswan/ipsec_ipe4.h,v
-+ *
-+ * Revision 1.5 2002/04/24 07:36:46 mcr
-+ * Moved from ./klips/net/ipsec/ipsec_ipe4.h,v
-+ *
-+ * Revision 1.4 2001/06/14 19:35:08 rgb
-+ * Update copyright date.
-+ *
-+ * Revision 1.3 1999/04/11 00:28:57 henry
-+ * GPL boilerplate
-+ *
-+ * Revision 1.2 1999/04/06 04:54:25 rgb
-+ * Fix/Add RCSID Id: and Log: bits to make PHMDs happy. This includes
-+ * patch shell fixes.
-+ *
-+ * Revision 1.1 1998/06/18 21:27:47 henry
-+ * move sources from klips/src to klips/net/ipsec, to keep stupid
-+ * kernel-build scripts happier in the presence of symlinks
-+ *
-+ * Revision 1.1 1998/04/09 03:06:07 henry
-+ * sources moved up from linux/net/ipsec
-+ *
-+ * Revision 1.1.1.1 1998/04/08 05:35:03 henry
-+ * RGB's ipsec-0.8pre2.tar.gz ipsec-0.8
-+ *
-+ * Revision 0.4 1997/01/15 01:28:15 ji
-+ * No changes.
-+ *
-+ * Revision 0.3 1996/11/20 14:48:53 ji
-+ * Release update only.
-+ *
-+ * Revision 0.2 1996/11/02 00:18:33 ji
-+ * First limited release.
-+ *
-+ *
-+ */
---- /dev/null Tue Mar 11 13:02:56 2003
-+++ linux/include/openswan/ipsec_ipip.h Mon Feb 9 13:51:03 2004
-@@ -0,0 +1,45 @@
-+/*
-+ * Copyright (C) 2003 Michael Richardson <mcr@sandelman.ottawa.on.ca>
-+ *
-+ * 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. See <http://www.fsf.org/copyleft/gpl.txt>.
-+ *
-+ * 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.
-+ *
-+ * RCSID $Id: ipsec_ipip.h,v 1.2 2004/04/05 19:55:05 mcr Exp $
-+ */
-+
-+#ifndef _IPSEC_IPIP_H_
-+
-+#ifndef IPPROTO_IPIP
-+#define IPPROTO_IPIP 4
-+#endif /* IPPROTO_ESP */
-+
-+extern struct xform_functions ipip_xform_funcs[];
-+
-+#define _IPSEC_IPIP_H_
-+
-+#endif /* _IPSEC_IPIP_H_ */
-+
-+/*
-+ * $Log: ipsec_ipip.h,v $
-+ * Revision 1.2 2004/04/05 19:55:05 mcr
-+ * Moved from linux/include/freeswan/ipsec_ipip.h,v
-+ *
-+ * Revision 1.1 2003/12/13 19:10:16 mcr
-+ * refactored rcv and xmit code - same as FS 2.05.
-+ *
-+ * Revision 1.1 2003/12/11 20:14:58 mcr
-+ * refactored the xmit code, to move all encapsulation
-+ * code into protocol functions. Note that all functions
-+ * are essentially done by a single function, which is probably
-+ * wrong.
-+ * the rcv_functions structures are renamed xform_functions.
-+ *
-+ *
-+ */
---- /dev/null Tue Mar 11 13:02:56 2003
-+++ linux/include/openswan/ipsec_kversion.h Mon Feb 9 13:51:03 2004
-@@ -0,0 +1,239 @@
-+#ifndef _FREESWAN_KVERSIONS_H
-+/*
-+ * header file for FreeS/WAN library functions
-+ * Copyright (C) 1998, 1999, 2000 Henry Spencer.
-+ * Copyright (C) 1999, 2000, 2001 Richard Guy Briggs
-+ *
-+ * This library is free software; you can redistribute it and/or modify it
-+ * under the terms of the GNU Library General Public License as published by
-+ * the Free Software Foundation; either version 2 of the License, or (at your
-+ * option) any later version. See <http://www.fsf.org/copyleft/lgpl.txt>.
-+ *
-+ * This library 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 Library General Public
-+ * License for more details.
-+ *
-+ * RCSID $Id: ipsec_kversion.h,v 1.9 2004/04/05 19:55:05 mcr Exp $
-+ */
-+#define _FREESWAN_KVERSIONS_H /* seen it, no need to see it again */
-+
-+/*
-+ * this file contains a series of atomic defines that depend upon
-+ * kernel version numbers. The kernel versions are arranged
-+ * in version-order number (which is often not chronological)
-+ * and each clause enables or disables a feature.
-+ */
-+
-+/*
-+ * First, assorted kernel-version-dependent trickery.
-+ */
-+#include <linux/version.h>
-+#ifndef KERNEL_VERSION
-+#define KERNEL_VERSION(x,y,z) (((x)<<16)+((y)<<8)+(z))
-+#endif
-+
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,0)
-+#define HEADER_CACHE_BIND_21
-+#endif
-+
-+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0)
-+#define SPINLOCK
-+#define PROC_FS_21
-+#define NETLINK_SOCK
-+#define NET_21
-+#endif
-+
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,19)
-+#define net_device_stats enet_statistics
-+#endif
-+
-+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0)
-+#define SPINLOCK_23
-+#define NETDEV_23
-+# ifndef CONFIG_IP_ALIAS
-+# define CONFIG_IP_ALIAS
-+# endif
-+#include <linux/socket.h>
-+#include <linux/skbuff.h>
-+#include <linux/netlink.h>
-+# ifdef NETLINK_XFRM
-+# define NETDEV_25
-+# endif
-+#endif
-+
-+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,25)
-+#define PROC_FS_2325
-+#undef PROC_FS_21
-+#endif
-+
-+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,30)
-+#define PROC_NO_DUMMY
-+#endif
-+
-+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,35)
-+#define SKB_COPY_EXPAND
-+#endif
-+
-+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,37)
-+#define IP_SELECT_IDENT
-+#endif
-+
-+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,50)) && defined(CONFIG_NETFILTER)
-+#define SKB_RESET_NFCT
-+#endif
-+
-+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,2)
-+#define IP_SELECT_IDENT_NEW
-+#endif
-+
-+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,4)
-+#define IPH_is_SKB_PULLED
-+#define SKB_COW_NEW
-+#define PROTO_HANDLER_SINGLE_PARM
-+#define IP_FRAGMENT_LINEARIZE 1
-+#else /* LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,4) */
-+# ifdef REDHAT_BOGOSITY
-+# define IP_SELECT_IDENT_NEW
-+# define IPH_is_SKB_PULLED
-+# define SKB_COW_NEW
-+# define PROTO_HANDLER_SINGLE_PARM
-+# endif /* REDHAT_BOGOSITY */
-+#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,4) */
-+
-+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,9)
-+#define MALLOC_SLAB
-+#define LINUX_KERNEL_HAS_SNPRINTF
-+#endif
-+
-+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
-+#define HAVE_NETDEV_PRINTK 1
-+#endif
-+
-+#ifdef NET_21
-+# include <linux/in6.h>
-+#else
-+ /* old kernel in.h has some IPv6 stuff, but not quite enough */
-+# define s6_addr16 s6_addr
-+# define AF_INET6 10
-+# define uint8_t __u8
-+# define uint16_t __u16
-+# define uint32_t __u32
-+# define uint64_t __u64
-+#endif
-+
-+#ifdef NET_21
-+# define ipsec_kfree_skb(a) kfree_skb(a)
-+#else /* NET_21 */
-+# define ipsec_kfree_skb(a) kfree_skb(a, FREE_WRITE)
-+#endif /* NET_21 */
-+
-+#ifdef NETDEV_23
-+# define device net_device
-+# define ipsec_dev_get dev_get_by_name
-+# define __ipsec_dev_get __dev_get_by_name
-+# define ipsec_dev_put(x) dev_put(x)
-+# define __ipsec_dev_put(x) __dev_put(x)
-+# define ipsec_dev_hold(x) dev_hold(x)
-+#else /* NETDEV_23 */
-+# define ipsec_dev_get dev_get
-+# define __ipsec_dev_put(x)
-+# define ipsec_dev_put(x)
-+# define ipsec_dev_hold(x)
-+#endif /* NETDEV_23 */
-+
-+#ifndef SPINLOCK
-+# include <linux/bios32.h>
-+ /* simulate spin locks and read/write locks */
-+ typedef struct {
-+ volatile char lock;
-+ } spinlock_t;
-+
-+ typedef struct {
-+ volatile unsigned int lock;
-+ } rwlock_t;
-+
-+# define spin_lock_init(x) { (x)->lock = 0;}
-+# define rw_lock_init(x) { (x)->lock = 0; }
-+
-+# define spin_lock(x) { while ((x)->lock) barrier(); (x)->lock=1;}
-+# define spin_lock_irq(x) { cli(); spin_lock(x);}
-+# define spin_lock_irqsave(x,flags) { save_flags(flags); spin_lock_irq(x);}
-+
-+# define spin_unlock(x) { (x)->lock=0;}
-+# define spin_unlock_irq(x) { spin_unlock(x); sti();}
-+# define spin_unlock_irqrestore(x,flags) { spin_unlock(x); restore_flags(flags);}
-+
-+# define read_lock(x) spin_lock(x)
-+# define read_lock_irq(x) spin_lock_irq(x)
-+# define read_lock_irqsave(x,flags) spin_lock_irqsave(x,flags)
-+
-+# define read_unlock(x) spin_unlock(x)
-+# define read_unlock_irq(x) spin_unlock_irq(x)
-+# define read_unlock_irqrestore(x,flags) spin_unlock_irqrestore(x,flags)
-+
-+# define write_lock(x) spin_lock(x)
-+# define write_lock_irq(x) spin_lock_irq(x)
-+# define write_lock_irqsave(x,flags) spin_lock_irqsave(x,flags)
-+
-+# define write_unlock(x) spin_unlock(x)
-+# define write_unlock_irq(x) spin_unlock_irq(x)
-+# define write_unlock_irqrestore(x,flags) spin_unlock_irqrestore(x,flags)
-+#endif /* !SPINLOCK */
-+
-+#ifndef SPINLOCK_23
-+# define spin_lock_bh(x) spin_lock_irq(x)
-+# define spin_unlock_bh(x) spin_unlock_irq(x)
-+
-+# define read_lock_bh(x) read_lock_irq(x)
-+# define read_unlock_bh(x) read_unlock_irq(x)
-+
-+# define write_lock_bh(x) write_lock_irq(x)
-+# define write_unlock_bh(x) write_unlock_irq(x)
-+#endif /* !SPINLOCK_23 */
-+
-+#ifndef HAVE_NETDEV_PRINTK
-+#define netdev_printk(sevlevel, netdev, msglevel, format, arg...) \
-+ printk(sevlevel "%s: " format , netdev->name , ## arg)
-+#endif
-+
-+#endif /* _FREESWAN_KVERSIONS_H */
-+
-+/*
-+ * $Log: ipsec_kversion.h,v $
-+ * Revision 1.9 2004/04/05 19:55:05 mcr
-+ * Moved from linux/include/freeswan/ipsec_kversion.h,v
-+ *
-+ * Revision 1.8 2003/12/13 19:10:16 mcr
-+ * refactored rcv and xmit code - same as FS 2.05.
-+ *
-+ * Revision 1.7 2003/07/31 22:48:08 mcr
-+ * derive NET25-ness from presence of NETLINK_XFRM macro.
-+ *
-+ * Revision 1.6 2003/06/24 20:22:32 mcr
-+ * added new global: ipsecdevices[] so that we can keep track of
-+ * the ipsecX devices. They will be referenced with dev_hold(),
-+ * so 2.2 may need this as well.
-+ *
-+ * Revision 1.5 2003/04/03 17:38:09 rgb
-+ * Centralised ipsec_kfree_skb and ipsec_dev_{get,put}.
-+ *
-+ * Revision 1.4 2002/04/24 07:36:46 mcr
-+ * Moved from ./klips/net/ipsec/ipsec_kversion.h,v
-+ *
-+ * Revision 1.3 2002/04/12 03:21:17 mcr
-+ * three parameter version of ip_select_ident appears first
-+ * in 2.4.2 (RH7.1) not 2.4.4.
-+ *
-+ * Revision 1.2 2002/03/08 21:35:22 rgb
-+ * Defined LINUX_KERNEL_HAS_SNPRINTF to shut up compiler warnings after
-+ * 2.4.9. (Andreas Piesk).
-+ *
-+ * Revision 1.1 2002/01/29 02:11:42 mcr
-+ * removal of kversions.h - sources that needed it now use ipsec_param.h.
-+ * updating of IPv6 structures to match latest in6.h version.
-+ * removed dead code from freeswan.h that also duplicated kversions.h
-+ * code.
-+ *
-+ *
-+ */
---- /dev/null Tue Mar 11 13:02:56 2003
-+++ linux/include/openswan/ipsec_life.h Mon Feb 9 13:51:03 2004
-@@ -0,0 +1,112 @@
-+/*
-+ * Definitions relevant to IPSEC lifetimes
-+ * Copyright (C) 2001 Richard Guy Briggs <rgb@freeswan.org>
-+ * and Michael Richardson <mcr@freeswan.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. See <http://www.fsf.org/copyleft/gpl.txt>.
-+ *
-+ * 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.
-+ *
-+ * RCSID $Id: ipsec_life.h,v 1.4 2004/04/05 19:55:05 mcr Exp $
-+ *
-+ * This file derived from ipsec_xform.h on 2001/9/18 by mcr.
-+ *
-+ */
-+
-+/*
-+ * This file describes the book keeping fields for the
-+ * IPsec Security Association Structure. ("ipsec_sa")
-+ *
-+ * This structure is never allocated directly by kernel code,
-+ * (it is always a static/auto or is part of a structure)
-+ * so it does not have a reference count.
-+ *
-+ */
-+
-+#ifndef _IPSEC_LIFE_H_
-+
-+/*
-+ * _count is total count.
-+ * _hard is hard limit (kill SA after this number)
-+ * _soft is soft limit (try to renew SA after this number)
-+ * _last is used in some special cases.
-+ *
-+ */
-+
-+struct ipsec_lifetime64
-+{
-+ __u64 ipl_count;
-+ __u64 ipl_soft;
-+ __u64 ipl_hard;
-+ __u64 ipl_last;
-+};
-+
-+struct ipsec_lifetimes
-+{
-+ /* number of bytes processed */
-+ struct ipsec_lifetime64 ipl_bytes;
-+
-+ /* number of packets processed */
-+ struct ipsec_lifetime64 ipl_packets;
-+
-+ /* time since SA was added */
-+ struct ipsec_lifetime64 ipl_addtime;
-+
-+ /* time since SA was first used */
-+ struct ipsec_lifetime64 ipl_usetime;
-+
-+ /* from rfc2367:
-+ * For CURRENT, the number of different connections,
-+ * endpoints, or flows that the association has been
-+ * allocated towards. For HARD and SOFT, the number of
-+ * these the association may be allocated towards
-+ * before it expires. The concept of a connection,
-+ * flow, or endpoint is system specific.
-+ *
-+ * mcr(2001-9-18) it is unclear what purpose these serve for FreeSWAN.
-+ * They are maintained for PF_KEY compatibility.
-+ */
-+ struct ipsec_lifetime64 ipl_allocations;
-+};
-+
-+enum ipsec_life_alive {
-+ ipsec_life_harddied = -1,
-+ ipsec_life_softdied = 0,
-+ ipsec_life_okay = 1
-+};
-+
-+enum ipsec_life_type {
-+ ipsec_life_timebased = 1,
-+ ipsec_life_countbased= 0
-+};
-+
-+#define _IPSEC_LIFE_H_
-+#endif /* _IPSEC_LIFE_H_ */
-+
-+
-+/*
-+ * $Log: ipsec_life.h,v $
-+ * Revision 1.4 2004/04/05 19:55:05 mcr
-+ * Moved from linux/include/freeswan/ipsec_life.h,v
-+ *
-+ * Revision 1.3 2002/04/24 07:36:46 mcr
-+ * Moved from ./klips/net/ipsec/ipsec_life.h,v
-+ *
-+ * Revision 1.2 2001/11/26 09:16:14 rgb
-+ * Merge MCR's ipsec_sa, eroute, proc and struct lifetime changes.
-+ *
-+ * Revision 1.1.2.1 2001/09/25 02:25:58 mcr
-+ * lifetime structure created and common functions created.
-+ *
-+ *
-+ * Local variables:
-+ * c-file-style: "linux"
-+ * End:
-+ *
-+ */
---- /dev/null Tue Mar 11 13:02:56 2003
-+++ linux/include/openswan/ipsec_md5h.h Mon Feb 9 13:51:03 2004
-@@ -0,0 +1,140 @@
-+/*
-+ * RCSID $Id: ipsec_md5h.h,v 1.9 2004/04/05 19:55:05 mcr Exp $
-+ */
-+
-+/*
-+ * The rest of this file is Copyright RSA DSI. See the following comments
-+ * for the full Copyright notice.
-+ */
-+
-+#ifndef _IPSEC_MD5H_H_
-+#define _IPSEC_MD5H_H_
-+
-+/* GLOBAL.H - RSAREF types and constants
-+ */
-+
-+/* PROTOTYPES should be set to one if and only if the compiler supports
-+ function argument prototyping.
-+ The following makes PROTOTYPES default to 0 if it has not already
-+ been defined with C compiler flags.
-+ */
-+#ifndef PROTOTYPES
-+#define PROTOTYPES 1
-+#endif /* !PROTOTYPES */
-+
-+/* POINTER defines a generic pointer type */
-+typedef __u8 *POINTER;
-+
-+/* UINT2 defines a two byte word */
-+typedef __u16 UINT2;
-+
-+/* UINT4 defines a four byte word */
-+typedef __u32 UINT4;
-+
-+/* PROTO_LIST is defined depending on how PROTOTYPES is defined above.
-+ If using PROTOTYPES, then PROTO_LIST returns the list, otherwise it
-+ returns an empty list.
-+ */
-+
-+#if PROTOTYPES
-+#define PROTO_LIST(list) list
-+#else /* PROTOTYPES */
-+#define PROTO_LIST(list) ()
-+#endif /* PROTOTYPES */
-+
-+
-+/* MD5.H - header file for MD5C.C
-+ */
-+
-+/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
-+rights reserved.
-+
-+License to copy and use this software is granted provided that it
-+is identified as the "RSA Data Security, Inc. MD5 Message-Digest
-+Algorithm" in all material mentioning or referencing this software
-+or this function.
-+
-+License is also granted to make and use derivative works provided
-+that such works are identified as "derived from the RSA Data
-+Security, Inc. MD5 Message-Digest Algorithm" in all material
-+mentioning or referencing the derived work.
-+
-+RSA Data Security, Inc. makes no representations concerning either
-+the merchantability of this software or the suitability of this
-+software for any particular purpose. It is provided "as is"
-+without express or implied warranty of any kind.
-+
-+These notices must be retained in any copies of any part of this
-+documentation and/or software.
-+ */
-+
-+/* MD5 context. */
-+typedef struct {
-+ UINT4 state[4]; /* state (ABCD) */
-+ UINT4 count[2]; /* number of bits, modulo 2^64 (lsb first) */
-+ unsigned char buffer[64]; /* input buffer */
-+} MD5_CTX;
-+
-+void MD5Init PROTO_LIST ((void *));
-+void MD5Update PROTO_LIST
-+ ((void *, unsigned char *, __u32));
-+void MD5Final PROTO_LIST ((unsigned char [16], void *));
-+
-+#endif /* _IPSEC_MD5H_H_ */
-+
-+/*
-+ * $Log: ipsec_md5h.h,v $
-+ * Revision 1.9 2004/04/05 19:55:05 mcr
-+ * Moved from linux/include/freeswan/ipsec_md5h.h,v
-+ *
-+ * Revision 1.8 2002/09/10 01:45:09 mcr
-+ * changed type of MD5_CTX and SHA1_CTX to void * so that
-+ * the function prototypes would match, and could be placed
-+ * into a pointer to a function.
-+ *
-+ * Revision 1.7 2002/04/24 07:36:46 mcr
-+ * Moved from ./klips/net/ipsec/ipsec_md5h.h,v
-+ *
-+ * Revision 1.6 1999/12/13 13:59:13 rgb
-+ * Quick fix to argument size to Update bugs.
-+ *
-+ * Revision 1.5 1999/12/07 18:16:23 rgb
-+ * Fixed comments at end of #endif lines.
-+ *
-+ * Revision 1.4 1999/04/06 04:54:26 rgb
-+ * Fix/Add RCSID Id: and Log: bits to make PHMDs happy. This includes
-+ * patch shell fixes.
-+ *
-+ * Revision 1.3 1999/01/22 06:19:58 rgb
-+ * 64-bit clean-up.
-+ *
-+ * Revision 1.2 1998/11/30 13:22:54 rgb
-+ * Rationalised all the klips kernel file headers. They are much shorter
-+ * now and won't conflict under RH5.2.
-+ *
-+ * Revision 1.1 1998/06/18 21:27:48 henry
-+ * move sources from klips/src to klips/net/ipsec, to keep stupid
-+ * kernel-build scripts happier in the presence of symlinks
-+ *
-+ * Revision 1.2 1998/04/23 20:54:03 rgb
-+ * Fixed md5 and sha1 include file nesting issues, to be cleaned up when
-+ * verified.
-+ *
-+ * Revision 1.1 1998/04/09 03:04:21 henry
-+ * sources moved up from linux/net/ipsec
-+ * these two include files modified not to include others except in kernel
-+ *
-+ * Revision 1.1.1.1 1998/04/08 05:35:03 henry
-+ * RGB's ipsec-0.8pre2.tar.gz ipsec-0.8
-+ *
-+ * Revision 0.4 1997/01/15 01:28:15 ji
-+ * No changes.
-+ *
-+ * Revision 0.3 1996/11/20 14:48:53 ji
-+ * Release update only.
-+ *
-+ * Revision 0.2 1996/11/02 00:18:33 ji
-+ * First limited release.
-+ *
-+ *
-+ */
---- /dev/null Tue Mar 11 13:02:56 2003
-+++ linux/include/openswan/ipsec_param.h Mon Feb 9 13:51:03 2004
-@@ -0,0 +1,333 @@
-+/*
-+ * @(#) FreeSWAN tunable paramaters
-+ *
-+ * Copyright (C) 2001 Richard Guy Briggs <rgb@freeswan.org>
-+ * and Michael Richardson <mcr@freeswan.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. See <http://www.fsf.org/copyleft/gpl.txt>.
-+ *
-+ * 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.
-+ *
-+ * RCSID $Id: ipsec_param.h,v 1.24 2004/04/05 19:55:06 mcr Exp $
-+ *
-+ */
-+
-+/*
-+ * This file provides a set of #define's which may be tuned by various
-+ * people/configurations. It keeps all compile-time tunables in one place.
-+ *
-+ * This file should be included before all other IPsec kernel-only files.
-+ *
-+ */
-+
-+#ifndef _IPSEC_PARAM_H_
-+
-+#ifdef __KERNEL__
-+#include "ipsec_kversion.h"
-+
-+/* Set number of ipsecX virtual devices here. */
-+/* This must be < exp(field width of IPSEC_DEV_FORMAT) */
-+/* It must also be reasonable so as not to overload the memory and CPU */
-+/* constraints of the host. */
-+#define IPSEC_NUM_IF 4
-+/* The field width must be < IF_NAM_SIZ - strlen("ipsec") - 1. */
-+/* With "ipsec" being 5 characters, that means 10 is the max field width */
-+/* but machine memory and CPU constraints are not likely to tollerate */
-+/* more than 3 digits. The default is one digit. */
-+/* Update: userland scripts get upset if they can't find "ipsec0", so */
-+/* for now, no "0"-padding should be used (which would have been helpful */
-+/* to make text-searches work */
-+#define IPSEC_DEV_FORMAT "ipsec%d"
-+/* For, say, 500 virtual ipsec devices, I would recommend: */
-+/* #define IPSEC_NUM_IF 500 */
-+/* #define IPSEC_DEV_FORMAT "ipsec%03d" */
-+/* Note that the "interfaces=" line in /etc/ipsec.conf would be, um, challenging. */
-+
-+/* use dynamic ipsecX device allocation */
-+#ifndef CONFIG_IPSEC_DYNDEV
-+#define CONFIG_IPSEC_DYNDEV 1
-+#endif /* CONFIG_IPSEC_DYNDEV */
-+
-+
-+#ifdef CONFIG_IPSEC_BIGGATE
-+# define SADB_HASHMOD 8069
-+#else /* CONFIG_IPSEC_BIGGATE */
-+# define SADB_HASHMOD 257
-+#endif /* CONFIG_IPSEC_BIGGATE */
-+#endif /* __KERNEL__ */
-+
-+/*
-+ * This is for the SA reference table. This number is related to the
-+ * maximum number of SAs that KLIPS can concurrently deal with, plus enough
-+ * space for keeping expired SAs around.
-+ *
-+ * TABLE_MAX_WIDTH is the number of bits that we will use.
-+ * MAIN_TABLE_WIDTH is the number of bits used for the primary index table.
-+ *
-+ */
-+#ifndef IPSEC_SA_REF_TABLE_IDX_WIDTH
-+# define IPSEC_SA_REF_TABLE_IDX_WIDTH 16
-+#endif
-+
-+#ifndef IPSEC_SA_REF_MAINTABLE_IDX_WIDTH
-+# define IPSEC_SA_REF_MAINTABLE_IDX_WIDTH 4
-+#endif
-+
-+#ifndef IPSEC_SA_REF_FREELIST_NUM_ENTRIES
-+# define IPSEC_SA_REF_FREELIST_NUM_ENTRIES 256
-+#endif
-+
-+#ifndef IPSEC_SA_REF_CODE
-+# define IPSEC_SA_REF_CODE 1
-+#endif
-+
-+#ifdef __KERNEL__
-+/* This is defined for 2.4, but not 2.2.... */
-+#ifndef ARPHRD_VOID
-+# define ARPHRD_VOID 0xFFFF
-+#endif
-+
-+/*
-+ * Worry about PROC_FS stuff
-+ */
-+#if defined(PROC_FS_2325)
-+/* kernel 2.4 */
-+# define IPSEC_PROC_LAST_ARG ,int *eof,void *data
-+# define IPSEC_PROCFS_DEBUG_NO_STATIC
-+# define IPSEC_PROC_SUBDIRS
-+#else
-+/* kernel <2.4 */
-+# define IPSEC_PROCFS_DEBUG_NO_STATIC DEBUG_NO_STATIC
-+
-+# ifndef PROC_NO_DUMMY
-+# define IPSEC_PROC_LAST_ARG , int dummy
-+# else
-+# define IPSEC_PROC_LAST_ARG
-+# endif /* !PROC_NO_DUMMY */
-+#endif /* PROC_FS_2325 */
-+
-+#if !defined(LINUX_KERNEL_HAS_SNPRINTF)
-+/* GNU CPP specific! */
-+# define snprintf(buf, len, fmt...) sprintf(buf, ##fmt)
-+#endif /* !LINUX_KERNEL_HAS_SNPRINTF */
-+
-+#ifdef SPINLOCK
-+# ifdef SPINLOCK_23
-+# include <linux/spinlock.h> /* *lock* */
-+# else /* SPINLOCK_23 */
-+# include <asm/spinlock.h> /* *lock* */
-+# endif /* SPINLOCK_23 */
-+#endif /* SPINLOCK */
-+
-+#ifndef KLIPS_FIXES_DES_PARITY
-+# define KLIPS_FIXES_DES_PARITY 1
-+#endif /* !KLIPS_FIXES_DES_PARITY */
-+
-+/* we don't really want to print these unless there are really big problems */
-+#ifndef KLIPS_DIVULGE_CYPHER_KEY
-+# define KLIPS_DIVULGE_CYPHER_KEY 0
-+#endif /* !KLIPS_DIVULGE_CYPHER_KEY */
-+
-+#ifndef KLIPS_DIVULGE_HMAC_KEY
-+# define KLIPS_DIVULGE_HMAC_KEY 0
-+#endif /* !KLIPS_DIVULGE_HMAC_KEY */
-+
-+#ifndef IPSEC_DISALLOW_IPOPTIONS
-+# define IPSEC_DISALLOW_IPOPTIONS 1
-+#endif /* !KLIPS_DIVULGE_HMAC_KEY */
-+
-+/* extra toggles for regression testing */
-+#ifdef CONFIG_IPSEC_REGRESS
-+
-+/*
-+ * should pfkey_acquire() become 100% lossy?
-+ *
-+ */
-+extern int sysctl_ipsec_regress_pfkey_lossage;
-+#ifndef KLIPS_PFKEY_ACQUIRE_LOSSAGE
-+# ifdef CONFIG_IPSEC_PFKEY_ACQUIRE_LOSSAGE
-+# define KLIPS_PFKEY_ACQUIRE_LOSSAGE 100
-+# else /* CONFIG_IPSEC_PFKEY_ACQUIRE_LOSSAGE */
-+/* not by default! */
-+# define KLIPS_PFKEY_ACQUIRE_LOSSAGE 0
-+# endif /* CONFIG_IPSEC_PFKEY_ACQUIRE_LOSSAGE */
-+#endif /* KLIPS_PFKEY_ACQUIRE_LOSSAGE */
-+
-+#endif /* CONFIG_IPSEC_REGRESS */
-+
-+
-+/*
-+ * debugging routines.
-+ */
-+#ifdef CONFIG_IPSEC_DEBUG
-+extern void ipsec_print_ip(struct iphdr *ip);
-+
-+ #define KLIPS_PRINT(flag, format, args...) \
-+ ((flag) ? printk(KERN_INFO format , ## args) : 0)
-+ #define KLIPS_PRINTMORE(flag, format, args...) \
-+ ((flag) ? printk(format , ## args) : 0)
-+ #define KLIPS_IP_PRINT(flag, ip) \
-+ ((flag) ? ipsec_print_ip(ip) : 0)
-+#else /* CONFIG_IPSEC_DEBUG */
-+ #define KLIPS_PRINT(flag, format, args...) do ; while(0)
-+ #define KLIPS_PRINTMORE(flag, format, args...) do ; while(0)
-+ #define KLIPS_IP_PRINT(flag, ip) do ; while(0)
-+#endif /* CONFIG_IPSEC_DEBUG */
-+
-+
-+/*
-+ * Stupid kernel API differences in APIs. Not only do some
-+ * kernels not have ip_select_ident, but some have differing APIs,
-+ * and SuSE has one with one parameter, but no way of checking to
-+ * see what is really what.
-+ */
-+
-+#ifdef SUSE_LINUX_2_4_19_IS_STUPID
-+#define KLIPS_IP_SELECT_IDENT(iph, skb) ip_select_ident(iph)
-+#else
-+
-+/* simplest case, nothing */
-+#if !defined(IP_SELECT_IDENT)
-+#define KLIPS_IP_SELECT_IDENT(iph, skb) do { iph->id = htons(ip_id_count++); } while(0)
-+#endif
-+
-+/* kernels > 2.3.37-ish */
-+#if defined(IP_SELECT_IDENT) && !defined(IP_SELECT_IDENT_NEW)
-+#define KLIPS_IP_SELECT_IDENT(iph, skb) ip_select_ident(iph, skb->dst)
-+#endif
-+
-+/* kernels > 2.4.2 */
-+#if defined(IP_SELECT_IDENT) && defined(IP_SELECT_IDENT_NEW)
-+#define KLIPS_IP_SELECT_IDENT(iph, skb) ip_select_ident(iph, skb->dst, NULL)
-+#endif
-+
-+#endif /* SUSE_LINUX_2_4_19_IS_STUPID */
-+
-+/*
-+ * make klips fail test:east-espiv-01.
-+ * exploit is at testing/attacks/espiv
-+ *
-+ */
-+#define KLIPS_IMPAIRMENT_ESPIV_CBC_ATTACK 0
-+
-+
-+/* IP_FRAGMENT_LINEARIZE is set in freeswan.h if Kernel > 2.4.4 */
-+#ifndef IP_FRAGMENT_LINEARIZE
-+# define IP_FRAGMENT_LINEARIZE 0
-+#endif /* IP_FRAGMENT_LINEARIZE */
-+#endif /* __KERNEL__ */
-+
-+#define _IPSEC_PARAM_H_
-+#endif /* _IPSEC_PARAM_H_ */
-+
-+/*
-+ * $Log: ipsec_param.h,v $
-+ * Revision 1.24 2004/04/05 19:55:06 mcr
-+ * Moved from linux/include/freeswan/ipsec_param.h,v
-+ *
-+ * Revision 1.23 2003/12/13 19:10:16 mcr
-+ * refactored rcv and xmit code - same as FS 2.05.
-+ *
-+ * Revision 1.22 2003/10/31 02:27:05 mcr
-+ * pulled up port-selector patches and sa_id elimination.
-+ *
-+ * Revision 1.21.4.1 2003/10/29 01:10:19 mcr
-+ * elimited "struct sa_id"
-+ *
-+ * Revision 1.21 2003/04/03 17:38:18 rgb
-+ * Centralised ipsec_kfree_skb and ipsec_dev_{get,put}.
-+ * Change indentation for readability.
-+ *
-+ * Revision 1.20 2003/03/14 08:09:26 rgb
-+ * Fixed up CONFIG_IPSEC_DYNDEV definitions.
-+ *
-+ * Revision 1.19 2003/01/30 02:31:43 rgb
-+ *
-+ * Rename SAref table macro names for clarity.
-+ *
-+ * Revision 1.18 2002/09/30 19:06:26 rgb
-+ * Reduce default table to 16 bits width.
-+ *
-+ * Revision 1.17 2002/09/20 15:40:29 rgb
-+ * Define switch to activate new SAref code.
-+ * Prefix macros with "IPSEC_".
-+ * Rework saref freelist.
-+ * Restrict some bits to kernel context for use to klips utils.
-+ *
-+ * Revision 1.16 2002/09/20 05:00:31 rgb
-+ * Define switch to divulge hmac keys for debugging.
-+ * Added IPOPTIONS switch.
-+ *
-+ * Revision 1.15 2002/09/19 02:34:24 mcr
-+ * define IPSEC_PROC_SUBDIRS if we are 2.4, and use that in ipsec_proc.c
-+ * to decide if we are to create /proc/net/ipsec/.
-+ *
-+ * Revision 1.14 2002/08/30 01:20:54 mcr
-+ * reorganized 2.0/2.2/2.4 procfs support macro so match
-+ * 2.4 values/typedefs.
-+ *
-+ * Revision 1.13 2002/07/28 22:03:28 mcr
-+ * added some documentation to SA_REF_*
-+ * turned on fix for ESPIV attack, now that we have the attack code.
-+ *
-+ * Revision 1.12 2002/07/26 08:48:31 rgb
-+ * Added SA ref table code.
-+ *
-+ * Revision 1.11 2002/07/23 02:57:45 rgb
-+ * Define ARPHRD_VOID for < 2.4 kernels.
-+ *
-+ * Revision 1.10 2002/05/27 21:37:28 rgb
-+ * Set the defaults sanely for those adventurous enough to try more than 1
-+ * digit of ipsec devices.
-+ *
-+ * Revision 1.9 2002/05/27 18:56:07 rgb
-+ * Convert to dynamic ipsec device allocation.
-+ *
-+ * Revision 1.8 2002/04/24 07:36:47 mcr
-+ * Moved from ./klips/net/ipsec/ipsec_param.h,v
-+ *
-+ * Revision 1.7 2002/04/20 00:12:25 rgb
-+ * Added esp IV CBC attack fix, disabled.
-+ *
-+ * Revision 1.6 2002/01/29 02:11:42 mcr
-+ * removal of kversions.h - sources that needed it now use ipsec_param.h.
-+ * updating of IPv6 structures to match latest in6.h version.
-+ * removed dead code from freeswan.h that also duplicated kversions.h
-+ * code.
-+ *
-+ * Revision 1.5 2002/01/28 19:22:01 mcr
-+ * by default, turn off LINEARIZE option
-+ * (let kversions.h turn it on)
-+ *
-+ * Revision 1.4 2002/01/20 20:19:36 mcr
-+ * renamed option to IP_FRAGMENT_LINEARIZE.
-+ *
-+ * Revision 1.3 2002/01/12 02:57:25 mcr
-+ * first regression test causes acquire messages to be lost
-+ * 100% of the time. This is to help testing of pluto.
-+ *
-+ * Revision 1.2 2001/11/26 09:16:14 rgb
-+ * Merge MCR's ipsec_sa, eroute, proc and struct lifetime changes.
-+ *
-+ * Revision 1.1.2.3 2001/10/23 04:40:16 mcr
-+ * added #define for DIVULGING session keys in debug output.
-+ *
-+ * Revision 1.1.2.2 2001/10/22 20:53:25 mcr
-+ * added a define to control forcing of DES parity.
-+ *
-+ * Revision 1.1.2.1 2001/09/25 02:20:19 mcr
-+ * many common kernel configuration questions centralized.
-+ * more things remain that should be moved from freeswan.h.
-+ *
-+ *
-+ * Local variables:
-+ * c-file-style: "linux"
-+ * End:
-+ *
-+ */
---- /dev/null Tue Mar 11 13:02:56 2003
-+++ linux/include/openswan/ipsec_policy.h Mon Feb 9 13:51:03 2004
-@@ -0,0 +1,216 @@
-+#ifndef _IPSEC_POLICY_H
-+/*
-+ * policy interface file between pluto and applications
-+ * Copyright (C) 2003 Michael Richardson <mcr@freeswan.org>
-+ *
-+ * This library is free software; you can redistribute it and/or modify it
-+ * under the terms of the GNU Library General Public License as published by
-+ * the Free Software Foundation; either version 2 of the License, or (at your
-+ * option) any later version. See <http://www.fsf.org/copyleft/lgpl.txt>.
-+ *
-+ * This library 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 Library General Public
-+ * License for more details.
-+ *
-+ * RCSID $Id: ipsec_policy.h,v 1.5 2004/06/17 04:23:33 mcr Exp $
-+ */
-+#define _IPSEC_POLICY_H /* seen it, no need to see it again */
-+
-+
-+/*
-+ * this file defines an interface between an application (or rather an
-+ * application library) and a key/policy daemon. It provides for inquiries
-+ * as to the current state of a connected socket, as well as for general
-+ * questions.
-+ *
-+ * In general, the interface is defined as a series of functional interfaces,
-+ * and the policy messages should be internal. However, because this is in
-+ * fact an ABI between pieces of the system that may get compiled and revised
-+ * seperately, this ABI must be public and revision controlled.
-+ *
-+ * It is expected that the daemon will always support previous versions.
-+ */
-+
-+#define IPSEC_POLICY_MSG_REVISION (unsigned)200305061
-+
-+enum ipsec_policy_command {
-+ IPSEC_CMD_QUERY_FD = 1,
-+ IPSEC_CMD_QUERY_HOSTPAIR = 2,
-+ IPSEC_CMD_QUERY_DSTONLY = 3,
-+};
-+
-+struct ipsec_policy_msg_head {
-+ u_int32_t ipm_version;
-+ u_int32_t ipm_msg_len;
-+ u_int32_t ipm_msg_type;
-+ u_int32_t ipm_msg_seq;
-+};
-+
-+enum ipsec_privacy_quality {
-+ IPSEC_PRIVACY_NONE = 0,
-+ IPSEC_PRIVACY_INTEGRAL = 4, /* not private at all. AH-like */
-+ IPSEC_PRIVACY_UNKNOWN = 8, /* something is claimed, but details unavail */
-+ IPSEC_PRIVACY_ROT13 = 12, /* trivially breakable, i.e. 1DES */
-+ IPSEC_PRIVACY_GAK = 16, /* known eavesdroppers */
-+ IPSEC_PRIVACY_PRIVATE = 32, /* secure for at least a decade */
-+ IPSEC_PRIVACY_STRONG = 64, /* ridiculously secure */
-+ IPSEC_PRIVACY_TORTOISE = 192, /* even stronger, but very slow */
-+ IPSEC_PRIVACY_OTP = 224, /* some kind of *true* one time pad */
-+};
-+
-+enum ipsec_bandwidth_quality {
-+ IPSEC_QOS_UNKNOWN = 0, /* unknown bandwidth */
-+ IPSEC_QOS_INTERACTIVE = 16, /* reasonably moderate jitter, moderate fast.
-+ Good enough for telnet/ssh. */
-+ IPSEC_QOS_VOIP = 32, /* faster crypto, predicable jitter */
-+ IPSEC_QOS_FTP = 64, /* higher throughput crypto, perhaps hardware
-+ offloaded, but latency/jitter may be bad */
-+ IPSEC_QOS_WIRESPEED = 128, /* expect to be able to fill your pipe */
-+};
-+
-+/* moved from programs/pluto/constants.h */
-+/* IPsec AH transform values
-+ * RFC2407 The Internet IP security Domain of Interpretation for ISAKMP 4.4.3
-+ * and in http://www.iana.org/assignments/isakmp-registry
-+ */
-+enum ipsec_authentication_algo {
-+ AH_MD5=2,
-+ AH_SHA=3,
-+ AH_DES=4,
-+ AH_SHA2_256=5,
-+ AH_SHA2_384=6,
-+ AH_SHA2_512=7
-+};
-+
-+/* IPsec ESP transform values
-+ * RFC2407 The Internet IP security Domain of Interpretation for ISAKMP 4.4.4
-+ * and from http://www.iana.org/assignments/isakmp-registry
-+ */
-+
-+enum ipsec_cipher_algo {
-+ ESP_reserved=0,
-+ ESP_DES_IV64=1,
-+ ESP_DES=2,
-+ ESP_3DES=3,
-+ ESP_RC5=4,
-+ ESP_IDEA=5,
-+ ESP_CAST=6,
-+ ESP_BLOWFISH=7,
-+ ESP_3IDEA=8,
-+ ESP_DES_IV32=9,
-+ ESP_RC4=10,
-+ ESP_NULL=11,
-+ ESP_AES=12,
-+};
-+
-+/* IPCOMP transform values
-+ * RFC2407 The Internet IP security Domain of Interpretation for ISAKMP 4.4.5
-+ */
-+
-+enum ipsec_comp_algo {
-+ IPCOMP_OUI= 1,
-+ IPCOMP_DEFLATE= 2,
-+ IPCOMP_LZS= 3,
-+ IPCOMP_V42BIS= 4
-+};
-+
-+/* Identification type values
-+ * RFC 2407 The Internet IP security Domain of Interpretation for ISAKMP 4.6.2.1
-+ */
-+
-+enum ipsec_id_type {
-+ ID_IMPOSSIBLE= (-2), /* private to Pluto */
-+ ID_MYID= (-1), /* private to Pluto */
-+ ID_NONE= 0, /* private to Pluto */
-+ ID_IPV4_ADDR= 1,
-+ ID_FQDN= 2,
-+ ID_USER_FQDN= 3,
-+ ID_IPV4_ADDR_SUBNET= 4,
-+ ID_IPV6_ADDR= 5,
-+ ID_IPV6_ADDR_SUBNET= 6,
-+ ID_IPV4_ADDR_RANGE= 7,
-+ ID_IPV6_ADDR_RANGE= 8,
-+ ID_DER_ASN1_DN= 9,
-+ ID_DER_ASN1_GN= 10,
-+ ID_KEY_ID= 11
-+};
-+
-+/* Certificate type values
-+ * RFC 2408 ISAKMP, chapter 3.9
-+ */
-+enum ipsec_cert_type {
-+ CERT_NONE= 0, /* none, or guess from file contents */
-+ CERT_PKCS7_WRAPPED_X509= 1, /* self-signed certificate from disk */
-+ CERT_PGP= 2,
-+ CERT_DNS_SIGNED_KEY= 3, /* KEY RR from DNS */
-+ CERT_X509_SIGNATURE= 4,
-+ CERT_X509_KEY_EXCHANGE= 5,
-+ CERT_KERBEROS_TOKENS= 6,
-+ CERT_CRL= 7,
-+ CERT_ARL= 8,
-+ CERT_SPKI= 9,
-+ CERT_X509_ATTRIBUTE= 10,
-+ CERT_RAW_RSA= 11, /* raw RSA from config file */
-+};
-+
-+/* a SIG record in ASCII */
-+struct ipsec_dns_sig {
-+ char fqdn[256];
-+ char dns_sig[768]; /* empty string if not signed */
-+};
-+
-+struct ipsec_raw_key {
-+ char id_name[256];
-+ char fs_keyid[8];
-+};
-+
-+struct ipsec_identity {
-+ enum ipsec_id_type ii_type;
-+ enum ipsec_cert_type ii_format;
-+ union {
-+ struct ipsec_dns_sig ipsec_dns_signed;
-+ /* some thing for PGP */
-+ /* some thing for PKIX */
-+ struct ipsec_raw_key ipsec_raw_key;
-+ } ii_credential;
-+};
-+
-+#define IPSEC_MAX_CREDENTIALS 32
-+
-+struct ipsec_policy_cmd_query {
-+ struct ipsec_policy_msg_head head;
-+
-+ /* Query section */
-+ ip_address query_local; /* us */
-+ ip_address query_remote; /* them */
-+ u_short src_port, dst_port;
-+
-+ /* Answer section */
-+ enum ipsec_privacy_quality strength;
-+ enum ipsec_bandwidth_quality bandwidth;
-+ enum ipsec_authentication_algo auth_detail;
-+ enum ipsec_cipher_algo esp_detail;
-+ enum ipsec_comp_algo comp_detail;
-+
-+ int credential_count;
-+
-+ struct ipsec_identity credentials[IPSEC_MAX_CREDENTIALS];
-+};
-+
-+#define IPSEC_POLICY_SOCKET "/var/run/pluto.info"
-+
-+/* prototypes */
-+extern err_t ipsec_policy_lookup(int fd, struct ipsec_policy_cmd_query *result);
-+extern err_t ipsec_policy_init(void);
-+extern err_t ipsec_policy_final(void);
-+extern err_t ipsec_policy_readmsg(int policysock,
-+ unsigned char *buf, size_t buflen);
-+extern err_t ipsec_policy_sendrecv(unsigned char *buf, size_t buflen);
-+extern err_t ipsec_policy_cgilookup(struct ipsec_policy_cmd_query *result);
-+
-+
-+extern const char *ipsec_policy_version_code(void);
-+extern const char *ipsec_policy_version_string(void);
-+
-+#endif /* _IPSEC_POLICY_H */
---- /dev/null Tue Mar 11 13:02:56 2003
-+++ linux/include/openswan/ipsec_proto.h Mon Feb 9 13:51:03 2004
-@@ -0,0 +1,151 @@
-+/*
-+ * @(#) prototypes for FreeSWAN functions
-+ *
-+ * Copyright (C) 2001 Richard Guy Briggs <rgb@freeswan.org>
-+ * and Michael Richardson <mcr@freeswan.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. See <http://www.fsf.org/copyleft/gpl.txt>.
-+ *
-+ * 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.
-+ *
-+ * RCSID $Id: ipsec_proto.h,v 1.8 2004/04/05 19:55:06 mcr Exp $
-+ *
-+ */
-+
-+#ifndef _IPSEC_PROTO_H_
-+
-+#include "ipsec_param.h"
-+
-+/*
-+ * This file is a kernel only file that declares prototypes for
-+ * all intra-module function calls and global data structures.
-+ *
-+ * Include this file last.
-+ *
-+ */
-+
-+/* ipsec_init.c */
-+extern struct prng ipsec_prng;
-+
-+/* ipsec_sa.c */
-+extern struct ipsec_sa *ipsec_sadb_hash[SADB_HASHMOD];
-+extern spinlock_t tdb_lock;
-+extern int ipsec_sadb_init(void);
-+
-+extern struct ipsec_sa *ipsec_sa_getbyid(ip_said *);
-+extern int ipsec_sa_put(struct ipsec_sa *);
-+extern /* void */ int ipsec_sa_del(struct ipsec_sa *);
-+extern /* void */ int ipsec_sa_delchain(struct ipsec_sa *);
-+extern /* void */ int ipsec_sa_add(struct ipsec_sa *);
-+
-+extern int ipsec_sadb_cleanup(__u8);
-+extern int ipsec_sa_wipe(struct ipsec_sa *);
-+
-+/* debug declarations */
-+
-+/* ipsec_proc.c */
-+extern int ipsec_proc_init(void);
-+extern void ipsec_proc_cleanup(void);
-+
-+/* ipsec_radij.c */
-+extern int ipsec_makeroute(struct sockaddr_encap *ea,
-+ struct sockaddr_encap *em,
-+ ip_said said,
-+ uint32_t pid,
-+ struct sk_buff *skb,
-+ struct ident *ident_s,
-+ struct ident *ident_d);
-+
-+extern int ipsec_breakroute(struct sockaddr_encap *ea,
-+ struct sockaddr_encap *em,
-+ struct sk_buff **first,
-+ struct sk_buff **last);
-+
-+int ipsec_radijinit(void);
-+int ipsec_cleareroutes(void);
-+int ipsec_radijcleanup(void);
-+
-+/* ipsec_life.c */
-+extern enum ipsec_life_alive ipsec_lifetime_check(struct ipsec_lifetime64 *il64,
-+ const char *lifename,
-+ const char *saname,
-+ enum ipsec_life_type ilt,
-+ enum ipsec_direction idir,
-+ struct ipsec_sa *ips);
-+
-+
-+extern int ipsec_lifetime_format(char *buffer,
-+ int buflen,
-+ char *lifename,
-+ enum ipsec_life_type timebaselife,
-+ struct ipsec_lifetime64 *lifetime);
-+
-+extern void ipsec_lifetime_update_hard(struct ipsec_lifetime64 *lifetime,
-+ __u64 newvalue);
-+
-+extern void ipsec_lifetime_update_soft(struct ipsec_lifetime64 *lifetime,
-+ __u64 newvalue);
-+
-+
-+
-+
-+#ifdef CONFIG_IPSEC_DEBUG
-+
-+extern int debug_xform;
-+extern int debug_eroute;
-+extern int debug_spi;
-+extern int debug_netlink;
-+
-+#endif /* CONFIG_IPSEC_DEBUG */
-+
-+
-+
-+
-+#define _IPSEC_PROTO_H
-+#endif /* _IPSEC_PROTO_H_ */
-+
-+/*
-+ * $Log: ipsec_proto.h,v $
-+ * Revision 1.8 2004/04/05 19:55:06 mcr
-+ * Moved from linux/include/freeswan/ipsec_proto.h,v
-+ *
-+ * Revision 1.7 2003/10/31 02:27:05 mcr
-+ * pulled up port-selector patches and sa_id elimination.
-+ *
-+ * Revision 1.6.30.1 2003/10/29 01:10:19 mcr
-+ * elimited "struct sa_id"
-+ *
-+ * Revision 1.6 2002/05/23 07:13:48 rgb
-+ * Added ipsec_sa_put() for releasing an ipsec_sa refcount.
-+ *
-+ * Revision 1.5 2002/05/14 02:36:40 rgb
-+ * Converted reference from ipsec_sa_put to ipsec_sa_add to avoid confusion
-+ * with "put" usage in the kernel.
-+ *
-+ * Revision 1.4 2002/04/24 07:36:47 mcr
-+ * Moved from ./klips/net/ipsec/ipsec_proto.h,v
-+ *
-+ * Revision 1.3 2002/04/20 00:12:25 rgb
-+ * Added esp IV CBC attack fix, disabled.
-+ *
-+ * Revision 1.2 2001/11/26 09:16:15 rgb
-+ * Merge MCR's ipsec_sa, eroute, proc and struct lifetime changes.
-+ *
-+ * Revision 1.1.2.1 2001/09/25 02:21:01 mcr
-+ * ipsec_proto.h created to keep prototypes rather than deal with
-+ * cyclic dependancies of structures and prototypes in .h files.
-+ *
-+ *
-+ *
-+ * Local variables:
-+ * c-file-style: "linux"
-+ * End:
-+ *
-+ */
-+
---- /dev/null Tue Mar 11 13:02:56 2003
-+++ linux/include/openswan/ipsec_radij.h Mon Feb 9 13:51:03 2004
-@@ -0,0 +1,176 @@
-+/*
-+ * @(#) Definitions relevant to the IPSEC <> radij tree interfacing
-+ * Copyright (C) 1996, 1997 John Ioannidis.
-+ * Copyright (C) 1998, 1999, 2000, 2001 Richard Guy Briggs.
-+ *
-+ * 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. See <http://www.fsf.org/copyleft/gpl.txt>.
-+ *
-+ * 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.
-+ *
-+ * RCSID $Id: ipsec_radij.h,v 1.21 2004/04/29 11:06:42 ken Exp $
-+ */
-+
-+#ifndef _IPSEC_RADIJ_H
-+
-+#include <openswan.h>
-+
-+int ipsec_walk(char *);
-+
-+int ipsec_rj_walker_procprint(struct radij_node *, void *);
-+int ipsec_rj_walker_delete(struct radij_node *, void *);
-+
-+/* This structure is used to pass information between
-+ * ipsec_eroute_get_info and ipsec_rj_walker_procprint
-+ * (through rj_walktree) and between calls of ipsec_rj_walker_procprint.
-+ */
-+struct wsbuf
-+{
-+ /* from caller of ipsec_eroute_get_info: */
-+ char *const buffer; /* start of buffer provided */
-+ const int length; /* length of buffer provided */
-+ const off_t offset; /* file position of first character of interest */
-+ /* accumulated by ipsec_rj_walker_procprint: */
-+ int len; /* number of character filled into buffer */
-+ off_t begin; /* file position contained in buffer[0] (<=offset) */
-+};
-+
-+extern struct radij_node_head *rnh;
-+extern spinlock_t eroute_lock;
-+
-+struct eroute * ipsec_findroute(struct sockaddr_encap *);
-+
-+#define O1(x) (int)(((x)>>24)&0xff)
-+#define O2(x) (int)(((x)>>16)&0xff)
-+#define O3(x) (int)(((x)>>8)&0xff)
-+#define O4(x) (int)(((x))&0xff)
-+
-+#ifdef CONFIG_IPSEC_DEBUG
-+extern int debug_radij;
-+void rj_dumptrees(void);
-+
-+#define DB_RJ_DUMPTREES 0x0001
-+#define DB_RJ_FINDROUTE 0x0002
-+#endif /* CONFIG_IPSEC_DEBUG */
-+
-+#define _IPSEC_RADIJ_H
-+#endif
-+
-+/*
-+ * $Log: ipsec_radij.h,v $
-+ * Revision 1.21 2004/04/29 11:06:42 ken
-+ * Last bits from 2.06 procfs updates
-+ *
-+ * Revision 1.20 2004/04/06 02:49:08 mcr
-+ * pullup of algo code from alg-branch.
-+ *
-+ * Revision 1.19 2004/04/05 19:55:06 mcr
-+ * Moved from linux/include/freeswan/ipsec_radij.h,v
-+ *
-+ * Revision 1.18 2002/04/24 07:36:47 mcr
-+ * Moved from ./klips/net/ipsec/ipsec_radij.h,v
-+ *
-+ * Revision 1.17 2001/11/26 09:23:49 rgb
-+ * Merge MCR's ipsec_sa, eroute, proc and struct lifetime changes.
-+ *
-+ * Revision 1.16.2.1 2001/09/25 02:21:17 mcr
-+ * ipsec_proto.h created to keep prototypes rather than deal with
-+ * cyclic dependancies of structures and prototypes in .h files.
-+ *
-+ * Revision 1.16 2001/09/15 16:24:04 rgb
-+ * Re-inject first and last HOLD packet when an eroute REPLACE is done.
-+ *
-+ * Revision 1.15 2001/09/14 16:58:37 rgb
-+ * Added support for storing the first and last packets through a HOLD.
-+ *
-+ * Revision 1.14 2001/09/08 21:13:32 rgb
-+ * Added pfkey ident extension support for ISAKMPd. (NetCelo)
-+ *
-+ * Revision 1.13 2001/06/14 19:35:09 rgb
-+ * Update copyright date.
-+ *
-+ * Revision 1.12 2001/05/27 06:12:11 rgb
-+ * Added structures for pid, packet count and last access time to eroute.
-+ * Added packet count to beginning of /proc/net/ipsec_eroute.
-+ *
-+ * Revision 1.11 2000/09/08 19:12:56 rgb
-+ * Change references from DEBUG_IPSEC to CONFIG_IPSEC_DEBUG.
-+ *
-+ * Revision 1.10 1999/11/17 15:53:39 rgb
-+ * Changed all occurrences of #include "../../../lib/freeswan.h"
-+ * to #include <freeswan.h> which works due to -Ilibfreeswan in the
-+ * klips/net/ipsec/Makefile.
-+ *
-+ * Revision 1.9 1999/10/01 00:01:23 rgb
-+ * Added eroute structure locking.
-+ *
-+ * Revision 1.8 1999/04/11 00:28:59 henry
-+ * GPL boilerplate
-+ *
-+ * Revision 1.7 1999/04/06 04:54:26 rgb
-+ * Fix/Add RCSID Id: and Log: bits to make PHMDs happy. This includes
-+ * patch shell fixes.
-+ *
-+ * Revision 1.6 1999/01/22 06:23:26 rgb
-+ * Cruft clean-out.
-+ *
-+ * Revision 1.5 1998/10/25 02:42:08 rgb
-+ * Change return type on ipsec_breakroute and ipsec_makeroute and add an
-+ * argument to be able to transmit more infomation about errors.
-+ *
-+ * Revision 1.4 1998/10/19 14:44:29 rgb
-+ * Added inclusion of freeswan.h.
-+ * sa_id structure implemented and used: now includes protocol.
-+ *
-+ * Revision 1.3 1998/07/28 00:03:31 rgb
-+ * Comment out temporary inet_nto4u() kluge.
-+ *
-+ * Revision 1.2 1998/07/14 18:22:00 rgb
-+ * Add function to clear the eroute table.
-+ *
-+ * Revision 1.1 1998/06/18 21:27:49 henry
-+ * move sources from klips/src to klips/net/ipsec, to keep stupid
-+ * kernel-build scripts happier in the presence of symlinks
-+ *
-+ * Revision 1.5 1998/05/25 20:30:38 rgb
-+ * Remove temporary ipsec_walk, rj_deltree and rj_delnodes functions.
-+ *
-+ * Rename ipsec_rj_walker (ipsec_walk) to ipsec_rj_walker_procprint and
-+ * add ipsec_rj_walker_delete.
-+ *
-+ * Revision 1.4 1998/05/21 13:02:56 rgb
-+ * Imported definitions from ipsec_radij.c and radij.c to support /proc 3k
-+ * limit fix.
-+ *
-+ * Revision 1.3 1998/04/21 21:29:09 rgb
-+ * Rearrange debug switches to change on the fly debug output from user
-+ * space. Only kernel changes checked in at this time. radij.c was also
-+ * changed to temporarily remove buggy debugging code in rj_delete causing
-+ * an OOPS and hence, netlink device open errors.
-+ *
-+ * Revision 1.2 1998/04/14 17:30:39 rgb
-+ * Fix up compiling errors for radij tree memory reclamation.
-+ *
-+ * Revision 1.1 1998/04/09 03:06:10 henry
-+ * sources moved up from linux/net/ipsec
-+ *
-+ * Revision 1.1.1.1 1998/04/08 05:35:04 henry
-+ * RGB's ipsec-0.8pre2.tar.gz ipsec-0.8
-+ *
-+ * Revision 0.4 1997/01/15 01:28:15 ji
-+ * No changes.
-+ *
-+ * Revision 0.3 1996/11/20 14:39:04 ji
-+ * Minor cleanups.
-+ * Rationalized debugging code.
-+ *
-+ * Revision 0.2 1996/11/02 00:18:33 ji
-+ * First limited release.
-+ *
-+ *
-+ */
---- /dev/null Tue Mar 11 13:02:56 2003
-+++ linux/include/openswan/ipsec_rcv.h Mon Feb 9 13:51:03 2004
-@@ -0,0 +1,279 @@
-+/*
-+ *
-+ * Copyright (C) 1996, 1997 John Ioannidis.
-+ * Copyright (C) 1998, 1999, 2000, 2001 Richard Guy Briggs.
-+ *
-+ * 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. See <http://www.fsf.org/copyleft/gpl.txt>.
-+ *
-+ * 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.
-+ *
-+ * RCSID $Id: ipsec_rcv.h,v 1.21 2004/04/06 02:49:08 mcr Exp $
-+ */
-+
-+#ifndef IPSEC_RCV_H
-+#define IPSEC_RCV_H
-+
-+#include "openswan/ipsec_auth.h"
-+
-+#define DB_RX_PKTRX 0x0001
-+#define DB_RX_PKTRX2 0x0002
-+#define DB_RX_DMP 0x0004
-+#define DB_RX_IPSA 0x0010
-+#define DB_RX_XF 0x0020
-+#define DB_RX_IPAD 0x0040
-+#define DB_RX_INAU 0x0080
-+#define DB_RX_OINFO 0x0100
-+#define DB_RX_OINFO2 0x0200
-+#define DB_RX_OH 0x0400
-+#define DB_RX_REPLAY 0x0800
-+
-+#ifdef __KERNEL__
-+/* struct options; */
-+
-+#define __NO_VERSION__
-+#include <linux/module.h>
-+#include <linux/config.h> /* for CONFIG_IP_FORWARD */
-+#include <linux/version.h>
-+#include <openswan.h>
-+
-+#define IPSEC_BIRTH_TEMPLATE_MAXLEN 256
-+
-+struct ipsec_birth_reply {
-+ int packet_template_len;
-+ unsigned char packet_template[IPSEC_BIRTH_TEMPLATE_MAXLEN];
-+};
-+
-+extern struct ipsec_birth_reply ipsec_ipv4_birth_packet;
-+extern struct ipsec_birth_reply ipsec_ipv6_birth_packet;
-+
-+enum ipsec_rcv_value {
-+ IPSEC_RCV_LASTPROTO=1,
-+ IPSEC_RCV_OK=0,
-+ IPSEC_RCV_BADPROTO=-1,
-+ IPSEC_RCV_BADLEN=-2,
-+ IPSEC_RCV_ESP_BADALG=-3,
-+ IPSEC_RCV_3DES_BADBLOCKING=-4,
-+ IPSEC_RCV_ESP_DECAPFAIL=-5,
-+ IPSEC_RCV_DECAPFAIL=-6,
-+ IPSEC_RCV_SAIDNOTFOUND=-7,
-+ IPSEC_RCV_IPCOMPALONE=-8,
-+ IPSEC_RCV_IPCOMPFAILED=-10,
-+ IPSEC_RCV_SAIDNOTLIVE=-11,
-+ IPSEC_RCV_FAILEDINBOUND=-12,
-+ IPSEC_RCV_LIFETIMEFAILED=-13,
-+ IPSEC_RCV_BADAUTH=-14,
-+ IPSEC_RCV_REPLAYFAILED=-15,
-+ IPSEC_RCV_AUTHFAILED=-16,
-+ IPSEC_RCV_REPLAYROLLED=-17,
-+ IPSEC_RCV_BAD_DECRYPT=-18
-+};
-+
-+struct ipsec_rcv_state {
-+ struct sk_buff *skb;
-+ struct net_device_stats *stats;
-+ struct iphdr *ipp;
-+ struct ipsec_sa *ipsp;
-+ int len;
-+ int ilen;
-+ int authlen;
-+ int hard_header_len;
-+ int iphlen;
-+ struct auth_alg *authfuncs;
-+ ip_said said;
-+ char sa[SATOT_BUF];
-+ size_t sa_len;
-+ __u8 next_header;
-+ __u8 hash[AH_AMAX];
-+ char ipsaddr_txt[ADDRTOA_BUF];
-+ char ipdaddr_txt[ADDRTOA_BUF];
-+ __u8 *octx;
-+ __u8 *ictx;
-+ int ictx_len;
-+ int octx_len;
-+ union {
-+ struct {
-+ struct esphdr *espp;
-+ } espstuff;
-+ struct {
-+ struct ahhdr *ahp;
-+ } ahstuff;
-+ struct {
-+ struct ipcomphdr *compp;
-+ } ipcompstuff;
-+ } protostuff;
-+#ifdef CONFIG_IPSEC_NAT_TRAVERSAL
-+ __u8 natt_type;
-+ __u16 natt_sport;
-+ __u16 natt_dport;
-+ int natt_len;
-+#endif
-+};
-+
-+extern int
-+#ifdef PROTO_HANDLER_SINGLE_PARM
-+ipsec_rcv(struct sk_buff *skb);
-+#else /* PROTO_HANDLER_SINGLE_PARM */
-+ipsec_rcv(struct sk_buff *skb,
-+#ifdef NET_21
-+ unsigned short xlen);
-+#else /* NET_21 */
-+ struct device *dev,
-+ struct options *opt,
-+ __u32 daddr,
-+ unsigned short len,
-+ __u32 saddr,
-+ int redo,
-+ struct inet_protocol *protocol);
-+#endif /* NET_21 */
-+#endif /* PROTO_HANDLER_SINGLE_PARM */
-+
-+#ifdef CONFIG_IPSEC_DEBUG
-+extern int debug_rcv;
-+#endif /* CONFIG_IPSEC_DEBUG */
-+#define ipsec_rcv_dmp(_x,_y, _z) if (debug_rcv && sysctl_ipsec_debug_verbose) ipsec_dmp(_x,_y,_z)
-+
-+extern int sysctl_ipsec_inbound_policy_check;
-+#endif /* __KERNEL__ */
-+
-+#endif /* IPSEC_RCV_H */
-+
-+/*
-+ * $Log: ipsec_rcv.h,v $
-+ * Revision 1.21 2004/04/06 02:49:08 mcr
-+ * pullup of algo code from alg-branch.
-+ *
-+ * Revision 1.20 2004/04/05 19:55:06 mcr
-+ * Moved from linux/include/freeswan/ipsec_rcv.h,v
-+ *
-+ * Revision 1.19 2003/12/15 18:13:09 mcr
-+ * when compiling with NAT traversal, don't assume that the
-+ * kernel has been patched, unless CONFIG_IPSEC_NAT_NON_ESP
-+ * is set.
-+ *
-+ * Revision 1.18 2003/12/13 19:10:16 mcr
-+ * refactored rcv and xmit code - same as FS 2.05.
-+ *
-+ * Revision 1.17 2002/09/03 16:32:32 mcr
-+ * definitions of ipsec_birth_reply.
-+ *
-+ * Revision 1.16 2002/05/14 02:36:00 rgb
-+ * Change references to _TDB to _IPSA.
-+ *
-+ * Revision 1.15 2002/04/24 07:36:47 mcr
-+ * Moved from ./klips/net/ipsec/ipsec_rcv.h,v
-+ *
-+ * Revision 1.14 2001/09/07 22:15:48 rgb
-+ * Fix for removal of transport layer protocol handler arg in 2.4.4.
-+ *
-+ * Revision 1.13 2001/06/14 19:35:09 rgb
-+ * Update copyright date.
-+ *
-+ * Revision 1.12 2001/03/16 07:36:44 rgb
-+ * Fixed #endif comment to sate compiler.
-+ *
-+ * Revision 1.11 2000/09/21 04:34:21 rgb
-+ * Moved declaration of sysctl_ipsec_inbound_policy_check outside
-+ * CONFIG_IPSEC_DEBUG. (MB)
-+ *
-+ * Revision 1.10 2000/09/18 02:36:10 rgb
-+ * Exported sysctl_ipsec_inbound_policy_check for skb_decompress().
-+ *
-+ * Revision 1.9 2000/09/08 19:12:56 rgb
-+ * Change references from DEBUG_IPSEC to CONFIG_IPSEC_DEBUG.
-+ *
-+ * Revision 1.8 1999/11/18 04:09:19 rgb
-+ * Replaced all kernel version macros to shorter, readable form.
-+ *
-+ * Revision 1.7 1999/05/25 01:45:37 rgb
-+ * Fix version macros for 2.0.x as a module.
-+ *
-+ * Revision 1.6 1999/05/08 21:24:27 rgb
-+ * Add includes for 2.2.x include into net/ipv4/protocol.c
-+ *
-+ * Revision 1.5 1999/05/05 22:02:32 rgb
-+ * Add a quick and dirty port to 2.2 kernels by Marc Boucher <marc@mbsi.ca>.
-+ *
-+ * Revision 1.4 1999/04/11 00:28:59 henry
-+ * GPL boilerplate
-+ *
-+ * Revision 1.3 1999/04/06 04:54:27 rgb
-+ * Fix/Add RCSID Id: and Log: bits to make PHMDs happy. This includes
-+ * patch shell fixes.
-+ *
-+ * Revision 1.2 1999/01/22 20:06:59 rgb
-+ * Fixed cut-and-paste error from ipsec_esp.h.
-+ *
-+ * Revision 1.1 1999/01/21 20:29:12 rgb
-+ * Converted from transform switching to algorithm switching.
-+ *
-+ * Log: ipsec_esp.h,v
-+ * Revision 1.4 1998/08/12 00:07:32 rgb
-+ * Added data structures for new xforms: null, {,3}dessha1.
-+ *
-+ * Revision 1.3 1998/07/14 15:57:01 rgb
-+ * Add #ifdef __KERNEL__ to protect kernel-only structures.
-+ *
-+ * Revision 1.2 1998/06/25 19:33:46 rgb
-+ * Add prototype for protocol receive function.
-+ * Rearrange for more logical layout.
-+ *
-+ * Revision 1.1 1998/06/18 21:27:45 henry
-+ * move sources from klips/src to klips/net/ipsec, to keep stupid
-+ * kernel-build scripts happier in the presence of symlinks
-+ *
-+ * Revision 1.6 1998/06/05 02:28:08 rgb
-+ * Minor comment fix.
-+ *
-+ * Revision 1.5 1998/05/27 22:34:00 rgb
-+ * Changed structures to accomodate key separation.
-+ *
-+ * Revision 1.4 1998/05/18 22:28:43 rgb
-+ * Disable key printing facilities from /proc/net/ipsec_*.
-+ *
-+ * Revision 1.3 1998/04/21 21:29:07 rgb
-+ * Rearrange debug switches to change on the fly debug output from user
-+ * space. Only kernel changes checked in at this time. radij.c was also
-+ * changed to temporarily remove buggy debugging code in rj_delete causing
-+ * an OOPS and hence, netlink device open errors.
-+ *
-+ * Revision 1.2 1998/04/12 22:03:20 rgb
-+ * Updated ESP-3DES-HMAC-MD5-96,
-+ * ESP-DES-HMAC-MD5-96,
-+ * AH-HMAC-MD5-96,
-+ * AH-HMAC-SHA1-96 since Henry started freeswan cvs repository
-+ * from old standards (RFC182[5-9] to new (as of March 1998) drafts.
-+ *
-+ * Fixed eroute references in /proc/net/ipsec*.
-+ *
-+ * Started to patch module unloading memory leaks in ipsec_netlink and
-+ * radij tree unloading.
-+ *
-+ * Revision 1.1 1998/04/09 03:06:00 henry
-+ * sources moved up from linux/net/ipsec
-+ *
-+ * Revision 1.1.1.1 1998/04/08 05:35:02 henry
-+ * RGB's ipsec-0.8pre2.tar.gz ipsec-0.8
-+ *
-+ * Revision 0.5 1997/06/03 04:24:48 ji
-+ * Added ESP-3DES-MD5-96 transform.
-+ *
-+ * Revision 0.4 1997/01/15 01:28:15 ji
-+ * Added definitions for new ESP transforms.
-+ *
-+ * Revision 0.3 1996/11/20 14:35:48 ji
-+ * Minor Cleanup.
-+ * Rationalized debugging code.
-+ *
-+ * Revision 0.2 1996/11/02 00:18:33 ji
-+ * First limited release.
-+ *
-+ *
-+ */
-+
-+
---- /dev/null Tue Mar 11 13:02:56 2003
-+++ linux/include/openswan/ipsec_sa.h Mon Feb 9 13:51:03 2004
-@@ -0,0 +1,341 @@
-+/*
-+ * @(#) Definitions of IPsec Security Association (ipsec_sa)
-+ *
-+ * Copyright (C) 2001, 2002, 2003
-+ * Richard Guy Briggs <rgb@freeswan.org>
-+ * and Michael Richardson <mcr@freeswan.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. See <http://www.fsf.org/copyleft/gpl.txt>.
-+ *
-+ * 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.
-+ *
-+ * RCSID $Id: ipsec_sa.h,v 1.19 2004/04/05 19:55:06 mcr Exp $
-+ *
-+ * This file derived from ipsec_xform.h on 2001/9/18 by mcr.
-+ *
-+ */
-+
-+/*
-+ * This file describes the IPsec Security Association Structure.
-+ *
-+ * This structure keeps track of a single transform that may be done
-+ * to a set of packets. It can describe applying the transform or
-+ * apply the reverse. (e.g. compression vs expansion). However, it
-+ * only describes one at a time. To describe both, two structures would
-+ * be used, but since the sides of the transform are performed
-+ * on different machines typically it is usual to have only one side
-+ * of each association.
-+ *
-+ */
-+
-+#ifndef _IPSEC_SA_H_
-+
-+#ifdef __KERNEL__
-+#include "ipsec_stats.h"
-+#include "ipsec_life.h"
-+#include "ipsec_eroute.h"
-+#endif /* __KERNEL__ */
-+#include "ipsec_param.h"
-+
-+
-+/* SAs are held in a table.
-+ * Entries in this table are referenced by IPsecSAref_t values.
-+ * IPsecSAref_t values are conceptually subscripts. Because
-+ * we want to allocate the table piece-meal, the subscripting
-+ * is implemented with two levels, a bit like paged virtual memory.
-+ * This representation mechanism is known as an Iliffe Vector.
-+ *
-+ * The Main table (AKA the refTable) consists of 2^IPSEC_SA_REF_MAINTABLE_IDX_WIDTH
-+ * pointers to subtables.
-+ * Each subtable has 2^IPSEC_SA_REF_SUBTABLE_IDX_WIDTH entries, each of which
-+ * is a pointer to an SA.
-+ *
-+ * An IPsecSAref_t contains either an exceptional value (signified by the
-+ * high-order bit being on) or a reference to a table entry. A table entry
-+ * reference has the subtable subscript in the low-order
-+ * IPSEC_SA_REF_SUBTABLE_IDX_WIDTH bits and the Main table subscript
-+ * in the next lowest IPSEC_SA_REF_MAINTABLE_IDX_WIDTH bits.
-+ *
-+ * The Maintable entry for an IPsecSAref_t x, a pointer to its subtable, is
-+ * IPsecSAref2table(x). It is of type struct IPsecSArefSubTable *.
-+ *
-+ * The pointer to the SA for x is IPsecSAref2SA(x). It is of type
-+ * struct ipsec_sa*. The macro definition clearly shows the two-level
-+ * access needed to find the SA pointer.
-+ *
-+ * The Maintable is allocated when IPsec is initialized.
-+ * Each subtable is allocated when needed, but the first is allocated
-+ * when IPsec is initialized.
-+ *
-+ * IPsecSAref_t is designed to be smaller than an NFmark so that
-+ * they can be stored in NFmarks and still leave a few bits for other
-+ * purposes. The spare bits are in the low order of the NFmark
-+ * but in the high order of the IPsecSAref_t, so conversion is required.
-+ * We pick the upper bits of NFmark on the theory that they are less likely to
-+ * interfere with more pedestrian uses of nfmark.
-+ */
-+
-+
-+typedef unsigned short int IPsecRefTableUnusedCount;
-+
-+#define IPSEC_SA_REF_TABLE_NUM_ENTRIES (1 << IPSEC_SA_REF_TABLE_IDX_WIDTH)
-+
-+#ifdef __KERNEL__
-+#if ((IPSEC_SA_REF_TABLE_IDX_WIDTH - (1 + IPSEC_SA_REF_MAINTABLE_IDX_WIDTH)) < 0)
-+#error "IPSEC_SA_REF_TABLE_IDX_WIDTH("IPSEC_SA_REF_TABLE_IDX_WIDTH") MUST be < 1 + IPSEC_SA_REF_MAINTABLE_IDX_WIDTH("IPSEC_SA_REF_MAINTABLE_IDX_WIDTH")"
-+#endif
-+
-+#define IPSEC_SA_REF_SUBTABLE_IDX_WIDTH (IPSEC_SA_REF_TABLE_IDX_WIDTH - IPSEC_SA_REF_MAINTABLE_IDX_WIDTH)
-+
-+#define IPSEC_SA_REF_MAINTABLE_NUM_ENTRIES (1 << IPSEC_SA_REF_MAINTABLE_IDX_WIDTH)
-+#define IPSEC_SA_REF_SUBTABLE_NUM_ENTRIES (1 << IPSEC_SA_REF_SUBTABLE_IDX_WIDTH)
-+
-+#ifdef CONFIG_NETFILTER
-+#define IPSEC_SA_REF_HOST_FIELD(x) ((struct sk_buff*)(x))->nfmark
-+#define IPSEC_SA_REF_HOST_FIELD_TYPE typeof(IPSEC_SA_REF_HOST_FIELD(NULL))
-+#else /* CONFIG_NETFILTER */
-+/* just make it work for now, it doesn't matter, since there is no nfmark */
-+#define IPSEC_SA_REF_HOST_FIELD_TYPE unsigned long
-+#endif /* CONFIG_NETFILTER */
-+#define IPSEC_SA_REF_HOST_FIELD_WIDTH (8 * sizeof(IPSEC_SA_REF_HOST_FIELD_TYPE))
-+#define IPSEC_SA_REF_FIELD_WIDTH (8 * sizeof(IPsecSAref_t))
-+
-+#define IPSEC_SA_REF_MASK (IPSEC_SAREF_NULL >> (IPSEC_SA_REF_FIELD_WIDTH - IPSEC_SA_REF_TABLE_IDX_WIDTH))
-+#define IPSEC_SA_REF_TABLE_MASK ((IPSEC_SAREF_NULL >> (IPSEC_SA_REF_FIELD_WIDTH - IPSEC_SA_REF_MAINTABLE_IDX_WIDTH)) << IPSEC_SA_REF_SUBTABLE_IDX_WIDTH)
-+#define IPSEC_SA_REF_ENTRY_MASK (IPSEC_SAREF_NULL >> (IPSEC_SA_REF_FIELD_WIDTH - IPSEC_SA_REF_SUBTABLE_IDX_WIDTH))
-+
-+#define IPsecSAref2table(x) (((x) & IPSEC_SA_REF_TABLE_MASK) >> IPSEC_SA_REF_SUBTABLE_IDX_WIDTH)
-+#define IPsecSAref2entry(x) ((x) & IPSEC_SA_REF_ENTRY_MASK)
-+#define IPsecSArefBuild(x,y) (((x) << IPSEC_SA_REF_SUBTABLE_IDX_WIDTH) + (y))
-+
-+#define IPsecSAref2SA(x) (ipsec_sadb.refTable[IPsecSAref2table(x)]->entry[IPsecSAref2entry(x)])
-+#define IPsecSA2SAref(x) ((x)->ips_ref)
-+
-+#define EMT_INBOUND 0x01 /* SA direction, 1=inbound */
-+
-+/* 'struct ipsec_sa' should be 64bit aligned when allocated. */
-+struct ipsec_sa
-+{
-+ IPsecSAref_t ips_ref; /* reference table entry number */
-+ atomic_t ips_refcount; /* reference count for this struct */
-+ struct ipsec_sa *ips_hnext; /* next in hash chain */
-+ struct ipsec_sa *ips_inext; /* pointer to next xform */
-+ struct ipsec_sa *ips_onext; /* pointer to prev xform */
-+
-+ struct ifnet *ips_rcvif; /* related rcv encap interface */
-+
-+ ip_said ips_said; /* SA ID */
-+
-+ __u32 ips_seq; /* seq num of msg that initiated this SA */
-+ __u32 ips_pid; /* PID of process that initiated this SA */
-+ __u8 ips_authalg; /* auth algorithm for this SA */
-+ __u8 ips_encalg; /* enc algorithm for this SA */
-+
-+ struct ipsec_stats ips_errs;
-+
-+ __u8 ips_replaywin; /* replay window size */
-+ __u8 ips_state; /* state of SA */
-+ __u32 ips_replaywin_lastseq; /* last pkt sequence num */
-+ __u64 ips_replaywin_bitmap; /* bitmap of received pkts */
-+ __u32 ips_replaywin_maxdiff; /* max pkt sequence difference */
-+
-+ __u32 ips_flags; /* generic xform flags */
-+
-+
-+ struct ipsec_lifetimes ips_life; /* lifetime records */
-+
-+ /* selector information */
-+ __u8 ips_transport_protocol; /* protocol for this SA, if ports are involved */
-+ struct sockaddr*ips_addr_s; /* src sockaddr */
-+ struct sockaddr*ips_addr_d; /* dst sockaddr */
-+ struct sockaddr*ips_addr_p; /* proxy sockaddr */
-+ __u16 ips_addr_s_size;
-+ __u16 ips_addr_d_size;
-+ __u16 ips_addr_p_size;
-+ ip_address ips_flow_s;
-+ ip_address ips_flow_d;
-+ ip_address ips_mask_s;
-+ ip_address ips_mask_d;
-+
-+ __u16 ips_key_bits_a; /* size of authkey in bits */
-+ __u16 ips_auth_bits; /* size of authenticator in bits */
-+ __u16 ips_key_bits_e; /* size of enckey in bits */
-+ __u16 ips_iv_bits; /* size of IV in bits */
-+ __u8 ips_iv_size;
-+ __u16 ips_key_a_size;
-+ __u16 ips_key_e_size;
-+
-+ caddr_t ips_key_a; /* authentication key */
-+ caddr_t ips_key_e; /* encryption key */
-+ caddr_t ips_iv; /* Initialisation Vector */
-+
-+ struct ident ips_ident_s; /* identity src */
-+ struct ident ips_ident_d; /* identity dst */
-+
-+#ifdef CONFIG_IPSEC_IPCOMP
-+ __u16 ips_comp_adapt_tries; /* ipcomp self-adaption tries */
-+ __u16 ips_comp_adapt_skip; /* ipcomp self-adaption to-skip */
-+ __u64 ips_comp_ratio_cbytes; /* compressed bytes */
-+ __u64 ips_comp_ratio_dbytes; /* decompressed (or uncompressed) bytes */
-+#endif /* CONFIG_IPSEC_IPCOMP */
-+
-+#ifdef CONFIG_IPSEC_NAT_TRAVERSAL
-+ __u8 ips_natt_type;
-+ __u8 ips_natt_reserved[3];
-+ __u16 ips_natt_sport;
-+ __u16 ips_natt_dport;
-+
-+ struct sockaddr *ips_natt_oa;
-+ __u16 ips_natt_oa_size;
-+ __u16 ips_natt_reserved2;
-+#endif
-+
-+#if 0
-+ __u32 ips_sens_dpd;
-+ __u8 ips_sens_sens_level;
-+ __u8 ips_sens_sens_len;
-+ __u64* ips_sens_sens_bitmap;
-+ __u8 ips_sens_integ_level;
-+ __u8 ips_sens_integ_len;
-+ __u64* ips_sens_integ_bitmap;
-+#endif
-+ struct ipsec_alg_enc *ips_alg_enc;
-+ struct ipsec_alg_auth *ips_alg_auth;
-+ IPsecSAref_t ips_ref_rel;
-+};
-+
-+struct IPsecSArefSubTable
-+{
-+ struct ipsec_sa* entry[IPSEC_SA_REF_SUBTABLE_NUM_ENTRIES];
-+};
-+
-+struct ipsec_sadb {
-+ struct IPsecSArefSubTable* refTable[IPSEC_SA_REF_MAINTABLE_NUM_ENTRIES];
-+ IPsecSAref_t refFreeList[IPSEC_SA_REF_FREELIST_NUM_ENTRIES];
-+ int refFreeListHead;
-+ int refFreeListTail;
-+ IPsecSAref_t refFreeListCont;
-+ IPsecSAref_t said_hash[SADB_HASHMOD];
-+ spinlock_t sadb_lock;
-+};
-+
-+extern struct ipsec_sadb ipsec_sadb;
-+
-+extern int ipsec_SAref_recycle(void);
-+extern int ipsec_SArefSubTable_alloc(unsigned table);
-+extern int ipsec_saref_freelist_init(void);
-+extern int ipsec_sadb_init(void);
-+extern struct ipsec_sa *ipsec_sa_alloc(int*error); /* pass in error var by pointer */
-+extern IPsecSAref_t ipsec_SAref_alloc(int*erorr); /* pass in error var by pointer */
-+extern int ipsec_sa_free(struct ipsec_sa* ips);
-+extern int ipsec_sa_put(struct ipsec_sa *ips);
-+extern int ipsec_sa_add(struct ipsec_sa *ips);
-+extern int ipsec_sa_del(struct ipsec_sa *ips);
-+extern int ipsec_sa_delchain(struct ipsec_sa *ips);
-+extern int ipsec_sadb_cleanup(__u8 proto);
-+extern int ipsec_sadb_free(void);
-+extern int ipsec_sa_wipe(struct ipsec_sa *ips);
-+#endif /* __KERNEL__ */
-+
-+enum ipsec_direction {
-+ ipsec_incoming = 1,
-+ ipsec_outgoing = 2
-+};
-+
-+#define _IPSEC_SA_H_
-+#endif /* _IPSEC_SA_H_ */
-+
-+/*
-+ * $Log: ipsec_sa.h,v $
-+ * Revision 1.19 2004/04/05 19:55:06 mcr
-+ * Moved from linux/include/freeswan/ipsec_sa.h,v
-+ *
-+ * Revision 1.18 2004/04/05 19:41:05 mcr
-+ * merged alg-branch code.
-+ *
-+ * Revision 1.17.2.1 2003/12/22 15:25:52 jjo
-+ * . Merged algo-0.8.1-rc11-test1 into alg-branch
-+ *
-+ * Revision 1.17 2003/12/10 01:20:06 mcr
-+ * NAT-traversal patches to KLIPS.
-+ *
-+ * Revision 1.16 2003/10/31 02:27:05 mcr
-+ * pulled up port-selector patches and sa_id elimination.
-+ *
-+ * Revision 1.15.4.1 2003/10/29 01:10:19 mcr
-+ * elimited "struct sa_id"
-+ *
-+ * Revision 1.15 2003/05/11 00:53:09 mcr
-+ * IPsecSAref_t and macros were moved to freeswan.h.
-+ *
-+ * Revision 1.14 2003/02/12 19:31:55 rgb
-+ * Fixed bug in "file seen" machinery.
-+ * Updated copyright year.
-+ *
-+ * Revision 1.13 2003/01/30 02:31:52 rgb
-+ *
-+ * Re-wrote comments describing SAref system for accuracy.
-+ * Rename SAref table macro names for clarity.
-+ * Convert IPsecSAref_t from signed to unsigned to fix apparent SAref exhaustion bug.
-+ * Transmit error code through to caller from callee for better diagnosis of problems.
-+ * Enclose all macro arguments in parens to avoid any possible obscrure bugs.
-+ *
-+ * Revision 1.12 2002/10/07 18:31:19 rgb
-+ * Change comment to reflect the flexible nature of the main and sub-table widths.
-+ * Added a counter for the number of unused entries in each subtable.
-+ * Further break up host field type macro to host field.
-+ * Move field width sanity checks to ipsec_sa.c
-+ * Define a mask for an entire saref.
-+ *
-+ * Revision 1.11 2002/09/20 15:40:33 rgb
-+ * Re-write most of the SAref macros and types to eliminate any pointer references to Entrys.
-+ * Fixed SAref/nfmark macros.
-+ * Rework saref freeslist.
-+ * Place all ipsec sadb globals into one struct.
-+ * Restrict some bits to kernel context for use to klips utils.
-+ *
-+ * Revision 1.10 2002/09/20 05:00:34 rgb
-+ * Update copyright date.
-+ *
-+ * Revision 1.9 2002/09/17 17:19:29 mcr
-+ * make it compile even if there is no netfilter - we lost
-+ * functionality, but it works, especially on 2.2.
-+ *
-+ * Revision 1.8 2002/07/28 22:59:53 mcr
-+ * clarified/expanded one comment.
-+ *
-+ * Revision 1.7 2002/07/26 08:48:31 rgb
-+ * Added SA ref table code.
-+ *
-+ * Revision 1.6 2002/05/31 17:27:48 rgb
-+ * Comment fix.
-+ *
-+ * Revision 1.5 2002/05/27 18:55:03 rgb
-+ * Remove final vistiges of tdb references via IPSEC_KLIPS1_COMPAT.
-+ *
-+ * Revision 1.4 2002/05/23 07:13:36 rgb
-+ * Convert "usecount" to "refcount" to remove ambiguity.
-+ *
-+ * Revision 1.3 2002/04/24 07:36:47 mcr
-+ * Moved from ./klips/net/ipsec/ipsec_sa.h,v
-+ *
-+ * Revision 1.2 2001/11/26 09:16:15 rgb
-+ * Merge MCR's ipsec_sa, eroute, proc and struct lifetime changes.
-+ *
-+ * Revision 1.1.2.1 2001/09/25 02:24:58 mcr
-+ * struct tdb -> struct ipsec_sa.
-+ * sa(tdb) manipulation functions renamed and moved to ipsec_sa.c
-+ * ipsec_xform.c removed. header file still contains useful things.
-+ *
-+ *
-+ * Local variables:
-+ * c-file-style: "linux"
-+ * End:
-+ *
-+ */
---- /dev/null Tue Mar 11 13:02:56 2003
-+++ linux/include/openswan/ipsec_sha1.h Mon Feb 9 13:51:03 2004
-@@ -0,0 +1,79 @@
-+/*
-+ * RCSID $Id: ipsec_sha1.h,v 1.8 2004/04/05 19:55:07 mcr Exp $
-+ */
-+
-+/*
-+ * Here is the original comment from the distribution:
-+
-+SHA-1 in C
-+By Steve Reid <steve@edmweb.com>
-+100% Public Domain
-+
-+ * Adapted for use by the IPSEC code by John Ioannidis
-+ */
-+
-+
-+#ifndef _IPSEC_SHA1_H_
-+#define _IPSEC_SHA1_H_
-+
-+typedef struct
-+{
-+ __u32 state[5];
-+ __u32 count[2];
-+ __u8 buffer[64];
-+} SHA1_CTX;
-+
-+void SHA1Transform(__u32 state[5], __u8 buffer[64]);
-+void SHA1Init(void *context);
-+void SHA1Update(void *context, unsigned char *data, __u32 len);
-+void SHA1Final(unsigned char digest[20], void *context);
-+
-+
-+#endif /* _IPSEC_SHA1_H_ */
-+
-+/*
-+ * $Log: ipsec_sha1.h,v $
-+ * Revision 1.8 2004/04/05 19:55:07 mcr
-+ * Moved from linux/include/freeswan/ipsec_sha1.h,v
-+ *
-+ * Revision 1.7 2002/09/10 01:45:09 mcr
-+ * changed type of MD5_CTX and SHA1_CTX to void * so that
-+ * the function prototypes would match, and could be placed
-+ * into a pointer to a function.
-+ *
-+ * Revision 1.6 2002/04/24 07:36:47 mcr
-+ * Moved from ./klips/net/ipsec/ipsec_sha1.h,v
-+ *
-+ * Revision 1.5 1999/12/13 13:59:13 rgb
-+ * Quick fix to argument size to Update bugs.
-+ *
-+ * Revision 1.4 1999/12/07 18:16:23 rgb
-+ * Fixed comments at end of #endif lines.
-+ *
-+ * Revision 1.3 1999/04/06 04:54:27 rgb
-+ * Fix/Add RCSID Id: and Log: bits to make PHMDs happy. This includes
-+ * patch shell fixes.
-+ *
-+ * Revision 1.2 1998/11/30 13:22:54 rgb
-+ * Rationalised all the klips kernel file headers. They are much shorter
-+ * now and won't conflict under RH5.2.
-+ *
-+ * Revision 1.1 1998/06/18 21:27:50 henry
-+ * move sources from klips/src to klips/net/ipsec, to keep stupid
-+ * kernel-build scripts happier in the presence of symlinks
-+ *
-+ * Revision 1.2 1998/04/23 20:54:05 rgb
-+ * Fixed md5 and sha1 include file nesting issues, to be cleaned up when
-+ * verified.
-+ *
-+ * Revision 1.1 1998/04/09 03:04:21 henry
-+ * sources moved up from linux/net/ipsec
-+ * these two include files modified not to include others except in kernel
-+ *
-+ * Revision 1.1.1.1 1998/04/08 05:35:04 henry
-+ * RGB's ipsec-0.8pre2.tar.gz ipsec-0.8
-+ *
-+ * Revision 0.4 1997/01/15 01:28:15 ji
-+ * New transform
-+ *
-+ */
---- /dev/null Tue Mar 11 13:02:56 2003
-+++ linux/include/openswan/ipsec_stats.h Mon Feb 9 13:51:03 2004
-@@ -0,0 +1,75 @@
-+/*
-+ * @(#) definition of ipsec_stats structure
-+ *
-+ * Copyright (C) 2001 Richard Guy Briggs <rgb@freeswan.org>
-+ * and Michael Richardson <mcr@freeswan.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. See <http://www.fsf.org/copyleft/gpl.txt>.
-+ *
-+ * 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.
-+ *
-+ * RCSID $Id: ipsec_stats.h,v 1.6 2004/04/05 19:55:07 mcr Exp $
-+ *
-+ */
-+
-+/*
-+ * This file describes the errors/statistics that FreeSWAN collects.
-+ */
-+
-+#ifndef _IPSEC_STATS_H_
-+
-+struct ipsec_stats {
-+ __u32 ips_alg_errs; /* number of algorithm errors */
-+ __u32 ips_auth_errs; /* # of authentication errors */
-+ __u32 ips_encsize_errs; /* # of encryption size errors*/
-+ __u32 ips_encpad_errs; /* # of encryption pad errors*/
-+ __u32 ips_replaywin_errs; /* # of pkt sequence errors */
-+};
-+
-+extern int ipsec_snprintf(char * buf, ssize_t size, const char *fmt, ...);
-+
-+#define _IPSEC_STATS_H_
-+#endif /* _IPSEC_STATS_H_ */
-+
-+/*
-+ * $Log: ipsec_stats.h,v $
-+ * Revision 1.6 2004/04/05 19:55:07 mcr
-+ * Moved from linux/include/freeswan/ipsec_stats.h,v
-+ *
-+ * Revision 1.5 2004/04/05 19:41:05 mcr
-+ * merged alg-branch code.
-+ *
-+ * Revision 1.4 2004/03/28 20:27:19 paul
-+ * Included tested and confirmed fixes mcr made and dhr verified for
-+ * snprint statements. Changed one other snprintf to use ipsec_snprintf
-+ * so it wouldnt break compatibility with 2.0/2.2 kernels. Verified with
-+ * dhr. (thanks dhr!)
-+ *
-+ * Revision 1.4 2004/03/24 01:58:31 mcr
-+ * sprintf->snprintf for formatting into proc buffer.
-+ *
-+ * Revision 1.3.34.1 2004/04/05 04:30:46 mcr
-+ * patches for alg-branch to compile/work with 2.x openswan
-+ *
-+ * Revision 1.3 2002/04/24 07:36:47 mcr
-+ * Moved from ./klips/net/ipsec/ipsec_stats.h,v
-+ *
-+ * Revision 1.2 2001/11/26 09:16:16 rgb
-+ * Merge MCR's ipsec_sa, eroute, proc and struct lifetime changes.
-+ *
-+ * Revision 1.1.2.1 2001/09/25 02:27:00 mcr
-+ * statistics moved to seperate structure.
-+ *
-+ *
-+ *
-+ * Local variables:
-+ * c-file-style: "linux"
-+ * End:
-+ *
-+ */
---- /dev/null Tue Mar 11 13:02:56 2003
-+++ linux/include/openswan/ipsec_tunnel.h Mon Feb 9 13:51:03 2004
-@@ -0,0 +1,265 @@
-+/*
-+ * IPSEC tunneling code
-+ * Copyright (C) 1996, 1997 John Ioannidis.
-+ * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 Richard Guy Briggs.
-+ *
-+ * 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. See <http://www.fsf.org/copyleft/gpl.txt>.
-+ *
-+ * 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.
-+ *
-+ * RCSID $Id: ipsec_tunnel.h,v 1.29 2004/04/05 19:55:07 mcr Exp $
-+ */
-+
-+
-+#ifdef NET_21
-+# define DEV_QUEUE_XMIT(skb, device, pri) {\
-+ skb->dev = device; \
-+ neigh_compat_output(skb); \
-+ /* skb->dst->output(skb); */ \
-+ }
-+# define ICMP_SEND(skb_in, type, code, info, dev) \
-+ icmp_send(skb_in, type, code, htonl(info))
-+# define IP_SEND(skb, dev) \
-+ ip_send(skb);
-+#else /* NET_21 */
-+# define DEV_QUEUE_XMIT(skb, device, pri) {\
-+ dev_queue_xmit(skb, device, pri); \
-+ }
-+# define ICMP_SEND(skb_in, type, code, info, dev) \
-+ icmp_send(skb_in, type, code, info, dev)
-+# define IP_SEND(skb, dev) \
-+ if(ntohs(iph->tot_len) > physmtu) { \
-+ ip_fragment(NULL, skb, dev, 0); \
-+ ipsec_kfree_skb(skb); \
-+ } else { \
-+ dev_queue_xmit(skb, dev, SOPRI_NORMAL); \
-+ }
-+#endif /* NET_21 */
-+
-+
-+/*
-+ * Heavily based on drivers/net/new_tunnel.c. Lots
-+ * of ideas also taken from the 2.1.x version of drivers/net/shaper.c
-+ */
-+
-+struct ipsectunnelconf
-+{
-+ __u32 cf_cmd;
-+ union
-+ {
-+ char cfu_name[12];
-+ } cf_u;
-+#define cf_name cf_u.cfu_name
-+};
-+
-+#define IPSEC_SET_DEV (SIOCDEVPRIVATE)
-+#define IPSEC_DEL_DEV (SIOCDEVPRIVATE + 1)
-+#define IPSEC_CLR_DEV (SIOCDEVPRIVATE + 2)
-+
-+#ifdef __KERNEL__
-+#include <linux/version.h>
-+#ifndef KERNEL_VERSION
-+# define KERNEL_VERSION(x,y,z) (((x)<<16)+((y)<<8)+(z))
-+#endif
-+struct ipsecpriv
-+{
-+ struct sk_buff_head sendq;
-+ struct device *dev;
-+ struct wait_queue *wait_queue;
-+ char locked;
-+ int (*hard_start_xmit) (struct sk_buff *skb,
-+ struct device *dev);
-+ int (*hard_header) (struct sk_buff *skb,
-+ struct device *dev,
-+ unsigned short type,
-+ void *daddr,
-+ void *saddr,
-+ unsigned len);
-+#ifdef NET_21
-+ int (*rebuild_header)(struct sk_buff *skb);
-+#else /* NET_21 */
-+ int (*rebuild_header)(void *buff, struct device *dev,
-+ unsigned long raddr, struct sk_buff *skb);
-+#endif /* NET_21 */
-+ int (*set_mac_address)(struct device *dev, void *addr);
-+#ifndef NET_21
-+ void (*header_cache_bind)(struct hh_cache **hhp, struct device *dev,
-+ unsigned short htype, __u32 daddr);
-+#endif /* !NET_21 */
-+ void (*header_cache_update)(struct hh_cache *hh, struct device *dev, unsigned char * haddr);
-+ struct net_device_stats *(*get_stats)(struct device *dev);
-+ struct net_device_stats mystats;
-+ int mtu; /* What is the desired MTU? */
-+};
-+
-+extern char ipsec_tunnel_c_version[];
-+
-+extern struct device *ipsecdevices[IPSEC_NUM_IF];
-+
-+int ipsec_tunnel_init_devices(void);
-+
-+/* void */ int ipsec_tunnel_cleanup_devices(void);
-+
-+extern /* void */ int ipsec_init(void);
-+
-+extern int ipsec_tunnel_start_xmit(struct sk_buff *skb, struct device *dev);
-+
-+#ifdef CONFIG_IPSEC_DEBUG
-+extern int debug_tunnel;
-+extern int sysctl_ipsec_debug_verbose;
-+#endif /* CONFIG_IPSEC_DEBUG */
-+#endif /* __KERNEL__ */
-+
-+#ifdef CONFIG_IPSEC_DEBUG
-+#define DB_TN_INIT 0x0001
-+#define DB_TN_PROCFS 0x0002
-+#define DB_TN_XMIT 0x0010
-+#define DB_TN_OHDR 0x0020
-+#define DB_TN_CROUT 0x0040
-+#define DB_TN_OXFS 0x0080
-+#define DB_TN_REVEC 0x0100
-+#endif /* CONFIG_IPSEC_DEBUG */
-+
-+/*
-+ * $Log: ipsec_tunnel.h,v $
-+ * Revision 1.29 2004/04/05 19:55:07 mcr
-+ * Moved from linux/include/freeswan/ipsec_tunnel.h,v
-+ *
-+ * Revision 1.28 2003/06/24 20:22:32 mcr
-+ * added new global: ipsecdevices[] so that we can keep track of
-+ * the ipsecX devices. They will be referenced with dev_hold(),
-+ * so 2.2 may need this as well.
-+ *
-+ * Revision 1.27 2003/04/03 17:38:09 rgb
-+ * Centralised ipsec_kfree_skb and ipsec_dev_{get,put}.
-+ *
-+ * Revision 1.26 2003/02/12 19:32:20 rgb
-+ * Updated copyright year.
-+ *
-+ * Revision 1.25 2002/05/27 18:56:07 rgb
-+ * Convert to dynamic ipsec device allocation.
-+ *
-+ * Revision 1.24 2002/04/24 07:36:48 mcr
-+ * Moved from ./klips/net/ipsec/ipsec_tunnel.h,v
-+ *
-+ * Revision 1.23 2001/11/06 19:50:44 rgb
-+ * Moved IP_SEND, ICMP_SEND, DEV_QUEUE_XMIT macros to ipsec_tunnel.h for
-+ * use also by pfkey_v2_parser.c
-+ *
-+ * Revision 1.22 2001/09/15 16:24:05 rgb
-+ * Re-inject first and last HOLD packet when an eroute REPLACE is done.
-+ *
-+ * Revision 1.21 2001/06/14 19:35:10 rgb
-+ * Update copyright date.
-+ *
-+ * Revision 1.20 2000/09/15 11:37:02 rgb
-+ * Merge in heavily modified Svenning Soerensen's <svenning@post5.tele.dk>
-+ * IPCOMP zlib deflate code.
-+ *
-+ * Revision 1.19 2000/09/08 19:12:56 rgb
-+ * Change references from DEBUG_IPSEC to CONFIG_IPSEC_DEBUG.
-+ *
-+ * Revision 1.18 2000/07/28 13:50:54 rgb
-+ * Changed enet_statistics to net_device_stats and added back compatibility
-+ * for pre-2.1.19.
-+ *
-+ * Revision 1.17 1999/11/19 01:12:15 rgb
-+ * Purge unneeded proc_info prototypes, now that static linking uses
-+ * dynamic proc_info registration.
-+ *
-+ * Revision 1.16 1999/11/18 18:51:00 rgb
-+ * Changed all device registrations for static linking to
-+ * dynamic to reduce the number and size of patches.
-+ *
-+ * Revision 1.15 1999/11/18 04:14:21 rgb
-+ * Replaced all kernel version macros to shorter, readable form.
-+ * Added CONFIG_PROC_FS compiler directives in case it is shut off.
-+ * Added Marc Boucher's 2.3.25 proc patches.
-+ *
-+ * Revision 1.14 1999/05/25 02:50:10 rgb
-+ * Fix kernel version macros for 2.0.x static linking.
-+ *
-+ * Revision 1.13 1999/05/25 02:41:06 rgb
-+ * Add ipsec_klipsdebug support for static linking.
-+ *
-+ * Revision 1.12 1999/05/05 22:02:32 rgb
-+ * Add a quick and dirty port to 2.2 kernels by Marc Boucher <marc@mbsi.ca>.
-+ *
-+ * Revision 1.11 1999/04/29 15:19:50 rgb
-+ * Add return values to init and cleanup functions.
-+ *
-+ * Revision 1.10 1999/04/16 16:02:39 rgb
-+ * Bump up macro to 4 ipsec I/Fs.
-+ *
-+ * Revision 1.9 1999/04/15 15:37:25 rgb
-+ * Forward check changes from POST1_00 branch.
-+ *
-+ * Revision 1.5.2.1 1999/04/02 04:26:14 rgb
-+ * Backcheck from HEAD, pre1.0.
-+ *
-+ * Revision 1.8 1999/04/11 00:29:01 henry
-+ * GPL boilerplate
-+ *
-+ * Revision 1.7 1999/04/06 04:54:28 rgb
-+ * Fix/Add RCSID Id: and Log: bits to make PHMDs happy. This includes
-+ * patch shell fixes.
-+ *
-+ * Revision 1.6 1999/03/31 05:44:48 rgb
-+ * Keep PMTU reduction private.
-+ *
-+ * Revision 1.5 1999/02/10 22:31:20 rgb
-+ * Change rebuild_header member to reflect generality of link layer.
-+ *
-+ * Revision 1.4 1998/12/01 13:22:04 rgb
-+ * Added support for debug printing of version info.
-+ *
-+ * Revision 1.3 1998/07/29 20:42:46 rgb
-+ * Add a macro for clearing all tunnel devices.
-+ * Rearrange structures and declarations for sharing with userspace.
-+ *
-+ * Revision 1.2 1998/06/25 20:01:45 rgb
-+ * Make prototypes available for ipsec_init and ipsec proc_dir_entries
-+ * for static linking.
-+ *
-+ * Revision 1.1 1998/06/18 21:27:50 henry
-+ * move sources from klips/src to klips/net/ipsec, to keep stupid
-+ * kernel-build scripts happier in the presence of symlinks
-+ *
-+ * Revision 1.3 1998/05/18 21:51:50 rgb
-+ * Added macros for num of I/F's and a procfs debug switch.
-+ *
-+ * Revision 1.2 1998/04/21 21:29:09 rgb
-+ * Rearrange debug switches to change on the fly debug output from user
-+ * space. Only kernel changes checked in at this time. radij.c was also
-+ * changed to temporarily remove buggy debugging code in rj_delete causing
-+ * an OOPS and hence, netlink device open errors.
-+ *
-+ * Revision 1.1 1998/04/09 03:06:13 henry
-+ * sources moved up from linux/net/ipsec
-+ *
-+ * Revision 1.1.1.1 1998/04/08 05:35:05 henry
-+ * RGB's ipsec-0.8pre2.tar.gz ipsec-0.8
-+ *
-+ * Revision 0.5 1997/06/03 04:24:48 ji
-+ * Added transport mode.
-+ * Changed the way routing is done.
-+ * Lots of bug fixes.
-+ *
-+ * Revision 0.4 1997/01/15 01:28:15 ji
-+ * No changes.
-+ *
-+ * Revision 0.3 1996/11/20 14:39:04 ji
-+ * Minor cleanups.
-+ * Rationalized debugging code.
-+ *
-+ * Revision 0.2 1996/11/02 00:18:33 ji
-+ * First limited release.
-+ *
-+ *
-+ */
---- /dev/null Tue Mar 11 13:02:56 2003
-+++ linux/include/openswan/ipsec_xform.h Mon Feb 9 13:51:03 2004
-@@ -0,0 +1,254 @@
-+/*
-+ * Definitions relevant to IPSEC transformations
-+ * Copyright (C) 1996, 1997 John Ioannidis.
-+ * Copyright (C) 1998, 1999, 2000, 2001 Richard Guy Briggs.
-+ * COpyright (C) 2003 Michael Richardson <mcr@sandelman.ottawa.on.ca>
-+ *
-+ * 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. See <http://www.fsf.org/copyleft/gpl.txt>.
-+ *
-+ * 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.
-+ *
-+ * RCSID $Id: ipsec_xform.h,v 1.40 2004/04/06 02:49:08 mcr Exp $
-+ */
-+
-+#ifndef _IPSEC_XFORM_H_
-+
-+#include <openswan.h>
-+
-+#define XF_NONE 0 /* No transform set */
-+#define XF_IP4 1 /* IPv4 inside IPv4 */
-+#define XF_AHMD5 2 /* AH MD5 */
-+#define XF_AHSHA 3 /* AH SHA */
-+#define XF_ESP3DES 5 /* ESP DES3-CBC */
-+#define XF_AHHMACMD5 6 /* AH-HMAC-MD5 with opt replay prot */
-+#define XF_AHHMACSHA1 7 /* AH-HMAC-SHA1 with opt replay prot */
-+#define XF_ESP3DESMD5 9 /* triple DES, HMAC-MD-5, 128-bits of authentication */
-+#define XF_ESP3DESMD596 10 /* triple DES, HMAC-MD-5, 96-bits of authentication */
-+#define XF_ESPNULLMD596 12 /* NULL, HMAC-MD-5 with 96-bits of authentication */
-+#define XF_ESPNULLSHA196 13 /* NULL, HMAC-SHA-1 with 96-bits of authentication */
-+#define XF_ESP3DESSHA196 14 /* triple DES, HMAC-SHA-1, 96-bits of authentication */
-+#define XF_IP6 15 /* IPv6 inside IPv6 */
-+#define XF_COMPDEFLATE 16 /* IPCOMP deflate */
-+
-+#define XF_CLR 126 /* Clear SA table */
-+#define XF_DEL 127 /* Delete SA */
-+
-+/* IPsec AH transform values
-+ * RFC 2407
-+ * draft-ietf-ipsec-doi-tc-mib-02.txt
-+ */
-+
-+#define AH_NONE 0
-+#define AH_MD5 2
-+#define AH_SHA 3
-+/* draft-ietf-ipsec-ciph-aes-cbc-03.txt */
-+#define AH_SHA2_256 5
-+#define AH_SHA2_384 6
-+#define AH_SHA2_512 7
-+#define AH_RIPEMD 8
-+#define AH_MAX 15
-+
-+/* IPsec ESP transform values */
-+
-+#define ESP_NONE 0
-+#define ESP_DES 2
-+#define ESP_3DES 3
-+#define ESP_RC5 4
-+#define ESP_IDEA 5
-+#define ESP_CAST 6
-+#define ESP_BLOWFISH 7
-+#define ESP_3IDEA 8
-+#define ESP_RC4 10
-+#define ESP_NULL 11
-+#define ESP_AES 12
-+
-+/* as draft-ietf-ipsec-ciph-aes-cbc-02.txt */
-+#define ESP_MARS 249
-+#define ESP_RC6 250
-+#define ESP_SERPENT 252
-+#define ESP_TWOFISH 253
-+
-+/* IPCOMP transform values */
-+
-+#define IPCOMP_NONE 0
-+#define IPCOMP_OUI 1
-+#define IPCOMP_DEFLAT 2
-+#define IPCOMP_LZS 3
-+#define IPCOMP_V42BIS 4
-+
-+#define XFT_AUTH 0x0001
-+#define XFT_CONF 0x0100
-+
-+/* available if CONFIG_IPSEC_DEBUG is defined */
-+#define DB_XF_INIT 0x0001
-+
-+#define PROTO2TXT(x) \
-+ (x) == IPPROTO_AH ? "AH" : \
-+ (x) == IPPROTO_ESP ? "ESP" : \
-+ (x) == IPPROTO_IPIP ? "IPIP" : \
-+ (x) == IPPROTO_COMP ? "COMP" : \
-+ "UNKNOWN_proto"
-+static inline const char *enc_name_id (unsigned id) {
-+ static char buf[16];
-+ snprintf(buf, sizeof(buf), "_ID%d", id);
-+ return buf;
-+}
-+static inline const char *auth_name_id (unsigned id) {
-+ static char buf[16];
-+ snprintf(buf, sizeof(buf), "_ID%d", id);
-+ return buf;
-+}
-+#define IPS_XFORM_NAME(x) \
-+ PROTO2TXT((x)->ips_said.proto), \
-+ (x)->ips_said.proto == IPPROTO_COMP ? \
-+ ((x)->ips_encalg == SADB_X_CALG_DEFLATE ? \
-+ "_DEFLATE" : "_UNKNOWN_comp") : \
-+ (x)->ips_encalg == ESP_NONE ? "" : \
-+ (x)->ips_encalg == ESP_3DES ? "_3DES" : \
-+ (x)->ips_encalg == ESP_AES ? "_AES" : \
-+ (x)->ips_encalg == ESP_SERPENT ? "_SERPENT" : \
-+ (x)->ips_encalg == ESP_TWOFISH ? "_TWOFISH" : \
-+ enc_name_id(x->ips_encalg)/* "_UNKNOWN_encr" */, \
-+ (x)->ips_authalg == AH_NONE ? "" : \
-+ (x)->ips_authalg == AH_MD5 ? "_HMAC_MD5" : \
-+ (x)->ips_authalg == AH_SHA ? "_HMAC_SHA1" : \
-+ (x)->ips_authalg == AH_SHA2_256 ? "_HMAC_SHA2_256" : \
-+ (x)->ips_authalg == AH_SHA2_384 ? "_HMAC_SHA2_384" : \
-+ (x)->ips_authalg == AH_SHA2_512 ? "_HMAC_SHA2_512" : \
-+ auth_name_id(x->ips_authalg) /* "_UNKNOWN_auth" */ \
-+
-+#ifdef __KERNEL__
-+struct ipsec_rcv_state;
-+struct ipsec_xmit_state;
-+
-+struct xform_functions {
-+ enum ipsec_rcv_value (*rcv_checks)(struct ipsec_rcv_state *irs,
-+ struct sk_buff *skb);
-+ enum ipsec_rcv_value (*rcv_decrypt)(struct ipsec_rcv_state *irs);
-+
-+ enum ipsec_rcv_value (*rcv_setup_auth)(struct ipsec_rcv_state *irs,
-+ struct sk_buff *skb,
-+ __u32 *replay,
-+ unsigned char **authenticator);
-+ enum ipsec_rcv_value (*rcv_calc_auth)(struct ipsec_rcv_state *irs,
-+ struct sk_buff *skb);
-+
-+ enum ipsec_xmit_value (*xmit_setup)(struct ipsec_xmit_state *ixs);
-+ enum ipsec_xmit_value (*xmit_encrypt)(struct ipsec_xmit_state *ixs);
-+
-+ enum ipsec_xmit_value (*xmit_setup_auth)(struct ipsec_xmit_state *ixs,
-+ struct sk_buff *skb,
-+ __u32 *replay,
-+ unsigned char **authenticator);
-+ enum ipsec_xmit_value (*xmit_calc_auth)(struct ipsec_xmit_state *ixs,
-+ struct sk_buff *skb);
-+ int xmit_headroom;
-+ int xmit_needtailroom;
-+};
-+
-+#endif /* __KERNEL__ */
-+
-+#ifdef CONFIG_IPSEC_DEBUG
-+extern void ipsec_dmp(char *s, caddr_t bb, int len);
-+#else /* CONFIG_IPSEC_DEBUG */
-+#define ipsec_dmp(_x, _y, _z)
-+#endif /* CONFIG_IPSEC_DEBUG */
-+
-+
-+#define _IPSEC_XFORM_H_
-+#endif /* _IPSEC_XFORM_H_ */
-+
-+/*
-+ * $Log: ipsec_xform.h,v $
-+ * Revision 1.40 2004/04/06 02:49:08 mcr
-+ * pullup of algo code from alg-branch.
-+ *
-+ * Revision 1.39 2004/04/05 19:55:07 mcr
-+ * Moved from linux/include/freeswan/ipsec_xform.h,v
-+ *
-+ * Revision 1.38 2004/04/05 19:41:05 mcr
-+ * merged alg-branch code.
-+ *
-+ * Revision 1.37 2003/12/13 19:10:16 mcr
-+ * refactored rcv and xmit code - same as FS 2.05.
-+ *
-+ * Revision 1.36.34.1 2003/12/22 15:25:52 jjo
-+ * Merged algo-0.8.1-rc11-test1 into alg-branch
-+ *
-+ * Revision 1.36 2002/04/24 07:36:48 mcr
-+ * Moved from ./klips/net/ipsec/ipsec_xform.h,v
-+ *
-+ * Revision 1.35 2001/11/26 09:23:51 rgb
-+ * Merge MCR's ipsec_sa, eroute, proc and struct lifetime changes.
-+ *
-+ * Revision 1.33.2.1 2001/09/25 02:24:58 mcr
-+ * struct tdb -> struct ipsec_sa.
-+ * sa(tdb) manipulation functions renamed and moved to ipsec_sa.c
-+ * ipsec_xform.c removed. header file still contains useful things.
-+ *
-+ * Revision 1.34 2001/11/06 19:47:17 rgb
-+ * Changed lifetime_packets to uint32 from uint64.
-+ *
-+ * Revision 1.33 2001/09/08 21:13:34 rgb
-+ * Added pfkey ident extension support for ISAKMPd. (NetCelo)
-+ *
-+ * Revision 1.32 2001/07/06 07:40:01 rgb
-+ * Reformatted for readability.
-+ * Added inbound policy checking fields for use with IPIP SAs.
-+ *
-+ * Revision 1.31 2001/06/14 19:35:11 rgb
-+ * Update copyright date.
-+ *
-+ * Revision 1.30 2001/05/30 08:14:03 rgb
-+ * Removed vestiges of esp-null transforms.
-+ *
-+ * Revision 1.29 2001/01/30 23:42:47 rgb
-+ * Allow pfkey msgs from pid other than user context required for ACQUIRE
-+ * and subsequent ADD or UDATE.
-+ *
-+ * Revision 1.28 2000/11/06 04:30:40 rgb
-+ * Add Svenning's adaptive content compression.
-+ *
-+ * Revision 1.27 2000/09/19 00:38:25 rgb
-+ * Fixed algorithm name bugs introduced for ipcomp.
-+ *
-+ * Revision 1.26 2000/09/17 21:36:48 rgb
-+ * Added proto2txt macro.
-+ *
-+ * Revision 1.25 2000/09/17 18:56:47 rgb
-+ * Added IPCOMP support.
-+ *
-+ * Revision 1.24 2000/09/12 19:34:12 rgb
-+ * Defined XF_IP6 from Gerhard for ipv6 tunnel support.
-+ *
-+ * Revision 1.23 2000/09/12 03:23:14 rgb
-+ * Cleaned out now unused tdb_xform and tdb_xdata members of struct tdb.
-+ *
-+ * Revision 1.22 2000/09/08 19:12:56 rgb
-+ * Change references from DEBUG_IPSEC to CONFIG_IPSEC_DEBUG.
-+ *
-+ * Revision 1.21 2000/09/01 18:32:43 rgb
-+ * Added (disabled) sensitivity members to tdb struct.
-+ *
-+ * Revision 1.20 2000/08/30 05:31:01 rgb
-+ * Removed all the rest of the references to tdb_spi, tdb_proto, tdb_dst.
-+ * Kill remainder of tdb_xform, tdb_xdata, xformsw.
-+ *
-+ * Revision 1.19 2000/08/01 14:51:52 rgb
-+ * Removed _all_ remaining traces of DES.
-+ *
-+ * Revision 1.18 2000/01/21 06:17:45 rgb
-+ * Tidied up spacing.
-+ *
-+ *
-+ * Local variables:
-+ * c-file-style: "linux"
-+ * End:
-+ *
-+ */
---- /dev/null Tue Mar 11 13:02:56 2003
-+++ linux/include/openswan/ipsec_xmit.h Mon Feb 9 13:51:03 2004
-@@ -0,0 +1,176 @@
-+/*
-+ * IPSEC tunneling code
-+ * Copyright (C) 1996, 1997 John Ioannidis.
-+ * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 Richard Guy Briggs.
-+ *
-+ * 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. See <http://www.fsf.org/copyleft/gpl.txt>.
-+ *
-+ * 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.
-+ *
-+ * RCSID $Id: ipsec_xmit.h,v 1.9 2004/04/06 02:49:08 mcr Exp $
-+ */
-+
-+#include "openswan/ipsec_sa.h"
-+
-+enum ipsec_xmit_value
-+{
-+ IPSEC_XMIT_STOLEN=2,
-+ IPSEC_XMIT_PASS=1,
-+ IPSEC_XMIT_OK=0,
-+ IPSEC_XMIT_ERRMEMALLOC=-1,
-+ IPSEC_XMIT_ESP_BADALG=-2,
-+ IPSEC_XMIT_BADPROTO=-3,
-+ IPSEC_XMIT_ESP_PUSHPULLERR=-4,
-+ IPSEC_XMIT_BADLEN=-5,
-+ IPSEC_XMIT_AH_BADALG=-6,
-+ IPSEC_XMIT_SAIDNOTFOUND=-7,
-+ IPSEC_XMIT_SAIDNOTLIVE=-8,
-+ IPSEC_XMIT_REPLAYROLLED=-9,
-+ IPSEC_XMIT_LIFETIMEFAILED=-10,
-+ IPSEC_XMIT_CANNOTFRAG=-11,
-+ IPSEC_XMIT_MSSERR=-12,
-+ IPSEC_XMIT_ERRSKBALLOC=-13,
-+ IPSEC_XMIT_ENCAPFAIL=-14,
-+ IPSEC_XMIT_NODEV=-15,
-+ IPSEC_XMIT_NOPRIVDEV=-16,
-+ IPSEC_XMIT_NOPHYSDEV=-17,
-+ IPSEC_XMIT_NOSKB=-18,
-+ IPSEC_XMIT_NOIPV6=-19,
-+ IPSEC_XMIT_NOIPOPTIONS=-20,
-+ IPSEC_XMIT_TTLEXPIRED=-21,
-+ IPSEC_XMIT_BADHHLEN=-22,
-+ IPSEC_XMIT_PUSHPULLERR=-23,
-+ IPSEC_XMIT_ROUTEERR=-24,
-+ IPSEC_XMIT_RECURSDETECT=-25,
-+ IPSEC_XMIT_IPSENDFAILURE=-26,
-+ IPSEC_XMIT_ESPUDP=-27,
-+ IPSEC_XMIT_ESPUDP_BADTYPE=-28,
-+};
-+
-+struct ipsec_xmit_state
-+{
-+ struct sk_buff *skb; /* working skb pointer */
-+ struct device *dev; /* working dev pointer */
-+ struct ipsecpriv *prv; /* Our device' private space */
-+ struct sk_buff *oskb; /* Original skb pointer */
-+ struct net_device_stats *stats; /* This device's statistics */
-+ struct iphdr *iph; /* Our new IP header */
-+ __u32 newdst; /* The other SG's IP address */
-+ __u32 orgdst; /* Original IP destination address */
-+ __u32 orgedst; /* 1st SG's IP address */
-+ __u32 newsrc; /* The new source SG's IP address */
-+ __u32 orgsrc; /* Original IP source address */
-+ __u32 innersrc; /* Innermost IP source address */
-+ int iphlen; /* IP header length */
-+ int pyldsz; /* upper protocol payload size */
-+ int headroom;
-+ int tailroom;
-+ int authlen;
-+ int max_headroom; /* The extra header space needed */
-+ int max_tailroom; /* The extra stuffing needed */
-+ int ll_headroom; /* The extra link layer hard_header space needed */
-+ int tot_headroom; /* The total header space needed */
-+ int tot_tailroom; /* The totalstuffing needed */
-+ __u8 *saved_header; /* saved copy of the hard header */
-+ unsigned short sport, dport;
-+
-+ struct sockaddr_encap matcher; /* eroute search key */
-+ struct eroute *eroute;
-+ struct ipsec_sa *ipsp, *ipsq; /* ipsec_sa pointers */
-+ char sa_txt[SATOT_BUF];
-+ size_t sa_len;
-+ int hard_header_stripped; /* has the hard header been removed yet? */
-+ int hard_header_len;
-+ struct device *physdev;
-+/* struct device *virtdev; */
-+ short physmtu;
-+ short mtudiff;
-+#ifdef NET_21
-+ struct rtable *route;
-+#endif /* NET_21 */
-+ ip_said outgoing_said;
-+#ifdef NET_21
-+ int pass;
-+#endif /* NET_21 */
-+ int error;
-+ uint32_t eroute_pid;
-+ struct ipsec_sa ips;
-+#ifdef CONFIG_IPSEC_NAT_TRAVERSAL
-+ uint8_t natt_type;
-+ uint8_t natt_head;
-+ uint16_t natt_sport;
-+ uint16_t natt_dport;
-+#endif
-+};
-+
-+enum ipsec_xmit_value
-+ipsec_xmit_sanity_check_dev(struct ipsec_xmit_state *ixs);
-+
-+enum ipsec_xmit_value
-+ipsec_xmit_sanity_check_skb(struct ipsec_xmit_state *ixs);
-+
-+enum ipsec_xmit_value
-+ipsec_xmit_encap_bundle(struct ipsec_xmit_state *ixs);
-+
-+extern void ipsec_extract_ports(struct iphdr * iph, struct sockaddr_encap * er);
-+
-+
-+extern int ipsec_xmit_trap_count;
-+extern int ipsec_xmit_trap_sendcount;
-+
-+#ifdef CONFIG_IPSEC_DEBUG
-+extern int debug_tunnel;
-+extern int sysctl_ipsec_debug_verbose;
-+#endif /* CONFIG_IPSEC_DEBUG */
-+
-+#define debug_xmit debug_tunnel
-+
-+#define ipsec_xmit_dmp(_x,_y, _z) if (debug_xmit && sysctl_ipsec_debug_verbose) ipsec_dmp(_x,_y,_z)
-+
-+extern int sysctl_ipsec_icmp;
-+extern int sysctl_ipsec_tos;
-+
-+
-+/*
-+ * $Log: ipsec_xmit.h,v $
-+ * Revision 1.9 2004/04/06 02:49:08 mcr
-+ * pullup of algo code from alg-branch.
-+ *
-+ * Revision 1.8 2004/04/05 19:55:07 mcr
-+ * Moved from linux/include/freeswan/ipsec_xmit.h,v
-+ *
-+ * Revision 1.7 2004/02/03 03:11:40 mcr
-+ * new xmit type if the UDP encapsulation is wrong.
-+ *
-+ * Revision 1.6 2003/12/13 19:10:16 mcr
-+ * refactored rcv and xmit code - same as FS 2.05.
-+ *
-+ * Revision 1.5 2003/12/10 01:20:06 mcr
-+ * NAT-traversal patches to KLIPS.
-+ *
-+ * Revision 1.4 2003/12/06 16:37:04 mcr
-+ * 1.4.7a X.509 patch applied.
-+ *
-+ * Revision 1.3 2003/10/31 02:27:05 mcr
-+ * pulled up port-selector patches and sa_id elimination.
-+ *
-+ * Revision 1.2.4.2 2003/10/29 01:10:19 mcr
-+ * elimited "struct sa_id"
-+ *
-+ * Revision 1.2.4.1 2003/09/21 13:59:38 mcr
-+ * pre-liminary X.509 patch - does not yet pass tests.
-+ *
-+ * Revision 1.2 2003/06/20 01:42:13 mcr
-+ * added counters to measure how many ACQUIREs we send to pluto,
-+ * and how many are successfully sent.
-+ *
-+ * Revision 1.1 2003/02/12 19:31:03 rgb
-+ * Refactored from ipsec_tunnel.c
-+ *
-+ */
---- /dev/null Tue Mar 11 13:02:56 2003
-+++ linux/include/openswan/passert.h Mon Feb 9 13:51:03 2004
-@@ -0,0 +1,64 @@
-+/*
-+ * sanitize a string into a printable format.
-+ *
-+ * Copyright (C) 1998-2002 D. Hugh Redelmeier.
-+ * Copyright (C) 2003 Michael Richardson <mcr@freeswan.org>
-+ *
-+ * This library is free software; you can redistribute it and/or modify it
-+ * under the terms of the GNU Library General Public License as published by
-+ * the Free Software Foundation; either version 2 of the License, or (at your
-+ * option) any later version. See <http://www.fsf.org/copyleft/lgpl.txt>.
-+ *
-+ * This library 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 Library General Public
-+ * License for more details.
-+ *
-+ * RCSID $Id: passert.h,v 1.4 2004/04/06 02:49:08 mcr Exp $
-+ */
-+
-+#include "openswan.h"
-+
-+/* our versions of assert: log result */
-+
-+#ifdef DEBUG
-+
-+extern void passert_fail(const char *pred_str
-+ , const char *file_str, unsigned long line_no) NEVER_RETURNS;
-+
-+extern void pexpect_log(const char *pred_str
-+ , const char *file_str, unsigned long line_no);
-+
-+# define impossible() passert_fail("impossible", __FILE__, __LINE__)
-+
-+extern void switch_fail(int n
-+ , const char *file_str, unsigned long line_no) NEVER_RETURNS;
-+
-+# define bad_case(n) switch_fail((int) n, __FILE__, __LINE__)
-+
-+# define passert(pred) { \
-+ if (!(pred)) \
-+ passert_fail(#pred, __FILE__, __LINE__); \
-+ }
-+
-+# define pexpect(pred) { \
-+ if (!(pred)) \
-+ pexpect_log(#pred, __FILE__, __LINE__); \
-+ }
-+
-+/* assert that an err_t is NULL; evaluate exactly once */
-+# define happy(x) { \
-+ err_t ugh = x; \
-+ if (ugh != NULL) \
-+ passert_fail(ugh, __FILE__, __LINE__); \
-+ }
-+
-+#else /*!DEBUG*/
-+
-+# define impossible() abort()
-+# define bad_case(n) abort()
-+# define passert(pred) { } /* do nothing */
-+# define happy(x) { (void) x; } /* evaluate non-judgementally */
-+
-+#endif /*!DEBUG*/
-+
---- /dev/null Tue Mar 11 13:02:56 2003
-+++ linux/include/openswan/pfkey_debug.h Mon Feb 9 13:51:03 2004
-@@ -0,0 +1,54 @@
-+/*
-+ * sanitize a string into a printable format.
-+ *
-+ * Copyright (C) 1998-2002 D. Hugh Redelmeier.
-+ * Copyright (C) 2003 Michael Richardson <mcr@freeswan.org>
-+ *
-+ * This library is free software; you can redistribute it and/or modify it
-+ * under the terms of the GNU Library General Public License as published by
-+ * the Free Software Foundation; either version 2 of the License, or (at your
-+ * option) any later version. See <http://www.fsf.org/copyleft/lgpl.txt>.
-+ *
-+ * This library 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 Library General Public
-+ * License for more details.
-+ *
-+ * RCSID $Id: pfkey_debug.h,v 1.3 2004/04/05 19:55:07 mcr Exp $
-+ */
-+
-+#ifndef _FREESWAN_PFKEY_DEBUG_H
-+#define _FREESWAN_PFKEY_DEBUG_H
-+
-+#ifdef __KERNEL__
-+
-+/* note, kernel version ignores pfkey levels */
-+# define DEBUGGING(level,args...) \
-+ KLIPS_PRINT(debug_pfkey, "klips_debug:" args)
-+
-+# define ERROR(args...) printk(KERN_ERR "klips:" args)
-+
-+#else
-+
-+extern unsigned int pfkey_lib_debug;
-+
-+extern void (*pfkey_debug_func)(const char *message, ...) PRINTF_LIKE(1);
-+extern void (*pfkey_error_func)(const char *message, ...) PRINTF_LIKE(1);
-+
-+#define DEBUGGING(level,args...) if(pfkey_lib_debug & level) { \
-+ if(pfkey_debug_func != NULL) { \
-+ (*pfkey_debug_func)("pfkey_lib_debug:" args); \
-+ } else { \
-+ printf("pfkey_lib_debug:" args); \
-+ } }
-+
-+#define ERROR(args...) if(pfkey_error_func != NULL) { \
-+ (*pfkey_error_func)("pfkey_lib_debug:" args); \
-+ }
-+
-+# define MALLOC(size) malloc(size)
-+# define FREE(obj) free(obj)
-+
-+#endif
-+
-+#endif
---- /dev/null Tue Mar 11 13:02:56 2003
-+++ linux/include/openswan/radij.h Mon Feb 9 13:51:03 2004
-@@ -0,0 +1,280 @@
-+/*
-+ * RCSID $Id: radij.h,v 1.13 2004/04/05 19:55:08 mcr Exp $
-+ */
-+
-+/*
-+ * This file is defived from ${SRC}/sys/net/radix.h of BSD 4.4lite
-+ *
-+ * Variable and procedure names have been modified so that they don't
-+ * conflict with the original BSD code, as a small number of modifications
-+ * have been introduced and we may want to reuse this code in BSD.
-+ *
-+ * The `j' in `radij' is pronounced as a voiceless guttural (like a Greek
-+ * chi or a German ch sound (as `doch', not as in `milch'), or even a
-+ * spanish j as in Juan. It is not as far back in the throat like
-+ * the corresponding Hebrew sound, nor is it a soft breath like the English h.
-+ * It has nothing to do with the Dutch ij sound.
-+ *
-+ * Here is the appropriate copyright notice:
-+ */
-+
-+/*
-+ * Copyright (c) 1988, 1989, 1993
-+ * The Regents of the University of California. All rights reserved.
-+ *
-+ * Redistribution and use in source and binary forms, with or without
-+ * modification, are permitted provided that the following conditions
-+ * are met:
-+ * 1. Redistributions of source code must retain the above copyright
-+ * notice, this list of conditions and the following disclaimer.
-+ * 2. Redistributions in binary form must reproduce the above copyright
-+ * notice, this list of conditions and the following disclaimer in the
-+ * documentation and/or other materials provided with the distribution.
-+ * 3. All advertising materials mentioning features or use of this software
-+ * must display the following acknowledgement:
-+ * This product includes software developed by the University of
-+ * California, Berkeley and its contributors.
-+ * 4. Neither the name of the University nor the names of its contributors
-+ * may be used to endorse or promote products derived from this software
-+ * without specific prior written permission.
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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.
-+ *
-+ * @(#)radix.h 8.1 (Berkeley) 6/10/93
-+ */
-+
-+#ifndef _RADIJ_H_
-+#define _RADIJ_H_
-+
-+/*
-+#define RJ_DEBUG
-+*/
-+
-+#ifdef __KERNEL__
-+
-+#ifndef __P
-+#ifdef __STDC__
-+#define __P(x) x
-+#else
-+#define __P(x) ()
-+#endif
-+#endif
-+
-+/*
-+ * Radix search tree node layout.
-+ */
-+
-+struct radij_node
-+{
-+ struct radij_mask *rj_mklist; /* list of masks contained in subtree */
-+ struct radij_node *rj_p; /* parent */
-+ short rj_b; /* bit offset; -1-index(netmask) */
-+ char rj_bmask; /* node: mask for bit test*/
-+ u_char rj_flags; /* enumerated next */
-+#define RJF_NORMAL 1 /* leaf contains normal route */
-+#define RJF_ROOT 2 /* leaf is root leaf for tree */
-+#define RJF_ACTIVE 4 /* This node is alive (for rtfree) */
-+ union {
-+ struct { /* leaf only data: */
-+ caddr_t rj_Key; /* object of search */
-+ caddr_t rj_Mask; /* netmask, if present */
-+ struct radij_node *rj_Dupedkey;
-+ } rj_leaf;
-+ struct { /* node only data: */
-+ int rj_Off; /* where to start compare */
-+ struct radij_node *rj_L;/* progeny */
-+ struct radij_node *rj_R;/* progeny */
-+ }rj_node;
-+ } rj_u;
-+#ifdef RJ_DEBUG
-+ int rj_info;
-+ struct radij_node *rj_twin;
-+ struct radij_node *rj_ybro;
-+#endif
-+};
-+
-+#define rj_dupedkey rj_u.rj_leaf.rj_Dupedkey
-+#define rj_key rj_u.rj_leaf.rj_Key
-+#define rj_mask rj_u.rj_leaf.rj_Mask
-+#define rj_off rj_u.rj_node.rj_Off
-+#define rj_l rj_u.rj_node.rj_L
-+#define rj_r rj_u.rj_node.rj_R
-+
-+/*
-+ * Annotations to tree concerning potential routes applying to subtrees.
-+ */
-+
-+extern struct radij_mask {
-+ short rm_b; /* bit offset; -1-index(netmask) */
-+ char rm_unused; /* cf. rj_bmask */
-+ u_char rm_flags; /* cf. rj_flags */
-+ struct radij_mask *rm_mklist; /* more masks to try */
-+ caddr_t rm_mask; /* the mask */
-+ int rm_refs; /* # of references to this struct */
-+} *rj_mkfreelist;
-+
-+#define MKGet(m) {\
-+ if (rj_mkfreelist) {\
-+ m = rj_mkfreelist; \
-+ rj_mkfreelist = (m)->rm_mklist; \
-+ } else \
-+ R_Malloc(m, struct radij_mask *, sizeof (*(m))); }\
-+
-+#define MKFree(m) { (m)->rm_mklist = rj_mkfreelist; rj_mkfreelist = (m);}
-+
-+struct radij_node_head {
-+ struct radij_node *rnh_treetop;
-+ int rnh_addrsize; /* permit, but not require fixed keys */
-+ int rnh_pktsize; /* permit, but not require fixed keys */
-+#if 0
-+ struct radij_node *(*rnh_addaddr) /* add based on sockaddr */
-+ __P((void *v, void *mask,
-+ struct radij_node_head *head, struct radij_node nodes[]));
-+#endif
-+ int (*rnh_addaddr) /* add based on sockaddr */
-+ __P((void *v, void *mask,
-+ struct radij_node_head *head, struct radij_node nodes[]));
-+ struct radij_node *(*rnh_addpkt) /* add based on packet hdr */
-+ __P((void *v, void *mask,
-+ struct radij_node_head *head, struct radij_node nodes[]));
-+#if 0
-+ struct radij_node *(*rnh_deladdr) /* remove based on sockaddr */
-+ __P((void *v, void *mask, struct radij_node_head *head));
-+#endif
-+ int (*rnh_deladdr) /* remove based on sockaddr */
-+ __P((void *v, void *mask, struct radij_node_head *head, struct radij_node **node));
-+ struct radij_node *(*rnh_delpkt) /* remove based on packet hdr */
-+ __P((void *v, void *mask, struct radij_node_head *head));
-+ struct radij_node *(*rnh_matchaddr) /* locate based on sockaddr */
-+ __P((void *v, struct radij_node_head *head));
-+ struct radij_node *(*rnh_matchpkt) /* locate based on packet hdr */
-+ __P((void *v, struct radij_node_head *head));
-+ int (*rnh_walktree) /* traverse tree */
-+ __P((struct radij_node_head *head, int (*f)(struct radij_node *rn, void *w), void *w));
-+ struct radij_node rnh_nodes[3]; /* empty tree for common case */
-+};
-+
-+
-+#define Bcmp(a, b, n) memcmp(((caddr_t)(b)), ((caddr_t)(a)), (unsigned)(n))
-+#define Bcopy(a, b, n) memmove(((caddr_t)(b)), ((caddr_t)(a)), (unsigned)(n))
-+#define Bzero(p, n) memset((caddr_t)(p), 0, (unsigned)(n))
-+#define R_Malloc(p, t, n) ((p = (t) kmalloc((size_t)(n), GFP_ATOMIC)), Bzero((p),(n)))
-+#define Free(p) kfree((caddr_t)p);
-+
-+void rj_init __P((void));
-+int rj_inithead __P((void **, int));
-+int rj_refines __P((void *, void *));
-+int rj_walktree __P((struct radij_node_head *head, int (*f)(struct radij_node *rn, void *w), void *w));
-+struct radij_node
-+ *rj_addmask __P((void *, int, int)) /* , rgb */ ;
-+int /* * */ rj_addroute __P((void *, void *, struct radij_node_head *,
-+ struct radij_node [2])) /* , rgb */ ;
-+int /* * */ rj_delete __P((void *, void *, struct radij_node_head *, struct radij_node **)) /* , rgb */ ;
-+struct radij_node /* rgb */
-+ *rj_insert __P((void *, struct radij_node_head *, int *,
-+ struct radij_node [2])),
-+ *rj_match __P((void *, struct radij_node_head *)),
-+ *rj_newpair __P((void *, int, struct radij_node[2])),
-+ *rj_search __P((void *, struct radij_node *)),
-+ *rj_search_m __P((void *, struct radij_node *, void *));
-+
-+void rj_deltree(struct radij_node_head *);
-+void rj_delnodes(struct radij_node *);
-+void rj_free_mkfreelist(void);
-+int radijcleartree(void);
-+int radijcleanup(void);
-+
-+extern struct radij_node_head *mask_rjhead;
-+extern int maj_keylen;
-+#endif /* __KERNEL__ */
-+
-+#endif /* _RADIJ_H_ */
-+
-+
-+/*
-+ * $Log: radij.h,v $
-+ * Revision 1.13 2004/04/05 19:55:08 mcr
-+ * Moved from linux/include/freeswan/radij.h,v
-+ *
-+ * Revision 1.12 2002/04/24 07:36:48 mcr
-+ * Moved from ./klips/net/ipsec/radij.h,v
-+ *
-+ * Revision 1.11 2001/09/20 15:33:00 rgb
-+ * Min/max cleanup.
-+ *
-+ * Revision 1.10 1999/11/18 04:09:20 rgb
-+ * Replaced all kernel version macros to shorter, readable form.
-+ *
-+ * Revision 1.9 1999/05/05 22:02:33 rgb
-+ * Add a quick and dirty port to 2.2 kernels by Marc Boucher <marc@mbsi.ca>.
-+ *
-+ * Revision 1.8 1999/04/29 15:24:58 rgb
-+ * Add check for existence of macros min/max.
-+ *
-+ * Revision 1.7 1999/04/11 00:29:02 henry
-+ * GPL boilerplate
-+ *
-+ * Revision 1.6 1999/04/06 04:54:29 rgb
-+ * Fix/Add RCSID Id: and Log: bits to make PHMDs happy. This includes
-+ * patch shell fixes.
-+ *
-+ * Revision 1.5 1999/01/22 06:30:32 rgb
-+ * 64-bit clean-up.
-+ *
-+ * Revision 1.4 1998/11/30 13:22:55 rgb
-+ * Rationalised all the klips kernel file headers. They are much shorter
-+ * now and won't conflict under RH5.2.
-+ *
-+ * Revision 1.3 1998/10/25 02:43:27 rgb
-+ * Change return type on rj_addroute and rj_delete and add and argument
-+ * to the latter to be able to transmit more infomation about errors.
-+ *
-+ * Revision 1.2 1998/07/14 18:09:51 rgb
-+ * Add a routine to clear eroute table.
-+ * Added #ifdef __KERNEL__ directives to restrict scope of header.
-+ *
-+ * Revision 1.1 1998/06/18 21:30:22 henry
-+ * move sources from klips/src to klips/net/ipsec to keep stupid kernel
-+ * build scripts happier about symlinks
-+ *
-+ * Revision 1.4 1998/05/25 20:34:16 rgb
-+ * Remove temporary ipsec_walk, rj_deltree and rj_delnodes functions.
-+ *
-+ * Rename ipsec_rj_walker (ipsec_walk) to ipsec_rj_walker_procprint and
-+ * add ipsec_rj_walker_delete.
-+ *
-+ * Recover memory for eroute table on unload of module.
-+ *
-+ * Revision 1.3 1998/04/22 16:51:37 rgb
-+ * Tidy up radij debug code from recent rash of modifications to debug code.
-+ *
-+ * Revision 1.2 1998/04/14 17:30:38 rgb
-+ * Fix up compiling errors for radij tree memory reclamation.
-+ *
-+ * Revision 1.1 1998/04/09 03:06:16 henry
-+ * sources moved up from linux/net/ipsec
-+ *
-+ * Revision 1.1.1.1 1998/04/08 05:35:04 henry
-+ * RGB's ipsec-0.8pre2.tar.gz ipsec-0.8
-+ *
-+ * Revision 0.4 1997/01/15 01:28:15 ji
-+ * No changes.
-+ *
-+ * Revision 0.3 1996/11/20 14:44:45 ji
-+ * Release update only.
-+ *
-+ * Revision 0.2 1996/11/02 00:18:33 ji
-+ * First limited release.
-+ *
-+ *
-+ */
---- /dev/null Tue Mar 11 13:02:56 2003
-+++ linux/include/pfkey.h Mon Feb 9 13:51:03 2004
-@@ -0,0 +1,509 @@
-+/*
-+ * FreeS/WAN specific PF_KEY headers
-+ * Copyright (C) 1999, 2000, 2001 Richard Guy Briggs.
-+ *
-+ * 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. See <http://www.fsf.org/copyleft/gpl.txt>.
-+ *
-+ * 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.
-+ *
-+ * RCSID $Id: pfkey.h,v 1.45 2004/04/06 02:49:00 mcr Exp $
-+ */
-+
-+#ifndef __NET_IPSEC_PF_KEY_H
-+#define __NET_IPSEC_PF_KEY_H
-+#ifdef __KERNEL__
-+extern struct proto_ops pfkey_proto_ops;
-+typedef struct sock pfkey_sock;
-+extern int debug_pfkey;
-+
-+extern /* void */ int pfkey_init(void);
-+extern /* void */ int pfkey_cleanup(void);
-+
-+extern struct sock *pfkey_sock_list;
-+struct socket_list
-+{
-+ struct socket *socketp;
-+ struct socket_list *next;
-+};
-+extern int pfkey_list_insert_socket(struct socket*, struct socket_list**);
-+extern int pfkey_list_remove_socket(struct socket*, struct socket_list**);
-+extern struct socket_list *pfkey_open_sockets;
-+extern struct socket_list *pfkey_registered_sockets[SADB_SATYPE_MAX+1];
-+
-+struct supported
-+{
-+ uint16_t supported_alg_exttype;
-+ uint8_t supported_alg_id;
-+ uint8_t supported_alg_ivlen;
-+ uint16_t supported_alg_minbits;
-+ uint16_t supported_alg_maxbits;
-+};
-+
-+extern struct supported_list *pfkey_supported_list[SADB_SATYPE_MAX+1];
-+struct supported_list
-+{
-+ struct supported *supportedp;
-+ struct supported_list *next;
-+};
-+extern int pfkey_list_insert_supported(struct supported*, struct supported_list**);
-+extern int pfkey_list_remove_supported(struct supported*, struct supported_list**);
-+
-+struct sockaddr_key
-+{
-+ uint16_t key_family; /* PF_KEY */
-+ uint16_t key_pad; /* not used */
-+ uint32_t key_pid; /* process ID */
-+};
-+
-+struct pfkey_extracted_data
-+{
-+ struct ipsec_sa* ips;
-+ struct ipsec_sa* ips2;
-+ struct eroute *eroute;
-+};
-+
-+extern int
-+pfkey_alloc_eroute(struct eroute** eroute);
-+
-+extern int
-+pfkey_sa_process(struct sadb_ext *pfkey_ext,
-+ struct pfkey_extracted_data* extr);
-+
-+extern int
-+pfkey_lifetime_process(struct sadb_ext *pfkey_ext,
-+ struct pfkey_extracted_data* extr);
-+
-+extern int
-+pfkey_address_process(struct sadb_ext *pfkey_ext,
-+ struct pfkey_extracted_data* extr);
-+
-+extern int
-+pfkey_key_process(struct sadb_ext *pfkey_ext,
-+ struct pfkey_extracted_data* extr);
-+
-+extern int
-+pfkey_ident_process(struct sadb_ext *pfkey_ext,
-+ struct pfkey_extracted_data* extr);
-+
-+extern int
-+pfkey_sens_process(struct sadb_ext *pfkey_ext,
-+ struct pfkey_extracted_data* extr);
-+
-+extern int
-+pfkey_prop_process(struct sadb_ext *pfkey_ext,
-+ struct pfkey_extracted_data* extr);
-+
-+extern int
-+pfkey_supported_process(struct sadb_ext *pfkey_ext,
-+ struct pfkey_extracted_data* extr);
-+
-+extern int
-+pfkey_spirange_process(struct sadb_ext *pfkey_ext,
-+ struct pfkey_extracted_data* extr);
-+
-+extern int
-+pfkey_x_kmprivate_process(struct sadb_ext *pfkey_ext,
-+ struct pfkey_extracted_data* extr);
-+
-+extern int
-+pfkey_x_satype_process(struct sadb_ext *pfkey_ext,
-+ struct pfkey_extracted_data* extr);
-+
-+extern int
-+pfkey_x_debug_process(struct sadb_ext *pfkey_ext,
-+ struct pfkey_extracted_data* extr);
-+
-+extern int pfkey_upmsg(struct socket *, struct sadb_msg *);
-+extern int pfkey_expire(struct ipsec_sa *, int);
-+extern int pfkey_acquire(struct ipsec_sa *);
-+#else /* ! __KERNEL__ */
-+
-+extern void (*pfkey_debug_func)(const char *message, ...);
-+extern void (*pfkey_error_func)(const char *message, ...);
-+extern void pfkey_print(struct sadb_msg *msg, FILE *out);
-+
-+
-+#endif /* __KERNEL__ */
-+
-+extern uint8_t satype2proto(uint8_t satype);
-+extern uint8_t proto2satype(uint8_t proto);
-+extern char* satype2name(uint8_t satype);
-+extern char* proto2name(uint8_t proto);
-+
-+struct key_opt
-+{
-+ uint32_t key_pid; /* process ID */
-+ struct sock *sk;
-+};
-+
-+#define key_pid(sk) ((struct key_opt*)&((sk)->protinfo))->key_pid
-+
-+/* XXX-mcr this is not an alignment, this is because the count is in 64-bit
-+ * words.
-+ */
-+#define IPSEC_PFKEYv2_ALIGN (sizeof(uint64_t)/sizeof(uint8_t))
-+#define BITS_PER_OCTET 8
-+#define OCTETBITS 8
-+#define PFKEYBITS 64
-+#define DIVUP(x,y) ((x + y -1) / y) /* divide, rounding upwards */
-+#define ALIGN_N(x,y) (DIVUP(x,y) * y) /* align on y boundary */
-+
-+#define IPSEC_PFKEYv2_LEN(x) ((x) * IPSEC_PFKEYv2_ALIGN)
-+#define IPSEC_PFKEYv2_WORDS(x) ((x) / IPSEC_PFKEYv2_ALIGN)
-+
-+
-+#define PFKEYv2_MAX_MSGSIZE 4096
-+
-+/*
-+ * PF_KEYv2 permitted and required extensions in and out bitmaps
-+ */
-+struct pf_key_ext_parsers_def {
-+ int (*parser)(struct sadb_ext*);
-+ char *parser_name;
-+};
-+
-+
-+extern unsigned int extensions_bitmaps[2/*in/out*/][2/*perm/req*/][SADB_MAX + 1/*ext*/];
-+#define EXT_BITS_IN 0
-+#define EXT_BITS_OUT 1
-+#define EXT_BITS_PERM 0
-+#define EXT_BITS_REQ 1
-+
-+extern void pfkey_extensions_init(struct sadb_ext *extensions[SADB_EXT_MAX + 1]);
-+extern void pfkey_extensions_free(struct sadb_ext *extensions[SADB_EXT_MAX + 1]);
-+extern void pfkey_msg_free(struct sadb_msg **pfkey_msg);
-+
-+extern int pfkey_msg_parse(struct sadb_msg *pfkey_msg,
-+ struct pf_key_ext_parsers_def *ext_parsers[],
-+ struct sadb_ext **extensions,
-+ int dir);
-+
-+extern int pfkey_register_reply(int satype, struct sadb_msg *sadb_msg);
-+
-+/*
-+ * PF_KEYv2 build function prototypes
-+ */
-+
-+int
-+pfkey_msg_hdr_build(struct sadb_ext** pfkey_ext,
-+ uint8_t msg_type,
-+ uint8_t satype,
-+ uint8_t msg_errno,
-+ uint32_t seq,
-+ uint32_t pid);
-+
-+int
-+pfkey_sa_ref_build(struct sadb_ext ** pfkey_ext,
-+ uint16_t exttype,
-+ uint32_t spi, /* in network order */
-+ uint8_t replay_window,
-+ uint8_t sa_state,
-+ uint8_t auth,
-+ uint8_t encrypt,
-+ uint32_t flags,
-+ uint32_t/*IPsecSAref_t*/ ref);
-+
-+int
-+pfkey_sa_build(struct sadb_ext ** pfkey_ext,
-+ uint16_t exttype,
-+ uint32_t spi, /* in network order */
-+ uint8_t replay_window,
-+ uint8_t sa_state,
-+ uint8_t auth,
-+ uint8_t encrypt,
-+ uint32_t flags);
-+
-+int
-+pfkey_lifetime_build(struct sadb_ext ** pfkey_ext,
-+ uint16_t exttype,
-+ uint32_t allocations,
-+ uint64_t bytes,
-+ uint64_t addtime,
-+ uint64_t usetime,
-+ uint32_t packets);
-+
-+int
-+pfkey_address_build(struct sadb_ext** pfkey_ext,
-+ uint16_t exttype,
-+ uint8_t proto,
-+ uint8_t prefixlen,
-+ struct sockaddr* address);
-+
-+int
-+pfkey_key_build(struct sadb_ext** pfkey_ext,
-+ uint16_t exttype,
-+ uint16_t key_bits,
-+ char* key);
-+
-+int
-+pfkey_ident_build(struct sadb_ext** pfkey_ext,
-+ uint16_t exttype,
-+ uint16_t ident_type,
-+ uint64_t ident_id,
-+ uint8_t ident_len,
-+ char* ident_string);
-+
-+#ifdef NAT_TRAVERSAL
-+#ifdef __KERNEL__
-+extern int pfkey_nat_t_new_mapping(struct ipsec_sa *, struct sockaddr *, __u16);
-+extern int pfkey_x_nat_t_type_process(struct sadb_ext *pfkey_ext, struct pfkey_extracted_data* extr);
-+extern int pfkey_x_nat_t_port_process(struct sadb_ext *pfkey_ext, struct pfkey_extracted_data* extr);
-+#endif /* __KERNEL__ */
-+int
-+pfkey_x_nat_t_type_build(struct sadb_ext** pfkey_ext,
-+ uint8_t type);
-+int
-+pfkey_x_nat_t_port_build(struct sadb_ext** pfkey_ext,
-+ uint16_t exttype,
-+ uint16_t port);
-+#endif
-+
-+int
-+pfkey_sens_build(struct sadb_ext** pfkey_ext,
-+ uint32_t dpd,
-+ uint8_t sens_level,
-+ uint8_t sens_len,
-+ uint64_t* sens_bitmap,
-+ uint8_t integ_level,
-+ uint8_t integ_len,
-+ uint64_t* integ_bitmap);
-+
-+int pfkey_x_protocol_build(struct sadb_ext **, uint8_t);
-+
-+
-+int
-+pfkey_prop_build(struct sadb_ext** pfkey_ext,
-+ uint8_t replay,
-+ unsigned int comb_num,
-+ struct sadb_comb* comb);
-+
-+int
-+pfkey_supported_build(struct sadb_ext** pfkey_ext,
-+ uint16_t exttype,
-+ unsigned int alg_num,
-+ struct sadb_alg* alg);
-+
-+int
-+pfkey_spirange_build(struct sadb_ext** pfkey_ext,
-+ uint16_t exttype,
-+ uint32_t min,
-+ uint32_t max);
-+
-+int
-+pfkey_x_kmprivate_build(struct sadb_ext** pfkey_ext);
-+
-+int
-+pfkey_x_satype_build(struct sadb_ext** pfkey_ext,
-+ uint8_t satype);
-+
-+int
-+pfkey_x_debug_build(struct sadb_ext** pfkey_ext,
-+ uint32_t tunnel,
-+ uint32_t netlink,
-+ uint32_t xform,
-+ uint32_t eroute,
-+ uint32_t spi,
-+ uint32_t radij,
-+ uint32_t esp,
-+ uint32_t ah,
-+ uint32_t rcv,
-+ uint32_t pfkey,
-+ uint32_t ipcomp,
-+ uint32_t verbose);
-+
-+int
-+pfkey_msg_build(struct sadb_msg** pfkey_msg,
-+ struct sadb_ext* extensions[],
-+ int dir);
-+
-+/* in pfkey_v2_debug.c - routines to decode numbers -> strings */
-+const char *
-+pfkey_v2_sadb_ext_string(int extnum);
-+
-+const char *
-+pfkey_v2_sadb_type_string(int sadb_type);
-+
-+
-+#endif /* __NET_IPSEC_PF_KEY_H */
-+
-+/*
-+ * $Log: pfkey.h,v $
-+ * Revision 1.45 2004/04/06 02:49:00 mcr
-+ * pullup of algo code from alg-branch.
-+ *
-+ * Revision 1.44 2003/12/10 01:20:01 mcr
-+ * NAT-traversal patches to KLIPS.
-+ *
-+ * Revision 1.43 2003/10/31 02:26:44 mcr
-+ * pulled up port-selector patches.
-+ *
-+ * Revision 1.42.2.2 2003/10/29 01:09:32 mcr
-+ * added debugging for pfkey library.
-+ *
-+ * Revision 1.42.2.1 2003/09/21 13:59:34 mcr
-+ * pre-liminary X.509 patch - does not yet pass tests.
-+ *
-+ * Revision 1.42 2003/08/25 22:08:19 mcr
-+ * removed pfkey_proto_init() from pfkey.h for 2.6 support.
-+ *
-+ * Revision 1.41 2003/05/07 17:28:57 mcr
-+ * new function pfkey_debug_func added for us in debugging from
-+
-+ * pfkey library.
-+ *
-+ * Revision 1.40 2003/01/30 02:31:34 rgb
-+ *
-+ * Convert IPsecSAref_t from signed to unsigned to fix apparent SAref exhaustion bug.
-+ *
-+ * Revision 1.39 2002/09/20 15:40:21 rgb
-+ * Switch from pfkey_alloc_ipsec_sa() to ipsec_sa_alloc().
-+ * Added ref parameter to pfkey_sa_build().
-+ * Cleaned out unused cruft.
-+ *
-+ * Revision 1.38 2002/05/14 02:37:24 rgb
-+ * Change all references to tdb, TDB or Tunnel Descriptor Block to ips,
-+ * ipsec_sa or ipsec_sa.
-+ * Added function prototypes for the functions moved to
-+ * pfkey_v2_ext_process.c.
-+ *
-+ * Revision 1.37 2002/04/24 07:36:49 mcr
-+ * Moved from ./lib/pfkey.h,v
-+ *
-+ * Revision 1.36 2002/01/20 20:34:49 mcr
-+ * added pfkey_v2_sadb_type_string to decode sadb_type to string.
-+ *
-+ * Revision 1.35 2001/11/27 05:27:47 mcr
-+ * pfkey parses are now maintained by a structure
-+ * that includes their name for debug purposes.
-+ *
-+ * Revision 1.34 2001/11/26 09:23:53 rgb
-+ * Merge MCR's ipsec_sa, eroute, proc and struct lifetime changes.
-+ *
-+ * Revision 1.33 2001/11/06 19:47:47 rgb
-+ * Added packet parameter to lifetime and comb structures.
-+ *
-+ * Revision 1.32 2001/09/08 21:13:34 rgb
-+ * Added pfkey ident extension support for ISAKMPd. (NetCelo)
-+ *
-+ * Revision 1.31 2001/06/14 19:35:16 rgb
-+ * Update copyright date.
-+ *
-+ * Revision 1.30 2001/02/27 07:04:52 rgb
-+ * Added satype2name prototype.
-+ *
-+ * Revision 1.29 2001/02/26 19:59:33 rgb
-+ * Ditch unused sadb_satype2proto[], replaced by satype2proto().
-+ *
-+ * Revision 1.28 2000/10/10 20:10:19 rgb
-+ * Added support for debug_ipcomp and debug_verbose to klipsdebug.
-+ *
-+ * Revision 1.27 2000/09/21 04:20:45 rgb
-+ * Fixed array size off-by-one error. (Thanks Svenning!)
-+ *
-+ * Revision 1.26 2000/09/12 03:26:05 rgb
-+ * Added pfkey_acquire prototype.
-+ *
-+ * Revision 1.25 2000/09/08 19:21:28 rgb
-+ * Fix pfkey_prop_build() parameter to be only single indirection.
-+ *
-+ * Revision 1.24 2000/09/01 18:46:42 rgb
-+ * Added a supported algorithms array lists, one per satype and registered
-+ * existing algorithms.
-+ * Fixed pfkey_list_{insert,remove}_{socket,support}() to allow change to
-+ * list.
-+ *
-+ * Revision 1.23 2000/08/27 01:55:26 rgb
-+ * Define OCTETBITS and PFKEYBITS to avoid using 'magic' numbers in code.
-+ *
-+ * Revision 1.22 2000/08/20 21:39:23 rgb
-+ * Added kernel prototypes for kernel funcitions pfkey_upmsg() and
-+ * pfkey_expire().
-+ *
-+ * Revision 1.21 2000/08/15 17:29:23 rgb
-+ * Fixes from SZI to untested pfkey_prop_build().
-+ *
-+ * Revision 1.20 2000/05/10 20:14:19 rgb
-+ * Fleshed out sensitivity, proposal and supported extensions.
-+ *
-+ * Revision 1.19 2000/03/16 14:07:23 rgb
-+ * Renamed ALIGN macro to avoid fighting with others in kernel.
-+ *
-+ * Revision 1.18 2000/01/22 23:24:06 rgb
-+ * Added prototypes for proto2satype(), satype2proto() and proto2name().
-+ *
-+ * Revision 1.17 2000/01/21 06:26:59 rgb
-+ * Converted from double tdb arguments to one structure (extr)
-+ * containing pointers to all temporary information structures.
-+ * Added klipsdebug switching capability.
-+ * Dropped unused argument to pfkey_x_satype_build().
-+ *
-+ * Revision 1.16 1999/12/29 21:17:41 rgb
-+ * Changed pfkey_msg_build() I/F to include a struct sadb_msg**
-+ * parameter for cleaner manipulation of extensions[] and to guard
-+ * against potential memory leaks.
-+ * Changed the I/F to pfkey_msg_free() for the same reason.
-+ *
-+ * Revision 1.15 1999/12/09 23:12:54 rgb
-+ * Added macro for BITS_PER_OCTET.
-+ * Added argument to pfkey_sa_build() to do eroutes.
-+ *
-+ * Revision 1.14 1999/12/08 20:33:25 rgb
-+ * Changed sa_family_t to uint16_t for 2.0.xx compatibility.
-+ *
-+ * Revision 1.13 1999/12/07 19:53:40 rgb
-+ * Removed unused first argument from extension parsers.
-+ * Changed __u* types to uint* to avoid use of asm/types.h and
-+ * sys/types.h in userspace code.
-+ * Added function prototypes for pfkey message and extensions
-+ * initialisation and cleanup.
-+ *
-+ * Revision 1.12 1999/12/01 22:19:38 rgb
-+ * Change pfkey_sa_build to accept an SPI in network byte order.
-+ *
-+ * Revision 1.11 1999/11/27 11:55:26 rgb
-+ * Added extern sadb_satype2proto to enable moving protocol lookup table
-+ * to lib/pfkey_v2_parse.c.
-+ * Delete unused, moved typedefs.
-+ * Add argument to pfkey_msg_parse() for direction.
-+ * Consolidated the 4 1-d extension bitmap arrays into one 4-d array.
-+ *
-+ * Revision 1.10 1999/11/23 22:29:21 rgb
-+ * This file has been moved in the distribution from klips/net/ipsec to
-+ * lib.
-+ * Add macros for dealing with alignment and rounding up more opaquely.
-+ * The uint<n>_t type defines have been moved to freeswan.h to avoid
-+ * chicken-and-egg problems.
-+ * Add macros for dealing with alignment and rounding up more opaque.
-+ * Added prototypes for using extention header bitmaps.
-+ * Added prototypes of all the build functions.
-+ *
-+ * Revision 1.9 1999/11/20 21:59:48 rgb
-+ * Moved socketlist type declarations and prototypes for shared use.
-+ * Slightly modified scope of sockaddr_key declaration.
-+ *
-+ * Revision 1.8 1999/11/17 14:34:25 rgb
-+ * Protect sa_family_t from being used in userspace with GLIBC<2.
-+ *
-+ * Revision 1.7 1999/10/27 19:40:35 rgb
-+ * Add a maximum PFKEY packet size macro.
-+ *
-+ * Revision 1.6 1999/10/26 16:58:58 rgb
-+ * Created a sockaddr_key and key_opt socket extension structures.
-+ *
-+ * Revision 1.5 1999/06/10 05:24:41 rgb
-+ * Renamed variables to reduce confusion.
-+ *
-+ * Revision 1.4 1999/04/29 15:21:11 rgb
-+ * Add pfkey support to debugging.
-+ * Add return values to init and cleanup functions.
-+ *
-+ * Revision 1.3 1999/04/15 17:58:07 rgb
-+ * Add RCSID labels.
-+ *
-+ */
---- /dev/null Tue Mar 11 13:02:56 2003
-+++ linux/include/pfkeyv2.h Mon Feb 9 13:51:03 2004
-@@ -0,0 +1,467 @@
-+/*
-+ * RCSID $Id: pfkeyv2.h,v 1.30 2004/04/06 02:49:00 mcr Exp $
-+ */
-+
-+/*
-+RFC 2367 PF_KEY Key Management API July 1998
-+
-+
-+Appendix D: Sample Header File
-+
-+This file defines structures and symbols for the PF_KEY Version 2
-+key management interface. It was written at the U.S. Naval Research
-+Laboratory. This file is in the public domain. The authors ask that
-+you leave this credit intact on any copies of this file.
-+*/
-+#ifndef __PFKEY_V2_H
-+#define __PFKEY_V2_H 1
-+
-+#define PF_KEY_V2 2
-+#define PFKEYV2_REVISION 199806L
-+
-+#define SADB_RESERVED 0
-+#define SADB_GETSPI 1
-+#define SADB_UPDATE 2
-+#define SADB_ADD 3
-+#define SADB_DELETE 4
-+#define SADB_GET 5
-+#define SADB_ACQUIRE 6
-+#define SADB_REGISTER 7
-+#define SADB_EXPIRE 8
-+#define SADB_FLUSH 9
-+#define SADB_DUMP 10
-+#define SADB_X_PROMISC 11
-+#define SADB_X_PCHANGE 12
-+#define SADB_X_GRPSA 13
-+#define SADB_X_ADDFLOW 14
-+#define SADB_X_DELFLOW 15
-+#define SADB_X_DEBUG 16
-+#define SADB_X_NAT_T_NEW_MAPPING 17
-+#define SADB_MAX 17
-+
-+struct sadb_msg {
-+ uint8_t sadb_msg_version;
-+ uint8_t sadb_msg_type;
-+ uint8_t sadb_msg_errno;
-+ uint8_t sadb_msg_satype;
-+ uint16_t sadb_msg_len;
-+ uint16_t sadb_msg_reserved;
-+ uint32_t sadb_msg_seq;
-+ uint32_t sadb_msg_pid;
-+};
-+
-+struct sadb_ext {
-+ uint16_t sadb_ext_len;
-+ uint16_t sadb_ext_type;
-+};
-+
-+struct sadb_sa {
-+ uint16_t sadb_sa_len;
-+ uint16_t sadb_sa_exttype;
-+ uint32_t sadb_sa_spi;
-+ uint8_t sadb_sa_replay;
-+ uint8_t sadb_sa_state;
-+ uint8_t sadb_sa_auth;
-+ uint8_t sadb_sa_encrypt;
-+ uint32_t sadb_sa_flags;
-+ uint32_t /*IPsecSAref_t*/ sadb_x_sa_ref; /* 32 bits */
-+ uint8_t sadb_x_reserved[4];
-+};
-+
-+struct sadb_sa_v1 {
-+ uint16_t sadb_sa_len;
-+ uint16_t sadb_sa_exttype;
-+ uint32_t sadb_sa_spi;
-+ uint8_t sadb_sa_replay;
-+ uint8_t sadb_sa_state;
-+ uint8_t sadb_sa_auth;
-+ uint8_t sadb_sa_encrypt;
-+ uint32_t sadb_sa_flags;
-+};
-+
-+struct sadb_lifetime {
-+ uint16_t sadb_lifetime_len;
-+ uint16_t sadb_lifetime_exttype;
-+ uint32_t sadb_lifetime_allocations;
-+ uint64_t sadb_lifetime_bytes;
-+ uint64_t sadb_lifetime_addtime;
-+ uint64_t sadb_lifetime_usetime;
-+ uint32_t sadb_x_lifetime_packets;
-+ uint32_t sadb_x_lifetime_reserved;
-+};
-+
-+struct sadb_address {
-+ uint16_t sadb_address_len;
-+ uint16_t sadb_address_exttype;
-+ uint8_t sadb_address_proto;
-+ uint8_t sadb_address_prefixlen;
-+ uint16_t sadb_address_reserved;
-+};
-+
-+struct sadb_key {
-+ uint16_t sadb_key_len;
-+ uint16_t sadb_key_exttype;
-+ uint16_t sadb_key_bits;
-+ uint16_t sadb_key_reserved;
-+};
-+
-+struct sadb_ident {
-+ uint16_t sadb_ident_len;
-+ uint16_t sadb_ident_exttype;
-+ uint16_t sadb_ident_type;
-+ uint16_t sadb_ident_reserved;
-+ uint64_t sadb_ident_id;
-+};
-+
-+struct sadb_sens {
-+ uint16_t sadb_sens_len;
-+ uint16_t sadb_sens_exttype;
-+ uint32_t sadb_sens_dpd;
-+ uint8_t sadb_sens_sens_level;
-+ uint8_t sadb_sens_sens_len;
-+ uint8_t sadb_sens_integ_level;
-+ uint8_t sadb_sens_integ_len;
-+ uint32_t sadb_sens_reserved;
-+};
-+
-+struct sadb_prop {
-+ uint16_t sadb_prop_len;
-+ uint16_t sadb_prop_exttype;
-+ uint8_t sadb_prop_replay;
-+ uint8_t sadb_prop_reserved[3];
-+};
-+
-+struct sadb_comb {
-+ uint8_t sadb_comb_auth;
-+ uint8_t sadb_comb_encrypt;
-+ uint16_t sadb_comb_flags;
-+ uint16_t sadb_comb_auth_minbits;
-+ uint16_t sadb_comb_auth_maxbits;
-+ uint16_t sadb_comb_encrypt_minbits;
-+ uint16_t sadb_comb_encrypt_maxbits;
-+ uint32_t sadb_comb_reserved;
-+ uint32_t sadb_comb_soft_allocations;
-+ uint32_t sadb_comb_hard_allocations;
-+ uint64_t sadb_comb_soft_bytes;
-+ uint64_t sadb_comb_hard_bytes;
-+ uint64_t sadb_comb_soft_addtime;
-+ uint64_t sadb_comb_hard_addtime;
-+ uint64_t sadb_comb_soft_usetime;
-+ uint64_t sadb_comb_hard_usetime;
-+ uint32_t sadb_x_comb_soft_packets;
-+ uint32_t sadb_x_comb_hard_packets;
-+};
-+
-+struct sadb_supported {
-+ uint16_t sadb_supported_len;
-+ uint16_t sadb_supported_exttype;
-+ uint32_t sadb_supported_reserved;
-+};
-+
-+struct sadb_alg {
-+ uint8_t sadb_alg_id;
-+ uint8_t sadb_alg_ivlen;
-+ uint16_t sadb_alg_minbits;
-+ uint16_t sadb_alg_maxbits;
-+ uint16_t sadb_alg_reserved;
-+};
-+
-+struct sadb_spirange {
-+ uint16_t sadb_spirange_len;
-+ uint16_t sadb_spirange_exttype;
-+ uint32_t sadb_spirange_min;
-+ uint32_t sadb_spirange_max;
-+ uint32_t sadb_spirange_reserved;
-+};
-+
-+struct sadb_x_kmprivate {
-+ uint16_t sadb_x_kmprivate_len;
-+ uint16_t sadb_x_kmprivate_exttype;
-+ uint32_t sadb_x_kmprivate_reserved;
-+};
-+
-+struct sadb_x_satype {
-+ uint16_t sadb_x_satype_len;
-+ uint16_t sadb_x_satype_exttype;
-+ uint8_t sadb_x_satype_satype;
-+ uint8_t sadb_x_satype_reserved[3];
-+};
-+
-+struct sadb_x_policy {
-+ uint16_t sadb_x_policy_len;
-+ uint16_t sadb_x_policy_exttype;
-+ uint16_t sadb_x_policy_type;
-+ uint8_t sadb_x_policy_dir;
-+ uint8_t sadb_x_policy_reserved;
-+ uint32_t sadb_x_policy_id;
-+ uint32_t sadb_x_policy_reserved2;
-+};
-+
-+struct sadb_x_debug {
-+ uint16_t sadb_x_debug_len;
-+ uint16_t sadb_x_debug_exttype;
-+ uint32_t sadb_x_debug_tunnel;
-+ uint32_t sadb_x_debug_netlink;
-+ uint32_t sadb_x_debug_xform;
-+ uint32_t sadb_x_debug_eroute;
-+ uint32_t sadb_x_debug_spi;
-+ uint32_t sadb_x_debug_radij;
-+ uint32_t sadb_x_debug_esp;
-+ uint32_t sadb_x_debug_ah;
-+ uint32_t sadb_x_debug_rcv;
-+ uint32_t sadb_x_debug_pfkey;
-+ uint32_t sadb_x_debug_ipcomp;
-+ uint32_t sadb_x_debug_verbose;
-+ uint8_t sadb_x_debug_reserved[4];
-+};
-+
-+struct sadb_x_nat_t_type {
-+ uint16_t sadb_x_nat_t_type_len;
-+ uint16_t sadb_x_nat_t_type_exttype;
-+ uint8_t sadb_x_nat_t_type_type;
-+ uint8_t sadb_x_nat_t_type_reserved[3];
-+};
-+struct sadb_x_nat_t_port {
-+ uint16_t sadb_x_nat_t_port_len;
-+ uint16_t sadb_x_nat_t_port_exttype;
-+ uint16_t sadb_x_nat_t_port_port;
-+ uint16_t sadb_x_nat_t_port_reserved;
-+};
-+
-+/*
-+ * A protocol structure for passing through the transport level
-+ * protocol. It contains more fields than are actually used/needed
-+ * but it is this way to be compatible with the structure used in
-+ * OpenBSD (http://www.openbsd.org/cgi-bin/cvsweb/src/sys/net/pfkeyv2.h)
-+ */
-+struct sadb_protocol {
-+ uint16_t sadb_protocol_len;
-+ uint16_t sadb_protocol_exttype;
-+ uint8_t sadb_protocol_proto;
-+ uint8_t sadb_protocol_direction;
-+ uint8_t sadb_protocol_flags;
-+ uint8_t sadb_protocol_reserved2;
-+};
-+
-+#define SADB_EXT_RESERVED 0
-+#define SADB_EXT_SA 1
-+#define SADB_EXT_LIFETIME_CURRENT 2
-+#define SADB_EXT_LIFETIME_HARD 3
-+#define SADB_EXT_LIFETIME_SOFT 4
-+#define SADB_EXT_ADDRESS_SRC 5
-+#define SADB_EXT_ADDRESS_DST 6
-+#define SADB_EXT_ADDRESS_PROXY 7
-+#define SADB_EXT_KEY_AUTH 8
-+#define SADB_EXT_KEY_ENCRYPT 9
-+#define SADB_EXT_IDENTITY_SRC 10
-+#define SADB_EXT_IDENTITY_DST 11
-+#define SADB_EXT_SENSITIVITY 12
-+#define SADB_EXT_PROPOSAL 13
-+#define SADB_EXT_SUPPORTED_AUTH 14
-+#define SADB_EXT_SUPPORTED_ENCRYPT 15
-+#define SADB_EXT_SPIRANGE 16
-+#define SADB_X_EXT_KMPRIVATE 17
-+#define SADB_X_EXT_SATYPE2 18
-+#ifdef KERNEL26_HAS_KAME_DUPLICATES
-+#define SADB_X_EXT_POLICY 18
-+#endif
-+#define SADB_X_EXT_SA2 19
-+#define SADB_X_EXT_ADDRESS_DST2 20
-+#define SADB_X_EXT_ADDRESS_SRC_FLOW 21
-+#define SADB_X_EXT_ADDRESS_DST_FLOW 22
-+#define SADB_X_EXT_ADDRESS_SRC_MASK 23
-+#define SADB_X_EXT_ADDRESS_DST_MASK 24
-+#define SADB_X_EXT_DEBUG 25
-+#define SADB_X_EXT_PROTOCOL 26
-+#define SADB_X_EXT_NAT_T_TYPE 27
-+#define SADB_X_EXT_NAT_T_SPORT 28
-+#define SADB_X_EXT_NAT_T_DPORT 29
-+#define SADB_X_EXT_NAT_T_OA 30
-+#define SADB_EXT_MAX 30
-+
-+/* SADB_X_DELFLOW required over and above SADB_X_SAFLAGS_CLEARFLOW */
-+#define SADB_X_EXT_ADDRESS_DELFLOW \
-+ ( (1<<SADB_X_EXT_ADDRESS_SRC_FLOW) \
-+ | (1<<SADB_X_EXT_ADDRESS_DST_FLOW) \
-+ | (1<<SADB_X_EXT_ADDRESS_SRC_MASK) \
-+ | (1<<SADB_X_EXT_ADDRESS_DST_MASK))
-+
-+#define SADB_SATYPE_UNSPEC 0
-+#define SADB_SATYPE_AH 2
-+#define SADB_SATYPE_ESP 3
-+#define SADB_SATYPE_RSVP 5
-+#define SADB_SATYPE_OSPFV2 6
-+#define SADB_SATYPE_RIPV2 7
-+#define SADB_SATYPE_MIP 8
-+#define SADB_X_SATYPE_IPIP 9
-+#ifdef KERNEL26_HAS_KAME_DUPLICATES
-+#define SADB_X_SATYPE_IPCOMP 9 /* ICK! */
-+#endif
-+#define SADB_X_SATYPE_COMP 10
-+#define SADB_X_SATYPE_INT 11
-+#define SADB_SATYPE_MAX 11
-+
-+#define SADB_SASTATE_LARVAL 0
-+#define SADB_SASTATE_MATURE 1
-+#define SADB_SASTATE_DYING 2
-+#define SADB_SASTATE_DEAD 3
-+#define SADB_SASTATE_MAX 3
-+
-+#define SADB_SAFLAGS_PFS 1
-+#define SADB_X_SAFLAGS_REPLACEFLOW 2
-+#define SADB_X_SAFLAGS_CLEARFLOW 4
-+#define SADB_X_SAFLAGS_INFLOW 8
-+
-+/* not obvious, but these are the same values as used in isakmp,
-+ * and in freeswan/ipsec_policy.h. If you need to add any, they
-+ * should be added as according to
-+ * http://www.iana.org/assignments/isakmp-registry
-+ *
-+ * and if not, then please try to use a private-use value, and
-+ * consider asking IANA to assign a value.
-+ */
-+#define SADB_AALG_NONE 0
-+#define SADB_AALG_MD5HMAC 2
-+#define SADB_AALG_SHA1HMAC 3
-+#define SADB_X_AALG_SHA2_256HMAC 5
-+#define SADB_X_AALG_SHA2_384HMAC 6
-+#define SADB_X_AALG_SHA2_512HMAC 7
-+#define SADB_X_AALG_RIPEMD160HMAC 8
-+#define SADB_X_AALG_NULL 251 /* kame */
-+#define SADB_AALG_MAX 251
-+
-+#define SADB_EALG_NONE 0
-+#define SADB_EALG_DESCBC 2
-+#define SADB_EALG_3DESCBC 3
-+#define SADB_X_EALG_CASTCBC 6
-+#define SADB_X_EALG_BLOWFISHCBC 7
-+#define SADB_EALG_NULL 11
-+#define SADB_X_EALG_AESCBC 12
-+#define SADB_EALG_MAX 255
-+
-+#define SADB_X_CALG_NONE 0
-+#define SADB_X_CALG_OUI 1
-+#define SADB_X_CALG_DEFLATE 2
-+#define SADB_X_CALG_LZS 3
-+#define SADB_X_CALG_V42BIS 4
-+#ifdef KERNEL26_HAS_KAME_DUPLICATES
-+#define SADB_X_CALG_LZJH 4
-+#endif
-+#define SADB_X_CALG_MAX 4
-+
-+#define SADB_X_TALG_NONE 0
-+#define SADB_X_TALG_IPv4_in_IPv4 1
-+#define SADB_X_TALG_IPv6_in_IPv4 2
-+#define SADB_X_TALG_IPv4_in_IPv6 3
-+#define SADB_X_TALG_IPv6_in_IPv6 4
-+#define SADB_X_TALG_MAX 4
-+
-+
-+#define SADB_IDENTTYPE_RESERVED 0
-+#define SADB_IDENTTYPE_PREFIX 1
-+#define SADB_IDENTTYPE_FQDN 2
-+#define SADB_IDENTTYPE_USERFQDN 3
-+#define SADB_X_IDENTTYPE_CONNECTION 4
-+#define SADB_IDENTTYPE_MAX 4
-+
-+#define SADB_KEY_FLAGS_MAX 0
-+#endif /* __PFKEY_V2_H */
-+
-+/*
-+ * $Log: pfkeyv2.h,v $
-+ * Revision 1.30 2004/04/06 02:49:00 mcr
-+ * pullup of algo code from alg-branch.
-+ *
-+ * Revision 1.29 2003/12/22 21:35:58 mcr
-+ * new patches from Dr{Who}.
-+ *
-+ * Revision 1.28 2003/12/22 19:33:15 mcr
-+ * added 0.6c NAT-T patch.
-+ *
-+ * Revision 1.27 2003/12/10 01:20:01 mcr
-+ * NAT-traversal patches to KLIPS.
-+ *
-+ * Revision 1.26 2003/10/31 02:26:44 mcr
-+ * pulled up port-selector patches.
-+ *
-+ * Revision 1.25.4.1 2003/09/21 13:59:34 mcr
-+ * pre-liminary X.509 patch - does not yet pass tests.
-+ *
-+ * Revision 1.25 2003/07/31 23:59:17 mcr
-+ * re-introduce kernel 2.6 duplicate values for now.
-+ * hope to get them changed!
-+ *
-+ * Revision 1.24 2003/07/31 22:55:27 mcr
-+ * added some definitions to keep pfkeyv2.h files in sync.
-+ *
-+ * Revision 1.23 2003/05/11 00:43:48 mcr
-+ * added comment about origin of values used
-+ *
-+ * Revision 1.22 2003/01/30 02:31:34 rgb
-+ *
-+ * Convert IPsecSAref_t from signed to unsigned to fix apparent SAref exhaustion bug.
-+ *
-+ * Revision 1.21 2002/12/16 19:26:49 mcr
-+ * added definition of FS 1.xx sadb structure
-+ *
-+ * Revision 1.20 2002/09/20 15:40:25 rgb
-+ * Added sadb_x_sa_ref to struct sadb_sa.
-+ *
-+ * Revision 1.19 2002/04/24 07:36:49 mcr
-+ * Moved from ./lib/pfkeyv2.h,v
-+ *
-+ * Revision 1.18 2001/11/06 19:47:47 rgb
-+ * Added packet parameter to lifetime and comb structures.
-+ *
-+ * Revision 1.17 2001/09/08 21:13:35 rgb
-+ * Added pfkey ident extension support for ISAKMPd. (NetCelo)
-+ *
-+ * Revision 1.16 2001/07/06 19:49:46 rgb
-+ * Added SADB_X_SAFLAGS_INFLOW for supporting incoming policy checks.
-+ *
-+ * Revision 1.15 2001/02/26 20:00:43 rgb
-+ * Added internal IP protocol 61 for magic SAs.
-+ *
-+ * Revision 1.14 2001/02/08 18:51:05 rgb
-+ * Include RFC document title and appendix subsection title.
-+ *
-+ * Revision 1.13 2000/10/10 20:10:20 rgb
-+ * Added support for debug_ipcomp and debug_verbose to klipsdebug.
-+ *
-+ * Revision 1.12 2000/09/15 06:41:50 rgb
-+ * Added V42BIS constant.
-+ *
-+ * Revision 1.11 2000/09/12 22:35:37 rgb
-+ * Restructured to remove unused extensions from CLEARFLOW messages.
-+ *
-+ * Revision 1.10 2000/09/12 18:50:09 rgb
-+ * Added IPIP tunnel types as algo support.
-+ *
-+ * Revision 1.9 2000/08/21 16:47:19 rgb
-+ * Added SADB_X_CALG_* macros for IPCOMP.
-+ *
-+ * Revision 1.8 2000/08/09 20:43:34 rgb
-+ * Fixed bitmask value for SADB_X_SAFLAGS_CLEAREROUTE.
-+ *
-+ * Revision 1.7 2000/01/21 06:28:37 rgb
-+ * Added flow add/delete message type macros.
-+ * Added flow address extension type macros.
-+ * Tidied up spacing.
-+ * Added klipsdebug switching capability.
-+ *
-+ * Revision 1.6 1999/11/27 11:56:08 rgb
-+ * Add SADB_X_SATYPE_COMP for compression, eventually.
-+ *
-+ * Revision 1.5 1999/11/23 22:23:16 rgb
-+ * This file has been moved in the distribution from klips/net/ipsec to
-+ * lib.
-+ *
-+ * Revision 1.4 1999/04/29 15:23:29 rgb
-+ * Add GRPSA support.
-+ * Add support for a second SATYPE, SA and DST_ADDRESS.
-+ * Add IPPROTO_IPIP support.
-+ *
-+ * Revision 1.3 1999/04/15 17:58:08 rgb
-+ * Add RCSID labels.
-+ *
-+ */
---- /dev/null Tue Mar 11 13:02:56 2003
-+++ linux/include/zlib/zlib.h Mon Feb 9 13:51:03 2004
-@@ -0,0 +1,893 @@
-+/* zlib.h -- interface of the 'zlib' general purpose compression library
-+ version 1.1.4, March 11th, 2002
-+
-+ Copyright (C) 1995-2002 Jean-loup Gailly and Mark Adler
-+
-+ This software is provided 'as-is', without any express or implied
-+ warranty. In no event will the authors be held liable for any damages
-+ arising from the use of this software.
-+
-+ Permission is granted to anyone to use this software for any purpose,
-+ including commercial applications, and to alter it and redistribute it
-+ freely, subject to the following restrictions:
-+
-+ 1. The origin of this software must not be misrepresented; you must not
-+ claim that you wrote the original software. If you use this software
-+ in a product, an acknowledgment in the product documentation would be
-+ appreciated but is not required.
-+ 2. Altered source versions must be plainly marked as such, and must not be
-+ misrepresented as being the original software.
-+ 3. This notice may not be removed or altered from any source distribution.
-+
-+ Jean-loup Gailly Mark Adler
-+ jloup@gzip.org madler@alumni.caltech.edu
-+
-+
-+ The data format used by the zlib library is described by RFCs (Request for
-+ Comments) 1950 to 1952 in the files ftp://ds.internic.net/rfc/rfc1950.txt
-+ (zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format).
-+*/
-+
-+#ifndef _ZLIB_H
-+#define _ZLIB_H
-+
-+#include "zconf.h"
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+#define ZLIB_VERSION "1.1.4"
-+
-+/*
-+ The 'zlib' compression library provides in-memory compression and
-+ decompression functions, including integrity checks of the uncompressed
-+ data. This version of the library supports only one compression method
-+ (deflation) but other algorithms will be added later and will have the same
-+ stream interface.
-+
-+ Compression can be done in a single step if the buffers are large
-+ enough (for example if an input file is mmap'ed), or can be done by
-+ repeated calls of the compression function. In the latter case, the
-+ application must provide more input and/or consume the output
-+ (providing more output space) before each call.
-+
-+ The library also supports reading and writing files in gzip (.gz) format
-+ with an interface similar to that of stdio.
-+
-+ The library does not install any signal handler. The decoder checks
-+ the consistency of the compressed data, so the library should never
-+ crash even in case of corrupted input.
-+*/
-+
-+typedef voidpf (*alloc_func) OF((voidpf opaque, uInt items, uInt size));
-+typedef void (*free_func) OF((voidpf opaque, voidpf address));
-+
-+struct internal_state;
-+
-+typedef struct z_stream_s {
-+ Bytef *next_in; /* next input byte */
-+ uInt avail_in; /* number of bytes available at next_in */
-+ uLong total_in; /* total nb of input bytes read so far */
-+
-+ Bytef *next_out; /* next output byte should be put there */
-+ uInt avail_out; /* remaining free space at next_out */
-+ uLong total_out; /* total nb of bytes output so far */
-+
-+ const char *msg; /* last error message, NULL if no error */
-+ struct internal_state FAR *state; /* not visible by applications */
-+
-+ alloc_func zalloc; /* used to allocate the internal state */
-+ free_func zfree; /* used to free the internal state */
-+ voidpf opaque; /* private data object passed to zalloc and zfree */
-+
-+ int data_type; /* best guess about the data type: ascii or binary */
-+ uLong adler; /* adler32 value of the uncompressed data */
-+ uLong reserved; /* reserved for future use */
-+} z_stream;
-+
-+typedef z_stream FAR *z_streamp;
-+
-+/*
-+ The application must update next_in and avail_in when avail_in has
-+ dropped to zero. It must update next_out and avail_out when avail_out
-+ has dropped to zero. The application must initialize zalloc, zfree and
-+ opaque before calling the init function. All other fields are set by the
-+ compression library and must not be updated by the application.
-+
-+ The opaque value provided by the application will be passed as the first
-+ parameter for calls of zalloc and zfree. This can be useful for custom
-+ memory management. The compression library attaches no meaning to the
-+ opaque value.
-+
-+ zalloc must return Z_NULL if there is not enough memory for the object.
-+ If zlib is used in a multi-threaded application, zalloc and zfree must be
-+ thread safe.
-+
-+ On 16-bit systems, the functions zalloc and zfree must be able to allocate
-+ exactly 65536 bytes, but will not be required to allocate more than this
-+ if the symbol MAXSEG_64K is defined (see zconf.h). WARNING: On MSDOS,
-+ pointers returned by zalloc for objects of exactly 65536 bytes *must*
-+ have their offset normalized to zero. The default allocation function
-+ provided by this library ensures this (see zutil.c). To reduce memory
-+ requirements and avoid any allocation of 64K objects, at the expense of
-+ compression ratio, compile the library with -DMAX_WBITS=14 (see zconf.h).
-+
-+ The fields total_in and total_out can be used for statistics or
-+ progress reports. After compression, total_in holds the total size of
-+ the uncompressed data and may be saved for use in the decompressor
-+ (particularly if the decompressor wants to decompress everything in
-+ a single step).
-+*/
-+
-+ /* constants */
-+
-+#define Z_NO_FLUSH 0
-+#define Z_PARTIAL_FLUSH 1 /* will be removed, use Z_SYNC_FLUSH instead */
-+#define Z_SYNC_FLUSH 2
-+#define Z_FULL_FLUSH 3
-+#define Z_FINISH 4
-+/* Allowed flush values; see deflate() below for details */
-+
-+#define Z_OK 0
-+#define Z_STREAM_END 1
-+#define Z_NEED_DICT 2
-+#define Z_ERRNO (-1)
-+#define Z_STREAM_ERROR (-2)
-+#define Z_DATA_ERROR (-3)
-+#define Z_MEM_ERROR (-4)
-+#define Z_BUF_ERROR (-5)
-+#define Z_VERSION_ERROR (-6)
-+/* Return codes for the compression/decompression functions. Negative
-+ * values are errors, positive values are used for special but normal events.
-+ */
-+
-+#define Z_NO_COMPRESSION 0
-+#define Z_BEST_SPEED 1
-+#define Z_BEST_COMPRESSION 9
-+#define Z_DEFAULT_COMPRESSION (-1)
-+/* compression levels */
-+
-+#define Z_FILTERED 1
-+#define Z_HUFFMAN_ONLY 2
-+#define Z_DEFAULT_STRATEGY 0
-+/* compression strategy; see deflateInit2() below for details */
-+
-+#define Z_BINARY 0
-+#define Z_ASCII 1
-+#define Z_UNKNOWN 2
-+/* Possible values of the data_type field */
-+
-+#define Z_DEFLATED 8
-+/* The deflate compression method (the only one supported in this version) */
-+
-+#define Z_NULL 0 /* for initializing zalloc, zfree, opaque */
-+
-+#define zlib_version zlibVersion()
-+/* for compatibility with versions < 1.0.2 */
-+
-+ /* basic functions */
-+
-+ZEXTERN const char * ZEXPORT zlibVersion OF((void));
-+/* The application can compare zlibVersion and ZLIB_VERSION for consistency.
-+ If the first character differs, the library code actually used is
-+ not compatible with the zlib.h header file used by the application.
-+ This check is automatically made by deflateInit and inflateInit.
-+ */
-+
-+/*
-+ZEXTERN int ZEXPORT deflateInit OF((z_streamp strm, int level));
-+
-+ Initializes the internal stream state for compression. The fields
-+ zalloc, zfree and opaque must be initialized before by the caller.
-+ If zalloc and zfree are set to Z_NULL, deflateInit updates them to
-+ use default allocation functions.
-+
-+ The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9:
-+ 1 gives best speed, 9 gives best compression, 0 gives no compression at
-+ all (the input data is simply copied a block at a time).
-+ Z_DEFAULT_COMPRESSION requests a default compromise between speed and
-+ compression (currently equivalent to level 6).
-+
-+ deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not
-+ enough memory, Z_STREAM_ERROR if level is not a valid compression level,
-+ Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible
-+ with the version assumed by the caller (ZLIB_VERSION).
-+ msg is set to null if there is no error message. deflateInit does not
-+ perform any compression: this will be done by deflate().
-+*/
-+
-+
-+ZEXTERN int ZEXPORT deflate OF((z_streamp strm, int flush));
-+/*
-+ deflate compresses as much data as possible, and stops when the input
-+ buffer becomes empty or the output buffer becomes full. It may introduce some
-+ output latency (reading input without producing any output) except when
-+ forced to flush.
-+
-+ The detailed semantics are as follows. deflate performs one or both of the
-+ following actions:
-+
-+ - Compress more input starting at next_in and update next_in and avail_in
-+ accordingly. If not all input can be processed (because there is not
-+ enough room in the output buffer), next_in and avail_in are updated and
-+ processing will resume at this point for the next call of deflate().
-+
-+ - Provide more output starting at next_out and update next_out and avail_out
-+ accordingly. This action is forced if the parameter flush is non zero.
-+ Forcing flush frequently degrades the compression ratio, so this parameter
-+ should be set only when necessary (in interactive applications).
-+ Some output may be provided even if flush is not set.
-+
-+ Before the call of deflate(), the application should ensure that at least
-+ one of the actions is possible, by providing more input and/or consuming
-+ more output, and updating avail_in or avail_out accordingly; avail_out
-+ should never be zero before the call. The application can consume the
-+ compressed output when it wants, for example when the output buffer is full
-+ (avail_out == 0), or after each call of deflate(). If deflate returns Z_OK
-+ and with zero avail_out, it must be called again after making room in the
-+ output buffer because there might be more output pending.
-+
-+ If the parameter flush is set to Z_SYNC_FLUSH, all pending output is
-+ flushed to the output buffer and the output is aligned on a byte boundary, so
-+ that the decompressor can get all input data available so far. (In particular
-+ avail_in is zero after the call if enough output space has been provided
-+ before the call.) Flushing may degrade compression for some compression
-+ algorithms and so it should be used only when necessary.
-+
-+ If flush is set to Z_FULL_FLUSH, all output is flushed as with
-+ Z_SYNC_FLUSH, and the compression state is reset so that decompression can
-+ restart from this point if previous compressed data has been damaged or if
-+ random access is desired. Using Z_FULL_FLUSH too often can seriously degrade
-+ the compression.
-+
-+ If deflate returns with avail_out == 0, this function must be called again
-+ with the same value of the flush parameter and more output space (updated
-+ avail_out), until the flush is complete (deflate returns with non-zero
-+ avail_out).
-+
-+ If the parameter flush is set to Z_FINISH, pending input is processed,
-+ pending output is flushed and deflate returns with Z_STREAM_END if there
-+ was enough output space; if deflate returns with Z_OK, this function must be
-+ called again with Z_FINISH and more output space (updated avail_out) but no
-+ more input data, until it returns with Z_STREAM_END or an error. After
-+ deflate has returned Z_STREAM_END, the only possible operations on the
-+ stream are deflateReset or deflateEnd.
-+
-+ Z_FINISH can be used immediately after deflateInit if all the compression
-+ is to be done in a single step. In this case, avail_out must be at least
-+ 0.1% larger than avail_in plus 12 bytes. If deflate does not return
-+ Z_STREAM_END, then it must be called again as described above.
-+
-+ deflate() sets strm->adler to the adler32 checksum of all input read
-+ so far (that is, total_in bytes).
-+
-+ deflate() may update data_type if it can make a good guess about
-+ the input data type (Z_ASCII or Z_BINARY). In doubt, the data is considered
-+ binary. This field is only for information purposes and does not affect
-+ the compression algorithm in any manner.
-+
-+ deflate() returns Z_OK if some progress has been made (more input
-+ processed or more output produced), Z_STREAM_END if all input has been
-+ consumed and all output has been produced (only when flush is set to
-+ Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example
-+ if next_in or next_out was NULL), Z_BUF_ERROR if no progress is possible
-+ (for example avail_in or avail_out was zero).
-+*/
-+
-+
-+ZEXTERN int ZEXPORT deflateEnd OF((z_streamp strm));
-+/*
-+ All dynamically allocated data structures for this stream are freed.
-+ This function discards any unprocessed input and does not flush any
-+ pending output.
-+
-+ deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the
-+ stream state was inconsistent, Z_DATA_ERROR if the stream was freed
-+ prematurely (some input or output was discarded). In the error case,
-+ msg may be set but then points to a static string (which must not be
-+ deallocated).
-+*/
-+
-+
-+/*
-+ZEXTERN int ZEXPORT inflateInit OF((z_streamp strm));
-+
-+ Initializes the internal stream state for decompression. The fields
-+ next_in, avail_in, zalloc, zfree and opaque must be initialized before by
-+ the caller. If next_in is not Z_NULL and avail_in is large enough (the exact
-+ value depends on the compression method), inflateInit determines the
-+ compression method from the zlib header and allocates all data structures
-+ accordingly; otherwise the allocation will be deferred to the first call of
-+ inflate. If zalloc and zfree are set to Z_NULL, inflateInit updates them to
-+ use default allocation functions.
-+
-+ inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough
-+ memory, Z_VERSION_ERROR if the zlib library version is incompatible with the
-+ version assumed by the caller. msg is set to null if there is no error
-+ message. inflateInit does not perform any decompression apart from reading
-+ the zlib header if present: this will be done by inflate(). (So next_in and
-+ avail_in may be modified, but next_out and avail_out are unchanged.)
-+*/
-+
-+
-+ZEXTERN int ZEXPORT inflate OF((z_streamp strm, int flush));
-+/*
-+ inflate decompresses as much data as possible, and stops when the input
-+ buffer becomes empty or the output buffer becomes full. It may some
-+ introduce some output latency (reading input without producing any output)
-+ except when forced to flush.
-+
-+ The detailed semantics are as follows. inflate performs one or both of the
-+ following actions:
-+
-+ - Decompress more input starting at next_in and update next_in and avail_in
-+ accordingly. If not all input can be processed (because there is not
-+ enough room in the output buffer), next_in is updated and processing
-+ will resume at this point for the next call of inflate().
-+
-+ - Provide more output starting at next_out and update next_out and avail_out
-+ accordingly. inflate() provides as much output as possible, until there
-+ is no more input data or no more space in the output buffer (see below
-+ about the flush parameter).
-+
-+ Before the call of inflate(), the application should ensure that at least
-+ one of the actions is possible, by providing more input and/or consuming
-+ more output, and updating the next_* and avail_* values accordingly.
-+ The application can consume the uncompressed output when it wants, for
-+ example when the output buffer is full (avail_out == 0), or after each
-+ call of inflate(). If inflate returns Z_OK and with zero avail_out, it
-+ must be called again after making room in the output buffer because there
-+ might be more output pending.
-+
-+ If the parameter flush is set to Z_SYNC_FLUSH, inflate flushes as much
-+ output as possible to the output buffer. The flushing behavior of inflate is
-+ not specified for values of the flush parameter other than Z_SYNC_FLUSH
-+ and Z_FINISH, but the current implementation actually flushes as much output
-+ as possible anyway.
-+
-+ inflate() should normally be called until it returns Z_STREAM_END or an
-+ error. However if all decompression is to be performed in a single step
-+ (a single call of inflate), the parameter flush should be set to
-+ Z_FINISH. In this case all pending input is processed and all pending
-+ output is flushed; avail_out must be large enough to hold all the
-+ uncompressed data. (The size of the uncompressed data may have been saved
-+ by the compressor for this purpose.) The next operation on this stream must
-+ be inflateEnd to deallocate the decompression state. The use of Z_FINISH
-+ is never required, but can be used to inform inflate that a faster routine
-+ may be used for the single inflate() call.
-+
-+ If a preset dictionary is needed at this point (see inflateSetDictionary
-+ below), inflate sets strm-adler to the adler32 checksum of the
-+ dictionary chosen by the compressor and returns Z_NEED_DICT; otherwise
-+ it sets strm->adler to the adler32 checksum of all output produced
-+ so far (that is, total_out bytes) and returns Z_OK, Z_STREAM_END or
-+ an error code as described below. At the end of the stream, inflate()
-+ checks that its computed adler32 checksum is equal to that saved by the
-+ compressor and returns Z_STREAM_END only if the checksum is correct.
-+
-+ inflate() returns Z_OK if some progress has been made (more input processed
-+ or more output produced), Z_STREAM_END if the end of the compressed data has
-+ been reached and all uncompressed output has been produced, Z_NEED_DICT if a
-+ preset dictionary is needed at this point, Z_DATA_ERROR if the input data was
-+ corrupted (input stream not conforming to the zlib format or incorrect
-+ adler32 checksum), Z_STREAM_ERROR if the stream structure was inconsistent
-+ (for example if next_in or next_out was NULL), Z_MEM_ERROR if there was not
-+ enough memory, Z_BUF_ERROR if no progress is possible or if there was not
-+ enough room in the output buffer when Z_FINISH is used. In the Z_DATA_ERROR
-+ case, the application may then call inflateSync to look for a good
-+ compression block.
-+*/
-+
-+
-+ZEXTERN int ZEXPORT inflateEnd OF((z_streamp strm));
-+/*
-+ All dynamically allocated data structures for this stream are freed.
-+ This function discards any unprocessed input and does not flush any
-+ pending output.
-+
-+ inflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state
-+ was inconsistent. In the error case, msg may be set but then points to a
-+ static string (which must not be deallocated).
-+*/
-+
-+ /* Advanced functions */
-+
-+/*
-+ The following functions are needed only in some special applications.
-+*/
-+
-+/*
-+ZEXTERN int ZEXPORT deflateInit2 OF((z_streamp strm,
-+ int level,
-+ int method,
-+ int windowBits,
-+ int memLevel,
-+ int strategy));
-+
-+ This is another version of deflateInit with more compression options. The
-+ fields next_in, zalloc, zfree and opaque must be initialized before by
-+ the caller.
-+
-+ The method parameter is the compression method. It must be Z_DEFLATED in
-+ this version of the library.
-+
-+ The windowBits parameter is the base two logarithm of the window size
-+ (the size of the history buffer). It should be in the range 8..15 for this
-+ version of the library. Larger values of this parameter result in better
-+ compression at the expense of memory usage. The default value is 15 if
-+ deflateInit is used instead.
-+
-+ The memLevel parameter specifies how much memory should be allocated
-+ for the internal compression state. memLevel=1 uses minimum memory but
-+ is slow and reduces compression ratio; memLevel=9 uses maximum memory
-+ for optimal speed. The default value is 8. See zconf.h for total memory
-+ usage as a function of windowBits and memLevel.
-+
-+ The strategy parameter is used to tune the compression algorithm. Use the
-+ value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data produced by a
-+ filter (or predictor), or Z_HUFFMAN_ONLY to force Huffman encoding only (no
-+ string match). Filtered data consists mostly of small values with a
-+ somewhat random distribution. In this case, the compression algorithm is
-+ tuned to compress them better. The effect of Z_FILTERED is to force more
-+ Huffman coding and less string matching; it is somewhat intermediate
-+ between Z_DEFAULT and Z_HUFFMAN_ONLY. The strategy parameter only affects
-+ the compression ratio but not the correctness of the compressed output even
-+ if it is not set appropriately.
-+
-+ deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
-+ memory, Z_STREAM_ERROR if a parameter is invalid (such as an invalid
-+ method). msg is set to null if there is no error message. deflateInit2 does
-+ not perform any compression: this will be done by deflate().
-+*/
-+
-+ZEXTERN int ZEXPORT deflateSetDictionary OF((z_streamp strm,
-+ const Bytef *dictionary,
-+ uInt dictLength));
-+/*
-+ Initializes the compression dictionary from the given byte sequence
-+ without producing any compressed output. This function must be called
-+ immediately after deflateInit, deflateInit2 or deflateReset, before any
-+ call of deflate. The compressor and decompressor must use exactly the same
-+ dictionary (see inflateSetDictionary).
-+
-+ The dictionary should consist of strings (byte sequences) that are likely
-+ to be encountered later in the data to be compressed, with the most commonly
-+ used strings preferably put towards the end of the dictionary. Using a
-+ dictionary is most useful when the data to be compressed is short and can be
-+ predicted with good accuracy; the data can then be compressed better than
-+ with the default empty dictionary.
-+
-+ Depending on the size of the compression data structures selected by
-+ deflateInit or deflateInit2, a part of the dictionary may in effect be
-+ discarded, for example if the dictionary is larger than the window size in
-+ deflate or deflate2. Thus the strings most likely to be useful should be
-+ put at the end of the dictionary, not at the front.
-+
-+ Upon return of this function, strm->adler is set to the Adler32 value
-+ of the dictionary; the decompressor may later use this value to determine
-+ which dictionary has been used by the compressor. (The Adler32 value
-+ applies to the whole dictionary even if only a subset of the dictionary is
-+ actually used by the compressor.)
-+
-+ deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a
-+ parameter is invalid (such as NULL dictionary) or the stream state is
-+ inconsistent (for example if deflate has already been called for this stream
-+ or if the compression method is bsort). deflateSetDictionary does not
-+ perform any compression: this will be done by deflate().
-+*/
-+
-+ZEXTERN int ZEXPORT deflateCopy OF((z_streamp dest,
-+ z_streamp source));
-+/*
-+ Sets the destination stream as a complete copy of the source stream.
-+
-+ This function can be useful when several compression strategies will be
-+ tried, for example when there are several ways of pre-processing the input
-+ data with a filter. The streams that will be discarded should then be freed
-+ by calling deflateEnd. Note that deflateCopy duplicates the internal
-+ compression state which can be quite large, so this strategy is slow and
-+ can consume lots of memory.
-+
-+ deflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not
-+ enough memory, Z_STREAM_ERROR if the source stream state was inconsistent
-+ (such as zalloc being NULL). msg is left unchanged in both source and
-+ destination.
-+*/
-+
-+ZEXTERN int ZEXPORT deflateReset OF((z_streamp strm));
-+/*
-+ This function is equivalent to deflateEnd followed by deflateInit,
-+ but does not free and reallocate all the internal compression state.
-+ The stream will keep the same compression level and any other attributes
-+ that may have been set by deflateInit2.
-+
-+ deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source
-+ stream state was inconsistent (such as zalloc or state being NULL).
-+*/
-+
-+ZEXTERN int ZEXPORT deflateParams OF((z_streamp strm,
-+ int level,
-+ int strategy));
-+/*
-+ Dynamically update the compression level and compression strategy. The
-+ interpretation of level and strategy is as in deflateInit2. This can be
-+ used to switch between compression and straight copy of the input data, or
-+ to switch to a different kind of input data requiring a different
-+ strategy. If the compression level is changed, the input available so far
-+ is compressed with the old level (and may be flushed); the new level will
-+ take effect only at the next call of deflate().
-+
-+ Before the call of deflateParams, the stream state must be set as for
-+ a call of deflate(), since the currently available input may have to
-+ be compressed and flushed. In particular, strm->avail_out must be non-zero.
-+
-+ deflateParams returns Z_OK if success, Z_STREAM_ERROR if the source
-+ stream state was inconsistent or if a parameter was invalid, Z_BUF_ERROR
-+ if strm->avail_out was zero.
-+*/
-+
-+/*
-+ZEXTERN int ZEXPORT inflateInit2 OF((z_streamp strm,
-+ int windowBits));
-+
-+ This is another version of inflateInit with an extra parameter. The
-+ fields next_in, avail_in, zalloc, zfree and opaque must be initialized
-+ before by the caller.
-+
-+ The windowBits parameter is the base two logarithm of the maximum window
-+ size (the size of the history buffer). It should be in the range 8..15 for
-+ this version of the library. The default value is 15 if inflateInit is used
-+ instead. If a compressed stream with a larger window size is given as
-+ input, inflate() will return with the error code Z_DATA_ERROR instead of
-+ trying to allocate a larger window.
-+
-+ inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
-+ memory, Z_STREAM_ERROR if a parameter is invalid (such as a negative
-+ memLevel). msg is set to null if there is no error message. inflateInit2
-+ does not perform any decompression apart from reading the zlib header if
-+ present: this will be done by inflate(). (So next_in and avail_in may be
-+ modified, but next_out and avail_out are unchanged.)
-+*/
-+
-+ZEXTERN int ZEXPORT inflateSetDictionary OF((z_streamp strm,
-+ const Bytef *dictionary,
-+ uInt dictLength));
-+/*
-+ Initializes the decompression dictionary from the given uncompressed byte
-+ sequence. This function must be called immediately after a call of inflate
-+ if this call returned Z_NEED_DICT. The dictionary chosen by the compressor
-+ can be determined from the Adler32 value returned by this call of
-+ inflate. The compressor and decompressor must use exactly the same
-+ dictionary (see deflateSetDictionary).
-+
-+ inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a
-+ parameter is invalid (such as NULL dictionary) or the stream state is
-+ inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the
-+ expected one (incorrect Adler32 value). inflateSetDictionary does not
-+ perform any decompression: this will be done by subsequent calls of
-+ inflate().
-+*/
-+
-+ZEXTERN int ZEXPORT inflateSync OF((z_streamp strm));
-+/*
-+ Skips invalid compressed data until a full flush point (see above the
-+ description of deflate with Z_FULL_FLUSH) can be found, or until all
-+ available input is skipped. No output is provided.
-+
-+ inflateSync returns Z_OK if a full flush point has been found, Z_BUF_ERROR
-+ if no more input was provided, Z_DATA_ERROR if no flush point has been found,
-+ or Z_STREAM_ERROR if the stream structure was inconsistent. In the success
-+ case, the application may save the current current value of total_in which
-+ indicates where valid compressed data was found. In the error case, the
-+ application may repeatedly call inflateSync, providing more input each time,
-+ until success or end of the input data.
-+*/
-+
-+ZEXTERN int ZEXPORT inflateReset OF((z_streamp strm));
-+/*
-+ This function is equivalent to inflateEnd followed by inflateInit,
-+ but does not free and reallocate all the internal decompression state.
-+ The stream will keep attributes that may have been set by inflateInit2.
-+
-+ inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source
-+ stream state was inconsistent (such as zalloc or state being NULL).
-+*/
-+
-+
-+ /* utility functions */
-+
-+/*
-+ The following utility functions are implemented on top of the
-+ basic stream-oriented functions. To simplify the interface, some
-+ default options are assumed (compression level and memory usage,
-+ standard memory allocation functions). The source code of these
-+ utility functions can easily be modified if you need special options.
-+*/
-+
-+ZEXTERN int ZEXPORT compress OF((Bytef *dest, uLongf *destLen,
-+ const Bytef *source, uLong sourceLen));
-+/*
-+ Compresses the source buffer into the destination buffer. sourceLen is
-+ the byte length of the source buffer. Upon entry, destLen is the total
-+ size of the destination buffer, which must be at least 0.1% larger than
-+ sourceLen plus 12 bytes. Upon exit, destLen is the actual size of the
-+ compressed buffer.
-+ This function can be used to compress a whole file at once if the
-+ input file is mmap'ed.
-+ compress returns Z_OK if success, Z_MEM_ERROR if there was not
-+ enough memory, Z_BUF_ERROR if there was not enough room in the output
-+ buffer.
-+*/
-+
-+ZEXTERN int ZEXPORT compress2 OF((Bytef *dest, uLongf *destLen,
-+ const Bytef *source, uLong sourceLen,
-+ int level));
-+/*
-+ Compresses the source buffer into the destination buffer. The level
-+ parameter has the same meaning as in deflateInit. sourceLen is the byte
-+ length of the source buffer. Upon entry, destLen is the total size of the
-+ destination buffer, which must be at least 0.1% larger than sourceLen plus
-+ 12 bytes. Upon exit, destLen is the actual size of the compressed buffer.
-+
-+ compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
-+ memory, Z_BUF_ERROR if there was not enough room in the output buffer,
-+ Z_STREAM_ERROR if the level parameter is invalid.
-+*/
-+
-+ZEXTERN int ZEXPORT uncompress OF((Bytef *dest, uLongf *destLen,
-+ const Bytef *source, uLong sourceLen));
-+/*
-+ Decompresses the source buffer into the destination buffer. sourceLen is
-+ the byte length of the source buffer. Upon entry, destLen is the total
-+ size of the destination buffer, which must be large enough to hold the
-+ entire uncompressed data. (The size of the uncompressed data must have
-+ been saved previously by the compressor and transmitted to the decompressor
-+ by some mechanism outside the scope of this compression library.)
-+ Upon exit, destLen is the actual size of the compressed buffer.
-+ This function can be used to decompress a whole file at once if the
-+ input file is mmap'ed.
-+
-+ uncompress returns Z_OK if success, Z_MEM_ERROR if there was not
-+ enough memory, Z_BUF_ERROR if there was not enough room in the output
-+ buffer, or Z_DATA_ERROR if the input data was corrupted.
-+*/
-+
-+
-+typedef voidp gzFile;
-+
-+ZEXTERN gzFile ZEXPORT gzopen OF((const char *path, const char *mode));
-+/*
-+ Opens a gzip (.gz) file for reading or writing. The mode parameter
-+ is as in fopen ("rb" or "wb") but can also include a compression level
-+ ("wb9") or a strategy: 'f' for filtered data as in "wb6f", 'h' for
-+ Huffman only compression as in "wb1h". (See the description
-+ of deflateInit2 for more information about the strategy parameter.)
-+
-+ gzopen can be used to read a file which is not in gzip format; in this
-+ case gzread will directly read from the file without decompression.
-+
-+ gzopen returns NULL if the file could not be opened or if there was
-+ insufficient memory to allocate the (de)compression state; errno
-+ can be checked to distinguish the two cases (if errno is zero, the
-+ zlib error is Z_MEM_ERROR). */
-+
-+ZEXTERN gzFile ZEXPORT gzdopen OF((int fd, const char *mode));
-+/*
-+ gzdopen() associates a gzFile with the file descriptor fd. File
-+ descriptors are obtained from calls like open, dup, creat, pipe or
-+ fileno (in the file has been previously opened with fopen).
-+ The mode parameter is as in gzopen.
-+ The next call of gzclose on the returned gzFile will also close the
-+ file descriptor fd, just like fclose(fdopen(fd), mode) closes the file
-+ descriptor fd. If you want to keep fd open, use gzdopen(dup(fd), mode).
-+ gzdopen returns NULL if there was insufficient memory to allocate
-+ the (de)compression state.
-+*/
-+
-+ZEXTERN int ZEXPORT gzsetparams OF((gzFile file, int level, int strategy));
-+/*
-+ Dynamically update the compression level or strategy. See the description
-+ of deflateInit2 for the meaning of these parameters.
-+ gzsetparams returns Z_OK if success, or Z_STREAM_ERROR if the file was not
-+ opened for writing.
-+*/
-+
-+ZEXTERN int ZEXPORT gzread OF((gzFile file, voidp buf, unsigned len));
-+/*
-+ Reads the given number of uncompressed bytes from the compressed file.
-+ If the input file was not in gzip format, gzread copies the given number
-+ of bytes into the buffer.
-+ gzread returns the number of uncompressed bytes actually read (0 for
-+ end of file, -1 for error). */
-+
-+ZEXTERN int ZEXPORT gzwrite OF((gzFile file,
-+ const voidp buf, unsigned len));
-+/*
-+ Writes the given number of uncompressed bytes into the compressed file.
-+ gzwrite returns the number of uncompressed bytes actually written
-+ (0 in case of error).
-+*/
-+
-+ZEXTERN int ZEXPORTVA gzprintf OF((gzFile file, const char *format, ...));
-+/*
-+ Converts, formats, and writes the args to the compressed file under
-+ control of the format string, as in fprintf. gzprintf returns the number of
-+ uncompressed bytes actually written (0 in case of error).
-+*/
-+
-+ZEXTERN int ZEXPORT gzputs OF((gzFile file, const char *s));
-+/*
-+ Writes the given null-terminated string to the compressed file, excluding
-+ the terminating null character.
-+ gzputs returns the number of characters written, or -1 in case of error.
-+*/
-+
-+ZEXTERN char * ZEXPORT gzgets OF((gzFile file, char *buf, int len));
-+/*
-+ Reads bytes from the compressed file until len-1 characters are read, or
-+ a newline character is read and transferred to buf, or an end-of-file
-+ condition is encountered. The string is then terminated with a null
-+ character.
-+ gzgets returns buf, or Z_NULL in case of error.
-+*/
-+
-+ZEXTERN int ZEXPORT gzputc OF((gzFile file, int c));
-+/*
-+ Writes c, converted to an unsigned char, into the compressed file.
-+ gzputc returns the value that was written, or -1 in case of error.
-+*/
-+
-+ZEXTERN int ZEXPORT gzgetc OF((gzFile file));
-+/*
-+ Reads one byte from the compressed file. gzgetc returns this byte
-+ or -1 in case of end of file or error.
-+*/
-+
-+ZEXTERN int ZEXPORT gzflush OF((gzFile file, int flush));
-+/*
-+ Flushes all pending output into the compressed file. The parameter
-+ flush is as in the deflate() function. The return value is the zlib
-+ error number (see function gzerror below). gzflush returns Z_OK if
-+ the flush parameter is Z_FINISH and all output could be flushed.
-+ gzflush should be called only when strictly necessary because it can
-+ degrade compression.
-+*/
-+
-+ZEXTERN z_off_t ZEXPORT gzseek OF((gzFile file,
-+ z_off_t offset, int whence));
-+/*
-+ Sets the starting position for the next gzread or gzwrite on the
-+ given compressed file. The offset represents a number of bytes in the
-+ uncompressed data stream. The whence parameter is defined as in lseek(2);
-+ the value SEEK_END is not supported.
-+ If the file is opened for reading, this function is emulated but can be
-+ extremely slow. If the file is opened for writing, only forward seeks are
-+ supported; gzseek then compresses a sequence of zeroes up to the new
-+ starting position.
-+
-+ gzseek returns the resulting offset location as measured in bytes from
-+ the beginning of the uncompressed stream, or -1 in case of error, in
-+ particular if the file is opened for writing and the new starting position
-+ would be before the current position.
-+*/
-+
-+ZEXTERN int ZEXPORT gzrewind OF((gzFile file));
-+/*
-+ Rewinds the given file. This function is supported only for reading.
-+
-+ gzrewind(file) is equivalent to (int)gzseek(file, 0L, SEEK_SET)
-+*/
-+
-+ZEXTERN z_off_t ZEXPORT gztell OF((gzFile file));
-+/*
-+ Returns the starting position for the next gzread or gzwrite on the
-+ given compressed file. This position represents a number of bytes in the
-+ uncompressed data stream.
-+
-+ gztell(file) is equivalent to gzseek(file, 0L, SEEK_CUR)
-+*/
-+
-+ZEXTERN int ZEXPORT gzeof OF((gzFile file));
-+/*
-+ Returns 1 when EOF has previously been detected reading the given
-+ input stream, otherwise zero.
-+*/
-+
-+ZEXTERN int ZEXPORT gzclose OF((gzFile file));
-+/*
-+ Flushes all pending output if necessary, closes the compressed file
-+ and deallocates all the (de)compression state. The return value is the zlib
-+ error number (see function gzerror below).
-+*/
-+
-+ZEXTERN const char * ZEXPORT gzerror OF((gzFile file, int *errnum));
-+/*
-+ Returns the error message for the last error which occurred on the
-+ given compressed file. errnum is set to zlib error number. If an
-+ error occurred in the file system and not in the compression library,
-+ errnum is set to Z_ERRNO and the application may consult errno
-+ to get the exact error code.
-+*/
-+
-+ /* checksum functions */
-+
-+/*
-+ These functions are not related to compression but are exported
-+ anyway because they might be useful in applications using the
-+ compression library.
-+*/
-+
-+ZEXTERN uLong ZEXPORT adler32 OF((uLong adler, const Bytef *buf, uInt len));
-+
-+/*
-+ Update a running Adler-32 checksum with the bytes buf[0..len-1] and
-+ return the updated checksum. If buf is NULL, this function returns
-+ the required initial value for the checksum.
-+ An Adler-32 checksum is almost as reliable as a CRC32 but can be computed
-+ much faster. Usage example:
-+
-+ uLong adler = adler32(0L, Z_NULL, 0);
-+
-+ while (read_buffer(buffer, length) != EOF) {
-+ adler = adler32(adler, buffer, length);
-+ }
-+ if (adler != original_adler) error();
-+*/
-+
-+ZEXTERN uLong ZEXPORT crc32 OF((uLong crc, const Bytef *buf, uInt len));
-+/*
-+ Update a running crc with the bytes buf[0..len-1] and return the updated
-+ crc. If buf is NULL, this function returns the required initial value
-+ for the crc. Pre- and post-conditioning (one's complement) is performed
-+ within this function so it shouldn't be done by the application.
-+ Usage example:
-+
-+ uLong crc = crc32(0L, Z_NULL, 0);
-+
-+ while (read_buffer(buffer, length) != EOF) {
-+ crc = crc32(crc, buffer, length);
-+ }
-+ if (crc != original_crc) error();
-+*/
-+
-+
-+ /* various hacks, don't look :) */
-+
-+/* deflateInit and inflateInit are macros to allow checking the zlib version
-+ * and the compiler's view of z_stream:
-+ */
-+ZEXTERN int ZEXPORT deflateInit_ OF((z_streamp strm, int level,
-+ const char *version, int stream_size));
-+ZEXTERN int ZEXPORT inflateInit_ OF((z_streamp strm,
-+ const char *version, int stream_size));
-+ZEXTERN int ZEXPORT deflateInit2_ OF((z_streamp strm, int level, int method,
-+ int windowBits, int memLevel,
-+ int strategy, const char *version,
-+ int stream_size));
-+ZEXTERN int ZEXPORT inflateInit2_ OF((z_streamp strm, int windowBits,
-+ const char *version, int stream_size));
-+#define deflateInit(strm, level) \
-+ deflateInit_((strm), (level), ZLIB_VERSION, sizeof(z_stream))
-+#define inflateInit(strm) \
-+ inflateInit_((strm), ZLIB_VERSION, sizeof(z_stream))
-+#define deflateInit2(strm, level, method, windowBits, memLevel, strategy) \
-+ deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\
-+ (strategy), ZLIB_VERSION, sizeof(z_stream))
-+#define inflateInit2(strm, windowBits) \
-+ inflateInit2_((strm), (windowBits), ZLIB_VERSION, sizeof(z_stream))
-+
-+
-+#if !defined(_Z_UTIL_H) && !defined(NO_DUMMY_DECL)
-+ struct internal_state {int dummy;}; /* hack for buggy compilers */
-+#endif
-+
-+ZEXTERN const char * ZEXPORT zError OF((int err));
-+ZEXTERN int ZEXPORT inflateSyncPoint OF((z_streamp z));
-+ZEXTERN const uLongf * ZEXPORT get_crc_table OF((void));
-+
-+#ifdef __cplusplus
-+}
-+#endif
-+
-+#endif /* _ZLIB_H */
---- /dev/null Tue Mar 11 13:02:56 2003
-+++ linux/include/zlib/zutil.h Mon Feb 9 13:51:03 2004
-@@ -0,0 +1,225 @@
-+/* zutil.h -- internal interface and configuration of the compression library
-+ * Copyright (C) 1995-2002 Jean-loup Gailly.
-+ * For conditions of distribution and use, see copyright notice in zlib.h
-+ */
-+
-+/* WARNING: this file should *not* be used by applications. It is
-+ part of the implementation of the compression library and is
-+ subject to change. Applications should only use zlib.h.
-+ */
-+
-+/* @(#) $Id: zutil.h,v 1.4 2002/04/24 07:36:48 mcr Exp $ */
-+
-+#ifndef _Z_UTIL_H
-+#define _Z_UTIL_H
-+
-+#include "zlib.h"
-+
-+#include <linux/string.h>
-+#define HAVE_MEMCPY
-+
-+#if 0 // #ifdef STDC
-+# include <stddef.h>
-+# include <string.h>
-+# include <stdlib.h>
-+#endif
-+#ifndef __KERNEL__
-+#ifdef NO_ERRNO_H
-+ extern int errno;
-+#else
-+# include <errno.h>
-+#endif
-+#endif
-+
-+#ifndef local
-+# define local static
-+#endif
-+/* compile with -Dlocal if your debugger can't find static symbols */
-+
-+typedef unsigned char uch;
-+typedef uch FAR uchf;
-+typedef unsigned short ush;
-+typedef ush FAR ushf;
-+typedef unsigned long ulg;
-+
-+extern const char *z_errmsg[10]; /* indexed by 2-zlib_error */
-+/* (size given to avoid silly warnings with Visual C++) */
-+
-+#define ERR_MSG(err) z_errmsg[Z_NEED_DICT-(err)]
-+
-+#define ERR_RETURN(strm,err) \
-+ return (strm->msg = ERR_MSG(err), (err))
-+/* To be used only when the state is known to be valid */
-+
-+ /* common constants */
-+
-+#ifndef DEF_WBITS
-+# define DEF_WBITS MAX_WBITS
-+#endif
-+/* default windowBits for decompression. MAX_WBITS is for compression only */
-+
-+#if MAX_MEM_LEVEL >= 8
-+# define DEF_MEM_LEVEL 8
-+#else
-+# define DEF_MEM_LEVEL MAX_MEM_LEVEL
-+#endif
-+/* default memLevel */
-+
-+#define STORED_BLOCK 0
-+#define STATIC_TREES 1
-+#define DYN_TREES 2
-+/* The three kinds of block type */
-+
-+#define MIN_MATCH 3
-+#define MAX_MATCH 258
-+/* The minimum and maximum match lengths */
-+
-+#define PRESET_DICT 0x20 /* preset dictionary flag in zlib header */
-+
-+ /* target dependencies */
-+
-+#ifdef MSDOS
-+# define OS_CODE 0x00
-+# if defined(__TURBOC__) || defined(__BORLANDC__)
-+# if(__STDC__ == 1) && (defined(__LARGE__) || defined(__COMPACT__))
-+ /* Allow compilation with ANSI keywords only enabled */
-+ void _Cdecl farfree( void *block );
-+ void *_Cdecl farmalloc( unsigned long nbytes );
-+# else
-+# include <alloc.h>
-+# endif
-+# else /* MSC or DJGPP */
-+# include <malloc.h>
-+# endif
-+#endif
-+
-+#ifdef OS2
-+# define OS_CODE 0x06
-+#endif
-+
-+#ifdef WIN32 /* Window 95 & Windows NT */
-+# define OS_CODE 0x0b
-+#endif
-+
-+#if defined(VAXC) || defined(VMS)
-+# define OS_CODE 0x02
-+# define F_OPEN(name, mode) \
-+ fopen((name), (mode), "mbc=60", "ctx=stm", "rfm=fix", "mrs=512")
-+#endif
-+
-+#ifdef AMIGA
-+# define OS_CODE 0x01
-+#endif
-+
-+#if defined(ATARI) || defined(atarist)
-+# define OS_CODE 0x05
-+#endif
-+
-+#if defined(MACOS) || defined(TARGET_OS_MAC)
-+# define OS_CODE 0x07
-+# if defined(__MWERKS__) && __dest_os != __be_os && __dest_os != __win32_os
-+# include <unix.h> /* for fdopen */
-+# else
-+# ifndef fdopen
-+# define fdopen(fd,mode) NULL /* No fdopen() */
-+# endif
-+# endif
-+#endif
-+
-+#ifdef __50SERIES /* Prime/PRIMOS */
-+# define OS_CODE 0x0F
-+#endif
-+
-+#ifdef TOPS20
-+# define OS_CODE 0x0a
-+#endif
-+
-+#if defined(_BEOS_) || defined(RISCOS)
-+# define fdopen(fd,mode) NULL /* No fdopen() */
-+#endif
-+
-+#if (defined(_MSC_VER) && (_MSC_VER > 600))
-+# define fdopen(fd,type) _fdopen(fd,type)
-+#endif
-+
-+
-+ /* Common defaults */
-+
-+#ifndef OS_CODE
-+# define OS_CODE 0x03 /* assume Unix */
-+#endif
-+
-+#ifndef F_OPEN
-+# define F_OPEN(name, mode) fopen((name), (mode))
-+#endif
-+
-+ /* functions */
-+
-+#ifdef HAVE_STRERROR
-+ extern char *strerror OF((int));
-+# define zstrerror(errnum) strerror(errnum)
-+#else
-+# define zstrerror(errnum) ""
-+#endif
-+
-+#if defined(pyr)
-+# define NO_MEMCPY
-+#endif
-+#if defined(SMALL_MEDIUM) && !defined(_MSC_VER) && !defined(__SC__)
-+ /* Use our own functions for small and medium model with MSC <= 5.0.
-+ * You may have to use the same strategy for Borland C (untested).
-+ * The __SC__ check is for Symantec.
-+ */
-+# define NO_MEMCPY
-+#endif
-+#if defined(STDC) && !defined(HAVE_MEMCPY) && !defined(NO_MEMCPY)
-+# define HAVE_MEMCPY
-+#endif
-+#ifdef HAVE_MEMCPY
-+# ifdef SMALL_MEDIUM /* MSDOS small or medium model */
-+# define zmemcpy _fmemcpy
-+# define zmemcmp _fmemcmp
-+# define zmemzero(dest, len) _fmemset(dest, 0, len)
-+# else
-+# define zmemcpy memcpy
-+# define zmemcmp memcmp
-+# define zmemzero(dest, len) memset(dest, 0, len)
-+# endif
-+#else
-+ extern void zmemcpy OF((Bytef* dest, const Bytef* source, uInt len));
-+ extern int zmemcmp OF((const Bytef* s1, const Bytef* s2, uInt len));
-+ extern void zmemzero OF((Bytef* dest, uInt len));
-+#endif
-+
-+/* Diagnostic functions */
-+#ifdef DEBUG
-+# include <stdio.h>
-+ extern int z_verbose;
-+ extern void z_error OF((char *m));
-+# define Assert(cond,msg) {if(!(cond)) z_error(msg);}
-+# define Trace(x) {if (z_verbose>=0) fprintf x ;}
-+# define Tracev(x) {if (z_verbose>0) fprintf x ;}
-+# define Tracevv(x) {if (z_verbose>1) fprintf x ;}
-+# define Tracec(c,x) {if (z_verbose>0 && (c)) fprintf x ;}
-+# define Tracecv(c,x) {if (z_verbose>1 && (c)) fprintf x ;}
-+#else
-+# define Assert(cond,msg)
-+# define Trace(x)
-+# define Tracev(x)
-+# define Tracevv(x)
-+# define Tracec(c,x)
-+# define Tracecv(c,x)
-+#endif
-+
-+
-+typedef uLong (ZEXPORT *check_func) OF((uLong check, const Bytef *buf,
-+ uInt len));
-+voidpf zcalloc OF((voidpf opaque, unsigned items, unsigned size));
-+void zcfree OF((voidpf opaque, voidpf ptr));
-+
-+#define ZALLOC(strm, items, size) \
-+ (*((strm)->zalloc))((strm)->opaque, (items), (size))
-+#define ZFREE(strm, addr) (*((strm)->zfree))((strm)->opaque, (voidpf)(addr))
-+#define TRY_FREE(s, p) {if (p) ZFREE(s, p);}
-+
-+#endif /* _Z_UTIL_H */
---- /dev/null Tue Mar 11 13:02:56 2003
-+++ linux/lib/libfreeswan/Makefile.objs Mon Feb 9 13:51:03 2004
-@@ -0,0 +1,21 @@
-+obj-y += satot.o
-+obj-y += addrtot.o
-+obj-y += ultot.o
-+obj-y += addrtypeof.o
-+obj-y += anyaddr.o
-+obj-y += initaddr.o
-+obj-y += ultoa.o
-+obj-y += addrtoa.o
-+obj-y += subnettoa.o
-+obj-y += subnetof.o
-+obj-y += goodmask.o
-+obj-y += datatot.o
-+obj-y += rangetoa.o
-+obj-y += prng.o
-+obj-y += pfkey_v2_parse.o
-+obj-y += pfkey_v2_build.o
-+obj-y += pfkey_v2_debug.o
-+obj-y += pfkey_v2_ext_bits.o
-+
-+#version.c: ${LIBFREESWANDIR}/version.in.c ${OPENSWANSRCDIR}/Makefile.ver
-+# sed '/"/s/xxx/$(IPSECVERSION)/' ${LIBFREESWANDIR}/version.in.c >$@
---- /dev/null Tue Mar 11 13:02:56 2003
-+++ linux/lib/libfreeswan/addrtoa.c Mon Feb 9 13:51:03 2004
-@@ -0,0 +1,67 @@
-+/*
-+ * addresses to ASCII
-+ * Copyright (C) 1998, 1999 Henry Spencer.
-+ *
-+ * This library is free software; you can redistribute it and/or modify it
-+ * under the terms of the GNU Library General Public License as published by
-+ * the Free Software Foundation; either version 2 of the License, or (at your
-+ * option) any later version. See <http://www.fsf.org/copyleft/lgpl.txt>.
-+ *
-+ * This library 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 Library General Public
-+ * License for more details.
-+ *
-+ * RCSID $Id: addrtoa.c,v 1.9 2004/04/11 17:39:25 mcr Exp $
-+ */
-+#include "openswan.h"
-+
-+#define NBYTES 4 /* bytes in an address */
-+#define PERBYTE 4 /* three digits plus a dot or NUL */
-+#define BUFLEN (NBYTES*PERBYTE)
-+
-+#if BUFLEN != ADDRTOA_BUF
-+#error "ADDRTOA_BUF in openswan.h inconsistent with addrtoa() code"
-+#endif
-+
-+/*
-+ - addrtoa - convert binary address to ASCII dotted decimal
-+ */
-+size_t /* space needed for full conversion */
-+addrtoa(addr, format, dst, dstlen)
-+struct in_addr addr;
-+int format; /* character */
-+char *dst; /* need not be valid if dstlen is 0 */
-+size_t dstlen;
-+{
-+ unsigned long a = ntohl(addr.s_addr);
-+ int i;
-+ size_t n;
-+ unsigned long byte;
-+ char buf[BUFLEN];
-+ char *p;
-+
-+ switch (format) {
-+ case 0:
-+ break;
-+ default:
-+ return 0;
-+ break;
-+ }
-+
-+ p = buf;
-+ for (i = NBYTES-1; i >= 0; i--) {
-+ byte = (a >> (i*8)) & 0xff;
-+ p += ultoa(byte, 10, p, PERBYTE);
-+ if (i != 0)
-+ *(p-1) = '.';
-+ }
-+ n = p - buf;
-+
-+ if (dstlen > 0) {
-+ if (n > dstlen)
-+ buf[dstlen - 1] = '\0';
-+ strcpy(dst, buf);
-+ }
-+ return n;
-+}
---- /dev/null Tue Mar 11 13:02:56 2003
-+++ linux/lib/libfreeswan/addrtot.c Mon Feb 9 13:51:03 2004
-@@ -0,0 +1,334 @@
-+/*
-+ * addresses to text
-+ * Copyright (C) 2000 Henry Spencer.
-+ *
-+ * This library is free software; you can redistribute it and/or modify it
-+ * under the terms of the GNU Library General Public License as published by
-+ * the Free Software Foundation; either version 2 of the License, or (at your
-+ * option) any later version. See <http://www.fsf.org/copyleft/lgpl.txt>.
-+ *
-+ * This library 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 Library General Public
-+ * License for more details.
-+ *
-+ * RCSID $Id: addrtot.c,v 1.15 2004/04/11 17:39:25 mcr Exp $
-+ */
-+#include "openswan.h"
-+
-+#define IP4BYTES 4 /* bytes in an IPv4 address */
-+#define PERBYTE 4 /* three digits plus a dot or NUL */
-+#define IP6BYTES 16 /* bytes in an IPv6 address */
-+
-+/* forwards */
-+static size_t normal4(const unsigned char *s, size_t len, char *b, char **dp);
-+static size_t normal6(const unsigned char *s, size_t len, char *b, char **dp, int squish);
-+static size_t reverse4(const unsigned char *s, size_t len, char *b, char **dp);
-+static size_t reverse6(const unsigned char *s, size_t len, char *b, char **dp);
-+
-+/*
-+ - addrtot - convert binary address to text (dotted decimal or IPv6 string)
-+ */
-+size_t /* space needed for full conversion */
-+addrtot(src, format, dst, dstlen)
-+const ip_address *src;
-+int format; /* character */
-+char *dst; /* need not be valid if dstlen is 0 */
-+size_t dstlen;
-+{
-+ const unsigned char *b;
-+ size_t n;
-+ char buf[1+ADDRTOT_BUF+1]; /* :address: */
-+ char *p;
-+ int t = addrtypeof(src);
-+# define TF(t, f) (((t)<<8) | (f))
-+
-+ n = addrbytesptr(src, &b);
-+ if (n == 0) {
-+ bad:
-+ dst[0]='\0';
-+ strncat(dst, "<invalid>", dstlen);
-+ return sizeof("<invalid>");
-+ }
-+
-+ switch (TF(t, format)) {
-+ case TF(AF_INET, 0):
-+ n = normal4(b, n, buf, &p);
-+ break;
-+ case TF(AF_INET6, 0):
-+ n = normal6(b, n, buf, &p, 1);
-+ break;
-+ case TF(AF_INET, 'Q'):
-+ n = normal4(b, n, buf, &p);
-+ break;
-+ case TF(AF_INET6, 'Q'):
-+ n = normal6(b, n, buf, &p, 0);
-+ break;
-+ case TF(AF_INET, 'r'):
-+ n = reverse4(b, n, buf, &p);
-+ break;
-+ case TF(AF_INET6, 'r'):
-+ n = reverse6(b, n, buf, &p);
-+ break;
-+ default: /* including (AF_INET, 'R') */
-+ goto bad;
-+ break;
-+ }
-+
-+ if (dstlen > 0) {
-+ if (dstlen < n)
-+ p[dstlen - 1] = '\0';
-+ strcpy(dst, p);
-+ }
-+ return n;
-+}
-+
-+/*
-+ - normal4 - normal IPv4 address-text conversion
-+ */
-+static size_t /* size of text, including NUL */
-+normal4(srcp, srclen, buf, dstp)
-+const unsigned char *srcp;
-+size_t srclen;
-+char *buf; /* guaranteed large enough */
-+char **dstp; /* where to put result pointer */
-+{
-+ int i;
-+ char *p;
-+
-+ if (srclen != IP4BYTES) /* "can't happen" */
-+ return 0;
-+ p = buf;
-+ for (i = 0; i < IP4BYTES; i++) {
-+ p += ultot(srcp[i], 10, p, PERBYTE);
-+ if (i != IP4BYTES - 1)
-+ *(p-1) = '.'; /* overwrites the NUL */
-+ }
-+ *dstp = buf;
-+ return p - buf;
-+}
-+
-+/*
-+ - normal6 - normal IPv6 address-text conversion
-+ */
-+static size_t /* size of text, including NUL */
-+normal6(srcp, srclen, buf, dstp, squish)
-+const unsigned char *srcp;
-+size_t srclen;
-+char *buf; /* guaranteed large enough, plus 2 */
-+char **dstp; /* where to put result pointer */
-+int squish; /* whether to squish out 0:0 */
-+{
-+ int i;
-+ unsigned long piece;
-+ char *p;
-+ char *q;
-+
-+ if (srclen != IP6BYTES) /* "can't happen" */
-+ return 0;
-+ p = buf;
-+ *p++ = ':';
-+ for (i = 0; i < IP6BYTES/2; i++) {
-+ piece = (srcp[2*i] << 8) + srcp[2*i + 1];
-+ p += ultot(piece, 16, p, 5); /* 5 = abcd + NUL */
-+ *(p-1) = ':'; /* overwrites the NUL */
-+ }
-+ *p = '\0';
-+ q = strstr(buf, ":0:0:");
-+ if (squish && q != NULL) { /* zero squishing is possible */
-+ p = q + 1;
-+ while (*p == '0' && *(p+1) == ':')
-+ p += 2;
-+ q++;
-+ *q++ = ':'; /* overwrite first 0 */
-+ while (*p != '\0')
-+ *q++ = *p++;
-+ *q = '\0';
-+ if (!(*(q-1) == ':' && *(q-2) == ':'))
-+ *--q = '\0'; /* strip final : unless :: */
-+ p = buf;
-+ if (!(*p == ':' && *(p+1) == ':'))
-+ p++; /* skip initial : unless :: */
-+ } else {
-+ q = p;
-+ *--q = '\0'; /* strip final : */
-+ p = buf + 1; /* skip initial : */
-+ }
-+ *dstp = p;
-+ return q - p + 1;
-+}
-+
-+/*
-+ - reverse4 - IPv4 reverse-lookup conversion
-+ */
-+static size_t /* size of text, including NUL */
-+reverse4(srcp, srclen, buf, dstp)
-+const unsigned char *srcp;
-+size_t srclen;
-+char *buf; /* guaranteed large enough */
-+char **dstp; /* where to put result pointer */
-+{
-+ int i;
-+ char *p;
-+
-+ if (srclen != IP4BYTES) /* "can't happen" */
-+ return 0;
-+ p = buf;
-+ for (i = IP4BYTES-1; i >= 0; i--) {
-+ p += ultot(srcp[i], 10, p, PERBYTE);
-+ *(p-1) = '.'; /* overwrites the NUL */
-+ }
-+ strcpy(p, "IN-ADDR.ARPA.");
-+ *dstp = buf;
-+ return strlen(buf) + 1;
-+}
-+
-+/*
-+ - reverse6 - IPv6 reverse-lookup conversion (RFC 1886)
-+ * A trifle inefficient, really shouldn't use ultot...
-+ */
-+static size_t /* size of text, including NUL */
-+reverse6(srcp, srclen, buf, dstp)
-+const unsigned char *srcp;
-+size_t srclen;
-+char *buf; /* guaranteed large enough */
-+char **dstp; /* where to put result pointer */
-+{
-+ int i;
-+ unsigned long piece;
-+ char *p;
-+
-+ if (srclen != IP6BYTES) /* "can't happen" */
-+ return 0;
-+ p = buf;
-+ for (i = IP6BYTES-1; i >= 0; i--) {
-+ piece = srcp[i];
-+ p += ultot(piece&0xf, 16, p, 2);
-+ *(p-1) = '.';
-+ p += ultot(piece>>4, 16, p, 2);
-+ *(p-1) = '.';
-+ }
-+ strcpy(p, "IP6.ARPA.");
-+ *dstp = buf;
-+ return strlen(buf) + 1;
-+}
-+
-+/*
-+ - reverse6 - modern IPv6 reverse-lookup conversion (RFC 2874)
-+ * this version removed as it was obsoleted in the end.
-+ */
-+
-+#ifdef ADDRTOT_MAIN
-+
-+#include <stdio.h>
-+#include <sys/socket.h>
-+#include <netinet/in.h>
-+#include <arpa/inet.h>
-+
-+void regress(void);
-+
-+int
-+main(int argc, char *argv[])
-+{
-+ if (argc < 2) {
-+ fprintf(stderr, "Usage: %s {addr|net/mask|begin...end|-r}\n",
-+ argv[0]);
-+ exit(2);
-+ }
-+
-+ if (strcmp(argv[1], "-r") == 0) {
-+ regress();
-+ fprintf(stderr, "regress() returned?!?\n");
-+ exit(1);
-+ }
-+ exit(0);
-+}
-+
-+struct rtab {
-+ char *input;
-+ char format;
-+ char *output; /* NULL means error expected */
-+} rtab[] = {
-+ {"1.2.3.0", 0, "1.2.3.0"},
-+ {"1:2::3:4", 0, "1:2::3:4"},
-+ {"1:2::3:4", 'Q', "1:2:0:0:0:0:3:4"},
-+ {"1:2:0:0:3:4:0:0", 0, "1:2::3:4:0:0"},
-+ {"1.2.3.4", 'r' , "4.3.2.1.IN-ADDR.ARPA."},
-+ /* 0 1 2 3 4 5 6 7 8 9 a b c d e f 0 1 2 3 4 5 6 7 8 9 a b c d e f */
-+ {"1:2::3:4", 'r', "4.0.0.0.3.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.2.0.0.0.1.0.0.0.IP6.ARPA."},
-+ {NULL, 0, NULL}
-+};
-+
-+void
-+regress()
-+{
-+ struct rtab *r;
-+ int status = 0;
-+ ip_address a;
-+ char in[100];
-+ char buf[100];
-+ const char *oops;
-+ size_t n;
-+
-+ for (r = rtab; r->input != NULL; r++) {
-+ strcpy(in, r->input);
-+
-+ /* convert it *to* internal format */
-+ oops = ttoaddr(in, strlen(in), 0, &a);
-+
-+ /* now convert it back */
-+
-+ n = addrtot(&a, r->format, buf, sizeof(buf));
-+
-+ if (n == 0 && r->output == NULL)
-+ {} /* okay, error expected */
-+
-+ else if (n == 0) {
-+ printf("`%s' atoasr failed\n", r->input);
-+ status = 1;
-+
-+ } else if (r->output == NULL) {
-+ printf("`%s' atoasr succeeded unexpectedly '%c'\n",
-+ r->input, r->format);
-+ status = 1;
-+ } else {
-+ if (strcasecmp(r->output, buf) != 0) {
-+ printf("`%s' '%c' gave `%s', expected `%s'\n",
-+ r->input, r->format, buf, r->output);
-+ status = 1;
-+ }
-+ }
-+ }
-+ exit(status);
-+}
-+
-+#endif /* ADDRTOT_MAIN */
-+
-+/*
-+ * $Log: addrtot.c,v $
-+ * Revision 1.15 2004/04/11 17:39:25 mcr
-+ * removed internal.h requirements.
-+ *
-+ * Revision 1.14 2004/03/08 01:59:08 ken
-+ * freeswan.h -> openswan.h
-+ *
-+ * Revision 1.13 2004/01/05 23:21:05 mcr
-+ * if the address type is invalid, then return length of <invalid>
-+ * string!
-+ *
-+ * Revision 1.12 2003/12/30 06:42:48 mcr
-+ * added $Log: addrtot.c,v $
-+ * added Revision 1.15 2004/04/11 17:39:25 mcr
-+ * added removed internal.h requirements.
-+ * added
-+ * added Revision 1.14 2004/03/08 01:59:08 ken
-+ * added freeswan.h -> openswan.h
-+ * added
-+ * added Revision 1.13 2004/01/05 23:21:05 mcr
-+ * added if the address type is invalid, then return length of <invalid>
-+ * added string!
-+ * added
-+ *
-+ *
-+ */
-+
---- /dev/null Tue Mar 11 13:02:56 2003
-+++ linux/lib/libfreeswan/addrtypeof.c Mon Feb 9 13:51:03 2004
-@@ -0,0 +1,93 @@
-+/*
-+ * extract parts of an ip_address
-+ * Copyright (C) 2000 Henry Spencer.
-+ *
-+ * This library is free software; you can redistribute it and/or modify it
-+ * under the terms of the GNU Library General Public License as published by
-+ * the Free Software Foundation; either version 2 of the License, or (at your
-+ * option) any later version. See <http://www.fsf.org/copyleft/lgpl.txt>.
-+ *
-+ * This library 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 Library General Public
-+ * License for more details.
-+ *
-+ * RCSID $Id: addrtypeof.c,v 1.9 2004/04/11 17:39:25 mcr Exp $
-+ */
-+#include "openswan.h"
-+
-+/*
-+ - addrtypeof - get the type of an ip_address
-+ */
-+int
-+addrtypeof(src)
-+const ip_address *src;
-+{
-+ return src->u.v4.sin_family;
-+}
-+
-+/*
-+ - addrbytesptr - get pointer to the address bytes of an ip_address
-+ */
-+size_t /* 0 for error */
-+addrbytesptr(src, dstp)
-+const ip_address *src;
-+const unsigned char **dstp; /* NULL means just a size query */
-+{
-+ const unsigned char *p;
-+ size_t n;
-+
-+ switch (src->u.v4.sin_family) {
-+ case AF_INET:
-+ p = (const unsigned char *)&src->u.v4.sin_addr.s_addr;
-+ n = 4;
-+ break;
-+ case AF_INET6:
-+ p = (const unsigned char *)&src->u.v6.sin6_addr;
-+ n = 16;
-+ break;
-+ default:
-+ return 0;
-+ break;
-+ }
-+
-+ if (dstp != NULL)
-+ *dstp = p;
-+ return n;
-+}
-+
-+/*
-+ - addrlenof - get length of the address bytes of an ip_address
-+ */
-+size_t /* 0 for error */
-+addrlenof(src)
-+const ip_address *src;
-+{
-+ return addrbytesptr(src, NULL);
-+}
-+
-+/*
-+ - addrbytesof - get the address bytes of an ip_address
-+ */
-+size_t /* 0 for error */
-+addrbytesof(src, dst, dstlen)
-+const ip_address *src;
-+unsigned char *dst;
-+size_t dstlen;
-+{
-+ const unsigned char *p;
-+ size_t n;
-+ size_t ncopy;
-+
-+ n = addrbytesptr(src, &p);
-+ if (n == 0)
-+ return 0;
-+
-+ if (dstlen > 0) {
-+ ncopy = n;
-+ if (ncopy > dstlen)
-+ ncopy = dstlen;
-+ memcpy(dst, p, ncopy);
-+ }
-+ return n;
-+}
---- /dev/null Tue Mar 11 13:02:56 2003
-+++ linux/lib/libfreeswan/anyaddr.c Mon Feb 9 13:51:03 2004
-@@ -0,0 +1,145 @@
-+/*
-+ * special addresses
-+ * Copyright (C) 2000 Henry Spencer.
-+ *
-+ * This library is free software; you can redistribute it and/or modify it
-+ * under the terms of the GNU Library General Public License as published by
-+ * the Free Software Foundation; either version 2 of the License, or (at your
-+ * option) any later version. See <http://www.fsf.org/copyleft/lgpl.txt>.
-+ *
-+ * This library 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 Library General Public
-+ * License for more details.
-+ *
-+ * RCSID $Id: anyaddr.c,v 1.9 2004/04/11 17:39:25 mcr Exp $
-+ */
-+#include "openswan.h"
-+
-+/* these are mostly fallbacks for the no-IPv6-support-in-library case */
-+#ifndef IN6ADDR_ANY_INIT
-+#define IN6ADDR_ANY_INIT {{{ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }}}
-+#endif
-+#ifndef IN6ADDR_LOOPBACK_INIT
-+#define IN6ADDR_LOOPBACK_INIT {{{ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1 }}}
-+#endif
-+
-+static struct in6_addr v6any = IN6ADDR_ANY_INIT;
-+static struct in6_addr v6loop = IN6ADDR_LOOPBACK_INIT;
-+
-+/*
-+ - anyaddr - initialize to the any-address value
-+ */
-+err_t /* NULL for success, else string literal */
-+anyaddr(af, dst)
-+int af; /* address family */
-+ip_address *dst;
-+{
-+ uint32_t v4any = htonl(INADDR_ANY);
-+
-+ switch (af) {
-+ case AF_INET:
-+ return initaddr((unsigned char *)&v4any, sizeof(v4any), af, dst);
-+ break;
-+ case AF_INET6:
-+ return initaddr((unsigned char *)&v6any, sizeof(v6any), af, dst);
-+ break;
-+ default:
-+ return "unknown address family in anyaddr/unspecaddr";
-+ break;
-+ }
-+}
-+
-+/*
-+ - unspecaddr - initialize to the unspecified-address value
-+ */
-+err_t /* NULL for success, else string literal */
-+unspecaddr(af, dst)
-+int af; /* address family */
-+ip_address *dst;
-+{
-+ return anyaddr(af, dst);
-+}
-+
-+/*
-+ - loopbackaddr - initialize to the loopback-address value
-+ */
-+err_t /* NULL for success, else string literal */
-+loopbackaddr(af, dst)
-+int af; /* address family */
-+ip_address *dst;
-+{
-+ uint32_t v4loop = htonl(INADDR_LOOPBACK);
-+
-+ switch (af) {
-+ case AF_INET:
-+ return initaddr((unsigned char *)&v4loop, sizeof(v4loop), af, dst);
-+ break;
-+ case AF_INET6:
-+ return initaddr((unsigned char *)&v6loop, sizeof(v6loop), af, dst);
-+ break;
-+ default:
-+ return "unknown address family in loopbackaddr";
-+ break;
-+ }
-+}
-+
-+/*
-+ - isanyaddr - test for the any-address value
-+ */
-+int
-+isanyaddr(src)
-+const ip_address *src;
-+{
-+ uint32_t v4any = htonl(INADDR_ANY);
-+ int cmp;
-+
-+ switch (src->u.v4.sin_family) {
-+ case AF_INET:
-+ cmp = memcmp(&src->u.v4.sin_addr.s_addr, &v4any, sizeof(v4any));
-+ break;
-+ case AF_INET6:
-+ cmp = memcmp(&src->u.v6.sin6_addr, &v6any, sizeof(v6any));
-+ break;
-+ default:
-+ return 0;
-+ break;
-+ }
-+
-+ return (cmp == 0) ? 1 : 0;
-+}
-+
-+/*
-+ - isunspecaddr - test for the unspecified-address value
-+ */
-+int
-+isunspecaddr(src)
-+const ip_address *src;
-+{
-+ return isanyaddr(src);
-+}
-+
-+/*
-+ - isloopbackaddr - test for the loopback-address value
-+ */
-+int
-+isloopbackaddr(src)
-+const ip_address *src;
-+{
-+ uint32_t v4loop = htonl(INADDR_LOOPBACK);
-+ int cmp;
-+
-+ switch (src->u.v4.sin_family) {
-+ case AF_INET:
-+ cmp = memcmp(&src->u.v4.sin_addr.s_addr, &v4loop, sizeof(v4loop));
-+ break;
-+ case AF_INET6:
-+ cmp = memcmp(&src->u.v6.sin6_addr, &v6loop, sizeof(v6loop));
-+ break;
-+ default:
-+ return 0;
-+ break;
-+ }
-+
-+ return (cmp == 0) ? 1 : 0;
-+}
---- /dev/null Tue Mar 11 13:02:56 2003
-+++ linux/lib/libfreeswan/datatot.c Mon Feb 9 13:51:03 2004
-@@ -0,0 +1,232 @@
-+/*
-+ * convert from binary data (e.g. key) to text form
-+ * Copyright (C) 2000 Henry Spencer.
-+ *
-+ * This library is free software; you can redistribute it and/or modify it
-+ * under the terms of the GNU Library General Public License as published by
-+ * the Free Software Foundation; either version 2 of the License, or (at your
-+ * option) any later version. See <http://www.fsf.org/copyleft/lgpl.txt>.
-+ *
-+ * This library 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 Library General Public
-+ * License for more details.
-+ *
-+ * RCSID $Id: datatot.c,v 1.5 2004/04/11 17:39:25 mcr Exp $
-+ */
-+#include "openswan.h"
-+
-+static void convert(const char *src, size_t nreal, int format, char *out);
-+
-+/*
-+ - datatot - convert data bytes to text
-+ */
-+size_t /* true length (with NUL) for success */
-+datatot(src, srclen, format, dst, dstlen)
-+const char *src;
-+size_t srclen;
-+int format; /* character indicating what format */
-+char *dst; /* need not be valid if dstlen is 0 */
-+size_t dstlen;
-+{
-+ size_t inblocksize; /* process this many bytes at a time */
-+ size_t outblocksize; /* producing this many */
-+ size_t breakevery; /* add a _ every this many (0 means don't) */
-+ size_t sincebreak; /* output bytes since last _ */
-+ char breakchar; /* character used to break between groups */
-+ char inblock[10]; /* enough for any format */
-+ char outblock[10]; /* enough for any format */
-+ char fake[1]; /* fake output area for dstlen == 0 */
-+ size_t needed; /* return value */
-+ char *stop; /* where the terminating NUL will go */
-+ size_t ntodo; /* remaining input */
-+ size_t nreal;
-+ char *out;
-+ char *prefix;
-+
-+ breakevery = 0;
-+ breakchar = '_';
-+
-+ switch (format) {
-+ case 0:
-+ case 'h':
-+ format = 'x';
-+ breakevery = 8;
-+ /* FALLTHROUGH */
-+ case 'x':
-+ inblocksize = 1;
-+ outblocksize = 2;
-+ prefix = "0x";
-+ break;
-+ case ':':
-+ format = 'x';
-+ breakevery = 2;
-+ breakchar = ':';
-+ /* FALLTHROUGH */
-+ case 16:
-+ inblocksize = 1;
-+ outblocksize = 2;
-+ prefix = "";
-+ format = 'x';
-+ break;
-+ case 's':
-+ inblocksize = 3;
-+ outblocksize = 4;
-+ prefix = "0s";
-+ break;
-+ case 64: /* beware, equals ' ' */
-+ inblocksize = 3;
-+ outblocksize = 4;
-+ prefix = "";
-+ format = 's';
-+ break;
-+ default:
-+ return 0;
-+ break;
-+ }
-+ assert(inblocksize < sizeof(inblock));
-+ assert(outblocksize < sizeof(outblock));
-+ assert(breakevery % outblocksize == 0);
-+
-+ if (srclen == 0)
-+ return 0;
-+ ntodo = srclen;
-+
-+ if (dstlen == 0) { /* dispose of awkward special case */
-+ dst = fake;
-+ dstlen = 1;
-+ }
-+ stop = dst + dstlen - 1;
-+
-+ nreal = strlen(prefix);
-+ needed = nreal; /* for starters */
-+ if (dstlen <= nreal) { /* prefix won't fit */
-+ strncpy(dst, prefix, dstlen - 1);
-+ dst += dstlen - 1;
-+ } else {
-+ strcpy(dst, prefix);
-+ dst += nreal;
-+ }
-+ assert(dst <= stop);
-+ sincebreak = 0;
-+
-+ while (ntodo > 0) {
-+ if (ntodo < inblocksize) { /* incomplete input */
-+ memset(inblock, 0, sizeof(inblock));
-+ memcpy(inblock, src, ntodo);
-+ src = inblock;
-+ nreal = ntodo;
-+ ntodo = inblocksize;
-+ } else
-+ nreal = inblocksize;
-+ out = (outblocksize > stop - dst) ? outblock : dst;
-+
-+ convert(src, nreal, format, out);
-+ needed += outblocksize;
-+ sincebreak += outblocksize;
-+ if (dst < stop) {
-+ if (out != dst) {
-+ assert(outblocksize > stop - dst);
-+ memcpy(dst, out, stop - dst);
-+ dst = stop;
-+ } else
-+ dst += outblocksize;
-+ }
-+
-+ src += inblocksize;
-+ ntodo -= inblocksize;
-+ if (breakevery != 0 && sincebreak >= breakevery && ntodo > 0) {
-+ if (dst < stop)
-+ *dst++ = breakchar;
-+ needed++;
-+ sincebreak = 0;
-+ }
-+ }
-+
-+ assert(dst <= stop);
-+ *dst++ = '\0';
-+ needed++;
-+
-+ return needed;
-+}
-+
-+/*
-+ - convert - convert one input block to one output block
-+ */
-+static void
-+convert(src, nreal, format, out)
-+const char *src;
-+size_t nreal; /* how much of the input block is real */
-+int format;
-+char *out;
-+{
-+ static char hex[] = "0123456789abcdef";
-+ static char base64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
-+ "abcdefghijklmnopqrstuvwxyz"
-+ "0123456789+/";
-+ unsigned char c;
-+ unsigned char c1, c2, c3;
-+
-+ assert(nreal > 0);
-+ switch (format) {
-+ case 'x':
-+ assert(nreal == 1);
-+ c = (unsigned char)*src;
-+ *out++ = hex[c >> 4];
-+ *out++ = hex[c & 0xf];
-+ break;
-+ case 's':
-+ c1 = (unsigned char)*src++;
-+ c2 = (unsigned char)*src++;
-+ c3 = (unsigned char)*src++;
-+ *out++ = base64[c1 >> 2]; /* top 6 bits of c1 */
-+ c = (c1 & 0x3) << 4; /* bottom 2 of c1... */
-+ c |= c2 >> 4; /* ...top 4 of c2 */
-+ *out++ = base64[c];
-+ if (nreal == 1)
-+ *out++ = '=';
-+ else {
-+ c = (c2 & 0xf) << 2; /* bottom 4 of c2... */
-+ c |= c3 >> 6; /* ...top 2 of c3 */
-+ *out++ = base64[c];
-+ }
-+ if (nreal <= 2)
-+ *out++ = '=';
-+ else
-+ *out++ = base64[c3 & 0x3f]; /* bottom 6 of c3 */
-+ break;
-+ default:
-+ assert(nreal == 0); /* unknown format */
-+ break;
-+ }
-+}
-+
-+/*
-+ - datatoa - convert data to ASCII
-+ * backward-compatibility synonym for datatot
-+ */
-+size_t /* true length (with NUL) for success */
-+datatoa(src, srclen, format, dst, dstlen)
-+const char *src;
-+size_t srclen;
-+int format; /* character indicating what format */
-+char *dst; /* need not be valid if dstlen is 0 */
-+size_t dstlen;
-+{
-+ return datatot(src, srclen, format, dst, dstlen);
-+}
-+
-+/*
-+ - bytestoa - convert data bytes to ASCII
-+ * backward-compatibility synonym for datatot
-+ */
-+size_t /* true length (with NUL) for success */
-+bytestoa(src, srclen, format, dst, dstlen)
-+const char *src;
-+size_t srclen;
-+int format; /* character indicating what format */
-+char *dst; /* need not be valid if dstlen is 0 */
-+size_t dstlen;
-+{
-+ return datatot(src, srclen, format, dst, dstlen);
-+}
---- /dev/null Tue Mar 11 13:02:56 2003
-+++ linux/lib/libfreeswan/goodmask.c Mon Feb 9 13:51:03 2004
-@@ -0,0 +1,100 @@
-+/*
-+ * minor utilities for subnet-mask manipulation
-+ * Copyright (C) 1998, 1999 Henry Spencer.
-+ *
-+ * This library is free software; you can redistribute it and/or modify it
-+ * under the terms of the GNU Library General Public License as published by
-+ * the Free Software Foundation; either version 2 of the License, or (at your
-+ * option) any later version. See <http://www.fsf.org/copyleft/lgpl.txt>.
-+ *
-+ * This library 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 Library General Public
-+ * License for more details.
-+ *
-+ * RCSID $Id: goodmask.c,v 1.11 2004/04/11 19:43:48 mcr Exp $
-+ */
-+#include "openswan.h"
-+
-+#ifndef ABITS
-+#define ABITS 32 /* bits in an IPv4 address */
-+#endif
-+
-+/*
-+ - goodmask - is this a good (^1*0*$) subnet mask?
-+ * You are not expected to understand this. See Henry S. Warren Jr,
-+ * "Functions realizable with word-parallel logical and two's-complement
-+ * addition instructions", CACM 20.6 (June 1977), p.439.
-+ */
-+int /* predicate */
-+goodmask(mask)
-+struct in_addr mask;
-+{
-+ unsigned long x = ntohl(mask.s_addr);
-+ /* clear rightmost contiguous string of 1-bits */
-+# define CRCS1B(x) (((x|(x-1))+1)&x)
-+# define TOPBIT (1UL << 31)
-+
-+ /* either zero, or has one string of 1-bits which is left-justified */
-+ if (x == 0 || (CRCS1B(x) == 0 && (x&TOPBIT)))
-+ return 1;
-+ return 0;
-+}
-+
-+/*
-+ - masktobits - how many bits in this mask?
-+ * The algorithm is essentially a binary search, but highly optimized
-+ * for this particular task.
-+ */
-+int /* -1 means !goodmask() */
-+masktobits(mask)
-+struct in_addr mask;
-+{
-+ unsigned long m = ntohl(mask.s_addr);
-+ int masklen;
-+
-+ if (!goodmask(mask))
-+ return -1;
-+
-+ if (m&0x00000001UL)
-+ return 32;
-+ masklen = 0;
-+ if (m&(0x0000ffffUL<<1)) { /* <<1 for 1-origin numbering */
-+ masklen |= 0x10;
-+ m <<= 16;
-+ }
-+ if (m&(0x00ff0000UL<<1)) {
-+ masklen |= 0x08;
-+ m <<= 8;
-+ }
-+ if (m&(0x0f000000UL<<1)) {
-+ masklen |= 0x04;
-+ m <<= 4;
-+ }
-+ if (m&(0x30000000UL<<1)) {
-+ masklen |= 0x02;
-+ m <<= 2;
-+ }
-+ if (m&(0x40000000UL<<1))
-+ masklen |= 0x01;
-+
-+ return masklen;
-+}
-+
-+/*
-+ - bitstomask - return a mask with this many high bits on
-+ */
-+struct in_addr
-+bitstomask(n)
-+int n;
-+{
-+ struct in_addr result;
-+
-+ if (n > 0 && n <= ABITS)
-+ result.s_addr = htonl(~((1UL << (ABITS - n)) - 1));
-+ else if (n == 0)
-+ result.s_addr = 0;
-+ else
-+ result.s_addr = 0; /* best error report we can do */
-+ return result;
-+}
---- /dev/null Tue Mar 11 13:02:56 2003
-+++ linux/lib/libfreeswan/initaddr.c Mon Feb 9 13:51:03 2004
-@@ -0,0 +1,50 @@
-+/*
-+ * initialize address structure
-+ * Copyright (C) 2000 Henry Spencer.
-+ *
-+ * This library is free software; you can redistribute it and/or modify it
-+ * under the terms of the GNU Library General Public License as published by
-+ * the Free Software Foundation; either version 2 of the License, or (at your
-+ * option) any later version. See <http://www.fsf.org/copyleft/lgpl.txt>.
-+ *
-+ * This library 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 Library General Public
-+ * License for more details.
-+ *
-+ * RCSID $Id: initaddr.c,v 1.5 2004/04/11 17:39:25 mcr Exp $
-+ */
-+#include "openswan.h"
-+
-+/*
-+ - initaddr - initialize ip_address from bytes
-+ */
-+err_t /* NULL for success, else string literal */
-+initaddr(src, srclen, af, dst)
-+const unsigned char *src;
-+size_t srclen;
-+int af; /* address family */
-+ip_address *dst;
-+{
-+ switch (af) {
-+ case AF_INET:
-+ if (srclen != 4)
-+ return "IPv4 address must be exactly 4 bytes";
-+ dst->u.v4.sin_family = af;
-+ dst->u.v4.sin_port = 0; /* unused */
-+ memcpy((char *)&dst->u.v4.sin_addr.s_addr, src, srclen);
-+ break;
-+ case AF_INET6:
-+ if (srclen != 16)
-+ return "IPv6 address must be exactly 16 bytes";
-+ dst->u.v6.sin6_family = af;
-+ dst->u.v6.sin6_flowinfo = 0; /* unused */
-+ dst->u.v6.sin6_port = 0; /* unused */
-+ memcpy((char *)&dst->u.v6.sin6_addr, src, srclen);
-+ break;
-+ default:
-+ return "unknown address family in initaddr";
-+ break;
-+ }
-+ return NULL;
-+}
---- /dev/null Tue Mar 11 13:02:56 2003
-+++ linux/lib/libfreeswan/pfkey_v2_build.c Mon Feb 9 13:51:03 2004
-@@ -0,0 +1,1559 @@
-+/*
-+ * RFC2367 PF_KEYv2 Key management API message parser
-+ * Copyright (C) 1999, 2000, 2001 Richard Guy Briggs.
-+ *
-+ * 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. See <http://www.fsf.org/copyleft/gpl.txt>.
-+ *
-+ * 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.
-+ *
-+ * RCSID $Id: pfkey_v2_build.c,v 1.49 2004/04/12 02:59:06 mcr Exp $
-+ */
-+
-+/*
-+ * Template from klips/net/ipsec/ipsec/ipsec_parser.c.
-+ */
-+
-+char pfkey_v2_build_c_version[] = "$Id: pfkey_v2_build.c,v 1.49 2004/04/12 02:59:06 mcr Exp $";
-+
-+/*
-+ * Some ugly stuff to allow consistent debugging code for use in the
-+ * kernel and in user space
-+*/
-+
-+#ifdef __KERNEL__
-+
-+# include <linux/kernel.h> /* for printk */
-+
-+# include "openswan/ipsec_kversion.h" /* for malloc switch */
-+# ifdef MALLOC_SLAB
-+# include <linux/slab.h> /* kmalloc() */
-+# else /* MALLOC_SLAB */
-+# include <linux/malloc.h> /* kmalloc() */
-+# endif /* MALLOC_SLAB */
-+# include <linux/errno.h> /* error codes */
-+# include <linux/types.h> /* size_t */
-+# include <linux/interrupt.h> /* mark_bh */
-+
-+# include <linux/netdevice.h> /* struct device, and other headers */
-+# include <linux/etherdevice.h> /* eth_type_trans */
-+# include <linux/ip.h> /* struct iphdr */
-+# if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
-+# include <linux/ipv6.h> /* struct ipv6hdr */
-+# endif /* if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) */
-+
-+# define MALLOC(size) kmalloc(size, GFP_ATOMIC)
-+# define FREE(obj) kfree(obj)
-+# include <openswan.h>
-+#else /* __KERNEL__ */
-+
-+# include <sys/types.h>
-+# include <linux/types.h>
-+# include <linux/errno.h>
-+# include <malloc.h>
-+# include <string.h> /* memset */
-+
-+# include <openswan.h>
-+
-+#endif /* __KERNEL__ */
-+
-+#include <pfkeyv2.h>
-+#include <pfkey.h>
-+
-+#ifdef __KERNEL__
-+#include "openswan/radij.h" /* rd_nodes */
-+#include "openswan/ipsec_encap.h" /* sockaddr_encap */
-+#endif /* __KERNEL__ */
-+
-+
-+#include "openswan/ipsec_sa.h" /* IPSEC_SAREF_NULL, IPSEC_SA_REF_TABLE_IDX_WIDTH */
-+#include "openswan/pfkey_debug.h"
-+
-+
-+#define SENDERR(_x) do { error = -(_x); goto errlab; } while (0)
-+
-+void
-+pfkey_extensions_init(struct sadb_ext *extensions[SADB_EXT_MAX + 1])
-+{
-+ int i;
-+
-+ for (i = 0; i != SADB_EXT_MAX + 1; i++) {
-+ extensions[i] = NULL;
-+ }
-+}
-+
-+void
-+pfkey_extensions_free(struct sadb_ext *extensions[SADB_EXT_MAX + 1])
-+{
-+ int i;
-+
-+ if(!extensions) {
-+ return;
-+ }
-+
-+ if(extensions[0]) {
-+ memset(extensions[0], 0, sizeof(struct sadb_msg));
-+ FREE(extensions[0]);
-+ extensions[0] = NULL;
-+ }
-+
-+ for (i = 1; i != SADB_EXT_MAX + 1; i++) {
-+ if(extensions[i]) {
-+ memset(extensions[i], 0, extensions[i]->sadb_ext_len * IPSEC_PFKEYv2_ALIGN);
-+ FREE(extensions[i]);
-+ extensions[i] = NULL;
-+ }
-+ }
-+}
-+
-+void
-+pfkey_msg_free(struct sadb_msg **pfkey_msg)
-+{
-+ if(*pfkey_msg) {
-+ memset(*pfkey_msg, 0, (*pfkey_msg)->sadb_msg_len * IPSEC_PFKEYv2_ALIGN);
-+ FREE(*pfkey_msg);
-+ *pfkey_msg = NULL;
-+ }
-+}
-+
-+/* Default extension builders taken from the KLIPS code */
-+
-+int
-+pfkey_msg_hdr_build(struct sadb_ext** pfkey_ext,
-+ uint8_t msg_type,
-+ uint8_t satype,
-+ uint8_t msg_errno,
-+ uint32_t seq,
-+ uint32_t pid)
-+{
-+ int error = 0;
-+ struct sadb_msg *pfkey_msg = (struct sadb_msg *)*pfkey_ext;
-+
-+ DEBUGGING(PF_KEY_DEBUG_BUILD,
-+ "pfkey_msg_hdr_build:\n");
-+ DEBUGGING(PF_KEY_DEBUG_BUILD,
-+ "pfkey_msg_hdr_build: "
-+ "on_entry &pfkey_ext=0p%p pfkey_ext=0p%p *pfkey_ext=0p%p.\n",
-+ &pfkey_ext,
-+ pfkey_ext,
-+ *pfkey_ext);
-+ /* sanity checks... */
-+ if(pfkey_msg) {
-+ DEBUGGING(PF_KEY_DEBUG_BUILD,
-+ "pfkey_msg_hdr_build: "
-+ "why is pfkey_msg already pointing to something?\n");
-+ SENDERR(EINVAL);
-+ }
-+
-+ if(!msg_type) {
-+ DEBUGGING(PF_KEY_DEBUG_BUILD,
-+ "pfkey_msg_hdr_build: "
-+ "msg type not set, must be non-zero..\n");
-+ SENDERR(EINVAL);
-+ }
-+
-+ if(msg_type > SADB_MAX) {
-+ DEBUGGING(PF_KEY_DEBUG_BUILD,
-+ "pfkey_msg_hdr_build: "
-+ "msg type too large:%d.\n",
-+ msg_type);
-+ SENDERR(EINVAL);
-+ }
-+
-+ if(satype > SADB_SATYPE_MAX) {
-+ DEBUGGING(PF_KEY_DEBUG_BUILD,
-+ "pfkey_msg_hdr_build: "
-+ "satype %d > max %d\n",
-+ satype, SADB_SATYPE_MAX);
-+ SENDERR(EINVAL);
-+ }
-+
-+ if(!(*pfkey_ext = (struct sadb_ext*)
-+ pfkey_msg = (struct sadb_msg*)
-+ MALLOC(sizeof(struct sadb_msg)))) {
-+ DEBUGGING(PF_KEY_DEBUG_BUILD,
-+ "pfkey_msg_hdr_build: "
-+ "memory allocation failed\n");
-+ SENDERR(ENOMEM);
-+ }
-+ memset(pfkey_msg, 0, sizeof(struct sadb_msg));
-+
-+ pfkey_msg->sadb_msg_len = sizeof(struct sadb_msg) / IPSEC_PFKEYv2_ALIGN;
-+
-+ pfkey_msg->sadb_msg_type = msg_type;
-+ pfkey_msg->sadb_msg_satype = satype;
-+
-+ pfkey_msg->sadb_msg_version = PF_KEY_V2;
-+ pfkey_msg->sadb_msg_errno = msg_errno;
-+ pfkey_msg->sadb_msg_reserved = 0;
-+ pfkey_msg->sadb_msg_seq = seq;
-+ pfkey_msg->sadb_msg_pid = pid;
-+ DEBUGGING(PF_KEY_DEBUG_BUILD,
-+ "pfkey_msg_hdr_build: "
-+ "on_exit &pfkey_ext=0p%p pfkey_ext=0p%p *pfkey_ext=0p%p.\n",
-+ &pfkey_ext,
-+ pfkey_ext,
-+ *pfkey_ext);
-+errlab:
-+ return error;
-+}
-+
-+int
-+pfkey_sa_ref_build(struct sadb_ext ** pfkey_ext,
-+ uint16_t exttype,
-+ uint32_t spi,
-+ uint8_t replay_window,
-+ uint8_t sa_state,
-+ uint8_t auth,
-+ uint8_t encrypt,
-+ uint32_t flags,
-+ uint32_t/*IPsecSAref_t*/ ref)
-+{
-+ int error = 0;
-+ struct sadb_sa *pfkey_sa = (struct sadb_sa *)*pfkey_ext;
-+
-+ DEBUGGING(PF_KEY_DEBUG_BUILD,
-+ "pfkey_sa_build: "
-+ "spi=%08x replay=%d sa_state=%d auth=%d encrypt=%d flags=%d\n",
-+ ntohl(spi), /* in network order */
-+ replay_window,
-+ sa_state,
-+ auth,
-+ encrypt,
-+ flags);
-+ /* sanity checks... */
-+ if(pfkey_sa) {
-+ DEBUGGING(PF_KEY_DEBUG_BUILD,
-+ "pfkey_sa_build: "
-+ "why is pfkey_sa already pointing to something?\n");
-+ SENDERR(EINVAL);
-+ }
-+
-+ if(exttype != SADB_EXT_SA &&
-+ exttype != SADB_X_EXT_SA2) {
-+ DEBUGGING(PF_KEY_DEBUG_BUILD,
-+ "pfkey_sa_build: "
-+ "invalid exttype=%d.\n",
-+ exttype);
-+ SENDERR(EINVAL);
-+ }
-+
-+ if(replay_window > 64) {
-+ DEBUGGING(PF_KEY_DEBUG_BUILD,
-+ "pfkey_sa_build: "
-+ "replay window size: %d -- must be 0 <= size <= 64\n",
-+ replay_window);
-+ SENDERR(EINVAL);
-+ }
-+
-+ if(auth > SADB_AALG_MAX) {
-+ DEBUGGING(PF_KEY_DEBUG_BUILD,
-+ "pfkey_sa_build: "
-+ "auth=%d > SADB_AALG_MAX=%d.\n",
-+ auth,
-+ SADB_AALG_MAX);
-+ SENDERR(EINVAL);
-+ }
-+
-+ if(encrypt > SADB_EALG_MAX) {
-+ DEBUGGING(PF_KEY_DEBUG_BUILD,
-+ "pfkey_sa_build: "
-+ "encrypt=%d > SADB_EALG_MAX=%d.\n",
-+ encrypt,
-+ SADB_EALG_MAX);
-+ SENDERR(EINVAL);
-+ }
-+
-+ if(sa_state > SADB_SASTATE_MAX) {
-+ DEBUGGING(PF_KEY_DEBUG_BUILD,
-+ "pfkey_sa_build: "
-+ "sa_state=%d exceeds MAX=%d.\n",
-+ sa_state,
-+ SADB_SASTATE_MAX);
-+ SENDERR(EINVAL);
-+ }
-+
-+ if(sa_state == SADB_SASTATE_DEAD) {
-+ DEBUGGING(PF_KEY_DEBUG_BUILD,
-+ "pfkey_sa_build: "
-+ "sa_state=%d is DEAD=%d is not allowed.\n",
-+ sa_state,
-+ SADB_SASTATE_DEAD);
-+ SENDERR(EINVAL);
-+ }
-+
-+ if((IPSEC_SAREF_NULL != ref) && (ref >= (1 << IPSEC_SA_REF_TABLE_IDX_WIDTH))) {
-+ DEBUGGING(PF_KEY_DEBUG_BUILD,
-+ "pfkey_sa_build: "
-+ "SAref=%d must be (SAref == IPSEC_SAREF_NULL(%d) || SAref < IPSEC_SA_REF_TABLE_NUM_ENTRIES(%d)).\n",
-+ ref,
-+ IPSEC_SAREF_NULL,
-+ IPSEC_SA_REF_TABLE_NUM_ENTRIES);
-+ SENDERR(EINVAL);
-+ }
-+
-+ if(!(*pfkey_ext = (struct sadb_ext*)
-+ pfkey_sa = (struct sadb_sa*)
-+ MALLOC(sizeof(struct sadb_sa)))) {
-+ DEBUGGING(PF_KEY_DEBUG_BUILD,
-+ "pfkey_sa_build: "
-+ "memory allocation failed\n");
-+ SENDERR(ENOMEM);
-+ }
-+ memset(pfkey_sa, 0, sizeof(struct sadb_sa));
-+
-+ pfkey_sa->sadb_sa_len = sizeof(*pfkey_sa) / IPSEC_PFKEYv2_ALIGN;
-+ pfkey_sa->sadb_sa_exttype = exttype;
-+ pfkey_sa->sadb_sa_spi = spi;
-+ pfkey_sa->sadb_sa_replay = replay_window;
-+ pfkey_sa->sadb_sa_state = sa_state;
-+ pfkey_sa->sadb_sa_auth = auth;
-+ pfkey_sa->sadb_sa_encrypt = encrypt;
-+ pfkey_sa->sadb_sa_flags = flags;
-+ pfkey_sa->sadb_x_sa_ref = ref;
-+
-+errlab:
-+ return error;
-+}
-+
-+int
-+pfkey_sa_build(struct sadb_ext ** pfkey_ext,
-+ uint16_t exttype,
-+ uint32_t spi,
-+ uint8_t replay_window,
-+ uint8_t sa_state,
-+ uint8_t auth,
-+ uint8_t encrypt,
-+ uint32_t flags)
-+{
-+ return pfkey_sa_ref_build(pfkey_ext,
-+ exttype,
-+ spi,
-+ replay_window,
-+ sa_state,
-+ auth,
-+ encrypt,
-+ flags,
-+ IPSEC_SAREF_NULL);
-+}
-+
-+int
-+pfkey_lifetime_build(struct sadb_ext ** pfkey_ext,
-+ uint16_t exttype,
-+ uint32_t allocations,
-+ uint64_t bytes,
-+ uint64_t addtime,
-+ uint64_t usetime,
-+ uint32_t packets)
-+{
-+ int error = 0;
-+ struct sadb_lifetime *pfkey_lifetime = (struct sadb_lifetime *)*pfkey_ext;
-+
-+ DEBUGGING(PF_KEY_DEBUG_BUILD,
-+ "pfkey_lifetime_build:\n");
-+ /* sanity checks... */
-+ if(pfkey_lifetime) {
-+ DEBUGGING(PF_KEY_DEBUG_BUILD,
-+ "pfkey_lifetime_build: "
-+ "why is pfkey_lifetime already pointing to something?\n");
-+ SENDERR(EINVAL);
-+ }
-+
-+ if(exttype != SADB_EXT_LIFETIME_CURRENT &&
-+ exttype != SADB_EXT_LIFETIME_HARD &&
-+ exttype != SADB_EXT_LIFETIME_SOFT) {
-+ DEBUGGING(PF_KEY_DEBUG_BUILD,
-+ "pfkey_lifetime_build: "
-+ "invalid exttype=%d.\n",
-+ exttype);
-+ SENDERR(EINVAL);
-+ }
-+
-+ if(!(*pfkey_ext = (struct sadb_ext*)
-+ pfkey_lifetime = (struct sadb_lifetime*)
-+ MALLOC(sizeof(struct sadb_lifetime)))) {
-+ DEBUGGING(PF_KEY_DEBUG_BUILD,
-+ "pfkey_lifetime_build: "
-+ "memory allocation failed\n");
-+ SENDERR(ENOMEM);
-+ }
-+ memset(pfkey_lifetime, 0, sizeof(struct sadb_lifetime));
-+
-+ pfkey_lifetime->sadb_lifetime_len = sizeof(struct sadb_lifetime) / IPSEC_PFKEYv2_ALIGN;
-+ pfkey_lifetime->sadb_lifetime_exttype = exttype;
-+ pfkey_lifetime->sadb_lifetime_allocations = allocations;
-+ pfkey_lifetime->sadb_lifetime_bytes = bytes;
-+ pfkey_lifetime->sadb_lifetime_addtime = addtime;
-+ pfkey_lifetime->sadb_lifetime_usetime = usetime;
-+ pfkey_lifetime->sadb_x_lifetime_packets = packets;
-+
-+errlab:
-+ return error;
-+}
-+
-+int
-+pfkey_address_build(struct sadb_ext** pfkey_ext,
-+ uint16_t exttype,
-+ uint8_t proto,
-+ uint8_t prefixlen,
-+ struct sockaddr* address)
-+{
-+ int error = 0;
-+ int saddr_len = 0;
-+ char ipaddr_txt[ADDRTOT_BUF + 6/*extra for port number*/];
-+ struct sadb_address *pfkey_address = (struct sadb_address *)*pfkey_ext;
-+
-+ DEBUGGING(PF_KEY_DEBUG_BUILD,
-+ "pfkey_address_build: "
-+ "exttype=%d proto=%d prefixlen=%d\n",
-+ exttype,
-+ proto,
-+ prefixlen);
-+ /* sanity checks... */
-+ if(pfkey_address) {
-+ ERROR("pfkey_address_build: "
-+ "why is pfkey_address already pointing to something?\n");
-+ SENDERR(EINVAL);
-+ }
-+
-+ if (!address) {
-+ ERROR("pfkey_address_build: " "address is NULL\n");
-+ SENDERR(EINVAL);
-+ }
-+
-+ switch(exttype) {
-+ case SADB_EXT_ADDRESS_SRC:
-+ case SADB_EXT_ADDRESS_DST:
-+ case SADB_EXT_ADDRESS_PROXY:
-+ case SADB_X_EXT_ADDRESS_DST2:
-+ case SADB_X_EXT_ADDRESS_SRC_FLOW:
-+ case SADB_X_EXT_ADDRESS_DST_FLOW:
-+ case SADB_X_EXT_ADDRESS_SRC_MASK:
-+ case SADB_X_EXT_ADDRESS_DST_MASK:
-+#ifdef NAT_TRAVERSAL
-+ case SADB_X_EXT_NAT_T_OA:
-+#endif
-+ break;
-+ default:
-+ ERROR("pfkey_address_build: "
-+ "unrecognised ext_type=%d.\n",
-+ exttype);
-+ SENDERR(EINVAL);
-+ }
-+
-+ switch(address->sa_family) {
-+ case AF_INET:
-+ DEBUGGING(PF_KEY_DEBUG_BUILD,
-+ "pfkey_address_build: "
-+ "found address family AF_INET.\n");
-+ saddr_len = sizeof(struct sockaddr_in);
-+ sprintf(ipaddr_txt, "%d.%d.%d.%d:%d"
-+ , (((struct sockaddr_in*)address)->sin_addr.s_addr >> 0) & 0xFF
-+ , (((struct sockaddr_in*)address)->sin_addr.s_addr >> 8) & 0xFF
-+ , (((struct sockaddr_in*)address)->sin_addr.s_addr >> 16) & 0xFF
-+ , (((struct sockaddr_in*)address)->sin_addr.s_addr >> 24) & 0xFF
-+ , ntohs(((struct sockaddr_in*)address)->sin_port));
-+ break;
-+ case AF_INET6:
-+ DEBUGGING(PF_KEY_DEBUG_BUILD,
-+ "pfkey_address_build: "
-+ "found address family AF_INET6.\n");
-+ saddr_len = sizeof(struct sockaddr_in6);
-+ sprintf(ipaddr_txt, "%x:%x:%x:%x:%x:%x:%x:%x-%x"
-+ , ntohs(((struct sockaddr_in6*)address)->sin6_addr.s6_addr16[0])
-+ , ntohs(((struct sockaddr_in6*)address)->sin6_addr.s6_addr16[1])
-+ , ntohs(((struct sockaddr_in6*)address)->sin6_addr.s6_addr16[2])
-+ , ntohs(((struct sockaddr_in6*)address)->sin6_addr.s6_addr16[3])
-+ , ntohs(((struct sockaddr_in6*)address)->sin6_addr.s6_addr16[4])
-+ , ntohs(((struct sockaddr_in6*)address)->sin6_addr.s6_addr16[5])
-+ , ntohs(((struct sockaddr_in6*)address)->sin6_addr.s6_addr16[6])
-+ , ntohs(((struct sockaddr_in6*)address)->sin6_addr.s6_addr16[7])
-+ , ntohs(((struct sockaddr_in6*)address)->sin6_port));
-+ break;
-+ default:
-+ ERROR("pfkey_address_build: "
-+ "address->sa_family=%d not supported.\n",
-+ address->sa_family);
-+ SENDERR(EPFNOSUPPORT);
-+ }
-+
-+ DEBUGGING(PF_KEY_DEBUG_BUILD,
-+ "pfkey_address_build: "
-+ "found address=%s.\n",
-+ ipaddr_txt);
-+ if(prefixlen != 0) {
-+ ERROR("pfkey_address_build: "
-+ "address prefixes not supported yet.\n");
-+ SENDERR(EAFNOSUPPORT); /* not supported yet */
-+ }
-+
-+ /* allocate some memory for the extension */
-+ pfkey_address = (struct sadb_address*)
-+ MALLOC(ALIGN_N(sizeof(struct sadb_address) + saddr_len, IPSEC_PFKEYv2_ALIGN));
-+ *pfkey_ext = (struct sadb_ext*)pfkey_address;
-+
-+ if(pfkey_address == NULL ) {
-+ ERROR("pfkey_lifetime_build: "
-+ "memory allocation failed\n");
-+ SENDERR(ENOMEM);
-+ }
-+ memset(pfkey_address,
-+ 0,
-+ ALIGN_N(sizeof(struct sadb_address) + saddr_len,
-+ IPSEC_PFKEYv2_ALIGN));
-+
-+ pfkey_address->sadb_address_len = DIVUP(sizeof(struct sadb_address) + saddr_len,
-+ IPSEC_PFKEYv2_ALIGN);
-+
-+ pfkey_address->sadb_address_exttype = exttype;
-+ pfkey_address->sadb_address_proto = proto;
-+ pfkey_address->sadb_address_prefixlen = prefixlen;
-+ pfkey_address->sadb_address_reserved = 0;
-+
-+ memcpy((char*)pfkey_address + sizeof(struct sadb_address),
-+ address,
-+ saddr_len);
-+
-+#if 0
-+ for(i = 0; i < sizeof(struct sockaddr_in) - offsetof(struct sockaddr_in, sin_zero); i++) {
-+ pfkey_address_s_ska.sin_zero[i] = 0;
-+ }
-+#endif
-+ DEBUGGING(PF_KEY_DEBUG_BUILD,
-+ "pfkey_address_build: "
-+ "successful created len: %d.\n", pfkey_address->sadb_address_len);
-+
-+ errlab:
-+ return error;
-+}
-+
-+int
-+pfkey_key_build(struct sadb_ext** pfkey_ext,
-+ uint16_t exttype,
-+ uint16_t key_bits,
-+ char* key)
-+{
-+ int error = 0;
-+ struct sadb_key *pfkey_key = (struct sadb_key *)*pfkey_ext;
-+
-+ DEBUGGING(PF_KEY_DEBUG_BUILD,
-+ "pfkey_key_build:\n");
-+ /* sanity checks... */
-+ if(pfkey_key) {
-+ ERROR("pfkey_key_build: "
-+ "why is pfkey_key already pointing to something?\n");
-+ SENDERR(EINVAL);
-+ }
-+
-+ if(!key_bits) {
-+ ERROR("pfkey_key_build: "
-+ "key_bits is zero, it must be non-zero.\n");
-+ SENDERR(EINVAL);
-+ }
-+
-+ if( !((exttype == SADB_EXT_KEY_AUTH) || (exttype == SADB_EXT_KEY_ENCRYPT))) {
-+ ERROR("pfkey_key_build: "
-+ "unsupported extension type=%d.\n",
-+ exttype);
-+ SENDERR(EINVAL);
-+ }
-+
-+ if(!(*pfkey_ext = (struct sadb_ext*)
-+ pfkey_key = (struct sadb_key*)
-+ MALLOC(sizeof(struct sadb_key) +
-+ DIVUP(key_bits, 64) * IPSEC_PFKEYv2_ALIGN))) {
-+ ERROR("pfkey_key_build: "
-+ "memory allocation failed\n");
-+ SENDERR(ENOMEM);
-+ }
-+ memset(pfkey_key,
-+ 0,
-+ sizeof(struct sadb_key) +
-+ DIVUP(key_bits, 64) * IPSEC_PFKEYv2_ALIGN);
-+
-+ pfkey_key->sadb_key_len = DIVUP(sizeof(struct sadb_key) * IPSEC_PFKEYv2_ALIGN + key_bits,
-+ 64);
-+ pfkey_key->sadb_key_exttype = exttype;
-+ pfkey_key->sadb_key_bits = key_bits;
-+ pfkey_key->sadb_key_reserved = 0;
-+ memcpy((char*)pfkey_key + sizeof(struct sadb_key),
-+ key,
-+ DIVUP(key_bits, 8));
-+
-+errlab:
-+ return error;
-+}
-+
-+int
-+pfkey_ident_build(struct sadb_ext** pfkey_ext,
-+ uint16_t exttype,
-+ uint16_t ident_type,
-+ uint64_t ident_id,
-+ uint8_t ident_len,
-+ char* ident_string)
-+{
-+ int error = 0;
-+ struct sadb_ident *pfkey_ident = (struct sadb_ident *)*pfkey_ext;
-+ int data_len = ident_len * IPSEC_PFKEYv2_ALIGN - sizeof(struct sadb_ident);
-+
-+ DEBUGGING(PF_KEY_DEBUG_BUILD,
-+ "pfkey_ident_build:\n");
-+ /* sanity checks... */
-+ if(pfkey_ident) {
-+ ERROR("pfkey_ident_build: "
-+ "why is pfkey_ident already pointing to something?\n");
-+ SENDERR(EINVAL);
-+ }
-+
-+ if( ! ((exttype == SADB_EXT_IDENTITY_SRC) ||
-+ (exttype == SADB_EXT_IDENTITY_DST))) {
-+ ERROR("pfkey_ident_build: "
-+ "unsupported extension type=%d.\n",
-+ exttype);
-+ SENDERR(EINVAL);
-+ }
-+
-+ if((ident_type == SADB_IDENTTYPE_RESERVED)) {
-+ ERROR("pfkey_ident_build: "
-+ "ident_type must be non-zero.\n");
-+ SENDERR(EINVAL);
-+ }
-+
-+ if(ident_type > SADB_IDENTTYPE_MAX) {
-+ ERROR("pfkey_ident_build: "
-+ "identtype=%d out of range.\n",
-+ ident_type);
-+ SENDERR(EINVAL);
-+ }
-+
-+ if(((ident_type == SADB_IDENTTYPE_PREFIX) ||
-+ (ident_type == SADB_IDENTTYPE_FQDN)) &&
-+ !ident_string) {
-+ ERROR("pfkey_ident_build: "
-+ "string required to allocate size of extension.\n");
-+ SENDERR(EINVAL);
-+ }
-+
-+#if 0
-+ if((ident_type == SADB_IDENTTYPE_USERFQDN) ) {
-+ }
-+#endif
-+
-+ if(!(*pfkey_ext = (struct sadb_ext*)
-+ pfkey_ident = (struct sadb_ident*)
-+ MALLOC(ident_len * IPSEC_PFKEYv2_ALIGN))) {
-+ ERROR("pfkey_ident_build: "
-+ "memory allocation failed\n");
-+ SENDERR(ENOMEM);
-+ }
-+ memset(pfkey_ident, 0, ident_len * IPSEC_PFKEYv2_ALIGN);
-+
-+ pfkey_ident->sadb_ident_len = ident_len;
-+ pfkey_ident->sadb_ident_exttype = exttype;
-+ pfkey_ident->sadb_ident_type = ident_type;
-+ pfkey_ident->sadb_ident_reserved = 0;
-+ pfkey_ident->sadb_ident_id = ident_id;
-+ memcpy((char*)pfkey_ident + sizeof(struct sadb_ident),
-+ ident_string,
-+ data_len);
-+
-+errlab:
-+ return error;
-+}
-+
-+int
-+pfkey_sens_build(struct sadb_ext** pfkey_ext,
-+ uint32_t dpd,
-+ uint8_t sens_level,
-+ uint8_t sens_len,
-+ uint64_t* sens_bitmap,
-+ uint8_t integ_level,
-+ uint8_t integ_len,
-+ uint64_t* integ_bitmap)
-+{
-+ int error = 0;
-+ struct sadb_sens *pfkey_sens = (struct sadb_sens *)*pfkey_ext;
-+ int i;
-+ uint64_t* bitmap;
-+
-+ DEBUGGING(PF_KEY_DEBUG_BUILD,
-+ "pfkey_sens_build:\n");
-+ /* sanity checks... */
-+ if(pfkey_sens) {
-+ ERROR("pfkey_sens_build: "
-+ "why is pfkey_sens already pointing to something?\n");
-+ SENDERR(EINVAL);
-+ }
-+
-+ DEBUGGING(PF_KEY_DEBUG_BUILD,
-+ "pfkey_sens_build: "
-+ "Sorry, I can't build exttype=%d yet.\n",
-+ (*pfkey_ext)->sadb_ext_type);
-+ SENDERR(EINVAL); /* don't process these yet */
-+
-+ if(!(*pfkey_ext = (struct sadb_ext*)
-+ pfkey_sens = (struct sadb_sens*)
-+ MALLOC(sizeof(struct sadb_sens) +
-+ (sens_len + integ_len) * sizeof(uint64_t)))) {
-+ ERROR("pfkey_sens_build: "
-+ "memory allocation failed\n");
-+ SENDERR(ENOMEM);
-+ }
-+ memset(pfkey_sens,
-+ 0,
-+ sizeof(struct sadb_sens) +
-+ (sens_len + integ_len) * sizeof(uint64_t));
-+
-+ pfkey_sens->sadb_sens_len = (sizeof(struct sadb_sens) +
-+ (sens_len + integ_len) * sizeof(uint64_t)) / IPSEC_PFKEYv2_ALIGN;
-+ pfkey_sens->sadb_sens_exttype = SADB_EXT_SENSITIVITY;
-+ pfkey_sens->sadb_sens_dpd = dpd;
-+ pfkey_sens->sadb_sens_sens_level = sens_level;
-+ pfkey_sens->sadb_sens_sens_len = sens_len;
-+ pfkey_sens->sadb_sens_integ_level = integ_level;
-+ pfkey_sens->sadb_sens_integ_len = integ_len;
-+ pfkey_sens->sadb_sens_reserved = 0;
-+
-+ bitmap = (uint64_t*)((char*)pfkey_ext + sizeof(struct sadb_sens));
-+ for(i = 0; i < sens_len; i++) {
-+ *bitmap = sens_bitmap[i];
-+ bitmap++;
-+ }
-+ for(i = 0; i < integ_len; i++) {
-+ *bitmap = integ_bitmap[i];
-+ bitmap++;
-+ }
-+
-+errlab:
-+ return error;
-+}
-+
-+int
-+pfkey_prop_build(struct sadb_ext** pfkey_ext,
-+ uint8_t replay,
-+ unsigned int comb_num,
-+ struct sadb_comb* comb)
-+{
-+ int error = 0;
-+ int i;
-+ struct sadb_prop *pfkey_prop = (struct sadb_prop *)*pfkey_ext;
-+ struct sadb_comb *combp;
-+
-+ DEBUGGING(PF_KEY_DEBUG_BUILD,
-+ "pfkey_prop_build:\n");
-+ /* sanity checks... */
-+ if(pfkey_prop) {
-+ ERROR("pfkey_prop_build: "
-+ "why is pfkey_prop already pointing to something?\n");
-+ SENDERR(EINVAL);
-+ }
-+
-+ if(!(*pfkey_ext = (struct sadb_ext*)
-+ pfkey_prop = (struct sadb_prop*)
-+ MALLOC(sizeof(struct sadb_prop) +
-+ comb_num * sizeof(struct sadb_comb)))) {
-+ ERROR("pfkey_prop_build: "
-+ "memory allocation failed\n");
-+ SENDERR(ENOMEM);
-+ }
-+ memset(pfkey_prop,
-+ 0,
-+ sizeof(struct sadb_prop) +
-+ comb_num * sizeof(struct sadb_comb));
-+
-+ pfkey_prop->sadb_prop_len = (sizeof(struct sadb_prop) +
-+ comb_num * sizeof(struct sadb_comb)) / IPSEC_PFKEYv2_ALIGN;
-+
-+ pfkey_prop->sadb_prop_exttype = SADB_EXT_PROPOSAL;
-+ pfkey_prop->sadb_prop_replay = replay;
-+
-+ for(i=0; i<3; i++) {
-+ pfkey_prop->sadb_prop_reserved[i] = 0;
-+ }
-+
-+ combp = (struct sadb_comb*)((char*)*pfkey_ext + sizeof(struct sadb_prop));
-+ for(i = 0; i < comb_num; i++) {
-+ memcpy (combp, &(comb[i]), sizeof(struct sadb_comb));
-+ combp++;
-+ }
-+
-+#if 0
-+ uint8_t sadb_comb_auth;
-+ uint8_t sadb_comb_encrypt;
-+ uint16_t sadb_comb_flags;
-+ uint16_t sadb_comb_auth_minbits;
-+ uint16_t sadb_comb_auth_maxbits;
-+ uint16_t sadb_comb_encrypt_minbits;
-+ uint16_t sadb_comb_encrypt_maxbits;
-+ uint32_t sadb_comb_reserved;
-+ uint32_t sadb_comb_soft_allocations;
-+ uint32_t sadb_comb_hard_allocations;
-+ uint64_t sadb_comb_soft_bytes;
-+ uint64_t sadb_comb_hard_bytes;
-+ uint64_t sadb_comb_soft_addtime;
-+ uint64_t sadb_comb_hard_addtime;
-+ uint64_t sadb_comb_soft_usetime;
-+ uint64_t sadb_comb_hard_usetime;
-+ uint32_t sadb_comb_soft_packets;
-+ uint32_t sadb_comb_hard_packets;
-+#endif
-+errlab:
-+ return error;
-+}
-+
-+int
-+pfkey_supported_build(struct sadb_ext** pfkey_ext,
-+ uint16_t exttype,
-+ unsigned int alg_num,
-+ struct sadb_alg* alg)
-+{
-+ int error = 0;
-+ unsigned int i;
-+ struct sadb_supported *pfkey_supported = (struct sadb_supported *)*pfkey_ext;
-+ struct sadb_alg *pfkey_alg;
-+
-+ /* sanity checks... */
-+ if(pfkey_supported) {
-+ DEBUGGING(PF_KEY_DEBUG_BUILD,
-+ "pfkey_supported_build: "
-+ "why is pfkey_supported already pointing to something?\n");
-+ SENDERR(EINVAL);
-+ }
-+
-+ if( !((exttype == SADB_EXT_SUPPORTED_AUTH) || (exttype == SADB_EXT_SUPPORTED_ENCRYPT))) {
-+ DEBUGGING(PF_KEY_DEBUG_BUILD,
-+ "pfkey_supported_build: "
-+ "unsupported extension type=%d.\n",
-+ exttype);
-+ SENDERR(EINVAL);
-+ }
-+
-+ if(!(*pfkey_ext = (struct sadb_ext*)
-+ pfkey_supported = (struct sadb_supported*)
-+ MALLOC(sizeof(struct sadb_supported) +
-+ alg_num *
-+ sizeof(struct sadb_alg)))) {
-+ DEBUGGING(PF_KEY_DEBUG_BUILD,
-+ "pfkey_supported_build: "
-+ "memory allocation failed\n");
-+ SENDERR(ENOMEM);
-+ }
-+ memset(pfkey_supported,
-+ 0,
-+ sizeof(struct sadb_supported) +
-+ alg_num *
-+ sizeof(struct sadb_alg));
-+
-+ pfkey_supported->sadb_supported_len = (sizeof(struct sadb_supported) +
-+ alg_num *
-+ sizeof(struct sadb_alg)) /
-+ IPSEC_PFKEYv2_ALIGN;
-+ pfkey_supported->sadb_supported_exttype = exttype;
-+ pfkey_supported->sadb_supported_reserved = 0;
-+
-+ pfkey_alg = (struct sadb_alg*)((char*)pfkey_supported + sizeof(struct sadb_supported));
-+ for(i = 0; i < alg_num; i++) {
-+ memcpy (pfkey_alg, &(alg[i]), sizeof(struct sadb_alg));
-+ pfkey_alg->sadb_alg_reserved = 0;
-+ pfkey_alg++;
-+ }
-+
-+#if 0
-+ DEBUGGING(PF_KEY_DEBUG_BUILD,
-+ "pfkey_supported_build: "
-+ "Sorry, I can't build exttype=%d yet.\n",
-+ (*pfkey_ext)->sadb_ext_type);
-+ SENDERR(EINVAL); /* don't process these yet */
-+
-+ uint8_t sadb_alg_id;
-+ uint8_t sadb_alg_ivlen;
-+ uint16_t sadb_alg_minbits;
-+ uint16_t sadb_alg_maxbits;
-+ uint16_t sadb_alg_reserved;
-+#endif
-+errlab:
-+ return error;
-+}
-+
-+int
-+pfkey_spirange_build(struct sadb_ext** pfkey_ext,
-+ uint16_t exttype,
-+ uint32_t min, /* in network order */
-+ uint32_t max) /* in network order */
-+{
-+ int error = 0;
-+ struct sadb_spirange *pfkey_spirange = (struct sadb_spirange *)*pfkey_ext;
-+
-+ /* sanity checks... */
-+ if(pfkey_spirange) {
-+ DEBUGGING(PF_KEY_DEBUG_BUILD,
-+ "pfkey_spirange_build: "
-+ "why is pfkey_spirange already pointing to something?\n");
-+ SENDERR(EINVAL);
-+ }
-+
-+ if(ntohl(max) < ntohl(min)) {
-+ DEBUGGING(PF_KEY_DEBUG_BUILD,
-+ "pfkey_spirange_build: "
-+ "minspi=%08x must be < maxspi=%08x.\n",
-+ ntohl(min),
-+ ntohl(max));
-+ SENDERR(EINVAL);
-+ }
-+
-+ if(ntohl(min) <= 255) {
-+ DEBUGGING(PF_KEY_DEBUG_BUILD,
-+ "pfkey_spirange_build: "
-+ "minspi=%08x must be > 255.\n",
-+ ntohl(min));
-+ SENDERR(EEXIST);
-+ }
-+
-+ if(!(*pfkey_ext = (struct sadb_ext*)
-+ pfkey_spirange = (struct sadb_spirange*)
-+ MALLOC(sizeof(struct sadb_spirange)))) {
-+ DEBUGGING(PF_KEY_DEBUG_BUILD,
-+ "pfkey_spirange_build: "
-+ "memory allocation failed\n");
-+ SENDERR(ENOMEM);
-+ }
-+ memset(pfkey_spirange,
-+ 0,
-+ sizeof(struct sadb_spirange));
-+
-+ pfkey_spirange->sadb_spirange_len = sizeof(struct sadb_spirange) / IPSEC_PFKEYv2_ALIGN;
-+
-+ pfkey_spirange->sadb_spirange_exttype = SADB_EXT_SPIRANGE;
-+ pfkey_spirange->sadb_spirange_min = min;
-+ pfkey_spirange->sadb_spirange_max = max;
-+ pfkey_spirange->sadb_spirange_reserved = 0;
-+ errlab:
-+ return error;
-+}
-+
-+int
-+pfkey_x_kmprivate_build(struct sadb_ext** pfkey_ext)
-+{
-+ int error = 0;
-+ struct sadb_x_kmprivate *pfkey_x_kmprivate = (struct sadb_x_kmprivate *)*pfkey_ext;
-+
-+ /* sanity checks... */
-+ if(pfkey_x_kmprivate) {
-+ DEBUGGING(PF_KEY_DEBUG_BUILD,
-+ "pfkey_x_kmprivate_build: "
-+ "why is pfkey_x_kmprivate already pointing to something?\n");
-+ SENDERR(EINVAL);
-+ }
-+
-+ pfkey_x_kmprivate->sadb_x_kmprivate_reserved = 0;
-+
-+ DEBUGGING(PF_KEY_DEBUG_BUILD,
-+ "pfkey_x_kmprivate_build: "
-+ "Sorry, I can't build exttype=%d yet.\n",
-+ (*pfkey_ext)->sadb_ext_type);
-+ SENDERR(EINVAL); /* don't process these yet */
-+
-+ if(!(*pfkey_ext = (struct sadb_ext*)
-+ pfkey_x_kmprivate = (struct sadb_x_kmprivate*)
-+ MALLOC(sizeof(struct sadb_x_kmprivate)))) {
-+ DEBUGGING(PF_KEY_DEBUG_BUILD,
-+ "pfkey_x_kmprivate_build: "
-+ "memory allocation failed\n");
-+ SENDERR(ENOMEM);
-+ }
-+ memset(pfkey_x_kmprivate,
-+ 0,
-+ sizeof(struct sadb_x_kmprivate));
-+
-+ pfkey_x_kmprivate->sadb_x_kmprivate_len =
-+ sizeof(struct sadb_x_kmprivate) / IPSEC_PFKEYv2_ALIGN;
-+
-+ pfkey_x_kmprivate->sadb_x_kmprivate_exttype = SADB_X_EXT_KMPRIVATE;
-+ pfkey_x_kmprivate->sadb_x_kmprivate_reserved = 0;
-+errlab:
-+ return error;
-+}
-+
-+int
-+pfkey_x_satype_build(struct sadb_ext** pfkey_ext,
-+ uint8_t satype)
-+{
-+ int error = 0;
-+ int i;
-+ struct sadb_x_satype *pfkey_x_satype = (struct sadb_x_satype *)*pfkey_ext;
-+
-+ DEBUGGING(PF_KEY_DEBUG_BUILD,
-+ "pfkey_x_satype_build:\n");
-+ /* sanity checks... */
-+ if(pfkey_x_satype) {
-+ ERROR("pfkey_x_satype_build: "
-+ "why is pfkey_x_satype already pointing to something?\n");
-+ SENDERR(EINVAL);
-+ }
-+
-+ if(!satype) {
-+ ERROR("pfkey_x_satype_build: "
-+ "SA type not set, must be non-zero.\n");
-+ SENDERR(EINVAL);
-+ }
-+
-+ if(satype > SADB_SATYPE_MAX) {
-+ ERROR("pfkey_x_satype_build: "
-+ "satype %d > max %d\n",
-+ satype, SADB_SATYPE_MAX);
-+ SENDERR(EINVAL);
-+ }
-+
-+ if(!(*pfkey_ext = (struct sadb_ext*)pfkey_x_satype = (struct sadb_x_satype*)
-+ MALLOC(sizeof(struct sadb_x_satype)))) {
-+ ERROR("pfkey_x_satype_build: "
-+ "memory allocation failed\n");
-+ SENDERR(ENOMEM);
-+ }
-+ memset(pfkey_x_satype,
-+ 0,
-+ sizeof(struct sadb_x_satype));
-+
-+ pfkey_x_satype->sadb_x_satype_len = sizeof(struct sadb_x_satype) / IPSEC_PFKEYv2_ALIGN;
-+
-+ pfkey_x_satype->sadb_x_satype_exttype = SADB_X_EXT_SATYPE2;
-+ pfkey_x_satype->sadb_x_satype_satype = satype;
-+ for(i=0; i<3; i++) {
-+ pfkey_x_satype->sadb_x_satype_reserved[i] = 0;
-+ }
-+
-+errlab:
-+ return error;
-+}
-+
-+int
-+pfkey_x_debug_build(struct sadb_ext** pfkey_ext,
-+ uint32_t tunnel,
-+ uint32_t netlink,
-+ uint32_t xform,
-+ uint32_t eroute,
-+ uint32_t spi,
-+ uint32_t radij,
-+ uint32_t esp,
-+ uint32_t ah,
-+ uint32_t rcv,
-+ uint32_t pfkey,
-+ uint32_t ipcomp,
-+ uint32_t verbose)
-+{
-+ int error = 0;
-+ int i;
-+ struct sadb_x_debug *pfkey_x_debug = (struct sadb_x_debug *)*pfkey_ext;
-+
-+ DEBUGGING(PF_KEY_DEBUG_BUILD,
-+ "pfkey_x_debug_build:\n");
-+ /* sanity checks... */
-+ if(pfkey_x_debug) {
-+ ERROR("pfkey_x_debug_build: "
-+ "why is pfkey_x_debug already pointing to something?\n");
-+ SENDERR(EINVAL);
-+ }
-+
-+ DEBUGGING(PF_KEY_DEBUG_BUILD,
-+ "pfkey_x_debug_build: "
-+ "tunnel=%x netlink=%x xform=%x eroute=%x spi=%x radij=%x esp=%x ah=%x rcv=%x pfkey=%x ipcomp=%x verbose=%x?\n",
-+ tunnel, netlink, xform, eroute, spi, radij, esp, ah, rcv, pfkey, ipcomp, verbose);
-+
-+ if(!(*pfkey_ext = (struct sadb_ext*)pfkey_x_debug = (struct sadb_x_debug*)
-+ MALLOC(sizeof(struct sadb_x_debug)))) {
-+ ERROR("pfkey_x_debug_build: "
-+ "memory allocation failed\n");
-+ SENDERR(ENOMEM);
-+ }
-+#if 0
-+ memset(pfkey_x_debug,
-+ 0,
-+ sizeof(struct sadb_x_debug));
-+#endif
-+
-+ pfkey_x_debug->sadb_x_debug_len = sizeof(struct sadb_x_debug) / IPSEC_PFKEYv2_ALIGN;
-+ pfkey_x_debug->sadb_x_debug_exttype = SADB_X_EXT_DEBUG;
-+
-+ pfkey_x_debug->sadb_x_debug_tunnel = tunnel;
-+ pfkey_x_debug->sadb_x_debug_netlink = netlink;
-+ pfkey_x_debug->sadb_x_debug_xform = xform;
-+ pfkey_x_debug->sadb_x_debug_eroute = eroute;
-+ pfkey_x_debug->sadb_x_debug_spi = spi;
-+ pfkey_x_debug->sadb_x_debug_radij = radij;
-+ pfkey_x_debug->sadb_x_debug_esp = esp;
-+ pfkey_x_debug->sadb_x_debug_ah = ah;
-+ pfkey_x_debug->sadb_x_debug_rcv = rcv;
-+ pfkey_x_debug->sadb_x_debug_pfkey = pfkey;
-+ pfkey_x_debug->sadb_x_debug_ipcomp = ipcomp;
-+ pfkey_x_debug->sadb_x_debug_verbose = verbose;
-+
-+ for(i=0; i<4; i++) {
-+ pfkey_x_debug->sadb_x_debug_reserved[i] = 0;
-+ }
-+
-+errlab:
-+ return error;
-+}
-+
-+int
-+pfkey_x_nat_t_type_build(struct sadb_ext** pfkey_ext,
-+ uint8_t type)
-+{
-+ int error = 0;
-+ int i;
-+ struct sadb_x_nat_t_type *pfkey_x_nat_t_type = (struct sadb_x_nat_t_type *)*pfkey_ext;
-+
-+ DEBUGGING(PF_KEY_DEBUG_BUILD,
-+ "pfkey_x_nat_t_type_build:\n");
-+ /* sanity checks... */
-+ if(pfkey_x_nat_t_type) {
-+ DEBUGGING(PF_KEY_DEBUG_BUILD,
-+ "pfkey_x_nat_t_type_build: "
-+ "why is pfkey_x_nat_t_type already pointing to something?\n");
-+ SENDERR(EINVAL);
-+ }
-+
-+ DEBUGGING(PF_KEY_DEBUG_BUILD,
-+ "pfkey_x_nat_t_type_build: "
-+ "type=%d\n", type);
-+
-+ if(!(*pfkey_ext = (struct sadb_ext*)pfkey_x_nat_t_type = (struct sadb_x_nat_t_type*)
-+ MALLOC(sizeof(struct sadb_x_nat_t_type)))) {
-+ DEBUGGING(PF_KEY_DEBUG_BUILD,
-+ "pfkey_x_nat_t_type_build: "
-+ "memory allocation failed\n");
-+ SENDERR(ENOMEM);
-+ }
-+
-+ pfkey_x_nat_t_type->sadb_x_nat_t_type_len = sizeof(struct sadb_x_nat_t_type) / IPSEC_PFKEYv2_ALIGN;
-+ pfkey_x_nat_t_type->sadb_x_nat_t_type_exttype = SADB_X_EXT_NAT_T_TYPE;
-+ pfkey_x_nat_t_type->sadb_x_nat_t_type_type = type;
-+ for(i=0; i<3; i++) {
-+ pfkey_x_nat_t_type->sadb_x_nat_t_type_reserved[i] = 0;
-+ }
-+
-+errlab:
-+ return error;
-+}
-+int
-+pfkey_x_nat_t_port_build(struct sadb_ext** pfkey_ext,
-+ uint16_t exttype,
-+ uint16_t port)
-+{
-+ int error = 0;
-+ struct sadb_x_nat_t_port *pfkey_x_nat_t_port = (struct sadb_x_nat_t_port *)*pfkey_ext;
-+
-+ DEBUGGING(PF_KEY_DEBUG_BUILD,
-+ "pfkey_x_nat_t_port_build:\n");
-+ /* sanity checks... */
-+ if(pfkey_x_nat_t_port) {
-+ DEBUGGING(PF_KEY_DEBUG_BUILD,
-+ "pfkey_x_nat_t_port_build: "
-+ "why is pfkey_x_nat_t_port already pointing to something?\n");
-+ SENDERR(EINVAL);
-+ }
-+
-+ switch(exttype) {
-+ case SADB_X_EXT_NAT_T_SPORT:
-+ case SADB_X_EXT_NAT_T_DPORT:
-+ break;
-+ default:
-+ DEBUGGING(PF_KEY_DEBUG_BUILD,
-+ "pfkey_nat_t_port_build: "
-+ "unrecognised ext_type=%d.\n",
-+ exttype);
-+ SENDERR(EINVAL);
-+ }
-+
-+ DEBUGGING(PF_KEY_DEBUG_BUILD,
-+ "pfkey_x_nat_t_port_build: "
-+ "ext=%d, port=%d\n", exttype, port);
-+
-+ if(!(*pfkey_ext = (struct sadb_ext*)pfkey_x_nat_t_port = (struct sadb_x_nat_t_port*)
-+ MALLOC(sizeof(struct sadb_x_nat_t_port)))) {
-+ DEBUGGING(PF_KEY_DEBUG_BUILD,
-+ "pfkey_x_nat_t_port_build: "
-+ "memory allocation failed\n");
-+ SENDERR(ENOMEM);
-+ }
-+
-+ pfkey_x_nat_t_port->sadb_x_nat_t_port_len = sizeof(struct sadb_x_nat_t_port) / IPSEC_PFKEYv2_ALIGN;
-+ pfkey_x_nat_t_port->sadb_x_nat_t_port_exttype = exttype;
-+ pfkey_x_nat_t_port->sadb_x_nat_t_port_port = port;
-+ pfkey_x_nat_t_port->sadb_x_nat_t_port_reserved = 0;
-+
-+errlab:
-+ return error;
-+}
-+
-+int pfkey_x_protocol_build(struct sadb_ext **pfkey_ext,
-+ uint8_t protocol)
-+{
-+ int error = 0;
-+ struct sadb_protocol * p = (struct sadb_protocol *)*pfkey_ext;
-+ DEBUGGING(PF_KEY_DEBUG_BUILD,"pfkey_x_protocol_build: protocol=%u\n", protocol);
-+ /* sanity checks... */
-+ if (p != 0) {
-+ ERROR("pfkey_x_protocol_build: bogus protocol pointer\n");
-+ SENDERR(EINVAL);
-+ }
-+ if ((p = (struct sadb_protocol*)MALLOC(sizeof(*p))) == 0) {
-+ ERROR("pfkey_build: memory allocation failed\n");
-+ SENDERR(ENOMEM);
-+ }
-+ *pfkey_ext = (struct sadb_ext *)p;
-+ p->sadb_protocol_len = sizeof(*p) / sizeof(uint64_t);
-+ p->sadb_protocol_exttype = SADB_X_EXT_PROTOCOL;
-+ p->sadb_protocol_proto = protocol;
-+ p->sadb_protocol_flags = 0;
-+ p->sadb_protocol_reserved2 = 0;
-+ errlab:
-+ return error;
-+}
-+
-+
-+#if I_DONT_THINK_THIS_WILL_BE_USEFUL
-+int (*ext_default_builders[SADB_EXT_MAX +1])(struct sadb_msg*, struct sadb_ext*)
-+ =
-+{
-+ NULL, /* pfkey_msg_build, */
-+ pfkey_sa_build,
-+ pfkey_lifetime_build,
-+ pfkey_lifetime_build,
-+ pfkey_lifetime_build,
-+ pfkey_address_build,
-+ pfkey_address_build,
-+ pfkey_address_build,
-+ pfkey_key_build,
-+ pfkey_key_build,
-+ pfkey_ident_build,
-+ pfkey_ident_build,
-+ pfkey_sens_build,
-+ pfkey_prop_build,
-+ pfkey_supported_build,
-+ pfkey_supported_build,
-+ pfkey_spirange_build,
-+ pfkey_x_kmprivate_build,
-+ pfkey_x_satype_build,
-+ pfkey_sa_build,
-+ pfkey_address_build,
-+ pfkey_address_build,
-+ pfkey_address_build,
-+ pfkey_address_build,
-+ pfkey_address_build,
-+ pfkey_x_ext_debug_build
-+};
-+#endif
-+
-+int
-+pfkey_msg_build(struct sadb_msg **pfkey_msg, struct sadb_ext *extensions[], int dir)
-+{
-+ int error = 0;
-+ unsigned ext;
-+ unsigned total_size;
-+ struct sadb_ext *pfkey_ext;
-+ int extensions_seen = 0;
-+#ifndef __KERNEL__
-+ struct sadb_ext *extensions_check[SADB_EXT_MAX + 1];
-+#endif
-+
-+ if(!extensions[0]) {
-+ ERROR("pfkey_msg_build: "
-+ "extensions[0] must be specified (struct sadb_msg).\n");
-+ SENDERR(EINVAL);
-+ }
-+
-+ /* figure out the total size for all the requested extensions */
-+ total_size = IPSEC_PFKEYv2_WORDS(sizeof(struct sadb_msg));
-+ for(ext = 1; ext <= SADB_EXT_MAX; ext++) {
-+ if(extensions[ext]) {
-+ total_size += (extensions[ext])->sadb_ext_len;
-+ }
-+ }
-+
-+ /* allocate that much space */
-+ *pfkey_msg = (struct sadb_msg*)MALLOC(total_size * IPSEC_PFKEYv2_ALIGN);
-+ if(*pfkey_msg == NULL) {
-+ ERROR("pfkey_msg_build: "
-+ "memory allocation failed\n");
-+ SENDERR(ENOMEM);
-+ }
-+
-+ DEBUGGING(PF_KEY_DEBUG_BUILD,
-+ "pfkey_msg_build: "
-+ "pfkey_msg=0p%p allocated %lu bytes, &(extensions[0])=0p%p\n",
-+ *pfkey_msg,
-+ (unsigned long)(total_size * IPSEC_PFKEYv2_ALIGN),
-+ &(extensions[0]));
-+
-+ memcpy(*pfkey_msg,
-+ extensions[0],
-+ sizeof(struct sadb_msg));
-+ (*pfkey_msg)->sadb_msg_len = total_size;
-+ (*pfkey_msg)->sadb_msg_reserved = 0;
-+ extensions_seen = 1 ;
-+
-+ /*
-+ * point pfkey_ext to immediately after the space for the header,
-+ * i.e. at the first extension location.
-+ */
-+ pfkey_ext = (struct sadb_ext*)(((char*)(*pfkey_msg)) + sizeof(struct sadb_msg));
-+
-+ for(ext = 1; ext <= SADB_EXT_MAX; ext++) {
-+ /* copy from extension[ext] to buffer */
-+ if(extensions[ext]) {
-+ /* Is this type of extension permitted for this type of message? */
-+ if(!(extensions_bitmaps[dir][EXT_BITS_PERM][(*pfkey_msg)->sadb_msg_type] &
-+ 1<<ext)) {
-+ ERROR("pfkey_msg_build: "
-+ "ext type %d not permitted, exts_perm=%08x, 1<<type=%08x\n",
-+ ext,
-+ extensions_bitmaps[dir][EXT_BITS_PERM][(*pfkey_msg)->sadb_msg_type],
-+ 1<<ext);
-+ SENDERR(EINVAL);
-+ }
-+
-+ DEBUGGING(PF_KEY_DEBUG_BUILD,
-+ "pfkey_msg_build: "
-+ "copying %lu bytes from extensions[%u] (type=%d)\n",
-+ (unsigned long)(extensions[ext]->sadb_ext_len * IPSEC_PFKEYv2_ALIGN),
-+ ext,
-+ extensions[ext]->sadb_ext_type);
-+
-+ memcpy(pfkey_ext,
-+ extensions[ext],
-+ (extensions[ext])->sadb_ext_len * IPSEC_PFKEYv2_ALIGN);
-+ ((char*)pfkey_ext) += (extensions[ext])->sadb_ext_len * IPSEC_PFKEYv2_ALIGN;
-+ /* Mark that we have seen this extension and remember the header location */
-+ extensions_seen |= ( 1 << ext );
-+ }
-+ }
-+
-+ /* check required extensions */
-+ DEBUGGING(PF_KEY_DEBUG_BUILD,
-+ "pfkey_msg_build: "
-+ "extensions permitted=%08x, seen=%08x, required=%08x.\n",
-+ extensions_bitmaps[dir][EXT_BITS_PERM][(*pfkey_msg)->sadb_msg_type],
-+ extensions_seen,
-+ extensions_bitmaps[dir][EXT_BITS_REQ][(*pfkey_msg)->sadb_msg_type]);
-+
-+ if((extensions_seen &
-+ extensions_bitmaps[dir][EXT_BITS_REQ][(*pfkey_msg)->sadb_msg_type]) !=
-+ extensions_bitmaps[dir][EXT_BITS_REQ][(*pfkey_msg)->sadb_msg_type]) {
-+ DEBUGGING(PF_KEY_DEBUG_BUILD,
-+ "pfkey_msg_build: "
-+ "required extensions missing:%08x.\n",
-+ extensions_bitmaps[dir][EXT_BITS_REQ][(*pfkey_msg)->sadb_msg_type] -
-+ (extensions_seen &
-+ extensions_bitmaps[dir][EXT_BITS_REQ][(*pfkey_msg)->sadb_msg_type]) );
-+ SENDERR(EINVAL);
-+ }
-+
-+#ifndef __KERNEL__
-+/*
-+ * this is silly, there is no need to reparse the message that we just built.
-+ *
-+ */
-+ if((error = pfkey_msg_parse(*pfkey_msg, NULL, extensions_check, dir))) {
-+ ERROR(
-+ "pfkey_msg_build: "
-+ "Trouble parsing newly built pfkey message, error=%d.\n",
-+ error);
-+ SENDERR(-error);
-+ }
-+#endif
-+
-+errlab:
-+
-+ return error;
-+}
-+
-+/*
-+ * $Log: pfkey_v2_build.c,v $
-+ * Revision 1.49 2004/04/12 02:59:06 mcr
-+ * erroneously moved pfkey_v2_build.c
-+ *
-+ * Revision 1.48 2004/04/09 18:00:40 mcr
-+ * Moved from linux/lib/libfreeswan/pfkey_v2_build.c,v
-+ *
-+ * Revision 1.47 2004/03/08 01:59:08 ken
-+ * freeswan.h -> openswan.h
-+ *
-+ * Revision 1.46 2003/12/10 01:20:19 mcr
-+ * NAT-traversal patches to KLIPS.
-+ *
-+ * Revision 1.45 2003/12/04 23:01:12 mcr
-+ * removed ipsec_netlink.h
-+ *
-+ * Revision 1.44 2003/10/31 02:27:12 mcr
-+ * pulled up port-selector patches and sa_id elimination.
-+ *
-+ * Revision 1.43.4.2 2003/10/29 01:11:32 mcr
-+ * added debugging for pfkey library.
-+ *
-+ * Revision 1.43.4.1 2003/09/21 13:59:44 mcr
-+ * pre-liminary X.509 patch - does not yet pass tests.
-+ *
-+ * Revision 1.43 2003/05/07 17:29:17 mcr
-+ * new function pfkey_debug_func added for us in debugging from
-+ * pfkey library.
-+ *
-+ * Revision 1.42 2003/01/30 02:32:09 rgb
-+ *
-+ * Rename SAref table macro names for clarity.
-+ * Convert IPsecSAref_t from signed to unsigned to fix apparent SAref exhaustion bug.
-+ *
-+ * Revision 1.41 2002/12/13 18:16:02 mcr
-+ * restored sa_ref code
-+ *
-+ * Revision 1.40 2002/12/13 18:06:52 mcr
-+ * temporarily removed sadb_x_sa_ref reference for 2.xx
-+ *
-+ * Revision 1.39 2002/12/13 17:43:28 mcr
-+ * commented out access to sadb_x_sa_ref for 2.xx branch
-+ *
-+ * Revision 1.38 2002/10/09 03:12:05 dhr
-+ *
-+ * [kenb+dhr] 64-bit fixes
-+ *
-+ * Revision 1.37 2002/09/20 15:40:39 rgb
-+ * Added new function pfkey_sa_ref_build() to accomodate saref parameter.
-+ *
-+ * Revision 1.36 2002/09/20 05:01:22 rgb
-+ * Generalise for platform independance: fix (ia64) using unsigned for sizes.
-+ *
-+ * Revision 1.35 2002/07/24 18:44:54 rgb
-+ * Type fiddling to tame ia64 compiler.
-+ *
-+ * Revision 1.34 2002/05/23 07:14:11 rgb
-+ * Cleaned up %p variants to 0p%p for test suite cleanup.
-+ *
-+ * Revision 1.33 2002/04/24 07:55:32 mcr
-+ * #include patches and Makefiles for post-reorg compilation.
-+ *
-+ * Revision 1.32 2002/04/24 07:36:40 mcr
-+ * Moved from ./lib/pfkey_v2_build.c,v
-+ *
-+ * Revision 1.31 2002/01/29 22:25:35 rgb
-+ * Re-add ipsec_kversion.h to keep MALLOC happy.
-+ *
-+ * Revision 1.30 2002/01/29 01:59:09 mcr
-+ * removal of kversions.h - sources that needed it now use ipsec_param.h.
-+ * updating of IPv6 structures to match latest in6.h version.
-+ * removed dead code from openswan.h that also duplicated kversions.h
-+ * code.
-+ *
-+ * Revision 1.29 2001/12/19 21:06:09 rgb
-+ * Added port numbers to pfkey_address_build() debugging.
-+ *
-+ * Revision 1.28 2001/11/06 19:47:47 rgb
-+ * Added packet parameter to lifetime and comb structures.
-+ *
-+ * Revision 1.27 2001/10/18 04:45:24 rgb
-+ * 2.4.9 kernel deprecates linux/malloc.h in favour of linux/slab.h,
-+ * lib/openswan.h version macros moved to lib/kversions.h.
-+ * Other compiler directive cleanups.
-+ *
-+ * Revision 1.26 2001/09/08 21:13:34 rgb
-+ * Added pfkey ident extension support for ISAKMPd. (NetCelo)
-+ *
-+ * Revision 1.25 2001/06/14 19:35:16 rgb
-+ * Update copyright date.
-+ *
-+ * Revision 1.24 2001/03/20 03:49:45 rgb
-+ * Ditch superfluous debug_pfkey declaration.
-+ * Move misplaced openswan.h inclusion for kernel case.
-+ *
-+ * Revision 1.23 2001/03/16 07:41:50 rgb
-+ * Put openswan.h include before pluto includes.
-+ *
-+ * Revision 1.22 2001/02/27 22:24:56 rgb
-+ * Re-formatting debug output (line-splitting, joining, 1arg/line).
-+ * Check for satoa() return codes.
-+ *
-+ * Revision 1.21 2000/11/17 18:10:30 rgb
-+ * Fixed bugs mostly relating to spirange, to treat all spi variables as
-+ * network byte order since this is the way PF_KEYv2 stored spis.
-+ *
-+ * Revision 1.20 2000/10/12 00:02:39 rgb
-+ * Removed 'format, ##' nonsense from debug macros for RH7.0.
-+ *
-+ * Revision 1.19 2000/10/10 20:10:20 rgb
-+ * Added support for debug_ipcomp and debug_verbose to klipsdebug.
-+ *
-+ * Revision 1.18 2000/09/12 18:59:54 rgb
-+ * Added Gerhard's IPv6 support to pfkey parts of libopenswan.
-+ *
-+ * Revision 1.17 2000/09/12 03:27:00 rgb
-+ * Moved DEBUGGING definition to compile kernel with debug off.
-+ *
-+ * Revision 1.16 2000/09/08 19:22:12 rgb
-+ * Fixed pfkey_prop_build() parameter to be only single indirection.
-+ * Fixed struct alg copy.
-+ *
-+ * Revision 1.15 2000/08/20 21:40:01 rgb
-+ * Added an address parameter sanity check to pfkey_address_build().
-+ *
-+ * Revision 1.14 2000/08/15 17:29:23 rgb
-+ * Fixes from SZI to untested pfkey_prop_build().
-+ *
-+ * Revision 1.13 2000/06/02 22:54:14 rgb
-+ * Added Gerhard Gessler's struct sockaddr_storage mods for IPv6 support.
-+ *
-+ * Revision 1.12 2000/05/10 19:24:01 rgb
-+ * Fleshed out sensitivity, proposal and supported extensions.
-+ *
-+ * Revision 1.11 2000/03/16 14:07:23 rgb
-+ * Renamed ALIGN macro to avoid fighting with others in kernel.
-+ *
-+ * Revision 1.10 2000/01/24 21:14:35 rgb
-+ * Added disabled pluto pfkey lib debug flag.
-+ *
-+ * Revision 1.9 2000/01/21 06:27:32 rgb
-+ * Added address cases for eroute flows.
-+ * Removed unused code.
-+ * Dropped unused argument to pfkey_x_satype_build().
-+ * Indented compiler directives for readability.
-+ * Added klipsdebug switching capability.
-+ * Fixed SADB_EXT_MAX bug not permitting last extension access.
-+ *
-+ * Revision 1.8 1999/12/29 21:17:41 rgb
-+ * Changed pfkey_msg_build() I/F to include a struct sadb_msg**
-+ * parameter for cleaner manipulation of extensions[] and to guard
-+ * against potential memory leaks.
-+ * Changed the I/F to pfkey_msg_free() for the same reason.
-+ *
-+ * Revision 1.7 1999/12/09 23:12:20 rgb
-+ * Removed unused cruft.
-+ * Added argument to pfkey_sa_build() to do eroutes.
-+ * Fixed exttype check in as yet unused pfkey_lifetime_build().
-+ *
-+ * Revision 1.6 1999/12/07 19:54:29 rgb
-+ * Removed static pluto debug flag.
-+ * Added functions for pfkey message and extensions initialisation
-+ * and cleanup.
-+ *
-+ * Revision 1.5 1999/12/01 22:20:06 rgb
-+ * Changed pfkey_sa_build to accept an SPI in network byte order.
-+ * Added <string.h> to quiet userspace compiler.
-+ * Moved pfkey_lib_debug variable into the library.
-+ * Removed SATYPE check from pfkey_msg_hdr_build so FLUSH will work.
-+ * Added extension assembly debugging.
-+ * Isolated assignment with brackets to be sure of scope.
-+ *
-+ * Revision 1.4 1999/11/27 11:57:35 rgb
-+ * Added ipv6 headers.
-+ * Remove over-zealous algorithm sanity checkers from pfkey_sa_build.
-+ * Debugging error messages added.
-+ * Fixed missing auth and encrypt assignment bug.
-+ * Add argument to pfkey_msg_parse() for direction.
-+ * Move parse-after-build check inside pfkey_msg_build().
-+ * Consolidated the 4 1-d extension bitmap arrays into one 4-d array.
-+ * Add CVS log entry to bottom of file.
-+ *
-+ */
---- /dev/null Tue Mar 11 13:02:56 2003
-+++ linux/lib/libfreeswan/pfkey_v2_debug.c Mon Feb 9 13:51:03 2004
-@@ -0,0 +1,176 @@
-+/*
-+ * @(#) pfkey version 2 debugging messages
-+ *
-+ * Copyright (C) 2001 Richard Guy Briggs <rgb@openswan.org>
-+ * and Michael Richardson <mcr@openswan.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. See <http://www.fsf.org/copyleft/gpl.txt>.
-+ *
-+ * 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.
-+ *
-+ * RCSID $Id: pfkey_v2_debug.c,v 1.9 2004/03/08 01:59:08 ken Exp $
-+ *
-+ */
-+
-+#ifdef __KERNEL__
-+
-+# include <linux/kernel.h> /* for printk */
-+
-+# include "openswan/ipsec_kversion.h" /* for malloc switch */
-+# ifdef MALLOC_SLAB
-+# include <linux/slab.h> /* kmalloc() */
-+# else /* MALLOC_SLAB */
-+# include <linux/malloc.h> /* kmalloc() */
-+# endif /* MALLOC_SLAB */
-+# include <linux/errno.h> /* error codes */
-+# include <linux/types.h> /* size_t */
-+# include <linux/interrupt.h> /* mark_bh */
-+
-+# include <linux/netdevice.h> /* struct device, and other headers */
-+# include <linux/etherdevice.h> /* eth_type_trans */
-+extern int debug_pfkey;
-+
-+#else /* __KERNEL__ */
-+
-+# include <sys/types.h>
-+# include <linux/types.h>
-+# include <linux/errno.h>
-+
-+#endif /* __KERNEL__ */
-+
-+#include "openswan.h"
-+#include "pfkeyv2.h"
-+#include "pfkey.h"
-+
-+/*
-+ * This file provides ASCII translations of PF_KEY magic numbers.
-+ *
-+ */
-+
-+static char *pfkey_sadb_ext_strings[]={
-+ "reserved", /* SADB_EXT_RESERVED 0 */
-+ "security-association", /* SADB_EXT_SA 1 */
-+ "lifetime-current", /* SADB_EXT_LIFETIME_CURRENT 2 */
-+ "lifetime-hard", /* SADB_EXT_LIFETIME_HARD 3 */
-+ "lifetime-soft", /* SADB_EXT_LIFETIME_SOFT 4 */
-+ "source-address", /* SADB_EXT_ADDRESS_SRC 5 */
-+ "destination-address", /* SADB_EXT_ADDRESS_DST 6 */
-+ "proxy-address", /* SADB_EXT_ADDRESS_PROXY 7 */
-+ "authentication-key", /* SADB_EXT_KEY_AUTH 8 */
-+ "cipher-key", /* SADB_EXT_KEY_ENCRYPT 9 */
-+ "source-identity", /* SADB_EXT_IDENTITY_SRC 10 */
-+ "destination-identity", /* SADB_EXT_IDENTITY_DST 11 */
-+ "sensitivity-label", /* SADB_EXT_SENSITIVITY 12 */
-+ "proposal", /* SADB_EXT_PROPOSAL 13 */
-+ "supported-auth", /* SADB_EXT_SUPPORTED_AUTH 14 */
-+ "supported-cipher", /* SADB_EXT_SUPPORTED_ENCRYPT 15 */
-+ "spi-range", /* SADB_EXT_SPIRANGE 16 */
-+ "X-kmpprivate", /* SADB_X_EXT_KMPRIVATE 17 */
-+ "X-satype2", /* SADB_X_EXT_SATYPE2 18 */
-+ "X-security-association", /* SADB_X_EXT_SA2 19 */
-+ "X-destination-address2", /* SADB_X_EXT_ADDRESS_DST2 20 */
-+ "X-source-flow-address", /* SADB_X_EXT_ADDRESS_SRC_FLOW 21 */
-+ "X-dest-flow-address", /* SADB_X_EXT_ADDRESS_DST_FLOW 22 */
-+ "X-source-mask", /* SADB_X_EXT_ADDRESS_SRC_MASK 23 */
-+ "X-dest-mask", /* SADB_X_EXT_ADDRESS_DST_MASK 24 */
-+ "X-set-debug", /* SADB_X_EXT_DEBUG 25 */
-+#ifdef NAT_TRAVERSAL
-+ "X-NAT-T-type", /* SADB_X_EXT_NAT_T_TYPE 26 */
-+ "X-NAT-T-sport", /* SADB_X_EXT_NAT_T_SPORT 27 */
-+ "X-NAT-T-dport", /* SADB_X_EXT_NAT_T_DPORT 28 */
-+ "X-NAT-T-OA", /* SADB_X_EXT_NAT_T_OA 29 */
-+#endif
-+};
-+
-+const char *
-+pfkey_v2_sadb_ext_string(int ext)
-+{
-+ if(ext <= SADB_EXT_MAX) {
-+ return pfkey_sadb_ext_strings[ext];
-+ } else {
-+ return "unknown-ext";
-+ }
-+}
-+
-+
-+static char *pfkey_sadb_type_strings[]={
-+ "reserved", /* SADB_RESERVED */
-+ "getspi", /* SADB_GETSPI */
-+ "update", /* SADB_UPDATE */
-+ "add", /* SADB_ADD */
-+ "delete", /* SADB_DELETE */
-+ "get", /* SADB_GET */
-+ "acquire", /* SADB_ACQUIRE */
-+ "register", /* SADB_REGISTER */
-+ "expire", /* SADB_EXPIRE */
-+ "flush", /* SADB_FLUSH */
-+ "dump", /* SADB_DUMP */
-+ "x-promisc", /* SADB_X_PROMISC */
-+ "x-pchange", /* SADB_X_PCHANGE */
-+ "x-groupsa", /* SADB_X_GRPSA */
-+ "x-addflow(eroute)", /* SADB_X_ADDFLOW */
-+ "x-delflow(eroute)", /* SADB_X_DELFLOW */
-+ "x-debug", /* SADB_X_DEBUG */
-+};
-+
-+const char *
-+pfkey_v2_sadb_type_string(int sadb_type)
-+{
-+ if(sadb_type <= SADB_MAX) {
-+ return pfkey_sadb_type_strings[sadb_type];
-+ } else {
-+ return "unknown-sadb-type";
-+ }
-+}
-+
-+
-+
-+
-+/*
-+ * $Log: pfkey_v2_debug.c,v $
-+ * Revision 1.9 2004/03/08 01:59:08 ken
-+ * freeswan.h -> openswan.h
-+ *
-+ * Revision 1.8 2003/12/10 01:20:19 mcr
-+ * NAT-traversal patches to KLIPS.
-+ *
-+ * Revision 1.7 2002/09/20 05:01:26 rgb
-+ * Fixed limit inclusion error in both type and ext string conversion.
-+ *
-+ * Revision 1.6 2002/04/24 07:55:32 mcr
-+ * #include patches and Makefiles for post-reorg compilation.
-+ *
-+ * Revision 1.5 2002/04/24 07:36:40 mcr
-+ * Moved from ./lib/pfkey_v2_debug.c,v
-+ *
-+ * Revision 1.4 2002/01/29 22:25:36 rgb
-+ * Re-add ipsec_kversion.h to keep MALLOC happy.
-+ *
-+ * Revision 1.3 2002/01/29 01:59:09 mcr
-+ * removal of kversions.h - sources that needed it now use ipsec_param.h.
-+ * updating of IPv6 structures to match latest in6.h version.
-+ * removed dead code from openswan.h that also duplicated kversions.h
-+ * code.
-+ *
-+ * Revision 1.2 2002/01/20 20:34:50 mcr
-+ * added pfkey_v2_sadb_type_string to decode sadb_type to string.
-+ *
-+ * Revision 1.1 2001/11/27 05:30:06 mcr
-+ * initial set of debug strings for pfkey debugging.
-+ * this will eventually only be included for debug builds.
-+ *
-+ * Revision 1.1 2001/09/21 04:12:03 mcr
-+ * first compilable version.
-+ *
-+ *
-+ * Local variables:
-+ * c-file-style: "linux"
-+ * End:
-+ *
-+ */
---- /dev/null Tue Mar 11 13:02:56 2003
-+++ linux/lib/libfreeswan/pfkey_v2_ext_bits.c Mon Feb 9 13:51:03 2004
-@@ -0,0 +1,808 @@
-+/*
-+ * RFC2367 PF_KEYv2 Key management API message parser
-+ * Copyright (C) 1999, 2000, 2001 Richard Guy Briggs.
-+ *
-+ * 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. See <http://www.fsf.org/copyleft/gpl.txt>.
-+ *
-+ * 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.
-+ *
-+ * RCSID $Id: pfkey_v2_ext_bits.c,v 1.20 2004/03/08 01:59:08 ken Exp $
-+ */
-+
-+/*
-+ * Template from klips/net/ipsec/ipsec/ipsec_parse.c.
-+ */
-+
-+char pfkey_v2_ext_bits_c_version[] = "$Id: pfkey_v2_ext_bits.c,v 1.20 2004/03/08 01:59:08 ken Exp $";
-+
-+/*
-+ * Some ugly stuff to allow consistent debugging code for use in the
-+ * kernel and in user space
-+*/
-+
-+#ifdef __KERNEL__
-+
-+# include <linux/kernel.h> /* for printk */
-+
-+# include "openswan/ipsec_kversion.h" /* for malloc switch */
-+# ifdef MALLOC_SLAB
-+# include <linux/slab.h> /* kmalloc() */
-+# else /* MALLOC_SLAB */
-+# include <linux/malloc.h> /* kmalloc() */
-+# endif /* MALLOC_SLAB */
-+# include <linux/errno.h> /* error codes */
-+# include <linux/types.h> /* size_t */
-+# include <linux/interrupt.h> /* mark_bh */
-+
-+# include <linux/netdevice.h> /* struct device, and other headers */
-+# include <linux/etherdevice.h> /* eth_type_trans */
-+# include <linux/ip.h> /* struct iphdr */
-+# if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
-+# include <linux/ipv6.h>
-+# endif /* defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) */
-+
-+#else /* __KERNEL__ */
-+
-+# include <sys/types.h>
-+# include <linux/types.h>
-+# include <linux/errno.h>
-+#endif
-+
-+#include <openswan.h>
-+#include <pfkeyv2.h>
-+#include <pfkey.h>
-+
-+unsigned int extensions_bitmaps[2/*in/out*/][2/*perm/req*/][SADB_MAX + 1/*ext*/] = {
-+
-+/* INBOUND EXTENSIONS */
-+{
-+
-+/* PERMITTED IN */
-+{
-+/* SADB_RESERVED */
-+0
-+,
-+/* SADB_GETSPI */
-+1<<SADB_EXT_RESERVED
-+| 1<<SADB_EXT_ADDRESS_SRC
-+| 1<<SADB_EXT_ADDRESS_DST
-+| 1<<SADB_EXT_ADDRESS_PROXY
-+| 1<<SADB_EXT_SPIRANGE
-+,
-+/* SADB_UPDATE */
-+1<<SADB_EXT_RESERVED
-+| 1<<SADB_EXT_SA
-+| 1<<SADB_EXT_LIFETIME_CURRENT
-+| 1<<SADB_EXT_LIFETIME_HARD
-+| 1<<SADB_EXT_LIFETIME_SOFT
-+| 1<<SADB_EXT_ADDRESS_SRC
-+| 1<<SADB_EXT_ADDRESS_DST
-+| 1<<SADB_EXT_ADDRESS_PROXY
-+| 1<<SADB_EXT_KEY_AUTH
-+| 1<<SADB_EXT_KEY_ENCRYPT
-+| 1<<SADB_EXT_IDENTITY_SRC
-+| 1<<SADB_EXT_IDENTITY_DST
-+| 1<<SADB_EXT_SENSITIVITY
-+| 1<<SADB_X_EXT_NAT_T_SPORT
-+| 1<<SADB_X_EXT_NAT_T_DPORT
-+,
-+/* SADB_ADD */
-+1<<SADB_EXT_RESERVED
-+| 1<<SADB_EXT_SA
-+| 1<<SADB_EXT_LIFETIME_HARD
-+| 1<<SADB_EXT_LIFETIME_SOFT
-+| 1<<SADB_EXT_ADDRESS_SRC
-+| 1<<SADB_EXT_ADDRESS_DST
-+| 1<<SADB_EXT_ADDRESS_PROXY
-+| 1<<SADB_EXT_KEY_AUTH
-+| 1<<SADB_EXT_KEY_ENCRYPT
-+| 1<<SADB_EXT_IDENTITY_SRC
-+| 1<<SADB_EXT_IDENTITY_DST
-+| 1<<SADB_EXT_SENSITIVITY
-+| 1<<SADB_X_EXT_NAT_T_TYPE
-+| 1<<SADB_X_EXT_NAT_T_SPORT
-+| 1<<SADB_X_EXT_NAT_T_DPORT
-+| 1<<SADB_X_EXT_NAT_T_OA
-+,
-+/* SADB_DELETE */
-+1<<SADB_EXT_RESERVED
-+| 1<<SADB_EXT_SA
-+| 1<<SADB_EXT_ADDRESS_SRC
-+| 1<<SADB_EXT_ADDRESS_DST
-+,
-+/* SADB_GET */
-+1<<SADB_EXT_RESERVED
-+| 1<<SADB_EXT_SA
-+| 1<<SADB_EXT_ADDRESS_SRC
-+| 1<<SADB_EXT_ADDRESS_DST
-+,
-+/* SADB_ACQUIRE */
-+1<<SADB_EXT_RESERVED
-+| 1<<SADB_EXT_ADDRESS_SRC
-+| 1<<SADB_EXT_ADDRESS_DST
-+| 1<<SADB_EXT_ADDRESS_PROXY
-+| 1<<SADB_EXT_IDENTITY_SRC
-+| 1<<SADB_EXT_IDENTITY_DST
-+| 1<<SADB_EXT_SENSITIVITY
-+| 1<<SADB_EXT_PROPOSAL
-+,
-+/* SADB_REGISTER */
-+1<<SADB_EXT_RESERVED
-+,
-+/* SADB_EXPIRE */
-+0
-+,
-+/* SADB_FLUSH */
-+1<<SADB_EXT_RESERVED
-+,
-+/* SADB_DUMP */
-+1<<SADB_EXT_RESERVED
-+,
-+/* SADB_X_PROMISC */
-+1<<SADB_EXT_RESERVED
-+| 1<<SADB_EXT_SA
-+| 1<<SADB_EXT_LIFETIME_CURRENT
-+| 1<<SADB_EXT_LIFETIME_HARD
-+| 1<<SADB_EXT_LIFETIME_SOFT
-+| 1<<SADB_EXT_ADDRESS_SRC
-+| 1<<SADB_EXT_ADDRESS_DST
-+| 1<<SADB_EXT_ADDRESS_PROXY
-+| 1<<SADB_EXT_KEY_AUTH
-+| 1<<SADB_EXT_KEY_ENCRYPT
-+| 1<<SADB_EXT_IDENTITY_SRC
-+| 1<<SADB_EXT_IDENTITY_DST
-+| 1<<SADB_EXT_SENSITIVITY
-+| 1<<SADB_EXT_PROPOSAL
-+| 1<<SADB_EXT_SUPPORTED_AUTH
-+| 1<<SADB_EXT_SUPPORTED_ENCRYPT
-+| 1<<SADB_EXT_SPIRANGE
-+| 1<<SADB_X_EXT_KMPRIVATE
-+| 1<<SADB_X_EXT_SATYPE2
-+| 1<<SADB_X_EXT_SA2
-+| 1<<SADB_X_EXT_ADDRESS_DST2
-+,
-+/* SADB_X_PCHANGE */
-+1<<SADB_EXT_RESERVED
-+| 1<<SADB_EXT_SA
-+| 1<<SADB_EXT_LIFETIME_CURRENT
-+| 1<<SADB_EXT_LIFETIME_HARD
-+| 1<<SADB_EXT_LIFETIME_SOFT
-+| 1<<SADB_EXT_ADDRESS_SRC
-+| 1<<SADB_EXT_ADDRESS_DST
-+| 1<<SADB_EXT_ADDRESS_PROXY
-+| 1<<SADB_EXT_KEY_AUTH
-+| 1<<SADB_EXT_KEY_ENCRYPT
-+| 1<<SADB_EXT_IDENTITY_SRC
-+| 1<<SADB_EXT_IDENTITY_DST
-+| 1<<SADB_EXT_SENSITIVITY
-+| 1<<SADB_EXT_PROPOSAL
-+| 1<<SADB_EXT_SUPPORTED_AUTH
-+| 1<<SADB_EXT_SUPPORTED_ENCRYPT
-+| 1<<SADB_EXT_SPIRANGE
-+| 1<<SADB_X_EXT_KMPRIVATE
-+| 1<<SADB_X_EXT_SATYPE2
-+| 1<<SADB_X_EXT_SA2
-+| 1<<SADB_X_EXT_ADDRESS_DST2
-+,
-+/* SADB_X_GRPSA */
-+1<<SADB_EXT_RESERVED
-+| 1<<SADB_EXT_SA
-+| 1<<SADB_EXT_ADDRESS_DST
-+| 1<<SADB_X_EXT_SATYPE2
-+| 1<<SADB_X_EXT_SA2
-+| 1<<SADB_X_EXT_ADDRESS_DST2
-+,
-+/* SADB_X_ADDFLOW */
-+1<<SADB_EXT_RESERVED
-+| 1<<SADB_EXT_SA
-+| 1<<SADB_EXT_ADDRESS_SRC
-+| 1<<SADB_EXT_ADDRESS_DST
-+| 1<<SADB_X_EXT_ADDRESS_SRC_FLOW
-+| 1<<SADB_X_EXT_ADDRESS_DST_FLOW
-+| 1<<SADB_X_EXT_ADDRESS_SRC_MASK
-+| 1<<SADB_X_EXT_ADDRESS_DST_MASK
-+| 1<<SADB_EXT_IDENTITY_SRC
-+| 1<<SADB_EXT_IDENTITY_DST
-+| 1<<SADB_X_EXT_PROTOCOL
-+,
-+/* SADB_X_DELFLOW */
-+1<<SADB_EXT_RESERVED
-+| 1<<SADB_EXT_SA
-+| 1<<SADB_X_EXT_ADDRESS_SRC_FLOW
-+| 1<<SADB_X_EXT_ADDRESS_DST_FLOW
-+| 1<<SADB_X_EXT_ADDRESS_SRC_MASK
-+| 1<<SADB_X_EXT_ADDRESS_DST_MASK
-+| 1<<SADB_EXT_IDENTITY_SRC
-+| 1<<SADB_EXT_IDENTITY_DST
-+| 1<<SADB_X_EXT_PROTOCOL
-+,
-+/* SADB_X_DEBUG */
-+1<<SADB_EXT_RESERVED
-+| 1<<SADB_X_EXT_DEBUG
-+,
-+/* SADB_X_NAT_T_NEW_MAPPING */
-+1<<SADB_EXT_RESERVED
-+| 1<<SADB_EXT_SA
-+| 1<<SADB_EXT_ADDRESS_SRC
-+| 1<<SADB_EXT_ADDRESS_DST
-+| 1<<SADB_X_EXT_NAT_T_SPORT
-+| 1<<SADB_X_EXT_NAT_T_DPORT
-+},
-+
-+/* REQUIRED IN */
-+{
-+/* SADB_RESERVED */
-+0
-+,
-+/* SADB_GETSPI */
-+1<<SADB_EXT_RESERVED
-+| 1<<SADB_EXT_ADDRESS_SRC
-+| 1<<SADB_EXT_ADDRESS_DST
-+| 1<<SADB_EXT_SPIRANGE
-+,
-+/* SADB_UPDATE */
-+1<<SADB_EXT_RESERVED
-+| 1<<SADB_EXT_SA
-+| 1<<SADB_EXT_ADDRESS_SRC
-+| 1<<SADB_EXT_ADDRESS_DST
-+/*| 1<<SADB_EXT_KEY_AUTH*/
-+/*| 1<<SADB_EXT_KEY_ENCRYPT*/
-+,
-+/* SADB_ADD */
-+1<<SADB_EXT_RESERVED
-+| 1<<SADB_EXT_SA
-+| 1<<SADB_EXT_ADDRESS_SRC
-+| 1<<SADB_EXT_ADDRESS_DST
-+/*| 1<<SADB_EXT_KEY_AUTH*/
-+/*| 1<<SADB_EXT_KEY_ENCRYPT*/
-+,
-+/* SADB_DELETE */
-+1<<SADB_EXT_RESERVED
-+| 1<<SADB_EXT_SA
-+| 1<<SADB_EXT_ADDRESS_SRC
-+| 1<<SADB_EXT_ADDRESS_DST
-+,
-+/* SADB_GET */
-+1<<SADB_EXT_RESERVED
-+| 1<<SADB_EXT_SA
-+| 1<<SADB_EXT_ADDRESS_SRC
-+| 1<<SADB_EXT_ADDRESS_DST
-+,
-+/* SADB_ACQUIRE */
-+1<<SADB_EXT_RESERVED
-+| 1<<SADB_EXT_ADDRESS_SRC
-+| 1<<SADB_EXT_ADDRESS_DST
-+| 1<<SADB_EXT_PROPOSAL
-+,
-+/* SADB_REGISTER */
-+1<<SADB_EXT_RESERVED
-+,
-+/* SADB_EXPIRE */
-+0
-+,
-+/* SADB_FLUSH */
-+1<<SADB_EXT_RESERVED
-+,
-+/* SADB_DUMP */
-+1<<SADB_EXT_RESERVED
-+,
-+/* SADB_X_PROMISC */
-+1<<SADB_EXT_RESERVED
-+| 1<<SADB_EXT_SA
-+| 1<<SADB_EXT_LIFETIME_CURRENT
-+| 1<<SADB_EXT_LIFETIME_HARD
-+| 1<<SADB_EXT_LIFETIME_SOFT
-+| 1<<SADB_EXT_ADDRESS_SRC
-+| 1<<SADB_EXT_ADDRESS_DST
-+| 1<<SADB_EXT_ADDRESS_PROXY
-+| 1<<SADB_EXT_KEY_AUTH
-+| 1<<SADB_EXT_KEY_ENCRYPT
-+| 1<<SADB_EXT_IDENTITY_SRC
-+| 1<<SADB_EXT_IDENTITY_DST
-+| 1<<SADB_EXT_SENSITIVITY
-+| 1<<SADB_EXT_PROPOSAL
-+| 1<<SADB_EXT_SUPPORTED_AUTH
-+| 1<<SADB_EXT_SUPPORTED_ENCRYPT
-+| 1<<SADB_EXT_SPIRANGE
-+| 1<<SADB_X_EXT_KMPRIVATE
-+| 1<<SADB_X_EXT_SATYPE2
-+| 1<<SADB_X_EXT_SA2
-+| 1<<SADB_X_EXT_ADDRESS_DST2
-+,
-+/* SADB_X_PCHANGE */
-+1<<SADB_EXT_RESERVED
-+| 1<<SADB_EXT_SA
-+| 1<<SADB_EXT_LIFETIME_CURRENT
-+| 1<<SADB_EXT_LIFETIME_HARD
-+| 1<<SADB_EXT_LIFETIME_SOFT
-+| 1<<SADB_EXT_ADDRESS_SRC
-+| 1<<SADB_EXT_ADDRESS_DST
-+| 1<<SADB_EXT_ADDRESS_PROXY
-+| 1<<SADB_EXT_KEY_AUTH
-+| 1<<SADB_EXT_KEY_ENCRYPT
-+| 1<<SADB_EXT_IDENTITY_SRC
-+| 1<<SADB_EXT_IDENTITY_DST
-+| 1<<SADB_EXT_SENSITIVITY
-+| 1<<SADB_EXT_PROPOSAL
-+| 1<<SADB_EXT_SUPPORTED_AUTH
-+| 1<<SADB_EXT_SUPPORTED_ENCRYPT
-+| 1<<SADB_EXT_SPIRANGE
-+| 1<<SADB_X_EXT_KMPRIVATE
-+| 1<<SADB_X_EXT_SATYPE2
-+| 1<<SADB_X_EXT_SA2
-+| 1<<SADB_X_EXT_ADDRESS_DST2
-+,
-+/* SADB_X_GRPSA */
-+1<<SADB_EXT_RESERVED
-+| 1<<SADB_EXT_SA
-+| 1<<SADB_EXT_ADDRESS_DST
-+/*| 1<<SADB_X_EXT_SATYPE2*/
-+/*| 1<<SADB_X_EXT_SA2*/
-+/*| 1<<SADB_X_EXT_ADDRESS_DST2*/
-+,
-+/* SADB_X_ADDFLOW */
-+1<<SADB_EXT_RESERVED
-+| 1<<SADB_EXT_SA
-+| 1<<SADB_EXT_ADDRESS_DST
-+| 1<<SADB_X_EXT_ADDRESS_SRC_FLOW
-+| 1<<SADB_X_EXT_ADDRESS_DST_FLOW
-+| 1<<SADB_X_EXT_ADDRESS_SRC_MASK
-+| 1<<SADB_X_EXT_ADDRESS_DST_MASK
-+,
-+/* SADB_X_DELFLOW */
-+1<<SADB_EXT_RESERVED
-+/*| 1<<SADB_EXT_SA*/
-+#if 0 /* SADB_X_CLREROUTE doesn't need all these... */
-+| 1<<SADB_X_EXT_ADDRESS_SRC_FLOW
-+| 1<<SADB_X_EXT_ADDRESS_DST_FLOW
-+| 1<<SADB_X_EXT_ADDRESS_SRC_MASK
-+| 1<<SADB_X_EXT_ADDRESS_DST_MASK
-+#endif
-+,
-+/* SADB_X_DEBUG */
-+1<<SADB_EXT_RESERVED
-+| 1<<SADB_X_EXT_DEBUG
-+,
-+/* SADB_X_NAT_T_NEW_MAPPING */
-+1<<SADB_EXT_RESERVED
-+| 1<<SADB_EXT_SA
-+| 1<<SADB_EXT_ADDRESS_SRC
-+| 1<<SADB_EXT_ADDRESS_DST
-+| 1<<SADB_X_EXT_NAT_T_SPORT
-+| 1<<SADB_X_EXT_NAT_T_DPORT
-+}
-+
-+},
-+
-+/* OUTBOUND EXTENSIONS */
-+{
-+
-+/* PERMITTED OUT */
-+{
-+/* SADB_RESERVED */
-+0
-+,
-+/* SADB_GETSPI */
-+1<<SADB_EXT_RESERVED
-+| 1<<SADB_EXT_SA
-+| 1<<SADB_EXT_ADDRESS_SRC
-+| 1<<SADB_EXT_ADDRESS_DST
-+,
-+/* SADB_UPDATE */
-+1<<SADB_EXT_RESERVED
-+| 1<<SADB_EXT_SA
-+| 1<<SADB_EXT_LIFETIME_CURRENT
-+| 1<<SADB_EXT_LIFETIME_HARD
-+| 1<<SADB_EXT_LIFETIME_SOFT
-+| 1<<SADB_EXT_ADDRESS_SRC
-+| 1<<SADB_EXT_ADDRESS_DST
-+| 1<<SADB_EXT_ADDRESS_PROXY
-+| 1<<SADB_EXT_IDENTITY_SRC
-+| 1<<SADB_EXT_IDENTITY_DST
-+| 1<<SADB_EXT_SENSITIVITY
-+| 1<<SADB_X_EXT_NAT_T_SPORT
-+| 1<<SADB_X_EXT_NAT_T_DPORT
-+,
-+/* SADB_ADD */
-+1<<SADB_EXT_RESERVED
-+| 1<<SADB_EXT_SA
-+| 1<<SADB_EXT_LIFETIME_HARD
-+| 1<<SADB_EXT_LIFETIME_SOFT
-+| 1<<SADB_EXT_ADDRESS_SRC
-+| 1<<SADB_EXT_ADDRESS_DST
-+| 1<<SADB_EXT_IDENTITY_SRC
-+| 1<<SADB_EXT_IDENTITY_DST
-+| 1<<SADB_EXT_SENSITIVITY
-+| 1<<SADB_X_EXT_NAT_T_TYPE
-+| 1<<SADB_X_EXT_NAT_T_SPORT
-+| 1<<SADB_X_EXT_NAT_T_DPORT
-+| 1<<SADB_X_EXT_NAT_T_OA
-+,
-+/* SADB_DELETE */
-+1<<SADB_EXT_RESERVED
-+| 1<<SADB_EXT_SA
-+| 1<<SADB_EXT_ADDRESS_SRC
-+| 1<<SADB_EXT_ADDRESS_DST
-+,
-+/* SADB_GET */
-+1<<SADB_EXT_RESERVED
-+| 1<<SADB_EXT_SA
-+| 1<<SADB_EXT_LIFETIME_CURRENT
-+| 1<<SADB_EXT_LIFETIME_HARD
-+| 1<<SADB_EXT_LIFETIME_SOFT
-+| 1<<SADB_EXT_ADDRESS_SRC
-+| 1<<SADB_EXT_ADDRESS_DST
-+| 1<<SADB_EXT_ADDRESS_PROXY
-+| 1<<SADB_EXT_KEY_AUTH
-+| 1<<SADB_EXT_KEY_ENCRYPT
-+| 1<<SADB_EXT_IDENTITY_SRC
-+| 1<<SADB_EXT_IDENTITY_DST
-+| 1<<SADB_EXT_SENSITIVITY
-+| 1<<SADB_X_EXT_NAT_T_TYPE
-+| 1<<SADB_X_EXT_NAT_T_SPORT
-+| 1<<SADB_X_EXT_NAT_T_DPORT
-+| 1<<SADB_X_EXT_NAT_T_OA
-+,
-+/* SADB_ACQUIRE */
-+1<<SADB_EXT_RESERVED
-+| 1<<SADB_EXT_ADDRESS_SRC
-+| 1<<SADB_EXT_ADDRESS_DST
-+| 1<<SADB_EXT_ADDRESS_PROXY
-+| 1<<SADB_EXT_IDENTITY_SRC
-+| 1<<SADB_EXT_IDENTITY_DST
-+| 1<<SADB_EXT_SENSITIVITY
-+| 1<<SADB_EXT_PROPOSAL
-+,
-+/* SADB_REGISTER */
-+1<<SADB_EXT_RESERVED
-+| 1<<SADB_EXT_SUPPORTED_AUTH
-+| 1<<SADB_EXT_SUPPORTED_ENCRYPT
-+,
-+/* SADB_EXPIRE */
-+1<<SADB_EXT_RESERVED
-+| 1<<SADB_EXT_SA
-+| 1<<SADB_EXT_LIFETIME_CURRENT
-+| 1<<SADB_EXT_LIFETIME_HARD
-+| 1<<SADB_EXT_LIFETIME_SOFT
-+| 1<<SADB_EXT_ADDRESS_SRC
-+| 1<<SADB_EXT_ADDRESS_DST
-+,
-+/* SADB_FLUSH */
-+1<<SADB_EXT_RESERVED
-+,
-+/* SADB_DUMP */
-+1<<SADB_EXT_RESERVED
-+| 1<<SADB_EXT_SA
-+| 1<<SADB_EXT_LIFETIME_CURRENT
-+| 1<<SADB_EXT_LIFETIME_HARD
-+| 1<<SADB_EXT_LIFETIME_SOFT
-+| 1<<SADB_EXT_ADDRESS_SRC
-+| 1<<SADB_EXT_ADDRESS_DST
-+| 1<<SADB_EXT_ADDRESS_PROXY
-+| 1<<SADB_EXT_KEY_AUTH
-+| 1<<SADB_EXT_KEY_ENCRYPT
-+| 1<<SADB_EXT_IDENTITY_SRC
-+| 1<<SADB_EXT_IDENTITY_DST
-+| 1<<SADB_EXT_SENSITIVITY
-+| 1<<SADB_X_EXT_NAT_T_TYPE
-+| 1<<SADB_X_EXT_NAT_T_SPORT
-+| 1<<SADB_X_EXT_NAT_T_DPORT
-+| 1<<SADB_X_EXT_NAT_T_OA
-+,
-+/* SADB_X_PROMISC */
-+1<<SADB_EXT_RESERVED
-+| 1<<SADB_EXT_SA
-+| 1<<SADB_EXT_LIFETIME_CURRENT
-+| 1<<SADB_EXT_LIFETIME_HARD
-+| 1<<SADB_EXT_LIFETIME_SOFT
-+| 1<<SADB_EXT_ADDRESS_SRC
-+| 1<<SADB_EXT_ADDRESS_DST
-+| 1<<SADB_EXT_ADDRESS_PROXY
-+| 1<<SADB_EXT_KEY_AUTH
-+| 1<<SADB_EXT_KEY_ENCRYPT
-+| 1<<SADB_EXT_IDENTITY_SRC
-+| 1<<SADB_EXT_IDENTITY_DST
-+| 1<<SADB_EXT_SENSITIVITY
-+| 1<<SADB_EXT_PROPOSAL
-+| 1<<SADB_EXT_SUPPORTED_AUTH
-+| 1<<SADB_EXT_SUPPORTED_ENCRYPT
-+| 1<<SADB_EXT_SPIRANGE
-+| 1<<SADB_X_EXT_KMPRIVATE
-+| 1<<SADB_X_EXT_SATYPE2
-+| 1<<SADB_X_EXT_SA2
-+| 1<<SADB_X_EXT_ADDRESS_DST2
-+,
-+/* SADB_X_PCHANGE */
-+1<<SADB_EXT_RESERVED
-+| 1<<SADB_EXT_SA
-+| 1<<SADB_EXT_LIFETIME_CURRENT
-+| 1<<SADB_EXT_LIFETIME_HARD
-+| 1<<SADB_EXT_LIFETIME_SOFT
-+| 1<<SADB_EXT_ADDRESS_SRC
-+| 1<<SADB_EXT_ADDRESS_DST
-+| 1<<SADB_EXT_ADDRESS_PROXY
-+| 1<<SADB_EXT_KEY_AUTH
-+| 1<<SADB_EXT_KEY_ENCRYPT
-+| 1<<SADB_EXT_IDENTITY_SRC
-+| 1<<SADB_EXT_IDENTITY_DST
-+| 1<<SADB_EXT_SENSITIVITY
-+| 1<<SADB_EXT_PROPOSAL
-+| 1<<SADB_EXT_SUPPORTED_AUTH
-+| 1<<SADB_EXT_SUPPORTED_ENCRYPT
-+| 1<<SADB_EXT_SPIRANGE
-+| 1<<SADB_X_EXT_KMPRIVATE
-+| 1<<SADB_X_EXT_SATYPE2
-+| 1<<SADB_X_EXT_SA2
-+| 1<<SADB_X_EXT_ADDRESS_DST2
-+,
-+/* SADB_X_GRPSA */
-+1<<SADB_EXT_RESERVED
-+| 1<<SADB_EXT_SA
-+| 1<<SADB_EXT_ADDRESS_DST
-+| 1<<SADB_X_EXT_SATYPE2
-+| 1<<SADB_X_EXT_SA2
-+| 1<<SADB_X_EXT_ADDRESS_DST2
-+,
-+/* SADB_X_ADDFLOW */
-+1<<SADB_EXT_RESERVED
-+| 1<<SADB_EXT_SA
-+| 1<<SADB_EXT_ADDRESS_SRC
-+| 1<<SADB_EXT_ADDRESS_DST
-+| 1<<SADB_X_EXT_ADDRESS_SRC_FLOW
-+| 1<<SADB_X_EXT_ADDRESS_DST_FLOW
-+| 1<<SADB_X_EXT_ADDRESS_SRC_MASK
-+| 1<<SADB_X_EXT_ADDRESS_DST_MASK
-+| 1<<SADB_X_EXT_PROTOCOL
-+,
-+/* SADB_X_DELFLOW */
-+1<<SADB_EXT_RESERVED
-+| 1<<SADB_EXT_SA
-+| 1<<SADB_X_EXT_ADDRESS_SRC_FLOW
-+| 1<<SADB_X_EXT_ADDRESS_DST_FLOW
-+| 1<<SADB_X_EXT_ADDRESS_SRC_MASK
-+| 1<<SADB_X_EXT_ADDRESS_DST_MASK
-+| 1<<SADB_X_EXT_PROTOCOL
-+,
-+/* SADB_X_DEBUG */
-+1<<SADB_EXT_RESERVED
-+| 1<<SADB_X_EXT_DEBUG
-+,
-+/* SADB_X_NAT_T_NEW_MAPPING */
-+1<<SADB_EXT_RESERVED
-+| 1<<SADB_EXT_SA
-+| 1<<SADB_EXT_ADDRESS_SRC
-+| 1<<SADB_EXT_ADDRESS_DST
-+| 1<<SADB_X_EXT_NAT_T_SPORT
-+| 1<<SADB_X_EXT_NAT_T_DPORT
-+},
-+
-+/* REQUIRED OUT */
-+{
-+/* SADB_RESERVED */
-+0
-+,
-+/* SADB_GETSPI */
-+1<<SADB_EXT_RESERVED
-+| 1<<SADB_EXT_SA
-+| 1<<SADB_EXT_ADDRESS_SRC
-+| 1<<SADB_EXT_ADDRESS_DST
-+,
-+/* SADB_UPDATE */
-+1<<SADB_EXT_RESERVED
-+| 1<<SADB_EXT_SA
-+| 1<<SADB_EXT_ADDRESS_SRC
-+| 1<<SADB_EXT_ADDRESS_DST
-+,
-+/* SADB_ADD */
-+1<<SADB_EXT_RESERVED
-+| 1<<SADB_EXT_SA
-+| 1<<SADB_EXT_ADDRESS_SRC
-+| 1<<SADB_EXT_ADDRESS_DST
-+,
-+/* SADB_DELETE */
-+1<<SADB_EXT_RESERVED
-+| 1<<SADB_EXT_SA
-+| 1<<SADB_EXT_ADDRESS_SRC
-+| 1<<SADB_EXT_ADDRESS_DST
-+,
-+/* SADB_GET */
-+1<<SADB_EXT_RESERVED
-+| 1<<SADB_EXT_SA
-+| 1<<SADB_EXT_ADDRESS_SRC
-+| 1<<SADB_EXT_ADDRESS_DST
-+/* | 1<<SADB_EXT_KEY_AUTH */
-+/* | 1<<SADB_EXT_KEY_ENCRYPT */
-+,
-+/* SADB_ACQUIRE */
-+1<<SADB_EXT_RESERVED
-+| 1<<SADB_EXT_ADDRESS_SRC
-+| 1<<SADB_EXT_ADDRESS_DST
-+| 1<<SADB_EXT_PROPOSAL
-+,
-+/* SADB_REGISTER */
-+1<<SADB_EXT_RESERVED
-+/* | 1<<SADB_EXT_SUPPORTED_AUTH
-+ | 1<<SADB_EXT_SUPPORTED_ENCRYPT */
-+,
-+/* SADB_EXPIRE */
-+1<<SADB_EXT_RESERVED
-+| 1<<SADB_EXT_SA
-+| 1<<SADB_EXT_LIFETIME_CURRENT
-+/* | 1<<SADB_EXT_LIFETIME_HARD
-+ | 1<<SADB_EXT_LIFETIME_SOFT */
-+| 1<<SADB_EXT_ADDRESS_SRC
-+| 1<<SADB_EXT_ADDRESS_DST
-+,
-+/* SADB_FLUSH */
-+1<<SADB_EXT_RESERVED
-+,
-+/* SADB_DUMP */
-+1<<SADB_EXT_RESERVED
-+| 1<<SADB_EXT_SA
-+| 1<<SADB_EXT_ADDRESS_SRC
-+| 1<<SADB_EXT_ADDRESS_DST
-+| 1<<SADB_EXT_KEY_AUTH
-+| 1<<SADB_EXT_KEY_ENCRYPT
-+,
-+/* SADB_X_PROMISC */
-+1<<SADB_EXT_RESERVED
-+| 1<<SADB_EXT_SA
-+| 1<<SADB_EXT_LIFETIME_CURRENT
-+| 1<<SADB_EXT_LIFETIME_HARD
-+| 1<<SADB_EXT_LIFETIME_SOFT
-+| 1<<SADB_EXT_ADDRESS_SRC
-+| 1<<SADB_EXT_ADDRESS_DST
-+| 1<<SADB_EXT_ADDRESS_PROXY
-+| 1<<SADB_EXT_KEY_AUTH
-+| 1<<SADB_EXT_KEY_ENCRYPT
-+| 1<<SADB_EXT_IDENTITY_SRC
-+| 1<<SADB_EXT_IDENTITY_DST
-+| 1<<SADB_EXT_SENSITIVITY
-+| 1<<SADB_EXT_PROPOSAL
-+| 1<<SADB_EXT_SUPPORTED_AUTH
-+| 1<<SADB_EXT_SUPPORTED_ENCRYPT
-+| 1<<SADB_EXT_SPIRANGE
-+| 1<<SADB_X_EXT_KMPRIVATE
-+| 1<<SADB_X_EXT_SATYPE2
-+| 1<<SADB_X_EXT_SA2
-+| 1<<SADB_X_EXT_ADDRESS_DST2
-+,
-+/* SADB_X_PCHANGE */
-+1<<SADB_EXT_RESERVED
-+| 1<<SADB_EXT_SA
-+| 1<<SADB_EXT_LIFETIME_CURRENT
-+| 1<<SADB_EXT_LIFETIME_HARD
-+| 1<<SADB_EXT_LIFETIME_SOFT
-+| 1<<SADB_EXT_ADDRESS_SRC
-+| 1<<SADB_EXT_ADDRESS_DST
-+| 1<<SADB_EXT_ADDRESS_PROXY
-+| 1<<SADB_EXT_KEY_AUTH
-+| 1<<SADB_EXT_KEY_ENCRYPT
-+| 1<<SADB_EXT_IDENTITY_SRC
-+| 1<<SADB_EXT_IDENTITY_DST
-+| 1<<SADB_EXT_SENSITIVITY
-+| 1<<SADB_EXT_PROPOSAL
-+| 1<<SADB_EXT_SUPPORTED_AUTH
-+| 1<<SADB_EXT_SUPPORTED_ENCRYPT
-+| 1<<SADB_EXT_SPIRANGE
-+| 1<<SADB_X_EXT_KMPRIVATE
-+| 1<<SADB_X_EXT_SATYPE2
-+| 1<<SADB_X_EXT_SA2
-+| 1<<SADB_X_EXT_ADDRESS_DST2
-+,
-+/* SADB_X_GRPSA */
-+1<<SADB_EXT_RESERVED
-+| 1<<SADB_EXT_SA
-+| 1<<SADB_EXT_ADDRESS_DST
-+,
-+/* SADB_X_ADDFLOW */
-+1<<SADB_EXT_RESERVED
-+| 1<<SADB_EXT_SA
-+| 1<<SADB_EXT_ADDRESS_DST
-+| 1<<SADB_X_EXT_ADDRESS_SRC_FLOW
-+| 1<<SADB_X_EXT_ADDRESS_DST_FLOW
-+| 1<<SADB_X_EXT_ADDRESS_SRC_MASK
-+| 1<<SADB_X_EXT_ADDRESS_DST_MASK
-+,
-+/* SADB_X_DELFLOW */
-+1<<SADB_EXT_RESERVED
-+/*| 1<<SADB_EXT_SA*/
-+| 1<<SADB_X_EXT_ADDRESS_SRC_FLOW
-+| 1<<SADB_X_EXT_ADDRESS_DST_FLOW
-+| 1<<SADB_X_EXT_ADDRESS_SRC_MASK
-+| 1<<SADB_X_EXT_ADDRESS_DST_MASK
-+,
-+/* SADB_X_DEBUG */
-+1<<SADB_EXT_RESERVED
-+| 1<<SADB_X_EXT_DEBUG
-+,
-+/* SADB_X_NAT_T_NEW_MAPPING */
-+1<<SADB_EXT_RESERVED
-+| 1<<SADB_EXT_SA
-+| 1<<SADB_EXT_ADDRESS_SRC
-+| 1<<SADB_EXT_ADDRESS_DST
-+| 1<<SADB_X_EXT_NAT_T_SPORT
-+| 1<<SADB_X_EXT_NAT_T_DPORT
-+}
-+}
-+};
-+
-+/*
-+ * $Log: pfkey_v2_ext_bits.c,v $
-+ * Revision 1.20 2004/03/08 01:59:08 ken
-+ * freeswan.h -> openswan.h
-+ *
-+ * Revision 1.19 2003/12/22 21:38:13 mcr
-+ * removed extraenous #endif.
-+ *
-+ * Revision 1.18 2003/12/22 19:34:41 mcr
-+ * added 0.6c NAT-T patch.
-+ *
-+ * Revision 1.17 2003/12/10 01:20:19 mcr
-+ * NAT-traversal patches to KLIPS.
-+ *
-+ * Revision 1.16 2003/10/31 02:27:12 mcr
-+ * pulled up port-selector patches and sa_id elimination.
-+ *
-+ * Revision 1.15.30.1 2003/09/21 13:59:44 mcr
-+ * pre-liminary X.509 patch - does not yet pass tests.
-+ *
-+ * Revision 1.15 2002/04/24 07:55:32 mcr
-+ * #include patches and Makefiles for post-reorg compilation.
-+ *
-+ * Revision 1.14 2002/04/24 07:36:40 mcr
-+ * Moved from ./lib/pfkey_v2_ext_bits.c,v
-+ *
-+ * Revision 1.13 2002/01/29 22:25:36 rgb
-+ * Re-add ipsec_kversion.h to keep MALLOC happy.
-+ *
-+ * Revision 1.12 2002/01/29 01:59:10 mcr
-+ * removal of kversions.h - sources that needed it now use ipsec_param.h.
-+ * updating of IPv6 structures to match latest in6.h version.
-+ * removed dead code from openswan.h that also duplicated kversions.h
-+ * code.
-+ *
-+ * Revision 1.11 2001/10/18 04:45:24 rgb
-+ * 2.4.9 kernel deprecates linux/malloc.h in favour of linux/slab.h,
-+ * lib/openswan.h version macros moved to lib/kversions.h.
-+ * Other compiler directive cleanups.
-+ *
-+ * Revision 1.10 2001/09/08 21:13:35 rgb
-+ * Added pfkey ident extension support for ISAKMPd. (NetCelo)
-+ *
-+ * Revision 1.9 2001/06/14 19:35:16 rgb
-+ * Update copyright date.
-+ *
-+ * Revision 1.8 2001/03/26 23:07:36 rgb
-+ * Remove requirement for auth and enc key from UPDATE.
-+ *
-+ * Revision 1.7 2000/09/12 22:35:37 rgb
-+ * Restructured to remove unused extensions from CLEARFLOW messages.
-+ *
-+ * Revision 1.6 2000/09/09 06:39:01 rgb
-+ * Added comments for clarity.
-+ *
-+ * Revision 1.5 2000/06/02 22:54:14 rgb
-+ * Added Gerhard Gessler's struct sockaddr_storage mods for IPv6 support.
-+ *
-+ * Revision 1.4 2000/01/21 06:27:56 rgb
-+ * Added address cases for eroute flows.
-+ * Added comments for each message type.
-+ * Added klipsdebug switching capability.
-+ * Fixed GRPSA bitfields.
-+ *
-+ * Revision 1.3 1999/12/01 22:20:27 rgb
-+ * Remove requirement for a proxy address in an incoming getspi message.
-+ *
-+ * Revision 1.2 1999/11/27 11:57:06 rgb
-+ * Consolidated the 4 1-d extension bitmap arrays into one 4-d array.
-+ * Add CVS log entry to bottom of file.
-+ * Cleaned out unused bits.
-+ *
-+ */
---- /dev/null Tue Mar 11 13:02:56 2003
-+++ linux/lib/libfreeswan/pfkey_v2_parse.c Mon Feb 9 13:51:03 2004
-@@ -0,0 +1,1820 @@
-+/*
-+ * RFC2367 PF_KEYv2 Key management API message parser
-+ * Copyright (C) 1999, 2000, 2001 Richard Guy Briggs.
-+ *
-+ * 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. See <http://www.fsf.org/copyleft/gpl.txt>.
-+ *
-+ * 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.
-+ *
-+ * RCSID $Id: pfkey_v2_parse.c,v 1.59 2004/04/18 03:03:49 mcr Exp $
-+ */
-+
-+/*
-+ * Template from klips/net/ipsec/ipsec/ipsec_parser.c.
-+ */
-+
-+char pfkey_v2_parse_c_version[] = "$Id: pfkey_v2_parse.c,v 1.59 2004/04/18 03:03:49 mcr Exp $";
-+
-+/*
-+ * Some ugly stuff to allow consistent debugging code for use in the
-+ * kernel and in user space
-+*/
-+
-+#ifdef __KERNEL__
-+
-+# include <linux/kernel.h> /* for printk */
-+
-+#include "openswan/ipsec_kversion.h" /* for malloc switch */
-+
-+# ifdef MALLOC_SLAB
-+# include <linux/slab.h> /* kmalloc() */
-+# else /* MALLOC_SLAB */
-+# include <linux/malloc.h> /* kmalloc() */
-+# endif /* MALLOC_SLAB */
-+# include <linux/errno.h> /* error codes */
-+# include <linux/types.h> /* size_t */
-+# include <linux/interrupt.h> /* mark_bh */
-+
-+# include <linux/netdevice.h> /* struct device, and other headers */
-+# include <linux/etherdevice.h> /* eth_type_trans */
-+# include <linux/ip.h> /* struct iphdr */
-+# if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
-+# include <linux/ipv6.h> /* struct ipv6hdr */
-+# endif /* if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) */
-+extern int debug_pfkey;
-+
-+# include <openswan.h>
-+
-+#include "openswan/ipsec_encap.h"
-+
-+#else /* __KERNEL__ */
-+
-+# include <sys/types.h>
-+# include <linux/types.h>
-+# include <linux/errno.h>
-+
-+# include <openswan.h>
-+# include "constants.h"
-+# include "programs/pluto/defs.h" /* for PRINTF_LIKE */
-+
-+#endif /* __KERNEL__ */
-+
-+
-+#include <pfkeyv2.h>
-+#include <pfkey.h>
-+
-+#include "openswan/ipsec_sa.h" /* IPSEC_SAREF_NULL, IPSEC_SA_REF_TABLE_IDX_WIDTH */
-+
-+/*
-+ * how to handle debugging for pfkey.
-+ */
-+#include <openswan/pfkey_debug.h>
-+
-+unsigned int pfkey_lib_debug = PF_KEY_DEBUG_PARSE_NONE;
-+void (*pfkey_debug_func)(const char *message, ...) PRINTF_LIKE(1);
-+void (*pfkey_error_func)(const char *message, ...) PRINTF_LIKE(1);
-+
-+
-+#define SENDERR(_x) do { error = -(_x); goto errlab; } while (0)
-+
-+struct satype_tbl {
-+ uint8_t proto;
-+ uint8_t satype;
-+ char* name;
-+} static satype_tbl[] = {
-+#ifdef __KERNEL__
-+ { IPPROTO_ESP, SADB_SATYPE_ESP, "ESP" },
-+ { IPPROTO_AH, SADB_SATYPE_AH, "AH" },
-+ { IPPROTO_IPIP, SADB_X_SATYPE_IPIP, "IPIP" },
-+#ifdef CONFIG_IPSEC_IPCOMP
-+ { IPPROTO_COMP, SADB_X_SATYPE_COMP, "COMP" },
-+#endif /* CONFIG_IPSEC_IPCOMP */
-+ { IPPROTO_INT, SADB_X_SATYPE_INT, "INT" },
-+#else /* __KERNEL__ */
-+ { SA_ESP, SADB_SATYPE_ESP, "ESP" },
-+ { SA_AH, SADB_SATYPE_AH, "AH" },
-+ { SA_IPIP, SADB_X_SATYPE_IPIP, "IPIP" },
-+ { SA_COMP, SADB_X_SATYPE_COMP, "COMP" },
-+ { SA_INT, SADB_X_SATYPE_INT, "INT" },
-+#endif /* __KERNEL__ */
-+ { 0, 0, "UNKNOWN" }
-+};
-+
-+uint8_t
-+satype2proto(uint8_t satype)
-+{
-+ int i =0;
-+
-+ while(satype_tbl[i].satype != satype && satype_tbl[i].satype != 0) {
-+ i++;
-+ }
-+ return satype_tbl[i].proto;
-+}
-+
-+uint8_t
-+proto2satype(uint8_t proto)
-+{
-+ int i = 0;
-+
-+ while(satype_tbl[i].proto != proto && satype_tbl[i].proto != 0) {
-+ i++;
-+ }
-+ return satype_tbl[i].satype;
-+}
-+
-+char*
-+satype2name(uint8_t satype)
-+{
-+ int i = 0;
-+
-+ while(satype_tbl[i].satype != satype && satype_tbl[i].satype != 0) {
-+ i++;
-+ }
-+ return satype_tbl[i].name;
-+}
-+
-+char*
-+proto2name(uint8_t proto)
-+{
-+ int i = 0;
-+
-+ while(satype_tbl[i].proto != proto && satype_tbl[i].proto != 0) {
-+ i++;
-+ }
-+ return satype_tbl[i].name;
-+}
-+
-+/* Default extension parsers taken from the KLIPS code */
-+
-+DEBUG_NO_STATIC int
-+pfkey_sa_parse(struct sadb_ext *pfkey_ext)
-+{
-+ int error = 0;
-+ struct sadb_sa *pfkey_sa = (struct sadb_sa *)pfkey_ext;
-+#if 0
-+ struct sadb_sa sav2;
-+#endif
-+
-+ /* sanity checks... */
-+ if(!pfkey_sa) {
-+ ERROR("pfkey_sa_parse: "
-+ "NULL pointer passed in.\n");
-+ SENDERR(EINVAL);
-+ }
-+
-+#if 0
-+ /* check if this structure is short, and if so, fix it up.
-+ * XXX this is NOT the way to do things.
-+ */
-+ if(pfkey_sa->sadb_sa_len == sizeof(struct sadb_sa_v1)/IPSEC_PFKEYv2_ALIGN) {
-+
-+ /* yes, so clear out a temporary structure, and copy first */
-+ memset(&sav2, 0, sizeof(sav2));
-+ memcpy(&sav2, pfkey_sa, sizeof(struct sadb_sa_v1));
-+ sav2.sadb_x_sa_ref=-1;
-+ sav2.sadb_sa_len = sizeof(struct sadb_sa) / IPSEC_PFKEYv2_ALIGN;
-+
-+ pfkey_sa = &sav2;
-+ }
-+#endif
-+
-+
-+ if(pfkey_sa->sadb_sa_len != sizeof(struct sadb_sa) / IPSEC_PFKEYv2_ALIGN) {
-+ ERROR(
-+ "pfkey_sa_parse: "
-+ "length wrong pfkey_sa->sadb_sa_len=%d sizeof(struct sadb_sa)=%d.\n",
-+ pfkey_sa->sadb_sa_len,
-+ (int)sizeof(struct sadb_sa));
-+ SENDERR(EINVAL);
-+ }
-+
-+ if(pfkey_sa->sadb_sa_encrypt > SADB_EALG_MAX) {
-+ ERROR(
-+ "pfkey_sa_parse: "
-+ "pfkey_sa->sadb_sa_encrypt=%d > SADB_EALG_MAX=%d.\n",
-+ pfkey_sa->sadb_sa_encrypt,
-+ SADB_EALG_MAX);
-+ SENDERR(EINVAL);
-+ }
-+
-+ if(pfkey_sa->sadb_sa_auth > SADB_AALG_MAX) {
-+ ERROR(
-+ "pfkey_sa_parse: "
-+ "pfkey_sa->sadb_sa_auth=%d > SADB_AALG_MAX=%d.\n",
-+ pfkey_sa->sadb_sa_auth,
-+ SADB_AALG_MAX);
-+ SENDERR(EINVAL);
-+ }
-+
-+ if(pfkey_sa->sadb_sa_state > SADB_SASTATE_MAX) {
-+ ERROR(
-+ "pfkey_sa_parse: "
-+ "state=%d exceeds MAX=%d.\n",
-+ pfkey_sa->sadb_sa_state,
-+ SADB_SASTATE_MAX);
-+ SENDERR(EINVAL);
-+ }
-+
-+ if(pfkey_sa->sadb_sa_state == SADB_SASTATE_DEAD) {
-+ ERROR(
-+ "pfkey_sa_parse: "
-+ "state=%d is DEAD=%d.\n",
-+ pfkey_sa->sadb_sa_state,
-+ SADB_SASTATE_DEAD);
-+ SENDERR(EINVAL);
-+ }
-+
-+ if(pfkey_sa->sadb_sa_replay > 64) {
-+ ERROR(
-+ "pfkey_sa_parse: "
-+ "replay window size: %d -- must be 0 <= size <= 64\n",
-+ pfkey_sa->sadb_sa_replay);
-+ SENDERR(EINVAL);
-+ }
-+
-+ if(! ((pfkey_sa->sadb_sa_exttype == SADB_EXT_SA) ||
-+ (pfkey_sa->sadb_sa_exttype == SADB_X_EXT_SA2)))
-+ {
-+ ERROR(
-+ "pfkey_sa_parse: "
-+ "unknown exttype=%d, expecting SADB_EXT_SA=%d or SADB_X_EXT_SA2=%d.\n",
-+ pfkey_sa->sadb_sa_exttype,
-+ SADB_EXT_SA,
-+ SADB_X_EXT_SA2);
-+ SENDERR(EINVAL);
-+ }
-+
-+ if((IPSEC_SAREF_NULL != pfkey_sa->sadb_x_sa_ref) && (pfkey_sa->sadb_x_sa_ref >= (1 << IPSEC_SA_REF_TABLE_IDX_WIDTH))) {
-+ ERROR(
-+ "pfkey_sa_parse: "
-+ "SAref=%d must be (SAref == IPSEC_SAREF_NULL(%d) || SAref < IPSEC_SA_REF_TABLE_NUM_ENTRIES(%d)).\n",
-+ pfkey_sa->sadb_x_sa_ref,
-+ IPSEC_SAREF_NULL,
-+ IPSEC_SA_REF_TABLE_NUM_ENTRIES);
-+ SENDERR(EINVAL);
-+ }
-+
-+ DEBUGGING(PF_KEY_DEBUG_PARSE_STRUCT,
-+ "pfkey_sa_parse: "
-+ "successfully found len=%d exttype=%d(%s) spi=%08lx replay=%d state=%d auth=%d encrypt=%d flags=%d ref=%d.\n",
-+ pfkey_sa->sadb_sa_len,
-+ pfkey_sa->sadb_sa_exttype,
-+ pfkey_v2_sadb_ext_string(pfkey_sa->sadb_sa_exttype),
-+ (long unsigned int)ntohl(pfkey_sa->sadb_sa_spi),
-+ pfkey_sa->sadb_sa_replay,
-+ pfkey_sa->sadb_sa_state,
-+ pfkey_sa->sadb_sa_auth,
-+ pfkey_sa->sadb_sa_encrypt,
-+ pfkey_sa->sadb_sa_flags,
-+ pfkey_sa->sadb_x_sa_ref);
-+
-+ errlab:
-+ return error;
-+}
-+
-+DEBUG_NO_STATIC int
-+pfkey_lifetime_parse(struct sadb_ext *pfkey_ext)
-+{
-+ int error = 0;
-+ struct sadb_lifetime *pfkey_lifetime = (struct sadb_lifetime *)pfkey_ext;
-+
-+ DEBUGGING(PF_KEY_DEBUG_PARSE_FLOW,
-+ "pfkey_lifetime_parse:enter\n");
-+ /* sanity checks... */
-+ if(!pfkey_lifetime) {
-+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
-+ "pfkey_lifetime_parse: "
-+ "NULL pointer passed in.\n");
-+ SENDERR(EINVAL);
-+ }
-+
-+ if(pfkey_lifetime->sadb_lifetime_len !=
-+ sizeof(struct sadb_lifetime) / IPSEC_PFKEYv2_ALIGN) {
-+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
-+ "pfkey_lifetime_parse: "
-+ "length wrong pfkey_lifetime->sadb_lifetime_len=%d sizeof(struct sadb_lifetime)=%d.\n",
-+ pfkey_lifetime->sadb_lifetime_len,
-+ (int)sizeof(struct sadb_lifetime));
-+ SENDERR(EINVAL);
-+ }
-+
-+ if((pfkey_lifetime->sadb_lifetime_exttype != SADB_EXT_LIFETIME_HARD) &&
-+ (pfkey_lifetime->sadb_lifetime_exttype != SADB_EXT_LIFETIME_SOFT) &&
-+ (pfkey_lifetime->sadb_lifetime_exttype != SADB_EXT_LIFETIME_CURRENT)) {
-+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
-+ "pfkey_lifetime_parse: "
-+ "unexpected ext_type=%d.\n",
-+ pfkey_lifetime->sadb_lifetime_exttype);
-+ SENDERR(EINVAL);
-+ }
-+
-+ DEBUGGING(PF_KEY_DEBUG_PARSE_STRUCT,
-+ "pfkey_lifetime_parse: "
-+ "life_type=%d(%s) alloc=%u bytes=%u add=%u use=%u pkts=%u.\n",
-+ pfkey_lifetime->sadb_lifetime_exttype,
-+ pfkey_v2_sadb_ext_string(pfkey_lifetime->sadb_lifetime_exttype),
-+ pfkey_lifetime->sadb_lifetime_allocations,
-+ (unsigned)pfkey_lifetime->sadb_lifetime_bytes,
-+ (unsigned)pfkey_lifetime->sadb_lifetime_addtime,
-+ (unsigned)pfkey_lifetime->sadb_lifetime_usetime,
-+ pfkey_lifetime->sadb_x_lifetime_packets);
-+errlab:
-+ return error;
-+}
-+
-+DEBUG_NO_STATIC int
-+pfkey_address_parse(struct sadb_ext *pfkey_ext)
-+{
-+ int error = 0;
-+ int saddr_len = 0;
-+ struct sadb_address *pfkey_address = (struct sadb_address *)pfkey_ext;
-+ struct sockaddr* s = (struct sockaddr*)((char*)pfkey_address + sizeof(*pfkey_address));
-+ char ipaddr_txt[ADDRTOT_BUF];
-+
-+ /* sanity checks... */
-+ if(!pfkey_address) {
-+ ERROR(
-+ "pfkey_address_parse: "
-+ "NULL pointer passed in.\n");
-+ SENDERR(EINVAL);
-+ }
-+
-+ if(pfkey_address->sadb_address_len <
-+ (sizeof(struct sadb_address) + sizeof(struct sockaddr))/
-+ IPSEC_PFKEYv2_ALIGN) {
-+ ERROR("pfkey_address_parse: "
-+ "size wrong 1 ext_len=%d, adr_ext_len=%d, saddr_len=%d.\n",
-+ pfkey_address->sadb_address_len,
-+ (int)sizeof(struct sadb_address),
-+ (int)sizeof(struct sockaddr));
-+ SENDERR(EINVAL);
-+ }
-+
-+ if(pfkey_address->sadb_address_reserved) {
-+ ERROR("pfkey_address_parse: "
-+ "res=%d, must be zero.\n",
-+ pfkey_address->sadb_address_reserved);
-+ SENDERR(EINVAL);
-+ }
-+
-+ switch(pfkey_address->sadb_address_exttype) {
-+ case SADB_EXT_ADDRESS_SRC:
-+ case SADB_EXT_ADDRESS_DST:
-+ case SADB_EXT_ADDRESS_PROXY:
-+ case SADB_X_EXT_ADDRESS_DST2:
-+ case SADB_X_EXT_ADDRESS_SRC_FLOW:
-+ case SADB_X_EXT_ADDRESS_DST_FLOW:
-+ case SADB_X_EXT_ADDRESS_SRC_MASK:
-+ case SADB_X_EXT_ADDRESS_DST_MASK:
-+#ifdef NAT_TRAVERSAL
-+ case SADB_X_EXT_NAT_T_OA:
-+#endif
-+ break;
-+ default:
-+ ERROR(
-+ "pfkey_address_parse: "
-+ "unexpected ext_type=%d.\n",
-+ pfkey_address->sadb_address_exttype);
-+ SENDERR(EINVAL);
-+ }
-+
-+ switch(s->sa_family) {
-+ case AF_INET:
-+ saddr_len = sizeof(struct sockaddr_in);
-+ sprintf(ipaddr_txt, "%d.%d.%d.%d"
-+ , (((struct sockaddr_in*)s)->sin_addr.s_addr >> 0) & 0xFF
-+ , (((struct sockaddr_in*)s)->sin_addr.s_addr >> 8) & 0xFF
-+ , (((struct sockaddr_in*)s)->sin_addr.s_addr >> 16) & 0xFF
-+ , (((struct sockaddr_in*)s)->sin_addr.s_addr >> 24) & 0xFF);
-+ DEBUGGING(PF_KEY_DEBUG_PARSE_STRUCT,
-+ "pfkey_address_parse: "
-+ "found exttype=%u(%s) family=%d(AF_INET) address=%s proto=%u port=%u.\n",
-+ pfkey_address->sadb_address_exttype,
-+ pfkey_v2_sadb_ext_string(pfkey_address->sadb_address_exttype),
-+ s->sa_family,
-+ ipaddr_txt,
-+ pfkey_address->sadb_address_proto,
-+ ntohs(((struct sockaddr_in*)s)->sin_port));
-+ break;
-+ case AF_INET6:
-+ saddr_len = sizeof(struct sockaddr_in6);
-+ sprintf(ipaddr_txt, "%x:%x:%x:%x:%x:%x:%x:%x"
-+ , ntohs(((struct sockaddr_in6*)s)->sin6_addr.s6_addr16[0])
-+ , ntohs(((struct sockaddr_in6*)s)->sin6_addr.s6_addr16[1])
-+ , ntohs(((struct sockaddr_in6*)s)->sin6_addr.s6_addr16[2])
-+ , ntohs(((struct sockaddr_in6*)s)->sin6_addr.s6_addr16[3])
-+ , ntohs(((struct sockaddr_in6*)s)->sin6_addr.s6_addr16[4])
-+ , ntohs(((struct sockaddr_in6*)s)->sin6_addr.s6_addr16[5])
-+ , ntohs(((struct sockaddr_in6*)s)->sin6_addr.s6_addr16[6])
-+ , ntohs(((struct sockaddr_in6*)s)->sin6_addr.s6_addr16[7]));
-+ DEBUGGING(PF_KEY_DEBUG_PARSE_STRUCT,
-+ "pfkey_address_parse: "
-+ "found exttype=%u(%s) family=%d(AF_INET6) address=%s proto=%u port=%u.\n",
-+ pfkey_address->sadb_address_exttype,
-+ pfkey_v2_sadb_ext_string(pfkey_address->sadb_address_exttype),
-+ s->sa_family,
-+ ipaddr_txt,
-+ pfkey_address->sadb_address_proto,
-+ ((struct sockaddr_in6*)s)->sin6_port);
-+ break;
-+ default:
-+ ERROR(
-+ "pfkey_address_parse: "
-+ "s->sa_family=%d not supported.\n",
-+ s->sa_family);
-+ SENDERR(EPFNOSUPPORT);
-+ }
-+
-+ if(pfkey_address->sadb_address_len !=
-+ DIVUP(sizeof(struct sadb_address) + saddr_len, IPSEC_PFKEYv2_ALIGN)) {
-+ ERROR(
-+ "pfkey_address_parse: "
-+ "size wrong 2 ext_len=%d, adr_ext_len=%d, saddr_len=%d.\n",
-+ pfkey_address->sadb_address_len,
-+ (int)sizeof(struct sadb_address),
-+ saddr_len);
-+ SENDERR(EINVAL);
-+ }
-+
-+ if(pfkey_address->sadb_address_prefixlen != 0) {
-+ ERROR(
-+ "pfkey_address_parse: "
-+ "address prefixes not supported yet.\n");
-+ SENDERR(EAFNOSUPPORT); /* not supported yet */
-+ }
-+
-+ /* XXX check if port!=0 */
-+
-+ DEBUGGING(PF_KEY_DEBUG_PARSE_FLOW,
-+ "pfkey_address_parse: successful.\n");
-+ errlab:
-+ return error;
-+}
-+
-+DEBUG_NO_STATIC int
-+pfkey_key_parse(struct sadb_ext *pfkey_ext)
-+{
-+ int error = 0;
-+ struct sadb_key *pfkey_key = (struct sadb_key *)pfkey_ext;
-+
-+ /* sanity checks... */
-+
-+ if(!pfkey_key) {
-+ ERROR(
-+ "pfkey_key_parse: "
-+ "NULL pointer passed in.\n");
-+ SENDERR(EINVAL);
-+ }
-+
-+ if(pfkey_key->sadb_key_len < sizeof(struct sadb_key) / IPSEC_PFKEYv2_ALIGN) {
-+ ERROR(
-+ "pfkey_key_parse: "
-+ "size wrong ext_len=%d, key_ext_len=%d.\n",
-+ pfkey_key->sadb_key_len,
-+ (int)sizeof(struct sadb_key));
-+ SENDERR(EINVAL);
-+ }
-+
-+ if(!pfkey_key->sadb_key_bits) {
-+ ERROR(
-+ "pfkey_key_parse: "
-+ "key length set to zero, must be non-zero.\n");
-+ SENDERR(EINVAL);
-+ }
-+
-+ if(pfkey_key->sadb_key_len !=
-+ DIVUP(sizeof(struct sadb_key) * OCTETBITS + pfkey_key->sadb_key_bits,
-+ PFKEYBITS)) {
-+ ERROR(
-+ "pfkey_key_parse: "
-+ "key length=%d does not agree with extension length=%d.\n",
-+ pfkey_key->sadb_key_bits,
-+ pfkey_key->sadb_key_len);
-+ SENDERR(EINVAL);
-+ }
-+
-+ if(pfkey_key->sadb_key_reserved) {
-+ ERROR(
-+ "pfkey_key_parse: "
-+ "res=%d, must be zero.\n",
-+ pfkey_key->sadb_key_reserved);
-+ SENDERR(EINVAL);
-+ }
-+
-+ if(! ( (pfkey_key->sadb_key_exttype == SADB_EXT_KEY_AUTH) ||
-+ (pfkey_key->sadb_key_exttype == SADB_EXT_KEY_ENCRYPT))) {
-+ ERROR(
-+ "pfkey_key_parse: "
-+ "expecting extension type AUTH or ENCRYPT, got %d.\n",
-+ pfkey_key->sadb_key_exttype);
-+ SENDERR(EINVAL);
-+ }
-+
-+ DEBUGGING(PF_KEY_DEBUG_PARSE_STRUCT,
-+ "pfkey_key_parse: "
-+ "success, found len=%d exttype=%d(%s) bits=%d reserved=%d.\n",
-+ pfkey_key->sadb_key_len,
-+ pfkey_key->sadb_key_exttype,
-+ pfkey_v2_sadb_ext_string(pfkey_key->sadb_key_exttype),
-+ pfkey_key->sadb_key_bits,
-+ pfkey_key->sadb_key_reserved);
-+
-+errlab:
-+ return error;
-+}
-+
-+DEBUG_NO_STATIC int
-+pfkey_ident_parse(struct sadb_ext *pfkey_ext)
-+{
-+ int error = 0;
-+ struct sadb_ident *pfkey_ident = (struct sadb_ident *)pfkey_ext;
-+
-+ /* sanity checks... */
-+ if(pfkey_ident->sadb_ident_len < sizeof(struct sadb_ident) / IPSEC_PFKEYv2_ALIGN) {
-+ ERROR(
-+ "pfkey_ident_parse: "
-+ "size wrong ext_len=%d, key_ext_len=%d.\n",
-+ pfkey_ident->sadb_ident_len,
-+ (int)sizeof(struct sadb_ident));
-+ SENDERR(EINVAL);
-+ }
-+
-+ if(pfkey_ident->sadb_ident_type > SADB_IDENTTYPE_MAX) {
-+ ERROR(
-+ "pfkey_ident_parse: "
-+ "ident_type=%d out of range, must be less than %d.\n",
-+ pfkey_ident->sadb_ident_type,
-+ SADB_IDENTTYPE_MAX);
-+ SENDERR(EINVAL);
-+ }
-+
-+ if(pfkey_ident->sadb_ident_reserved) {
-+ ERROR(
-+ "pfkey_ident_parse: "
-+ "res=%d, must be zero.\n",
-+ pfkey_ident->sadb_ident_reserved);
-+ SENDERR(EINVAL);
-+ }
-+
-+ /* string terminator/padding must be zero */
-+ if(pfkey_ident->sadb_ident_len > sizeof(struct sadb_ident) / IPSEC_PFKEYv2_ALIGN) {
-+ if(*((char*)pfkey_ident + pfkey_ident->sadb_ident_len * IPSEC_PFKEYv2_ALIGN - 1)) {
-+ ERROR(
-+ "pfkey_ident_parse: "
-+ "string padding must be zero, last is 0x%02x.\n",
-+ *((char*)pfkey_ident +
-+ pfkey_ident->sadb_ident_len * IPSEC_PFKEYv2_ALIGN - 1));
-+ SENDERR(EINVAL);
-+ }
-+ }
-+
-+ if( ! ((pfkey_ident->sadb_ident_exttype == SADB_EXT_IDENTITY_SRC) ||
-+ (pfkey_ident->sadb_ident_exttype == SADB_EXT_IDENTITY_DST))) {
-+ ERROR(
-+ "pfkey_key_parse: "
-+ "expecting extension type IDENTITY_SRC or IDENTITY_DST, got %d.\n",
-+ pfkey_ident->sadb_ident_exttype);
-+ SENDERR(EINVAL);
-+ }
-+
-+errlab:
-+ return error;
-+}
-+
-+DEBUG_NO_STATIC int
-+pfkey_sens_parse(struct sadb_ext *pfkey_ext)
-+{
-+ int error = 0;
-+ struct sadb_sens *pfkey_sens = (struct sadb_sens *)pfkey_ext;
-+
-+ /* sanity checks... */
-+ if(pfkey_sens->sadb_sens_len < sizeof(struct sadb_sens) / IPSEC_PFKEYv2_ALIGN) {
-+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
-+ "pfkey_sens_parse: "
-+ "size wrong ext_len=%d, key_ext_len=%d.\n",
-+ pfkey_sens->sadb_sens_len,
-+ (int)sizeof(struct sadb_sens));
-+ SENDERR(EINVAL);
-+ }
-+
-+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
-+ "pfkey_sens_parse: "
-+ "Sorry, I can't parse exttype=%d yet.\n",
-+ pfkey_ext->sadb_ext_type);
-+#if 0
-+ SENDERR(EINVAL); /* don't process these yet */
-+#endif
-+
-+errlab:
-+ return error;
-+}
-+
-+DEBUG_NO_STATIC int
-+pfkey_prop_parse(struct sadb_ext *pfkey_ext)
-+{
-+ int error = 0;
-+ int i, num_comb;
-+ struct sadb_prop *pfkey_prop = (struct sadb_prop *)pfkey_ext;
-+ struct sadb_comb *pfkey_comb = (struct sadb_comb *)((char*)pfkey_ext + sizeof(struct sadb_prop));
-+
-+ /* sanity checks... */
-+ if((pfkey_prop->sadb_prop_len < sizeof(struct sadb_prop) / IPSEC_PFKEYv2_ALIGN) ||
-+ (((pfkey_prop->sadb_prop_len * IPSEC_PFKEYv2_ALIGN) - sizeof(struct sadb_prop)) % sizeof(struct sadb_comb))) {
-+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
-+ "pfkey_prop_parse: "
-+ "size wrong ext_len=%d, prop_ext_len=%d comb_ext_len=%d.\n",
-+ pfkey_prop->sadb_prop_len,
-+ (int)sizeof(struct sadb_prop),
-+ (int)sizeof(struct sadb_comb));
-+ SENDERR(EINVAL);
-+ }
-+
-+ if(pfkey_prop->sadb_prop_replay > 64) {
-+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
-+ "pfkey_prop_parse: "
-+ "replay window size: %d -- must be 0 <= size <= 64\n",
-+ pfkey_prop->sadb_prop_replay);
-+ SENDERR(EINVAL);
-+ }
-+
-+ for(i=0; i<3; i++) {
-+ if(pfkey_prop->sadb_prop_reserved[i]) {
-+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
-+ "pfkey_prop_parse: "
-+ "res[%d]=%d, must be zero.\n",
-+ i, pfkey_prop->sadb_prop_reserved[i]);
-+ SENDERR(EINVAL);
-+ }
-+ }
-+
-+ num_comb = ((pfkey_prop->sadb_prop_len * IPSEC_PFKEYv2_ALIGN) - sizeof(struct sadb_prop)) / sizeof(struct sadb_comb);
-+
-+ for(i = 0; i < num_comb; i++) {
-+ if(pfkey_comb->sadb_comb_auth > SADB_AALG_MAX) {
-+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
-+ "pfkey_prop_parse: "
-+ "pfkey_comb[%d]->sadb_comb_auth=%d > SADB_AALG_MAX=%d.\n",
-+ i,
-+ pfkey_comb->sadb_comb_auth,
-+ SADB_AALG_MAX);
-+ SENDERR(EINVAL);
-+ }
-+
-+ if(pfkey_comb->sadb_comb_auth) {
-+ if(!pfkey_comb->sadb_comb_auth_minbits) {
-+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
-+ "pfkey_prop_parse: "
-+ "pfkey_comb[%d]->sadb_comb_auth_minbits=0, fatal.\n",
-+ i);
-+ SENDERR(EINVAL);
-+ }
-+ if(!pfkey_comb->sadb_comb_auth_maxbits) {
-+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
-+ "pfkey_prop_parse: "
-+ "pfkey_comb[%d]->sadb_comb_auth_maxbits=0, fatal.\n",
-+ i);
-+ SENDERR(EINVAL);
-+ }
-+ if(pfkey_comb->sadb_comb_auth_minbits > pfkey_comb->sadb_comb_auth_maxbits) {
-+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
-+ "pfkey_prop_parse: "
-+ "pfkey_comb[%d]->sadb_comb_auth_minbits=%d > maxbits=%d, fatal.\n",
-+ i,
-+ pfkey_comb->sadb_comb_auth_minbits,
-+ pfkey_comb->sadb_comb_auth_maxbits);
-+ SENDERR(EINVAL);
-+ }
-+ } else {
-+ if(pfkey_comb->sadb_comb_auth_minbits) {
-+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
-+ "pfkey_prop_parse: "
-+ "pfkey_comb[%d]->sadb_comb_auth_minbits=%d != 0, fatal.\n",
-+ i,
-+ pfkey_comb->sadb_comb_auth_minbits);
-+ SENDERR(EINVAL);
-+ }
-+ if(pfkey_comb->sadb_comb_auth_maxbits) {
-+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
-+ "pfkey_prop_parse: "
-+ "pfkey_comb[%d]->sadb_comb_auth_maxbits=%d != 0, fatal.\n",
-+ i,
-+ pfkey_comb->sadb_comb_auth_maxbits);
-+ SENDERR(EINVAL);
-+ }
-+ }
-+
-+ if(pfkey_comb->sadb_comb_encrypt > SADB_EALG_MAX) {
-+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
-+ "pfkey_comb_parse: "
-+ "pfkey_comb[%d]->sadb_comb_encrypt=%d > SADB_EALG_MAX=%d.\n",
-+ i,
-+ pfkey_comb->sadb_comb_encrypt,
-+ SADB_EALG_MAX);
-+ SENDERR(EINVAL);
-+ }
-+
-+ if(pfkey_comb->sadb_comb_encrypt) {
-+ if(!pfkey_comb->sadb_comb_encrypt_minbits) {
-+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
-+ "pfkey_prop_parse: "
-+ "pfkey_comb[%d]->sadb_comb_encrypt_minbits=0, fatal.\n",
-+ i);
-+ SENDERR(EINVAL);
-+ }
-+ if(!pfkey_comb->sadb_comb_encrypt_maxbits) {
-+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
-+ "pfkey_prop_parse: "
-+ "pfkey_comb[%d]->sadb_comb_encrypt_maxbits=0, fatal.\n",
-+ i);
-+ SENDERR(EINVAL);
-+ }
-+ if(pfkey_comb->sadb_comb_encrypt_minbits > pfkey_comb->sadb_comb_encrypt_maxbits) {
-+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
-+ "pfkey_prop_parse: "
-+ "pfkey_comb[%d]->sadb_comb_encrypt_minbits=%d > maxbits=%d, fatal.\n",
-+ i,
-+ pfkey_comb->sadb_comb_encrypt_minbits,
-+ pfkey_comb->sadb_comb_encrypt_maxbits);
-+ SENDERR(EINVAL);
-+ }
-+ } else {
-+ if(pfkey_comb->sadb_comb_encrypt_minbits) {
-+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
-+ "pfkey_prop_parse: "
-+ "pfkey_comb[%d]->sadb_comb_encrypt_minbits=%d != 0, fatal.\n",
-+ i,
-+ pfkey_comb->sadb_comb_encrypt_minbits);
-+ SENDERR(EINVAL);
-+ }
-+ if(pfkey_comb->sadb_comb_encrypt_maxbits) {
-+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
-+ "pfkey_prop_parse: "
-+ "pfkey_comb[%d]->sadb_comb_encrypt_maxbits=%d != 0, fatal.\n",
-+ i,
-+ pfkey_comb->sadb_comb_encrypt_maxbits);
-+ SENDERR(EINVAL);
-+ }
-+ }
-+
-+ /* XXX do sanity check on flags */
-+
-+ if(pfkey_comb->sadb_comb_hard_allocations && pfkey_comb->sadb_comb_soft_allocations > pfkey_comb->sadb_comb_hard_allocations) {
-+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
-+ "pfkey_prop_parse: "
-+ "pfkey_comb[%d]->sadb_comb_soft_allocations=%d > hard_allocations=%d, fatal.\n",
-+ i,
-+ pfkey_comb->sadb_comb_soft_allocations,
-+ pfkey_comb->sadb_comb_hard_allocations);
-+ SENDERR(EINVAL);
-+ }
-+
-+ if(pfkey_comb->sadb_comb_hard_bytes && pfkey_comb->sadb_comb_soft_bytes > pfkey_comb->sadb_comb_hard_bytes) {
-+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
-+ "pfkey_prop_parse: "
-+ "pfkey_comb[%d]->sadb_comb_soft_bytes=%Ld > hard_bytes=%Ld, fatal.\n",
-+ i,
-+ (unsigned long long int)pfkey_comb->sadb_comb_soft_bytes,
-+ (unsigned long long int)pfkey_comb->sadb_comb_hard_bytes);
-+ SENDERR(EINVAL);
-+ }
-+
-+ if(pfkey_comb->sadb_comb_hard_addtime && pfkey_comb->sadb_comb_soft_addtime > pfkey_comb->sadb_comb_hard_addtime) {
-+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
-+ "pfkey_prop_parse: "
-+ "pfkey_comb[%d]->sadb_comb_soft_addtime=%Ld > hard_addtime=%Ld, fatal.\n",
-+ i,
-+ (unsigned long long int)pfkey_comb->sadb_comb_soft_addtime,
-+ (unsigned long long int)pfkey_comb->sadb_comb_hard_addtime);
-+ SENDERR(EINVAL);
-+ }
-+
-+ if(pfkey_comb->sadb_comb_hard_usetime && pfkey_comb->sadb_comb_soft_usetime > pfkey_comb->sadb_comb_hard_usetime) {
-+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
-+ "pfkey_prop_parse: "
-+ "pfkey_comb[%d]->sadb_comb_soft_usetime=%Ld > hard_usetime=%Ld, fatal.\n",
-+ i,
-+ (unsigned long long int)pfkey_comb->sadb_comb_soft_usetime,
-+ (unsigned long long int)pfkey_comb->sadb_comb_hard_usetime);
-+ SENDERR(EINVAL);
-+ }
-+
-+ if(pfkey_comb->sadb_x_comb_hard_packets && pfkey_comb->sadb_x_comb_soft_packets > pfkey_comb->sadb_x_comb_hard_packets) {
-+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
-+ "pfkey_prop_parse: "
-+ "pfkey_comb[%d]->sadb_x_comb_soft_packets=%d > hard_packets=%d, fatal.\n",
-+ i,
-+ pfkey_comb->sadb_x_comb_soft_packets,
-+ pfkey_comb->sadb_x_comb_hard_packets);
-+ SENDERR(EINVAL);
-+ }
-+
-+ if(pfkey_comb->sadb_comb_reserved) {
-+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
-+ "pfkey_prop_parse: "
-+ "comb[%d].res=%d, must be zero.\n",
-+ i,
-+ pfkey_comb->sadb_comb_reserved);
-+ SENDERR(EINVAL);
-+ }
-+ pfkey_comb++;
-+ }
-+
-+errlab:
-+ return error;
-+}
-+
-+DEBUG_NO_STATIC int
-+pfkey_supported_parse(struct sadb_ext *pfkey_ext)
-+{
-+ int error = 0;
-+ unsigned int i, num_alg;
-+ struct sadb_supported *pfkey_supported = (struct sadb_supported *)pfkey_ext;
-+ struct sadb_alg *pfkey_alg = (struct sadb_alg*)((char*)pfkey_ext + sizeof(struct sadb_supported));
-+
-+ /* sanity checks... */
-+ if((pfkey_supported->sadb_supported_len <
-+ sizeof(struct sadb_supported) / IPSEC_PFKEYv2_ALIGN) ||
-+ (((pfkey_supported->sadb_supported_len * IPSEC_PFKEYv2_ALIGN) -
-+ sizeof(struct sadb_supported)) % sizeof(struct sadb_alg))) {
-+
-+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
-+ "pfkey_supported_parse: "
-+ "size wrong ext_len=%d, supported_ext_len=%d alg_ext_len=%d.\n",
-+ pfkey_supported->sadb_supported_len,
-+ (int)sizeof(struct sadb_supported),
-+ (int)sizeof(struct sadb_alg));
-+ SENDERR(EINVAL);
-+ }
-+
-+ if(pfkey_supported->sadb_supported_reserved) {
-+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
-+ "pfkey_supported_parse: "
-+ "res=%d, must be zero.\n",
-+ pfkey_supported->sadb_supported_reserved);
-+ SENDERR(EINVAL);
-+ }
-+
-+ num_alg = ((pfkey_supported->sadb_supported_len * IPSEC_PFKEYv2_ALIGN) - sizeof(struct sadb_supported)) / sizeof(struct sadb_alg);
-+
-+ for(i = 0; i < num_alg; i++) {
-+ /* process algo description */
-+ if(pfkey_alg->sadb_alg_reserved) {
-+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
-+ "pfkey_supported_parse: "
-+ "alg[%d], id=%d, ivlen=%d, minbits=%d, maxbits=%d, res=%d, must be zero.\n",
-+ i,
-+ pfkey_alg->sadb_alg_id,
-+ pfkey_alg->sadb_alg_ivlen,
-+ pfkey_alg->sadb_alg_minbits,
-+ pfkey_alg->sadb_alg_maxbits,
-+ pfkey_alg->sadb_alg_reserved);
-+ SENDERR(EINVAL);
-+ }
-+
-+ /* XXX can alg_id auth/enc be determined from info given?
-+ Yes, but OpenBSD's method does not iteroperate with rfc2367.
-+ rgb, 2000-04-06 */
-+
-+ switch(pfkey_supported->sadb_supported_exttype) {
-+ case SADB_EXT_SUPPORTED_AUTH:
-+ if(pfkey_alg->sadb_alg_id > SADB_AALG_MAX) {
-+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
-+ "pfkey_supported_parse: "
-+ "alg[%d], alg_id=%d > SADB_AALG_MAX=%d, fatal.\n",
-+ i,
-+ pfkey_alg->sadb_alg_id,
-+ SADB_AALG_MAX);
-+ SENDERR(EINVAL);
-+ }
-+ break;
-+ case SADB_EXT_SUPPORTED_ENCRYPT:
-+ if(pfkey_alg->sadb_alg_id > SADB_EALG_MAX) {
-+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
-+ "pfkey_supported_parse: "
-+ "alg[%d], alg_id=%d > SADB_EALG_MAX=%d, fatal.\n",
-+ i,
-+ pfkey_alg->sadb_alg_id,
-+ SADB_EALG_MAX);
-+ SENDERR(EINVAL);
-+ }
-+ break;
-+ default:
-+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
-+ "pfkey_supported_parse: "
-+ "alg[%d], alg_id=%d > SADB_EALG_MAX=%d, fatal.\n",
-+ i,
-+ pfkey_alg->sadb_alg_id,
-+ SADB_EALG_MAX);
-+ SENDERR(EINVAL);
-+ }
-+ pfkey_alg++;
-+ }
-+
-+ errlab:
-+ return error;
-+}
-+
-+DEBUG_NO_STATIC int
-+pfkey_spirange_parse(struct sadb_ext *pfkey_ext)
-+{
-+ int error = 0;
-+ struct sadb_spirange *pfkey_spirange = (struct sadb_spirange *)pfkey_ext;
-+
-+ /* sanity checks... */
-+ if(pfkey_spirange->sadb_spirange_len !=
-+ sizeof(struct sadb_spirange) / IPSEC_PFKEYv2_ALIGN) {
-+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
-+ "pfkey_spirange_parse: "
-+ "size wrong ext_len=%d, key_ext_len=%d.\n",
-+ pfkey_spirange->sadb_spirange_len,
-+ (int)sizeof(struct sadb_spirange));
-+ SENDERR(EINVAL);
-+ }
-+
-+ if(pfkey_spirange->sadb_spirange_reserved) {
-+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
-+ "pfkey_spirange_parse: "
-+ "reserved=%d must be set to zero.\n",
-+ pfkey_spirange->sadb_spirange_reserved);
-+ SENDERR(EINVAL);
-+ }
-+
-+ if(ntohl(pfkey_spirange->sadb_spirange_max) < ntohl(pfkey_spirange->sadb_spirange_min)) {
-+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
-+ "pfkey_spirange_parse: "
-+ "minspi=%08x must be < maxspi=%08x.\n",
-+ ntohl(pfkey_spirange->sadb_spirange_min),
-+ ntohl(pfkey_spirange->sadb_spirange_max));
-+ SENDERR(EINVAL);
-+ }
-+
-+ if(ntohl(pfkey_spirange->sadb_spirange_min) <= 255) {
-+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
-+ "pfkey_spirange_parse: "
-+ "minspi=%08x must be > 255.\n",
-+ ntohl(pfkey_spirange->sadb_spirange_min));
-+ SENDERR(EEXIST);
-+ }
-+
-+ DEBUGGING(PF_KEY_DEBUG_PARSE_STRUCT,
-+ "pfkey_spirange_parse: "
-+ "ext_len=%u ext_type=%u(%s) min=%u max=%u res=%u.\n",
-+ pfkey_spirange->sadb_spirange_len,
-+ pfkey_spirange->sadb_spirange_exttype,
-+ pfkey_v2_sadb_ext_string(pfkey_spirange->sadb_spirange_exttype),
-+ pfkey_spirange->sadb_spirange_min,
-+ pfkey_spirange->sadb_spirange_max,
-+ pfkey_spirange->sadb_spirange_reserved);
-+ errlab:
-+ return error;
-+}
-+
-+DEBUG_NO_STATIC int
-+pfkey_x_kmprivate_parse(struct sadb_ext *pfkey_ext)
-+{
-+ int error = 0;
-+ struct sadb_x_kmprivate *pfkey_x_kmprivate = (struct sadb_x_kmprivate *)pfkey_ext;
-+
-+ /* sanity checks... */
-+ if(pfkey_x_kmprivate->sadb_x_kmprivate_len <
-+ sizeof(struct sadb_x_kmprivate) / IPSEC_PFKEYv2_ALIGN) {
-+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
-+ "pfkey_x_kmprivate_parse: "
-+ "size wrong ext_len=%d, key_ext_len=%d.\n",
-+ pfkey_x_kmprivate->sadb_x_kmprivate_len,
-+ (int)sizeof(struct sadb_x_kmprivate));
-+ SENDERR(EINVAL);
-+ }
-+
-+ if(pfkey_x_kmprivate->sadb_x_kmprivate_reserved) {
-+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
-+ "pfkey_x_kmprivate_parse: "
-+ "reserved=%d must be set to zero.\n",
-+ pfkey_x_kmprivate->sadb_x_kmprivate_reserved);
-+ SENDERR(EINVAL);
-+ }
-+
-+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
-+ "pfkey_x_kmprivate_parse: "
-+ "Sorry, I can't parse exttype=%d yet.\n",
-+ pfkey_ext->sadb_ext_type);
-+ SENDERR(EINVAL); /* don't process these yet */
-+
-+errlab:
-+ return error;
-+}
-+
-+DEBUG_NO_STATIC int
-+pfkey_x_satype_parse(struct sadb_ext *pfkey_ext)
-+{
-+ int error = 0;
-+ int i;
-+ struct sadb_x_satype *pfkey_x_satype = (struct sadb_x_satype *)pfkey_ext;
-+
-+ DEBUGGING(PF_KEY_DEBUG_PARSE_FLOW,
-+ "pfkey_x_satype_parse: enter\n");
-+ /* sanity checks... */
-+ if(pfkey_x_satype->sadb_x_satype_len !=
-+ sizeof(struct sadb_x_satype) / IPSEC_PFKEYv2_ALIGN) {
-+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
-+ "pfkey_x_satype_parse: "
-+ "size wrong ext_len=%d, key_ext_len=%d.\n",
-+ pfkey_x_satype->sadb_x_satype_len,
-+ (int)sizeof(struct sadb_x_satype));
-+ SENDERR(EINVAL);
-+ }
-+
-+ if(!pfkey_x_satype->sadb_x_satype_satype) {
-+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
-+ "pfkey_x_satype_parse: "
-+ "satype is zero, must be non-zero.\n");
-+ SENDERR(EINVAL);
-+ }
-+
-+ if(pfkey_x_satype->sadb_x_satype_satype > SADB_SATYPE_MAX) {
-+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
-+ "pfkey_x_satype_parse: "
-+ "satype %d > max %d, invalid.\n",
-+ pfkey_x_satype->sadb_x_satype_satype, SADB_SATYPE_MAX);
-+ SENDERR(EINVAL);
-+ }
-+
-+ if(!(satype2proto(pfkey_x_satype->sadb_x_satype_satype))) {
-+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
-+ "pfkey_x_satype_parse: "
-+ "proto lookup from satype=%d failed.\n",
-+ pfkey_x_satype->sadb_x_satype_satype);
-+ SENDERR(EINVAL);
-+ }
-+
-+ for(i = 0; i < 3; i++) {
-+ if(pfkey_x_satype->sadb_x_satype_reserved[i]) {
-+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
-+ "pfkey_x_satype_parse: "
-+ "reserved[%d]=%d must be set to zero.\n",
-+ i, pfkey_x_satype->sadb_x_satype_reserved[i]);
-+ SENDERR(EINVAL);
-+ }
-+ }
-+
-+ DEBUGGING(PF_KEY_DEBUG_PARSE_STRUCT,
-+ "pfkey_x_satype_parse: "
-+ "len=%u ext=%u(%s) satype=%u(%s) res=%u,%u,%u.\n",
-+ pfkey_x_satype->sadb_x_satype_len,
-+ pfkey_x_satype->sadb_x_satype_exttype,
-+ pfkey_v2_sadb_ext_string(pfkey_x_satype->sadb_x_satype_exttype),
-+ pfkey_x_satype->sadb_x_satype_satype,
-+ satype2name(pfkey_x_satype->sadb_x_satype_satype),
-+ pfkey_x_satype->sadb_x_satype_reserved[0],
-+ pfkey_x_satype->sadb_x_satype_reserved[1],
-+ pfkey_x_satype->sadb_x_satype_reserved[2]);
-+errlab:
-+ return error;
-+}
-+
-+DEBUG_NO_STATIC int
-+pfkey_x_ext_debug_parse(struct sadb_ext *pfkey_ext)
-+{
-+ int error = 0;
-+ int i;
-+ struct sadb_x_debug *pfkey_x_debug = (struct sadb_x_debug *)pfkey_ext;
-+
-+ DEBUGGING(PF_KEY_DEBUG_PARSE_FLOW,
-+ "pfkey_x_debug_parse: enter\n");
-+ /* sanity checks... */
-+ if(pfkey_x_debug->sadb_x_debug_len !=
-+ sizeof(struct sadb_x_debug) / IPSEC_PFKEYv2_ALIGN) {
-+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
-+ "pfkey_x_debug_parse: "
-+ "size wrong ext_len=%d, key_ext_len=%d.\n",
-+ pfkey_x_debug->sadb_x_debug_len,
-+ (int)sizeof(struct sadb_x_debug));
-+ SENDERR(EINVAL);
-+ }
-+
-+ for(i = 0; i < 4; i++) {
-+ if(pfkey_x_debug->sadb_x_debug_reserved[i]) {
-+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
-+ "pfkey_x_debug_parse: "
-+ "reserved[%d]=%d must be set to zero.\n",
-+ i, pfkey_x_debug->sadb_x_debug_reserved[i]);
-+ SENDERR(EINVAL);
-+ }
-+ }
-+
-+errlab:
-+ return error;
-+}
-+
-+DEBUG_NO_STATIC int
-+pfkey_x_ext_protocol_parse(struct sadb_ext *pfkey_ext)
-+{
-+ int error = 0;
-+ struct sadb_protocol *p = (struct sadb_protocol *)pfkey_ext;
-+
-+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, "pfkey_x_protocol_parse:\n");
-+ /* sanity checks... */
-+
-+ if (p->sadb_protocol_len != sizeof(*p)/IPSEC_PFKEYv2_ALIGN) {
-+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
-+ "pfkey_x_protocol_parse: size wrong ext_len=%d, key_ext_len=%d.\n",
-+ p->sadb_protocol_len, (int)sizeof(*p));
-+ SENDERR(EINVAL);
-+ }
-+
-+ if (p->sadb_protocol_reserved2 != 0) {
-+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
-+ "pfkey_protocol_parse: res=%d, must be zero.\n",
-+ p->sadb_protocol_reserved2);
-+ SENDERR(EINVAL);
-+ }
-+
-+ errlab:
-+ return error;
-+}
-+
-+#ifdef NAT_TRAVERSAL
-+DEBUG_NO_STATIC int
-+pfkey_x_ext_nat_t_type_parse(struct sadb_ext *pfkey_ext)
-+{
-+ return 0;
-+}
-+DEBUG_NO_STATIC int
-+pfkey_x_ext_nat_t_port_parse(struct sadb_ext *pfkey_ext)
-+{
-+ return 0;
-+}
-+#endif
-+
-+#define DEFINEPARSER(NAME) static struct pf_key_ext_parsers_def NAME##_def={NAME, #NAME};
-+
-+DEFINEPARSER(pfkey_sa_parse);
-+DEFINEPARSER(pfkey_lifetime_parse);
-+DEFINEPARSER(pfkey_address_parse);
-+DEFINEPARSER(pfkey_key_parse);
-+DEFINEPARSER(pfkey_ident_parse);
-+DEFINEPARSER(pfkey_sens_parse);
-+DEFINEPARSER(pfkey_prop_parse);
-+DEFINEPARSER(pfkey_supported_parse);
-+DEFINEPARSER(pfkey_spirange_parse);
-+DEFINEPARSER(pfkey_x_kmprivate_parse);
-+DEFINEPARSER(pfkey_x_satype_parse);
-+DEFINEPARSER(pfkey_x_ext_debug_parse);
-+DEFINEPARSER(pfkey_x_ext_protocol_parse);
-+#ifdef NAT_TRAVERSAL
-+DEFINEPARSER(pfkey_x_ext_nat_t_type_parse);
-+DEFINEPARSER(pfkey_x_ext_nat_t_port_parse);
-+#endif
-+
-+struct pf_key_ext_parsers_def *ext_default_parsers[]=
-+{
-+ NULL, /* pfkey_msg_parse, */
-+ &pfkey_sa_parse_def,
-+ &pfkey_lifetime_parse_def,
-+ &pfkey_lifetime_parse_def,
-+ &pfkey_lifetime_parse_def,
-+ &pfkey_address_parse_def,
-+ &pfkey_address_parse_def,
-+ &pfkey_address_parse_def,
-+ &pfkey_key_parse_def,
-+ &pfkey_key_parse_def,
-+ &pfkey_ident_parse_def,
-+ &pfkey_ident_parse_def,
-+ &pfkey_sens_parse_def,
-+ &pfkey_prop_parse_def,
-+ &pfkey_supported_parse_def,
-+ &pfkey_supported_parse_def,
-+ &pfkey_spirange_parse_def,
-+ &pfkey_x_kmprivate_parse_def,
-+ &pfkey_x_satype_parse_def,
-+ &pfkey_sa_parse_def,
-+ &pfkey_address_parse_def,
-+ &pfkey_address_parse_def,
-+ &pfkey_address_parse_def,
-+ &pfkey_address_parse_def,
-+ &pfkey_address_parse_def,
-+ &pfkey_x_ext_debug_parse_def,
-+ &pfkey_x_ext_protocol_parse_def
-+#ifdef NAT_TRAVERSAL
-+ ,
-+ &pfkey_x_ext_nat_t_type_parse_def,
-+ &pfkey_x_ext_nat_t_port_parse_def,
-+ &pfkey_x_ext_nat_t_port_parse_def,
-+ &pfkey_address_parse_def
-+#endif
-+};
-+
-+int
-+pfkey_msg_parse(struct sadb_msg *pfkey_msg,
-+ struct pf_key_ext_parsers_def *ext_parsers[],
-+ struct sadb_ext *extensions[],
-+ int dir)
-+{
-+ int error = 0;
-+ int remain;
-+ struct sadb_ext *pfkey_ext;
-+ int extensions_seen = 0;
-+
-+ DEBUGGING(PF_KEY_DEBUG_PARSE_STRUCT,
-+ "pfkey_msg_parse: "
-+ "parsing message ver=%d, type=%d(%s), errno=%d, satype=%d(%s), len=%d, res=%d, seq=%d, pid=%d.\n",
-+ pfkey_msg->sadb_msg_version,
-+ pfkey_msg->sadb_msg_type,
-+ pfkey_v2_sadb_type_string(pfkey_msg->sadb_msg_type),
-+ pfkey_msg->sadb_msg_errno,
-+ pfkey_msg->sadb_msg_satype,
-+ satype2name(pfkey_msg->sadb_msg_satype),
-+ pfkey_msg->sadb_msg_len,
-+ pfkey_msg->sadb_msg_reserved,
-+ pfkey_msg->sadb_msg_seq,
-+ pfkey_msg->sadb_msg_pid);
-+
-+ if(ext_parsers == NULL) ext_parsers = ext_default_parsers;
-+
-+ pfkey_extensions_init(extensions);
-+
-+ remain = pfkey_msg->sadb_msg_len;
-+ remain -= sizeof(struct sadb_msg) / IPSEC_PFKEYv2_ALIGN;
-+
-+ pfkey_ext = (struct sadb_ext*)((char*)pfkey_msg +
-+ sizeof(struct sadb_msg));
-+
-+ extensions[0] = (struct sadb_ext *) pfkey_msg;
-+
-+
-+ if(pfkey_msg->sadb_msg_version != PF_KEY_V2) {
-+ ERROR("pfkey_msg_parse: "
-+ "not PF_KEY_V2 msg, found %d, should be %d.\n",
-+ pfkey_msg->sadb_msg_version,
-+ PF_KEY_V2);
-+ SENDERR(EINVAL);
-+ }
-+
-+ if(!pfkey_msg->sadb_msg_type) {
-+ ERROR("pfkey_msg_parse: "
-+ "msg type not set, must be non-zero..\n");
-+ SENDERR(EINVAL);
-+ }
-+
-+ if(pfkey_msg->sadb_msg_type > SADB_MAX) {
-+ ERROR("pfkey_msg_parse: "
-+ "msg type=%d > max=%d.\n",
-+ pfkey_msg->sadb_msg_type,
-+ SADB_MAX);
-+ SENDERR(EINVAL);
-+ }
-+
-+ switch(pfkey_msg->sadb_msg_type) {
-+ case SADB_GETSPI:
-+ case SADB_UPDATE:
-+ case SADB_ADD:
-+ case SADB_DELETE:
-+ case SADB_GET:
-+ case SADB_X_GRPSA:
-+ case SADB_X_ADDFLOW:
-+ if(!satype2proto(pfkey_msg->sadb_msg_satype)) {
-+ ERROR("pfkey_msg_parse: "
-+ "satype %d conversion to proto failed for msg_type %d (%s).\n",
-+ pfkey_msg->sadb_msg_satype,
-+ pfkey_msg->sadb_msg_type,
-+ pfkey_v2_sadb_type_string(pfkey_msg->sadb_msg_type));
-+ SENDERR(EINVAL);
-+ } else {
-+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
-+ "pfkey_msg_parse: "
-+ "satype %d(%s) conversion to proto gives %d for msg_type %d(%s).\n",
-+ pfkey_msg->sadb_msg_satype,
-+ satype2name(pfkey_msg->sadb_msg_satype),
-+ satype2proto(pfkey_msg->sadb_msg_satype),
-+ pfkey_msg->sadb_msg_type,
-+ pfkey_v2_sadb_type_string(pfkey_msg->sadb_msg_type));
-+ }
-+ case SADB_ACQUIRE:
-+ case SADB_REGISTER:
-+ case SADB_EXPIRE:
-+ if(!pfkey_msg->sadb_msg_satype) {
-+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
-+ "pfkey_msg_parse: "
-+ "satype is zero, must be non-zero for msg_type %d(%s).\n",
-+ pfkey_msg->sadb_msg_type,
-+ pfkey_v2_sadb_type_string(pfkey_msg->sadb_msg_type));
-+ SENDERR(EINVAL);
-+ }
-+ default:
-+ break;
-+ }
-+
-+ /* errno must not be set in downward messages */
-+ /* this is not entirely true... a response to an ACQUIRE could return an error */
-+ if((dir == EXT_BITS_IN) && (pfkey_msg->sadb_msg_type != SADB_ACQUIRE) && pfkey_msg->sadb_msg_errno) {
-+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
-+ "pfkey_msg_parse: "
-+ "errno set to %d.\n",
-+ pfkey_msg->sadb_msg_errno);
-+ SENDERR(EINVAL);
-+ }
-+
-+ DEBUGGING(PF_KEY_DEBUG_PARSE_FLOW,
-+ "pfkey_msg_parse: "
-+ "remain=%d, ext_type=%d(%s), ext_len=%d.\n",
-+ remain,
-+ pfkey_ext->sadb_ext_type,
-+ pfkey_v2_sadb_ext_string(pfkey_ext->sadb_ext_type),
-+ pfkey_ext->sadb_ext_len);
-+
-+ DEBUGGING(PF_KEY_DEBUG_PARSE_FLOW,
-+ "pfkey_msg_parse: "
-+ "extensions permitted=%08x, required=%08x.\n",
-+ extensions_bitmaps[dir][EXT_BITS_PERM][pfkey_msg->sadb_msg_type],
-+ extensions_bitmaps[dir][EXT_BITS_REQ][pfkey_msg->sadb_msg_type]);
-+
-+ extensions_seen = 1;
-+
-+ while( (remain * IPSEC_PFKEYv2_ALIGN) >= sizeof(struct sadb_ext) ) {
-+ /* Is there enough message left to support another extension header? */
-+ if(remain < pfkey_ext->sadb_ext_len) {
-+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
-+ "pfkey_msg_parse: "
-+ "remain %d less than ext len %d.\n",
-+ remain, pfkey_ext->sadb_ext_len);
-+ SENDERR(EINVAL);
-+ }
-+
-+ DEBUGGING(PF_KEY_DEBUG_PARSE_FLOW,
-+ "pfkey_msg_parse: "
-+ "parsing ext type=%d(%s) remain=%d.\n",
-+ pfkey_ext->sadb_ext_type,
-+ pfkey_v2_sadb_ext_string(pfkey_ext->sadb_ext_type),
-+ remain);
-+
-+ /* Is the extension header type valid? */
-+ if((pfkey_ext->sadb_ext_type > SADB_EXT_MAX) || (!pfkey_ext->sadb_ext_type)) {
-+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
-+ "pfkey_msg_parse: "
-+ "ext type %d(%s) invalid, SADB_EXT_MAX=%d.\n",
-+ pfkey_ext->sadb_ext_type,
-+ pfkey_v2_sadb_ext_string(pfkey_ext->sadb_ext_type),
-+ SADB_EXT_MAX);
-+ SENDERR(EINVAL);
-+ }
-+
-+ /* Have we already seen this type of extension? */
-+ if((extensions_seen & ( 1 << pfkey_ext->sadb_ext_type )) != 0)
-+ {
-+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
-+ "pfkey_msg_parse: "
-+ "ext type %d(%s) already seen.\n",
-+ pfkey_ext->sadb_ext_type,
-+ pfkey_v2_sadb_ext_string(pfkey_ext->sadb_ext_type));
-+ SENDERR(EINVAL);
-+ }
-+
-+ /* Do I even know about this type of extension? */
-+ if(ext_parsers[pfkey_ext->sadb_ext_type]==NULL) {
-+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
-+ "pfkey_msg_parse: "
-+ "ext type %d(%s) unknown, ignoring.\n",
-+ pfkey_ext->sadb_ext_type,
-+ pfkey_v2_sadb_ext_string(pfkey_ext->sadb_ext_type));
-+ goto next_ext;
-+ }
-+
-+ /* Is this type of extension permitted for this type of message? */
-+ if(!(extensions_bitmaps[dir][EXT_BITS_PERM][pfkey_msg->sadb_msg_type] &
-+ 1<<pfkey_ext->sadb_ext_type)) {
-+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
-+ "pfkey_msg_parse: "
-+ "ext type %d(%s) not permitted, exts_perm_in=%08x, 1<<type=%08x\n",
-+ pfkey_ext->sadb_ext_type,
-+ pfkey_v2_sadb_ext_string(pfkey_ext->sadb_ext_type),
-+ extensions_bitmaps[dir][EXT_BITS_PERM][pfkey_msg->sadb_msg_type],
-+ 1<<pfkey_ext->sadb_ext_type);
-+ SENDERR(EINVAL);
-+ }
-+
-+ DEBUGGING(PF_KEY_DEBUG_PARSE_STRUCT,
-+ "pfkey_msg_parse: "
-+ "remain=%d ext_type=%d(%s) ext_len=%d parsing ext 0p%p with parser %s.\n",
-+ remain,
-+ pfkey_ext->sadb_ext_type,
-+ pfkey_v2_sadb_ext_string(pfkey_ext->sadb_ext_type),
-+ pfkey_ext->sadb_ext_len,
-+ pfkey_ext,
-+ ext_parsers[pfkey_ext->sadb_ext_type]->parser_name);
-+
-+ /* Parse the extension */
-+ if((error =
-+ (*ext_parsers[pfkey_ext->sadb_ext_type]->parser)(pfkey_ext))) {
-+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
-+ "pfkey_msg_parse: "
-+ "extension parsing for type %d(%s) failed with error %d.\n",
-+ pfkey_ext->sadb_ext_type,
-+ pfkey_v2_sadb_ext_string(pfkey_ext->sadb_ext_type),
-+ error);
-+ SENDERR(-error);
-+ }
-+ DEBUGGING(PF_KEY_DEBUG_PARSE_FLOW,
-+ "pfkey_msg_parse: "
-+ "Extension %d(%s) parsed.\n",
-+ pfkey_ext->sadb_ext_type,
-+ pfkey_v2_sadb_ext_string(pfkey_ext->sadb_ext_type));
-+
-+ /* Mark that we have seen this extension and remember the header location */
-+ extensions_seen |= ( 1 << pfkey_ext->sadb_ext_type );
-+ extensions[pfkey_ext->sadb_ext_type] = pfkey_ext;
-+
-+ next_ext:
-+ /* Calculate how much message remains */
-+ remain -= pfkey_ext->sadb_ext_len;
-+
-+ if(!remain) {
-+ break;
-+ }
-+ /* Find the next extension header */
-+ pfkey_ext = (struct sadb_ext*)((char*)pfkey_ext +
-+ pfkey_ext->sadb_ext_len * IPSEC_PFKEYv2_ALIGN);
-+ }
-+
-+ if(remain) {
-+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
-+ "pfkey_msg_parse: "
-+ "unexpected remainder of %d.\n",
-+ remain);
-+ /* why is there still something remaining? */
-+ SENDERR(EINVAL);
-+ }
-+
-+ /* check required extensions */
-+ DEBUGGING(PF_KEY_DEBUG_PARSE_STRUCT,
-+ "pfkey_msg_parse: "
-+ "extensions permitted=%08x, seen=%08x, required=%08x.\n",
-+ extensions_bitmaps[dir][EXT_BITS_PERM][pfkey_msg->sadb_msg_type],
-+ extensions_seen,
-+ extensions_bitmaps[dir][EXT_BITS_REQ][pfkey_msg->sadb_msg_type]);
-+
-+ /* don't check further if it is an error return message since it
-+ may not have a body */
-+ if(pfkey_msg->sadb_msg_errno) {
-+ SENDERR(-error);
-+ }
-+
-+ if((extensions_seen &
-+ extensions_bitmaps[dir][EXT_BITS_REQ][pfkey_msg->sadb_msg_type]) !=
-+ extensions_bitmaps[dir][EXT_BITS_REQ][pfkey_msg->sadb_msg_type]) {
-+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
-+ "pfkey_msg_parse: "
-+ "required extensions missing:%08x.\n",
-+ extensions_bitmaps[dir][EXT_BITS_REQ][pfkey_msg->sadb_msg_type] -
-+ (extensions_seen &
-+ extensions_bitmaps[dir][EXT_BITS_REQ][pfkey_msg->sadb_msg_type]));
-+ SENDERR(EINVAL);
-+ }
-+
-+ if((dir == EXT_BITS_IN) && (pfkey_msg->sadb_msg_type == SADB_X_DELFLOW)
-+ && ((extensions_seen & SADB_X_EXT_ADDRESS_DELFLOW)
-+ != SADB_X_EXT_ADDRESS_DELFLOW)
-+ && (((extensions_seen & (1<<SADB_EXT_SA)) != (1<<SADB_EXT_SA))
-+ || ((((struct sadb_sa*)extensions[SADB_EXT_SA])->sadb_sa_flags
-+ & SADB_X_SAFLAGS_CLEARFLOW)
-+ != SADB_X_SAFLAGS_CLEARFLOW))) {
-+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
-+ "pfkey_msg_parse: "
-+ "required SADB_X_DELFLOW extensions missing: either %08x must be present or %08x must be present with SADB_X_SAFLAGS_CLEARFLOW set.\n",
-+ SADB_X_EXT_ADDRESS_DELFLOW
-+ - (extensions_seen & SADB_X_EXT_ADDRESS_DELFLOW),
-+ (1<<SADB_EXT_SA) - (extensions_seen & (1<<SADB_EXT_SA)));
-+ SENDERR(EINVAL);
-+ }
-+
-+ switch(pfkey_msg->sadb_msg_type) {
-+ case SADB_ADD:
-+ case SADB_UPDATE:
-+ /* check maturity */
-+ if(((struct sadb_sa*)extensions[SADB_EXT_SA])->sadb_sa_state !=
-+ SADB_SASTATE_MATURE) {
-+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
-+ "pfkey_msg_parse: "
-+ "state=%d for add or update should be MATURE=%d.\n",
-+ ((struct sadb_sa*)extensions[SADB_EXT_SA])->sadb_sa_state,
-+ SADB_SASTATE_MATURE);
-+ SENDERR(EINVAL);
-+ }
-+
-+ /* check AH and ESP */
-+ switch(((struct sadb_msg*)extensions[SADB_EXT_RESERVED])->sadb_msg_satype) {
-+ case SADB_SATYPE_AH:
-+ if(!(((struct sadb_sa*)extensions[SADB_EXT_SA]) &&
-+ ((struct sadb_sa*)extensions[SADB_EXT_SA])->sadb_sa_auth !=
-+ SADB_AALG_NONE)) {
-+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
-+ "pfkey_msg_parse: "
-+ "auth alg is zero, must be non-zero for AH SAs.\n");
-+ SENDERR(EINVAL);
-+ }
-+ if(((struct sadb_sa*)(extensions[SADB_EXT_SA]))->sadb_sa_encrypt !=
-+ SADB_EALG_NONE) {
-+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
-+ "pfkey_msg_parse: "
-+ "AH handed encalg=%d, must be zero.\n",
-+ ((struct sadb_sa*)(extensions[SADB_EXT_SA]))->sadb_sa_encrypt);
-+ SENDERR(EINVAL);
-+ }
-+ break;
-+ case SADB_SATYPE_ESP:
-+ if(!(((struct sadb_sa*)extensions[SADB_EXT_SA]) &&
-+ ((struct sadb_sa*)extensions[SADB_EXT_SA])->sadb_sa_encrypt !=
-+ SADB_EALG_NONE)) {
-+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
-+ "pfkey_msg_parse: "
-+ "encrypt alg=%d is zero, must be non-zero for ESP=%d SAs.\n",
-+ ((struct sadb_sa*)extensions[SADB_EXT_SA])->sadb_sa_encrypt,
-+ ((struct sadb_msg*)extensions[SADB_EXT_RESERVED])->sadb_msg_satype);
-+ SENDERR(EINVAL);
-+ }
-+ if((((struct sadb_sa*)(extensions[SADB_EXT_SA]))->sadb_sa_encrypt ==
-+ SADB_EALG_NULL) &&
-+ (((struct sadb_sa*)(extensions[SADB_EXT_SA]))->sadb_sa_auth ==
-+ SADB_AALG_NONE) ) {
-+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
-+ "pfkey_msg_parse: "
-+ "ESP handed encNULL+authNONE, illegal combination.\n");
-+ SENDERR(EINVAL);
-+ }
-+ break;
-+ case SADB_X_SATYPE_COMP:
-+ if(!(((struct sadb_sa*)extensions[SADB_EXT_SA]) &&
-+ ((struct sadb_sa*)extensions[SADB_EXT_SA])->sadb_sa_encrypt !=
-+ SADB_EALG_NONE)) {
-+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
-+ "pfkey_msg_parse: "
-+ "encrypt alg=%d is zero, must be non-zero for COMP=%d SAs.\n",
-+ ((struct sadb_sa*)extensions[SADB_EXT_SA])->sadb_sa_encrypt,
-+ ((struct sadb_msg*)extensions[SADB_EXT_RESERVED])->sadb_msg_satype);
-+ SENDERR(EINVAL);
-+ }
-+ if(((struct sadb_sa*)(extensions[SADB_EXT_SA]))->sadb_sa_auth !=
-+ SADB_AALG_NONE) {
-+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
-+ "pfkey_msg_parse: "
-+ "COMP handed auth=%d, must be zero.\n",
-+ ((struct sadb_sa*)(extensions[SADB_EXT_SA]))->sadb_sa_auth);
-+ SENDERR(EINVAL);
-+ }
-+ break;
-+ default:
-+ break;
-+ }
-+ if(ntohl(((struct sadb_sa*)(extensions[SADB_EXT_SA]))->sadb_sa_spi) <= 255) {
-+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
-+ "pfkey_msg_parse: "
-+ "spi=%08x must be > 255.\n",
-+ ntohl(((struct sadb_sa*)(extensions[SADB_EXT_SA]))->sadb_sa_spi));
-+ SENDERR(EINVAL);
-+ }
-+ default:
-+ break;
-+ }
-+errlab:
-+
-+ return error;
-+}
-+
-+/*
-+ * $Log: pfkey_v2_parse.c,v $
-+ * Revision 1.59 2004/04/18 03:03:49 mcr
-+ * renamed common include files from pluto directory.
-+ *
-+ * Revision 1.58 2004/03/08 01:59:08 ken
-+ * freeswan.h -> openswan.h
-+ *
-+ * Revision 1.57 2003/12/10 01:20:19 mcr
-+ * NAT-traversal patches to KLIPS.
-+ *
-+ * Revision 1.56 2003/12/04 23:01:12 mcr
-+ * removed ipsec_netlink.h
-+ *
-+ * Revision 1.55 2003/11/07 01:30:37 ken
-+ * Cast sizeof() to int to keep things 64bit clean
-+ *
-+ * Revision 1.54 2003/10/31 02:27:12 mcr
-+ * pulled up port-selector patches and sa_id elimination.
-+ *
-+ * Revision 1.53.20.2 2003/10/29 01:11:32 mcr
-+ * added debugging for pfkey library.
-+ *
-+ * Revision 1.53.20.1 2003/09/21 13:59:44 mcr
-+ * pre-liminary X.509 patch - does not yet pass tests.
-+ *
-+ * Revision 1.53 2003/01/30 02:32:09 rgb
-+ *
-+ * Rename SAref table macro names for clarity.
-+ * Convert IPsecSAref_t from signed to unsigned to fix apparent SAref exhaustion bug.
-+ *
-+ * Revision 1.52 2002/12/30 06:53:07 mcr
-+ * deal with short SA structures... #if 0 out for now. Probably
-+ * not quite the right way.
-+ *
-+ * Revision 1.51 2002/12/13 18:16:02 mcr
-+ * restored sa_ref code
-+ *
-+ * Revision 1.50 2002/12/13 18:06:52 mcr
-+ * temporarily removed sadb_x_sa_ref reference for 2.xx
-+ *
-+ * Revision 1.49 2002/10/05 05:02:58 dhr
-+ *
-+ * C labels go on statements
-+ *
-+ * Revision 1.48 2002/09/20 15:40:45 rgb
-+ * Added sadb_x_sa_ref to struct sadb_sa.
-+ *
-+ * Revision 1.47 2002/09/20 05:01:31 rgb
-+ * Fixed usage of pfkey_lib_debug.
-+ * Format for function declaration style consistency.
-+ * Added text labels to elucidate numeric values presented.
-+ * Re-organised debug output to reduce noise in output.
-+ *
-+ * Revision 1.46 2002/07/24 18:44:54 rgb
-+ * Type fiddling to tame ia64 compiler.
-+ *
-+ * Revision 1.45 2002/05/23 07:14:11 rgb
-+ * Cleaned up %p variants to 0p%p for test suite cleanup.
-+ *
-+ * Revision 1.44 2002/04/24 07:55:32 mcr
-+ * #include patches and Makefiles for post-reorg compilation.
-+ *
-+ * Revision 1.43 2002/04/24 07:36:40 mcr
-+ * Moved from ./lib/pfkey_v2_parse.c,v
-+ *
-+ * Revision 1.42 2002/01/29 22:25:36 rgb
-+ * Re-add ipsec_kversion.h to keep MALLOC happy.
-+ *
-+ * Revision 1.41 2002/01/29 01:59:10 mcr
-+ * removal of kversions.h - sources that needed it now use ipsec_param.h.
-+ * updating of IPv6 structures to match latest in6.h version.
-+ * removed dead code from openswan.h that also duplicated kversions.h
-+ * code.
-+ *
-+ * Revision 1.40 2002/01/20 20:34:50 mcr
-+ * added pfkey_v2_sadb_type_string to decode sadb_type to string.
-+ *
-+ * Revision 1.39 2001/11/27 05:29:22 mcr
-+ * pfkey parses are now maintained by a structure
-+ * that includes their name for debug purposes.
-+ * DEBUGGING() macro changed so that it takes a debug
-+ * level so that pf_key() can use this to decode the
-+ * structures without innundanting humans.
-+ * Also uses pfkey_v2_sadb_ext_string() in messages.
-+ *
-+ * Revision 1.38 2001/11/06 19:47:47 rgb
-+ * Added packet parameter to lifetime and comb structures.
-+ *
-+ * Revision 1.37 2001/10/18 04:45:24 rgb
-+ * 2.4.9 kernel deprecates linux/malloc.h in favour of linux/slab.h,
-+ * lib/openswan.h version macros moved to lib/kversions.h.
-+ * Other compiler directive cleanups.
-+ *
-+ * Revision 1.36 2001/06/14 19:35:16 rgb
-+ * Update copyright date.
-+ *
-+ * Revision 1.35 2001/05/03 19:44:51 rgb
-+ * Standardise on SENDERR() macro.
-+ *
-+ * Revision 1.34 2001/03/16 07:41:51 rgb
-+ * Put openswan.h include before pluto includes.
-+ *
-+ * Revision 1.33 2001/02/27 07:13:51 rgb
-+ * Added satype2name() function.
-+ * Added text to default satype_tbl entry.
-+ * Added satype2name() conversions for most satype debug output.
-+ *
-+ * Revision 1.32 2001/02/26 20:01:09 rgb
-+ * Added internal IP protocol 61 for magic SAs.
-+ * Ditch unused sadb_satype2proto[], replaced by satype2proto().
-+ * Re-formatted debug output (split lines, consistent spacing).
-+ * Removed acquire, register and expire requirements for a known satype.
-+ * Changed message type checking to a switch structure.
-+ * Verify expected NULL auth for IPCOMP.
-+ * Enforced spi > 0x100 requirement, now that pass uses a magic SA for
-+ * appropriate message types.
-+ *
-+ * Revision 1.31 2000/12/01 07:09:00 rgb
-+ * Added ipcomp sanity check to require encalgo is set.
-+ *
-+ * Revision 1.30 2000/11/17 18:10:30 rgb
-+ * Fixed bugs mostly relating to spirange, to treat all spi variables as
-+ * network byte order since this is the way PF_KEYv2 stored spis.
-+ *
-+ * Revision 1.29 2000/10/12 00:02:39 rgb
-+ * Removed 'format, ##' nonsense from debug macros for RH7.0.
-+ *
-+ * Revision 1.28 2000/09/20 16:23:04 rgb
-+ * Remove over-paranoid extension check in the presence of sadb_msg_errno.
-+ *
-+ * Revision 1.27 2000/09/20 04:04:21 rgb
-+ * Changed static functions to DEBUG_NO_STATIC to reveal function names in
-+ * oopsen.
-+ *
-+ * Revision 1.26 2000/09/15 11:37:02 rgb
-+ * Merge in heavily modified Svenning Soerensen's <svenning@post5.tele.dk>
-+ * IPCOMP zlib deflate code.
-+ *
-+ * Revision 1.25 2000/09/12 22:35:37 rgb
-+ * Restructured to remove unused extensions from CLEARFLOW messages.
-+ *
-+ * Revision 1.24 2000/09/12 18:59:54 rgb
-+ * Added Gerhard's IPv6 support to pfkey parts of libopenswan.
-+ *
-+ * Revision 1.23 2000/09/12 03:27:00 rgb
-+ * Moved DEBUGGING definition to compile kernel with debug off.
-+ *
-+ * Revision 1.22 2000/09/09 06:39:27 rgb
-+ * Restrict pfkey errno check to downward messages only.
-+ *
-+ * Revision 1.21 2000/09/08 19:22:34 rgb
-+ * Enabled pfkey_sens_parse().
-+ * Added check for errno on downward acquire messages only.
-+ *
-+ * Revision 1.20 2000/09/01 18:48:23 rgb
-+ * Fixed reserved check bug and added debug output in
-+ * pfkey_supported_parse().
-+ * Fixed debug output label bug in pfkey_ident_parse().
-+ *
-+ * Revision 1.19 2000/08/27 01:55:26 rgb
-+ * Define OCTETBITS and PFKEYBITS to avoid using 'magic' numbers in code.
-+ *
-+ * Revision 1.18 2000/08/24 17:00:36 rgb
-+ * Ignore unknown extensions instead of failing.
-+ *
-+ * Revision 1.17 2000/06/02 22:54:14 rgb
-+ * Added Gerhard Gessler's struct sockaddr_storage mods for IPv6 support.
-+ *
-+ * Revision 1.16 2000/05/10 19:25:11 rgb
-+ * Fleshed out proposal and supported extensions.
-+ *
-+ * Revision 1.15 2000/01/24 21:15:31 rgb
-+ * Added disabled pluto pfkey lib debug flag.
-+ * Added algo debugging reporting.
-+ *
-+ * Revision 1.14 2000/01/22 23:24:29 rgb
-+ * Added new functions proto2satype() and satype2proto() and lookup
-+ * table satype_tbl. Also added proto2name() since it was easy.
-+ *
-+ * Revision 1.13 2000/01/21 09:43:59 rgb
-+ * Cast ntohl(spi) as (unsigned long int) to shut up compiler.
-+ *
-+ * Revision 1.12 2000/01/21 06:28:19 rgb
-+ * Added address cases for eroute flows.
-+ * Indented compiler directives for readability.
-+ * Added klipsdebug switching capability.
-+ *
-+ * Revision 1.11 1999/12/29 21:14:59 rgb
-+ * Fixed debug text cut and paste typo.
-+ *
-+ * Revision 1.10 1999/12/10 17:45:24 rgb
-+ * Added address debugging.
-+ *
-+ * Revision 1.9 1999/12/09 23:11:42 rgb
-+ * Ditched <string.h> include since we no longer use memset().
-+ * Use new pfkey_extensions_init() instead of memset().
-+ * Added check for SATYPE in pfkey_msg_build().
-+ * Tidy up comments and debugging comments.
-+ *
-+ * Revision 1.8 1999/12/07 19:55:26 rgb
-+ * Removed unused first argument from extension parsers.
-+ * Removed static pluto debug flag.
-+ * Moved message type and state checking to pfkey_msg_parse().
-+ * Changed print[fk] type from lx to x to quiet compiler.
-+ * Removed redundant remain check.
-+ * Changed __u* types to uint* to avoid use of asm/types.h and
-+ * sys/types.h in userspace code.
-+ *
-+ * Revision 1.7 1999/12/01 22:20:51 rgb
-+ * Moved pfkey_lib_debug variable into the library.
-+ * Added pfkey version check into header parsing.
-+ * Added check for SATYPE only for those extensions that require a
-+ * non-zero value.
-+ *
-+ * Revision 1.6 1999/11/27 11:58:05 rgb
-+ * Added ipv6 headers.
-+ * Moved sadb_satype2proto protocol lookup table from
-+ * klips/net/ipsec/pfkey_v2_parser.c.
-+ * Enable lifetime_current checking.
-+ * Debugging error messages added.
-+ * Add argument to pfkey_msg_parse() for direction.
-+ * Consolidated the 4 1-d extension bitmap arrays into one 4-d array.
-+ * Add CVS log entry to bottom of file.
-+ * Moved auth and enc alg check to pfkey_msg_parse().
-+ * Enable accidentally disabled spirange parsing.
-+ * Moved protocol/algorithm checks from klips/net/ipsec/pfkey_v2_parser.c
-+ *
-+ * Local variables:
-+ * c-file-style: "linux"
-+ * End:
-+ *
-+ */
---- /dev/null Tue Mar 11 13:02:56 2003
-+++ linux/lib/libfreeswan/prng.c Mon Feb 9 13:51:03 2004
-@@ -0,0 +1,201 @@
-+/*
-+ * crypto-class pseudorandom number generator
-+ * currently uses same algorithm as RC4(TM), from Schneier 2nd ed p397
-+ * Copyright (C) 2002 Henry Spencer.
-+ *
-+ * This library is free software; you can redistribute it and/or modify it
-+ * under the terms of the GNU Library General Public License as published by
-+ * the Free Software Foundation; either version 2 of the License, or (at your
-+ * option) any later version. See <http://www.fsf.org/copyleft/lgpl.txt>.
-+ *
-+ * This library 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 Library General Public
-+ * License for more details.
-+ *
-+ * RCSID $Id: prng.c,v 1.6 2004/04/11 17:39:25 mcr Exp $
-+ */
-+#include "openswan.h"
-+
-+/*
-+ - prng_init - initialize PRNG from a key
-+ */
-+void
-+prng_init(prng, key, keylen)
-+struct prng *prng;
-+const unsigned char *key;
-+size_t keylen;
-+{
-+ unsigned char k[256];
-+ int i, j;
-+ unsigned const char *p;
-+ unsigned const char *keyend = key + keylen;
-+ unsigned char t;
-+
-+ for (i = 0; i <= 255; i++)
-+ prng->sbox[i] = i;
-+ p = key;
-+ for (i = 0; i <= 255; i++) {
-+ k[i] = *p++;
-+ if (p >= keyend)
-+ p = key;
-+ }
-+ j = 0;
-+ for (i = 0; i <= 255; i++) {
-+ j = (j + prng->sbox[i] + k[i]) & 0xff;
-+ t = prng->sbox[i];
-+ prng->sbox[i] = prng->sbox[j];
-+ prng->sbox[j] = t;
-+ k[i] = 0; /* clear out key memory */
-+ }
-+ prng->i = 0;
-+ prng->j = 0;
-+ prng->count = 0;
-+}
-+
-+/*
-+ - prng_bytes - get some pseudorandom bytes from PRNG
-+ */
-+void
-+prng_bytes(prng, dst, dstlen)
-+struct prng *prng;
-+unsigned char *dst;
-+size_t dstlen;
-+{
-+ int i, j, t;
-+ unsigned char *p = dst;
-+ size_t remain = dstlen;
-+# define MAX 4000000000ul
-+
-+ while (remain > 0) {
-+ i = (prng->i + 1) & 0xff;
-+ prng->i = i;
-+ j = (prng->j + prng->sbox[i]) & 0xff;
-+ prng->j = j;
-+ t = prng->sbox[i];
-+ prng->sbox[i] = prng->sbox[j];
-+ prng->sbox[j] = t;
-+ t = (t + prng->sbox[i]) & 0xff;
-+ *p++ = prng->sbox[t];
-+ remain--;
-+ }
-+ if (prng->count < MAX - dstlen)
-+ prng->count += dstlen;
-+ else
-+ prng->count = MAX;
-+}
-+
-+/*
-+ - prnt_count - how many bytes have been extracted from PRNG so far?
-+ */
-+unsigned long
-+prng_count(prng)
-+struct prng *prng;
-+{
-+ return prng->count;
-+}
-+
-+/*
-+ - prng_final - clear out PRNG to ensure nothing left in memory
-+ */
-+void
-+prng_final(prng)
-+struct prng *prng;
-+{
-+ int i;
-+
-+ for (i = 0; i <= 255; i++)
-+ prng->sbox[i] = 0;
-+ prng->i = 0;
-+ prng->j = 0;
-+ prng->count = 0; /* just for good measure */
-+}
-+
-+
-+
-+#ifdef PRNG_MAIN
-+
-+#include <stdio.h>
-+
-+void regress();
-+
-+int
-+main(argc, argv)
-+int argc;
-+char *argv[];
-+{
-+ struct prng pr;
-+ unsigned char buf[100];
-+ unsigned char *p;
-+ size_t n;
-+
-+ if (argc < 2) {
-+ fprintf(stderr, "Usage: %s {key|-r}\n", argv[0]);
-+ exit(2);
-+ }
-+
-+ if (strcmp(argv[1], "-r") == 0) {
-+ regress();
-+ fprintf(stderr, "regress() returned?!?\n");
-+ exit(1);
-+ }
-+
-+ prng_init(&pr, argv[1], strlen(argv[1]));
-+ prng_bytes(&pr, buf, 32);
-+ printf("0x");
-+ for (p = buf, n = 32; n > 0; p++, n--)
-+ printf("%02x", *p);
-+ printf("\n%lu bytes\n", prng_count(&pr));
-+ prng_final(&pr);
-+ exit(0);
-+}
-+
-+void
-+regress()
-+{
-+ struct prng pr;
-+ unsigned char buf[100];
-+ unsigned char *p;
-+ size_t n;
-+ /* somewhat non-random sample key */
-+ unsigned char key[] = "here we go gathering nuts in May";
-+ /* first thirty bytes of output from that key */
-+ unsigned char good[] = "\x3f\x02\x8e\x4a\x2a\xea\x23\x18\x92\x7c"
-+ "\x09\x52\x83\x61\xaa\x26\xce\xbb\x9d\x71"
-+ "\x71\xe5\x10\x22\xaf\x60\x54\x8d\x5b\x28";
-+ int nzero, none;
-+ int show = 0;
-+
-+ prng_init(&pr, key, strlen(key));
-+ prng_bytes(&pr, buf, sizeof(buf));
-+ for (p = buf, n = sizeof(buf); n > 0; p++, n--) {
-+ if (*p == 0)
-+ nzero++;
-+ if (*p == 255)
-+ none++;
-+ }
-+ if (nzero > 3 || none > 3) {
-+ fprintf(stderr, "suspiciously non-random output!\n");
-+ show = 1;
-+ }
-+ if (memcmp(buf, good, strlen(good)) != 0) {
-+ fprintf(stderr, "incorrect output!\n");
-+ show = 1;
-+ }
-+ if (show) {
-+ fprintf(stderr, "0x");
-+ for (p = buf, n = sizeof(buf); n > 0; p++, n--)
-+ fprintf(stderr, "%02x", *p);
-+ fprintf(stderr, "\n");
-+ exit(1);
-+ }
-+ if (prng_count(&pr) != sizeof(buf)) {
-+ fprintf(stderr, "got %u bytes, but count is %lu\n",
-+ sizeof(buf), prng_count(&pr));
-+ exit(1);
-+ }
-+ prng_final(&pr);
-+ exit(0);
-+}
-+
-+#endif /* PRNG_MAIN */
---- /dev/null Tue Mar 11 13:02:56 2003
-+++ linux/lib/libfreeswan/rangetoa.c Mon Feb 9 13:51:03 2004
-@@ -0,0 +1,60 @@
-+/*
-+ * convert binary form of address range to ASCII
-+ * Copyright (C) 1998, 1999 Henry Spencer.
-+ *
-+ * This library is free software; you can redistribute it and/or modify it
-+ * under the terms of the GNU Library General Public License as published by
-+ * the Free Software Foundation; either version 2 of the License, or (at your
-+ * option) any later version. See <http://www.fsf.org/copyleft/lgpl.txt>.
-+ *
-+ * This library 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 Library General Public
-+ * License for more details.
-+ *
-+ * RCSID $Id: rangetoa.c,v 1.8 2004/04/11 17:39:25 mcr Exp $
-+ */
-+#include "openswan.h"
-+
-+/*
-+ - rangetoa - convert address range to ASCII
-+ */
-+size_t /* space needed for full conversion */
-+rangetoa(addrs, format, dst, dstlen)
-+struct in_addr addrs[2];
-+int format; /* character */
-+char *dst; /* need not be valid if dstlen is 0 */
-+size_t dstlen;
-+{
-+ size_t len;
-+ size_t rest;
-+ int n;
-+ char *p;
-+
-+ switch (format) {
-+ case 0:
-+ break;
-+ default:
-+ return 0;
-+ break;
-+ }
-+
-+ len = addrtoa(addrs[0], 0, dst, dstlen);
-+ if (len < dstlen)
-+ for (p = dst + len - 1, n = 3; len < dstlen && n > 0;
-+ p++, len++, n--)
-+ *p = '.';
-+ else
-+ p = NULL;
-+ if (len < dstlen)
-+ rest = dstlen - len;
-+ else {
-+ if (dstlen > 0)
-+ *(dst + dstlen - 1) = '\0';
-+ rest = 0;
-+ }
-+
-+ len += addrtoa(addrs[1], 0, p, rest);
-+
-+ return len;
-+}
---- /dev/null Tue Mar 11 13:02:56 2003
-+++ linux/lib/libfreeswan/satot.c Mon Feb 9 13:51:03 2004
-@@ -0,0 +1,133 @@
-+/*
-+ * convert from binary form of SA ID to text
-+ * Copyright (C) 2000, 2001 Henry Spencer.
-+ *
-+ * This library is free software; you can redistribute it and/or modify it
-+ * under the terms of the GNU Library General Public License as published by
-+ * the Free Software Foundation; either version 2 of the License, or (at your
-+ * option) any later version. See <http://www.fsf.org/copyleft/lgpl.txt>.
-+ *
-+ * This library 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 Library General Public
-+ * License for more details.
-+ *
-+ * RCSID $Id: satot.c,v 1.12 2004/04/11 17:10:21 mcr Exp $
-+ */
-+#include "openswan.h"
-+
-+static struct typename {
-+ char type;
-+ char *name;
-+} typenames[] = {
-+ { SA_AH, "ah" },
-+ { SA_ESP, "esp" },
-+ { SA_IPIP, "tun" },
-+ { SA_COMP, "comp" },
-+ { SA_INT, "int" },
-+ { 0, NULL }
-+};
-+
-+/*
-+ - satot - convert SA to text "ah507@1.2.3.4"
-+ */
-+size_t /* space needed for full conversion */
-+satot(sa, format, dst, dstlen)
-+const ip_said *sa;
-+int format; /* character */
-+char *dst; /* need not be valid if dstlen is 0 */
-+size_t dstlen;
-+{
-+ size_t len = 0; /* 0 means "not recognized yet" */
-+ int base;
-+ int showversion; /* use delimiter to show IP version? */
-+ struct typename *tn;
-+ char *p;
-+ char *pre;
-+ char buf[10+1+ULTOT_BUF+ADDRTOT_BUF];
-+ char unk[10];
-+
-+ switch (format) {
-+ case 0:
-+ base = 16;
-+ showversion = 1;
-+ break;
-+ case 'f':
-+ base = 17;
-+ showversion = 1;
-+ break;
-+ case 'x':
-+ base = 'x';
-+ showversion = 0;
-+ break;
-+ case 'd':
-+ base = 10;
-+ showversion = 0;
-+ break;
-+ default:
-+ return 0;
-+ break;
-+ }
-+
-+ memset(buf, 0, sizeof(buf));
-+
-+ pre = NULL;
-+ for (tn = typenames; tn->name != NULL; tn++)
-+ if (sa->proto == tn->type) {
-+ pre = tn->name;
-+ break; /* NOTE BREAK OUT */
-+ }
-+ if (pre == NULL) { /* unknown protocol */
-+ strcpy(unk, "unk");
-+ (void) ultot((unsigned char)sa->proto, 10, unk+strlen(unk),
-+ sizeof(unk)-strlen(unk));
-+ pre = unk;
-+ }
-+
-+ if (strcmp(pre, PASSTHROUGHTYPE) == 0 &&
-+ sa->spi == PASSTHROUGHSPI &&
-+ isunspecaddr(&sa->dst)) {
-+ strcpy(buf, (addrtypeof(&sa->dst) == AF_INET) ?
-+ PASSTHROUGH4NAME :
-+ PASSTHROUGH6NAME);
-+ len = strlen(buf);
-+ }
-+
-+ if (sa->proto == SA_INT) {
-+ switch (ntohl(sa->spi)) {
-+ case SPI_PASS: p = "%pass"; break;
-+ case SPI_DROP: p = "%drop"; break;
-+ case SPI_REJECT: p = "%reject"; break;
-+ case SPI_HOLD: p = "%hold"; break;
-+ case SPI_TRAP: p = "%trap"; break;
-+ case SPI_TRAPSUBNET: p = "%trapsubnet"; break;
-+ default: p = NULL; break;
-+ }
-+ if (p != NULL) {
-+ strcpy(buf, p);
-+ len = strlen(buf);
-+ }
-+ }
-+
-+ if (len == 0) { /* general case needed */
-+ strcpy(buf, pre);
-+ len = strlen(buf);
-+ if (showversion) {
-+ *(buf+len) = (addrtypeof(&sa->dst) == AF_INET) ? '.' :
-+ ':';
-+ len++;
-+ *(buf+len) = '\0';
-+ }
-+ len += ultot(ntohl(sa->spi), base, buf+len, sizeof(buf)-len);
-+ *(buf+len-1) = '@';
-+ len += addrtot(&sa->dst, 0, buf+len, sizeof(buf)-len);
-+ *(buf+len) = '\0';
-+ }
-+
-+ if (dst != NULL) {
-+ if (len > dstlen)
-+ *(buf+dstlen-1) = '\0';
-+ strcpy(dst, buf);
-+ }
-+ return len;
-+}
---- /dev/null Tue Mar 11 13:02:56 2003
-+++ linux/lib/libfreeswan/subnetof.c Mon Feb 9 13:51:03 2004
-@@ -0,0 +1,59 @@
-+/*
-+ * minor network-address manipulation utilities
-+ * Copyright (C) 1998, 1999 Henry Spencer.
-+ *
-+ * This library is free software; you can redistribute it and/or modify it
-+ * under the terms of the GNU Library General Public License as published by
-+ * the Free Software Foundation; either version 2 of the License, or (at your
-+ * option) any later version. See <http://www.fsf.org/copyleft/lgpl.txt>.
-+ *
-+ * This library 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 Library General Public
-+ * License for more details.
-+ *
-+ * RCSID $Id: subnetof.c,v 1.7 2004/04/11 17:39:25 mcr Exp $
-+ */
-+#include "openswan.h"
-+
-+/*
-+ - subnetof - given address and mask, return subnet part
-+ */
-+struct in_addr
-+subnetof(addr, mask)
-+struct in_addr addr;
-+struct in_addr mask;
-+{
-+ struct in_addr result;
-+
-+ result.s_addr = addr.s_addr & mask.s_addr;
-+ return result;
-+}
-+
-+/*
-+ - hostof - given address and mask, return host part
-+ */
-+struct in_addr
-+hostof(addr, mask)
-+struct in_addr addr;
-+struct in_addr mask;
-+{
-+ struct in_addr result;
-+
-+ result.s_addr = addr.s_addr & ~mask.s_addr;
-+ return result;
-+}
-+
-+/*
-+ - broadcastof - given (network) address and mask, return broadcast address
-+ */
-+struct in_addr
-+broadcastof(addr, mask)
-+struct in_addr addr;
-+struct in_addr mask;
-+{
-+ struct in_addr result;
-+
-+ result.s_addr = addr.s_addr | ~mask.s_addr;
-+ return result;
-+}
---- /dev/null Tue Mar 11 13:02:56 2003
-+++ linux/lib/libfreeswan/subnettoa.c Mon Feb 9 13:51:03 2004
-@@ -0,0 +1,61 @@
-+/*
-+ * convert binary form of subnet description to ASCII
-+ * Copyright (C) 1998, 1999 Henry Spencer.
-+ *
-+ * This library is free software; you can redistribute it and/or modify it
-+ * under the terms of the GNU Library General Public License as published by
-+ * the Free Software Foundation; either version 2 of the License, or (at your
-+ * option) any later version. See <http://www.fsf.org/copyleft/lgpl.txt>.
-+ *
-+ * This library 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 Library General Public
-+ * License for more details.
-+ *
-+ * RCSID $Id: subnettoa.c,v 1.10 2004/04/11 17:39:25 mcr Exp $
-+ */
-+#include "openswan.h"
-+
-+/*
-+ - subnettoa - convert address and mask to ASCII "addr/mask"
-+ * Output expresses the mask as a bit count if possible, else dotted decimal.
-+ */
-+size_t /* space needed for full conversion */
-+subnettoa(addr, mask, format, dst, dstlen)
-+struct in_addr addr;
-+struct in_addr mask;
-+int format; /* character */
-+char *dst; /* need not be valid if dstlen is 0 */
-+size_t dstlen;
-+{
-+ size_t len;
-+ size_t rest;
-+ int n;
-+ char *p;
-+
-+ switch (format) {
-+ case 0:
-+ break;
-+ default:
-+ return 0;
-+ break;
-+ }
-+
-+ len = addrtoa(addr, 0, dst, dstlen);
-+ if (len < dstlen) {
-+ dst[len - 1] = '/';
-+ p = dst + len;
-+ rest = dstlen - len;
-+ } else {
-+ p = NULL;
-+ rest = 0;
-+ }
-+
-+ n = masktobits(mask);
-+ if (n >= 0)
-+ len += ultoa((unsigned long)n, 10, p, rest);
-+ else
-+ len += addrtoa(mask, 0, p, rest);
-+
-+ return len;
-+}
---- /dev/null Tue Mar 11 13:02:56 2003
-+++ linux/lib/libfreeswan/ultoa.c Mon Feb 9 13:51:03 2004
-@@ -0,0 +1,66 @@
-+/*
-+ * convert unsigned long to ASCII
-+ * Copyright (C) 1998, 1999 Henry Spencer.
-+ *
-+ * This library is free software; you can redistribute it and/or modify it
-+ * under the terms of the GNU Library General Public License as published by
-+ * the Free Software Foundation; either version 2 of the License, or (at your
-+ * option) any later version. See <http://www.fsf.org/copyleft/lgpl.txt>.
-+ *
-+ * This library 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 Library General Public
-+ * License for more details.
-+ *
-+ * RCSID $Id: ultoa.c,v 1.9 2004/04/11 17:39:25 mcr Exp $
-+ */
-+#include "openswan.h"
-+
-+/*
-+ - ultoa - convert unsigned long to decimal ASCII
-+ */
-+size_t /* length required for full conversion */
-+ultoa(n, base, dst, dstlen)
-+unsigned long n;
-+int base;
-+char *dst; /* need not be valid if dstlen is 0 */
-+size_t dstlen;
-+{
-+ char buf[3*sizeof(unsigned long) + 1];
-+ char *bufend = buf + sizeof(buf);
-+ size_t len;
-+ char *p;
-+ static char hex[] = "0123456789abcdef";
-+
-+ p = bufend;
-+ *--p = '\0';
-+ if (base == 10) {
-+ do {
-+ *--p = n%10 + '0';
-+ n /= 10;
-+ } while (n != 0);
-+ } else if (base == 16) {
-+ do {
-+ *--p = hex[n&0xf];
-+ n >>= 4;
-+ } while (n != 0);
-+ *--p = 'x';
-+ *--p = '0';
-+ } else if (base == 8) {
-+ do {
-+ *--p = (n&07) + '0';
-+ n >>= 3;
-+ } while (n != 0);
-+ *--p = '0';
-+ } else
-+ *--p = '?';
-+
-+ len = bufend - p;
-+
-+ if (dstlen > 0) {
-+ if (len > dstlen)
-+ *(p + dstlen - 1) = '\0';
-+ strcpy(dst, p);
-+ }
-+ return len;
-+}
---- /dev/null Tue Mar 11 13:02:56 2003
-+++ linux/lib/libfreeswan/ultot.c Mon Feb 9 13:51:03 2004
-@@ -0,0 +1,82 @@
-+/*
-+ * convert unsigned long to text
-+ * Copyright (C) 2000 Henry Spencer.
-+ *
-+ * This library is free software; you can redistribute it and/or modify it
-+ * under the terms of the GNU Library General Public License as published by
-+ * the Free Software Foundation; either version 2 of the License, or (at your
-+ * option) any later version. See <http://www.fsf.org/copyleft/lgpl.txt>.
-+ *
-+ * This library 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 Library General Public
-+ * License for more details.
-+ *
-+ * RCSID $Id: ultot.c,v 1.4 2004/04/11 17:39:25 mcr Exp $
-+ */
-+#include "openswan.h"
-+
-+/*
-+ - ultot - convert unsigned long to text
-+ */
-+size_t /* length required for full conversion */
-+ultot(n, base, dst, dstlen)
-+unsigned long n;
-+int base;
-+char *dst; /* need not be valid if dstlen is 0 */
-+size_t dstlen;
-+{
-+ char buf[3*sizeof(unsigned long) + 1];
-+ char *bufend = buf + sizeof(buf);
-+ size_t len;
-+ char *p;
-+ static char hex[] = "0123456789abcdef";
-+# define HEX32 (32/4)
-+
-+ p = bufend;
-+ *--p = '\0';
-+ switch (base) {
-+ case 10:
-+ case 'd':
-+ do {
-+ *--p = n%10 + '0';
-+ n /= 10;
-+ } while (n != 0);
-+ break;
-+ case 16:
-+ case 17:
-+ case 'x':
-+ do {
-+ *--p = hex[n&0xf];
-+ n >>= 4;
-+ } while (n != 0);
-+ if (base == 17)
-+ while (bufend - p < HEX32 + 1)
-+ *--p = '0';
-+ if (base == 'x') {
-+ *--p = 'x';
-+ *--p = '0';
-+ }
-+ break;
-+ case 8:
-+ case 'o':
-+ do {
-+ *--p = (n&07) + '0';
-+ n >>= 3;
-+ } while (n != 0);
-+ if (base == 'o')
-+ *--p = '0';
-+ break;
-+ default:
-+ return 0;
-+ break;
-+ }
-+
-+ len = bufend - p;
-+ if (dstlen > 0) {
-+ if (len > dstlen)
-+ *(p + dstlen - 1) = '\0';
-+ strcpy(dst, p);
-+ }
-+ return len;
-+}
---- /dev/null Tue Mar 11 13:02:56 2003
-+++ linux/lib/zlib/Makefile Mon Feb 9 13:51:03 2004
-@@ -0,0 +1,118 @@
-+# (kernel) Makefile for IPCOMP zlib deflate code
-+# Copyright (C) 1998, 1999, 2000, 2001 Richard Guy Briggs.
-+# Copyright (C) 2000 Svenning Soerensen
-+#
-+# 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. See <http://www.fsf.org/copyleft/gpl.txt>.
-+#
-+# 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.
-+#
-+# RCSID $Id: Makefile,v 1.9 2002/04/24 07:55:32 mcr Exp $
-+#
-+
-+
-+
-+include ../Makefile.inc
-+
-+
-+
-+ifndef TOPDIR
-+TOPDIR := /usr/src/linux
-+endif
-+
-+
-+L_TARGET := zlib.a
-+
-+obj-y :=
-+
-+include Makefile.objs
-+
-+EXTRA_CFLAGS += $(KLIPSCOMPILE)
-+
-+EXTRA_CFLAGS += -Wall
-+#EXTRA_CFLAGS += -Wconversion
-+#EXTRA_CFLAGS += -Wmissing-prototypes
-+EXTRA_CFLAGS += -Wpointer-arith
-+#EXTRA_CFLAGS += -Wcast-qual
-+#EXTRA_CFLAGS += -Wmissing-declarations
-+EXTRA_CFLAGS += -Wstrict-prototypes
-+#EXTRA_CFLAGS += -pedantic
-+#EXTRA_CFLAGS += -W
-+#EXTRA_CFLAGS += -Wwrite-strings
-+EXTRA_CFLAGS += -Wbad-function-cast
-+EXTRA_CFLAGS += -DIPCOMP_PREFIX
-+
-+.S.o:
-+ $(CC) -D__ASSEMBLY__ -DNO_UNDERLINE -traditional -c $< -o $*.o
-+
-+asm-obj-$(CONFIG_M586) += match586.o
-+asm-obj-$(CONFIG_M586TSC) += match586.o
-+asm-obj-$(CONFIG_M586MMX) += match586.o
-+asm-obj-$(CONFIG_M686) += match686.o
-+asm-obj-$(CONFIG_MPENTIUMIII) += match686.o
-+asm-obj-$(CONFIG_MPENTIUM4) += match686.o
-+asm-obj-$(CONFIG_MK6) += match586.o
-+asm-obj-$(CONFIG_MK7) += match686.o
-+asm-obj-$(CONFIG_MCRUSOE) += match586.o
-+asm-obj-$(CONFIG_MWINCHIPC6) += match586.o
-+asm-obj-$(CONFIG_MWINCHIP2) += match686.o
-+asm-obj-$(CONFIG_MWINCHIP3D) += match686.o
-+
-+obj-y += $(asm-obj-y)
-+ifneq ($(strip $(asm-obj-y)),)
-+ EXTRA_CFLAGS += -DASMV
-+endif
-+
-+active-objs := $(sort $(obj-y) $(obj-m))
-+L_OBJS := $(obj-y)
-+M_OBJS := $(obj-m)
-+MIX_OBJS := $(filter $(export-objs), $(active-objs))
-+
-+include $(TOPDIR)/Rules.make
-+
-+$(obj-y) : $(TOPDIR)/include/linux/config.h $(TOPDIR)/include/linux/autoconf.h
-+
-+
-+clean:
-+ -rm -f *.o *.a
-+
-+checkprograms:
-+programs: $(L_TARGET)
-+
-+#
-+# $Log: Makefile,v $
-+# Revision 1.9 2002/04/24 07:55:32 mcr
-+# #include patches and Makefiles for post-reorg compilation.
-+#
-+# Revision 1.8 2002/04/24 07:36:44 mcr
-+# Moved from ./zlib/Makefile,v
-+#
-+# Revision 1.7 2002/03/27 23:34:35 mcr
-+# added programs: target
-+#
-+# Revision 1.6 2001/12/05 20:19:08 henry
-+# use new compile-control variable
-+#
-+# Revision 1.5 2001/11/27 16:38:08 mcr
-+# added new "checkprograms" target to deal with programs that
-+# are required for "make check", but that may not be ready to
-+# build for every user due to external dependancies.
-+#
-+# Revision 1.4 2001/10/24 14:46:24 henry
-+# Makefile.inc
-+#
-+# Revision 1.3 2001/04/21 23:05:24 rgb
-+# Update asm directives for 2.4 style makefiles.
-+#
-+# Revision 1.2 2001/01/29 22:22:00 rgb
-+# Convert to 2.4 new style with back compat.
-+#
-+# Revision 1.1.1.1 2000/09/29 18:51:33 rgb
-+# zlib_beginnings
-+#
-+#
---- /dev/null Tue Mar 11 13:02:56 2003
-+++ linux/lib/zlib/Makefile.objs Mon Feb 9 13:51:03 2004
-@@ -0,0 +1,27 @@
-+obj-$(CONFIG_IPSEC_IPCOMP) += adler32.o
-+obj-$(CONFIG_IPSEC_IPCOMP) += deflate.o
-+obj-$(CONFIG_IPSEC_IPCOMP) += infblock.o
-+obj-$(CONFIG_IPSEC_IPCOMP) += infcodes.o
-+obj-$(CONFIG_IPSEC_IPCOMP) += inffast.o
-+obj-$(CONFIG_IPSEC_IPCOMP) += inflate.o
-+obj-$(CONFIG_IPSEC_IPCOMP) += inftrees.o
-+obj-$(CONFIG_IPSEC_IPCOMP) += infutil.o
-+obj-$(CONFIG_IPSEC_IPCOMP) += trees.o
-+obj-$(CONFIG_IPSEC_IPCOMP) += zutil.o
-+
-+asm-obj-$(CONFIG_M586) += ${LIBZLIBSRCDIR}/match586.o
-+asm-obj-$(CONFIG_M586TSC) += ${LIBZLIBSRCDIR}/match586.o
-+asm-obj-$(CONFIG_M586MMX) += ${LIBZLIBSRCDIR}/match586.o
-+asm-obj-$(CONFIG_M686) += ${LIBZLIBSRCDIR}/match686.o
-+asm-obj-$(CONFIG_MPENTIUMIII) += ${LIBZLIBSRCDIR}/match686.o
-+asm-obj-$(CONFIG_MPENTIUM4) += ${LIBZLIBSRCDIR}/match686.o
-+asm-obj-$(CONFIG_MK6) += ${LIBZLIBSRCDIR}/match586.o
-+asm-obj-$(CONFIG_MK7) += ${LIBZLIBSRCDIR}/match686.o
-+asm-obj-$(CONFIG_MCRUSOE) += ${LIBZLIBSRCDIR}/match586.o
-+asm-obj-$(CONFIG_MWINCHIPC6) += ${LIBZLIBSRCDIR}/match586.o
-+asm-obj-$(CONFIG_MWINCHIP2) += ${LIBZLIBSRCDIR}/match686.o
-+asm-obj-$(CONFIG_MWINCHIP3D) += ${LIBZLIBSRCDIR}/match686.o
-+
-+EXTRA_CFLAGS += -DIPCOMP_PREFIX
-+
-+
---- /dev/null Tue Mar 11 13:02:56 2003
-+++ linux/lib/zlib/README Mon Feb 9 13:51:03 2004
-@@ -0,0 +1,147 @@
-+zlib 1.1.4 is a general purpose data compression library. All the code
-+is thread safe. The data format used by the zlib library
-+is described by RFCs (Request for Comments) 1950 to 1952 in the files
-+http://www.ietf.org/rfc/rfc1950.txt (zlib format), rfc1951.txt (deflate
-+format) and rfc1952.txt (gzip format). These documents are also available in
-+other formats from ftp://ftp.uu.net/graphics/png/documents/zlib/zdoc-index.html
-+
-+All functions of the compression library are documented in the file zlib.h
-+(volunteer to write man pages welcome, contact jloup@gzip.org). A usage
-+example of the library is given in the file example.c which also tests that
-+the library is working correctly. Another example is given in the file
-+minigzip.c. The compression library itself is composed of all source files
-+except example.c and minigzip.c.
-+
-+To compile all files and run the test program, follow the instructions
-+given at the top of Makefile. In short "make test; make install"
-+should work for most machines. For Unix: "./configure; make test; make install"
-+For MSDOS, use one of the special makefiles such as Makefile.msc.
-+For VMS, use Make_vms.com or descrip.mms.
-+
-+Questions about zlib should be sent to <zlib@gzip.org>, or to
-+Gilles Vollant <info@winimage.com> for the Windows DLL version.
-+The zlib home page is http://www.zlib.org or http://www.gzip.org/zlib/
-+Before reporting a problem, please check this site to verify that
-+you have the latest version of zlib; otherwise get the latest version and
-+check whether the problem still exists or not.
-+
-+PLEASE read the zlib FAQ http://www.gzip.org/zlib/zlib_faq.html
-+before asking for help.
-+
-+Mark Nelson <markn@ieee.org> wrote an article about zlib for the Jan. 1997
-+issue of Dr. Dobb's Journal; a copy of the article is available in
-+http://dogma.net/markn/articles/zlibtool/zlibtool.htm
-+
-+The changes made in version 1.1.4 are documented in the file ChangeLog.
-+The only changes made since 1.1.3 are bug corrections:
-+
-+- ZFREE was repeated on same allocation on some error conditions.
-+ This creates a security problem described in
-+ http://www.zlib.org/advisory-2002-03-11.txt
-+- Returned incorrect error (Z_MEM_ERROR) on some invalid data
-+- Avoid accesses before window for invalid distances with inflate window
-+ less than 32K.
-+- force windowBits > 8 to avoid a bug in the encoder for a window size
-+ of 256 bytes. (A complete fix will be available in 1.1.5).
-+
-+The beta version 1.1.5beta includes many more changes. A new official
-+version 1.1.5 will be released as soon as extensive testing has been
-+completed on it.
-+
-+
-+Unsupported third party contributions are provided in directory "contrib".
-+
-+A Java implementation of zlib is available in the Java Development Kit
-+http://www.javasoft.com/products/JDK/1.1/docs/api/Package-java.util.zip.html
-+See the zlib home page http://www.zlib.org for details.
-+
-+A Perl interface to zlib written by Paul Marquess <pmarquess@bfsec.bt.co.uk>
-+is in the CPAN (Comprehensive Perl Archive Network) sites
-+http://www.cpan.org/modules/by-module/Compress/
-+
-+A Python interface to zlib written by A.M. Kuchling <amk@magnet.com>
-+is available in Python 1.5 and later versions, see
-+http://www.python.org/doc/lib/module-zlib.html
-+
-+A zlib binding for TCL written by Andreas Kupries <a.kupries@westend.com>
-+is availlable at http://www.westend.com/~kupries/doc/trf/man/man.html
-+
-+An experimental package to read and write files in .zip format,
-+written on top of zlib by Gilles Vollant <info@winimage.com>, is
-+available at http://www.winimage.com/zLibDll/unzip.html
-+and also in the contrib/minizip directory of zlib.
-+
-+
-+Notes for some targets:
-+
-+- To build a Windows DLL version, include in a DLL project zlib.def, zlib.rc
-+ and all .c files except example.c and minigzip.c; compile with -DZLIB_DLL
-+ The zlib DLL support was initially done by Alessandro Iacopetti and is
-+ now maintained by Gilles Vollant <info@winimage.com>. Check the zlib DLL
-+ home page at http://www.winimage.com/zLibDll
-+
-+ From Visual Basic, you can call the DLL functions which do not take
-+ a structure as argument: compress, uncompress and all gz* functions.
-+ See contrib/visual-basic.txt for more information, or get
-+ http://www.tcfb.com/dowseware/cmp-z-it.zip
-+
-+- For 64-bit Irix, deflate.c must be compiled without any optimization.
-+ With -O, one libpng test fails. The test works in 32 bit mode (with
-+ the -n32 compiler flag). The compiler bug has been reported to SGI.
-+
-+- zlib doesn't work with gcc 2.6.3 on a DEC 3000/300LX under OSF/1 2.1
-+ it works when compiled with cc.
-+
-+- on Digital Unix 4.0D (formely OSF/1) on AlphaServer, the cc option -std1
-+ is necessary to get gzprintf working correctly. This is done by configure.
-+
-+- zlib doesn't work on HP-UX 9.05 with some versions of /bin/cc. It works
-+ with other compilers. Use "make test" to check your compiler.
-+
-+- gzdopen is not supported on RISCOS, BEOS and by some Mac compilers.
-+
-+- For Turbo C the small model is supported only with reduced performance to
-+ avoid any far allocation; it was tested with -DMAX_WBITS=11 -DMAX_MEM_LEVEL=3
-+
-+- For PalmOs, see http://www.cs.uit.no/~perm/PASTA/pilot/software.html
-+ Per Harald Myrvang <perm@stud.cs.uit.no>
-+
-+
-+Acknowledgments:
-+
-+ The deflate format used by zlib was defined by Phil Katz. The deflate
-+ and zlib specifications were written by L. Peter Deutsch. Thanks to all the
-+ people who reported problems and suggested various improvements in zlib;
-+ they are too numerous to cite here.
-+
-+Copyright notice:
-+
-+ (C) 1995-2002 Jean-loup Gailly and Mark Adler
-+
-+ This software is provided 'as-is', without any express or implied
-+ warranty. In no event will the authors be held liable for any damages
-+ arising from the use of this software.
-+
-+ Permission is granted to anyone to use this software for any purpose,
-+ including commercial applications, and to alter it and redistribute it
-+ freely, subject to the following restrictions:
-+
-+ 1. The origin of this software must not be misrepresented; you must not
-+ claim that you wrote the original software. If you use this software
-+ in a product, an acknowledgment in the product documentation would be
-+ appreciated but is not required.
-+ 2. Altered source versions must be plainly marked as such, and must not be
-+ misrepresented as being the original software.
-+ 3. This notice may not be removed or altered from any source distribution.
-+
-+ Jean-loup Gailly Mark Adler
-+ jloup@gzip.org madler@alumni.caltech.edu
-+
-+If you use the zlib library in a product, we would appreciate *not*
-+receiving lengthy legal documents to sign. The sources are provided
-+for free but without warranty of any kind. The library has been
-+entirely written by Jean-loup Gailly and Mark Adler; it does not
-+include third-party code.
-+
-+If you redistribute modified sources, we would appreciate that you include
-+in the file ChangeLog history information documenting your changes.
---- /dev/null Tue Mar 11 13:02:56 2003
-+++ linux/lib/zlib/README.freeswan Mon Feb 9 13:51:03 2004
-@@ -0,0 +1,13 @@
-+The only changes made to these files for use in FreeS/WAN are:
-+
-+ - In zconf.h, macros are defined to prefix global symbols with "ipcomp_"
-+ (or "_ipcomp"), when compiled with -DIPCOMP_PREFIX.
-+ - The copyright strings are defined local (static)
-+
-+ The above changes are made to avoid name collisions with ppp_deflate
-+ and ext2compr.
-+
-+ - Files not needed for FreeS/WAN have been removed
-+
-+ See the "README" file for information about where to obtain the complete
-+ zlib package.
---- /dev/null Tue Mar 11 13:02:56 2003
-+++ linux/lib/zlib/adler32.c Mon Feb 9 13:51:03 2004
-@@ -0,0 +1,49 @@
-+/* adler32.c -- compute the Adler-32 checksum of a data stream
-+ * Copyright (C) 1995-2002 Mark Adler
-+ * For conditions of distribution and use, see copyright notice in zlib.h
-+ */
-+
-+/* @(#) $Id: adler32.c,v 1.4 2002/04/24 07:55:32 mcr Exp $ */
-+
-+#include <zlib/zlib.h>
-+#include "zconf.h"
-+
-+#define BASE 65521L /* largest prime smaller than 65536 */
-+#define NMAX 5552
-+/* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */
-+
-+#define DO1(buf,i) {s1 += buf[i]; s2 += s1;}
-+#define DO2(buf,i) DO1(buf,i); DO1(buf,i+1);
-+#define DO4(buf,i) DO2(buf,i); DO2(buf,i+2);
-+#define DO8(buf,i) DO4(buf,i); DO4(buf,i+4);
-+#define DO16(buf) DO8(buf,0); DO8(buf,8);
-+
-+/* ========================================================================= */
-+uLong ZEXPORT adler32(adler, buf, len)
-+ uLong adler;
-+ const Bytef *buf;
-+ uInt len;
-+{
-+ unsigned long s1 = adler & 0xffff;
-+ unsigned long s2 = (adler >> 16) & 0xffff;
-+ int k;
-+
-+ if (buf == Z_NULL) return 1L;
-+
-+ while (len > 0) {
-+ k = len < NMAX ? len : NMAX;
-+ len -= k;
-+ while (k >= 16) {
-+ DO16(buf);
-+ buf += 16;
-+ k -= 16;
-+ }
-+ if (k != 0) do {
-+ s1 += *buf++;
-+ s2 += s1;
-+ } while (--k);
-+ s1 %= BASE;
-+ s2 %= BASE;
-+ }
-+ return (s2 << 16) | s1;
-+}
---- /dev/null Tue Mar 11 13:02:56 2003
-+++ linux/lib/zlib/deflate.c Mon Feb 9 13:51:03 2004
-@@ -0,0 +1,1351 @@
-+/* deflate.c -- compress data using the deflation algorithm
-+ * Copyright (C) 1995-2002 Jean-loup Gailly.
-+ * For conditions of distribution and use, see copyright notice in zlib.h
-+ */
-+
-+/*
-+ * ALGORITHM
-+ *
-+ * The "deflation" process depends on being able to identify portions
-+ * of the input text which are identical to earlier input (within a
-+ * sliding window trailing behind the input currently being processed).
-+ *
-+ * The most straightforward technique turns out to be the fastest for
-+ * most input files: try all possible matches and select the longest.
-+ * The key feature of this algorithm is that insertions into the string
-+ * dictionary are very simple and thus fast, and deletions are avoided
-+ * completely. Insertions are performed at each input character, whereas
-+ * string matches are performed only when the previous match ends. So it
-+ * is preferable to spend more time in matches to allow very fast string
-+ * insertions and avoid deletions. The matching algorithm for small
-+ * strings is inspired from that of Rabin & Karp. A brute force approach
-+ * is used to find longer strings when a small match has been found.
-+ * A similar algorithm is used in comic (by Jan-Mark Wams) and freeze
-+ * (by Leonid Broukhis).
-+ * A previous version of this file used a more sophisticated algorithm
-+ * (by Fiala and Greene) which is guaranteed to run in linear amortized
-+ * time, but has a larger average cost, uses more memory and is patented.
-+ * However the F&G algorithm may be faster for some highly redundant
-+ * files if the parameter max_chain_length (described below) is too large.
-+ *
-+ * ACKNOWLEDGEMENTS
-+ *
-+ * The idea of lazy evaluation of matches is due to Jan-Mark Wams, and
-+ * I found it in 'freeze' written by Leonid Broukhis.
-+ * Thanks to many people for bug reports and testing.
-+ *
-+ * REFERENCES
-+ *
-+ * Deutsch, L.P.,"DEFLATE Compressed Data Format Specification".
-+ * Available in ftp://ds.internic.net/rfc/rfc1951.txt
-+ *
-+ * A description of the Rabin and Karp algorithm is given in the book
-+ * "Algorithms" by R. Sedgewick, Addison-Wesley, p252.
-+ *
-+ * Fiala,E.R., and Greene,D.H.
-+ * Data Compression with Finite Windows, Comm.ACM, 32,4 (1989) 490-595
-+ *
-+ */
-+
-+/* @(#) $Id: deflate.c,v 1.3 2002/04/24 07:36:44 mcr Exp $ */
-+
-+#include "deflate.h"
-+
-+local const char deflate_copyright[] =
-+ " deflate 1.1.4 Copyright 1995-2002 Jean-loup Gailly ";
-+/*
-+ If you use the zlib library in a product, an acknowledgment is welcome
-+ in the documentation of your product. If for some reason you cannot
-+ include such an acknowledgment, I would appreciate that you keep this
-+ copyright string in the executable of your product.
-+ */
-+
-+/* ===========================================================================
-+ * Function prototypes.
-+ */
-+typedef enum {
-+ need_more, /* block not completed, need more input or more output */
-+ block_done, /* block flush performed */
-+ finish_started, /* finish started, need only more output at next deflate */
-+ finish_done /* finish done, accept no more input or output */
-+} block_state;
-+
-+typedef block_state (*compress_func) OF((deflate_state *s, int flush));
-+/* Compression function. Returns the block state after the call. */
-+
-+local void fill_window OF((deflate_state *s));
-+local block_state deflate_stored OF((deflate_state *s, int flush));
-+local block_state deflate_fast OF((deflate_state *s, int flush));
-+local block_state deflate_slow OF((deflate_state *s, int flush));
-+local void lm_init OF((deflate_state *s));
-+local void putShortMSB OF((deflate_state *s, uInt b));
-+local void flush_pending OF((z_streamp strm));
-+local int read_buf OF((z_streamp strm, Bytef *buf, unsigned size));
-+#ifdef ASMV
-+ void match_init OF((void)); /* asm code initialization */
-+ uInt longest_match OF((deflate_state *s, IPos cur_match));
-+#else
-+local uInt longest_match OF((deflate_state *s, IPos cur_match));
-+#endif
-+
-+#ifdef DEBUG
-+local void check_match OF((deflate_state *s, IPos start, IPos match,
-+ int length));
-+#endif
-+
-+/* ===========================================================================
-+ * Local data
-+ */
-+
-+#define NIL 0
-+/* Tail of hash chains */
-+
-+#ifndef TOO_FAR
-+# define TOO_FAR 4096
-+#endif
-+/* Matches of length 3 are discarded if their distance exceeds TOO_FAR */
-+
-+#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1)
-+/* Minimum amount of lookahead, except at the end of the input file.
-+ * See deflate.c for comments about the MIN_MATCH+1.
-+ */
-+
-+/* Values for max_lazy_match, good_match and max_chain_length, depending on
-+ * the desired pack level (0..9). The values given below have been tuned to
-+ * exclude worst case performance for pathological files. Better values may be
-+ * found for specific files.
-+ */
-+typedef struct config_s {
-+ ush good_length; /* reduce lazy search above this match length */
-+ ush max_lazy; /* do not perform lazy search above this match length */
-+ ush nice_length; /* quit search above this match length */
-+ ush max_chain;
-+ compress_func func;
-+} config;
-+
-+local const config configuration_table[10] = {
-+/* good lazy nice chain */
-+/* 0 */ {0, 0, 0, 0, deflate_stored}, /* store only */
-+/* 1 */ {4, 4, 8, 4, deflate_fast}, /* maximum speed, no lazy matches */
-+/* 2 */ {4, 5, 16, 8, deflate_fast},
-+/* 3 */ {4, 6, 32, 32, deflate_fast},
-+
-+/* 4 */ {4, 4, 16, 16, deflate_slow}, /* lazy matches */
-+/* 5 */ {8, 16, 32, 32, deflate_slow},
-+/* 6 */ {8, 16, 128, 128, deflate_slow},
-+/* 7 */ {8, 32, 128, 256, deflate_slow},
-+/* 8 */ {32, 128, 258, 1024, deflate_slow},
-+/* 9 */ {32, 258, 258, 4096, deflate_slow}}; /* maximum compression */
-+
-+/* Note: the deflate() code requires max_lazy >= MIN_MATCH and max_chain >= 4
-+ * For deflate_fast() (levels <= 3) good is ignored and lazy has a different
-+ * meaning.
-+ */
-+
-+#define EQUAL 0
-+/* result of memcmp for equal strings */
-+
-+struct static_tree_desc_s {int dummy;}; /* for buggy compilers */
-+
-+/* ===========================================================================
-+ * Update a hash value with the given input byte
-+ * IN assertion: all calls to to UPDATE_HASH are made with consecutive
-+ * input characters, so that a running hash key can be computed from the
-+ * previous key instead of complete recalculation each time.
-+ */
-+#define UPDATE_HASH(s,h,c) (h = (((h)<<s->hash_shift) ^ (c)) & s->hash_mask)
-+
-+
-+/* ===========================================================================
-+ * Insert string str in the dictionary and set match_head to the previous head
-+ * of the hash chain (the most recent string with same hash key). Return
-+ * the previous length of the hash chain.
-+ * If this file is compiled with -DFASTEST, the compression level is forced
-+ * to 1, and no hash chains are maintained.
-+ * IN assertion: all calls to to INSERT_STRING are made with consecutive
-+ * input characters and the first MIN_MATCH bytes of str are valid
-+ * (except for the last MIN_MATCH-1 bytes of the input file).
-+ */
-+#ifdef FASTEST
-+#define INSERT_STRING(s, str, match_head) \
-+ (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \
-+ match_head = s->head[s->ins_h], \
-+ s->head[s->ins_h] = (Pos)(str))
-+#else
-+#define INSERT_STRING(s, str, match_head) \
-+ (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \
-+ s->prev[(str) & s->w_mask] = match_head = s->head[s->ins_h], \
-+ s->head[s->ins_h] = (Pos)(str))
-+#endif
-+
-+/* ===========================================================================
-+ * Initialize the hash table (avoiding 64K overflow for 16 bit systems).
-+ * prev[] will be initialized on the fly.
-+ */
-+#define CLEAR_HASH(s) \
-+ s->head[s->hash_size-1] = NIL; \
-+ zmemzero((Bytef *)s->head, (unsigned)(s->hash_size-1)*sizeof(*s->head));
-+
-+/* ========================================================================= */
-+int ZEXPORT deflateInit_(strm, level, version, stream_size)
-+ z_streamp strm;
-+ int level;
-+ const char *version;
-+ int stream_size;
-+{
-+ return deflateInit2_(strm, level, Z_DEFLATED, MAX_WBITS, DEF_MEM_LEVEL,
-+ Z_DEFAULT_STRATEGY, version, stream_size);
-+ /* To do: ignore strm->next_in if we use it as window */
-+}
-+
-+/* ========================================================================= */
-+int ZEXPORT deflateInit2_(strm, level, method, windowBits, memLevel, strategy,
-+ version, stream_size)
-+ z_streamp strm;
-+ int level;
-+ int method;
-+ int windowBits;
-+ int memLevel;
-+ int strategy;
-+ const char *version;
-+ int stream_size;
-+{
-+ deflate_state *s;
-+ int noheader = 0;
-+ static const char* my_version = ZLIB_VERSION;
-+
-+ ushf *overlay;
-+ /* We overlay pending_buf and d_buf+l_buf. This works since the average
-+ * output size for (length,distance) codes is <= 24 bits.
-+ */
-+
-+ if (version == Z_NULL || version[0] != my_version[0] ||
-+ stream_size != sizeof(z_stream)) {
-+ return Z_VERSION_ERROR;
-+ }
-+ if (strm == Z_NULL) return Z_STREAM_ERROR;
-+
-+ strm->msg = Z_NULL;
-+ if (strm->zalloc == Z_NULL) {
-+ return Z_STREAM_ERROR;
-+/* strm->zalloc = zcalloc;
-+ strm->opaque = (voidpf)0;*/
-+ }
-+ if (strm->zfree == Z_NULL) return Z_STREAM_ERROR; /* strm->zfree = zcfree; */
-+
-+ if (level == Z_DEFAULT_COMPRESSION) level = 6;
-+#ifdef FASTEST
-+ level = 1;
-+#endif
-+
-+ if (windowBits < 0) { /* undocumented feature: suppress zlib header */
-+ noheader = 1;
-+ windowBits = -windowBits;
-+ }
-+ if (memLevel < 1 || memLevel > MAX_MEM_LEVEL || method != Z_DEFLATED ||
-+ windowBits < 9 || windowBits > 15 || level < 0 || level > 9 ||
-+ strategy < 0 || strategy > Z_HUFFMAN_ONLY) {
-+ return Z_STREAM_ERROR;
-+ }
-+ s = (deflate_state *) ZALLOC(strm, 1, sizeof(deflate_state));
-+ if (s == Z_NULL) return Z_MEM_ERROR;
-+ strm->state = (struct internal_state FAR *)s;
-+ s->strm = strm;
-+
-+ s->noheader = noheader;
-+ s->w_bits = windowBits;
-+ s->w_size = 1 << s->w_bits;
-+ s->w_mask = s->w_size - 1;
-+
-+ s->hash_bits = memLevel + 7;
-+ s->hash_size = 1 << s->hash_bits;
-+ s->hash_mask = s->hash_size - 1;
-+ s->hash_shift = ((s->hash_bits+MIN_MATCH-1)/MIN_MATCH);
-+
-+ s->window = (Bytef *) ZALLOC(strm, s->w_size, 2*sizeof(Byte));
-+ s->prev = (Posf *) ZALLOC(strm, s->w_size, sizeof(Pos));
-+ s->head = (Posf *) ZALLOC(strm, s->hash_size, sizeof(Pos));
-+
-+ s->lit_bufsize = 1 << (memLevel + 6); /* 16K elements by default */
-+
-+ overlay = (ushf *) ZALLOC(strm, s->lit_bufsize, sizeof(ush)+2);
-+ s->pending_buf = (uchf *) overlay;
-+ s->pending_buf_size = (ulg)s->lit_bufsize * (sizeof(ush)+2L);
-+
-+ if (s->window == Z_NULL || s->prev == Z_NULL || s->head == Z_NULL ||
-+ s->pending_buf == Z_NULL) {
-+ strm->msg = ERR_MSG(Z_MEM_ERROR);
-+ deflateEnd (strm);
-+ return Z_MEM_ERROR;
-+ }
-+ s->d_buf = overlay + s->lit_bufsize/sizeof(ush);
-+ s->l_buf = s->pending_buf + (1+sizeof(ush))*s->lit_bufsize;
-+
-+ s->level = level;
-+ s->strategy = strategy;
-+ s->method = (Byte)method;
-+
-+ return deflateReset(strm);
-+}
-+
-+/* ========================================================================= */
-+int ZEXPORT deflateSetDictionary (strm, dictionary, dictLength)
-+ z_streamp strm;
-+ const Bytef *dictionary;
-+ uInt dictLength;
-+{
-+ deflate_state *s;
-+ uInt length = dictLength;
-+ uInt n;
-+ IPos hash_head = 0;
-+
-+ if (strm == Z_NULL || strm->state == Z_NULL || dictionary == Z_NULL ||
-+ strm->state->status != INIT_STATE) return Z_STREAM_ERROR;
-+
-+ s = strm->state;
-+ strm->adler = adler32(strm->adler, dictionary, dictLength);
-+
-+ if (length < MIN_MATCH) return Z_OK;
-+ if (length > MAX_DIST(s)) {
-+ length = MAX_DIST(s);
-+#ifndef USE_DICT_HEAD
-+ dictionary += dictLength - length; /* use the tail of the dictionary */
-+#endif
-+ }
-+ zmemcpy(s->window, dictionary, length);
-+ s->strstart = length;
-+ s->block_start = (long)length;
-+
-+ /* Insert all strings in the hash table (except for the last two bytes).
-+ * s->lookahead stays null, so s->ins_h will be recomputed at the next
-+ * call of fill_window.
-+ */
-+ s->ins_h = s->window[0];
-+ UPDATE_HASH(s, s->ins_h, s->window[1]);
-+ for (n = 0; n <= length - MIN_MATCH; n++) {
-+ INSERT_STRING(s, n, hash_head);
-+ }
-+ if (hash_head) hash_head = 0; /* to make compiler happy */
-+ return Z_OK;
-+}
-+
-+/* ========================================================================= */
-+int ZEXPORT deflateReset (strm)
-+ z_streamp strm;
-+{
-+ deflate_state *s;
-+
-+ if (strm == Z_NULL || strm->state == Z_NULL ||
-+ strm->zalloc == Z_NULL || strm->zfree == Z_NULL) return Z_STREAM_ERROR;
-+
-+ strm->total_in = strm->total_out = 0;
-+ strm->msg = Z_NULL; /* use zfree if we ever allocate msg dynamically */
-+ strm->data_type = Z_UNKNOWN;
-+
-+ s = (deflate_state *)strm->state;
-+ s->pending = 0;
-+ s->pending_out = s->pending_buf;
-+
-+ if (s->noheader < 0) {
-+ s->noheader = 0; /* was set to -1 by deflate(..., Z_FINISH); */
-+ }
-+ s->status = s->noheader ? BUSY_STATE : INIT_STATE;
-+ strm->adler = 1;
-+ s->last_flush = Z_NO_FLUSH;
-+
-+ _tr_init(s);
-+ lm_init(s);
-+
-+ return Z_OK;
-+}
-+
-+/* ========================================================================= */
-+int ZEXPORT deflateParams(strm, level, strategy)
-+ z_streamp strm;
-+ int level;
-+ int strategy;
-+{
-+ deflate_state *s;
-+ compress_func func;
-+ int err = Z_OK;
-+
-+ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
-+ s = strm->state;
-+
-+ if (level == Z_DEFAULT_COMPRESSION) {
-+ level = 6;
-+ }
-+ if (level < 0 || level > 9 || strategy < 0 || strategy > Z_HUFFMAN_ONLY) {
-+ return Z_STREAM_ERROR;
-+ }
-+ func = configuration_table[s->level].func;
-+
-+ if (func != configuration_table[level].func && strm->total_in != 0) {
-+ /* Flush the last buffer: */
-+ err = deflate(strm, Z_PARTIAL_FLUSH);
-+ }
-+ if (s->level != level) {
-+ s->level = level;
-+ s->max_lazy_match = configuration_table[level].max_lazy;
-+ s->good_match = configuration_table[level].good_length;
-+ s->nice_match = configuration_table[level].nice_length;
-+ s->max_chain_length = configuration_table[level].max_chain;
-+ }
-+ s->strategy = strategy;
-+ return err;
-+}
-+
-+/* =========================================================================
-+ * Put a short in the pending buffer. The 16-bit value is put in MSB order.
-+ * IN assertion: the stream state is correct and there is enough room in
-+ * pending_buf.
-+ */
-+local void putShortMSB (s, b)
-+ deflate_state *s;
-+ uInt b;
-+{
-+ put_byte(s, (Byte)(b >> 8));
-+ put_byte(s, (Byte)(b & 0xff));
-+}
-+
-+/* =========================================================================
-+ * Flush as much pending output as possible. All deflate() output goes
-+ * through this function so some applications may wish to modify it
-+ * to avoid allocating a large strm->next_out buffer and copying into it.
-+ * (See also read_buf()).
-+ */
-+local void flush_pending(strm)
-+ z_streamp strm;
-+{
-+ unsigned len = strm->state->pending;
-+
-+ if (len > strm->avail_out) len = strm->avail_out;
-+ if (len == 0) return;
-+
-+ zmemcpy(strm->next_out, strm->state->pending_out, len);
-+ strm->next_out += len;
-+ strm->state->pending_out += len;
-+ strm->total_out += len;
-+ strm->avail_out -= len;
-+ strm->state->pending -= len;
-+ if (strm->state->pending == 0) {
-+ strm->state->pending_out = strm->state->pending_buf;
-+ }
-+}
-+
-+/* ========================================================================= */
-+int ZEXPORT deflate (strm, flush)
-+ z_streamp strm;
-+ int flush;
-+{
-+ int old_flush; /* value of flush param for previous deflate call */
-+ deflate_state *s;
-+
-+ if (strm == Z_NULL || strm->state == Z_NULL ||
-+ flush > Z_FINISH || flush < 0) {
-+ return Z_STREAM_ERROR;
-+ }
-+ s = strm->state;
-+
-+ if (strm->next_out == Z_NULL ||
-+ (strm->next_in == Z_NULL && strm->avail_in != 0) ||
-+ (s->status == FINISH_STATE && flush != Z_FINISH)) {
-+ ERR_RETURN(strm, Z_STREAM_ERROR);
-+ }
-+ if (strm->avail_out == 0) ERR_RETURN(strm, Z_BUF_ERROR);
-+
-+ s->strm = strm; /* just in case */
-+ old_flush = s->last_flush;
-+ s->last_flush = flush;
-+
-+ /* Write the zlib header */
-+ if (s->status == INIT_STATE) {
-+
-+ uInt header = (Z_DEFLATED + ((s->w_bits-8)<<4)) << 8;
-+ uInt level_flags = (s->level-1) >> 1;
-+
-+ if (level_flags > 3) level_flags = 3;
-+ header |= (level_flags << 6);
-+ if (s->strstart != 0) header |= PRESET_DICT;
-+ header += 31 - (header % 31);
-+
-+ s->status = BUSY_STATE;
-+ putShortMSB(s, header);
-+
-+ /* Save the adler32 of the preset dictionary: */
-+ if (s->strstart != 0) {
-+ putShortMSB(s, (uInt)(strm->adler >> 16));
-+ putShortMSB(s, (uInt)(strm->adler & 0xffff));
-+ }
-+ strm->adler = 1L;
-+ }
-+
-+ /* Flush as much pending output as possible */
-+ if (s->pending != 0) {
-+ flush_pending(strm);
-+ if (strm->avail_out == 0) {
-+ /* Since avail_out is 0, deflate will be called again with
-+ * more output space, but possibly with both pending and
-+ * avail_in equal to zero. There won't be anything to do,
-+ * but this is not an error situation so make sure we
-+ * return OK instead of BUF_ERROR at next call of deflate:
-+ */
-+ s->last_flush = -1;
-+ return Z_OK;
-+ }
-+
-+ /* Make sure there is something to do and avoid duplicate consecutive
-+ * flushes. For repeated and useless calls with Z_FINISH, we keep
-+ * returning Z_STREAM_END instead of Z_BUFF_ERROR.
-+ */
-+ } else if (strm->avail_in == 0 && flush <= old_flush &&
-+ flush != Z_FINISH) {
-+ ERR_RETURN(strm, Z_BUF_ERROR);
-+ }
-+
-+ /* User must not provide more input after the first FINISH: */
-+ if (s->status == FINISH_STATE && strm->avail_in != 0) {
-+ ERR_RETURN(strm, Z_BUF_ERROR);
-+ }
-+
-+ /* Start a new block or continue the current one.
-+ */
-+ if (strm->avail_in != 0 || s->lookahead != 0 ||
-+ (flush != Z_NO_FLUSH && s->status != FINISH_STATE)) {
-+ block_state bstate;
-+
-+ bstate = (*(configuration_table[s->level].func))(s, flush);
-+
-+ if (bstate == finish_started || bstate == finish_done) {
-+ s->status = FINISH_STATE;
-+ }
-+ if (bstate == need_more || bstate == finish_started) {
-+ if (strm->avail_out == 0) {
-+ s->last_flush = -1; /* avoid BUF_ERROR next call, see above */
-+ }
-+ return Z_OK;
-+ /* If flush != Z_NO_FLUSH && avail_out == 0, the next call
-+ * of deflate should use the same flush parameter to make sure
-+ * that the flush is complete. So we don't have to output an
-+ * empty block here, this will be done at next call. This also
-+ * ensures that for a very small output buffer, we emit at most
-+ * one empty block.
-+ */
-+ }
-+ if (bstate == block_done) {
-+ if (flush == Z_PARTIAL_FLUSH) {
-+ _tr_align(s);
-+ } else { /* FULL_FLUSH or SYNC_FLUSH */
-+ _tr_stored_block(s, (char*)0, 0L, 0);
-+ /* For a full flush, this empty block will be recognized
-+ * as a special marker by inflate_sync().
-+ */
-+ if (flush == Z_FULL_FLUSH) {
-+ CLEAR_HASH(s); /* forget history */
-+ }
-+ }
-+ flush_pending(strm);
-+ if (strm->avail_out == 0) {
-+ s->last_flush = -1; /* avoid BUF_ERROR at next call, see above */
-+ return Z_OK;
-+ }
-+ }
-+ }
-+ Assert(strm->avail_out > 0, "bug2");
-+
-+ if (flush != Z_FINISH) return Z_OK;
-+ if (s->noheader) return Z_STREAM_END;
-+
-+ /* Write the zlib trailer (adler32) */
-+ putShortMSB(s, (uInt)(strm->adler >> 16));
-+ putShortMSB(s, (uInt)(strm->adler & 0xffff));
-+ flush_pending(strm);
-+ /* If avail_out is zero, the application will call deflate again
-+ * to flush the rest.
-+ */
-+ s->noheader = -1; /* write the trailer only once! */
-+ return s->pending != 0 ? Z_OK : Z_STREAM_END;
-+}
-+
-+/* ========================================================================= */
-+int ZEXPORT deflateEnd (strm)
-+ z_streamp strm;
-+{
-+ int status;
-+
-+ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
-+
-+ status = strm->state->status;
-+ if (status != INIT_STATE && status != BUSY_STATE &&
-+ status != FINISH_STATE) {
-+ return Z_STREAM_ERROR;
-+ }
-+
-+ /* Deallocate in reverse order of allocations: */
-+ TRY_FREE(strm, strm->state->pending_buf);
-+ TRY_FREE(strm, strm->state->head);
-+ TRY_FREE(strm, strm->state->prev);
-+ TRY_FREE(strm, strm->state->window);
-+
-+ ZFREE(strm, strm->state);
-+ strm->state = Z_NULL;
-+
-+ return status == BUSY_STATE ? Z_DATA_ERROR : Z_OK;
-+}
-+
-+/* =========================================================================
-+ * Copy the source state to the destination state.
-+ * To simplify the source, this is not supported for 16-bit MSDOS (which
-+ * doesn't have enough memory anyway to duplicate compression states).
-+ */
-+int ZEXPORT deflateCopy (dest, source)
-+ z_streamp dest;
-+ z_streamp source;
-+{
-+#ifdef MAXSEG_64K
-+ return Z_STREAM_ERROR;
-+#else
-+ deflate_state *ds;
-+ deflate_state *ss;
-+ ushf *overlay;
-+
-+
-+ if (source == Z_NULL || dest == Z_NULL || source->state == Z_NULL) {
-+ return Z_STREAM_ERROR;
-+ }
-+
-+ ss = source->state;
-+
-+ *dest = *source;
-+
-+ ds = (deflate_state *) ZALLOC(dest, 1, sizeof(deflate_state));
-+ if (ds == Z_NULL) return Z_MEM_ERROR;
-+ dest->state = (struct internal_state FAR *) ds;
-+ *ds = *ss;
-+ ds->strm = dest;
-+
-+ ds->window = (Bytef *) ZALLOC(dest, ds->w_size, 2*sizeof(Byte));
-+ ds->prev = (Posf *) ZALLOC(dest, ds->w_size, sizeof(Pos));
-+ ds->head = (Posf *) ZALLOC(dest, ds->hash_size, sizeof(Pos));
-+ overlay = (ushf *) ZALLOC(dest, ds->lit_bufsize, sizeof(ush)+2);
-+ ds->pending_buf = (uchf *) overlay;
-+
-+ if (ds->window == Z_NULL || ds->prev == Z_NULL || ds->head == Z_NULL ||
-+ ds->pending_buf == Z_NULL) {
-+ deflateEnd (dest);
-+ return Z_MEM_ERROR;
-+ }
-+ /* following zmemcpy do not work for 16-bit MSDOS */
-+ zmemcpy(ds->window, ss->window, ds->w_size * 2 * sizeof(Byte));
-+ zmemcpy(ds->prev, ss->prev, ds->w_size * sizeof(Pos));
-+ zmemcpy(ds->head, ss->head, ds->hash_size * sizeof(Pos));
-+ zmemcpy(ds->pending_buf, ss->pending_buf, (uInt)ds->pending_buf_size);
-+
-+ ds->pending_out = ds->pending_buf + (ss->pending_out - ss->pending_buf);
-+ ds->d_buf = overlay + ds->lit_bufsize/sizeof(ush);
-+ ds->l_buf = ds->pending_buf + (1+sizeof(ush))*ds->lit_bufsize;
-+
-+ ds->l_desc.dyn_tree = ds->dyn_ltree;
-+ ds->d_desc.dyn_tree = ds->dyn_dtree;
-+ ds->bl_desc.dyn_tree = ds->bl_tree;
-+
-+ return Z_OK;
-+#endif
-+}
-+
-+/* ===========================================================================
-+ * Read a new buffer from the current input stream, update the adler32
-+ * and total number of bytes read. All deflate() input goes through
-+ * this function so some applications may wish to modify it to avoid
-+ * allocating a large strm->next_in buffer and copying from it.
-+ * (See also flush_pending()).
-+ */
-+local int read_buf(strm, buf, size)
-+ z_streamp strm;
-+ Bytef *buf;
-+ unsigned size;
-+{
-+ unsigned len = strm->avail_in;
-+
-+ if (len > size) len = size;
-+ if (len == 0) return 0;
-+
-+ strm->avail_in -= len;
-+
-+ if (!strm->state->noheader) {
-+ strm->adler = adler32(strm->adler, strm->next_in, len);
-+ }
-+ zmemcpy(buf, strm->next_in, len);
-+ strm->next_in += len;
-+ strm->total_in += len;
-+
-+ return (int)len;
-+}
-+
-+/* ===========================================================================
-+ * Initialize the "longest match" routines for a new zlib stream
-+ */
-+local void lm_init (s)
-+ deflate_state *s;
-+{
-+ s->window_size = (ulg)2L*s->w_size;
-+
-+ CLEAR_HASH(s);
-+
-+ /* Set the default configuration parameters:
-+ */
-+ s->max_lazy_match = configuration_table[s->level].max_lazy;
-+ s->good_match = configuration_table[s->level].good_length;
-+ s->nice_match = configuration_table[s->level].nice_length;
-+ s->max_chain_length = configuration_table[s->level].max_chain;
-+
-+ s->strstart = 0;
-+ s->block_start = 0L;
-+ s->lookahead = 0;
-+ s->match_length = s->prev_length = MIN_MATCH-1;
-+ s->match_available = 0;
-+ s->ins_h = 0;
-+#ifdef ASMV
-+ match_init(); /* initialize the asm code */
-+#endif
-+}
-+
-+/* ===========================================================================
-+ * Set match_start to the longest match starting at the given string and
-+ * return its length. Matches shorter or equal to prev_length are discarded,
-+ * in which case the result is equal to prev_length and match_start is
-+ * garbage.
-+ * IN assertions: cur_match is the head of the hash chain for the current
-+ * string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1
-+ * OUT assertion: the match length is not greater than s->lookahead.
-+ */
-+#ifndef ASMV
-+/* For 80x86 and 680x0, an optimized version will be provided in match.asm or
-+ * match.S. The code will be functionally equivalent.
-+ */
-+#ifndef FASTEST
-+local uInt longest_match(s, cur_match)
-+ deflate_state *s;
-+ IPos cur_match; /* current match */
-+{
-+ unsigned chain_length = s->max_chain_length;/* max hash chain length */
-+ register Bytef *scan = s->window + s->strstart; /* current string */
-+ register Bytef *match; /* matched string */
-+ register int len; /* length of current match */
-+ int best_len = s->prev_length; /* best match length so far */
-+ int nice_match = s->nice_match; /* stop if match long enough */
-+ IPos limit = s->strstart > (IPos)MAX_DIST(s) ?
-+ s->strstart - (IPos)MAX_DIST(s) : NIL;
-+ /* Stop when cur_match becomes <= limit. To simplify the code,
-+ * we prevent matches with the string of window index 0.
-+ */
-+ Posf *prev = s->prev;
-+ uInt wmask = s->w_mask;
-+
-+#ifdef UNALIGNED_OK
-+ /* Compare two bytes at a time. Note: this is not always beneficial.
-+ * Try with and without -DUNALIGNED_OK to check.
-+ */
-+ register Bytef *strend = s->window + s->strstart + MAX_MATCH - 1;
-+ register ush scan_start = *(ushf*)scan;
-+ register ush scan_end = *(ushf*)(scan+best_len-1);
-+#else
-+ register Bytef *strend = s->window + s->strstart + MAX_MATCH;
-+ register Byte scan_end1 = scan[best_len-1];
-+ register Byte scan_end = scan[best_len];
-+#endif
-+
-+ /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16.
-+ * It is easy to get rid of this optimization if necessary.
-+ */
-+ Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever");
-+
-+ /* Do not waste too much time if we already have a good match: */
-+ if (s->prev_length >= s->good_match) {
-+ chain_length >>= 2;
-+ }
-+ /* Do not look for matches beyond the end of the input. This is necessary
-+ * to make deflate deterministic.
-+ */
-+ if ((uInt)nice_match > s->lookahead) nice_match = s->lookahead;
-+
-+ Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead");
-+
-+ do {
-+ Assert(cur_match < s->strstart, "no future");
-+ match = s->window + cur_match;
-+
-+ /* Skip to next match if the match length cannot increase
-+ * or if the match length is less than 2:
-+ */
-+#if (defined(UNALIGNED_OK) && MAX_MATCH == 258)
-+ /* This code assumes sizeof(unsigned short) == 2. Do not use
-+ * UNALIGNED_OK if your compiler uses a different size.
-+ */
-+ if (*(ushf*)(match+best_len-1) != scan_end ||
-+ *(ushf*)match != scan_start) continue;
-+
-+ /* It is not necessary to compare scan[2] and match[2] since they are
-+ * always equal when the other bytes match, given that the hash keys
-+ * are equal and that HASH_BITS >= 8. Compare 2 bytes at a time at
-+ * strstart+3, +5, ... up to strstart+257. We check for insufficient
-+ * lookahead only every 4th comparison; the 128th check will be made
-+ * at strstart+257. If MAX_MATCH-2 is not a multiple of 8, it is
-+ * necessary to put more guard bytes at the end of the window, or
-+ * to check more often for insufficient lookahead.
-+ */
-+ Assert(scan[2] == match[2], "scan[2]?");
-+ scan++, match++;
-+ do {
-+ } while (*(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
-+ *(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
-+ *(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
-+ *(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
-+ scan < strend);
-+ /* The funny "do {}" generates better code on most compilers */
-+
-+ /* Here, scan <= window+strstart+257 */
-+ Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan");
-+ if (*scan == *match) scan++;
-+
-+ len = (MAX_MATCH - 1) - (int)(strend-scan);
-+ scan = strend - (MAX_MATCH-1);
-+
-+#else /* UNALIGNED_OK */
-+
-+ if (match[best_len] != scan_end ||
-+ match[best_len-1] != scan_end1 ||
-+ *match != *scan ||
-+ *++match != scan[1]) continue;
-+
-+ /* The check at best_len-1 can be removed because it will be made
-+ * again later. (This heuristic is not always a win.)
-+ * It is not necessary to compare scan[2] and match[2] since they
-+ * are always equal when the other bytes match, given that
-+ * the hash keys are equal and that HASH_BITS >= 8.
-+ */
-+ scan += 2, match++;
-+ Assert(*scan == *match, "match[2]?");
-+
-+ /* We check for insufficient lookahead only every 8th comparison;
-+ * the 256th check will be made at strstart+258.
-+ */
-+ do {
-+ } while (*++scan == *++match && *++scan == *++match &&
-+ *++scan == *++match && *++scan == *++match &&
-+ *++scan == *++match && *++scan == *++match &&
-+ *++scan == *++match && *++scan == *++match &&
-+ scan < strend);
-+
-+ Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan");
-+
-+ len = MAX_MATCH - (int)(strend - scan);
-+ scan = strend - MAX_MATCH;
-+
-+#endif /* UNALIGNED_OK */
-+
-+ if (len > best_len) {
-+ s->match_start = cur_match;
-+ best_len = len;
-+ if (len >= nice_match) break;
-+#ifdef UNALIGNED_OK
-+ scan_end = *(ushf*)(scan+best_len-1);
-+#else
-+ scan_end1 = scan[best_len-1];
-+ scan_end = scan[best_len];
-+#endif
-+ }
-+ } while ((cur_match = prev[cur_match & wmask]) > limit
-+ && --chain_length != 0);
-+
-+ if ((uInt)best_len <= s->lookahead) return (uInt)best_len;
-+ return s->lookahead;
-+}
-+
-+#else /* FASTEST */
-+/* ---------------------------------------------------------------------------
-+ * Optimized version for level == 1 only
-+ */
-+local uInt longest_match(s, cur_match)
-+ deflate_state *s;
-+ IPos cur_match; /* current match */
-+{
-+ register Bytef *scan = s->window + s->strstart; /* current string */
-+ register Bytef *match; /* matched string */
-+ register int len; /* length of current match */
-+ register Bytef *strend = s->window + s->strstart + MAX_MATCH;
-+
-+ /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16.
-+ * It is easy to get rid of this optimization if necessary.
-+ */
-+ Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever");
-+
-+ Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead");
-+
-+ Assert(cur_match < s->strstart, "no future");
-+
-+ match = s->window + cur_match;
-+
-+ /* Return failure if the match length is less than 2:
-+ */
-+ if (match[0] != scan[0] || match[1] != scan[1]) return MIN_MATCH-1;
-+
-+ /* The check at best_len-1 can be removed because it will be made
-+ * again later. (This heuristic is not always a win.)
-+ * It is not necessary to compare scan[2] and match[2] since they
-+ * are always equal when the other bytes match, given that
-+ * the hash keys are equal and that HASH_BITS >= 8.
-+ */
-+ scan += 2, match += 2;
-+ Assert(*scan == *match, "match[2]?");
-+
-+ /* We check for insufficient lookahead only every 8th comparison;
-+ * the 256th check will be made at strstart+258.
-+ */
-+ do {
-+ } while (*++scan == *++match && *++scan == *++match &&
-+ *++scan == *++match && *++scan == *++match &&
-+ *++scan == *++match && *++scan == *++match &&
-+ *++scan == *++match && *++scan == *++match &&
-+ scan < strend);
-+
-+ Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan");
-+
-+ len = MAX_MATCH - (int)(strend - scan);
-+
-+ if (len < MIN_MATCH) return MIN_MATCH - 1;
-+
-+ s->match_start = cur_match;
-+ return len <= s->lookahead ? len : s->lookahead;
-+}
-+#endif /* FASTEST */
-+#endif /* ASMV */
-+
-+#ifdef DEBUG
-+/* ===========================================================================
-+ * Check that the match at match_start is indeed a match.
-+ */
-+local void check_match(s, start, match, length)
-+ deflate_state *s;
-+ IPos start, match;
-+ int length;
-+{
-+ /* check that the match is indeed a match */
-+ if (zmemcmp(s->window + match,
-+ s->window + start, length) != EQUAL) {
-+ fprintf(stderr, " start %u, match %u, length %d\n",
-+ start, match, length);
-+ do {
-+ fprintf(stderr, "%c%c", s->window[match++], s->window[start++]);
-+ } while (--length != 0);
-+ z_error("invalid match");
-+ }
-+ if (z_verbose > 1) {
-+ fprintf(stderr,"\\[%d,%d]", start-match, length);
-+ do { putc(s->window[start++], stderr); } while (--length != 0);
-+ }
-+}
-+#else
-+# define check_match(s, start, match, length)
-+#endif
-+
-+/* ===========================================================================
-+ * Fill the window when the lookahead becomes insufficient.
-+ * Updates strstart and lookahead.
-+ *
-+ * IN assertion: lookahead < MIN_LOOKAHEAD
-+ * OUT assertions: strstart <= window_size-MIN_LOOKAHEAD
-+ * At least one byte has been read, or avail_in == 0; reads are
-+ * performed for at least two bytes (required for the zip translate_eol
-+ * option -- not supported here).
-+ */
-+local void fill_window(s)
-+ deflate_state *s;
-+{
-+ register unsigned n, m;
-+ register Posf *p;
-+ unsigned more; /* Amount of free space at the end of the window. */
-+ uInt wsize = s->w_size;
-+
-+ do {
-+ more = (unsigned)(s->window_size -(ulg)s->lookahead -(ulg)s->strstart);
-+
-+ /* Deal with !@#$% 64K limit: */
-+ if (more == 0 && s->strstart == 0 && s->lookahead == 0) {
-+ more = wsize;
-+
-+ } else if (more == (unsigned)(-1)) {
-+ /* Very unlikely, but possible on 16 bit machine if strstart == 0
-+ * and lookahead == 1 (input done one byte at time)
-+ */
-+ more--;
-+
-+ /* If the window is almost full and there is insufficient lookahead,
-+ * move the upper half to the lower one to make room in the upper half.
-+ */
-+ } else if (s->strstart >= wsize+MAX_DIST(s)) {
-+
-+ zmemcpy(s->window, s->window+wsize, (unsigned)wsize);
-+ s->match_start -= wsize;
-+ s->strstart -= wsize; /* we now have strstart >= MAX_DIST */
-+ s->block_start -= (long) wsize;
-+
-+ /* Slide the hash table (could be avoided with 32 bit values
-+ at the expense of memory usage). We slide even when level == 0
-+ to keep the hash table consistent if we switch back to level > 0
-+ later. (Using level 0 permanently is not an optimal usage of
-+ zlib, so we don't care about this pathological case.)
-+ */
-+ n = s->hash_size;
-+ p = &s->head[n];
-+ do {
-+ m = *--p;
-+ *p = (Pos)(m >= wsize ? m-wsize : NIL);
-+ } while (--n);
-+
-+ n = wsize;
-+#ifndef FASTEST
-+ p = &s->prev[n];
-+ do {
-+ m = *--p;
-+ *p = (Pos)(m >= wsize ? m-wsize : NIL);
-+ /* If n is not on any hash chain, prev[n] is garbage but
-+ * its value will never be used.
-+ */
-+ } while (--n);
-+#endif
-+ more += wsize;
-+ }
-+ if (s->strm->avail_in == 0) return;
-+
-+ /* If there was no sliding:
-+ * strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 &&
-+ * more == window_size - lookahead - strstart
-+ * => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1)
-+ * => more >= window_size - 2*WSIZE + 2
-+ * In the BIG_MEM or MMAP case (not yet supported),
-+ * window_size == input_size + MIN_LOOKAHEAD &&
-+ * strstart + s->lookahead <= input_size => more >= MIN_LOOKAHEAD.
-+ * Otherwise, window_size == 2*WSIZE so more >= 2.
-+ * If there was sliding, more >= WSIZE. So in all cases, more >= 2.
-+ */
-+ Assert(more >= 2, "more < 2");
-+
-+ n = read_buf(s->strm, s->window + s->strstart + s->lookahead, more);
-+ s->lookahead += n;
-+
-+ /* Initialize the hash value now that we have some input: */
-+ if (s->lookahead >= MIN_MATCH) {
-+ s->ins_h = s->window[s->strstart];
-+ UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]);
-+#if MIN_MATCH != 3
-+ Call UPDATE_HASH() MIN_MATCH-3 more times
-+#endif
-+ }
-+ /* If the whole input has less than MIN_MATCH bytes, ins_h is garbage,
-+ * but this is not important since only literal bytes will be emitted.
-+ */
-+
-+ } while (s->lookahead < MIN_LOOKAHEAD && s->strm->avail_in != 0);
-+}
-+
-+/* ===========================================================================
-+ * Flush the current block, with given end-of-file flag.
-+ * IN assertion: strstart is set to the end of the current match.
-+ */
-+#define FLUSH_BLOCK_ONLY(s, eof) { \
-+ _tr_flush_block(s, (s->block_start >= 0L ? \
-+ (charf *)&s->window[(unsigned)s->block_start] : \
-+ (charf *)Z_NULL), \
-+ (ulg)((long)s->strstart - s->block_start), \
-+ (eof)); \
-+ s->block_start = s->strstart; \
-+ flush_pending(s->strm); \
-+ Tracev((stderr,"[FLUSH]")); \
-+}
-+
-+/* Same but force premature exit if necessary. */
-+#define FLUSH_BLOCK(s, eof) { \
-+ FLUSH_BLOCK_ONLY(s, eof); \
-+ if (s->strm->avail_out == 0) return (eof) ? finish_started : need_more; \
-+}
-+
-+/* ===========================================================================
-+ * Copy without compression as much as possible from the input stream, return
-+ * the current block state.
-+ * This function does not insert new strings in the dictionary since
-+ * uncompressible data is probably not useful. This function is used
-+ * only for the level=0 compression option.
-+ * NOTE: this function should be optimized to avoid extra copying from
-+ * window to pending_buf.
-+ */
-+local block_state deflate_stored(s, flush)
-+ deflate_state *s;
-+ int flush;
-+{
-+ /* Stored blocks are limited to 0xffff bytes, pending_buf is limited
-+ * to pending_buf_size, and each stored block has a 5 byte header:
-+ */
-+ ulg max_block_size = 0xffff;
-+ ulg max_start;
-+
-+ if (max_block_size > s->pending_buf_size - 5) {
-+ max_block_size = s->pending_buf_size - 5;
-+ }
-+
-+ /* Copy as much as possible from input to output: */
-+ for (;;) {
-+ /* Fill the window as much as possible: */
-+ if (s->lookahead <= 1) {
-+
-+ Assert(s->strstart < s->w_size+MAX_DIST(s) ||
-+ s->block_start >= (long)s->w_size, "slide too late");
-+
-+ fill_window(s);
-+ if (s->lookahead == 0 && flush == Z_NO_FLUSH) return need_more;
-+
-+ if (s->lookahead == 0) break; /* flush the current block */
-+ }
-+ Assert(s->block_start >= 0L, "block gone");
-+
-+ s->strstart += s->lookahead;
-+ s->lookahead = 0;
-+
-+ /* Emit a stored block if pending_buf will be full: */
-+ max_start = s->block_start + max_block_size;
-+ if (s->strstart == 0 || (ulg)s->strstart >= max_start) {
-+ /* strstart == 0 is possible when wraparound on 16-bit machine */
-+ s->lookahead = (uInt)(s->strstart - max_start);
-+ s->strstart = (uInt)max_start;
-+ FLUSH_BLOCK(s, 0);
-+ }
-+ /* Flush if we may have to slide, otherwise block_start may become
-+ * negative and the data will be gone:
-+ */
-+ if (s->strstart - (uInt)s->block_start >= MAX_DIST(s)) {
-+ FLUSH_BLOCK(s, 0);
-+ }
-+ }
-+ FLUSH_BLOCK(s, flush == Z_FINISH);
-+ return flush == Z_FINISH ? finish_done : block_done;
-+}
-+
-+/* ===========================================================================
-+ * Compress as much as possible from the input stream, return the current
-+ * block state.
-+ * This function does not perform lazy evaluation of matches and inserts
-+ * new strings in the dictionary only for unmatched strings or for short
-+ * matches. It is used only for the fast compression options.
-+ */
-+local block_state deflate_fast(s, flush)
-+ deflate_state *s;
-+ int flush;
-+{
-+ IPos hash_head = NIL; /* head of the hash chain */
-+ int bflush; /* set if current block must be flushed */
-+
-+ for (;;) {
-+ /* Make sure that we always have enough lookahead, except
-+ * at the end of the input file. We need MAX_MATCH bytes
-+ * for the next match, plus MIN_MATCH bytes to insert the
-+ * string following the next match.
-+ */
-+ if (s->lookahead < MIN_LOOKAHEAD) {
-+ fill_window(s);
-+ if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) {
-+ return need_more;
-+ }
-+ if (s->lookahead == 0) break; /* flush the current block */
-+ }
-+
-+ /* Insert the string window[strstart .. strstart+2] in the
-+ * dictionary, and set hash_head to the head of the hash chain:
-+ */
-+ if (s->lookahead >= MIN_MATCH) {
-+ INSERT_STRING(s, s->strstart, hash_head);
-+ }
-+
-+ /* Find the longest match, discarding those <= prev_length.
-+ * At this point we have always match_length < MIN_MATCH
-+ */
-+ if (hash_head != NIL && s->strstart - hash_head <= MAX_DIST(s)) {
-+ /* To simplify the code, we prevent matches with the string
-+ * of window index 0 (in particular we have to avoid a match
-+ * of the string with itself at the start of the input file).
-+ */
-+ if (s->strategy != Z_HUFFMAN_ONLY) {
-+ s->match_length = longest_match (s, hash_head);
-+ }
-+ /* longest_match() sets match_start */
-+ }
-+ if (s->match_length >= MIN_MATCH) {
-+ check_match(s, s->strstart, s->match_start, s->match_length);
-+
-+ _tr_tally_dist(s, s->strstart - s->match_start,
-+ s->match_length - MIN_MATCH, bflush);
-+
-+ s->lookahead -= s->match_length;
-+
-+ /* Insert new strings in the hash table only if the match length
-+ * is not too large. This saves time but degrades compression.
-+ */
-+#ifndef FASTEST
-+ if (s->match_length <= s->max_insert_length &&
-+ s->lookahead >= MIN_MATCH) {
-+ s->match_length--; /* string at strstart already in hash table */
-+ do {
-+ s->strstart++;
-+ INSERT_STRING(s, s->strstart, hash_head);
-+ /* strstart never exceeds WSIZE-MAX_MATCH, so there are
-+ * always MIN_MATCH bytes ahead.
-+ */
-+ } while (--s->match_length != 0);
-+ s->strstart++;
-+ } else
-+#endif
-+ {
-+ s->strstart += s->match_length;
-+ s->match_length = 0;
-+ s->ins_h = s->window[s->strstart];
-+ UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]);
-+#if MIN_MATCH != 3
-+ Call UPDATE_HASH() MIN_MATCH-3 more times
-+#endif
-+ /* If lookahead < MIN_MATCH, ins_h is garbage, but it does not
-+ * matter since it will be recomputed at next deflate call.
-+ */
-+ }
-+ } else {
-+ /* No match, output a literal byte */
-+ Tracevv((stderr,"%c", s->window[s->strstart]));
-+ _tr_tally_lit (s, s->window[s->strstart], bflush);
-+ s->lookahead--;
-+ s->strstart++;
-+ }
-+ if (bflush) FLUSH_BLOCK(s, 0);
-+ }
-+ FLUSH_BLOCK(s, flush == Z_FINISH);
-+ return flush == Z_FINISH ? finish_done : block_done;
-+}
-+
-+/* ===========================================================================
-+ * Same as above, but achieves better compression. We use a lazy
-+ * evaluation for matches: a match is finally adopted only if there is
-+ * no better match at the next window position.
-+ */
-+local block_state deflate_slow(s, flush)
-+ deflate_state *s;
-+ int flush;
-+{
-+ IPos hash_head = NIL; /* head of hash chain */
-+ int bflush; /* set if current block must be flushed */
-+
-+ /* Process the input block. */
-+ for (;;) {
-+ /* Make sure that we always have enough lookahead, except
-+ * at the end of the input file. We need MAX_MATCH bytes
-+ * for the next match, plus MIN_MATCH bytes to insert the
-+ * string following the next match.
-+ */
-+ if (s->lookahead < MIN_LOOKAHEAD) {
-+ fill_window(s);
-+ if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) {
-+ return need_more;
-+ }
-+ if (s->lookahead == 0) break; /* flush the current block */
-+ }
-+
-+ /* Insert the string window[strstart .. strstart+2] in the
-+ * dictionary, and set hash_head to the head of the hash chain:
-+ */
-+ if (s->lookahead >= MIN_MATCH) {
-+ INSERT_STRING(s, s->strstart, hash_head);
-+ }
-+
-+ /* Find the longest match, discarding those <= prev_length.
-+ */
-+ s->prev_length = s->match_length, s->prev_match = s->match_start;
-+ s->match_length = MIN_MATCH-1;
-+
-+ if (hash_head != NIL && s->prev_length < s->max_lazy_match &&
-+ s->strstart - hash_head <= MAX_DIST(s)) {
-+ /* To simplify the code, we prevent matches with the string
-+ * of window index 0 (in particular we have to avoid a match
-+ * of the string with itself at the start of the input file).
-+ */
-+ if (s->strategy != Z_HUFFMAN_ONLY) {
-+ s->match_length = longest_match (s, hash_head);
-+ }
-+ /* longest_match() sets match_start */
-+
-+ if (s->match_length <= 5 && (s->strategy == Z_FILTERED ||
-+ (s->match_length == MIN_MATCH &&
-+ s->strstart - s->match_start > TOO_FAR))) {
-+
-+ /* If prev_match is also MIN_MATCH, match_start is garbage
-+ * but we will ignore the current match anyway.
-+ */
-+ s->match_length = MIN_MATCH-1;
-+ }
-+ }
-+ /* If there was a match at the previous step and the current
-+ * match is not better, output the previous match:
-+ */
-+ if (s->prev_length >= MIN_MATCH && s->match_length <= s->prev_length) {
-+ uInt max_insert = s->strstart + s->lookahead - MIN_MATCH;
-+ /* Do not insert strings in hash table beyond this. */
-+
-+ check_match(s, s->strstart-1, s->prev_match, s->prev_length);
-+
-+ _tr_tally_dist(s, s->strstart -1 - s->prev_match,
-+ s->prev_length - MIN_MATCH, bflush);
-+
-+ /* Insert in hash table all strings up to the end of the match.
-+ * strstart-1 and strstart are already inserted. If there is not
-+ * enough lookahead, the last two strings are not inserted in
-+ * the hash table.
-+ */
-+ s->lookahead -= s->prev_length-1;
-+ s->prev_length -= 2;
-+ do {
-+ if (++s->strstart <= max_insert) {
-+ INSERT_STRING(s, s->strstart, hash_head);
-+ }
-+ } while (--s->prev_length != 0);
-+ s->match_available = 0;
-+ s->match_length = MIN_MATCH-1;
-+ s->strstart++;
-+
-+ if (bflush) FLUSH_BLOCK(s, 0);
-+
-+ } else if (s->match_available) {
-+ /* If there was no match at the previous position, output a
-+ * single literal. If there was a match but the current match
-+ * is longer, truncate the previous match to a single literal.
-+ */
-+ Tracevv((stderr,"%c", s->window[s->strstart-1]));
-+ _tr_tally_lit(s, s->window[s->strstart-1], bflush);
-+ if (bflush) {
-+ FLUSH_BLOCK_ONLY(s, 0);
-+ }
-+ s->strstart++;
-+ s->lookahead--;
-+ if (s->strm->avail_out == 0) return need_more;
-+ } else {
-+ /* There is no previous match to compare with, wait for
-+ * the next step to decide.
-+ */
-+ s->match_available = 1;
-+ s->strstart++;
-+ s->lookahead--;
-+ }
-+ }
-+ Assert (flush != Z_NO_FLUSH, "no flush?");
-+ if (s->match_available) {
-+ Tracevv((stderr,"%c", s->window[s->strstart-1]));
-+ _tr_tally_lit(s, s->window[s->strstart-1], bflush);
-+ s->match_available = 0;
-+ }
-+ FLUSH_BLOCK(s, flush == Z_FINISH);
-+ return flush == Z_FINISH ? finish_done : block_done;
-+}
---- /dev/null Tue Mar 11 13:02:56 2003
-+++ linux/lib/zlib/deflate.h Mon Feb 9 13:51:03 2004
-@@ -0,0 +1,318 @@
-+/* deflate.h -- internal compression state
-+ * Copyright (C) 1995-2002 Jean-loup Gailly
-+ * For conditions of distribution and use, see copyright notice in zlib.h
-+ */
-+
-+/* WARNING: this file should *not* be used by applications. It is
-+ part of the implementation of the compression library and is
-+ subject to change. Applications should only use zlib.h.
-+ */
-+
-+/* @(#) $Id: deflate.h,v 1.4 2002/04/24 07:55:32 mcr Exp $ */
-+
-+#ifndef _DEFLATE_H
-+#define _DEFLATE_H
-+
-+#include "zlib/zutil.h"
-+
-+/* ===========================================================================
-+ * Internal compression state.
-+ */
-+
-+#define LENGTH_CODES 29
-+/* number of length codes, not counting the special END_BLOCK code */
-+
-+#define LITERALS 256
-+/* number of literal bytes 0..255 */
-+
-+#define L_CODES (LITERALS+1+LENGTH_CODES)
-+/* number of Literal or Length codes, including the END_BLOCK code */
-+
-+#define D_CODES 30
-+/* number of distance codes */
-+
-+#define BL_CODES 19
-+/* number of codes used to transfer the bit lengths */
-+
-+#define HEAP_SIZE (2*L_CODES+1)
-+/* maximum heap size */
-+
-+#define MAX_BITS 15
-+/* All codes must not exceed MAX_BITS bits */
-+
-+#define INIT_STATE 42
-+#define BUSY_STATE 113
-+#define FINISH_STATE 666
-+/* Stream status */
-+
-+
-+/* Data structure describing a single value and its code string. */
-+typedef struct ct_data_s {
-+ union {
-+ ush freq; /* frequency count */
-+ ush code; /* bit string */
-+ } fc;
-+ union {
-+ ush dad; /* father node in Huffman tree */
-+ ush len; /* length of bit string */
-+ } dl;
-+} FAR ct_data;
-+
-+#define Freq fc.freq
-+#define Code fc.code
-+#define Dad dl.dad
-+#define Len dl.len
-+
-+typedef struct static_tree_desc_s static_tree_desc;
-+
-+typedef struct tree_desc_s {
-+ ct_data *dyn_tree; /* the dynamic tree */
-+ int max_code; /* largest code with non zero frequency */
-+ static_tree_desc *stat_desc; /* the corresponding static tree */
-+} FAR tree_desc;
-+
-+typedef ush Pos;
-+typedef Pos FAR Posf;
-+typedef unsigned IPos;
-+
-+/* A Pos is an index in the character window. We use short instead of int to
-+ * save space in the various tables. IPos is used only for parameter passing.
-+ */
-+
-+typedef struct internal_state {
-+ z_streamp strm; /* pointer back to this zlib stream */
-+ int status; /* as the name implies */
-+ Bytef *pending_buf; /* output still pending */
-+ ulg pending_buf_size; /* size of pending_buf */
-+ Bytef *pending_out; /* next pending byte to output to the stream */
-+ int pending; /* nb of bytes in the pending buffer */
-+ int noheader; /* suppress zlib header and adler32 */
-+ Byte data_type; /* UNKNOWN, BINARY or ASCII */
-+ Byte method; /* STORED (for zip only) or DEFLATED */
-+ int last_flush; /* value of flush param for previous deflate call */
-+
-+ /* used by deflate.c: */
-+
-+ uInt w_size; /* LZ77 window size (32K by default) */
-+ uInt w_bits; /* log2(w_size) (8..16) */
-+ uInt w_mask; /* w_size - 1 */
-+
-+ Bytef *window;
-+ /* Sliding window. Input bytes are read into the second half of the window,
-+ * and move to the first half later to keep a dictionary of at least wSize
-+ * bytes. With this organization, matches are limited to a distance of
-+ * wSize-MAX_MATCH bytes, but this ensures that IO is always
-+ * performed with a length multiple of the block size. Also, it limits
-+ * the window size to 64K, which is quite useful on MSDOS.
-+ * To do: use the user input buffer as sliding window.
-+ */
-+
-+ ulg window_size;
-+ /* Actual size of window: 2*wSize, except when the user input buffer
-+ * is directly used as sliding window.
-+ */
-+
-+ Posf *prev;
-+ /* Link to older string with same hash index. To limit the size of this
-+ * array to 64K, this link is maintained only for the last 32K strings.
-+ * An index in this array is thus a window index modulo 32K.
-+ */
-+
-+ Posf *head; /* Heads of the hash chains or NIL. */
-+
-+ uInt ins_h; /* hash index of string to be inserted */
-+ uInt hash_size; /* number of elements in hash table */
-+ uInt hash_bits; /* log2(hash_size) */
-+ uInt hash_mask; /* hash_size-1 */
-+
-+ uInt hash_shift;
-+ /* Number of bits by which ins_h must be shifted at each input
-+ * step. It must be such that after MIN_MATCH steps, the oldest
-+ * byte no longer takes part in the hash key, that is:
-+ * hash_shift * MIN_MATCH >= hash_bits
-+ */
-+
-+ long block_start;
-+ /* Window position at the beginning of the current output block. Gets
-+ * negative when the window is moved backwards.
-+ */
-+
-+ uInt match_length; /* length of best match */
-+ IPos prev_match; /* previous match */
-+ int match_available; /* set if previous match exists */
-+ uInt strstart; /* start of string to insert */
-+ uInt match_start; /* start of matching string */
-+ uInt lookahead; /* number of valid bytes ahead in window */
-+
-+ uInt prev_length;
-+ /* Length of the best match at previous step. Matches not greater than this
-+ * are discarded. This is used in the lazy match evaluation.
-+ */
-+
-+ uInt max_chain_length;
-+ /* To speed up deflation, hash chains are never searched beyond this
-+ * length. A higher limit improves compression ratio but degrades the
-+ * speed.
-+ */
-+
-+ uInt max_lazy_match;
-+ /* Attempt to find a better match only when the current match is strictly
-+ * smaller than this value. This mechanism is used only for compression
-+ * levels >= 4.
-+ */
-+# define max_insert_length max_lazy_match
-+ /* Insert new strings in the hash table only if the match length is not
-+ * greater than this length. This saves time but degrades compression.
-+ * max_insert_length is used only for compression levels <= 3.
-+ */
-+
-+ int level; /* compression level (1..9) */
-+ int strategy; /* favor or force Huffman coding*/
-+
-+ uInt good_match;
-+ /* Use a faster search when the previous match is longer than this */
-+
-+ int nice_match; /* Stop searching when current match exceeds this */
-+
-+ /* used by trees.c: */
-+ /* Didn't use ct_data typedef below to supress compiler warning */
-+ struct ct_data_s dyn_ltree[HEAP_SIZE]; /* literal and length tree */
-+ struct ct_data_s dyn_dtree[2*D_CODES+1]; /* distance tree */
-+ struct ct_data_s bl_tree[2*BL_CODES+1]; /* Huffman tree for bit lengths */
-+
-+ struct tree_desc_s l_desc; /* desc. for literal tree */
-+ struct tree_desc_s d_desc; /* desc. for distance tree */
-+ struct tree_desc_s bl_desc; /* desc. for bit length tree */
-+
-+ ush bl_count[MAX_BITS+1];
-+ /* number of codes at each bit length for an optimal tree */
-+
-+ int heap[2*L_CODES+1]; /* heap used to build the Huffman trees */
-+ int heap_len; /* number of elements in the heap */
-+ int heap_max; /* element of largest frequency */
-+ /* The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used.
-+ * The same heap array is used to build all trees.
-+ */
-+
-+ uch depth[2*L_CODES+1];
-+ /* Depth of each subtree used as tie breaker for trees of equal frequency
-+ */
-+
-+ uchf *l_buf; /* buffer for literals or lengths */
-+
-+ uInt lit_bufsize;
-+ /* Size of match buffer for literals/lengths. There are 4 reasons for
-+ * limiting lit_bufsize to 64K:
-+ * - frequencies can be kept in 16 bit counters
-+ * - if compression is not successful for the first block, all input
-+ * data is still in the window so we can still emit a stored block even
-+ * when input comes from standard input. (This can also be done for
-+ * all blocks if lit_bufsize is not greater than 32K.)
-+ * - if compression is not successful for a file smaller than 64K, we can
-+ * even emit a stored file instead of a stored block (saving 5 bytes).
-+ * This is applicable only for zip (not gzip or zlib).
-+ * - creating new Huffman trees less frequently may not provide fast
-+ * adaptation to changes in the input data statistics. (Take for
-+ * example a binary file with poorly compressible code followed by
-+ * a highly compressible string table.) Smaller buffer sizes give
-+ * fast adaptation but have of course the overhead of transmitting
-+ * trees more frequently.
-+ * - I can't count above 4
-+ */
-+
-+ uInt last_lit; /* running index in l_buf */
-+
-+ ushf *d_buf;
-+ /* Buffer for distances. To simplify the code, d_buf and l_buf have
-+ * the same number of elements. To use different lengths, an extra flag
-+ * array would be necessary.
-+ */
-+
-+ ulg opt_len; /* bit length of current block with optimal trees */
-+ ulg static_len; /* bit length of current block with static trees */
-+ uInt matches; /* number of string matches in current block */
-+ int last_eob_len; /* bit length of EOB code for last block */
-+
-+#ifdef DEBUG
-+ ulg compressed_len; /* total bit length of compressed file mod 2^32 */
-+ ulg bits_sent; /* bit length of compressed data sent mod 2^32 */
-+#endif
-+
-+ ush bi_buf;
-+ /* Output buffer. bits are inserted starting at the bottom (least
-+ * significant bits).
-+ */
-+ int bi_valid;
-+ /* Number of valid bits in bi_buf. All bits above the last valid bit
-+ * are always zero.
-+ */
-+
-+} FAR deflate_state;
-+
-+/* Output a byte on the stream.
-+ * IN assertion: there is enough room in pending_buf.
-+ */
-+#define put_byte(s, c) {s->pending_buf[s->pending++] = (c);}
-+
-+
-+#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1)
-+/* Minimum amount of lookahead, except at the end of the input file.
-+ * See deflate.c for comments about the MIN_MATCH+1.
-+ */
-+
-+#define MAX_DIST(s) ((s)->w_size-MIN_LOOKAHEAD)
-+/* In order to simplify the code, particularly on 16 bit machines, match
-+ * distances are limited to MAX_DIST instead of WSIZE.
-+ */
-+
-+ /* in trees.c */
-+void _tr_init OF((deflate_state *s));
-+int _tr_tally OF((deflate_state *s, unsigned dist, unsigned lc));
-+void _tr_flush_block OF((deflate_state *s, charf *buf, ulg stored_len,
-+ int eof));
-+void _tr_align OF((deflate_state *s));
-+void _tr_stored_block OF((deflate_state *s, charf *buf, ulg stored_len,
-+ int eof));
-+
-+#define d_code(dist) \
-+ ((dist) < 256 ? _dist_code[dist] : _dist_code[256+((dist)>>7)])
-+/* Mapping from a distance to a distance code. dist is the distance - 1 and
-+ * must not have side effects. _dist_code[256] and _dist_code[257] are never
-+ * used.
-+ */
-+
-+#ifndef DEBUG
-+/* Inline versions of _tr_tally for speed: */
-+
-+#if defined(GEN_TREES_H) || !defined(STDC)
-+ extern uch _length_code[];
-+ extern uch _dist_code[];
-+#else
-+ extern const uch _length_code[];
-+ extern const uch _dist_code[];
-+#endif
-+
-+# define _tr_tally_lit(s, c, flush) \
-+ { uch cc = (c); \
-+ s->d_buf[s->last_lit] = 0; \
-+ s->l_buf[s->last_lit++] = cc; \
-+ s->dyn_ltree[cc].Freq++; \
-+ flush = (s->last_lit == s->lit_bufsize-1); \
-+ }
-+# define _tr_tally_dist(s, distance, length, flush) \
-+ { uch len = (length); \
-+ ush dist = (distance); \
-+ s->d_buf[s->last_lit] = dist; \
-+ s->l_buf[s->last_lit++] = len; \
-+ dist--; \
-+ s->dyn_ltree[_length_code[len]+LITERALS+1].Freq++; \
-+ s->dyn_dtree[d_code(dist)].Freq++; \
-+ flush = (s->last_lit == s->lit_bufsize-1); \
-+ }
-+#else
-+# define _tr_tally_lit(s, c, flush) flush = _tr_tally(s, 0, c)
-+# define _tr_tally_dist(s, distance, length, flush) \
-+ flush = _tr_tally(s, distance, length)
-+#endif
-+
-+#endif /* _DEFLATE_H */
---- /dev/null Tue Mar 11 13:02:56 2003
-+++ linux/lib/zlib/infblock.c Mon Feb 9 13:51:03 2004
-@@ -0,0 +1,403 @@
-+/* infblock.c -- interpret and process block types to last block
-+ * Copyright (C) 1995-2002 Mark Adler
-+ * For conditions of distribution and use, see copyright notice in zlib.h
-+ */
-+
-+#include <zlib/zutil.h>
-+#include "infblock.h"
-+#include "inftrees.h"
-+#include "infcodes.h"
-+#include "infutil.h"
-+
-+struct inflate_codes_state {int dummy;}; /* for buggy compilers */
-+
-+/* simplify the use of the inflate_huft type with some defines */
-+#define exop word.what.Exop
-+#define bits word.what.Bits
-+
-+/* Table for deflate from PKZIP's appnote.txt. */
-+local const uInt border[] = { /* Order of the bit length code lengths */
-+ 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15};
-+
-+/*
-+ Notes beyond the 1.93a appnote.txt:
-+
-+ 1. Distance pointers never point before the beginning of the output
-+ stream.
-+ 2. Distance pointers can point back across blocks, up to 32k away.
-+ 3. There is an implied maximum of 7 bits for the bit length table and
-+ 15 bits for the actual data.
-+ 4. If only one code exists, then it is encoded using one bit. (Zero
-+ would be more efficient, but perhaps a little confusing.) If two
-+ codes exist, they are coded using one bit each (0 and 1).
-+ 5. There is no way of sending zero distance codes--a dummy must be
-+ sent if there are none. (History: a pre 2.0 version of PKZIP would
-+ store blocks with no distance codes, but this was discovered to be
-+ too harsh a criterion.) Valid only for 1.93a. 2.04c does allow
-+ zero distance codes, which is sent as one code of zero bits in
-+ length.
-+ 6. There are up to 286 literal/length codes. Code 256 represents the
-+ end-of-block. Note however that the static length tree defines
-+ 288 codes just to fill out the Huffman codes. Codes 286 and 287
-+ cannot be used though, since there is no length base or extra bits
-+ defined for them. Similarily, there are up to 30 distance codes.
-+ However, static trees define 32 codes (all 5 bits) to fill out the
-+ Huffman codes, but the last two had better not show up in the data.
-+ 7. Unzip can check dynamic Huffman blocks for complete code sets.
-+ The exception is that a single code would not be complete (see #4).
-+ 8. The five bits following the block type is really the number of
-+ literal codes sent minus 257.
-+ 9. Length codes 8,16,16 are interpreted as 13 length codes of 8 bits
-+ (1+6+6). Therefore, to output three times the length, you output
-+ three codes (1+1+1), whereas to output four times the same length,
-+ you only need two codes (1+3). Hmm.
-+ 10. In the tree reconstruction algorithm, Code = Code + Increment
-+ only if BitLength(i) is not zero. (Pretty obvious.)
-+ 11. Correction: 4 Bits: # of Bit Length codes - 4 (4 - 19)
-+ 12. Note: length code 284 can represent 227-258, but length code 285
-+ really is 258. The last length deserves its own, short code
-+ since it gets used a lot in very redundant files. The length
-+ 258 is special since 258 - 3 (the min match length) is 255.
-+ 13. The literal/length and distance code bit lengths are read as a
-+ single stream of lengths. It is possible (and advantageous) for
-+ a repeat code (16, 17, or 18) to go across the boundary between
-+ the two sets of lengths.
-+ */
-+
-+
-+void inflate_blocks_reset(s, z, c)
-+inflate_blocks_statef *s;
-+z_streamp z;
-+uLongf *c;
-+{
-+ if (c != Z_NULL)
-+ *c = s->check;
-+ if (s->mode == BTREE || s->mode == DTREE)
-+ ZFREE(z, s->sub.trees.blens);
-+ if (s->mode == CODES)
-+ inflate_codes_free(s->sub.decode.codes, z);
-+ s->mode = TYPE;
-+ s->bitk = 0;
-+ s->bitb = 0;
-+ s->read = s->write = s->window;
-+ if (s->checkfn != Z_NULL)
-+ z->adler = s->check = (*s->checkfn)(0L, (const Bytef *)Z_NULL, 0);
-+ Tracev((stderr, "inflate: blocks reset\n"));
-+}
-+
-+
-+inflate_blocks_statef *inflate_blocks_new(z, c, w)
-+z_streamp z;
-+check_func c;
-+uInt w;
-+{
-+ inflate_blocks_statef *s;
-+
-+ if ((s = (inflate_blocks_statef *)ZALLOC
-+ (z,1,sizeof(struct inflate_blocks_state))) == Z_NULL)
-+ return s;
-+ if ((s->hufts =
-+ (inflate_huft *)ZALLOC(z, sizeof(inflate_huft), MANY)) == Z_NULL)
-+ {
-+ ZFREE(z, s);
-+ return Z_NULL;
-+ }
-+ if ((s->window = (Bytef *)ZALLOC(z, 1, w)) == Z_NULL)
-+ {
-+ ZFREE(z, s->hufts);
-+ ZFREE(z, s);
-+ return Z_NULL;
-+ }
-+ s->end = s->window + w;
-+ s->checkfn = c;
-+ s->mode = TYPE;
-+ Tracev((stderr, "inflate: blocks allocated\n"));
-+ inflate_blocks_reset(s, z, Z_NULL);
-+ return s;
-+}
-+
-+
-+int inflate_blocks(s, z, r)
-+inflate_blocks_statef *s;
-+z_streamp z;
-+int r;
-+{
-+ uInt t; /* temporary storage */
-+ uLong b; /* bit buffer */
-+ uInt k; /* bits in bit buffer */
-+ Bytef *p; /* input data pointer */
-+ uInt n; /* bytes available there */
-+ Bytef *q; /* output window write pointer */
-+ uInt m; /* bytes to end of window or read pointer */
-+
-+ /* copy input/output information to locals (UPDATE macro restores) */
-+ LOAD
-+
-+ /* process input based on current state */
-+ while (1) switch (s->mode)
-+ {
-+ case TYPE:
-+ NEEDBITS(3)
-+ t = (uInt)b & 7;
-+ s->last = t & 1;
-+ switch (t >> 1)
-+ {
-+ case 0: /* stored */
-+ Tracev((stderr, "inflate: stored block%s\n",
-+ s->last ? " (last)" : ""));
-+ DUMPBITS(3)
-+ t = k & 7; /* go to byte boundary */
-+ DUMPBITS(t)
-+ s->mode = LENS; /* get length of stored block */
-+ break;
-+ case 1: /* fixed */
-+ Tracev((stderr, "inflate: fixed codes block%s\n",
-+ s->last ? " (last)" : ""));
-+ {
-+ uInt bl, bd;
-+ inflate_huft *tl, *td;
-+
-+ inflate_trees_fixed(&bl, &bd, &tl, &td, z);
-+ s->sub.decode.codes = inflate_codes_new(bl, bd, tl, td, z);
-+ if (s->sub.decode.codes == Z_NULL)
-+ {
-+ r = Z_MEM_ERROR;
-+ LEAVE
-+ }
-+ }
-+ DUMPBITS(3)
-+ s->mode = CODES;
-+ break;
-+ case 2: /* dynamic */
-+ Tracev((stderr, "inflate: dynamic codes block%s\n",
-+ s->last ? " (last)" : ""));
-+ DUMPBITS(3)
-+ s->mode = TABLE;
-+ break;
-+ case 3: /* illegal */
-+ DUMPBITS(3)
-+ s->mode = BAD;
-+ z->msg = (char*)"invalid block type";
-+ r = Z_DATA_ERROR;
-+ LEAVE
-+ }
-+ break;
-+ case LENS:
-+ NEEDBITS(32)
-+ if ((((~b) >> 16) & 0xffff) != (b & 0xffff))
-+ {
-+ s->mode = BAD;
-+ z->msg = (char*)"invalid stored block lengths";
-+ r = Z_DATA_ERROR;
-+ LEAVE
-+ }
-+ s->sub.left = (uInt)b & 0xffff;
-+ b = k = 0; /* dump bits */
-+ Tracev((stderr, "inflate: stored length %u\n", s->sub.left));
-+ s->mode = s->sub.left ? STORED : (s->last ? DRY : TYPE);
-+ break;
-+ case STORED:
-+ if (n == 0)
-+ LEAVE
-+ NEEDOUT
-+ t = s->sub.left;
-+ if (t > n) t = n;
-+ if (t > m) t = m;
-+ zmemcpy(q, p, t);
-+ p += t; n -= t;
-+ q += t; m -= t;
-+ if ((s->sub.left -= t) != 0)
-+ break;
-+ Tracev((stderr, "inflate: stored end, %lu total out\n",
-+ z->total_out + (q >= s->read ? q - s->read :
-+ (s->end - s->read) + (q - s->window))));
-+ s->mode = s->last ? DRY : TYPE;
-+ break;
-+ case TABLE:
-+ NEEDBITS(14)
-+ s->sub.trees.table = t = (uInt)b & 0x3fff;
-+#ifndef PKZIP_BUG_WORKAROUND
-+ if ((t & 0x1f) > 29 || ((t >> 5) & 0x1f) > 29)
-+ {
-+ s->mode = BAD;
-+ z->msg = (char*)"too many length or distance symbols";
-+ r = Z_DATA_ERROR;
-+ LEAVE
-+ }
-+#endif
-+ t = 258 + (t & 0x1f) + ((t >> 5) & 0x1f);
-+ if ((s->sub.trees.blens = (uIntf*)ZALLOC(z, t, sizeof(uInt))) == Z_NULL)
-+ {
-+ r = Z_MEM_ERROR;
-+ LEAVE
-+ }
-+ DUMPBITS(14)
-+ s->sub.trees.index = 0;
-+ Tracev((stderr, "inflate: table sizes ok\n"));
-+ s->mode = BTREE;
-+ case BTREE:
-+ while (s->sub.trees.index < 4 + (s->sub.trees.table >> 10))
-+ {
-+ NEEDBITS(3)
-+ s->sub.trees.blens[border[s->sub.trees.index++]] = (uInt)b & 7;
-+ DUMPBITS(3)
-+ }
-+ while (s->sub.trees.index < 19)
-+ s->sub.trees.blens[border[s->sub.trees.index++]] = 0;
-+ s->sub.trees.bb = 7;
-+ t = inflate_trees_bits(s->sub.trees.blens, &s->sub.trees.bb,
-+ &s->sub.trees.tb, s->hufts, z);
-+ if (t != Z_OK)
-+ {
-+ r = t;
-+ if (r == Z_DATA_ERROR)
-+ {
-+ ZFREE(z, s->sub.trees.blens);
-+ s->mode = BAD;
-+ }
-+ LEAVE
-+ }
-+ s->sub.trees.index = 0;
-+ Tracev((stderr, "inflate: bits tree ok\n"));
-+ s->mode = DTREE;
-+ case DTREE:
-+ while (t = s->sub.trees.table,
-+ s->sub.trees.index < 258 + (t & 0x1f) + ((t >> 5) & 0x1f))
-+ {
-+ inflate_huft *h;
-+ uInt i, j, c;
-+
-+ t = s->sub.trees.bb;
-+ NEEDBITS(t)
-+ h = s->sub.trees.tb + ((uInt)b & inflate_mask[t]);
-+ t = h->bits;
-+ c = h->base;
-+ if (c < 16)
-+ {
-+ DUMPBITS(t)
-+ s->sub.trees.blens[s->sub.trees.index++] = c;
-+ }
-+ else /* c == 16..18 */
-+ {
-+ i = c == 18 ? 7 : c - 14;
-+ j = c == 18 ? 11 : 3;
-+ NEEDBITS(t + i)
-+ DUMPBITS(t)
-+ j += (uInt)b & inflate_mask[i];
-+ DUMPBITS(i)
-+ i = s->sub.trees.index;
-+ t = s->sub.trees.table;
-+ if (i + j > 258 + (t & 0x1f) + ((t >> 5) & 0x1f) ||
-+ (c == 16 && i < 1))
-+ {
-+ ZFREE(z, s->sub.trees.blens);
-+ s->mode = BAD;
-+ z->msg = (char*)"invalid bit length repeat";
-+ r = Z_DATA_ERROR;
-+ LEAVE
-+ }
-+ c = c == 16 ? s->sub.trees.blens[i - 1] : 0;
-+ do {
-+ s->sub.trees.blens[i++] = c;
-+ } while (--j);
-+ s->sub.trees.index = i;
-+ }
-+ }
-+ s->sub.trees.tb = Z_NULL;
-+ {
-+ uInt bl, bd;
-+ inflate_huft *tl, *td;
-+ inflate_codes_statef *c;
-+
-+ bl = 9; /* must be <= 9 for lookahead assumptions */
-+ bd = 6; /* must be <= 9 for lookahead assumptions */
-+ t = s->sub.trees.table;
-+ t = inflate_trees_dynamic(257 + (t & 0x1f), 1 + ((t >> 5) & 0x1f),
-+ s->sub.trees.blens, &bl, &bd, &tl, &td,
-+ s->hufts, z);
-+ if (t != Z_OK)
-+ {
-+ if (t == (uInt)Z_DATA_ERROR)
-+ {
-+ ZFREE(z, s->sub.trees.blens);
-+ s->mode = BAD;
-+ }
-+ r = t;
-+ LEAVE
-+ }
-+ Tracev((stderr, "inflate: trees ok\n"));
-+ if ((c = inflate_codes_new(bl, bd, tl, td, z)) == Z_NULL)
-+ {
-+ r = Z_MEM_ERROR;
-+ LEAVE
-+ }
-+ s->sub.decode.codes = c;
-+ }
-+ ZFREE(z, s->sub.trees.blens);
-+ s->mode = CODES;
-+ case CODES:
-+ UPDATE
-+ if ((r = inflate_codes(s, z, r)) != Z_STREAM_END)
-+ return inflate_flush(s, z, r);
-+ r = Z_OK;
-+ inflate_codes_free(s->sub.decode.codes, z);
-+ LOAD
-+ Tracev((stderr, "inflate: codes end, %lu total out\n",
-+ z->total_out + (q >= s->read ? q - s->read :
-+ (s->end - s->read) + (q - s->window))));
-+ if (!s->last)
-+ {
-+ s->mode = TYPE;
-+ break;
-+ }
-+ s->mode = DRY;
-+ case DRY:
-+ FLUSH
-+ if (s->read != s->write)
-+ LEAVE
-+ s->mode = DONE;
-+ case DONE:
-+ r = Z_STREAM_END;
-+ LEAVE
-+ case BAD:
-+ r = Z_DATA_ERROR;
-+ LEAVE
-+ default:
-+ r = Z_STREAM_ERROR;
-+ LEAVE
-+ }
-+}
-+
-+
-+int inflate_blocks_free(s, z)
-+inflate_blocks_statef *s;
-+z_streamp z;
-+{
-+ inflate_blocks_reset(s, z, Z_NULL);
-+ ZFREE(z, s->window);
-+ ZFREE(z, s->hufts);
-+ ZFREE(z, s);
-+ Tracev((stderr, "inflate: blocks freed\n"));
-+ return Z_OK;
-+}
-+
-+
-+void inflate_set_dictionary(s, d, n)
-+inflate_blocks_statef *s;
-+const Bytef *d;
-+uInt n;
-+{
-+ zmemcpy(s->window, d, n);
-+ s->read = s->write = s->window + n;
-+}
-+
-+
-+/* Returns true if inflate is currently at the end of a block generated
-+ * by Z_SYNC_FLUSH or Z_FULL_FLUSH.
-+ * IN assertion: s != Z_NULL
-+ */
-+int inflate_blocks_sync_point(s)
-+inflate_blocks_statef *s;
-+{
-+ return s->mode == LENS;
-+}
---- /dev/null Tue Mar 11 13:02:56 2003
-+++ linux/lib/zlib/infblock.h Mon Feb 9 13:51:03 2004
-@@ -0,0 +1,39 @@
-+/* infblock.h -- header to use infblock.c
-+ * Copyright (C) 1995-2002 Mark Adler
-+ * For conditions of distribution and use, see copyright notice in zlib.h
-+ */
-+
-+/* WARNING: this file should *not* be used by applications. It is
-+ part of the implementation of the compression library and is
-+ subject to change. Applications should only use zlib.h.
-+ */
-+
-+struct inflate_blocks_state;
-+typedef struct inflate_blocks_state FAR inflate_blocks_statef;
-+
-+extern inflate_blocks_statef * inflate_blocks_new OF((
-+ z_streamp z,
-+ check_func c, /* check function */
-+ uInt w)); /* window size */
-+
-+extern int inflate_blocks OF((
-+ inflate_blocks_statef *,
-+ z_streamp ,
-+ int)); /* initial return code */
-+
-+extern void inflate_blocks_reset OF((
-+ inflate_blocks_statef *,
-+ z_streamp ,
-+ uLongf *)); /* check value on output */
-+
-+extern int inflate_blocks_free OF((
-+ inflate_blocks_statef *,
-+ z_streamp));
-+
-+extern void inflate_set_dictionary OF((
-+ inflate_blocks_statef *s,
-+ const Bytef *d, /* dictionary */
-+ uInt n)); /* dictionary length */
-+
-+extern int inflate_blocks_sync_point OF((
-+ inflate_blocks_statef *s));
---- /dev/null Tue Mar 11 13:02:56 2003
-+++ linux/lib/zlib/infcodes.c Mon Feb 9 13:51:03 2004
-@@ -0,0 +1,251 @@
-+/* infcodes.c -- process literals and length/distance pairs
-+ * Copyright (C) 1995-2002 Mark Adler
-+ * For conditions of distribution and use, see copyright notice in zlib.h
-+ */
-+
-+#include <zlib/zutil.h>
-+#include "inftrees.h"
-+#include "infblock.h"
-+#include "infcodes.h"
-+#include "infutil.h"
-+#include "inffast.h"
-+
-+/* simplify the use of the inflate_huft type with some defines */
-+#define exop word.what.Exop
-+#define bits word.what.Bits
-+
-+typedef enum { /* waiting for "i:"=input, "o:"=output, "x:"=nothing */
-+ START, /* x: set up for LEN */
-+ LEN, /* i: get length/literal/eob next */
-+ LENEXT, /* i: getting length extra (have base) */
-+ DIST, /* i: get distance next */
-+ DISTEXT, /* i: getting distance extra */
-+ COPY, /* o: copying bytes in window, waiting for space */
-+ LIT, /* o: got literal, waiting for output space */
-+ WASH, /* o: got eob, possibly still output waiting */
-+ END, /* x: got eob and all data flushed */
-+ BADCODE} /* x: got error */
-+inflate_codes_mode;
-+
-+/* inflate codes private state */
-+struct inflate_codes_state {
-+
-+ /* mode */
-+ inflate_codes_mode mode; /* current inflate_codes mode */
-+
-+ /* mode dependent information */
-+ uInt len;
-+ union {
-+ struct {
-+ inflate_huft *tree; /* pointer into tree */
-+ uInt need; /* bits needed */
-+ } code; /* if LEN or DIST, where in tree */
-+ uInt lit; /* if LIT, literal */
-+ struct {
-+ uInt get; /* bits to get for extra */
-+ uInt dist; /* distance back to copy from */
-+ } copy; /* if EXT or COPY, where and how much */
-+ } sub; /* submode */
-+
-+ /* mode independent information */
-+ Byte lbits; /* ltree bits decoded per branch */
-+ Byte dbits; /* dtree bits decoder per branch */
-+ inflate_huft *ltree; /* literal/length/eob tree */
-+ inflate_huft *dtree; /* distance tree */
-+
-+};
-+
-+
-+inflate_codes_statef *inflate_codes_new(bl, bd, tl, td, z)
-+uInt bl, bd;
-+inflate_huft *tl;
-+inflate_huft *td; /* need separate declaration for Borland C++ */
-+z_streamp z;
-+{
-+ inflate_codes_statef *c;
-+
-+ if ((c = (inflate_codes_statef *)
-+ ZALLOC(z,1,sizeof(struct inflate_codes_state))) != Z_NULL)
-+ {
-+ c->mode = START;
-+ c->lbits = (Byte)bl;
-+ c->dbits = (Byte)bd;
-+ c->ltree = tl;
-+ c->dtree = td;
-+ Tracev((stderr, "inflate: codes new\n"));
-+ }
-+ return c;
-+}
-+
-+
-+int inflate_codes(s, z, r)
-+inflate_blocks_statef *s;
-+z_streamp z;
-+int r;
-+{
-+ uInt j; /* temporary storage */
-+ inflate_huft *t; /* temporary pointer */
-+ uInt e; /* extra bits or operation */
-+ uLong b; /* bit buffer */
-+ uInt k; /* bits in bit buffer */
-+ Bytef *p; /* input data pointer */
-+ uInt n; /* bytes available there */
-+ Bytef *q; /* output window write pointer */
-+ uInt m; /* bytes to end of window or read pointer */
-+ Bytef *f; /* pointer to copy strings from */
-+ inflate_codes_statef *c = s->sub.decode.codes; /* codes state */
-+
-+ /* copy input/output information to locals (UPDATE macro restores) */
-+ LOAD
-+
-+ /* process input and output based on current state */
-+ while (1) switch (c->mode)
-+ { /* waiting for "i:"=input, "o:"=output, "x:"=nothing */
-+ case START: /* x: set up for LEN */
-+#ifndef SLOW
-+ if (m >= 258 && n >= 10)
-+ {
-+ UPDATE
-+ r = inflate_fast(c->lbits, c->dbits, c->ltree, c->dtree, s, z);
-+ LOAD
-+ if (r != Z_OK)
-+ {
-+ c->mode = r == Z_STREAM_END ? WASH : BADCODE;
-+ break;
-+ }
-+ }
-+#endif /* !SLOW */
-+ c->sub.code.need = c->lbits;
-+ c->sub.code.tree = c->ltree;
-+ c->mode = LEN;
-+ case LEN: /* i: get length/literal/eob next */
-+ j = c->sub.code.need;
-+ NEEDBITS(j)
-+ t = c->sub.code.tree + ((uInt)b & inflate_mask[j]);
-+ DUMPBITS(t->bits)
-+ e = (uInt)(t->exop);
-+ if (e == 0) /* literal */
-+ {
-+ c->sub.lit = t->base;
-+ Tracevv((stderr, t->base >= 0x20 && t->base < 0x7f ?
-+ "inflate: literal '%c'\n" :
-+ "inflate: literal 0x%02x\n", t->base));
-+ c->mode = LIT;
-+ break;
-+ }
-+ if (e & 16) /* length */
-+ {
-+ c->sub.copy.get = e & 15;
-+ c->len = t->base;
-+ c->mode = LENEXT;
-+ break;
-+ }
-+ if ((e & 64) == 0) /* next table */
-+ {
-+ c->sub.code.need = e;
-+ c->sub.code.tree = t + t->base;
-+ break;
-+ }
-+ if (e & 32) /* end of block */
-+ {
-+ Tracevv((stderr, "inflate: end of block\n"));
-+ c->mode = WASH;
-+ break;
-+ }
-+ c->mode = BADCODE; /* invalid code */
-+ z->msg = (char*)"invalid literal/length code";
-+ r = Z_DATA_ERROR;
-+ LEAVE
-+ case LENEXT: /* i: getting length extra (have base) */
-+ j = c->sub.copy.get;
-+ NEEDBITS(j)
-+ c->len += (uInt)b & inflate_mask[j];
-+ DUMPBITS(j)
-+ c->sub.code.need = c->dbits;
-+ c->sub.code.tree = c->dtree;
-+ Tracevv((stderr, "inflate: length %u\n", c->len));
-+ c->mode = DIST;
-+ case DIST: /* i: get distance next */
-+ j = c->sub.code.need;
-+ NEEDBITS(j)
-+ t = c->sub.code.tree + ((uInt)b & inflate_mask[j]);
-+ DUMPBITS(t->bits)
-+ e = (uInt)(t->exop);
-+ if (e & 16) /* distance */
-+ {
-+ c->sub.copy.get = e & 15;
-+ c->sub.copy.dist = t->base;
-+ c->mode = DISTEXT;
-+ break;
-+ }
-+ if ((e & 64) == 0) /* next table */
-+ {
-+ c->sub.code.need = e;
-+ c->sub.code.tree = t + t->base;
-+ break;
-+ }
-+ c->mode = BADCODE; /* invalid code */
-+ z->msg = (char*)"invalid distance code";
-+ r = Z_DATA_ERROR;
-+ LEAVE
-+ case DISTEXT: /* i: getting distance extra */
-+ j = c->sub.copy.get;
-+ NEEDBITS(j)
-+ c->sub.copy.dist += (uInt)b & inflate_mask[j];
-+ DUMPBITS(j)
-+ Tracevv((stderr, "inflate: distance %u\n", c->sub.copy.dist));
-+ c->mode = COPY;
-+ case COPY: /* o: copying bytes in window, waiting for space */
-+ f = q - c->sub.copy.dist;
-+ while (f < s->window) /* modulo window size-"while" instead */
-+ f += s->end - s->window; /* of "if" handles invalid distances */
-+ while (c->len)
-+ {
-+ NEEDOUT
-+ OUTBYTE(*f++)
-+ if (f == s->end)
-+ f = s->window;
-+ c->len--;
-+ }
-+ c->mode = START;
-+ break;
-+ case LIT: /* o: got literal, waiting for output space */
-+ NEEDOUT
-+ OUTBYTE(c->sub.lit)
-+ c->mode = START;
-+ break;
-+ case WASH: /* o: got eob, possibly more output */
-+ if (k > 7) /* return unused byte, if any */
-+ {
-+ Assert(k < 16, "inflate_codes grabbed too many bytes")
-+ k -= 8;
-+ n++;
-+ p--; /* can always return one */
-+ }
-+ FLUSH
-+ if (s->read != s->write)
-+ LEAVE
-+ c->mode = END;
-+ case END:
-+ r = Z_STREAM_END;
-+ LEAVE
-+ case BADCODE: /* x: got error */
-+ r = Z_DATA_ERROR;
-+ LEAVE
-+ default:
-+ r = Z_STREAM_ERROR;
-+ LEAVE
-+ }
-+#ifdef NEED_DUMMY_RETURN
-+ return Z_STREAM_ERROR; /* Some dumb compilers complain without this */
-+#endif
-+}
-+
-+
-+void inflate_codes_free(c, z)
-+inflate_codes_statef *c;
-+z_streamp z;
-+{
-+ ZFREE(z, c);
-+ Tracev((stderr, "inflate: codes free\n"));
-+}
---- /dev/null Tue Mar 11 13:02:56 2003
-+++ linux/lib/zlib/infcodes.h Mon Feb 9 13:51:03 2004
-@@ -0,0 +1,31 @@
-+/* infcodes.h -- header to use infcodes.c
-+ * Copyright (C) 1995-2002 Mark Adler
-+ * For conditions of distribution and use, see copyright notice in zlib.h
-+ */
-+
-+/* WARNING: this file should *not* be used by applications. It is
-+ part of the implementation of the compression library and is
-+ subject to change. Applications should only use zlib.h.
-+ */
-+
-+#ifndef _INFCODES_H
-+#define _INFCODES_H
-+
-+struct inflate_codes_state;
-+typedef struct inflate_codes_state FAR inflate_codes_statef;
-+
-+extern inflate_codes_statef *inflate_codes_new OF((
-+ uInt, uInt,
-+ inflate_huft *, inflate_huft *,
-+ z_streamp ));
-+
-+extern int inflate_codes OF((
-+ inflate_blocks_statef *,
-+ z_streamp ,
-+ int));
-+
-+extern void inflate_codes_free OF((
-+ inflate_codes_statef *,
-+ z_streamp ));
-+
-+#endif /* _INFCODES_H */
---- /dev/null Tue Mar 11 13:02:56 2003
-+++ linux/lib/zlib/inffast.c Mon Feb 9 13:51:03 2004
-@@ -0,0 +1,183 @@
-+/* inffast.c -- process literals and length/distance pairs fast
-+ * Copyright (C) 1995-2002 Mark Adler
-+ * For conditions of distribution and use, see copyright notice in zlib.h
-+ */
-+
-+#include <zlib/zutil.h>
-+#include "inftrees.h"
-+#include "infblock.h"
-+#include "infcodes.h"
-+#include "infutil.h"
-+#include "inffast.h"
-+
-+struct inflate_codes_state {int dummy;}; /* for buggy compilers */
-+
-+/* simplify the use of the inflate_huft type with some defines */
-+#define exop word.what.Exop
-+#define bits word.what.Bits
-+
-+/* macros for bit input with no checking and for returning unused bytes */
-+#define GRABBITS(j) {while(k<(j)){b|=((uLong)NEXTBYTE)<<k;k+=8;}}
-+#define UNGRAB {c=z->avail_in-n;c=(k>>3)<c?k>>3:c;n+=c;p-=c;k-=c<<3;}
-+
-+/* Called with number of bytes left to write in window at least 258
-+ (the maximum string length) and number of input bytes available
-+ at least ten. The ten bytes are six bytes for the longest length/
-+ distance pair plus four bytes for overloading the bit buffer. */
-+
-+int inflate_fast(bl, bd, tl, td, s, z)
-+uInt bl, bd;
-+inflate_huft *tl;
-+inflate_huft *td; /* need separate declaration for Borland C++ */
-+inflate_blocks_statef *s;
-+z_streamp z;
-+{
-+ inflate_huft *t; /* temporary pointer */
-+ uInt e; /* extra bits or operation */
-+ uLong b; /* bit buffer */
-+ uInt k; /* bits in bit buffer */
-+ Bytef *p; /* input data pointer */
-+ uInt n; /* bytes available there */
-+ Bytef *q; /* output window write pointer */
-+ uInt m; /* bytes to end of window or read pointer */
-+ uInt ml; /* mask for literal/length tree */
-+ uInt md; /* mask for distance tree */
-+ uInt c; /* bytes to copy */
-+ uInt d; /* distance back to copy from */
-+ Bytef *r; /* copy source pointer */
-+
-+ /* load input, output, bit values */
-+ LOAD
-+
-+ /* initialize masks */
-+ ml = inflate_mask[bl];
-+ md = inflate_mask[bd];
-+
-+ /* do until not enough input or output space for fast loop */
-+ do { /* assume called with m >= 258 && n >= 10 */
-+ /* get literal/length code */
-+ GRABBITS(20) /* max bits for literal/length code */
-+ if ((e = (t = tl + ((uInt)b & ml))->exop) == 0)
-+ {
-+ DUMPBITS(t->bits)
-+ Tracevv((stderr, t->base >= 0x20 && t->base < 0x7f ?
-+ "inflate: * literal '%c'\n" :
-+ "inflate: * literal 0x%02x\n", t->base));
-+ *q++ = (Byte)t->base;
-+ m--;
-+ continue;
-+ }
-+ do {
-+ DUMPBITS(t->bits)
-+ if (e & 16)
-+ {
-+ /* get extra bits for length */
-+ e &= 15;
-+ c = t->base + ((uInt)b & inflate_mask[e]);
-+ DUMPBITS(e)
-+ Tracevv((stderr, "inflate: * length %u\n", c));
-+
-+ /* decode distance base of block to copy */
-+ GRABBITS(15); /* max bits for distance code */
-+ e = (t = td + ((uInt)b & md))->exop;
-+ do {
-+ DUMPBITS(t->bits)
-+ if (e & 16)
-+ {
-+ /* get extra bits to add to distance base */
-+ e &= 15;
-+ GRABBITS(e) /* get extra bits (up to 13) */
-+ d = t->base + ((uInt)b & inflate_mask[e]);
-+ DUMPBITS(e)
-+ Tracevv((stderr, "inflate: * distance %u\n", d));
-+
-+ /* do the copy */
-+ m -= c;
-+ r = q - d;
-+ if (r < s->window) /* wrap if needed */
-+ {
-+ do {
-+ r += s->end - s->window; /* force pointer in window */
-+ } while (r < s->window); /* covers invalid distances */
-+ e = s->end - r;
-+ if (c > e)
-+ {
-+ c -= e; /* wrapped copy */
-+ do {
-+ *q++ = *r++;
-+ } while (--e);
-+ r = s->window;
-+ do {
-+ *q++ = *r++;
-+ } while (--c);
-+ }
-+ else /* normal copy */
-+ {
-+ *q++ = *r++; c--;
-+ *q++ = *r++; c--;
-+ do {
-+ *q++ = *r++;
-+ } while (--c);
-+ }
-+ }
-+ else /* normal copy */
-+ {
-+ *q++ = *r++; c--;
-+ *q++ = *r++; c--;
-+ do {
-+ *q++ = *r++;
-+ } while (--c);
-+ }
-+ break;
-+ }
-+ else if ((e & 64) == 0)
-+ {
-+ t += t->base;
-+ e = (t += ((uInt)b & inflate_mask[e]))->exop;
-+ }
-+ else
-+ {
-+ z->msg = (char*)"invalid distance code";
-+ UNGRAB
-+ UPDATE
-+ return Z_DATA_ERROR;
-+ }
-+ } while (1);
-+ break;
-+ }
-+ if ((e & 64) == 0)
-+ {
-+ t += t->base;
-+ if ((e = (t += ((uInt)b & inflate_mask[e]))->exop) == 0)
-+ {
-+ DUMPBITS(t->bits)
-+ Tracevv((stderr, t->base >= 0x20 && t->base < 0x7f ?
-+ "inflate: * literal '%c'\n" :
-+ "inflate: * literal 0x%02x\n", t->base));
-+ *q++ = (Byte)t->base;
-+ m--;
-+ break;
-+ }
-+ }
-+ else if (e & 32)
-+ {
-+ Tracevv((stderr, "inflate: * end of block\n"));
-+ UNGRAB
-+ UPDATE
-+ return Z_STREAM_END;
-+ }
-+ else
-+ {
-+ z->msg = (char*)"invalid literal/length code";
-+ UNGRAB
-+ UPDATE
-+ return Z_DATA_ERROR;
-+ }
-+ } while (1);
-+ } while (m >= 258 && n >= 10);
-+
-+ /* not enough input or output--restore pointers and return */
-+ UNGRAB
-+ UPDATE
-+ return Z_OK;
-+}
---- /dev/null Tue Mar 11 13:02:56 2003
-+++ linux/lib/zlib/inffast.h Mon Feb 9 13:51:03 2004
-@@ -0,0 +1,22 @@
-+/* inffast.h -- header to use inffast.c
-+ * Copyright (C) 1995-2002 Mark Adler
-+ * For conditions of distribution and use, see copyright notice in zlib.h
-+ */
-+
-+/* WARNING: this file should *not* be used by applications. It is
-+ part of the implementation of the compression library and is
-+ subject to change. Applications should only use zlib.h.
-+ */
-+
-+#ifndef _INFFAST_H
-+#define _INFFAST_H
-+
-+extern int inflate_fast OF((
-+ uInt,
-+ uInt,
-+ inflate_huft *,
-+ inflate_huft *,
-+ inflate_blocks_statef *,
-+ z_streamp ));
-+
-+#endif /* _INFFAST_H */
---- /dev/null Tue Mar 11 13:02:56 2003
-+++ linux/lib/zlib/inffixed.h Mon Feb 9 13:51:03 2004
-@@ -0,0 +1,151 @@
-+/* inffixed.h -- table for decoding fixed codes
-+ * Generated automatically by the maketree.c program
-+ */
-+
-+/* WARNING: this file should *not* be used by applications. It is
-+ part of the implementation of the compression library and is
-+ subject to change. Applications should only use zlib.h.
-+ */
-+
-+local uInt fixed_bl = 9;
-+local uInt fixed_bd = 5;
-+local inflate_huft fixed_tl[] = {
-+ {{{96,7}},256}, {{{0,8}},80}, {{{0,8}},16}, {{{84,8}},115},
-+ {{{82,7}},31}, {{{0,8}},112}, {{{0,8}},48}, {{{0,9}},192},
-+ {{{80,7}},10}, {{{0,8}},96}, {{{0,8}},32}, {{{0,9}},160},
-+ {{{0,8}},0}, {{{0,8}},128}, {{{0,8}},64}, {{{0,9}},224},
-+ {{{80,7}},6}, {{{0,8}},88}, {{{0,8}},24}, {{{0,9}},144},
-+ {{{83,7}},59}, {{{0,8}},120}, {{{0,8}},56}, {{{0,9}},208},
-+ {{{81,7}},17}, {{{0,8}},104}, {{{0,8}},40}, {{{0,9}},176},
-+ {{{0,8}},8}, {{{0,8}},136}, {{{0,8}},72}, {{{0,9}},240},
-+ {{{80,7}},4}, {{{0,8}},84}, {{{0,8}},20}, {{{85,8}},227},
-+ {{{83,7}},43}, {{{0,8}},116}, {{{0,8}},52}, {{{0,9}},200},
-+ {{{81,7}},13}, {{{0,8}},100}, {{{0,8}},36}, {{{0,9}},168},
-+ {{{0,8}},4}, {{{0,8}},132}, {{{0,8}},68}, {{{0,9}},232},
-+ {{{80,7}},8}, {{{0,8}},92}, {{{0,8}},28}, {{{0,9}},152},
-+ {{{84,7}},83}, {{{0,8}},124}, {{{0,8}},60}, {{{0,9}},216},
-+ {{{82,7}},23}, {{{0,8}},108}, {{{0,8}},44}, {{{0,9}},184},
-+ {{{0,8}},12}, {{{0,8}},140}, {{{0,8}},76}, {{{0,9}},248},
-+ {{{80,7}},3}, {{{0,8}},82}, {{{0,8}},18}, {{{85,8}},163},
-+ {{{83,7}},35}, {{{0,8}},114}, {{{0,8}},50}, {{{0,9}},196},
-+ {{{81,7}},11}, {{{0,8}},98}, {{{0,8}},34}, {{{0,9}},164},
-+ {{{0,8}},2}, {{{0,8}},130}, {{{0,8}},66}, {{{0,9}},228},
-+ {{{80,7}},7}, {{{0,8}},90}, {{{0,8}},26}, {{{0,9}},148},
-+ {{{84,7}},67}, {{{0,8}},122}, {{{0,8}},58}, {{{0,9}},212},
-+ {{{82,7}},19}, {{{0,8}},106}, {{{0,8}},42}, {{{0,9}},180},
-+ {{{0,8}},10}, {{{0,8}},138}, {{{0,8}},74}, {{{0,9}},244},
-+ {{{80,7}},5}, {{{0,8}},86}, {{{0,8}},22}, {{{192,8}},0},
-+ {{{83,7}},51}, {{{0,8}},118}, {{{0,8}},54}, {{{0,9}},204},
-+ {{{81,7}},15}, {{{0,8}},102}, {{{0,8}},38}, {{{0,9}},172},
-+ {{{0,8}},6}, {{{0,8}},134}, {{{0,8}},70}, {{{0,9}},236},
-+ {{{80,7}},9}, {{{0,8}},94}, {{{0,8}},30}, {{{0,9}},156},
-+ {{{84,7}},99}, {{{0,8}},126}, {{{0,8}},62}, {{{0,9}},220},
-+ {{{82,7}},27}, {{{0,8}},110}, {{{0,8}},46}, {{{0,9}},188},
-+ {{{0,8}},14}, {{{0,8}},142}, {{{0,8}},78}, {{{0,9}},252},
-+ {{{96,7}},256}, {{{0,8}},81}, {{{0,8}},17}, {{{85,8}},131},
-+ {{{82,7}},31}, {{{0,8}},113}, {{{0,8}},49}, {{{0,9}},194},
-+ {{{80,7}},10}, {{{0,8}},97}, {{{0,8}},33}, {{{0,9}},162},
-+ {{{0,8}},1}, {{{0,8}},129}, {{{0,8}},65}, {{{0,9}},226},
-+ {{{80,7}},6}, {{{0,8}},89}, {{{0,8}},25}, {{{0,9}},146},
-+ {{{83,7}},59}, {{{0,8}},121}, {{{0,8}},57}, {{{0,9}},210},
-+ {{{81,7}},17}, {{{0,8}},105}, {{{0,8}},41}, {{{0,9}},178},
-+ {{{0,8}},9}, {{{0,8}},137}, {{{0,8}},73}, {{{0,9}},242},
-+ {{{80,7}},4}, {{{0,8}},85}, {{{0,8}},21}, {{{80,8}},258},
-+ {{{83,7}},43}, {{{0,8}},117}, {{{0,8}},53}, {{{0,9}},202},
-+ {{{81,7}},13}, {{{0,8}},101}, {{{0,8}},37}, {{{0,9}},170},
-+ {{{0,8}},5}, {{{0,8}},133}, {{{0,8}},69}, {{{0,9}},234},
-+ {{{80,7}},8}, {{{0,8}},93}, {{{0,8}},29}, {{{0,9}},154},
-+ {{{84,7}},83}, {{{0,8}},125}, {{{0,8}},61}, {{{0,9}},218},
-+ {{{82,7}},23}, {{{0,8}},109}, {{{0,8}},45}, {{{0,9}},186},
-+ {{{0,8}},13}, {{{0,8}},141}, {{{0,8}},77}, {{{0,9}},250},
-+ {{{80,7}},3}, {{{0,8}},83}, {{{0,8}},19}, {{{85,8}},195},
-+ {{{83,7}},35}, {{{0,8}},115}, {{{0,8}},51}, {{{0,9}},198},
-+ {{{81,7}},11}, {{{0,8}},99}, {{{0,8}},35}, {{{0,9}},166},
-+ {{{0,8}},3}, {{{0,8}},131}, {{{0,8}},67}, {{{0,9}},230},
-+ {{{80,7}},7}, {{{0,8}},91}, {{{0,8}},27}, {{{0,9}},150},
-+ {{{84,7}},67}, {{{0,8}},123}, {{{0,8}},59}, {{{0,9}},214},
-+ {{{82,7}},19}, {{{0,8}},107}, {{{0,8}},43}, {{{0,9}},182},
-+ {{{0,8}},11}, {{{0,8}},139}, {{{0,8}},75}, {{{0,9}},246},
-+ {{{80,7}},5}, {{{0,8}},87}, {{{0,8}},23}, {{{192,8}},0},
-+ {{{83,7}},51}, {{{0,8}},119}, {{{0,8}},55}, {{{0,9}},206},
-+ {{{81,7}},15}, {{{0,8}},103}, {{{0,8}},39}, {{{0,9}},174},
-+ {{{0,8}},7}, {{{0,8}},135}, {{{0,8}},71}, {{{0,9}},238},
-+ {{{80,7}},9}, {{{0,8}},95}, {{{0,8}},31}, {{{0,9}},158},
-+ {{{84,7}},99}, {{{0,8}},127}, {{{0,8}},63}, {{{0,9}},222},
-+ {{{82,7}},27}, {{{0,8}},111}, {{{0,8}},47}, {{{0,9}},190},
-+ {{{0,8}},15}, {{{0,8}},143}, {{{0,8}},79}, {{{0,9}},254},
-+ {{{96,7}},256}, {{{0,8}},80}, {{{0,8}},16}, {{{84,8}},115},
-+ {{{82,7}},31}, {{{0,8}},112}, {{{0,8}},48}, {{{0,9}},193},
-+ {{{80,7}},10}, {{{0,8}},96}, {{{0,8}},32}, {{{0,9}},161},
-+ {{{0,8}},0}, {{{0,8}},128}, {{{0,8}},64}, {{{0,9}},225},
-+ {{{80,7}},6}, {{{0,8}},88}, {{{0,8}},24}, {{{0,9}},145},
-+ {{{83,7}},59}, {{{0,8}},120}, {{{0,8}},56}, {{{0,9}},209},
-+ {{{81,7}},17}, {{{0,8}},104}, {{{0,8}},40}, {{{0,9}},177},
-+ {{{0,8}},8}, {{{0,8}},136}, {{{0,8}},72}, {{{0,9}},241},
-+ {{{80,7}},4}, {{{0,8}},84}, {{{0,8}},20}, {{{85,8}},227},
-+ {{{83,7}},43}, {{{0,8}},116}, {{{0,8}},52}, {{{0,9}},201},
-+ {{{81,7}},13}, {{{0,8}},100}, {{{0,8}},36}, {{{0,9}},169},
-+ {{{0,8}},4}, {{{0,8}},132}, {{{0,8}},68}, {{{0,9}},233},
-+ {{{80,7}},8}, {{{0,8}},92}, {{{0,8}},28}, {{{0,9}},153},
-+ {{{84,7}},83}, {{{0,8}},124}, {{{0,8}},60}, {{{0,9}},217},
-+ {{{82,7}},23}, {{{0,8}},108}, {{{0,8}},44}, {{{0,9}},185},
-+ {{{0,8}},12}, {{{0,8}},140}, {{{0,8}},76}, {{{0,9}},249},
-+ {{{80,7}},3}, {{{0,8}},82}, {{{0,8}},18}, {{{85,8}},163},
-+ {{{83,7}},35}, {{{0,8}},114}, {{{0,8}},50}, {{{0,9}},197},
-+ {{{81,7}},11}, {{{0,8}},98}, {{{0,8}},34}, {{{0,9}},165},
-+ {{{0,8}},2}, {{{0,8}},130}, {{{0,8}},66}, {{{0,9}},229},
-+ {{{80,7}},7}, {{{0,8}},90}, {{{0,8}},26}, {{{0,9}},149},
-+ {{{84,7}},67}, {{{0,8}},122}, {{{0,8}},58}, {{{0,9}},213},
-+ {{{82,7}},19}, {{{0,8}},106}, {{{0,8}},42}, {{{0,9}},181},
-+ {{{0,8}},10}, {{{0,8}},138}, {{{0,8}},74}, {{{0,9}},245},
-+ {{{80,7}},5}, {{{0,8}},86}, {{{0,8}},22}, {{{192,8}},0},
-+ {{{83,7}},51}, {{{0,8}},118}, {{{0,8}},54}, {{{0,9}},205},
-+ {{{81,7}},15}, {{{0,8}},102}, {{{0,8}},38}, {{{0,9}},173},
-+ {{{0,8}},6}, {{{0,8}},134}, {{{0,8}},70}, {{{0,9}},237},
-+ {{{80,7}},9}, {{{0,8}},94}, {{{0,8}},30}, {{{0,9}},157},
-+ {{{84,7}},99}, {{{0,8}},126}, {{{0,8}},62}, {{{0,9}},221},
-+ {{{82,7}},27}, {{{0,8}},110}, {{{0,8}},46}, {{{0,9}},189},
-+ {{{0,8}},14}, {{{0,8}},142}, {{{0,8}},78}, {{{0,9}},253},
-+ {{{96,7}},256}, {{{0,8}},81}, {{{0,8}},17}, {{{85,8}},131},
-+ {{{82,7}},31}, {{{0,8}},113}, {{{0,8}},49}, {{{0,9}},195},
-+ {{{80,7}},10}, {{{0,8}},97}, {{{0,8}},33}, {{{0,9}},163},
-+ {{{0,8}},1}, {{{0,8}},129}, {{{0,8}},65}, {{{0,9}},227},
-+ {{{80,7}},6}, {{{0,8}},89}, {{{0,8}},25}, {{{0,9}},147},
-+ {{{83,7}},59}, {{{0,8}},121}, {{{0,8}},57}, {{{0,9}},211},
-+ {{{81,7}},17}, {{{0,8}},105}, {{{0,8}},41}, {{{0,9}},179},
-+ {{{0,8}},9}, {{{0,8}},137}, {{{0,8}},73}, {{{0,9}},243},
-+ {{{80,7}},4}, {{{0,8}},85}, {{{0,8}},21}, {{{80,8}},258},
-+ {{{83,7}},43}, {{{0,8}},117}, {{{0,8}},53}, {{{0,9}},203},
-+ {{{81,7}},13}, {{{0,8}},101}, {{{0,8}},37}, {{{0,9}},171},
-+ {{{0,8}},5}, {{{0,8}},133}, {{{0,8}},69}, {{{0,9}},235},
-+ {{{80,7}},8}, {{{0,8}},93}, {{{0,8}},29}, {{{0,9}},155},
-+ {{{84,7}},83}, {{{0,8}},125}, {{{0,8}},61}, {{{0,9}},219},
-+ {{{82,7}},23}, {{{0,8}},109}, {{{0,8}},45}, {{{0,9}},187},
-+ {{{0,8}},13}, {{{0,8}},141}, {{{0,8}},77}, {{{0,9}},251},
-+ {{{80,7}},3}, {{{0,8}},83}, {{{0,8}},19}, {{{85,8}},195},
-+ {{{83,7}},35}, {{{0,8}},115}, {{{0,8}},51}, {{{0,9}},199},
-+ {{{81,7}},11}, {{{0,8}},99}, {{{0,8}},35}, {{{0,9}},167},
-+ {{{0,8}},3}, {{{0,8}},131}, {{{0,8}},67}, {{{0,9}},231},
-+ {{{80,7}},7}, {{{0,8}},91}, {{{0,8}},27}, {{{0,9}},151},
-+ {{{84,7}},67}, {{{0,8}},123}, {{{0,8}},59}, {{{0,9}},215},
-+ {{{82,7}},19}, {{{0,8}},107}, {{{0,8}},43}, {{{0,9}},183},
-+ {{{0,8}},11}, {{{0,8}},139}, {{{0,8}},75}, {{{0,9}},247},
-+ {{{80,7}},5}, {{{0,8}},87}, {{{0,8}},23}, {{{192,8}},0},
-+ {{{83,7}},51}, {{{0,8}},119}, {{{0,8}},55}, {{{0,9}},207},
-+ {{{81,7}},15}, {{{0,8}},103}, {{{0,8}},39}, {{{0,9}},175},
-+ {{{0,8}},7}, {{{0,8}},135}, {{{0,8}},71}, {{{0,9}},239},
-+ {{{80,7}},9}, {{{0,8}},95}, {{{0,8}},31}, {{{0,9}},159},
-+ {{{84,7}},99}, {{{0,8}},127}, {{{0,8}},63}, {{{0,9}},223},
-+ {{{82,7}},27}, {{{0,8}},111}, {{{0,8}},47}, {{{0,9}},191},
-+ {{{0,8}},15}, {{{0,8}},143}, {{{0,8}},79}, {{{0,9}},255}
-+ };
-+local inflate_huft fixed_td[] = {
-+ {{{80,5}},1}, {{{87,5}},257}, {{{83,5}},17}, {{{91,5}},4097},
-+ {{{81,5}},5}, {{{89,5}},1025}, {{{85,5}},65}, {{{93,5}},16385},
-+ {{{80,5}},3}, {{{88,5}},513}, {{{84,5}},33}, {{{92,5}},8193},
-+ {{{82,5}},9}, {{{90,5}},2049}, {{{86,5}},129}, {{{192,5}},24577},
-+ {{{80,5}},2}, {{{87,5}},385}, {{{83,5}},25}, {{{91,5}},6145},
-+ {{{81,5}},7}, {{{89,5}},1537}, {{{85,5}},97}, {{{93,5}},24577},
-+ {{{80,5}},4}, {{{88,5}},769}, {{{84,5}},49}, {{{92,5}},12289},
-+ {{{82,5}},13}, {{{90,5}},3073}, {{{86,5}},193}, {{{192,5}},24577}
-+ };
---- /dev/null Tue Mar 11 13:02:56 2003
-+++ linux/lib/zlib/inflate.c Mon Feb 9 13:51:03 2004
-@@ -0,0 +1,368 @@
-+/* inflate.c -- zlib interface to inflate modules
-+ * Copyright (C) 1995-2002 Mark Adler
-+ * For conditions of distribution and use, see copyright notice in zlib.h
-+ */
-+
-+#include <zlib/zutil.h>
-+#include "infblock.h"
-+
-+struct inflate_blocks_state {int dummy;}; /* for buggy compilers */
-+
-+typedef enum {
-+ METHOD, /* waiting for method byte */
-+ FLAG, /* waiting for flag byte */
-+ DICT4, /* four dictionary check bytes to go */
-+ DICT3, /* three dictionary check bytes to go */
-+ DICT2, /* two dictionary check bytes to go */
-+ DICT1, /* one dictionary check byte to go */
-+ DICT0, /* waiting for inflateSetDictionary */
-+ BLOCKS, /* decompressing blocks */
-+ CHECK4, /* four check bytes to go */
-+ CHECK3, /* three check bytes to go */
-+ CHECK2, /* two check bytes to go */
-+ CHECK1, /* one check byte to go */
-+ DONE, /* finished check, done */
-+ BAD} /* got an error--stay here */
-+inflate_mode;
-+
-+/* inflate private state */
-+struct internal_state {
-+
-+ /* mode */
-+ inflate_mode mode; /* current inflate mode */
-+
-+ /* mode dependent information */
-+ union {
-+ uInt method; /* if FLAGS, method byte */
-+ struct {
-+ uLong was; /* computed check value */
-+ uLong need; /* stream check value */
-+ } check; /* if CHECK, check values to compare */
-+ uInt marker; /* if BAD, inflateSync's marker bytes count */
-+ } sub; /* submode */
-+
-+ /* mode independent information */
-+ int nowrap; /* flag for no wrapper */
-+ uInt wbits; /* log2(window size) (8..15, defaults to 15) */
-+ inflate_blocks_statef
-+ *blocks; /* current inflate_blocks state */
-+
-+};
-+
-+
-+int ZEXPORT inflateReset(z)
-+z_streamp z;
-+{
-+ if (z == Z_NULL || z->state == Z_NULL)
-+ return Z_STREAM_ERROR;
-+ z->total_in = z->total_out = 0;
-+ z->msg = Z_NULL;
-+ z->state->mode = z->state->nowrap ? BLOCKS : METHOD;
-+ inflate_blocks_reset(z->state->blocks, z, Z_NULL);
-+ Tracev((stderr, "inflate: reset\n"));
-+ return Z_OK;
-+}
-+
-+
-+int ZEXPORT inflateEnd(z)
-+z_streamp z;
-+{
-+ if (z == Z_NULL || z->state == Z_NULL || z->zfree == Z_NULL)
-+ return Z_STREAM_ERROR;
-+ if (z->state->blocks != Z_NULL)
-+ inflate_blocks_free(z->state->blocks, z);
-+ ZFREE(z, z->state);
-+ z->state = Z_NULL;
-+ Tracev((stderr, "inflate: end\n"));
-+ return Z_OK;
-+}
-+
-+
-+int ZEXPORT inflateInit2_(z, w, version, stream_size)
-+z_streamp z;
-+int w;
-+const char *version;
-+int stream_size;
-+{
-+ if (version == Z_NULL || version[0] != ZLIB_VERSION[0] ||
-+ stream_size != sizeof(z_stream))
-+ return Z_VERSION_ERROR;
-+
-+ /* initialize state */
-+ if (z == Z_NULL)
-+ return Z_STREAM_ERROR;
-+ z->msg = Z_NULL;
-+ if (z->zalloc == Z_NULL)
-+ {
-+ return Z_STREAM_ERROR;
-+/* z->zalloc = zcalloc;
-+ z->opaque = (voidpf)0;
-+*/
-+ }
-+ if (z->zfree == Z_NULL) return Z_STREAM_ERROR; /* z->zfree = zcfree; */
-+ if ((z->state = (struct internal_state FAR *)
-+ ZALLOC(z,1,sizeof(struct internal_state))) == Z_NULL)
-+ return Z_MEM_ERROR;
-+ z->state->blocks = Z_NULL;
-+
-+ /* handle undocumented nowrap option (no zlib header or check) */
-+ z->state->nowrap = 0;
-+ if (w < 0)
-+ {
-+ w = - w;
-+ z->state->nowrap = 1;
-+ }
-+
-+ /* set window size */
-+ if (w < 8 || w > 15)
-+ {
-+ inflateEnd(z);
-+ return Z_STREAM_ERROR;
-+ }
-+ z->state->wbits = (uInt)w;
-+
-+ /* create inflate_blocks state */
-+ if ((z->state->blocks =
-+ inflate_blocks_new(z, z->state->nowrap ? Z_NULL : adler32, (uInt)1 << w))
-+ == Z_NULL)
-+ {
-+ inflateEnd(z);
-+ return Z_MEM_ERROR;
-+ }
-+ Tracev((stderr, "inflate: allocated\n"));
-+
-+ /* reset state */
-+ inflateReset(z);
-+ return Z_OK;
-+}
-+
-+
-+int ZEXPORT inflateInit_(z, version, stream_size)
-+z_streamp z;
-+const char *version;
-+int stream_size;
-+{
-+ return inflateInit2_(z, DEF_WBITS, version, stream_size);
-+}
-+
-+
-+#define NEEDBYTE {if(z->avail_in==0)return r;r=f;}
-+#define NEXTBYTE (z->avail_in--,z->total_in++,*z->next_in++)
-+
-+int ZEXPORT inflate(z, f)
-+z_streamp z;
-+int f;
-+{
-+ int r;
-+ uInt b;
-+
-+ if (z == Z_NULL || z->state == Z_NULL || z->next_in == Z_NULL)
-+ return Z_STREAM_ERROR;
-+ f = f == Z_FINISH ? Z_BUF_ERROR : Z_OK;
-+ r = Z_BUF_ERROR;
-+ while (1) switch (z->state->mode)
-+ {
-+ case METHOD:
-+ NEEDBYTE
-+ if (((z->state->sub.method = NEXTBYTE) & 0xf) != Z_DEFLATED)
-+ {
-+ z->state->mode = BAD;
-+ z->msg = (char*)"unknown compression method";
-+ z->state->sub.marker = 5; /* can't try inflateSync */
-+ break;
-+ }
-+ if ((z->state->sub.method >> 4) + 8 > z->state->wbits)
-+ {
-+ z->state->mode = BAD;
-+ z->msg = (char*)"invalid window size";
-+ z->state->sub.marker = 5; /* can't try inflateSync */
-+ break;
-+ }
-+ z->state->mode = FLAG;
-+ case FLAG:
-+ NEEDBYTE
-+ b = NEXTBYTE;
-+ if (((z->state->sub.method << 8) + b) % 31)
-+ {
-+ z->state->mode = BAD;
-+ z->msg = (char*)"incorrect header check";
-+ z->state->sub.marker = 5; /* can't try inflateSync */
-+ break;
-+ }
-+ Tracev((stderr, "inflate: zlib header ok\n"));
-+ if (!(b & PRESET_DICT))
-+ {
-+ z->state->mode = BLOCKS;
-+ break;
-+ }
-+ z->state->mode = DICT4;
-+ case DICT4:
-+ NEEDBYTE
-+ z->state->sub.check.need = (uLong)NEXTBYTE << 24;
-+ z->state->mode = DICT3;
-+ case DICT3:
-+ NEEDBYTE
-+ z->state->sub.check.need += (uLong)NEXTBYTE << 16;
-+ z->state->mode = DICT2;
-+ case DICT2:
-+ NEEDBYTE
-+ z->state->sub.check.need += (uLong)NEXTBYTE << 8;
-+ z->state->mode = DICT1;
-+ case DICT1:
-+ NEEDBYTE
-+ z->state->sub.check.need += (uLong)NEXTBYTE;
-+ z->adler = z->state->sub.check.need;
-+ z->state->mode = DICT0;
-+ return Z_NEED_DICT;
-+ case DICT0:
-+ z->state->mode = BAD;
-+ z->msg = (char*)"need dictionary";
-+ z->state->sub.marker = 0; /* can try inflateSync */
-+ return Z_STREAM_ERROR;
-+ case BLOCKS:
-+ r = inflate_blocks(z->state->blocks, z, r);
-+ if (r == Z_DATA_ERROR)
-+ {
-+ z->state->mode = BAD;
-+ z->state->sub.marker = 0; /* can try inflateSync */
-+ break;
-+ }
-+ if (r == Z_OK)
-+ r = f;
-+ if (r != Z_STREAM_END)
-+ return r;
-+ r = f;
-+ inflate_blocks_reset(z->state->blocks, z, &z->state->sub.check.was);
-+ if (z->state->nowrap)
-+ {
-+ z->state->mode = DONE;
-+ break;
-+ }
-+ z->state->mode = CHECK4;
-+ case CHECK4:
-+ NEEDBYTE
-+ z->state->sub.check.need = (uLong)NEXTBYTE << 24;
-+ z->state->mode = CHECK3;
-+ case CHECK3:
-+ NEEDBYTE
-+ z->state->sub.check.need += (uLong)NEXTBYTE << 16;
-+ z->state->mode = CHECK2;
-+ case CHECK2:
-+ NEEDBYTE
-+ z->state->sub.check.need += (uLong)NEXTBYTE << 8;
-+ z->state->mode = CHECK1;
-+ case CHECK1:
-+ NEEDBYTE
-+ z->state->sub.check.need += (uLong)NEXTBYTE;
-+
-+ if (z->state->sub.check.was != z->state->sub.check.need)
-+ {
-+ z->state->mode = BAD;
-+ z->msg = (char*)"incorrect data check";
-+ z->state->sub.marker = 5; /* can't try inflateSync */
-+ break;
-+ }
-+ Tracev((stderr, "inflate: zlib check ok\n"));
-+ z->state->mode = DONE;
-+ case DONE:
-+ return Z_STREAM_END;
-+ case BAD:
-+ return Z_DATA_ERROR;
-+ default:
-+ return Z_STREAM_ERROR;
-+ }
-+#ifdef NEED_DUMMY_RETURN
-+ return Z_STREAM_ERROR; /* Some dumb compilers complain without this */
-+#endif
-+}
-+
-+
-+int ZEXPORT inflateSetDictionary(z, dictionary, dictLength)
-+z_streamp z;
-+const Bytef *dictionary;
-+uInt dictLength;
-+{
-+ uInt length = dictLength;
-+
-+ if (z == Z_NULL || z->state == Z_NULL || z->state->mode != DICT0)
-+ return Z_STREAM_ERROR;
-+
-+ if (adler32(1L, dictionary, dictLength) != z->adler) return Z_DATA_ERROR;
-+ z->adler = 1L;
-+
-+ if (length >= ((uInt)1<<z->state->wbits))
-+ {
-+ length = (1<<z->state->wbits)-1;
-+ dictionary += dictLength - length;
-+ }
-+ inflate_set_dictionary(z->state->blocks, dictionary, length);
-+ z->state->mode = BLOCKS;
-+ return Z_OK;
-+}
-+
-+
-+int ZEXPORT inflateSync(z)
-+z_streamp z;
-+{
-+ uInt n; /* number of bytes to look at */
-+ Bytef *p; /* pointer to bytes */
-+ uInt m; /* number of marker bytes found in a row */
-+ uLong r, w; /* temporaries to save total_in and total_out */
-+
-+ /* set up */
-+ if (z == Z_NULL || z->state == Z_NULL)
-+ return Z_STREAM_ERROR;
-+ if (z->state->mode != BAD)
-+ {
-+ z->state->mode = BAD;
-+ z->state->sub.marker = 0;
-+ }
-+ if ((n = z->avail_in) == 0)
-+ return Z_BUF_ERROR;
-+ p = z->next_in;
-+ m = z->state->sub.marker;
-+
-+ /* search */
-+ while (n && m < 4)
-+ {
-+ static const Byte mark[4] = {0, 0, 0xff, 0xff};
-+ if (*p == mark[m])
-+ m++;
-+ else if (*p)
-+ m = 0;
-+ else
-+ m = 4 - m;
-+ p++, n--;
-+ }
-+
-+ /* restore */
-+ z->total_in += p - z->next_in;
-+ z->next_in = p;
-+ z->avail_in = n;
-+ z->state->sub.marker = m;
-+
-+ /* return no joy or set up to restart on a new block */
-+ if (m != 4)
-+ return Z_DATA_ERROR;
-+ r = z->total_in; w = z->total_out;
-+ inflateReset(z);
-+ z->total_in = r; z->total_out = w;
-+ z->state->mode = BLOCKS;
-+ return Z_OK;
-+}
-+
-+
-+/* Returns true if inflate is currently at the end of a block generated
-+ * by Z_SYNC_FLUSH or Z_FULL_FLUSH. This function is used by one PPP
-+ * implementation to provide an additional safety check. PPP uses Z_SYNC_FLUSH
-+ * but removes the length bytes of the resulting empty stored block. When
-+ * decompressing, PPP checks that at the end of input packet, inflate is
-+ * waiting for these length bytes.
-+ */
-+int ZEXPORT inflateSyncPoint(z)
-+z_streamp z;
-+{
-+ if (z == Z_NULL || z->state == Z_NULL || z->state->blocks == Z_NULL)
-+ return Z_STREAM_ERROR;
-+ return inflate_blocks_sync_point(z->state->blocks);
-+}
---- /dev/null Tue Mar 11 13:02:56 2003
-+++ linux/lib/zlib/inftrees.c Mon Feb 9 13:51:03 2004
-@@ -0,0 +1,454 @@
-+/* inftrees.c -- generate Huffman trees for efficient decoding
-+ * Copyright (C) 1995-2002 Mark Adler
-+ * For conditions of distribution and use, see copyright notice in zlib.h
-+ */
-+
-+#include <zlib/zutil.h>
-+#include "inftrees.h"
-+
-+#if !defined(BUILDFIXED) && !defined(STDC)
-+# define BUILDFIXED /* non ANSI compilers may not accept inffixed.h */
-+#endif
-+
-+local const char inflate_copyright[] =
-+ " inflate 1.1.4 Copyright 1995-2002 Mark Adler ";
-+/*
-+ If you use the zlib library in a product, an acknowledgment is welcome
-+ in the documentation of your product. If for some reason you cannot
-+ include such an acknowledgment, I would appreciate that you keep this
-+ copyright string in the executable of your product.
-+ */
-+struct internal_state {int dummy;}; /* for buggy compilers */
-+
-+/* simplify the use of the inflate_huft type with some defines */
-+#define exop word.what.Exop
-+#define bits word.what.Bits
-+
-+
-+local int huft_build OF((
-+ uIntf *, /* code lengths in bits */
-+ uInt, /* number of codes */
-+ uInt, /* number of "simple" codes */
-+ const uIntf *, /* list of base values for non-simple codes */
-+ const uIntf *, /* list of extra bits for non-simple codes */
-+ inflate_huft * FAR*,/* result: starting table */
-+ uIntf *, /* maximum lookup bits (returns actual) */
-+ inflate_huft *, /* space for trees */
-+ uInt *, /* hufts used in space */
-+ uIntf * )); /* space for values */
-+
-+/* Tables for deflate from PKZIP's appnote.txt. */
-+local const uInt cplens[31] = { /* Copy lengths for literal codes 257..285 */
-+ 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
-+ 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0};
-+ /* see note #13 above about 258 */
-+local const uInt cplext[31] = { /* Extra bits for literal codes 257..285 */
-+ 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2,
-+ 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 112, 112}; /* 112==invalid */
-+local const uInt cpdist[30] = { /* Copy offsets for distance codes 0..29 */
-+ 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,
-+ 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,
-+ 8193, 12289, 16385, 24577};
-+local const uInt cpdext[30] = { /* Extra bits for distance codes */
-+ 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6,
-+ 7, 7, 8, 8, 9, 9, 10, 10, 11, 11,
-+ 12, 12, 13, 13};
-+
-+/*
-+ Huffman code decoding is performed using a multi-level table lookup.
-+ The fastest way to decode is to simply build a lookup table whose
-+ size is determined by the longest code. However, the time it takes
-+ to build this table can also be a factor if the data being decoded
-+ is not very long. The most common codes are necessarily the
-+ shortest codes, so those codes dominate the decoding time, and hence
-+ the speed. The idea is you can have a shorter table that decodes the
-+ shorter, more probable codes, and then point to subsidiary tables for
-+ the longer codes. The time it costs to decode the longer codes is
-+ then traded against the time it takes to make longer tables.
-+
-+ This results of this trade are in the variables lbits and dbits
-+ below. lbits is the number of bits the first level table for literal/
-+ length codes can decode in one step, and dbits is the same thing for
-+ the distance codes. Subsequent tables are also less than or equal to
-+ those sizes. These values may be adjusted either when all of the
-+ codes are shorter than that, in which case the longest code length in
-+ bits is used, or when the shortest code is *longer* than the requested
-+ table size, in which case the length of the shortest code in bits is
-+ used.
-+
-+ There are two different values for the two tables, since they code a
-+ different number of possibilities each. The literal/length table
-+ codes 286 possible values, or in a flat code, a little over eight
-+ bits. The distance table codes 30 possible values, or a little less
-+ than five bits, flat. The optimum values for speed end up being
-+ about one bit more than those, so lbits is 8+1 and dbits is 5+1.
-+ The optimum values may differ though from machine to machine, and
-+ possibly even between compilers. Your mileage may vary.
-+ */
-+
-+
-+/* If BMAX needs to be larger than 16, then h and x[] should be uLong. */
-+#define BMAX 15 /* maximum bit length of any code */
-+
-+local int huft_build(b, n, s, d, e, t, m, hp, hn, v)
-+uIntf *b; /* code lengths in bits (all assumed <= BMAX) */
-+uInt n; /* number of codes (assumed <= 288) */
-+uInt s; /* number of simple-valued codes (0..s-1) */
-+const uIntf *d; /* list of base values for non-simple codes */
-+const uIntf *e; /* list of extra bits for non-simple codes */
-+inflate_huft * FAR *t; /* result: starting table */
-+uIntf *m; /* maximum lookup bits, returns actual */
-+inflate_huft *hp; /* space for trees */
-+uInt *hn; /* hufts used in space */
-+uIntf *v; /* working area: values in order of bit length */
-+/* Given a list of code lengths and a maximum table size, make a set of
-+ tables to decode that set of codes. Return Z_OK on success, Z_BUF_ERROR
-+ if the given code set is incomplete (the tables are still built in this
-+ case), or Z_DATA_ERROR if the input is invalid. */
-+{
-+
-+ uInt a; /* counter for codes of length k */
-+ uInt c[BMAX+1]; /* bit length count table */
-+ uInt f; /* i repeats in table every f entries */
-+ int g; /* maximum code length */
-+ int h; /* table level */
-+ register uInt i; /* counter, current code */
-+ register uInt j; /* counter */
-+ register int k; /* number of bits in current code */
-+ int l; /* bits per table (returned in m) */
-+ uInt mask; /* (1 << w) - 1, to avoid cc -O bug on HP */
-+ register uIntf *p; /* pointer into c[], b[], or v[] */
-+ inflate_huft *q; /* points to current table */
-+ struct inflate_huft_s r; /* table entry for structure assignment */
-+ inflate_huft *u[BMAX]; /* table stack */
-+ register int w; /* bits before this table == (l * h) */
-+ uInt x[BMAX+1]; /* bit offsets, then code stack */
-+ uIntf *xp; /* pointer into x */
-+ int y; /* number of dummy codes added */
-+ uInt z; /* number of entries in current table */
-+
-+
-+ /* Generate counts for each bit length */
-+ p = c;
-+#define C0 *p++ = 0;
-+#define C2 C0 C0 C0 C0
-+#define C4 C2 C2 C2 C2
-+ C4 /* clear c[]--assume BMAX+1 is 16 */
-+ p = b; i = n;
-+ do {
-+ c[*p++]++; /* assume all entries <= BMAX */
-+ } while (--i);
-+ if (c[0] == n) /* null input--all zero length codes */
-+ {
-+ *t = (inflate_huft *)Z_NULL;
-+ *m = 0;
-+ return Z_OK;
-+ }
-+
-+
-+ /* Find minimum and maximum length, bound *m by those */
-+ l = *m;
-+ for (j = 1; j <= BMAX; j++)
-+ if (c[j])
-+ break;
-+ k = j; /* minimum code length */
-+ if ((uInt)l < j)
-+ l = j;
-+ for (i = BMAX; i; i--)
-+ if (c[i])
-+ break;
-+ g = i; /* maximum code length */
-+ if ((uInt)l > i)
-+ l = i;
-+ *m = l;
-+
-+
-+ /* Adjust last length count to fill out codes, if needed */
-+ for (y = 1 << j; j < i; j++, y <<= 1)
-+ if ((y -= c[j]) < 0)
-+ return Z_DATA_ERROR;
-+ if ((y -= c[i]) < 0)
-+ return Z_DATA_ERROR;
-+ c[i] += y;
-+
-+
-+ /* Generate starting offsets into the value table for each length */
-+ x[1] = j = 0;
-+ p = c + 1; xp = x + 2;
-+ while (--i) { /* note that i == g from above */
-+ *xp++ = (j += *p++);
-+ }
-+
-+
-+ /* Make a table of values in order of bit lengths */
-+ p = b; i = 0;
-+ do {
-+ if ((j = *p++) != 0)
-+ v[x[j]++] = i;
-+ } while (++i < n);
-+ n = x[g]; /* set n to length of v */
-+
-+
-+ /* Generate the Huffman codes and for each, make the table entries */
-+ x[0] = i = 0; /* first Huffman code is zero */
-+ p = v; /* grab values in bit order */
-+ h = -1; /* no tables yet--level -1 */
-+ w = -l; /* bits decoded == (l * h) */
-+ u[0] = (inflate_huft *)Z_NULL; /* just to keep compilers happy */
-+ q = (inflate_huft *)Z_NULL; /* ditto */
-+ z = 0; /* ditto */
-+
-+ /* go through the bit lengths (k already is bits in shortest code) */
-+ for (; k <= g; k++)
-+ {
-+ a = c[k];
-+ while (a--)
-+ {
-+ /* here i is the Huffman code of length k bits for value *p */
-+ /* make tables up to required level */
-+ while (k > w + l)
-+ {
-+ h++;
-+ w += l; /* previous table always l bits */
-+
-+ /* compute minimum size table less than or equal to l bits */
-+ z = g - w;
-+ z = z > (uInt)l ? l : z; /* table size upper limit */
-+ if ((f = 1 << (j = k - w)) > a + 1) /* try a k-w bit table */
-+ { /* too few codes for k-w bit table */
-+ f -= a + 1; /* deduct codes from patterns left */
-+ xp = c + k;
-+ if (j < z)
-+ while (++j < z) /* try smaller tables up to z bits */
-+ {
-+ if ((f <<= 1) <= *++xp)
-+ break; /* enough codes to use up j bits */
-+ f -= *xp; /* else deduct codes from patterns */
-+ }
-+ }
-+ z = 1 << j; /* table entries for j-bit table */
-+
-+ /* allocate new table */
-+ if (*hn + z > MANY) /* (note: doesn't matter for fixed) */
-+ return Z_DATA_ERROR; /* overflow of MANY */
-+ u[h] = q = hp + *hn;
-+ *hn += z;
-+
-+ /* connect to last table, if there is one */
-+ if (h)
-+ {
-+ x[h] = i; /* save pattern for backing up */
-+ r.bits = (Byte)l; /* bits to dump before this table */
-+ r.exop = (Byte)j; /* bits in this table */
-+ j = i >> (w - l);
-+ r.base = (uInt)(q - u[h-1] - j); /* offset to this table */
-+ u[h-1][j] = r; /* connect to last table */
-+ }
-+ else
-+ *t = q; /* first table is returned result */
-+ }
-+
-+ /* set up table entry in r */
-+ r.bits = (Byte)(k - w);
-+ if (p >= v + n)
-+ r.exop = 128 + 64; /* out of values--invalid code */
-+ else if (*p < s)
-+ {
-+ r.exop = (Byte)(*p < 256 ? 0 : 32 + 64); /* 256 is end-of-block */
-+ r.base = *p++; /* simple code is just the value */
-+ }
-+ else
-+ {
-+ r.exop = (Byte)(e[*p - s] + 16 + 64);/* non-simple--look up in lists */
-+ r.base = d[*p++ - s];
-+ }
-+
-+ /* fill code-like entries with r */
-+ f = 1 << (k - w);
-+ for (j = i >> w; j < z; j += f)
-+ q[j] = r;
-+
-+ /* backwards increment the k-bit code i */
-+ for (j = 1 << (k - 1); i & j; j >>= 1)
-+ i ^= j;
-+ i ^= j;
-+
-+ /* backup over finished tables */
-+ mask = (1 << w) - 1; /* needed on HP, cc -O bug */
-+ while ((i & mask) != x[h])
-+ {
-+ h--; /* don't need to update q */
-+ w -= l;
-+ mask = (1 << w) - 1;
-+ }
-+ }
-+ }
-+
-+
-+ /* Return Z_BUF_ERROR if we were given an incomplete table */
-+ return y != 0 && g != 1 ? Z_BUF_ERROR : Z_OK;
-+}
-+
-+
-+int inflate_trees_bits(c, bb, tb, hp, z)
-+uIntf *c; /* 19 code lengths */
-+uIntf *bb; /* bits tree desired/actual depth */
-+inflate_huft * FAR *tb; /* bits tree result */
-+inflate_huft *hp; /* space for trees */
-+z_streamp z; /* for messages */
-+{
-+ int r;
-+ uInt hn = 0; /* hufts used in space */
-+ uIntf *v; /* work area for huft_build */
-+
-+ if ((v = (uIntf*)ZALLOC(z, 19, sizeof(uInt))) == Z_NULL)
-+ return Z_MEM_ERROR;
-+ r = huft_build(c, 19, 19, (uIntf*)Z_NULL, (uIntf*)Z_NULL,
-+ tb, bb, hp, &hn, v);
-+ if (r == Z_DATA_ERROR)
-+ z->msg = (char*)"oversubscribed dynamic bit lengths tree";
-+ else if (r == Z_BUF_ERROR || *bb == 0)
-+ {
-+ z->msg = (char*)"incomplete dynamic bit lengths tree";
-+ r = Z_DATA_ERROR;
-+ }
-+ ZFREE(z, v);
-+ return r;
-+}
-+
-+
-+int inflate_trees_dynamic(nl, nd, c, bl, bd, tl, td, hp, z)
-+uInt nl; /* number of literal/length codes */
-+uInt nd; /* number of distance codes */
-+uIntf *c; /* that many (total) code lengths */
-+uIntf *bl; /* literal desired/actual bit depth */
-+uIntf *bd; /* distance desired/actual bit depth */
-+inflate_huft * FAR *tl; /* literal/length tree result */
-+inflate_huft * FAR *td; /* distance tree result */
-+inflate_huft *hp; /* space for trees */
-+z_streamp z; /* for messages */
-+{
-+ int r;
-+ uInt hn = 0; /* hufts used in space */
-+ uIntf *v; /* work area for huft_build */
-+
-+ /* allocate work area */
-+ if ((v = (uIntf*)ZALLOC(z, 288, sizeof(uInt))) == Z_NULL)
-+ return Z_MEM_ERROR;
-+
-+ /* build literal/length tree */
-+ r = huft_build(c, nl, 257, cplens, cplext, tl, bl, hp, &hn, v);
-+ if (r != Z_OK || *bl == 0)
-+ {
-+ if (r == Z_DATA_ERROR)
-+ z->msg = (char*)"oversubscribed literal/length tree";
-+ else if (r != Z_MEM_ERROR)
-+ {
-+ z->msg = (char*)"incomplete literal/length tree";
-+ r = Z_DATA_ERROR;
-+ }
-+ ZFREE(z, v);
-+ return r;
-+ }
-+
-+ /* build distance tree */
-+ r = huft_build(c + nl, nd, 0, cpdist, cpdext, td, bd, hp, &hn, v);
-+ if (r != Z_OK || (*bd == 0 && nl > 257))
-+ {
-+ if (r == Z_DATA_ERROR)
-+ z->msg = (char*)"oversubscribed distance tree";
-+ else if (r == Z_BUF_ERROR) {
-+#ifdef PKZIP_BUG_WORKAROUND
-+ r = Z_OK;
-+ }
-+#else
-+ z->msg = (char*)"incomplete distance tree";
-+ r = Z_DATA_ERROR;
-+ }
-+ else if (r != Z_MEM_ERROR)
-+ {
-+ z->msg = (char*)"empty distance tree with lengths";
-+ r = Z_DATA_ERROR;
-+ }
-+ ZFREE(z, v);
-+ return r;
-+#endif
-+ }
-+
-+ /* done */
-+ ZFREE(z, v);
-+ return Z_OK;
-+}
-+
-+
-+/* build fixed tables only once--keep them here */
-+#ifdef BUILDFIXED
-+local int fixed_built = 0;
-+#define FIXEDH 544 /* number of hufts used by fixed tables */
-+local inflate_huft fixed_mem[FIXEDH];
-+local uInt fixed_bl;
-+local uInt fixed_bd;
-+local inflate_huft *fixed_tl;
-+local inflate_huft *fixed_td;
-+#else
-+#include "inffixed.h"
-+#endif
-+
-+
-+int inflate_trees_fixed(bl, bd, tl, td, z)
-+uIntf *bl; /* literal desired/actual bit depth */
-+uIntf *bd; /* distance desired/actual bit depth */
-+inflate_huft * FAR *tl; /* literal/length tree result */
-+inflate_huft * FAR *td; /* distance tree result */
-+z_streamp z; /* for memory allocation */
-+{
-+#ifdef BUILDFIXED
-+ /* build fixed tables if not already */
-+ if (!fixed_built)
-+ {
-+ int k; /* temporary variable */
-+ uInt f = 0; /* number of hufts used in fixed_mem */
-+ uIntf *c; /* length list for huft_build */
-+ uIntf *v; /* work area for huft_build */
-+
-+ /* allocate memory */
-+ if ((c = (uIntf*)ZALLOC(z, 288, sizeof(uInt))) == Z_NULL)
-+ return Z_MEM_ERROR;
-+ if ((v = (uIntf*)ZALLOC(z, 288, sizeof(uInt))) == Z_NULL)
-+ {
-+ ZFREE(z, c);
-+ return Z_MEM_ERROR;
-+ }
-+
-+ /* literal table */
-+ for (k = 0; k < 144; k++)
-+ c[k] = 8;
-+ for (; k < 256; k++)
-+ c[k] = 9;
-+ for (; k < 280; k++)
-+ c[k] = 7;
-+ for (; k < 288; k++)
-+ c[k] = 8;
-+ fixed_bl = 9;
-+ huft_build(c, 288, 257, cplens, cplext, &fixed_tl, &fixed_bl,
-+ fixed_mem, &f, v);
-+
-+ /* distance table */
-+ for (k = 0; k < 30; k++)
-+ c[k] = 5;
-+ fixed_bd = 5;
-+ huft_build(c, 30, 0, cpdist, cpdext, &fixed_td, &fixed_bd,
-+ fixed_mem, &f, v);
-+
-+ /* done */
-+ ZFREE(z, v);
-+ ZFREE(z, c);
-+ fixed_built = 1;
-+ }
-+#endif
-+ *bl = fixed_bl;
-+ *bd = fixed_bd;
-+ *tl = fixed_tl;
-+ *td = fixed_td;
-+ return Z_OK;
-+}
---- /dev/null Tue Mar 11 13:02:56 2003
-+++ linux/lib/zlib/inftrees.h Mon Feb 9 13:51:03 2004
-@@ -0,0 +1,63 @@
-+/* inftrees.h -- header to use inftrees.c
-+ * Copyright (C) 1995-2002 Mark Adler
-+ * For conditions of distribution and use, see copyright notice in zlib.h
-+ */
-+
-+/* WARNING: this file should *not* be used by applications. It is
-+ part of the implementation of the compression library and is
-+ subject to change. Applications should only use zlib.h.
-+ */
-+
-+/* Huffman code lookup table entry--this entry is four bytes for machines
-+ that have 16-bit pointers (e.g. PC's in the small or medium model). */
-+
-+#ifndef _INFTREES_H
-+#define _INFTREES_H
-+
-+typedef struct inflate_huft_s FAR inflate_huft;
-+
-+struct inflate_huft_s {
-+ union {
-+ struct {
-+ Byte Exop; /* number of extra bits or operation */
-+ Byte Bits; /* number of bits in this code or subcode */
-+ } what;
-+ uInt pad; /* pad structure to a power of 2 (4 bytes for */
-+ } word; /* 16-bit, 8 bytes for 32-bit int's) */
-+ uInt base; /* literal, length base, distance base,
-+ or table offset */
-+};
-+
-+/* Maximum size of dynamic tree. The maximum found in a long but non-
-+ exhaustive search was 1004 huft structures (850 for length/literals
-+ and 154 for distances, the latter actually the result of an
-+ exhaustive search). The actual maximum is not known, but the
-+ value below is more than safe. */
-+#define MANY 1440
-+
-+extern int inflate_trees_bits OF((
-+ uIntf *, /* 19 code lengths */
-+ uIntf *, /* bits tree desired/actual depth */
-+ inflate_huft * FAR *, /* bits tree result */
-+ inflate_huft *, /* space for trees */
-+ z_streamp)); /* for messages */
-+
-+extern int inflate_trees_dynamic OF((
-+ uInt, /* number of literal/length codes */
-+ uInt, /* number of distance codes */
-+ uIntf *, /* that many (total) code lengths */
-+ uIntf *, /* literal desired/actual bit depth */
-+ uIntf *, /* distance desired/actual bit depth */
-+ inflate_huft * FAR *, /* literal/length tree result */
-+ inflate_huft * FAR *, /* distance tree result */
-+ inflate_huft *, /* space for trees */
-+ z_streamp)); /* for messages */
-+
-+extern int inflate_trees_fixed OF((
-+ uIntf *, /* literal desired/actual bit depth */
-+ uIntf *, /* distance desired/actual bit depth */
-+ inflate_huft * FAR *, /* literal/length tree result */
-+ inflate_huft * FAR *, /* distance tree result */
-+ z_streamp)); /* for memory allocation */
-+
-+#endif /* _INFTREES_H */
---- /dev/null Tue Mar 11 13:02:56 2003
-+++ linux/lib/zlib/infutil.c Mon Feb 9 13:51:03 2004
-@@ -0,0 +1,87 @@
-+/* inflate_util.c -- data and routines common to blocks and codes
-+ * Copyright (C) 1995-2002 Mark Adler
-+ * For conditions of distribution and use, see copyright notice in zlib.h
-+ */
-+
-+#include <zlib/zutil.h>
-+#include "infblock.h"
-+#include "inftrees.h"
-+#include "infcodes.h"
-+#include "infutil.h"
-+
-+struct inflate_codes_state {int dummy;}; /* for buggy compilers */
-+
-+/* And'ing with mask[n] masks the lower n bits */
-+uInt inflate_mask[17] = {
-+ 0x0000,
-+ 0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff,
-+ 0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff
-+};
-+
-+
-+/* copy as much as possible from the sliding window to the output area */
-+int inflate_flush(s, z, r)
-+inflate_blocks_statef *s;
-+z_streamp z;
-+int r;
-+{
-+ uInt n;
-+ Bytef *p;
-+ Bytef *q;
-+
-+ /* local copies of source and destination pointers */
-+ p = z->next_out;
-+ q = s->read;
-+
-+ /* compute number of bytes to copy as far as end of window */
-+ n = (uInt)((q <= s->write ? s->write : s->end) - q);
-+ if (n > z->avail_out) n = z->avail_out;
-+ if (n && r == Z_BUF_ERROR) r = Z_OK;
-+
-+ /* update counters */
-+ z->avail_out -= n;
-+ z->total_out += n;
-+
-+ /* update check information */
-+ if (s->checkfn != Z_NULL)
-+ z->adler = s->check = (*s->checkfn)(s->check, q, n);
-+
-+ /* copy as far as end of window */
-+ zmemcpy(p, q, n);
-+ p += n;
-+ q += n;
-+
-+ /* see if more to copy at beginning of window */
-+ if (q == s->end)
-+ {
-+ /* wrap pointers */
-+ q = s->window;
-+ if (s->write == s->end)
-+ s->write = s->window;
-+
-+ /* compute bytes to copy */
-+ n = (uInt)(s->write - q);
-+ if (n > z->avail_out) n = z->avail_out;
-+ if (n && r == Z_BUF_ERROR) r = Z_OK;
-+
-+ /* update counters */
-+ z->avail_out -= n;
-+ z->total_out += n;
-+
-+ /* update check information */
-+ if (s->checkfn != Z_NULL)
-+ z->adler = s->check = (*s->checkfn)(s->check, q, n);
-+
-+ /* copy */
-+ zmemcpy(p, q, n);
-+ p += n;
-+ q += n;
-+ }
-+
-+ /* update pointers */
-+ z->next_out = p;
-+ s->read = q;
-+
-+ /* done */
-+ return r;
-+}
---- /dev/null Tue Mar 11 13:02:56 2003
-+++ linux/lib/zlib/infutil.h Mon Feb 9 13:51:03 2004
-@@ -0,0 +1,98 @@
-+/* infutil.h -- types and macros common to blocks and codes
-+ * Copyright (C) 1995-2002 Mark Adler
-+ * For conditions of distribution and use, see copyright notice in zlib.h
-+ */
-+
-+/* WARNING: this file should *not* be used by applications. It is
-+ part of the implementation of the compression library and is
-+ subject to change. Applications should only use zlib.h.
-+ */
-+
-+#ifndef _INFUTIL_H
-+#define _INFUTIL_H
-+
-+typedef enum {
-+ TYPE, /* get type bits (3, including end bit) */
-+ LENS, /* get lengths for stored */
-+ STORED, /* processing stored block */
-+ TABLE, /* get table lengths */
-+ BTREE, /* get bit lengths tree for a dynamic block */
-+ DTREE, /* get length, distance trees for a dynamic block */
-+ CODES, /* processing fixed or dynamic block */
-+ DRY, /* output remaining window bytes */
-+ DONE, /* finished last block, done */
-+ BAD} /* got a data error--stuck here */
-+inflate_block_mode;
-+
-+/* inflate blocks semi-private state */
-+struct inflate_blocks_state {
-+
-+ /* mode */
-+ inflate_block_mode mode; /* current inflate_block mode */
-+
-+ /* mode dependent information */
-+ union {
-+ uInt left; /* if STORED, bytes left to copy */
-+ struct {
-+ uInt table; /* table lengths (14 bits) */
-+ uInt index; /* index into blens (or border) */
-+ uIntf *blens; /* bit lengths of codes */
-+ uInt bb; /* bit length tree depth */
-+ inflate_huft *tb; /* bit length decoding tree */
-+ } trees; /* if DTREE, decoding info for trees */
-+ struct {
-+ inflate_codes_statef
-+ *codes;
-+ } decode; /* if CODES, current state */
-+ } sub; /* submode */
-+ uInt last; /* true if this block is the last block */
-+
-+ /* mode independent information */
-+ uInt bitk; /* bits in bit buffer */
-+ uLong bitb; /* bit buffer */
-+ inflate_huft *hufts; /* single malloc for tree space */
-+ Bytef *window; /* sliding window */
-+ Bytef *end; /* one byte after sliding window */
-+ Bytef *read; /* window read pointer */
-+ Bytef *write; /* window write pointer */
-+ check_func checkfn; /* check function */
-+ uLong check; /* check on output */
-+
-+};
-+
-+
-+/* defines for inflate input/output */
-+/* update pointers and return */
-+#define UPDBITS {s->bitb=b;s->bitk=k;}
-+#define UPDIN {z->avail_in=n;z->total_in+=p-z->next_in;z->next_in=p;}
-+#define UPDOUT {s->write=q;}
-+#define UPDATE {UPDBITS UPDIN UPDOUT}
-+#define LEAVE {UPDATE return inflate_flush(s,z,r);}
-+/* get bytes and bits */
-+#define LOADIN {p=z->next_in;n=z->avail_in;b=s->bitb;k=s->bitk;}
-+#define NEEDBYTE {if(n)r=Z_OK;else LEAVE}
-+#define NEXTBYTE (n--,*p++)
-+#define NEEDBITS(j) {while(k<(j)){NEEDBYTE;b|=((uLong)NEXTBYTE)<<k;k+=8;}}
-+#define DUMPBITS(j) {b>>=(j);k-=(j);}
-+/* output bytes */
-+#define WAVAIL (uInt)(q<s->read?s->read-q-1:s->end-q)
-+#define LOADOUT {q=s->write;m=(uInt)WAVAIL;}
-+#define WRAP {if(q==s->end&&s->read!=s->window){q=s->window;m=(uInt)WAVAIL;}}
-+#define FLUSH {UPDOUT r=inflate_flush(s,z,r); LOADOUT}
-+#define NEEDOUT {if(m==0){WRAP if(m==0){FLUSH WRAP if(m==0) LEAVE}}r=Z_OK;}
-+#define OUTBYTE(a) {*q++=(Byte)(a);m--;}
-+/* load local pointers */
-+#define LOAD {LOADIN LOADOUT}
-+
-+/* masks for lower bits (size given to avoid silly warnings with Visual C++) */
-+extern uInt inflate_mask[17];
-+
-+/* copy as much as possible from the sliding window to the output area */
-+extern int inflate_flush OF((
-+ inflate_blocks_statef *,
-+ z_streamp ,
-+ int));
-+
-+struct internal_state {int dummy;}; /* for buggy compilers */
-+
-+#endif /* _INFUTIL_H */
---- /dev/null Tue Mar 11 13:02:56 2003
-+++ linux/lib/zlib/match586.S Mon Feb 9 13:51:03 2004
-@@ -0,0 +1,357 @@
-+/* match.s -- Pentium-optimized version of longest_match()
-+ * Written for zlib 1.1.2
-+ * Copyright (C) 1998 Brian Raiter <breadbox@muppetlabs.com>
-+ *
-+ * This is free software; you can redistribute it and/or modify it
-+ * under the terms of the GNU General Public License.
-+ */
-+
-+#ifndef NO_UNDERLINE
-+#define match_init _ipcomp_match_init
-+#define longest_match _ipcomp_longest_match
-+#else
-+#define match_init ipcomp_match_init
-+#define longest_match ipcomp_longest_match
-+#endif
-+
-+#define MAX_MATCH (258)
-+#define MIN_MATCH (3)
-+#define MIN_LOOKAHEAD (MAX_MATCH + MIN_MATCH + 1)
-+#define MAX_MATCH_8 ((MAX_MATCH + 7) & ~7)
-+
-+/* stack frame offsets */
-+
-+#define wmask 0 /* local copy of s->wmask */
-+#define window 4 /* local copy of s->window */
-+#define windowbestlen 8 /* s->window + bestlen */
-+#define chainlenscanend 12 /* high word: current chain len */
-+ /* low word: last bytes sought */
-+#define scanstart 16 /* first two bytes of string */
-+#define scanalign 20 /* dword-misalignment of string */
-+#define nicematch 24 /* a good enough match size */
-+#define bestlen 28 /* size of best match so far */
-+#define scan 32 /* ptr to string wanting match */
-+
-+#define LocalVarsSize (36)
-+/* saved ebx 36 */
-+/* saved edi 40 */
-+/* saved esi 44 */
-+/* saved ebp 48 */
-+/* return address 52 */
-+#define deflatestate 56 /* the function arguments */
-+#define curmatch 60
-+
-+/* Offsets for fields in the deflate_state structure. These numbers
-+ * are calculated from the definition of deflate_state, with the
-+ * assumption that the compiler will dword-align the fields. (Thus,
-+ * changing the definition of deflate_state could easily cause this
-+ * program to crash horribly, without so much as a warning at
-+ * compile time. Sigh.)
-+ */
-+#define dsWSize 36
-+#define dsWMask 44
-+#define dsWindow 48
-+#define dsPrev 56
-+#define dsMatchLen 88
-+#define dsPrevMatch 92
-+#define dsStrStart 100
-+#define dsMatchStart 104
-+#define dsLookahead 108
-+#define dsPrevLen 112
-+#define dsMaxChainLen 116
-+#define dsGoodMatch 132
-+#define dsNiceMatch 136
-+
-+
-+.file "match.S"
-+
-+.globl match_init, longest_match
-+
-+.text
-+
-+/* uInt longest_match(deflate_state *deflatestate, IPos curmatch) */
-+
-+longest_match:
-+
-+/* Save registers that the compiler may be using, and adjust %esp to */
-+/* make room for our stack frame. */
-+
-+ pushl %ebp
-+ pushl %edi
-+ pushl %esi
-+ pushl %ebx
-+ subl $LocalVarsSize, %esp
-+
-+/* Retrieve the function arguments. %ecx will hold cur_match */
-+/* throughout the entire function. %edx will hold the pointer to the */
-+/* deflate_state structure during the function's setup (before */
-+/* entering the main loop). */
-+
-+ movl deflatestate(%esp), %edx
-+ movl curmatch(%esp), %ecx
-+
-+/* if ((uInt)nice_match > s->lookahead) nice_match = s->lookahead; */
-+
-+ movl dsNiceMatch(%edx), %eax
-+ movl dsLookahead(%edx), %ebx
-+ cmpl %eax, %ebx
-+ jl LookaheadLess
-+ movl %eax, %ebx
-+LookaheadLess: movl %ebx, nicematch(%esp)
-+
-+/* register Bytef *scan = s->window + s->strstart; */
-+
-+ movl dsWindow(%edx), %esi
-+ movl %esi, window(%esp)
-+ movl dsStrStart(%edx), %ebp
-+ lea (%esi,%ebp), %edi
-+ movl %edi, scan(%esp)
-+
-+/* Determine how many bytes the scan ptr is off from being */
-+/* dword-aligned. */
-+
-+ movl %edi, %eax
-+ negl %eax
-+ andl $3, %eax
-+ movl %eax, scanalign(%esp)
-+
-+/* IPos limit = s->strstart > (IPos)MAX_DIST(s) ? */
-+/* s->strstart - (IPos)MAX_DIST(s) : NIL; */
-+
-+ movl dsWSize(%edx), %eax
-+ subl $MIN_LOOKAHEAD, %eax
-+ subl %eax, %ebp
-+ jg LimitPositive
-+ xorl %ebp, %ebp
-+LimitPositive:
-+
-+/* unsigned chain_length = s->max_chain_length; */
-+/* if (s->prev_length >= s->good_match) { */
-+/* chain_length >>= 2; */
-+/* } */
-+
-+ movl dsPrevLen(%edx), %eax
-+ movl dsGoodMatch(%edx), %ebx
-+ cmpl %ebx, %eax
-+ movl dsMaxChainLen(%edx), %ebx
-+ jl LastMatchGood
-+ shrl $2, %ebx
-+LastMatchGood:
-+
-+/* chainlen is decremented once beforehand so that the function can */
-+/* use the sign flag instead of the zero flag for the exit test. */
-+/* It is then shifted into the high word, to make room for the scanend */
-+/* scanend value, which it will always accompany. */
-+
-+ decl %ebx
-+ shll $16, %ebx
-+
-+/* int best_len = s->prev_length; */
-+
-+ movl dsPrevLen(%edx), %eax
-+ movl %eax, bestlen(%esp)
-+
-+/* Store the sum of s->window + best_len in %esi locally, and in %esi. */
-+
-+ addl %eax, %esi
-+ movl %esi, windowbestlen(%esp)
-+
-+/* register ush scan_start = *(ushf*)scan; */
-+/* register ush scan_end = *(ushf*)(scan+best_len-1); */
-+
-+ movw (%edi), %bx
-+ movw %bx, scanstart(%esp)
-+ movw -1(%edi,%eax), %bx
-+ movl %ebx, chainlenscanend(%esp)
-+
-+/* Posf *prev = s->prev; */
-+/* uInt wmask = s->w_mask; */
-+
-+ movl dsPrev(%edx), %edi
-+ movl dsWMask(%edx), %edx
-+ mov %edx, wmask(%esp)
-+
-+/* Jump into the main loop. */
-+
-+ jmp LoopEntry
-+
-+.balign 16
-+
-+/* do {
-+ * match = s->window + cur_match;
-+ * if (*(ushf*)(match+best_len-1) != scan_end ||
-+ * *(ushf*)match != scan_start) continue;
-+ * [...]
-+ * } while ((cur_match = prev[cur_match & wmask]) > limit
-+ * && --chain_length != 0);
-+ *
-+ * Here is the inner loop of the function. The function will spend the
-+ * majority of its time in this loop, and majority of that time will
-+ * be spent in the first ten instructions.
-+ *
-+ * Within this loop:
-+ * %ebx = chainlenscanend - i.e., ((chainlen << 16) | scanend)
-+ * %ecx = curmatch
-+ * %edx = curmatch & wmask
-+ * %esi = windowbestlen - i.e., (window + bestlen)
-+ * %edi = prev
-+ * %ebp = limit
-+ *
-+ * Two optimization notes on the choice of instructions:
-+ *
-+ * The first instruction uses a 16-bit address, which costs an extra,
-+ * unpairable cycle. This is cheaper than doing a 32-bit access and
-+ * zeroing the high word, due to the 3-cycle misalignment penalty which
-+ * would occur half the time. This also turns out to be cheaper than
-+ * doing two separate 8-bit accesses, as the memory is so rarely in the
-+ * L1 cache.
-+ *
-+ * The window buffer, however, apparently spends a lot of time in the
-+ * cache, and so it is faster to retrieve the word at the end of the
-+ * match string with two 8-bit loads. The instructions that test the
-+ * word at the beginning of the match string, however, are executed
-+ * much less frequently, and there it was cheaper to use 16-bit
-+ * instructions, which avoided the necessity of saving off and
-+ * subsequently reloading one of the other registers.
-+ */
-+LookupLoop:
-+ /* 1 U & V */
-+ movw (%edi,%edx,2), %cx /* 2 U pipe */
-+ movl wmask(%esp), %edx /* 2 V pipe */
-+ cmpl %ebp, %ecx /* 3 U pipe */
-+ jbe LeaveNow /* 3 V pipe */
-+ subl $0x00010000, %ebx /* 4 U pipe */
-+ js LeaveNow /* 4 V pipe */
-+LoopEntry: movb -1(%esi,%ecx), %al /* 5 U pipe */
-+ andl %ecx, %edx /* 5 V pipe */
-+ cmpb %bl, %al /* 6 U pipe */
-+ jnz LookupLoop /* 6 V pipe */
-+ movb (%esi,%ecx), %ah
-+ cmpb %bh, %ah
-+ jnz LookupLoop
-+ movl window(%esp), %eax
-+ movw (%eax,%ecx), %ax
-+ cmpw scanstart(%esp), %ax
-+ jnz LookupLoop
-+
-+/* Store the current value of chainlen. */
-+
-+ movl %ebx, chainlenscanend(%esp)
-+
-+/* Point %edi to the string under scrutiny, and %esi to the string we */
-+/* are hoping to match it up with. In actuality, %esi and %edi are */
-+/* both pointed (MAX_MATCH_8 - scanalign) bytes ahead, and %edx is */
-+/* initialized to -(MAX_MATCH_8 - scanalign). */
-+
-+ movl window(%esp), %esi
-+ movl scan(%esp), %edi
-+ addl %ecx, %esi
-+ movl scanalign(%esp), %eax
-+ movl $(-MAX_MATCH_8), %edx
-+ lea MAX_MATCH_8(%edi,%eax), %edi
-+ lea MAX_MATCH_8(%esi,%eax), %esi
-+
-+/* Test the strings for equality, 8 bytes at a time. At the end,
-+ * adjust %edx so that it is offset to the exact byte that mismatched.
-+ *
-+ * We already know at this point that the first three bytes of the
-+ * strings match each other, and they can be safely passed over before
-+ * starting the compare loop. So what this code does is skip over 0-3
-+ * bytes, as much as necessary in order to dword-align the %edi
-+ * pointer. (%esi will still be misaligned three times out of four.)
-+ *
-+ * It should be confessed that this loop usually does not represent
-+ * much of the total running time. Replacing it with a more
-+ * straightforward "rep cmpsb" would not drastically degrade
-+ * performance.
-+ */
-+LoopCmps:
-+ movl (%esi,%edx), %eax
-+ movl (%edi,%edx), %ebx
-+ xorl %ebx, %eax
-+ jnz LeaveLoopCmps
-+ movl 4(%esi,%edx), %eax
-+ movl 4(%edi,%edx), %ebx
-+ xorl %ebx, %eax
-+ jnz LeaveLoopCmps4
-+ addl $8, %edx
-+ jnz LoopCmps
-+ jmp LenMaximum
-+LeaveLoopCmps4: addl $4, %edx
-+LeaveLoopCmps: testl $0x0000FFFF, %eax
-+ jnz LenLower
-+ addl $2, %edx
-+ shrl $16, %eax
-+LenLower: subb $1, %al
-+ adcl $0, %edx
-+
-+/* Calculate the length of the match. If it is longer than MAX_MATCH, */
-+/* then automatically accept it as the best possible match and leave. */
-+
-+ lea (%edi,%edx), %eax
-+ movl scan(%esp), %edi
-+ subl %edi, %eax
-+ cmpl $MAX_MATCH, %eax
-+ jge LenMaximum
-+
-+/* If the length of the match is not longer than the best match we */
-+/* have so far, then forget it and return to the lookup loop. */
-+
-+ movl deflatestate(%esp), %edx
-+ movl bestlen(%esp), %ebx
-+ cmpl %ebx, %eax
-+ jg LongerMatch
-+ movl chainlenscanend(%esp), %ebx
-+ movl windowbestlen(%esp), %esi
-+ movl dsPrev(%edx), %edi
-+ movl wmask(%esp), %edx
-+ andl %ecx, %edx
-+ jmp LookupLoop
-+
-+/* s->match_start = cur_match; */
-+/* best_len = len; */
-+/* if (len >= nice_match) break; */
-+/* scan_end = *(ushf*)(scan+best_len-1); */
-+
-+LongerMatch: movl nicematch(%esp), %ebx
-+ movl %eax, bestlen(%esp)
-+ movl %ecx, dsMatchStart(%edx)
-+ cmpl %ebx, %eax
-+ jge LeaveNow
-+ movl window(%esp), %esi
-+ addl %eax, %esi
-+ movl %esi, windowbestlen(%esp)
-+ movl chainlenscanend(%esp), %ebx
-+ movw -1(%edi,%eax), %bx
-+ movl dsPrev(%edx), %edi
-+ movl %ebx, chainlenscanend(%esp)
-+ movl wmask(%esp), %edx
-+ andl %ecx, %edx
-+ jmp LookupLoop
-+
-+/* Accept the current string, with the maximum possible length. */
-+
-+LenMaximum: movl deflatestate(%esp), %edx
-+ movl $MAX_MATCH, bestlen(%esp)
-+ movl %ecx, dsMatchStart(%edx)
-+
-+/* if ((uInt)best_len <= s->lookahead) return (uInt)best_len; */
-+/* return s->lookahead; */
-+
-+LeaveNow:
-+ movl deflatestate(%esp), %edx
-+ movl bestlen(%esp), %ebx
-+ movl dsLookahead(%edx), %eax
-+ cmpl %eax, %ebx
-+ jg LookaheadRet
-+ movl %ebx, %eax
-+LookaheadRet:
-+
-+/* Restore the stack and return from whence we came. */
-+
-+ addl $LocalVarsSize, %esp
-+ popl %ebx
-+ popl %esi
-+ popl %edi
-+ popl %ebp
-+match_init: ret
---- /dev/null Tue Mar 11 13:02:56 2003
-+++ linux/lib/zlib/match686.S Mon Feb 9 13:51:03 2004
-@@ -0,0 +1,330 @@
-+/* match.s -- Pentium-Pro-optimized version of longest_match()
-+ * Written for zlib 1.1.2
-+ * Copyright (C) 1998 Brian Raiter <breadbox@muppetlabs.com>
-+ *
-+ * This is free software; you can redistribute it and/or modify it
-+ * under the terms of the GNU General Public License.
-+ */
-+
-+#ifndef NO_UNDERLINE
-+#define match_init _ipcomp_match_init
-+#define longest_match _ipcomp_longest_match
-+#else
-+#define match_init ipcomp_match_init
-+#define longest_match ipcomp_longest_match
-+#endif
-+
-+#define MAX_MATCH (258)
-+#define MIN_MATCH (3)
-+#define MIN_LOOKAHEAD (MAX_MATCH + MIN_MATCH + 1)
-+#define MAX_MATCH_8 ((MAX_MATCH + 7) & ~7)
-+
-+/* stack frame offsets */
-+
-+#define chainlenwmask 0 /* high word: current chain len */
-+ /* low word: s->wmask */
-+#define window 4 /* local copy of s->window */
-+#define windowbestlen 8 /* s->window + bestlen */
-+#define scanstart 16 /* first two bytes of string */
-+#define scanend 12 /* last two bytes of string */
-+#define scanalign 20 /* dword-misalignment of string */
-+#define nicematch 24 /* a good enough match size */
-+#define bestlen 28 /* size of best match so far */
-+#define scan 32 /* ptr to string wanting match */
-+
-+#define LocalVarsSize (36)
-+/* saved ebx 36 */
-+/* saved edi 40 */
-+/* saved esi 44 */
-+/* saved ebp 48 */
-+/* return address 52 */
-+#define deflatestate 56 /* the function arguments */
-+#define curmatch 60
-+
-+/* Offsets for fields in the deflate_state structure. These numbers
-+ * are calculated from the definition of deflate_state, with the
-+ * assumption that the compiler will dword-align the fields. (Thus,
-+ * changing the definition of deflate_state could easily cause this
-+ * program to crash horribly, without so much as a warning at
-+ * compile time. Sigh.)
-+ */
-+#define dsWSize 36
-+#define dsWMask 44
-+#define dsWindow 48
-+#define dsPrev 56
-+#define dsMatchLen 88
-+#define dsPrevMatch 92
-+#define dsStrStart 100
-+#define dsMatchStart 104
-+#define dsLookahead 108
-+#define dsPrevLen 112
-+#define dsMaxChainLen 116
-+#define dsGoodMatch 132
-+#define dsNiceMatch 136
-+
-+
-+.file "match.S"
-+
-+.globl match_init, longest_match
-+
-+.text
-+
-+/* uInt longest_match(deflate_state *deflatestate, IPos curmatch) */
-+
-+longest_match:
-+
-+/* Save registers that the compiler may be using, and adjust %esp to */
-+/* make room for our stack frame. */
-+
-+ pushl %ebp
-+ pushl %edi
-+ pushl %esi
-+ pushl %ebx
-+ subl $LocalVarsSize, %esp
-+
-+/* Retrieve the function arguments. %ecx will hold cur_match */
-+/* throughout the entire function. %edx will hold the pointer to the */
-+/* deflate_state structure during the function's setup (before */
-+/* entering the main loop). */
-+
-+ movl deflatestate(%esp), %edx
-+ movl curmatch(%esp), %ecx
-+
-+/* uInt wmask = s->w_mask; */
-+/* unsigned chain_length = s->max_chain_length; */
-+/* if (s->prev_length >= s->good_match) { */
-+/* chain_length >>= 2; */
-+/* } */
-+
-+ movl dsPrevLen(%edx), %eax
-+ movl dsGoodMatch(%edx), %ebx
-+ cmpl %ebx, %eax
-+ movl dsWMask(%edx), %eax
-+ movl dsMaxChainLen(%edx), %ebx
-+ jl LastMatchGood
-+ shrl $2, %ebx
-+LastMatchGood:
-+
-+/* chainlen is decremented once beforehand so that the function can */
-+/* use the sign flag instead of the zero flag for the exit test. */
-+/* It is then shifted into the high word, to make room for the wmask */
-+/* value, which it will always accompany. */
-+
-+ decl %ebx
-+ shll $16, %ebx
-+ orl %eax, %ebx
-+ movl %ebx, chainlenwmask(%esp)
-+
-+/* if ((uInt)nice_match > s->lookahead) nice_match = s->lookahead; */
-+
-+ movl dsNiceMatch(%edx), %eax
-+ movl dsLookahead(%edx), %ebx
-+ cmpl %eax, %ebx
-+ jl LookaheadLess
-+ movl %eax, %ebx
-+LookaheadLess: movl %ebx, nicematch(%esp)
-+
-+/* register Bytef *scan = s->window + s->strstart; */
-+
-+ movl dsWindow(%edx), %esi
-+ movl %esi, window(%esp)
-+ movl dsStrStart(%edx), %ebp
-+ lea (%esi,%ebp), %edi
-+ movl %edi, scan(%esp)
-+
-+/* Determine how many bytes the scan ptr is off from being */
-+/* dword-aligned. */
-+
-+ movl %edi, %eax
-+ negl %eax
-+ andl $3, %eax
-+ movl %eax, scanalign(%esp)
-+
-+/* IPos limit = s->strstart > (IPos)MAX_DIST(s) ? */
-+/* s->strstart - (IPos)MAX_DIST(s) : NIL; */
-+
-+ movl dsWSize(%edx), %eax
-+ subl $MIN_LOOKAHEAD, %eax
-+ subl %eax, %ebp
-+ jg LimitPositive
-+ xorl %ebp, %ebp
-+LimitPositive:
-+
-+/* int best_len = s->prev_length; */
-+
-+ movl dsPrevLen(%edx), %eax
-+ movl %eax, bestlen(%esp)
-+
-+/* Store the sum of s->window + best_len in %esi locally, and in %esi. */
-+
-+ addl %eax, %esi
-+ movl %esi, windowbestlen(%esp)
-+
-+/* register ush scan_start = *(ushf*)scan; */
-+/* register ush scan_end = *(ushf*)(scan+best_len-1); */
-+/* Posf *prev = s->prev; */
-+
-+ movzwl (%edi), %ebx
-+ movl %ebx, scanstart(%esp)
-+ movzwl -1(%edi,%eax), %ebx
-+ movl %ebx, scanend(%esp)
-+ movl dsPrev(%edx), %edi
-+
-+/* Jump into the main loop. */
-+
-+ movl chainlenwmask(%esp), %edx
-+ jmp LoopEntry
-+
-+.balign 16
-+
-+/* do {
-+ * match = s->window + cur_match;
-+ * if (*(ushf*)(match+best_len-1) != scan_end ||
-+ * *(ushf*)match != scan_start) continue;
-+ * [...]
-+ * } while ((cur_match = prev[cur_match & wmask]) > limit
-+ * && --chain_length != 0);
-+ *
-+ * Here is the inner loop of the function. The function will spend the
-+ * majority of its time in this loop, and majority of that time will
-+ * be spent in the first ten instructions.
-+ *
-+ * Within this loop:
-+ * %ebx = scanend
-+ * %ecx = curmatch
-+ * %edx = chainlenwmask - i.e., ((chainlen << 16) | wmask)
-+ * %esi = windowbestlen - i.e., (window + bestlen)
-+ * %edi = prev
-+ * %ebp = limit
-+ */
-+LookupLoop:
-+ andl %edx, %ecx
-+ movzwl (%edi,%ecx,2), %ecx
-+ cmpl %ebp, %ecx
-+ jbe LeaveNow
-+ subl $0x00010000, %edx
-+ js LeaveNow
-+LoopEntry: movzwl -1(%esi,%ecx), %eax
-+ cmpl %ebx, %eax
-+ jnz LookupLoop
-+ movl window(%esp), %eax
-+ movzwl (%eax,%ecx), %eax
-+ cmpl scanstart(%esp), %eax
-+ jnz LookupLoop
-+
-+/* Store the current value of chainlen. */
-+
-+ movl %edx, chainlenwmask(%esp)
-+
-+/* Point %edi to the string under scrutiny, and %esi to the string we */
-+/* are hoping to match it up with. In actuality, %esi and %edi are */
-+/* both pointed (MAX_MATCH_8 - scanalign) bytes ahead, and %edx is */
-+/* initialized to -(MAX_MATCH_8 - scanalign). */
-+
-+ movl window(%esp), %esi
-+ movl scan(%esp), %edi
-+ addl %ecx, %esi
-+ movl scanalign(%esp), %eax
-+ movl $(-MAX_MATCH_8), %edx
-+ lea MAX_MATCH_8(%edi,%eax), %edi
-+ lea MAX_MATCH_8(%esi,%eax), %esi
-+
-+/* Test the strings for equality, 8 bytes at a time. At the end,
-+ * adjust %edx so that it is offset to the exact byte that mismatched.
-+ *
-+ * We already know at this point that the first three bytes of the
-+ * strings match each other, and they can be safely passed over before
-+ * starting the compare loop. So what this code does is skip over 0-3
-+ * bytes, as much as necessary in order to dword-align the %edi
-+ * pointer. (%esi will still be misaligned three times out of four.)
-+ *
-+ * It should be confessed that this loop usually does not represent
-+ * much of the total running time. Replacing it with a more
-+ * straightforward "rep cmpsb" would not drastically degrade
-+ * performance.
-+ */
-+LoopCmps:
-+ movl (%esi,%edx), %eax
-+ xorl (%edi,%edx), %eax
-+ jnz LeaveLoopCmps
-+ movl 4(%esi,%edx), %eax
-+ xorl 4(%edi,%edx), %eax
-+ jnz LeaveLoopCmps4
-+ addl $8, %edx
-+ jnz LoopCmps
-+ jmp LenMaximum
-+LeaveLoopCmps4: addl $4, %edx
-+LeaveLoopCmps: testl $0x0000FFFF, %eax
-+ jnz LenLower
-+ addl $2, %edx
-+ shrl $16, %eax
-+LenLower: subb $1, %al
-+ adcl $0, %edx
-+
-+/* Calculate the length of the match. If it is longer than MAX_MATCH, */
-+/* then automatically accept it as the best possible match and leave. */
-+
-+ lea (%edi,%edx), %eax
-+ movl scan(%esp), %edi
-+ subl %edi, %eax
-+ cmpl $MAX_MATCH, %eax
-+ jge LenMaximum
-+
-+/* If the length of the match is not longer than the best match we */
-+/* have so far, then forget it and return to the lookup loop. */
-+
-+ movl deflatestate(%esp), %edx
-+ movl bestlen(%esp), %ebx
-+ cmpl %ebx, %eax
-+ jg LongerMatch
-+ movl windowbestlen(%esp), %esi
-+ movl dsPrev(%edx), %edi
-+ movl scanend(%esp), %ebx
-+ movl chainlenwmask(%esp), %edx
-+ jmp LookupLoop
-+
-+/* s->match_start = cur_match; */
-+/* best_len = len; */
-+/* if (len >= nice_match) break; */
-+/* scan_end = *(ushf*)(scan+best_len-1); */
-+
-+LongerMatch: movl nicematch(%esp), %ebx
-+ movl %eax, bestlen(%esp)
-+ movl %ecx, dsMatchStart(%edx)
-+ cmpl %ebx, %eax
-+ jge LeaveNow
-+ movl window(%esp), %esi
-+ addl %eax, %esi
-+ movl %esi, windowbestlen(%esp)
-+ movzwl -1(%edi,%eax), %ebx
-+ movl dsPrev(%edx), %edi
-+ movl %ebx, scanend(%esp)
-+ movl chainlenwmask(%esp), %edx
-+ jmp LookupLoop
-+
-+/* Accept the current string, with the maximum possible length. */
-+
-+LenMaximum: movl deflatestate(%esp), %edx
-+ movl $MAX_MATCH, bestlen(%esp)
-+ movl %ecx, dsMatchStart(%edx)
-+
-+/* if ((uInt)best_len <= s->lookahead) return (uInt)best_len; */
-+/* return s->lookahead; */
-+
-+LeaveNow:
-+ movl deflatestate(%esp), %edx
-+ movl bestlen(%esp), %ebx
-+ movl dsLookahead(%edx), %eax
-+ cmpl %eax, %ebx
-+ jg LookaheadRet
-+ movl %ebx, %eax
-+LookaheadRet:
-+
-+/* Restore the stack and return from whence we came. */
-+
-+ addl $LocalVarsSize, %esp
-+ popl %ebx
-+ popl %esi
-+ popl %edi
-+ popl %ebp
-+match_init: ret
---- /dev/null Tue Mar 11 13:02:56 2003
-+++ linux/lib/zlib/trees.c Mon Feb 9 13:51:03 2004
-@@ -0,0 +1,1214 @@
-+/* trees.c -- output deflated data using Huffman coding
-+ * Copyright (C) 1995-2002 Jean-loup Gailly
-+ * For conditions of distribution and use, see copyright notice in zlib.h
-+ */
-+
-+/*
-+ * ALGORITHM
-+ *
-+ * The "deflation" process uses several Huffman trees. The more
-+ * common source values are represented by shorter bit sequences.
-+ *
-+ * Each code tree is stored in a compressed form which is itself
-+ * a Huffman encoding of the lengths of all the code strings (in
-+ * ascending order by source values). The actual code strings are
-+ * reconstructed from the lengths in the inflate process, as described
-+ * in the deflate specification.
-+ *
-+ * REFERENCES
-+ *
-+ * Deutsch, L.P.,"'Deflate' Compressed Data Format Specification".
-+ * Available in ftp.uu.net:/pub/archiving/zip/doc/deflate-1.1.doc
-+ *
-+ * Storer, James A.
-+ * Data Compression: Methods and Theory, pp. 49-50.
-+ * Computer Science Press, 1988. ISBN 0-7167-8156-5.
-+ *
-+ * Sedgewick, R.
-+ * Algorithms, p290.
-+ * Addison-Wesley, 1983. ISBN 0-201-06672-6.
-+ */
-+
-+/* @(#) $Id: trees.c,v 1.3 2002/04/24 07:36:45 mcr Exp $ */
-+
-+/* #define GEN_TREES_H */
-+
-+#include "deflate.h"
-+
-+#ifdef DEBUG
-+# include <ctype.h>
-+#endif
-+
-+/* ===========================================================================
-+ * Constants
-+ */
-+
-+#define MAX_BL_BITS 7
-+/* Bit length codes must not exceed MAX_BL_BITS bits */
-+
-+#define END_BLOCK 256
-+/* end of block literal code */
-+
-+#define REP_3_6 16
-+/* repeat previous bit length 3-6 times (2 bits of repeat count) */
-+
-+#define REPZ_3_10 17
-+/* repeat a zero length 3-10 times (3 bits of repeat count) */
-+
-+#define REPZ_11_138 18
-+/* repeat a zero length 11-138 times (7 bits of repeat count) */
-+
-+local const int extra_lbits[LENGTH_CODES] /* extra bits for each length code */
-+ = {0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0};
-+
-+local const int extra_dbits[D_CODES] /* extra bits for each distance code */
-+ = {0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13};
-+
-+local const int extra_blbits[BL_CODES]/* extra bits for each bit length code */
-+ = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7};
-+
-+local const uch bl_order[BL_CODES]
-+ = {16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15};
-+/* The lengths of the bit length codes are sent in order of decreasing
-+ * probability, to avoid transmitting the lengths for unused bit length codes.
-+ */
-+
-+#define Buf_size (8 * 2*sizeof(char))
-+/* Number of bits used within bi_buf. (bi_buf might be implemented on
-+ * more than 16 bits on some systems.)
-+ */
-+
-+/* ===========================================================================
-+ * Local data. These are initialized only once.
-+ */
-+
-+#define DIST_CODE_LEN 512 /* see definition of array dist_code below */
-+
-+#if defined(GEN_TREES_H) || !defined(STDC)
-+/* non ANSI compilers may not accept trees.h */
-+
-+local ct_data static_ltree[L_CODES+2];
-+/* The static literal tree. Since the bit lengths are imposed, there is no
-+ * need for the L_CODES extra codes used during heap construction. However
-+ * The codes 286 and 287 are needed to build a canonical tree (see _tr_init
-+ * below).
-+ */
-+
-+local ct_data static_dtree[D_CODES];
-+/* The static distance tree. (Actually a trivial tree since all codes use
-+ * 5 bits.)
-+ */
-+
-+uch _dist_code[DIST_CODE_LEN];
-+/* Distance codes. The first 256 values correspond to the distances
-+ * 3 .. 258, the last 256 values correspond to the top 8 bits of
-+ * the 15 bit distances.
-+ */
-+
-+uch _length_code[MAX_MATCH-MIN_MATCH+1];
-+/* length code for each normalized match length (0 == MIN_MATCH) */
-+
-+local int base_length[LENGTH_CODES];
-+/* First normalized length for each code (0 = MIN_MATCH) */
-+
-+local int base_dist[D_CODES];
-+/* First normalized distance for each code (0 = distance of 1) */
-+
-+#else
-+# include "trees.h"
-+#endif /* GEN_TREES_H */
-+
-+struct static_tree_desc_s {
-+ const ct_data *static_tree; /* static tree or NULL */
-+ const intf *extra_bits; /* extra bits for each code or NULL */
-+ int extra_base; /* base index for extra_bits */
-+ int elems; /* max number of elements in the tree */
-+ int max_length; /* max bit length for the codes */
-+};
-+
-+local static_tree_desc static_l_desc =
-+{static_ltree, extra_lbits, LITERALS+1, L_CODES, MAX_BITS};
-+
-+local static_tree_desc static_d_desc =
-+{static_dtree, extra_dbits, 0, D_CODES, MAX_BITS};
-+
-+local static_tree_desc static_bl_desc =
-+{(const ct_data *)0, extra_blbits, 0, BL_CODES, MAX_BL_BITS};
-+
-+/* ===========================================================================
-+ * Local (static) routines in this file.
-+ */
-+
-+local void tr_static_init OF((void));
-+local void init_block OF((deflate_state *s));
-+local void pqdownheap OF((deflate_state *s, ct_data *tree, int k));
-+local void gen_bitlen OF((deflate_state *s, tree_desc *desc));
-+local void gen_codes OF((ct_data *tree, int max_code, ushf *bl_count));
-+local void build_tree OF((deflate_state *s, tree_desc *desc));
-+local void scan_tree OF((deflate_state *s, ct_data *tree, int max_code));
-+local void send_tree OF((deflate_state *s, ct_data *tree, int max_code));
-+local int build_bl_tree OF((deflate_state *s));
-+local void send_all_trees OF((deflate_state *s, int lcodes, int dcodes,
-+ int blcodes));
-+local void compress_block OF((deflate_state *s, const ct_data *ltree,
-+ const ct_data *dtree));
-+local void set_data_type OF((deflate_state *s));
-+local unsigned bi_reverse OF((unsigned value, int length));
-+local void bi_windup OF((deflate_state *s));
-+local void bi_flush OF((deflate_state *s));
-+local void copy_block OF((deflate_state *s, charf *buf, unsigned len,
-+ int header));
-+
-+#ifdef GEN_TREES_H
-+local void gen_trees_header OF((void));
-+#endif
-+
-+#ifndef DEBUG
-+# define send_code(s, c, tree) send_bits(s, tree[c].Code, tree[c].Len)
-+ /* Send a code of the given tree. c and tree must not have side effects */
-+
-+#else /* DEBUG */
-+# define send_code(s, c, tree) \
-+ { if (z_verbose>2) fprintf(stderr,"\ncd %3d ",(c)); \
-+ send_bits(s, tree[c].Code, tree[c].Len); }
-+#endif
-+
-+/* ===========================================================================
-+ * Output a short LSB first on the stream.
-+ * IN assertion: there is enough room in pendingBuf.
-+ */
-+#define put_short(s, w) { \
-+ put_byte(s, (uch)((w) & 0xff)); \
-+ put_byte(s, (uch)((ush)(w) >> 8)); \
-+}
-+
-+/* ===========================================================================
-+ * Send a value on a given number of bits.
-+ * IN assertion: length <= 16 and value fits in length bits.
-+ */
-+#ifdef DEBUG
-+local void send_bits OF((deflate_state *s, int value, int length));
-+
-+local void send_bits(s, value, length)
-+ deflate_state *s;
-+ int value; /* value to send */
-+ int length; /* number of bits */
-+{
-+ Tracevv((stderr," l %2d v %4x ", length, value));
-+ Assert(length > 0 && length <= 15, "invalid length");
-+ s->bits_sent += (ulg)length;
-+
-+ /* If not enough room in bi_buf, use (valid) bits from bi_buf and
-+ * (16 - bi_valid) bits from value, leaving (width - (16-bi_valid))
-+ * unused bits in value.
-+ */
-+ if (s->bi_valid > (int)Buf_size - length) {
-+ s->bi_buf |= (value << s->bi_valid);
-+ put_short(s, s->bi_buf);
-+ s->bi_buf = (ush)value >> (Buf_size - s->bi_valid);
-+ s->bi_valid += length - Buf_size;
-+ } else {
-+ s->bi_buf |= value << s->bi_valid;
-+ s->bi_valid += length;
-+ }
-+}
-+#else /* !DEBUG */
-+
-+#define send_bits(s, value, length) \
-+{ int len = length;\
-+ if (s->bi_valid > (int)Buf_size - len) {\
-+ int val = value;\
-+ s->bi_buf |= (val << s->bi_valid);\
-+ put_short(s, s->bi_buf);\
-+ s->bi_buf = (ush)val >> (Buf_size - s->bi_valid);\
-+ s->bi_valid += len - Buf_size;\
-+ } else {\
-+ s->bi_buf |= (value) << s->bi_valid;\
-+ s->bi_valid += len;\
-+ }\
-+}
-+#endif /* DEBUG */
-+
-+
-+#define MAX(a,b) (a >= b ? a : b)
-+/* the arguments must not have side effects */
-+
-+/* ===========================================================================
-+ * Initialize the various 'constant' tables.
-+ */
-+local void tr_static_init()
-+{
-+#if defined(GEN_TREES_H) || !defined(STDC)
-+ static int static_init_done = 0;
-+ int n; /* iterates over tree elements */
-+ int bits; /* bit counter */
-+ int length; /* length value */
-+ int code; /* code value */
-+ int dist; /* distance index */
-+ ush bl_count[MAX_BITS+1];
-+ /* number of codes at each bit length for an optimal tree */
-+
-+ if (static_init_done) return;
-+
-+ /* For some embedded targets, global variables are not initialized: */
-+ static_l_desc.static_tree = static_ltree;
-+ static_l_desc.extra_bits = extra_lbits;
-+ static_d_desc.static_tree = static_dtree;
-+ static_d_desc.extra_bits = extra_dbits;
-+ static_bl_desc.extra_bits = extra_blbits;
-+
-+ /* Initialize the mapping length (0..255) -> length code (0..28) */
-+ length = 0;
-+ for (code = 0; code < LENGTH_CODES-1; code++) {
-+ base_length[code] = length;
-+ for (n = 0; n < (1<<extra_lbits[code]); n++) {
-+ _length_code[length++] = (uch)code;
-+ }
-+ }
-+ Assert (length == 256, "tr_static_init: length != 256");
-+ /* Note that the length 255 (match length 258) can be represented
-+ * in two different ways: code 284 + 5 bits or code 285, so we
-+ * overwrite length_code[255] to use the best encoding:
-+ */
-+ _length_code[length-1] = (uch)code;
-+
-+ /* Initialize the mapping dist (0..32K) -> dist code (0..29) */
-+ dist = 0;
-+ for (code = 0 ; code < 16; code++) {
-+ base_dist[code] = dist;
-+ for (n = 0; n < (1<<extra_dbits[code]); n++) {
-+ _dist_code[dist++] = (uch)code;
-+ }
-+ }
-+ Assert (dist == 256, "tr_static_init: dist != 256");
-+ dist >>= 7; /* from now on, all distances are divided by 128 */
-+ for ( ; code < D_CODES; code++) {
-+ base_dist[code] = dist << 7;
-+ for (n = 0; n < (1<<(extra_dbits[code]-7)); n++) {
-+ _dist_code[256 + dist++] = (uch)code;
-+ }
-+ }
-+ Assert (dist == 256, "tr_static_init: 256+dist != 512");
-+
-+ /* Construct the codes of the static literal tree */
-+ for (bits = 0; bits <= MAX_BITS; bits++) bl_count[bits] = 0;
-+ n = 0;
-+ while (n <= 143) static_ltree[n++].Len = 8, bl_count[8]++;
-+ while (n <= 255) static_ltree[n++].Len = 9, bl_count[9]++;
-+ while (n <= 279) static_ltree[n++].Len = 7, bl_count[7]++;
-+ while (n <= 287) static_ltree[n++].Len = 8, bl_count[8]++;
-+ /* Codes 286 and 287 do not exist, but we must include them in the
-+ * tree construction to get a canonical Huffman tree (longest code
-+ * all ones)
-+ */
-+ gen_codes((ct_data *)static_ltree, L_CODES+1, bl_count);
-+
-+ /* The static distance tree is trivial: */
-+ for (n = 0; n < D_CODES; n++) {
-+ static_dtree[n].Len = 5;
-+ static_dtree[n].Code = bi_reverse((unsigned)n, 5);
-+ }
-+ static_init_done = 1;
-+
-+# ifdef GEN_TREES_H
-+ gen_trees_header();
-+# endif
-+#endif /* defined(GEN_TREES_H) || !defined(STDC) */
-+}
-+
-+/* ===========================================================================
-+ * Genererate the file trees.h describing the static trees.
-+ */
-+#ifdef GEN_TREES_H
-+# ifndef DEBUG
-+# include <stdio.h>
-+# endif
-+
-+# define SEPARATOR(i, last, width) \
-+ ((i) == (last)? "\n};\n\n" : \
-+ ((i) % (width) == (width)-1 ? ",\n" : ", "))
-+
-+void gen_trees_header()
-+{
-+ FILE *header = fopen("trees.h", "w");
-+ int i;
-+
-+ Assert (header != NULL, "Can't open trees.h");
-+ fprintf(header,
-+ "/* header created automatically with -DGEN_TREES_H */\n\n");
-+
-+ fprintf(header, "local const ct_data static_ltree[L_CODES+2] = {\n");
-+ for (i = 0; i < L_CODES+2; i++) {
-+ fprintf(header, "{{%3u},{%3u}}%s", static_ltree[i].Code,
-+ static_ltree[i].Len, SEPARATOR(i, L_CODES+1, 5));
-+ }
-+
-+ fprintf(header, "local const ct_data static_dtree[D_CODES] = {\n");
-+ for (i = 0; i < D_CODES; i++) {
-+ fprintf(header, "{{%2u},{%2u}}%s", static_dtree[i].Code,
-+ static_dtree[i].Len, SEPARATOR(i, D_CODES-1, 5));
-+ }
-+
-+ fprintf(header, "const uch _dist_code[DIST_CODE_LEN] = {\n");
-+ for (i = 0; i < DIST_CODE_LEN; i++) {
-+ fprintf(header, "%2u%s", _dist_code[i],
-+ SEPARATOR(i, DIST_CODE_LEN-1, 20));
-+ }
-+
-+ fprintf(header, "const uch _length_code[MAX_MATCH-MIN_MATCH+1]= {\n");
-+ for (i = 0; i < MAX_MATCH-MIN_MATCH+1; i++) {
-+ fprintf(header, "%2u%s", _length_code[i],
-+ SEPARATOR(i, MAX_MATCH-MIN_MATCH, 20));
-+ }
-+
-+ fprintf(header, "local const int base_length[LENGTH_CODES] = {\n");
-+ for (i = 0; i < LENGTH_CODES; i++) {
-+ fprintf(header, "%1u%s", base_length[i],
-+ SEPARATOR(i, LENGTH_CODES-1, 20));
-+ }
-+
-+ fprintf(header, "local const int base_dist[D_CODES] = {\n");
-+ for (i = 0; i < D_CODES; i++) {
-+ fprintf(header, "%5u%s", base_dist[i],
-+ SEPARATOR(i, D_CODES-1, 10));
-+ }
-+
-+ fclose(header);
-+}
-+#endif /* GEN_TREES_H */
-+
-+/* ===========================================================================
-+ * Initialize the tree data structures for a new zlib stream.
-+ */
-+void _tr_init(s)
-+ deflate_state *s;
-+{
-+ tr_static_init();
-+
-+ s->l_desc.dyn_tree = s->dyn_ltree;
-+ s->l_desc.stat_desc = &static_l_desc;
-+
-+ s->d_desc.dyn_tree = s->dyn_dtree;
-+ s->d_desc.stat_desc = &static_d_desc;
-+
-+ s->bl_desc.dyn_tree = s->bl_tree;
-+ s->bl_desc.stat_desc = &static_bl_desc;
-+
-+ s->bi_buf = 0;
-+ s->bi_valid = 0;
-+ s->last_eob_len = 8; /* enough lookahead for inflate */
-+#ifdef DEBUG
-+ s->compressed_len = 0L;
-+ s->bits_sent = 0L;
-+#endif
-+
-+ /* Initialize the first block of the first file: */
-+ init_block(s);
-+}
-+
-+/* ===========================================================================
-+ * Initialize a new block.
-+ */
-+local void init_block(s)
-+ deflate_state *s;
-+{
-+ int n; /* iterates over tree elements */
-+
-+ /* Initialize the trees. */
-+ for (n = 0; n < L_CODES; n++) s->dyn_ltree[n].Freq = 0;
-+ for (n = 0; n < D_CODES; n++) s->dyn_dtree[n].Freq = 0;
-+ for (n = 0; n < BL_CODES; n++) s->bl_tree[n].Freq = 0;
-+
-+ s->dyn_ltree[END_BLOCK].Freq = 1;
-+ s->opt_len = s->static_len = 0L;
-+ s->last_lit = s->matches = 0;
-+}
-+
-+#define SMALLEST 1
-+/* Index within the heap array of least frequent node in the Huffman tree */
-+
-+
-+/* ===========================================================================
-+ * Remove the smallest element from the heap and recreate the heap with
-+ * one less element. Updates heap and heap_len.
-+ */
-+#define pqremove(s, tree, top) \
-+{\
-+ top = s->heap[SMALLEST]; \
-+ s->heap[SMALLEST] = s->heap[s->heap_len--]; \
-+ pqdownheap(s, tree, SMALLEST); \
-+}
-+
-+/* ===========================================================================
-+ * Compares to subtrees, using the tree depth as tie breaker when
-+ * the subtrees have equal frequency. This minimizes the worst case length.
-+ */
-+#define smaller(tree, n, m, depth) \
-+ (tree[n].Freq < tree[m].Freq || \
-+ (tree[n].Freq == tree[m].Freq && depth[n] <= depth[m]))
-+
-+/* ===========================================================================
-+ * Restore the heap property by moving down the tree starting at node k,
-+ * exchanging a node with the smallest of its two sons if necessary, stopping
-+ * when the heap property is re-established (each father smaller than its
-+ * two sons).
-+ */
-+local void pqdownheap(s, tree, k)
-+ deflate_state *s;
-+ ct_data *tree; /* the tree to restore */
-+ int k; /* node to move down */
-+{
-+ int v = s->heap[k];
-+ int j = k << 1; /* left son of k */
-+ while (j <= s->heap_len) {
-+ /* Set j to the smallest of the two sons: */
-+ if (j < s->heap_len &&
-+ smaller(tree, s->heap[j+1], s->heap[j], s->depth)) {
-+ j++;
-+ }
-+ /* Exit if v is smaller than both sons */
-+ if (smaller(tree, v, s->heap[j], s->depth)) break;
-+
-+ /* Exchange v with the smallest son */
-+ s->heap[k] = s->heap[j]; k = j;
-+
-+ /* And continue down the tree, setting j to the left son of k */
-+ j <<= 1;
-+ }
-+ s->heap[k] = v;
-+}
-+
-+/* ===========================================================================
-+ * Compute the optimal bit lengths for a tree and update the total bit length
-+ * for the current block.
-+ * IN assertion: the fields freq and dad are set, heap[heap_max] and
-+ * above are the tree nodes sorted by increasing frequency.
-+ * OUT assertions: the field len is set to the optimal bit length, the
-+ * array bl_count contains the frequencies for each bit length.
-+ * The length opt_len is updated; static_len is also updated if stree is
-+ * not null.
-+ */
-+local void gen_bitlen(s, desc)
-+ deflate_state *s;
-+ tree_desc *desc; /* the tree descriptor */
-+{
-+ ct_data *tree = desc->dyn_tree;
-+ int max_code = desc->max_code;
-+ const ct_data *stree = desc->stat_desc->static_tree;
-+ const intf *extra = desc->stat_desc->extra_bits;
-+ int base = desc->stat_desc->extra_base;
-+ int max_length = desc->stat_desc->max_length;
-+ int h; /* heap index */
-+ int n, m; /* iterate over the tree elements */
-+ int bits; /* bit length */
-+ int xbits; /* extra bits */
-+ ush f; /* frequency */
-+ int overflow = 0; /* number of elements with bit length too large */
-+
-+ for (bits = 0; bits <= MAX_BITS; bits++) s->bl_count[bits] = 0;
-+
-+ /* In a first pass, compute the optimal bit lengths (which may
-+ * overflow in the case of the bit length tree).
-+ */
-+ tree[s->heap[s->heap_max]].Len = 0; /* root of the heap */
-+
-+ for (h = s->heap_max+1; h < HEAP_SIZE; h++) {
-+ n = s->heap[h];
-+ bits = tree[tree[n].Dad].Len + 1;
-+ if (bits > max_length) bits = max_length, overflow++;
-+ tree[n].Len = (ush)bits;
-+ /* We overwrite tree[n].Dad which is no longer needed */
-+
-+ if (n > max_code) continue; /* not a leaf node */
-+
-+ s->bl_count[bits]++;
-+ xbits = 0;
-+ if (n >= base) xbits = extra[n-base];
-+ f = tree[n].Freq;
-+ s->opt_len += (ulg)f * (bits + xbits);
-+ if (stree) s->static_len += (ulg)f * (stree[n].Len + xbits);
-+ }
-+ if (overflow == 0) return;
-+
-+ Trace((stderr,"\nbit length overflow\n"));
-+ /* This happens for example on obj2 and pic of the Calgary corpus */
-+
-+ /* Find the first bit length which could increase: */
-+ do {
-+ bits = max_length-1;
-+ while (s->bl_count[bits] == 0) bits--;
-+ s->bl_count[bits]--; /* move one leaf down the tree */
-+ s->bl_count[bits+1] += 2; /* move one overflow item as its brother */
-+ s->bl_count[max_length]--;
-+ /* The brother of the overflow item also moves one step up,
-+ * but this does not affect bl_count[max_length]
-+ */
-+ overflow -= 2;
-+ } while (overflow > 0);
-+
-+ /* Now recompute all bit lengths, scanning in increasing frequency.
-+ * h is still equal to HEAP_SIZE. (It is simpler to reconstruct all
-+ * lengths instead of fixing only the wrong ones. This idea is taken
-+ * from 'ar' written by Haruhiko Okumura.)
-+ */
-+ for (bits = max_length; bits != 0; bits--) {
-+ n = s->bl_count[bits];
-+ while (n != 0) {
-+ m = s->heap[--h];
-+ if (m > max_code) continue;
-+ if (tree[m].Len != (unsigned) bits) {
-+ Trace((stderr,"code %d bits %d->%d\n", m, tree[m].Len, bits));
-+ s->opt_len += ((long)bits - (long)tree[m].Len)
-+ *(long)tree[m].Freq;
-+ tree[m].Len = (ush)bits;
-+ }
-+ n--;
-+ }
-+ }
-+}
-+
-+/* ===========================================================================
-+ * Generate the codes for a given tree and bit counts (which need not be
-+ * optimal).
-+ * IN assertion: the array bl_count contains the bit length statistics for
-+ * the given tree and the field len is set for all tree elements.
-+ * OUT assertion: the field code is set for all tree elements of non
-+ * zero code length.
-+ */
-+local void gen_codes (tree, max_code, bl_count)
-+ ct_data *tree; /* the tree to decorate */
-+ int max_code; /* largest code with non zero frequency */
-+ ushf *bl_count; /* number of codes at each bit length */
-+{
-+ ush next_code[MAX_BITS+1]; /* next code value for each bit length */
-+ ush code = 0; /* running code value */
-+ int bits; /* bit index */
-+ int n; /* code index */
-+
-+ /* The distribution counts are first used to generate the code values
-+ * without bit reversal.
-+ */
-+ for (bits = 1; bits <= MAX_BITS; bits++) {
-+ next_code[bits] = code = (code + bl_count[bits-1]) << 1;
-+ }
-+ /* Check that the bit counts in bl_count are consistent. The last code
-+ * must be all ones.
-+ */
-+ Assert (code + bl_count[MAX_BITS]-1 == (1<<MAX_BITS)-1,
-+ "inconsistent bit counts");
-+ Tracev((stderr,"\ngen_codes: max_code %d ", max_code));
-+
-+ for (n = 0; n <= max_code; n++) {
-+ int len = tree[n].Len;
-+ if (len == 0) continue;
-+ /* Now reverse the bits */
-+ tree[n].Code = bi_reverse(next_code[len]++, len);
-+
-+ Tracecv(tree != static_ltree, (stderr,"\nn %3d %c l %2d c %4x (%x) ",
-+ n, (isgraph(n) ? n : ' '), len, tree[n].Code, next_code[len]-1));
-+ }
-+}
-+
-+/* ===========================================================================
-+ * Construct one Huffman tree and assigns the code bit strings and lengths.
-+ * Update the total bit length for the current block.
-+ * IN assertion: the field freq is set for all tree elements.
-+ * OUT assertions: the fields len and code are set to the optimal bit length
-+ * and corresponding code. The length opt_len is updated; static_len is
-+ * also updated if stree is not null. The field max_code is set.
-+ */
-+local void build_tree(s, desc)
-+ deflate_state *s;
-+ tree_desc *desc; /* the tree descriptor */
-+{
-+ ct_data *tree = desc->dyn_tree;
-+ const ct_data *stree = desc->stat_desc->static_tree;
-+ int elems = desc->stat_desc->elems;
-+ int n, m; /* iterate over heap elements */
-+ int max_code = -1; /* largest code with non zero frequency */
-+ int node; /* new node being created */
-+
-+ /* Construct the initial heap, with least frequent element in
-+ * heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n+1].
-+ * heap[0] is not used.
-+ */
-+ s->heap_len = 0, s->heap_max = HEAP_SIZE;
-+
-+ for (n = 0; n < elems; n++) {
-+ if (tree[n].Freq != 0) {
-+ s->heap[++(s->heap_len)] = max_code = n;
-+ s->depth[n] = 0;
-+ } else {
-+ tree[n].Len = 0;
-+ }
-+ }
-+
-+ /* The pkzip format requires that at least one distance code exists,
-+ * and that at least one bit should be sent even if there is only one
-+ * possible code. So to avoid special checks later on we force at least
-+ * two codes of non zero frequency.
-+ */
-+ while (s->heap_len < 2) {
-+ node = s->heap[++(s->heap_len)] = (max_code < 2 ? ++max_code : 0);
-+ tree[node].Freq = 1;
-+ s->depth[node] = 0;
-+ s->opt_len--; if (stree) s->static_len -= stree[node].Len;
-+ /* node is 0 or 1 so it does not have extra bits */
-+ }
-+ desc->max_code = max_code;
-+
-+ /* The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree,
-+ * establish sub-heaps of increasing lengths:
-+ */
-+ for (n = s->heap_len/2; n >= 1; n--) pqdownheap(s, tree, n);
-+
-+ /* Construct the Huffman tree by repeatedly combining the least two
-+ * frequent nodes.
-+ */
-+ node = elems; /* next internal node of the tree */
-+ do {
-+ pqremove(s, tree, n); /* n = node of least frequency */
-+ m = s->heap[SMALLEST]; /* m = node of next least frequency */
-+
-+ s->heap[--(s->heap_max)] = n; /* keep the nodes sorted by frequency */
-+ s->heap[--(s->heap_max)] = m;
-+
-+ /* Create a new node father of n and m */
-+ tree[node].Freq = tree[n].Freq + tree[m].Freq;
-+ s->depth[node] = (uch) (MAX(s->depth[n], s->depth[m]) + 1);
-+ tree[n].Dad = tree[m].Dad = (ush)node;
-+#ifdef DUMP_BL_TREE
-+ if (tree == s->bl_tree) {
-+ fprintf(stderr,"\nnode %d(%d), sons %d(%d) %d(%d)",
-+ node, tree[node].Freq, n, tree[n].Freq, m, tree[m].Freq);
-+ }
-+#endif
-+ /* and insert the new node in the heap */
-+ s->heap[SMALLEST] = node++;
-+ pqdownheap(s, tree, SMALLEST);
-+
-+ } while (s->heap_len >= 2);
-+
-+ s->heap[--(s->heap_max)] = s->heap[SMALLEST];
-+
-+ /* At this point, the fields freq and dad are set. We can now
-+ * generate the bit lengths.
-+ */
-+ gen_bitlen(s, (tree_desc *)desc);
-+
-+ /* The field len is now set, we can generate the bit codes */
-+ gen_codes ((ct_data *)tree, max_code, s->bl_count);
-+}
-+
-+/* ===========================================================================
-+ * Scan a literal or distance tree to determine the frequencies of the codes
-+ * in the bit length tree.
-+ */
-+local void scan_tree (s, tree, max_code)
-+ deflate_state *s;
-+ ct_data *tree; /* the tree to be scanned */
-+ int max_code; /* and its largest code of non zero frequency */
-+{
-+ int n; /* iterates over all tree elements */
-+ int prevlen = -1; /* last emitted length */
-+ int curlen; /* length of current code */
-+ int nextlen = tree[0].Len; /* length of next code */
-+ int count = 0; /* repeat count of the current code */
-+ int max_count = 7; /* max repeat count */
-+ int min_count = 4; /* min repeat count */
-+
-+ if (nextlen == 0) max_count = 138, min_count = 3;
-+ tree[max_code+1].Len = (ush)0xffff; /* guard */
-+
-+ for (n = 0; n <= max_code; n++) {
-+ curlen = nextlen; nextlen = tree[n+1].Len;
-+ if (++count < max_count && curlen == nextlen) {
-+ continue;
-+ } else if (count < min_count) {
-+ s->bl_tree[curlen].Freq += count;
-+ } else if (curlen != 0) {
-+ if (curlen != prevlen) s->bl_tree[curlen].Freq++;
-+ s->bl_tree[REP_3_6].Freq++;
-+ } else if (count <= 10) {
-+ s->bl_tree[REPZ_3_10].Freq++;
-+ } else {
-+ s->bl_tree[REPZ_11_138].Freq++;
-+ }
-+ count = 0; prevlen = curlen;
-+ if (nextlen == 0) {
-+ max_count = 138, min_count = 3;
-+ } else if (curlen == nextlen) {
-+ max_count = 6, min_count = 3;
-+ } else {
-+ max_count = 7, min_count = 4;
-+ }
-+ }
-+}
-+
-+/* ===========================================================================
-+ * Send a literal or distance tree in compressed form, using the codes in
-+ * bl_tree.
-+ */
-+local void send_tree (s, tree, max_code)
-+ deflate_state *s;
-+ ct_data *tree; /* the tree to be scanned */
-+ int max_code; /* and its largest code of non zero frequency */
-+{
-+ int n; /* iterates over all tree elements */
-+ int prevlen = -1; /* last emitted length */
-+ int curlen; /* length of current code */
-+ int nextlen = tree[0].Len; /* length of next code */
-+ int count = 0; /* repeat count of the current code */
-+ int max_count = 7; /* max repeat count */
-+ int min_count = 4; /* min repeat count */
-+
-+ /* tree[max_code+1].Len = -1; */ /* guard already set */
-+ if (nextlen == 0) max_count = 138, min_count = 3;
-+
-+ for (n = 0; n <= max_code; n++) {
-+ curlen = nextlen; nextlen = tree[n+1].Len;
-+ if (++count < max_count && curlen == nextlen) {
-+ continue;
-+ } else if (count < min_count) {
-+ do { send_code(s, curlen, s->bl_tree); } while (--count != 0);
-+
-+ } else if (curlen != 0) {
-+ if (curlen != prevlen) {
-+ send_code(s, curlen, s->bl_tree); count--;
-+ }
-+ Assert(count >= 3 && count <= 6, " 3_6?");
-+ send_code(s, REP_3_6, s->bl_tree); send_bits(s, count-3, 2);
-+
-+ } else if (count <= 10) {
-+ send_code(s, REPZ_3_10, s->bl_tree); send_bits(s, count-3, 3);
-+
-+ } else {
-+ send_code(s, REPZ_11_138, s->bl_tree); send_bits(s, count-11, 7);
-+ }
-+ count = 0; prevlen = curlen;
-+ if (nextlen == 0) {
-+ max_count = 138, min_count = 3;
-+ } else if (curlen == nextlen) {
-+ max_count = 6, min_count = 3;
-+ } else {
-+ max_count = 7, min_count = 4;
-+ }
-+ }
-+}
-+
-+/* ===========================================================================
-+ * Construct the Huffman tree for the bit lengths and return the index in
-+ * bl_order of the last bit length code to send.
-+ */
-+local int build_bl_tree(s)
-+ deflate_state *s;
-+{
-+ int max_blindex; /* index of last bit length code of non zero freq */
-+
-+ /* Determine the bit length frequencies for literal and distance trees */
-+ scan_tree(s, (ct_data *)s->dyn_ltree, s->l_desc.max_code);
-+ scan_tree(s, (ct_data *)s->dyn_dtree, s->d_desc.max_code);
-+
-+ /* Build the bit length tree: */
-+ build_tree(s, (tree_desc *)(&(s->bl_desc)));
-+ /* opt_len now includes the length of the tree representations, except
-+ * the lengths of the bit lengths codes and the 5+5+4 bits for the counts.
-+ */
-+
-+ /* Determine the number of bit length codes to send. The pkzip format
-+ * requires that at least 4 bit length codes be sent. (appnote.txt says
-+ * 3 but the actual value used is 4.)
-+ */
-+ for (max_blindex = BL_CODES-1; max_blindex >= 3; max_blindex--) {
-+ if (s->bl_tree[bl_order[max_blindex]].Len != 0) break;
-+ }
-+ /* Update opt_len to include the bit length tree and counts */
-+ s->opt_len += 3*(max_blindex+1) + 5+5+4;
-+ Tracev((stderr, "\ndyn trees: dyn %ld, stat %ld",
-+ s->opt_len, s->static_len));
-+
-+ return max_blindex;
-+}
-+
-+/* ===========================================================================
-+ * Send the header for a block using dynamic Huffman trees: the counts, the
-+ * lengths of the bit length codes, the literal tree and the distance tree.
-+ * IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4.
-+ */
-+local void send_all_trees(s, lcodes, dcodes, blcodes)
-+ deflate_state *s;
-+ int lcodes, dcodes, blcodes; /* number of codes for each tree */
-+{
-+ int rank; /* index in bl_order */
-+
-+ Assert (lcodes >= 257 && dcodes >= 1 && blcodes >= 4, "not enough codes");
-+ Assert (lcodes <= L_CODES && dcodes <= D_CODES && blcodes <= BL_CODES,
-+ "too many codes");
-+ Tracev((stderr, "\nbl counts: "));
-+ send_bits(s, lcodes-257, 5); /* not +255 as stated in appnote.txt */
-+ send_bits(s, dcodes-1, 5);
-+ send_bits(s, blcodes-4, 4); /* not -3 as stated in appnote.txt */
-+ for (rank = 0; rank < blcodes; rank++) {
-+ Tracev((stderr, "\nbl code %2d ", bl_order[rank]));
-+ send_bits(s, s->bl_tree[bl_order[rank]].Len, 3);
-+ }
-+ Tracev((stderr, "\nbl tree: sent %ld", s->bits_sent));
-+
-+ send_tree(s, (ct_data *)s->dyn_ltree, lcodes-1); /* literal tree */
-+ Tracev((stderr, "\nlit tree: sent %ld", s->bits_sent));
-+
-+ send_tree(s, (ct_data *)s->dyn_dtree, dcodes-1); /* distance tree */
-+ Tracev((stderr, "\ndist tree: sent %ld", s->bits_sent));
-+}
-+
-+/* ===========================================================================
-+ * Send a stored block
-+ */
-+void _tr_stored_block(s, buf, stored_len, eof)
-+ deflate_state *s;
-+ charf *buf; /* input block */
-+ ulg stored_len; /* length of input block */
-+ int eof; /* true if this is the last block for a file */
-+{
-+ send_bits(s, (STORED_BLOCK<<1)+eof, 3); /* send block type */
-+#ifdef DEBUG
-+ s->compressed_len = (s->compressed_len + 3 + 7) & (ulg)~7L;
-+ s->compressed_len += (stored_len + 4) << 3;
-+#endif
-+ copy_block(s, buf, (unsigned)stored_len, 1); /* with header */
-+}
-+
-+/* ===========================================================================
-+ * Send one empty static block to give enough lookahead for inflate.
-+ * This takes 10 bits, of which 7 may remain in the bit buffer.
-+ * The current inflate code requires 9 bits of lookahead. If the
-+ * last two codes for the previous block (real code plus EOB) were coded
-+ * on 5 bits or less, inflate may have only 5+3 bits of lookahead to decode
-+ * the last real code. In this case we send two empty static blocks instead
-+ * of one. (There are no problems if the previous block is stored or fixed.)
-+ * To simplify the code, we assume the worst case of last real code encoded
-+ * on one bit only.
-+ */
-+void _tr_align(s)
-+ deflate_state *s;
-+{
-+ send_bits(s, STATIC_TREES<<1, 3);
-+ send_code(s, END_BLOCK, static_ltree);
-+#ifdef DEBUG
-+ s->compressed_len += 10L; /* 3 for block type, 7 for EOB */
-+#endif
-+ bi_flush(s);
-+ /* Of the 10 bits for the empty block, we have already sent
-+ * (10 - bi_valid) bits. The lookahead for the last real code (before
-+ * the EOB of the previous block) was thus at least one plus the length
-+ * of the EOB plus what we have just sent of the empty static block.
-+ */
-+ if (1 + s->last_eob_len + 10 - s->bi_valid < 9) {
-+ send_bits(s, STATIC_TREES<<1, 3);
-+ send_code(s, END_BLOCK, static_ltree);
-+#ifdef DEBUG
-+ s->compressed_len += 10L;
-+#endif
-+ bi_flush(s);
-+ }
-+ s->last_eob_len = 7;
-+}
-+
-+/* ===========================================================================
-+ * Determine the best encoding for the current block: dynamic trees, static
-+ * trees or store, and output the encoded block to the zip file.
-+ */
-+void _tr_flush_block(s, buf, stored_len, eof)
-+ deflate_state *s;
-+ charf *buf; /* input block, or NULL if too old */
-+ ulg stored_len; /* length of input block */
-+ int eof; /* true if this is the last block for a file */
-+{
-+ ulg opt_lenb, static_lenb; /* opt_len and static_len in bytes */
-+ int max_blindex = 0; /* index of last bit length code of non zero freq */
-+
-+ /* Build the Huffman trees unless a stored block is forced */
-+ if (s->level > 0) {
-+
-+ /* Check if the file is ascii or binary */
-+ if (s->data_type == Z_UNKNOWN) set_data_type(s);
-+
-+ /* Construct the literal and distance trees */
-+ build_tree(s, (tree_desc *)(&(s->l_desc)));
-+ Tracev((stderr, "\nlit data: dyn %ld, stat %ld", s->opt_len,
-+ s->static_len));
-+
-+ build_tree(s, (tree_desc *)(&(s->d_desc)));
-+ Tracev((stderr, "\ndist data: dyn %ld, stat %ld", s->opt_len,
-+ s->static_len));
-+ /* At this point, opt_len and static_len are the total bit lengths of
-+ * the compressed block data, excluding the tree representations.
-+ */
-+
-+ /* Build the bit length tree for the above two trees, and get the index
-+ * in bl_order of the last bit length code to send.
-+ */
-+ max_blindex = build_bl_tree(s);
-+
-+ /* Determine the best encoding. Compute first the block length in bytes*/
-+ opt_lenb = (s->opt_len+3+7)>>3;
-+ static_lenb = (s->static_len+3+7)>>3;
-+
-+ Tracev((stderr, "\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u ",
-+ opt_lenb, s->opt_len, static_lenb, s->static_len, stored_len,
-+ s->last_lit));
-+
-+ if (static_lenb <= opt_lenb) opt_lenb = static_lenb;
-+
-+ } else {
-+ Assert(buf != (char*)0, "lost buf");
-+ opt_lenb = static_lenb = stored_len + 5; /* force a stored block */
-+ }
-+
-+#ifdef FORCE_STORED
-+ if (buf != (char*)0) { /* force stored block */
-+#else
-+ if (stored_len+4 <= opt_lenb && buf != (char*)0) {
-+ /* 4: two words for the lengths */
-+#endif
-+ /* The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE.
-+ * Otherwise we can't have processed more than WSIZE input bytes since
-+ * the last block flush, because compression would have been
-+ * successful. If LIT_BUFSIZE <= WSIZE, it is never too late to
-+ * transform a block into a stored block.
-+ */
-+ _tr_stored_block(s, buf, stored_len, eof);
-+
-+#ifdef FORCE_STATIC
-+ } else if (static_lenb >= 0) { /* force static trees */
-+#else
-+ } else if (static_lenb == opt_lenb) {
-+#endif
-+ send_bits(s, (STATIC_TREES<<1)+eof, 3);
-+ compress_block(s, static_ltree, static_dtree);
-+#ifdef DEBUG
-+ s->compressed_len += 3 + s->static_len;
-+#endif
-+ } else {
-+ send_bits(s, (DYN_TREES<<1)+eof, 3);
-+ send_all_trees(s, s->l_desc.max_code+1, s->d_desc.max_code+1,
-+ max_blindex+1);
-+ compress_block(s, s->dyn_ltree, s->dyn_dtree);
-+#ifdef DEBUG
-+ s->compressed_len += 3 + s->opt_len;
-+#endif
-+ }
-+ Assert (s->compressed_len == s->bits_sent, "bad compressed size");
-+ /* The above check is made mod 2^32, for files larger than 512 MB
-+ * and uLong implemented on 32 bits.
-+ */
-+ init_block(s);
-+
-+ if (eof) {
-+ bi_windup(s);
-+#ifdef DEBUG
-+ s->compressed_len += 7; /* align on byte boundary */
-+#endif
-+ }
-+ Tracev((stderr,"\ncomprlen %lu(%lu) ", s->compressed_len>>3,
-+ s->compressed_len-7*eof));
-+}
-+
-+/* ===========================================================================
-+ * Save the match info and tally the frequency counts. Return true if
-+ * the current block must be flushed.
-+ */
-+int _tr_tally (s, dist, lc)
-+ deflate_state *s;
-+ unsigned dist; /* distance of matched string */
-+ unsigned lc; /* match length-MIN_MATCH or unmatched char (if dist==0) */
-+{
-+ s->d_buf[s->last_lit] = (ush)dist;
-+ s->l_buf[s->last_lit++] = (uch)lc;
-+ if (dist == 0) {
-+ /* lc is the unmatched char */
-+ s->dyn_ltree[lc].Freq++;
-+ } else {
-+ s->matches++;
-+ /* Here, lc is the match length - MIN_MATCH */
-+ dist--; /* dist = match distance - 1 */
-+ Assert((ush)dist < (ush)MAX_DIST(s) &&
-+ (ush)lc <= (ush)(MAX_MATCH-MIN_MATCH) &&
-+ (ush)d_code(dist) < (ush)D_CODES, "_tr_tally: bad match");
-+
-+ s->dyn_ltree[_length_code[lc]+LITERALS+1].Freq++;
-+ s->dyn_dtree[d_code(dist)].Freq++;
-+ }
-+
-+#ifdef TRUNCATE_BLOCK
-+ /* Try to guess if it is profitable to stop the current block here */
-+ if ((s->last_lit & 0x1fff) == 0 && s->level > 2) {
-+ /* Compute an upper bound for the compressed length */
-+ ulg out_length = (ulg)s->last_lit*8L;
-+ ulg in_length = (ulg)((long)s->strstart - s->block_start);
-+ int dcode;
-+ for (dcode = 0; dcode < D_CODES; dcode++) {
-+ out_length += (ulg)s->dyn_dtree[dcode].Freq *
-+ (5L+extra_dbits[dcode]);
-+ }
-+ out_length >>= 3;
-+ Tracev((stderr,"\nlast_lit %u, in %ld, out ~%ld(%ld%%) ",
-+ s->last_lit, in_length, out_length,
-+ 100L - out_length*100L/in_length));
-+ if (s->matches < s->last_lit/2 && out_length < in_length/2) return 1;
-+ }
-+#endif
-+ return (s->last_lit == s->lit_bufsize-1);
-+ /* We avoid equality with lit_bufsize because of wraparound at 64K
-+ * on 16 bit machines and because stored blocks are restricted to
-+ * 64K-1 bytes.
-+ */
-+}
-+
-+/* ===========================================================================
-+ * Send the block data compressed using the given Huffman trees
-+ */
-+local void compress_block(s, ltree, dtree)
-+ deflate_state *s;
-+ const ct_data *ltree; /* literal tree */
-+ const ct_data *dtree; /* distance tree */
-+{
-+ unsigned dist; /* distance of matched string */
-+ int lc; /* match length or unmatched char (if dist == 0) */
-+ unsigned lx = 0; /* running index in l_buf */
-+ unsigned code; /* the code to send */
-+ int extra; /* number of extra bits to send */
-+
-+ if (s->last_lit != 0) do {
-+ dist = s->d_buf[lx];
-+ lc = s->l_buf[lx++];
-+ if (dist == 0) {
-+ send_code(s, lc, ltree); /* send a literal byte */
-+ Tracecv(isgraph(lc), (stderr," '%c' ", lc));
-+ } else {
-+ /* Here, lc is the match length - MIN_MATCH */
-+ code = _length_code[lc];
-+ send_code(s, code+LITERALS+1, ltree); /* send the length code */
-+ extra = extra_lbits[code];
-+ if (extra != 0) {
-+ lc -= base_length[code];
-+ send_bits(s, lc, extra); /* send the extra length bits */
-+ }
-+ dist--; /* dist is now the match distance - 1 */
-+ code = d_code(dist);
-+ Assert (code < D_CODES, "bad d_code");
-+
-+ send_code(s, code, dtree); /* send the distance code */
-+ extra = extra_dbits[code];
-+ if (extra != 0) {
-+ dist -= base_dist[code];
-+ send_bits(s, dist, extra); /* send the extra distance bits */
-+ }
-+ } /* literal or match pair ? */
-+
-+ /* Check that the overlay between pending_buf and d_buf+l_buf is ok: */
-+ Assert(s->pending < s->lit_bufsize + 2*lx, "pendingBuf overflow");
-+
-+ } while (lx < s->last_lit);
-+
-+ send_code(s, END_BLOCK, ltree);
-+ s->last_eob_len = ltree[END_BLOCK].Len;
-+}
-+
-+/* ===========================================================================
-+ * Set the data type to ASCII or BINARY, using a crude approximation:
-+ * binary if more than 20% of the bytes are <= 6 or >= 128, ascii otherwise.
-+ * IN assertion: the fields freq of dyn_ltree are set and the total of all
-+ * frequencies does not exceed 64K (to fit in an int on 16 bit machines).
-+ */
-+local void set_data_type(s)
-+ deflate_state *s;
-+{
-+ int n = 0;
-+ unsigned ascii_freq = 0;
-+ unsigned bin_freq = 0;
-+ while (n < 7) bin_freq += s->dyn_ltree[n++].Freq;
-+ while (n < 128) ascii_freq += s->dyn_ltree[n++].Freq;
-+ while (n < LITERALS) bin_freq += s->dyn_ltree[n++].Freq;
-+ s->data_type = (Byte)(bin_freq > (ascii_freq >> 2) ? Z_BINARY : Z_ASCII);
-+}
-+
-+/* ===========================================================================
-+ * Reverse the first len bits of a code, using straightforward code (a faster
-+ * method would use a table)
-+ * IN assertion: 1 <= len <= 15
-+ */
-+local unsigned bi_reverse(code, len)
-+ unsigned code; /* the value to invert */
-+ int len; /* its bit length */
-+{
-+ register unsigned res = 0;
-+ do {
-+ res |= code & 1;
-+ code >>= 1, res <<= 1;
-+ } while (--len > 0);
-+ return res >> 1;
-+}
-+
-+/* ===========================================================================
-+ * Flush the bit buffer, keeping at most 7 bits in it.
-+ */
-+local void bi_flush(s)
-+ deflate_state *s;
-+{
-+ if (s->bi_valid == 16) {
-+ put_short(s, s->bi_buf);
-+ s->bi_buf = 0;
-+ s->bi_valid = 0;
-+ } else if (s->bi_valid >= 8) {
-+ put_byte(s, (Byte)s->bi_buf);
-+ s->bi_buf >>= 8;
-+ s->bi_valid -= 8;
-+ }
-+}
-+
-+/* ===========================================================================
-+ * Flush the bit buffer and align the output on a byte boundary
-+ */
-+local void bi_windup(s)
-+ deflate_state *s;
-+{
-+ if (s->bi_valid > 8) {
-+ put_short(s, s->bi_buf);
-+ } else if (s->bi_valid > 0) {
-+ put_byte(s, (Byte)s->bi_buf);
-+ }
-+ s->bi_buf = 0;
-+ s->bi_valid = 0;
-+#ifdef DEBUG
-+ s->bits_sent = (s->bits_sent+7) & ~7;
-+#endif
-+}
-+
-+/* ===========================================================================
-+ * Copy a stored block, storing first the length and its
-+ * one's complement if requested.
-+ */
-+local void copy_block(s, buf, len, header)
-+ deflate_state *s;
-+ charf *buf; /* the input data */
-+ unsigned len; /* its length */
-+ int header; /* true if block header must be written */
-+{
-+ bi_windup(s); /* align on byte boundary */
-+ s->last_eob_len = 8; /* enough lookahead for inflate */
-+
-+ if (header) {
-+ put_short(s, (ush)len);
-+ put_short(s, (ush)~len);
-+#ifdef DEBUG
-+ s->bits_sent += 2*16;
-+#endif
-+ }
-+#ifdef DEBUG
-+ s->bits_sent += (ulg)len<<3;
-+#endif
-+ while (len--) {
-+ put_byte(s, *buf++);
-+ }
-+}
---- /dev/null Tue Mar 11 13:02:56 2003
-+++ linux/lib/zlib/trees.h Mon Feb 9 13:51:03 2004
-@@ -0,0 +1,128 @@
-+/* header created automatically with -DGEN_TREES_H */
-+
-+local const ct_data static_ltree[L_CODES+2] = {
-+{{ 12},{ 8}}, {{140},{ 8}}, {{ 76},{ 8}}, {{204},{ 8}}, {{ 44},{ 8}},
-+{{172},{ 8}}, {{108},{ 8}}, {{236},{ 8}}, {{ 28},{ 8}}, {{156},{ 8}},
-+{{ 92},{ 8}}, {{220},{ 8}}, {{ 60},{ 8}}, {{188},{ 8}}, {{124},{ 8}},
-+{{252},{ 8}}, {{ 2},{ 8}}, {{130},{ 8}}, {{ 66},{ 8}}, {{194},{ 8}},
-+{{ 34},{ 8}}, {{162},{ 8}}, {{ 98},{ 8}}, {{226},{ 8}}, {{ 18},{ 8}},
-+{{146},{ 8}}, {{ 82},{ 8}}, {{210},{ 8}}, {{ 50},{ 8}}, {{178},{ 8}},
-+{{114},{ 8}}, {{242},{ 8}}, {{ 10},{ 8}}, {{138},{ 8}}, {{ 74},{ 8}},
-+{{202},{ 8}}, {{ 42},{ 8}}, {{170},{ 8}}, {{106},{ 8}}, {{234},{ 8}},
-+{{ 26},{ 8}}, {{154},{ 8}}, {{ 90},{ 8}}, {{218},{ 8}}, {{ 58},{ 8}},
-+{{186},{ 8}}, {{122},{ 8}}, {{250},{ 8}}, {{ 6},{ 8}}, {{134},{ 8}},
-+{{ 70},{ 8}}, {{198},{ 8}}, {{ 38},{ 8}}, {{166},{ 8}}, {{102},{ 8}},
-+{{230},{ 8}}, {{ 22},{ 8}}, {{150},{ 8}}, {{ 86},{ 8}}, {{214},{ 8}},
-+{{ 54},{ 8}}, {{182},{ 8}}, {{118},{ 8}}, {{246},{ 8}}, {{ 14},{ 8}},
-+{{142},{ 8}}, {{ 78},{ 8}}, {{206},{ 8}}, {{ 46},{ 8}}, {{174},{ 8}},
-+{{110},{ 8}}, {{238},{ 8}}, {{ 30},{ 8}}, {{158},{ 8}}, {{ 94},{ 8}},
-+{{222},{ 8}}, {{ 62},{ 8}}, {{190},{ 8}}, {{126},{ 8}}, {{254},{ 8}},
-+{{ 1},{ 8}}, {{129},{ 8}}, {{ 65},{ 8}}, {{193},{ 8}}, {{ 33},{ 8}},
-+{{161},{ 8}}, {{ 97},{ 8}}, {{225},{ 8}}, {{ 17},{ 8}}, {{145},{ 8}},
-+{{ 81},{ 8}}, {{209},{ 8}}, {{ 49},{ 8}}, {{177},{ 8}}, {{113},{ 8}},
-+{{241},{ 8}}, {{ 9},{ 8}}, {{137},{ 8}}, {{ 73},{ 8}}, {{201},{ 8}},
-+{{ 41},{ 8}}, {{169},{ 8}}, {{105},{ 8}}, {{233},{ 8}}, {{ 25},{ 8}},
-+{{153},{ 8}}, {{ 89},{ 8}}, {{217},{ 8}}, {{ 57},{ 8}}, {{185},{ 8}},
-+{{121},{ 8}}, {{249},{ 8}}, {{ 5},{ 8}}, {{133},{ 8}}, {{ 69},{ 8}},
-+{{197},{ 8}}, {{ 37},{ 8}}, {{165},{ 8}}, {{101},{ 8}}, {{229},{ 8}},
-+{{ 21},{ 8}}, {{149},{ 8}}, {{ 85},{ 8}}, {{213},{ 8}}, {{ 53},{ 8}},
-+{{181},{ 8}}, {{117},{ 8}}, {{245},{ 8}}, {{ 13},{ 8}}, {{141},{ 8}},
-+{{ 77},{ 8}}, {{205},{ 8}}, {{ 45},{ 8}}, {{173},{ 8}}, {{109},{ 8}},
-+{{237},{ 8}}, {{ 29},{ 8}}, {{157},{ 8}}, {{ 93},{ 8}}, {{221},{ 8}},
-+{{ 61},{ 8}}, {{189},{ 8}}, {{125},{ 8}}, {{253},{ 8}}, {{ 19},{ 9}},
-+{{275},{ 9}}, {{147},{ 9}}, {{403},{ 9}}, {{ 83},{ 9}}, {{339},{ 9}},
-+{{211},{ 9}}, {{467},{ 9}}, {{ 51},{ 9}}, {{307},{ 9}}, {{179},{ 9}},
-+{{435},{ 9}}, {{115},{ 9}}, {{371},{ 9}}, {{243},{ 9}}, {{499},{ 9}},
-+{{ 11},{ 9}}, {{267},{ 9}}, {{139},{ 9}}, {{395},{ 9}}, {{ 75},{ 9}},
-+{{331},{ 9}}, {{203},{ 9}}, {{459},{ 9}}, {{ 43},{ 9}}, {{299},{ 9}},
-+{{171},{ 9}}, {{427},{ 9}}, {{107},{ 9}}, {{363},{ 9}}, {{235},{ 9}},
-+{{491},{ 9}}, {{ 27},{ 9}}, {{283},{ 9}}, {{155},{ 9}}, {{411},{ 9}},
-+{{ 91},{ 9}}, {{347},{ 9}}, {{219},{ 9}}, {{475},{ 9}}, {{ 59},{ 9}},
-+{{315},{ 9}}, {{187},{ 9}}, {{443},{ 9}}, {{123},{ 9}}, {{379},{ 9}},
-+{{251},{ 9}}, {{507},{ 9}}, {{ 7},{ 9}}, {{263},{ 9}}, {{135},{ 9}},
-+{{391},{ 9}}, {{ 71},{ 9}}, {{327},{ 9}}, {{199},{ 9}}, {{455},{ 9}},
-+{{ 39},{ 9}}, {{295},{ 9}}, {{167},{ 9}}, {{423},{ 9}}, {{103},{ 9}},
-+{{359},{ 9}}, {{231},{ 9}}, {{487},{ 9}}, {{ 23},{ 9}}, {{279},{ 9}},
-+{{151},{ 9}}, {{407},{ 9}}, {{ 87},{ 9}}, {{343},{ 9}}, {{215},{ 9}},
-+{{471},{ 9}}, {{ 55},{ 9}}, {{311},{ 9}}, {{183},{ 9}}, {{439},{ 9}},
-+{{119},{ 9}}, {{375},{ 9}}, {{247},{ 9}}, {{503},{ 9}}, {{ 15},{ 9}},
-+{{271},{ 9}}, {{143},{ 9}}, {{399},{ 9}}, {{ 79},{ 9}}, {{335},{ 9}},
-+{{207},{ 9}}, {{463},{ 9}}, {{ 47},{ 9}}, {{303},{ 9}}, {{175},{ 9}},
-+{{431},{ 9}}, {{111},{ 9}}, {{367},{ 9}}, {{239},{ 9}}, {{495},{ 9}},
-+{{ 31},{ 9}}, {{287},{ 9}}, {{159},{ 9}}, {{415},{ 9}}, {{ 95},{ 9}},
-+{{351},{ 9}}, {{223},{ 9}}, {{479},{ 9}}, {{ 63},{ 9}}, {{319},{ 9}},
-+{{191},{ 9}}, {{447},{ 9}}, {{127},{ 9}}, {{383},{ 9}}, {{255},{ 9}},
-+{{511},{ 9}}, {{ 0},{ 7}}, {{ 64},{ 7}}, {{ 32},{ 7}}, {{ 96},{ 7}},
-+{{ 16},{ 7}}, {{ 80},{ 7}}, {{ 48},{ 7}}, {{112},{ 7}}, {{ 8},{ 7}},
-+{{ 72},{ 7}}, {{ 40},{ 7}}, {{104},{ 7}}, {{ 24},{ 7}}, {{ 88},{ 7}},
-+{{ 56},{ 7}}, {{120},{ 7}}, {{ 4},{ 7}}, {{ 68},{ 7}}, {{ 36},{ 7}},
-+{{100},{ 7}}, {{ 20},{ 7}}, {{ 84},{ 7}}, {{ 52},{ 7}}, {{116},{ 7}},
-+{{ 3},{ 8}}, {{131},{ 8}}, {{ 67},{ 8}}, {{195},{ 8}}, {{ 35},{ 8}},
-+{{163},{ 8}}, {{ 99},{ 8}}, {{227},{ 8}}
-+};
-+
-+local const ct_data static_dtree[D_CODES] = {
-+{{ 0},{ 5}}, {{16},{ 5}}, {{ 8},{ 5}}, {{24},{ 5}}, {{ 4},{ 5}},
-+{{20},{ 5}}, {{12},{ 5}}, {{28},{ 5}}, {{ 2},{ 5}}, {{18},{ 5}},
-+{{10},{ 5}}, {{26},{ 5}}, {{ 6},{ 5}}, {{22},{ 5}}, {{14},{ 5}},
-+{{30},{ 5}}, {{ 1},{ 5}}, {{17},{ 5}}, {{ 9},{ 5}}, {{25},{ 5}},
-+{{ 5},{ 5}}, {{21},{ 5}}, {{13},{ 5}}, {{29},{ 5}}, {{ 3},{ 5}},
-+{{19},{ 5}}, {{11},{ 5}}, {{27},{ 5}}, {{ 7},{ 5}}, {{23},{ 5}}
-+};
-+
-+const uch _dist_code[DIST_CODE_LEN] = {
-+ 0, 1, 2, 3, 4, 4, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8,
-+ 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10,
-+10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
-+11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
-+12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13,
-+13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
-+13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
-+14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
-+14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
-+14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15,
-+15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
-+15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
-+15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 16, 17,
-+18, 18, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22,
-+23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
-+24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
-+26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
-+26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27,
-+27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
-+27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
-+28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
-+28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
-+28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
-+29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
-+29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
-+29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29
-+};
-+
-+const uch _length_code[MAX_MATCH-MIN_MATCH+1]= {
-+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 12, 12,
-+13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16,
-+17, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19,
-+19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
-+21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22,
-+22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23,
-+23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
-+24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
-+25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
-+25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26,
-+26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
-+26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
-+27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28
-+};
-+
-+local const int base_length[LENGTH_CODES] = {
-+0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 20, 24, 28, 32, 40, 48, 56,
-+64, 80, 96, 112, 128, 160, 192, 224, 0
-+};
-+
-+local const int base_dist[D_CODES] = {
-+ 0, 1, 2, 3, 4, 6, 8, 12, 16, 24,
-+ 32, 48, 64, 96, 128, 192, 256, 384, 512, 768,
-+ 1024, 1536, 2048, 3072, 4096, 6144, 8192, 12288, 16384, 24576
-+};
-+
---- /dev/null Tue Mar 11 13:02:56 2003
-+++ linux/lib/zlib/zconf.h Mon Feb 9 13:51:03 2004
-@@ -0,0 +1,309 @@
-+/* zconf.h -- configuration of the zlib compression library
-+ * Copyright (C) 1995-2002 Jean-loup Gailly.
-+ * For conditions of distribution and use, see copyright notice in zlib.h
-+ */
-+
-+/* @(#) $Id: zconf.h,v 1.3 2002/04/24 07:36:45 mcr Exp $ */
-+
-+#ifndef _ZCONF_H
-+#define _ZCONF_H
-+
-+/*
-+ * If you *really* need a unique prefix for all types and library functions,
-+ * compile with -DZ_PREFIX. The "standard" zlib should be compiled without it.
-+ */
-+#ifdef IPCOMP_PREFIX
-+# define deflateInit_ ipcomp_deflateInit_
-+# define deflate ipcomp_deflate
-+# define deflateEnd ipcomp_deflateEnd
-+# define inflateInit_ ipcomp_inflateInit_
-+# define inflate ipcomp_inflate
-+# define inflateEnd ipcomp_inflateEnd
-+# define deflateInit2_ ipcomp_deflateInit2_
-+# define deflateSetDictionary ipcomp_deflateSetDictionary
-+# define deflateCopy ipcomp_deflateCopy
-+# define deflateReset ipcomp_deflateReset
-+# define deflateParams ipcomp_deflateParams
-+# define inflateInit2_ ipcomp_inflateInit2_
-+# define inflateSetDictionary ipcomp_inflateSetDictionary
-+# define inflateSync ipcomp_inflateSync
-+# define inflateSyncPoint ipcomp_inflateSyncPoint
-+# define inflateReset ipcomp_inflateReset
-+# define compress ipcomp_compress
-+# define compress2 ipcomp_compress2
-+# define uncompress ipcomp_uncompress
-+# define adler32 ipcomp_adler32
-+# define crc32 ipcomp_crc32
-+# define get_crc_table ipcomp_get_crc_table
-+/* SSS: these also need to be prefixed to avoid clash with ppp_deflate and ext2compression */
-+# define inflate_blocks ipcomp_deflate_blocks
-+# define inflate_blocks_free ipcomp_deflate_blocks_free
-+# define inflate_blocks_new ipcomp_inflate_blocks_new
-+# define inflate_blocks_reset ipcomp_inflate_blocks_reset
-+# define inflate_blocks_sync_point ipcomp_inflate_blocks_sync_point
-+# define inflate_set_dictionary ipcomp_inflate_set_dictionary
-+# define inflate_codes ipcomp_inflate_codes
-+# define inflate_codes_free ipcomp_inflate_codes_free
-+# define inflate_codes_new ipcomp_inflate_codes_new
-+# define inflate_fast ipcomp_inflate_fast
-+# define inflate_trees_bits ipcomp_inflate_trees_bits
-+# define inflate_trees_dynamic ipcomp_inflate_trees_dynamic
-+# define inflate_trees_fixed ipcomp_inflate_trees_fixed
-+# define inflate_flush ipcomp_inflate_flush
-+# define inflate_mask ipcomp_inflate_mask
-+# define _dist_code _ipcomp_dist_code
-+# define _length_code _ipcomp_length_code
-+# define _tr_align _ipcomp_tr_align
-+# define _tr_flush_block _ipcomp_tr_flush_block
-+# define _tr_init _ipcomp_tr_init
-+# define _tr_stored_block _ipcomp_tr_stored_block
-+# define _tr_tally _ipcomp_tr_tally
-+# define zError ipcomp_zError
-+# define z_errmsg ipcomp_z_errmsg
-+# define zlibVersion ipcomp_zlibVersion
-+# define match_init ipcomp_match_init
-+# define longest_match ipcomp_longest_match
-+#endif
-+
-+#ifdef Z_PREFIX
-+# define Byte z_Byte
-+# define uInt z_uInt
-+# define uLong z_uLong
-+# define Bytef z_Bytef
-+# define charf z_charf
-+# define intf z_intf
-+# define uIntf z_uIntf
-+# define uLongf z_uLongf
-+# define voidpf z_voidpf
-+# define voidp z_voidp
-+#endif
-+
-+#if (defined(_WIN32) || defined(__WIN32__)) && !defined(WIN32)
-+# define WIN32
-+#endif
-+#if defined(__GNUC__) || defined(WIN32) || defined(__386__) || defined(i386)
-+# ifndef __32BIT__
-+# define __32BIT__
-+# endif
-+#endif
-+#if defined(__MSDOS__) && !defined(MSDOS)
-+# define MSDOS
-+#endif
-+
-+/*
-+ * Compile with -DMAXSEG_64K if the alloc function cannot allocate more
-+ * than 64k bytes at a time (needed on systems with 16-bit int).
-+ */
-+#if defined(MSDOS) && !defined(__32BIT__)
-+# define MAXSEG_64K
-+#endif
-+#ifdef MSDOS
-+# define UNALIGNED_OK
-+#endif
-+
-+#if (defined(MSDOS) || defined(_WINDOWS) || defined(WIN32)) && !defined(STDC)
-+# define STDC
-+#endif
-+#if defined(__STDC__) || defined(__cplusplus) || defined(__OS2__)
-+# ifndef STDC
-+# define STDC
-+# endif
-+#endif
-+
-+#ifndef STDC
-+# ifndef const /* cannot use !defined(STDC) && !defined(const) on Mac */
-+# define const
-+# endif
-+#endif
-+
-+/* Some Mac compilers merge all .h files incorrectly: */
-+#if defined(__MWERKS__) || defined(applec) ||defined(THINK_C) ||defined(__SC__)
-+# define NO_DUMMY_DECL
-+#endif
-+
-+/* Old Borland C incorrectly complains about missing returns: */
-+#if defined(__BORLANDC__) && (__BORLANDC__ < 0x500)
-+# define NEED_DUMMY_RETURN
-+#endif
-+
-+
-+/* Maximum value for memLevel in deflateInit2 */
-+#ifndef MAX_MEM_LEVEL
-+# ifdef MAXSEG_64K
-+# define MAX_MEM_LEVEL 8
-+# else
-+# define MAX_MEM_LEVEL 9
-+# endif
-+#endif
-+
-+/* Maximum value for windowBits in deflateInit2 and inflateInit2.
-+ * WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files
-+ * created by gzip. (Files created by minigzip can still be extracted by
-+ * gzip.)
-+ */
-+#ifndef MAX_WBITS
-+# define MAX_WBITS 15 /* 32K LZ77 window */
-+#endif
-+
-+/* The memory requirements for deflate are (in bytes):
-+ (1 << (windowBits+2)) + (1 << (memLevel+9))
-+ that is: 128K for windowBits=15 + 128K for memLevel = 8 (default values)
-+ plus a few kilobytes for small objects. For example, if you want to reduce
-+ the default memory requirements from 256K to 128K, compile with
-+ make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7"
-+ Of course this will generally degrade compression (there's no free lunch).
-+
-+ The memory requirements for inflate are (in bytes) 1 << windowBits
-+ that is, 32K for windowBits=15 (default value) plus a few kilobytes
-+ for small objects.
-+*/
-+
-+ /* Type declarations */
-+
-+#ifndef OF /* function prototypes */
-+# ifdef STDC
-+# define OF(args) args
-+# else
-+# define OF(args) ()
-+# endif
-+#endif
-+
-+/* The following definitions for FAR are needed only for MSDOS mixed
-+ * model programming (small or medium model with some far allocations).
-+ * This was tested only with MSC; for other MSDOS compilers you may have
-+ * to define NO_MEMCPY in zutil.h. If you don't need the mixed model,
-+ * just define FAR to be empty.
-+ */
-+#if (defined(M_I86SM) || defined(M_I86MM)) && !defined(__32BIT__)
-+ /* MSC small or medium model */
-+# define SMALL_MEDIUM
-+# ifdef _MSC_VER
-+# define FAR _far
-+# else
-+# define FAR far
-+# endif
-+#endif
-+#if defined(__BORLANDC__) && (defined(__SMALL__) || defined(__MEDIUM__))
-+# ifndef __32BIT__
-+# define SMALL_MEDIUM
-+# define FAR _far
-+# endif
-+#endif
-+
-+/* Compile with -DZLIB_DLL for Windows DLL support */
-+#if defined(ZLIB_DLL)
-+# if defined(_WINDOWS) || defined(WINDOWS)
-+# ifdef FAR
-+# undef FAR
-+# endif
-+# include <windows.h>
-+# define ZEXPORT WINAPI
-+# ifdef WIN32
-+# define ZEXPORTVA WINAPIV
-+# else
-+# define ZEXPORTVA FAR _cdecl _export
-+# endif
-+# endif
-+# if defined (__BORLANDC__)
-+# if (__BORLANDC__ >= 0x0500) && defined (WIN32)
-+# include <windows.h>
-+# define ZEXPORT __declspec(dllexport) WINAPI
-+# define ZEXPORTRVA __declspec(dllexport) WINAPIV
-+# else
-+# if defined (_Windows) && defined (__DLL__)
-+# define ZEXPORT _export
-+# define ZEXPORTVA _export
-+# endif
-+# endif
-+# endif
-+#endif
-+
-+#if defined (__BEOS__)
-+# if defined (ZLIB_DLL)
-+# define ZEXTERN extern __declspec(dllexport)
-+# else
-+# define ZEXTERN extern __declspec(dllimport)
-+# endif
-+#endif
-+
-+#ifndef ZEXPORT
-+# define ZEXPORT
-+#endif
-+#ifndef ZEXPORTVA
-+# define ZEXPORTVA
-+#endif
-+#ifndef ZEXTERN
-+# define ZEXTERN extern
-+#endif
-+
-+#ifndef FAR
-+# define FAR
-+#endif
-+
-+#if !defined(MACOS) && !defined(TARGET_OS_MAC)
-+typedef unsigned char Byte; /* 8 bits */
-+#endif
-+typedef unsigned int uInt; /* 16 bits or more */
-+typedef unsigned long uLong; /* 32 bits or more */
-+
-+#ifdef SMALL_MEDIUM
-+ /* Borland C/C++ and some old MSC versions ignore FAR inside typedef */
-+# define Bytef Byte FAR
-+#else
-+ typedef Byte FAR Bytef;
-+#endif
-+typedef char FAR charf;
-+typedef int FAR intf;
-+typedef uInt FAR uIntf;
-+typedef uLong FAR uLongf;
-+
-+#ifdef STDC
-+ typedef void FAR *voidpf;
-+ typedef void *voidp;
-+#else
-+ typedef Byte FAR *voidpf;
-+ typedef Byte *voidp;
-+#endif
-+
-+#ifdef HAVE_UNISTD_H
-+# include <sys/types.h> /* for off_t */
-+# include <unistd.h> /* for SEEK_* and off_t */
-+# define z_off_t off_t
-+#endif
-+#ifndef SEEK_SET
-+# define SEEK_SET 0 /* Seek from beginning of file. */
-+# define SEEK_CUR 1 /* Seek from current position. */
-+# define SEEK_END 2 /* Set file pointer to EOF plus "offset" */
-+#endif
-+#ifndef z_off_t
-+# define z_off_t long
-+#endif
-+
-+/* MVS linker does not support external names larger than 8 bytes */
-+#if defined(__MVS__)
-+# pragma map(deflateInit_,"DEIN")
-+# pragma map(deflateInit2_,"DEIN2")
-+# pragma map(deflateEnd,"DEEND")
-+# pragma map(inflateInit_,"ININ")
-+# pragma map(inflateInit2_,"ININ2")
-+# pragma map(inflateEnd,"INEND")
-+# pragma map(inflateSync,"INSY")
-+# pragma map(inflateSetDictionary,"INSEDI")
-+# pragma map(inflate_blocks,"INBL")
-+# pragma map(inflate_blocks_new,"INBLNE")
-+# pragma map(inflate_blocks_free,"INBLFR")
-+# pragma map(inflate_blocks_reset,"INBLRE")
-+# pragma map(inflate_codes_free,"INCOFR")
-+# pragma map(inflate_codes,"INCO")
-+# pragma map(inflate_fast,"INFA")
-+# pragma map(inflate_flush,"INFLU")
-+# pragma map(inflate_mask,"INMA")
-+# pragma map(inflate_set_dictionary,"INSEDI2")
-+# pragma map(ipcomp_inflate_copyright,"INCOPY")
-+# pragma map(inflate_trees_bits,"INTRBI")
-+# pragma map(inflate_trees_dynamic,"INTRDY")
-+# pragma map(inflate_trees_fixed,"INTRFI")
-+# pragma map(inflate_trees_free,"INTRFR")
-+#endif
-+
-+#endif /* _ZCONF_H */
---- /dev/null Tue Mar 11 13:02:56 2003
-+++ linux/lib/zlib/zutil.c Mon Feb 9 13:51:03 2004
-@@ -0,0 +1,227 @@
-+/* zutil.c -- target dependent utility functions for the compression library
-+ * Copyright (C) 1995-2002 Jean-loup Gailly.
-+ * For conditions of distribution and use, see copyright notice in zlib.h
-+ */
-+
-+/* @(#) $Id: zutil.c,v 1.4 2002/04/24 07:55:32 mcr Exp $ */
-+
-+#include <zlib/zutil.h>
-+
-+#define MY_ZCALLOC
-+
-+struct internal_state {int dummy;}; /* for buggy compilers */
-+
-+#ifndef STDC
-+extern void exit OF((int));
-+#endif
-+
-+const char *z_errmsg[10] = {
-+"need dictionary", /* Z_NEED_DICT 2 */
-+"stream end", /* Z_STREAM_END 1 */
-+"", /* Z_OK 0 */
-+"file error", /* Z_ERRNO (-1) */
-+"stream error", /* Z_STREAM_ERROR (-2) */
-+"data error", /* Z_DATA_ERROR (-3) */
-+"insufficient memory", /* Z_MEM_ERROR (-4) */
-+"buffer error", /* Z_BUF_ERROR (-5) */
-+"incompatible version",/* Z_VERSION_ERROR (-6) */
-+""};
-+
-+
-+const char * ZEXPORT zlibVersion()
-+{
-+ return ZLIB_VERSION;
-+}
-+
-+#ifdef DEBUG
-+
-+# ifndef verbose
-+# define verbose 0
-+# endif
-+int z_verbose = verbose;
-+
-+void z_error (m)
-+ char *m;
-+{
-+ fprintf(stderr, "%s\n", m);
-+ exit(1);
-+}
-+#endif
-+
-+/* exported to allow conversion of error code to string for compress() and
-+ * uncompress()
-+ */
-+const char * ZEXPORT zError(err)
-+ int err;
-+{
-+ return ERR_MSG(err);
-+}
-+
-+
-+#ifndef HAVE_MEMCPY
-+
-+void zmemcpy(dest, source, len)
-+ Bytef* dest;
-+ const Bytef* source;
-+ uInt len;
-+{
-+ if (len == 0) return;
-+ do {
-+ *dest++ = *source++; /* ??? to be unrolled */
-+ } while (--len != 0);
-+}
-+
-+int zmemcmp(s1, s2, len)
-+ const Bytef* s1;
-+ const Bytef* s2;
-+ uInt len;
-+{
-+ uInt j;
-+
-+ for (j = 0; j < len; j++) {
-+ if (s1[j] != s2[j]) return 2*(s1[j] > s2[j])-1;
-+ }
-+ return 0;
-+}
-+
-+void zmemzero(dest, len)
-+ Bytef* dest;
-+ uInt len;
-+{
-+ if (len == 0) return;
-+ do {
-+ *dest++ = 0; /* ??? to be unrolled */
-+ } while (--len != 0);
-+}
-+#endif
-+
-+#ifdef __TURBOC__
-+#if (defined( __BORLANDC__) || !defined(SMALL_MEDIUM)) && !defined(__32BIT__)
-+/* Small and medium model in Turbo C are for now limited to near allocation
-+ * with reduced MAX_WBITS and MAX_MEM_LEVEL
-+ */
-+# define MY_ZCALLOC
-+
-+/* Turbo C malloc() does not allow dynamic allocation of 64K bytes
-+ * and farmalloc(64K) returns a pointer with an offset of 8, so we
-+ * must fix the pointer. Warning: the pointer must be put back to its
-+ * original form in order to free it, use zcfree().
-+ */
-+
-+#define MAX_PTR 10
-+/* 10*64K = 640K */
-+
-+local int next_ptr = 0;
-+
-+typedef struct ptr_table_s {
-+ voidpf org_ptr;
-+ voidpf new_ptr;
-+} ptr_table;
-+
-+local ptr_table table[MAX_PTR];
-+/* This table is used to remember the original form of pointers
-+ * to large buffers (64K). Such pointers are normalized with a zero offset.
-+ * Since MSDOS is not a preemptive multitasking OS, this table is not
-+ * protected from concurrent access. This hack doesn't work anyway on
-+ * a protected system like OS/2. Use Microsoft C instead.
-+ */
-+
-+voidpf zcalloc (voidpf opaque, unsigned items, unsigned size)
-+{
-+ voidpf buf = opaque; /* just to make some compilers happy */
-+ ulg bsize = (ulg)items*size;
-+
-+ /* If we allocate less than 65520 bytes, we assume that farmalloc
-+ * will return a usable pointer which doesn't have to be normalized.
-+ */
-+ if (bsize < 65520L) {
-+ buf = farmalloc(bsize);
-+ if (*(ush*)&buf != 0) return buf;
-+ } else {
-+ buf = farmalloc(bsize + 16L);
-+ }
-+ if (buf == NULL || next_ptr >= MAX_PTR) return NULL;
-+ table[next_ptr].org_ptr = buf;
-+
-+ /* Normalize the pointer to seg:0 */
-+ *((ush*)&buf+1) += ((ush)((uch*)buf-0) + 15) >> 4;
-+ *(ush*)&buf = 0;
-+ table[next_ptr++].new_ptr = buf;
-+ return buf;
-+}
-+
-+void zcfree (voidpf opaque, voidpf ptr)
-+{
-+ int n;
-+ if (*(ush*)&ptr != 0) { /* object < 64K */
-+ farfree(ptr);
-+ return;
-+ }
-+ /* Find the original pointer */
-+ for (n = 0; n < next_ptr; n++) {
-+ if (ptr != table[n].new_ptr) continue;
-+
-+ farfree(table[n].org_ptr);
-+ while (++n < next_ptr) {
-+ table[n-1] = table[n];
-+ }
-+ next_ptr--;
-+ return;
-+ }
-+ ptr = opaque; /* just to make some compilers happy */
-+ Assert(0, "zcfree: ptr not found");
-+}
-+#endif
-+#endif /* __TURBOC__ */
-+
-+
-+#if defined(M_I86) && !defined(__32BIT__)
-+/* Microsoft C in 16-bit mode */
-+
-+# define MY_ZCALLOC
-+
-+#if (!defined(_MSC_VER) || (_MSC_VER <= 600))
-+# define _halloc halloc
-+# define _hfree hfree
-+#endif
-+
-+voidpf zcalloc (voidpf opaque, unsigned items, unsigned size)
-+{
-+ if (opaque) opaque = 0; /* to make compiler happy */
-+ return _halloc((long)items, size);
-+}
-+
-+void zcfree (voidpf opaque, voidpf ptr)
-+{
-+ if (opaque) opaque = 0; /* to make compiler happy */
-+ _hfree(ptr);
-+}
-+
-+#endif /* MSC */
-+
-+
-+#ifndef MY_ZCALLOC /* Any system without a special alloc function */
-+
-+#ifndef STDC
-+extern voidp calloc OF((uInt items, uInt size));
-+extern void free OF((voidpf ptr));
-+#endif
-+
-+voidpf zcalloc (opaque, items, size)
-+ voidpf opaque;
-+ unsigned items;
-+ unsigned size;
-+{
-+ if (opaque) items += size - size; /* make compiler happy */
-+ return (voidpf)calloc(items, size);
-+}
-+
-+void zcfree (opaque, ptr)
-+ voidpf opaque;
-+ voidpf ptr;
-+{
-+ free(ptr);
-+ if (opaque) return; /* make compiler happy */
-+}
-+
-+#endif /* MY_ZCALLOC */
---- linux/net/Config.in.orig Fri Feb 9 14:34:13 2001
-+++ linux/net/Config.in Thu Feb 22 19:40:08 2001
-@@ -88,4 +88,9 @@
- #bool 'Network code profiler' CONFIG_NET_PROFILE
- endmenu
-
-+tristate 'IP Security Protocol (FreeS/WAN IPSEC)' CONFIG_IPSEC
-+if [ "$CONFIG_IPSEC" != "n" ]; then
-+ source net/ipsec/Config.in
-+fi
-+
- endmenu
-RCSID $Id: Makefile.fs2_4.patch,v 1.7 2002/07/28 23:12:39 mcr Exp $
---- linux/net/Makefile.preipsec Mon Jun 11 22:15:27 2001
-+++ linux/net/Makefile Tue Nov 6 21:07:43 2001
-@@ -17,6 +17,7 @@
- subdir-$(CONFIG_NET) += 802 sched
- subdir-$(CONFIG_INET) += ipv4
- subdir-$(CONFIG_NETFILTER) += ipv4/netfilter
-+subdir-$(CONFIG_IPSEC) += ipsec
- subdir-$(CONFIG_UNIX) += unix
- subdir-$(CONFIG_IPV6) += ipv6
-
---- /dev/null Tue Mar 11 13:02:56 2003
-+++ linux/net/ipsec/Config.in Mon Feb 9 13:51:03 2004
-@@ -0,0 +1,76 @@
-+#
-+# IPSEC configuration
-+# Copyright (C) 1998, 1999, 2000,2001 Richard Guy Briggs.
-+#
-+# 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. See <http://www.fsf.org/copyleft/gpl.txt>.
-+#
-+# 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.
-+#
-+# RCSID $Id: Config.in,v 1.30 2004/06/23 09:49:37 ken Exp $
-+
-+comment 'IPSec options (Openswan)'
-+
-+bool ' IPSEC: IP-in-IP encapsulation (tunnel mode)' CONFIG_IPSEC_IPIP
-+
-+bool ' IPSEC: Authentication Header' CONFIG_IPSEC_AH
-+if [ "$CONFIG_IPSEC_AH" = "y" -o "$CONFIG_IPSEC_ESP" = "y" ]; then
-+ bool ' HMAC-MD5 authentication algorithm' CONFIG_IPSEC_AUTH_HMAC_MD5
-+ bool ' HMAC-SHA1 authentication algorithm' CONFIG_IPSEC_AUTH_HMAC_SHA1
-+fi
-+
-+bool ' IPSEC: Encapsulating Security Payload' CONFIG_IPSEC_ESP
-+if [ "$CONFIG_IPSEC_ESP" = "y" ]; then
-+ bool ' 3DES encryption algorithm' CONFIG_IPSEC_ENC_3DES
-+ bool ' AES encryption algorithm' CONFIG_IPSEC_ENC_AES
-+fi
-+
-+bool ' IPSEC Modular Extensions' CONFIG_IPSEC_ALG
-+if [ "$CONFIG_IPSEC_ALG" != "n" ]; then
-+ source net/ipsec/alg/Config.in
-+fi
-+
-+bool ' IPSEC: IP Compression' CONFIG_IPSEC_IPCOMP
-+
-+bool ' IPSEC Debugging Option' CONFIG_IPSEC_DEBUG
-+
-+#
-+#
-+# $Log: Config.in,v $
-+# Revision 1.30 2004/06/23 09:49:37 ken
-+# Free -> Open
-+#
-+# Revision 1.29 2004/04/06 02:49:25 mcr
-+# pullup of algo code from alg-branch.
-+#
-+# Revision 1.28 2004/02/03 03:12:26 mcr
-+# remove NAT-traversal option from IPsec config,
-+# as it should be in the kernel configuration if
-+# the NAT-T patch is installed.
-+#
-+# Revision 1.27.2.2 2004/04/05 04:30:46 mcr
-+# patches for alg-branch to compile/work with 2.x openswan
-+#
-+# Revision 1.27.2.1 2003/12/23 12:48:25 jjo
-+# Added missing alg part to linux/net/ipsec/Config.in
-+#
-+# Revision 1.27 2003/12/10 01:14:27 mcr
-+# NAT-traversal patches to KLIPS.
-+#
-+# Revision 1.26 2002/04/24 07:36:26 mcr
-+# Moved from ./klips/net/ipsec/Config.in,v
-+#
-+# Revision 1.25 2002/02/21 19:55:12 mcr
-+# removed all traces of IPSEC_CONFIG_REGRESS because it
-+# screwed up 2.2's "make menuconfig" scripts.
-+#
-+# Revision 1.24 2002/01/28 20:24:31 mcr
-+# commented out IPSEC_REGRESS option from user visible config.
-+#
-+#
-+
---- /dev/null Tue Mar 11 13:02:56 2003
-+++ linux/net/ipsec/Makefile Mon Feb 9 13:51:03 2004
-@@ -0,0 +1,337 @@
-+# Makefile for KLIPS kernel code as a module
-+# Copyright (C) 1998, 1999, 2000,2001 Richard Guy Briggs.
-+# Copyright (C) 2002 Michael Richardson <mcr@freeswan.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. See <http://www.fsf.org/copyleft/gpl.txt>.
-+#
-+# 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.
-+#
-+# RCSID $Id: Makefile,v 1.72 2004/06/22 14:44:07 ken Exp $
-+#
-+# 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).
-+#
-+
-+ifeq ($(strip $(KLIPSMODULE)),)
-+OPENSWANSRCDIR=.
-+else
-+OPENSWANSRCDIR=../../..
-+endif
-+-include ${OPENSWANSRCDIR}/Makefile.ver
-+
-+ifeq ($(strip $(KLIPS_TOP)),)
-+KLIPS_TOP=../..
-+endif
-+
-+ifneq ($(strip $(KLIPSMODULE)),)
-+
-+ifndef TOPDIR
-+TOPDIR:=/usr/src/linux
-+endif
-+export TOPDIR
-+
-+endif
-+
-+#
-+# This magic from User-Mode-Linux list. It gets list of -I options, as
-+# UML needs some extra, that varry by revision.
-+#
-+KERNEL_CFLAGS= $(shell $(MAKE) -C $(TOPDIR) --no-print-directory -s -f Makefile ARCH=$(ARCH) MAKEFLAGS= script SCRIPT='@echo $$(CFLAGS)' )
-+
-+MODULE_CFLAGS= $(shell $(MAKE) -C $(TOPDIR) --no-print-directory -s -f Makefile ARCH=$(ARCH) MAKEFLAGS= script SCRIPT='@echo $$(MODFLAGS)' )
-+
-+subdir- :=
-+subdir-n :=
-+subdir-y :=
-+subdir-m :=
-+
-+
-+MOD_DESTDIR:=net/ipsec
-+
-+export TOPDIR
-+
-+all: ipsec.o
-+
-+foo:
-+ echo KERNEL: ${KERNEL_CFLAGS}
-+ echo MODULE: ${MODULE_CFLAGS}
-+
-+ipsec.o: foo
-+
-+O_TARGET := ipsec.o
-+obj-y := ipsec_init.o ipsec_sa.o ipsec_radij.o radij.o
-+obj-y += ipsec_life.o ipsec_proc.o
-+obj-y += ipsec_tunnel.o ipsec_xmit.o ipsec_rcv.o ipsec_ipip.o
-+obj-y += sysctl_net_ipsec.o
-+obj-y += pfkey_v2.o pfkey_v2_parser.o pfkey_v2_ext_process.o
-+obj-y += version.o
-+obj-$(CONFIG_IPSEC_AH) += ipsec_ah.o
-+obj-$(CONFIG_IPSEC_ESP) += ipsec_esp.o
-+obj-$(CONFIG_IPSEC_IPCOMP)+= ipsec_ipcomp.o
-+
-+CFLAGS_ipsec_alg.o += -DEXPORT_SYMTAB
-+obj-$(CONFIG_IPSEC_ALG) += ipsec_alg.o
-+obj-$(CONFIG_IPSEC_ENC_AES) += ipsec_alg_aes.o
-+obj-$(CONFIG_IPSEC_ENC_CRYPTOAPI) += ipsec_alg_cryptoapi.o
-+
-+export-objs += ipsec_alg.o
-+
-+
-+LIBDESDIR=${KLIPS_TOP}/crypto/ciphers/des
-+VPATH+= ${LIBDESDIR}
-+
-+include ${LIBDESDIR}/Makefile.objs
-+
-+LIBFREESWANDIR=${KLIPS_TOP}/lib/libfreeswan
-+VPATH+=${LIBFREESWANDIR}
-+
-+include ${LIBFREESWANDIR}/Makefile.objs
-+
-+# IPcomp stuff
-+obj-$(CONFIG_IPSEC_IPCOMP) += ipcomp.o
-+
-+LIBZLIBSRCDIR=${KLIPS_TOP}/lib/zlib
-+VPATH+=${LIBZLIBSRCDIR}
-+
-+LIBAESDIR=$(KLIPS_TOP)/crypto/ciphers/aes
-+VPATH+=${LIBAESDIR}
-+include ${LIBAESDIR}/Makefile.objs
-+
-+# CFLAGS='$(CFLAGS)' \
-+# MODULE_CFLAGS='$(MODULE_CFLAGS)' KERNEL_CFLAGS='$(KERNEL_CFLAGS)' \
-+#
-+include ${LIBZLIBSRCDIR}/Makefile.objs
-+
-+export-objs := radij.o
-+
-+EXTRA_CFLAGS += $(ALGO_FLAGS)
-+
-+
-+# include file with .h-style macros that would otherwise be created by
-+# config. Must occur before other includes.
-+ifneq ($(strip $(MODULE_DEF_INCLUDE)),)
-+EXTRA_CFLAGS += -include ${MODULE_DEF_INCLUDE}
-+endif
-+
-+# 'override CFLAGS' should really be 'EXTRA_CFLAGS'
-+#EXTRA_CFLAGS += -nostdinc
-+EXTRA_CFLAGS += -I${KLIPS_TOP}/include
-+
-+EXTRA_CFLAGS += -I${TOPDIR}/include
-+EXTRA_CFLAGS += -I${LIBZLIBSRCDIR}
-+
-+ifeq ($(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION),2.4.2-2)
-+EXTRA_CFLAGS += -DREDHAT_BOGOSITY
-+endif
-+
-+ifeq ($(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION),2.4.3-12)
-+EXTRA_CFLAGS += -DREDHAT_BOGOSITY
-+endif
-+
-+
-+#ifeq ($(CONFIG_IPSEC_DEBUG),y)
-+#EXTRA_CFLAGS += -g
-+#endif
-+
-+#ifeq ($(CONFIG_IPSEC_ALG), y)
-+EXTRA_CFLAGS += -DCONFIG_IPSEC_ALG
-+#endif
-+# MOST of these flags are in KERNEL_CFLAGS already!
-+
-+EXTRA_CFLAGS += $(KLIPSCOMPILE)
-+EXTRA_CFLAGS += -Wall
-+#EXTRA_CFLAGS += -Werror
-+#EXTRA_CFLAGS += -Wconversion
-+#EXTRA_CFLAGS += -Wmissing-prototypes
-+# cannot use both -Wpointer-arith and -Werror with CONFIG_HIGHMEM
-+# include/linux/highmem.h has an inline function definition that uses void* arithmentic.
-+ifeq ($(CONFIG_NOHIGHMEM),y)
-+EXTRA_CFLAGS += -Wpointer-arith
-+endif
-+#EXTRA_CFLAGS += -Wcast-qual
-+#EXTRA_CFLAGS += -Wmissing-declarations
-+#EXTRA_CFLAGS += -Wstrict-prototypes
-+#EXTRA_CFLAGS += -pedantic
-+#EXTRA_CFLAGS += -O3
-+#EXTRA_CFLAGS += -W
-+#EXTRA_CFLAGS += -Wwrite-strings
-+#EXTRA_CFLAGS += -Wbad-function-cast
-+
-+ifneq ($(strip $(KLIPSMODULE)),)
-+# for when we aren't building in the kernel tree
-+EXTRA_CFLAGS += -DARCH=${ARCH}
-+EXTRA_CFLAGS += -DMODVERSIONS
-+EXTRA_CFLAGS += -include ${TOPDIR}/include/linux/modversions.h
-+EXTRA_CFLAGS += ${MODULE_CFLAGS}
-+endif
-+
-+EXTRA_CFLAGS += ${KERNEL_CFLAGS}
-+
-+#EXTRA_CFLAGS += -DRJ_DEBUG -DRJ_DEBUG2
-+
-+
-+# GCC 3.2 (and we presume any other 3.x) wants -falign-functions
-+# in place of the traditional -malign-functions. Getting this
-+# wrong leads to a warning, which is fatal due to our use of -Werror.
-+ifeq ($(patsubst 3.%,3,$(shell $(CC) -dumpversion)),3)
-+override CFLAGS:=$(subst -malign-functions=,-falign-functions=,$(CFLAGS))
-+endif
-+
-+
-+obj-$(CONFIG_IPSEC_AUTH_HMAC_MD5) += ipsec_md5c.o
-+obj-$(CONFIG_IPSEC_AUTH_HMAC_SHA1) += ipsec_sha1.o
-+
-+###
-+### Pre Rules.make
-+###
-+# undo O_TARGET, obj-y if no static
-+ifneq ($(CONFIG_IPSEC),y)
-+O_TARGET :=
-+ipsec_obj-y := $(obj-y)
-+obj-y :=
-+subdir-y :=
-+endif
-+
-+# Define obj-m if modular ipsec
-+ifeq ($(CONFIG_IPSEC),m)
-+obj-m += ipsec.o
-+endif
-+
-+
-+# These rules translate from new to old makefile rules
-+# Translate to Rules.make lists.
-+multi-used := $(filter $(list-multi), $(obj-y) $(obj-m))
-+multi-objs := $(foreach m, $(multi-used), $($(basename $(m))-objs))
-+active-objs := $(sort $(multi-objs) $(obj-y) $(obj-m))
-+O_OBJS := $(obj-y)
-+M_OBJS := $(obj-m)
-+MIX_OBJS := $(filter $(export-objs), $(active-objs))
-+OX_OBJS := $(export-objs)
-+SUB_DIRS := $(subdir-y)
-+ALL_SUB_DIRS := $(subdir-y) $(subdir-m)
-+MOD_SUB_DIRS := $(subdir-m)
-+
-+# dunno why, but some 2.2 setups may need explicit -DEXPORT_SYMTAB
-+# uncomment next line if ipsec_alg.c compilation fails with
-+# "parse error before `EXPORT_SYMTAB_not_defined'" --Juanjo
-+
-+include $(TOPDIR)/Rules.make
-+
-+###
-+### Post Rules.make
-+###
-+# for modular ipsec, no O_TARGET defined => define ipsec.o creation rules
-+ifeq ($(CONFIG_IPSEC),m)
-+ipsec.o : $(ipsec_obj-y)
-+ rm -f $@
-+ $(LD) $(LD_EXTRAFLAGS) -r $(ipsec_obj-y) -o $@
-+endif
-+
-+$(ipsec_obj-y) $(obj-y) $(obj-m): $(TOPDIR)/include/linux/config.h $(TOPDIR)/include/linux/autoconf.h
-+
-+#$(obj-y) $(obj-m): $(TOPDIR)/include/linux/config.h $(TOPDIR)/include/linux/autoconf.h
-+
-+USE_STANDARD_AS_RULE=true
-+
-+clean:
-+ $(MAKE) -C alg clean
-+ -rm -f *.o
-+ -rm -f .*.o.flags
-+ -rm -f version.c
-+
-+tags TAGS: *.c *.h libfreeswan/*.c libfreeswan/*.h
-+ etags *.c ../../include/*.h ../../include/freeswan/*.h
-+ ctags *.c ../../include/*.h ../../include/freeswan/*.h
-+
-+tar:
-+ tar -cvf /dev/f1 .
-+
-+#
-+# $Log: Makefile,v $
-+# Revision 1.72 2004/06/22 14:44:07 ken
-+# Merge nice version of Nate's CryptoAPI patch
-+#
-+# Revision 1.71 2004/04/18 03:04:21 mcr
-+# removed duplicate version.o reference.
-+#
-+# Revision 1.70 2004/04/14 05:09:39 ken
-+# We need to link version.o
-+#
-+# Revision 1.69 2004/04/12 04:02:39 ken
-+# version.o no longer exists
-+#
-+# Revision 1.68 2004/04/11 17:08:41 mcr
-+# moved PASSTHROUGH definitions to openswan.h
-+# requirement for internal.h removed.
-+# version.c is now generated by patch at patch-time.
-+#
-+# Revision 1.67 2004/04/06 02:49:25 mcr
-+# pullup of algo code from alg-branch.
-+#
-+# Revision 1.66 2004/04/03 19:44:41 ken
-+# FREESWANSRCDIR -> OPENSWANSRCDIR (patch by folken)
-+#
-+# Revision 1.65 2004/02/09 16:22:07 paul
-+# Added -f to rm version.c in clean target to prevent bogus error
-+#
-+# Revision 1.64 2003/12/22 19:40:57 mcr
-+# NAT-T patches 0.6c.
-+#
-+# Revision 1.63 2003/12/13 19:10:21 mcr
-+# refactored rcv and xmit code - same as FS 2.05.
-+#
-+# Revision 1.62.4.2 2004/04/05 04:30:46 mcr
-+# patches for alg-branch to compile/work with 2.x openswan
-+#
-+# Revision 1.62.4.1 2003/12/22 15:25:52 jjo
-+# Merged algo-0.8.1-rc11-test1 into alg-branch
-+#
-+# Revision 1.62 2003/10/31 02:27:55 mcr
-+# pulled up port-selector patches and sa_id elimination.
-+#
-+# Revision 1.61.4.1 2003/10/29 01:30:41 mcr
-+# elimited "struct sa_id".
-+#
-+# Revision 1.61 2003/06/22 21:07:46 mcr
-+# adjusted TAGS target in makefile to be useful in 2.00 source layout.
-+#
-+# Revision 1.60 2003/05/03 23:45:23 mcr
-+# rm .o.flags and generated version.c file.
-+#
-+# Revision 1.59 2003/02/12 19:32:47 rgb
-+# Added ipsec_xmit to the list of object files.
-+#
-+# Revision 1.58 2003/01/03 00:36:44 rgb
-+#
-+# Added emacs compile-command.
-+#
-+# Revision 1.57 2002/11/08 23:49:53 mcr
-+# use KERNEL_CFLAGS and MODULE_CFLAGS to get proper list
-+# of include directories.
-+# This also eliminates some of the guesswork in the kernel
-+# configuration file.
-+#
-+# Revision 1.56 2002/11/08 23:23:18 mcr
-+# attempt to guess kernel compilation flags (i.e. list of -I)
-+# by using some magic targets in the kernel makefile.
-+#
-+# Revision 1.55 2002/11/08 10:13:33 mcr
-+# added additional include directories for module builds for 2.4.19.
-+#
-+# Revision 1.54 2002/10/20 06:10:30 build
-+# CONFIG_NOHIGHMEM for -Wpointer-arith RPM building issues.
-+#
-+# (elided rest of log)
-+#
-+# Local Variables:
-+# compile-command: "(cd ../../.. && source umlsetup.sh && make -C ${POOLSPACE} module/ipsec.o)"
-+# End Variables:
-+#
-+
---- /dev/null Tue Mar 11 13:02:56 2003
-+++ linux/net/ipsec/alg/Config.alg_aes.in Mon Feb 9 13:51:03 2004
-@@ -0,0 +1,3 @@
-+if [ "$CONFIG_IPSEC_ALG" = "y" ]; then
-+ tristate ' AES encryption algorithm' CONFIG_IPSEC_ALG_AES
-+fi
---- /dev/null Tue Mar 11 13:02:56 2003
-+++ linux/net/ipsec/alg/Config.alg_cryptoapi.in Mon Feb 9 13:51:03 2004
-@@ -0,0 +1,6 @@
-+if [ "$CONFIG_IPSEC_ALG" = "y" ]; then
-+ dep_tristate ' CRYPTOAPI ciphers support (needs cryptoapi patch)' CONFIG_IPSEC_ALG_CRYPTOAPI $CONFIG_CRYPTO
-+ if [ "$CONFIG_IPSEC_ALG_CRYPTOAPI" != "n" ]; then
-+ bool ' CRYPTOAPI proprietary ciphers ' CONFIG_IPSEC_ALG_NON_LIBRE
-+ fi
-+fi
---- /dev/null Tue Mar 11 13:02:56 2003
-+++ linux/net/ipsec/alg/Config.in Mon Feb 9 13:51:03 2004
-@@ -0,0 +1,3 @@
-+#Placeholder
-+source net/ipsec/alg/Config.alg_aes.in
-+source net/ipsec/alg/Config.alg_cryptoapi.in
---- /dev/null Tue Mar 11 13:02:56 2003
-+++ linux/net/ipsec/alg/Makefile Mon Feb 9 13:51:03 2004
-@@ -0,0 +1,112 @@
-+# Makefile,v 1.1.2.1 2003/11/21 18:12:23 jjo Exp
-+ifeq ($(strip $(KLIPSMODULE)),)
-+FREESWANSRCDIR=.
-+else
-+FREESWANSRCDIR=../../../..
-+endif
-+ifeq ($(strip $(KLIPS_TOP)),)
-+KLIPS_TOP=../../..
-+override EXTRA_CFLAGS += -I$(KLIPS_TOP)/include
-+endif
-+
-+ifeq ($(CONFIG_IPSEC_DEBUG),y)
-+override EXTRA_CFLAGS += -g
-+endif
-+
-+# LIBCRYPTO normally comes as an argument from "parent" Makefile
-+# (this applies both to FS' "make module" and eg. Linux' "make modules"
-+# But make dep doest follow same evaluations, so we need this default:
-+LIBCRYPTO=$(TOPDIR)/lib/libcrypto
-+
-+override EXTRA_CFLAGS += -I$(LIBCRYPTO)/include
-+override EXTRA_CFLAGS += -Wall -Wpointer-arith -Wstrict-prototypes
-+
-+MOD_LIST_NAME := NET_MISC_MODULES
-+
-+#O_TARGET := static_init.o
-+
-+subdir- :=
-+subdir-n :=
-+subdir-y :=
-+subdir-m :=
-+
-+obj-y := static_init.o
-+
-+ARCH_ASM-y :=
-+ARCH_ASM-$(CONFIG_M586) := i586
-+ARCH_ASM-$(CONFIG_M586TSC) := i586
-+ARCH_ASM-$(CONFIG_M586MMX) := i586
-+ARCH_ASM-$(CONFIG_MK6) := i586
-+ARCH_ASM-$(CONFIG_M686) := i686
-+ARCH_ASM-$(CONFIG_MPENTIUMIII) := i686
-+ARCH_ASM-$(CONFIG_MPENTIUM4) := i686
-+ARCH_ASM-$(CONFIG_MK7) := i686
-+ARCH_ASM-$(CONFIG_MCRUSOE) := i586
-+ARCH_ASM-$(CONFIG_MWINCHIPC6) := i586
-+ARCH_ASM-$(CONFIG_MWINCHIP2) := i586
-+ARCH_ASM-$(CONFIG_MWINCHIP3D) := i586
-+ARCH_ASM-$(CONFIG_USERMODE) := i586
-+
-+ARCH_ASM :=$(ARCH_ASM-y)
-+ifdef NO_ASM
-+ARCH_ASM :=
-+endif
-+
-+# The algorithm makefiles may put dependences, short-circuit them
-+null:
-+
-+makefiles=$(filter-out %.preipsec, $(wildcard Makefile.alg_*))
-+ifneq ($(makefiles),)
-+#include Makefile.alg_aes
-+#include Makefile.alg_aes-opt
-+include $(makefiles)
-+endif
-+
-+# These rules translate from new to old makefile rules
-+# Translate to Rules.make lists.
-+multi-used := $(filter $(list-multi), $(obj-y) $(obj-m))
-+multi-objs := $(foreach m, $(multi-used), $($(basename $(m))-objs))
-+active-objs := $(sort $(multi-objs) $(obj-y) $(obj-m))
-+O_OBJS := $(obj-y)
-+M_OBJS := $(obj-m)
-+MIX_OBJS := $(filter $(export-objs), $(active-objs))
-+#OX_OBJS := $(export-objs)
-+SUB_DIRS := $(subdir-y)
-+ALL_SUB_DIRS := $(subdir-y) $(subdir-m)
-+MOD_SUB_DIRS := $(subdir-m)
-+
-+
-+static_init_mod.o: $(obj-y)
-+ rm -f $@
-+ $(LD) $(LD_EXTRAFLAGS) $(obj-y) -r -o $@
-+
-+perlasm: $(LIBCRYPTO)/perlasm
-+ ln -sf $? $@
-+
-+$(obj-y) $(obj-m): $(TOPDIR)/include/linux/config.h $(TOPDIR)/include/linux/autoconf.h $(KLIPS_TOP)/include/freeswan/ipsec_alg.h
-+$(alg_obj-y) $(alg_obj-m): perlasm $(TOPDIR)/include/linux/config.h $(TOPDIR)/include/linux/autoconf.h $(KLIPS_TOP)/include/freeswan/ipsec_alg.h
-+
-+
-+all_alg_modules: perlasm $(ALG_MODULES)
-+ @echo "ALG_MODULES=$(ALG_MODULES)"
-+
-+
-+#
-+# Construct alg. init. function: call ipsec_ALGO_init() for every static algo
-+# Needed when there are static algos (with static or modular ipsec.o)
-+#
-+static_init.c: $(TOPDIR)/include/linux/autoconf.h Makefile $(makefiles) scripts/mk-static_init.c.sh
-+ @echo "Re-creating $@"
-+ $(SHELL) scripts/mk-static_init.c.sh $(static_init-func-y) > $@
-+
-+clean:
-+ @for i in $(ALG_SUBDIRS);do test -d $$i && make -C $$i clean;done;exit 0
-+ @find . -type l -exec rm -f {} \;
-+ -rm -f perlasm
-+ -rm -rf $(ALG_SUBDIRS)
-+ -rm -f *.o static_init.c
-+
-+ifdef TOPDIR
-+include $(TOPDIR)/Rules.make
-+endif
-+
---- /dev/null Tue Mar 11 13:02:56 2003
-+++ linux/net/ipsec/alg/Makefile.alg_aes Mon Feb 9 13:51:03 2004
-@@ -0,0 +1,23 @@
-+MOD_AES := ipsec_aes.o
-+
-+ALG_MODULES += $(MOD_AES)
-+ALG_SUBDIRS += libaes
-+
-+obj-$(CONFIG_IPSEC_ALG_AES) += $(MOD_AES)
-+static_init-func-$(CONFIG_IPSEC_ALG_AES)+= ipsec_aes_init
-+alg_obj-$(CONFIG_IPSEC_ALG_AES) += ipsec_alg_aes.o
-+
-+AES_OBJS := ipsec_alg_aes.o libaes/libaes.a
-+
-+$(MOD_AES): libaes $(AES_OBJS)
-+ $(LD) $(EXTRA_LDFLAGS) -r $(AES_OBJS) -o $@
-+
-+libaes: $(LIBCRYPTO)/libaes
-+ test -d $@ || mkdir $@ ;exit 0
-+ test -d $@/asm || mkdir $@/asm;exit 0
-+ cd $@ && ln -sf $?/Makefile $?/*.[chS] .
-+ cd $@/asm && ln -sf $?/asm/*.S .
-+
-+libaes/libaes.a: libaes
-+ ( cd libaes && \
-+ $(MAKE) CC='$(CC)' 'ARCH_ASM=$(ARCH_ASM)' CFLAGS='$(CFLAGS) $(EXTRA_CFLAGS)' libaes.a ;)
---- /dev/null Tue Mar 11 13:02:56 2003
-+++ linux/net/ipsec/alg/Makefile.alg_cryptoapi Mon Feb 9 13:51:03 2004
-@@ -0,0 +1,14 @@
-+MOD_CRYPTOAPI := ipsec_cryptoapi.o
-+
-+ifneq ($(wildcard $(TOPDIR)/include/linux/crypto.h),)
-+ALG_MODULES += $(MOD_CRYPTOAPI)
-+obj-$(CONFIG_IPSEC_ALG_CRYPTOAPI) += $(MOD_CRYPTOAPI)
-+static_init-func-$(CONFIG_IPSEC_ALG_CRYPTOAPI)+= ipsec_cryptoapi_init
-+alg_obj-$(CONFIG_IPSEC_ALG_CRYPTOAPI) += ipsec_alg_cryptoapi.o
-+else
-+$(warning "Linux CryptoAPI (2.4.22+ or 2.6.x) not found, not building ipsec_cryptoapi.o")
-+endif
-+
-+CRYPTOAPI_OBJS := ipsec_alg_cryptoapi.o
-+$(MOD_CRYPTOAPI): $(CRYPTOAPI_OBJS)
-+ $(LD) -r $(CRYPTOAPI_OBJS) -o $@
---- /dev/null Tue Mar 11 13:02:56 2003
-+++ linux/net/ipsec/alg/ipsec_alg_aes.c Mon Feb 9 13:51:03 2004
-@@ -0,0 +1,253 @@
-+/*
-+ * ipsec_alg AES cipher stubs
-+ *
-+ * Author: JuanJo Ciarlante <jjo-ipsec@mendoza.gov.ar>
-+ *
-+ * ipsec_alg_aes.c,v 1.1.2.1 2003/11/21 18:12:23 jjo Exp
-+ *
-+ * 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. See <http://www.fsf.org/copyleft/gpl.txt>.
-+ *
-+ * 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.
-+ *
-+ * Fixes by:
-+ * PK: Pawel Krawczyk <kravietz@aba.krakow.pl>
-+ * Fixes list:
-+ * PK: make XCBC comply with latest draft (keylength)
-+ *
-+ */
-+#include <linux/config.h>
-+#include <linux/version.h>
-+
-+/*
-+ * special case: ipsec core modular with this static algo inside:
-+ * must avoid MODULE magic for this file
-+ */
-+#if CONFIG_IPSEC_MODULE && CONFIG_IPSEC_ALG_AES
-+#undef MODULE
-+#endif
-+
-+#include <linux/module.h>
-+#include <linux/init.h>
-+
-+#include <linux/kernel.h> /* printk() */
-+#include <linux/errno.h> /* error codes */
-+#include <linux/types.h> /* size_t */
-+#include <linux/string.h>
-+
-+/* Check if __exit is defined, if not null it */
-+#ifndef __exit
-+#define __exit
-+#endif
-+
-+/* Low freeswan header coupling */
-+#include "freeswan/ipsec_alg.h"
-+#include "libaes/aes_cbc.h"
-+
-+#define CONFIG_IPSEC_ALG_AES_MAC 1
-+
-+#define AES_CONTEXT_T aes_context
-+MODULE_AUTHOR("JuanJo Ciarlante <jjo-ipsec@mendoza.gov.ar>");
-+static int debug=0;
-+MODULE_PARM(debug, "i");
-+static int test=0;
-+MODULE_PARM(test, "i");
-+static int excl=0;
-+MODULE_PARM(excl, "i");
-+static int keyminbits=0;
-+MODULE_PARM(keyminbits, "i");
-+static int keymaxbits=0;
-+MODULE_PARM(keymaxbits, "i");
-+
-+#if CONFIG_IPSEC_ALG_AES_MAC
-+#include "libaes/aes_xcbc_mac.h"
-+
-+/*
-+ * Not IANA number yet (draft-ietf-ipsec-ciph-aes-xcbc-mac-00.txt).
-+ * We use 9 for non-modular algorithm and none for modular, thus
-+ * forcing user to specify one on module load. -kravietz
-+ */
-+#ifdef MODULE
-+static int auth_id=0;
-+#else
-+static int auth_id=9;
-+#endif
-+MODULE_PARM(auth_id, "i");
-+#endif
-+
-+#define ESP_AES 12 /* truely _constant_ :) */
-+
-+/* 128, 192 or 256 */
-+#define ESP_AES_KEY_SZ_MIN 16 /* 128 bit secret key */
-+#define ESP_AES_KEY_SZ_MAX 32 /* 256 bit secret key */
-+#define ESP_AES_CBC_BLK_LEN 16 /* AES-CBC block size */
-+
-+/* Values according to draft-ietf-ipsec-ciph-aes-xcbc-mac-02.txt
-+ * -kravietz
-+ */
-+#define ESP_AES_MAC_KEY_SZ 16 /* 128 bit MAC key */
-+#define ESP_AES_MAC_BLK_LEN 16 /* 128 bit block */
-+
-+static int _aes_set_key(struct ipsec_alg_enc *alg, __u8 * key_e, const __u8 * key, size_t keysize) {
-+ int ret;
-+ AES_CONTEXT_T *ctx=(AES_CONTEXT_T*)key_e;
-+ ret=AES_set_key(ctx, key, keysize)!=0? 0: -EINVAL;
-+ if (debug > 0)
-+ printk(KERN_DEBUG "klips_debug:_aes_set_key:"
-+ "ret=%d key_e=%p key=%p keysize=%d\n",
-+ ret, key_e, key, keysize);
-+ return ret;
-+}
-+static int _aes_cbc_encrypt(struct ipsec_alg_enc *alg, __u8 * key_e, __u8 * in, int ilen, const __u8 * iv, int encrypt) {
-+ AES_CONTEXT_T *ctx=(AES_CONTEXT_T*)key_e;
-+ if (debug > 0)
-+ printk(KERN_DEBUG "klips_debug:_aes_cbc_encrypt:"
-+ "key_e=%p in=%p ilen=%d iv=%p encrypt=%d\n",
-+ key_e, in, ilen, iv, encrypt);
-+ return AES_cbc_encrypt(ctx, in, in, ilen, iv, encrypt);
-+}
-+#if CONFIG_IPSEC_ALG_AES_MAC
-+static int _aes_mac_set_key(struct ipsec_alg_auth *alg, __u8 * key_a, const __u8 * key, int keylen) {
-+ aes_context_mac *ctxm=(aes_context_mac *)key_a;
-+ return AES_xcbc_mac_set_key(ctxm, key, keylen)? 0 : -EINVAL;
-+}
-+static int _aes_mac_hash(struct ipsec_alg_auth *alg, __u8 * key_a, const __u8 * dat, int len, __u8 * hash, int hashlen) {
-+ int ret;
-+ char hash_buf[16];
-+ aes_context_mac *ctxm=(aes_context_mac *)key_a;
-+ ret=AES_xcbc_mac_hash(ctxm, dat, len, hash_buf);
-+ memcpy(hash, hash_buf, hashlen);
-+ return ret;
-+}
-+static struct ipsec_alg_auth ipsec_alg_AES_MAC = {
-+ ixt_version: IPSEC_ALG_VERSION,
-+ ixt_module: THIS_MODULE,
-+ ixt_refcnt: ATOMIC_INIT(0),
-+ ixt_alg_type: IPSEC_ALG_TYPE_AUTH,
-+ ixt_alg_id: 0,
-+ ixt_name: "aes_mac",
-+ ixt_blocksize: ESP_AES_MAC_BLK_LEN,
-+ ixt_keyminbits: ESP_AES_MAC_KEY_SZ*8,
-+ ixt_keymaxbits: ESP_AES_MAC_KEY_SZ*8,
-+ ixt_a_keylen: ESP_AES_MAC_KEY_SZ,
-+ ixt_a_ctx_size: sizeof(aes_context_mac),
-+ ixt_a_hmac_set_key: _aes_mac_set_key,
-+ ixt_a_hmac_hash:_aes_mac_hash,
-+};
-+#endif /* CONFIG_IPSEC_ALG_AES_MAC */
-+static struct ipsec_alg_enc ipsec_alg_AES = {
-+ ixt_version: IPSEC_ALG_VERSION,
-+ ixt_module: THIS_MODULE,
-+ ixt_refcnt: ATOMIC_INIT(0),
-+ ixt_alg_type: IPSEC_ALG_TYPE_ENCRYPT,
-+ ixt_alg_id: ESP_AES,
-+ ixt_name: "aes",
-+ ixt_blocksize: ESP_AES_CBC_BLK_LEN,
-+ ixt_keyminbits: ESP_AES_KEY_SZ_MIN*8,
-+ ixt_keymaxbits: ESP_AES_KEY_SZ_MAX*8,
-+ ixt_e_keylen: ESP_AES_KEY_SZ_MAX,
-+ ixt_e_ctx_size: sizeof(AES_CONTEXT_T),
-+ ixt_e_set_key: _aes_set_key,
-+ ixt_e_cbc_encrypt:_aes_cbc_encrypt,
-+};
-+
-+IPSEC_ALG_MODULE_INIT( ipsec_aes_init )
-+{
-+ int ret, test_ret;
-+ if (keyminbits)
-+ ipsec_alg_AES.ixt_keyminbits=keyminbits;
-+ if (keymaxbits) {
-+ ipsec_alg_AES.ixt_keymaxbits=keymaxbits;
-+ if (keymaxbits*8>ipsec_alg_AES.ixt_keymaxbits)
-+ ipsec_alg_AES.ixt_e_keylen=keymaxbits*8;
-+ }
-+ if (excl) ipsec_alg_AES.ixt_state |= IPSEC_ALG_ST_EXCL;
-+ ret=register_ipsec_alg_enc(&ipsec_alg_AES);
-+ printk("ipsec_aes_init(alg_type=%d alg_id=%d name=%s): ret=%d\n",
-+ ipsec_alg_AES.ixt_alg_type,
-+ ipsec_alg_AES.ixt_alg_id,
-+ ipsec_alg_AES.ixt_name,
-+ ret);
-+ if (ret==0 && test) {
-+ test_ret=ipsec_alg_test(
-+ ipsec_alg_AES.ixt_alg_type,
-+ ipsec_alg_AES.ixt_alg_id,
-+ test);
-+ printk("ipsec_aes_init(alg_type=%d alg_id=%d): test_ret=%d\n",
-+ ipsec_alg_AES.ixt_alg_type,
-+ ipsec_alg_AES.ixt_alg_id,
-+ test_ret);
-+ }
-+#if CONFIG_IPSEC_ALG_AES_MAC
-+ if (auth_id!=0){
-+ int ret;
-+ ipsec_alg_AES_MAC.ixt_alg_id=auth_id;
-+ ret=register_ipsec_alg_auth(&ipsec_alg_AES_MAC);
-+ printk("ipsec_aes_init(alg_type=%d alg_id=%d name=%s): ret=%d\n",
-+ ipsec_alg_AES_MAC.ixt_alg_type,
-+ ipsec_alg_AES_MAC.ixt_alg_id,
-+ ipsec_alg_AES_MAC.ixt_name,
-+ ret);
-+ if (ret==0 && test) {
-+ test_ret=ipsec_alg_test(
-+ ipsec_alg_AES_MAC.ixt_alg_type,
-+ ipsec_alg_AES_MAC.ixt_alg_id,
-+ test);
-+ printk("ipsec_aes_init(alg_type=%d alg_id=%d): test_ret=%d\n",
-+ ipsec_alg_AES_MAC.ixt_alg_type,
-+ ipsec_alg_AES_MAC.ixt_alg_id,
-+ test_ret);
-+ }
-+ } else {
-+ printk(KERN_DEBUG "klips_debug: experimental ipsec_alg_AES_MAC not registered [Ok] (auth_id=%d)\n", auth_id);
-+ }
-+#endif /* CONFIG_IPSEC_ALG_AES_MAC */
-+ return ret;
-+}
-+IPSEC_ALG_MODULE_EXIT( ipsec_aes_fini )
-+{
-+#if CONFIG_IPSEC_ALG_AES_MAC
-+ if (auth_id) unregister_ipsec_alg_auth(&ipsec_alg_AES_MAC);
-+#endif /* CONFIG_IPSEC_ALG_AES_MAC */
-+ unregister_ipsec_alg_enc(&ipsec_alg_AES);
-+ return;
-+}
-+#ifdef MODULE_LICENSE
-+MODULE_LICENSE("GPL");
-+#endif
-+
-+#if 0+NOT_YET
-+#ifndef MODULE
-+/*
-+ * This is intended for static module setups, currently
-+ * doesn't work for modular ipsec.o with static algos inside
-+ */
-+static int setup_keybits(const char *str)
-+{
-+ unsigned aux;
-+ char *end;
-+
-+ aux = simple_strtoul(str,&end,0);
-+ if (aux != 128 && aux != 192 && aux != 256)
-+ return 0;
-+ keyminbits = aux;
-+
-+ if (*end == 0 || *end != ',')
-+ return 1;
-+ str=end+1;
-+ aux = simple_strtoul(str, NULL, 0);
-+ if (aux != 128 && aux != 192 && aux != 256)
-+ return 0;
-+ if (aux >= keyminbits)
-+ keymaxbits = aux;
-+ return 1;
-+}
-+__setup("ipsec_aes_keybits=", setup_keybits);
-+#endif
-+#endif
-+EXPORT_NO_SYMBOLS;
---- /dev/null Tue Mar 11 13:02:56 2003
-+++ linux/net/ipsec/alg/ipsec_alg_cryptoapi.c Mon Feb 9 13:51:03 2004
-@@ -0,0 +1,421 @@
-+/*
-+ * ipsec_alg to linux cryptoapi GLUE
-+ *
-+ * Authors: CODE.ar TEAM
-+ * Harpo MAxx <harpo@linuxmendoza.org.ar>
-+ * JuanJo Ciarlante <jjo-ipsec@mendoza.gov.ar>
-+ * Luciano Ruete <docemeses@softhome.net>
-+ *
-+ * ipsec_alg_cryptoapi.c,v 1.1.2.1 2003/11/21 18:12:23 jjo Exp
-+ *
-+ * 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. See <http://www.fsf.org/copyleft/gpl.txt>.
-+ *
-+ * 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.
-+ *
-+ * Example usage:
-+ * modinfo -p ipsec_cryptoapi (quite useful info, including supported algos)
-+ * modprobe ipsec_cryptoapi
-+ * modprobe ipsec_cryptoapi test=1
-+ * modprobe ipsec_cryptoapi excl=1 (exclusive cipher/algo)
-+ * modprobe ipsec_cryptoapi noauto=1 aes=1 twofish=1 (only these ciphers)
-+ * modprobe ipsec_cryptoapi aes=128,128 (force these keylens)
-+ * modprobe ipsec_cryptoapi des_ede3=0 (everything but 3DES)
-+ */
-+#include <linux/config.h>
-+#include <linux/version.h>
-+
-+/*
-+ * special case: ipsec core modular with this static algo inside:
-+ * must avoid MODULE magic for this file
-+ */
-+#if CONFIG_IPSEC_MODULE && CONFIG_IPSEC_ALG_CRYPTOAPI
-+#undef MODULE
-+#endif
-+
-+#include <linux/module.h>
-+#include <linux/init.h>
-+
-+#include <linux/kernel.h> /* printk() */
-+#include <linux/errno.h> /* error codes */
-+#include <linux/types.h> /* size_t */
-+#include <linux/string.h>
-+
-+/* Check if __exit is defined, if not null it */
-+#ifndef __exit
-+#define __exit
-+#endif
-+
-+/* warn the innocent */
-+#if !defined (CONFIG_CRYPTO) && !defined (CONFIG_CRYPTO_MODULE)
-+#warning "No linux CryptoAPI found, install 2.4.22+ or 2.6.x"
-+#define NO_CRYPTOAPI_SUPPORT
-+#endif
-+/* Low freeswan header coupling */
-+#include "freeswan/ipsec_alg.h"
-+
-+#include <linux/crypto.h>
-+#ifdef CRYPTO_API_VERSION_CODE
-+#warning "Old CryptoAPI is not supported. Only linux-2.4.22+ or linux-2.6.x are supported"
-+#define NO_CRYPTOAPI_SUPPORT
-+#endif
-+
-+#ifdef NO_CRYPTOAPI_SUPPORT
-+#warning "Building an unusable module :P"
-+/* Catch old CryptoAPI by not allowing module to load */
-+IPSEC_ALG_MODULE_INIT( ipsec_cryptoapi_init )
-+{
-+ printk(KERN_WARNING "ipsec_cryptoapi.o was not built on stock Linux CryptoAPI (2.4.22+ or 2.6.x), not loading.\n");
-+ return -EINVAL;
-+}
-+#else
-+#include <asm/scatterlist.h>
-+#include <asm/pgtable.h>
-+#include <linux/mm.h>
-+
-+#define CIPHERNAME_AES "aes"
-+#define CIPHERNAME_3DES "des3_ede"
-+#define CIPHERNAME_BLOWFISH "blowfish"
-+#define CIPHERNAME_CAST "cast5"
-+#define CIPHERNAME_SERPENT "serpent"
-+#define CIPHERNAME_TWOFISH "twofish"
-+
-+#define ESP_3DES 3
-+#define ESP_AES 12
-+#define ESP_BLOWFISH 7 /* truely _constant_ :) */
-+#define ESP_CAST 6 /* quite constant :) */
-+#define ESP_SERPENT 252 /* from ipsec drafts */
-+#define ESP_TWOFISH 253 /* from ipsec drafts */
-+
-+#define AH_MD5 2
-+#define AH_SHA 3
-+#define DIGESTNAME_MD5 "md5"
-+#define DIGESTNAME_SHA1 "sha1"
-+
-+MODULE_AUTHOR("Juanjo Ciarlante, Harpo MAxx, Luciano Ruete");
-+static int debug=0;
-+MODULE_PARM(debug, "i");
-+static int test=0;
-+MODULE_PARM(test, "i");
-+static int excl=0;
-+MODULE_PARM(excl, "i");
-+
-+static int noauto = 0;
-+MODULE_PARM(noauto,"i");
-+MODULE_PARM_DESC(noauto, "Dont try all known algos, just setup enabled ones");
-+
-+static int des_ede3[] = {-1, -1};
-+static int aes[] = {-1, -1};
-+static int blowfish[] = {-1, -1};
-+static int cast[] = {-1, -1};
-+static int serpent[] = {-1, -1};
-+static int twofish[] = {-1, -1};
-+
-+MODULE_PARM(des_ede3,"1-2i");
-+MODULE_PARM(aes,"1-2i");
-+MODULE_PARM(blowfish,"1-2i");
-+MODULE_PARM(cast,"1-2i");
-+MODULE_PARM(serpent,"1-2i");
-+MODULE_PARM(twofish,"1-2i");
-+MODULE_PARM_DESC(des_ede3, "0: disable | 1: force_enable | min,max: dontuse");
-+MODULE_PARM_DESC(aes, "0: disable | 1: force_enable | min,max: keybitlens");
-+MODULE_PARM_DESC(blowfish, "0: disable | 1: force_enable | min,max: keybitlens");
-+MODULE_PARM_DESC(cast, "0: disable | 1: force_enable | min,max: keybitlens");
-+MODULE_PARM_DESC(serpent, "0: disable | 1: force_enable | min,max: keybitlens");
-+MODULE_PARM_DESC(twofish, "0: disable | 1: force_enable | min,max: keybitlens");
-+
-+struct ipsec_alg_capi_cipher {
-+ const char *ciphername; /* cryptoapi's ciphername */
-+ unsigned blocksize;
-+ unsigned short minbits;
-+ unsigned short maxbits;
-+ int *parm; /* lkm param for this cipher */
-+ struct ipsec_alg_enc alg; /* note it's not a pointer */
-+};
-+static struct ipsec_alg_capi_cipher alg_capi_carray[] = {
-+ { CIPHERNAME_AES , 16, 128, 256, aes , { ixt_alg_id: ESP_AES, }},
-+ { CIPHERNAME_TWOFISH , 16, 128, 256, twofish, { ixt_alg_id: ESP_TWOFISH, }},
-+ { CIPHERNAME_SERPENT , 16, 128, 256, serpent, { ixt_alg_id: ESP_SERPENT, }},
-+ { CIPHERNAME_CAST , 8, 128, 128, cast , { ixt_alg_id: ESP_CAST, }},
-+ { CIPHERNAME_BLOWFISH , 8, 96, 448, blowfish,{ ixt_alg_id: ESP_BLOWFISH, }},
-+ { CIPHERNAME_3DES , 8, 192, 192, des_ede3,{ ixt_alg_id: ESP_3DES, }},
-+ { NULL, 0, 0, 0, NULL, {} }
-+};
-+#ifdef NOT_YET
-+struct ipsec_alg_capi_digest {
-+ const char *digestname; /* cryptoapi's digestname */
-+ struct digest_implementation *di;
-+ struct ipsec_alg_auth alg; /* note it's not a pointer */
-+};
-+static struct ipsec_alg_capi_cipher alg_capi_darray[] = {
-+ { DIGESTNAME_MD5, NULL, { ixt_alg_id: AH_MD5, }},
-+ { DIGESTNAME_SHA1, NULL, { ixt_alg_id: AH_SHA, }},
-+ { NULL, NULL, {} }
-+};
-+#endif
-+/*
-+ * "generic" linux cryptoapi setup_cipher() function
-+ */
-+int setup_cipher(const char *ciphername)
-+{
-+ return crypto_alg_available(ciphername, 0);
-+}
-+
-+/*
-+ * setups ipsec_alg_capi_cipher "hyper" struct components, calling
-+ * register_ipsec_alg for cointaned ipsec_alg object
-+ */
-+static void _capi_destroy_key (struct ipsec_alg_enc *alg, __u8 *key_e);
-+static __u8 * _capi_new_key (struct ipsec_alg_enc *alg, const __u8 *key, size_t keylen);
-+static int _capi_cbc_encrypt(struct ipsec_alg_enc *alg, __u8 * key_e, __u8 * in, int ilen, const __u8 * iv, int encrypt);
-+
-+static int
-+setup_ipsec_alg_capi_cipher(struct ipsec_alg_capi_cipher *cptr)
-+{
-+ int ret;
-+ cptr->alg.ixt_version = IPSEC_ALG_VERSION;
-+ cptr->alg.ixt_module = THIS_MODULE;
-+ atomic_set (& cptr->alg.ixt_refcnt, 0);
-+ strncpy (cptr->alg.ixt_name , cptr->ciphername, sizeof (cptr->alg.ixt_name));
-+
-+ cptr->alg.ixt_blocksize=cptr->blocksize;
-+ cptr->alg.ixt_keyminbits=cptr->minbits;
-+ cptr->alg.ixt_keymaxbits=cptr->maxbits;
-+ cptr->alg.ixt_state = 0;
-+ if (excl) cptr->alg.ixt_state |= IPSEC_ALG_ST_EXCL;
-+ cptr->alg.ixt_e_keylen=cptr->alg.ixt_keymaxbits/8;
-+ cptr->alg.ixt_e_ctx_size = 0;
-+ cptr->alg.ixt_alg_type = IPSEC_ALG_TYPE_ENCRYPT;
-+ cptr->alg.ixt_e_new_key = _capi_new_key;
-+ cptr->alg.ixt_e_destroy_key = _capi_destroy_key;
-+ cptr->alg.ixt_e_cbc_encrypt = _capi_cbc_encrypt;
-+ cptr->alg.ixt_data = cptr;
-+
-+ ret=register_ipsec_alg_enc(&cptr->alg);
-+ printk("setup_ipsec_alg_capi_cipher(): "
-+ "alg_type=%d alg_id=%d name=%s "
-+ "keyminbits=%d keymaxbits=%d, ret=%d\n",
-+ cptr->alg.ixt_alg_type,
-+ cptr->alg.ixt_alg_id,
-+ cptr->alg.ixt_name,
-+ cptr->alg.ixt_keyminbits,
-+ cptr->alg.ixt_keymaxbits,
-+ ret);
-+ return ret;
-+}
-+/*
-+ * called in ipsec_sa_wipe() time, will destroy key contexts
-+ * and do 1 unbind()
-+ */
-+static void
-+_capi_destroy_key (struct ipsec_alg_enc *alg, __u8 *key_e)
-+{
-+ struct crypto_tfm *tfm=(struct crypto_tfm*)key_e;
-+
-+ if (debug > 0)
-+ printk(KERN_DEBUG "klips_debug: _capi_destroy_key:"
-+ "name=%s key_e=%p \n",
-+ alg->ixt_name, key_e);
-+ if (!key_e) {
-+ printk(KERN_ERR "klips_debug: _capi_destroy_key:"
-+ "name=%s NULL key_e!\n",
-+ alg->ixt_name);
-+ return;
-+ }
-+ crypto_free_tfm(tfm);
-+}
-+
-+/*
-+ * create new key context, need alg->ixt_data to know which
-+ * (of many) cipher inside this module is the target
-+ */
-+static __u8 *
-+_capi_new_key (struct ipsec_alg_enc *alg, const __u8 *key, size_t keylen)
-+{
-+ struct ipsec_alg_capi_cipher *cptr;
-+ struct crypto_tfm *tfm=NULL;
-+
-+ cptr = alg->ixt_data;
-+ if (!cptr) {
-+ printk(KERN_ERR "_capi_new_key(): "
-+ "NULL ixt_data (?!) for \"%s\" algo\n"
-+ , alg->ixt_name);
-+ goto err;
-+ }
-+ if (debug > 0)
-+ printk(KERN_DEBUG "klips_debug:_capi_new_key:"
-+ "name=%s cptr=%p key=%p keysize=%d\n",
-+ alg->ixt_name, cptr, key, keylen);
-+
-+ /*
-+ * alloc tfm
-+ */
-+ tfm = crypto_alloc_tfm(cptr->ciphername, CRYPTO_TFM_MODE_CBC);
-+ if (!tfm) {
-+ printk(KERN_ERR "_capi_new_key(): "
-+ "NULL tfm for \"%s\" cryptoapi (\"%s\") algo\n"
-+ , alg->ixt_name, cptr->ciphername);
-+ goto err;
-+ }
-+ if (crypto_cipher_setkey(tfm, key, keylen) < 0) {
-+ printk(KERN_ERR "_capi_new_key(): "
-+ "failed new_key() for \"%s\" cryptoapi algo (keylen=%d)\n"
-+ , alg->ixt_name, keylen);
-+ crypto_free_tfm(tfm);
-+ tfm=NULL;
-+ }
-+err:
-+ if (debug > 0)
-+ printk(KERN_DEBUG "klips_debug:_capi_new_key:"
-+ "name=%s key=%p keylen=%d tfm=%p\n",
-+ alg->ixt_name, key, keylen, tfm);
-+ return (__u8 *) tfm;
-+}
-+/*
-+ * core encryption function: will use cx->ci to call actual cipher's
-+ * cbc function
-+ */
-+static int
-+_capi_cbc_encrypt(struct ipsec_alg_enc *alg, __u8 * key_e, __u8 * in, int ilen, const __u8 * iv, int encrypt) {
-+ int error =0;
-+ struct crypto_tfm *tfm=(struct crypto_tfm *)key_e;
-+ struct scatterlist sg = {
-+ .page = virt_to_page(in),
-+ .offset = (unsigned long)(in) % PAGE_SIZE,
-+ .length=ilen,
-+ };
-+ if (debug > 1)
-+ printk(KERN_DEBUG "klips_debug:_capi_cbc_encrypt:"
-+ "key_e=%p "
-+ "in=%p out=%p ilen=%d iv=%p encrypt=%d\n"
-+ , key_e
-+ , in, in, ilen, iv, encrypt);
-+ crypto_cipher_set_iv(tfm, iv, crypto_tfm_alg_ivsize(tfm));
-+ if (encrypt)
-+ error = crypto_cipher_encrypt (tfm, &sg, &sg, ilen);
-+ else
-+ error = crypto_cipher_decrypt (tfm, &sg, &sg, ilen);
-+ if (debug > 1)
-+ printk(KERN_DEBUG "klips_debug:_capi_cbc_encrypt:"
-+ "error=%d\n"
-+ , error);
-+ return (error<0)? error : ilen;
-+}
-+/*
-+ * main initialization loop: for each cipher in list, do
-+ * 1) setup cryptoapi cipher else continue
-+ * 2) register ipsec_alg object
-+ */
-+static int
-+setup_cipher_list (struct ipsec_alg_capi_cipher* clist)
-+{
-+ struct ipsec_alg_capi_cipher *cptr;
-+ /* foreach cipher in list ... */
-+ for (cptr=clist;cptr->ciphername;cptr++) {
-+ /*
-+ * see if cipher has been disabled (0) or
-+ * if noauto set and not enabled (1)
-+ */
-+ if (cptr->parm[0] == 0 || (noauto && cptr->parm[0] < 0)) {
-+ if (debug>0)
-+ printk(KERN_INFO "setup_cipher_list(): "
-+ "ciphername=%s skipped at user request: "
-+ "noauto=%d parm[0]=%d parm[1]=%d\n"
-+ , cptr->ciphername
-+ , noauto
-+ , cptr->parm[0]
-+ , cptr->parm[1]);
-+ continue;
-+ }
-+ /*
-+ * use a local ci to avoid touching cptr->ci,
-+ * if register ipsec_alg success then bind cipher
-+ */
-+ if( setup_cipher(cptr->ciphername) ) {
-+ if (debug > 0)
-+ printk(KERN_DEBUG "klips_debug:"
-+ "setup_cipher_list():"
-+ "ciphername=%s found\n"
-+ , cptr->ciphername);
-+ if (setup_ipsec_alg_capi_cipher(cptr) == 0) {
-+
-+
-+ } else {
-+ printk(KERN_ERR "klips_debug:"
-+ "setup_cipher_list():"
-+ "ciphername=%s failed ipsec_alg_register\n"
-+ , cptr->ciphername);
-+ }
-+ } else {
-+ if (debug>0)
-+ printk(KERN_INFO "setup_cipher_list(): lookup for ciphername=%s: not found \n",
-+ cptr->ciphername);
-+ }
-+ }
-+ return 0;
-+}
-+/*
-+ * deregister ipsec_alg objects and unbind ciphers
-+ */
-+static int
-+unsetup_cipher_list (struct ipsec_alg_capi_cipher* clist)
-+{
-+ struct ipsec_alg_capi_cipher *cptr;
-+ /* foreach cipher in list ... */
-+ for (cptr=clist;cptr->ciphername;cptr++) {
-+ if (cptr->alg.ixt_state & IPSEC_ALG_ST_REGISTERED) {
-+ unregister_ipsec_alg_enc(&cptr->alg);
-+ }
-+ }
-+ return 0;
-+}
-+/*
-+ * test loop for registered algos
-+ */
-+static int
-+test_cipher_list (struct ipsec_alg_capi_cipher* clist)
-+{
-+ int test_ret;
-+ struct ipsec_alg_capi_cipher *cptr;
-+ /* foreach cipher in list ... */
-+ for (cptr=clist;cptr->ciphername;cptr++) {
-+ if (cptr->alg.ixt_state & IPSEC_ALG_ST_REGISTERED) {
-+ test_ret=ipsec_alg_test(
-+ cptr->alg.ixt_alg_type,
-+ cptr->alg.ixt_alg_id,
-+ test);
-+ printk("test_cipher_list(alg_type=%d alg_id=%d): test_ret=%d\n",
-+ cptr->alg.ixt_alg_type,
-+ cptr->alg.ixt_alg_id,
-+ test_ret);
-+ }
-+ }
-+ return 0;
-+}
-+
-+IPSEC_ALG_MODULE_INIT( ipsec_cryptoapi_init )
-+{
-+ int ret, test_ret;
-+ if ((ret=setup_cipher_list(alg_capi_carray)) < 0)
-+ return -EPROTONOSUPPORT;
-+ if (ret==0 && test) {
-+ test_ret=test_cipher_list(alg_capi_carray);
-+ }
-+ return ret;
-+}
-+IPSEC_ALG_MODULE_EXIT( ipsec_cryptoapi_fini )
-+{
-+ unsetup_cipher_list(alg_capi_carray);
-+ return;
-+}
-+#ifdef MODULE_LICENSE
-+MODULE_LICENSE("GPL");
-+#endif
-+
-+EXPORT_NO_SYMBOLS;
-+#endif /* NO_CRYPTOAPI_SUPPORT */
---- /dev/null Tue Mar 11 13:02:56 2003
-+++ linux/net/ipsec/alg/scripts/mk-static_init.c.sh Mon Feb 9 13:51:03 2004
-@@ -0,0 +1,18 @@
-+#!/bin/sh
-+cat << EOF
-+#include <linux/kernel.h>
-+#include <linux/list.h>
-+#include "freeswan/ipsec_alg.h"
-+$(for i in $*; do
-+ test -z "$i" && continue
-+ echo "extern int $i(void);"
-+done)
-+void ipsec_alg_static_init(void){
-+ int __attribute__ ((unused)) err=0;
-+$(for i in $*; do
-+ test -z "$i" && continue
-+ echo " if ((err=$i()) < 0)"
-+ echo " printk(KERN_WARNING \"$i() returned %d\", err);"
-+done)
-+}
-+EOF
---- /dev/null Tue Mar 11 13:02:56 2003
-+++ linux/net/ipsec/defconfig Mon Feb 9 13:51:03 2004
-@@ -0,0 +1,146 @@
-+
-+#
-+# RCSID $Id: defconfig,v 1.25 2004/07/05 01:03:53 mcr Exp $
-+#
-+
-+#
-+# FreeS/WAN IPSec implementation, KLIPS kernel config defaults
-+#
-+
-+#
-+# First, lets override stuff already set or not in the kernel config.
-+#
-+# We can't even think about leaving this off...
-+CONFIG_INET=y
-+
-+#
-+# This must be on for subnet protection.
-+CONFIG_IP_FORWARD=y
-+
-+# Shut off IPSEC masquerading if it has been enabled, since it will
-+# break the compile. IPPROTO_ESP and IPPROTO_AH were included in
-+# net/ipv4/ip_masq.c when they should have gone into include/linux/in.h.
-+CONFIG_IP_MASQUERADE_IPSEC=n
-+
-+#
-+# Next, lets set the recommended FreeS/WAN configuration.
-+#
-+
-+# To config as static (preferred), 'y'. To config as module, 'm'.
-+CONFIG_IPSEC=y
-+
-+# To do tunnel mode IPSec, this must be enabled.
-+CONFIG_IPSEC_IPIP=y
-+
-+# To enable authentication, say 'y'. (Highly recommended)
-+CONFIG_IPSEC_AH=y
-+
-+# Authentication algorithm(s):
-+CONFIG_IPSEC_AUTH_HMAC_MD5=y
-+CONFIG_IPSEC_AUTH_HMAC_SHA1=y
-+
-+# To enable encryption, say 'y'. (Highly recommended)
-+CONFIG_IPSEC_ESP=y
-+
-+# Encryption algorithm(s):
-+CONFIG_IPSEC_ENC_3DES=y
-+CONFIG_IPSEC_ENC_AES=y
-+
-+# modular algo extensions (and new ALGOs)
-+CONFIG_IPSEC_ALG=y
-+CONFIG_IPSEC_ENC_3DES=y
-+CONFIG_IPSEC_ENC_AES=y
-+
-+CONFIG_IPSEC_ALG_TWOFISH=m
-+CONFIG_IPSEC_ALG_BLOWFISH=m
-+CONFIG_IPSEC_ALG_SERPENT=m
-+CONFIG_IPSEC_ALG_MD5=m
-+CONFIG_IPSEC_ALG_SHA1=m
-+CONFIG_IPSEC_ALG_SHA2=m
-+#CONFIG_IPSEC_ALG_CAST=n
-+#CONFIG_IPSEC_ALG_NULL=n
-+
-+# Use CryptoAPI for ALG? - by default, no.
-+CONFIG_IPSEC_ENC_CRYPTOAPI=n
-+
-+
-+# IP Compression: new, probably still has minor bugs.
-+CONFIG_IPSEC_IPCOMP=y
-+
-+# To enable userspace-switchable KLIPS debugging, say 'y'.
-+CONFIG_IPSEC_DEBUG=y
-+
-+# NAT Traversal
-+CONFIG_IPSEC_NAT_TRAVERSAL=y
-+
-+#
-+#
-+# $Log: defconfig,v $
-+# Revision 1.25 2004/07/05 01:03:53 mcr
-+# fix for adding cryptoapi code.
-+# keep it off for now, since UMLs do not have it yet.
-+#
-+# Revision 1.24 2004/04/06 02:49:25 mcr
-+# pullup of algo code from alg-branch.
-+#
-+# Revision 1.23.2.2 2004/04/05 04:30:46 mcr
-+# patches for alg-branch to compile/work with 2.x openswan
-+#
-+# Revision 1.23.2.1 2003/12/22 15:25:52 jjo
-+# . Merged algo-0.8.1-rc11-test1 into alg-branch
-+#
-+# Revision 1.23 2003/12/10 01:14:27 mcr
-+# NAT-traversal patches to KLIPS.
-+#
-+# Revision 1.22 2003/02/24 19:37:27 mcr
-+# changed default compilation mode to static.
-+#
-+# Revision 1.21 2002/04/24 07:36:27 mcr
-+# Moved from ./klips/net/ipsec/defconfig,v
-+#
-+# Revision 1.20 2002/04/02 04:07:40 mcr
-+# default build is now 'm'odule for KLIPS
-+#
-+# Revision 1.19 2002/03/08 18:57:17 rgb
-+# Added a blank line at the beginning of the file to make it easier for
-+# other projects to patch ./arch/i386/defconfig, for example
-+# LIDS+grSecurity requested by Jason Pattie.
-+#
-+# Revision 1.18 2000/11/30 17:26:56 rgb
-+# Cleaned out unused options and enabled ipcomp by default.
-+#
-+# Revision 1.17 2000/09/15 11:37:01 rgb
-+# Merge in heavily modified Svenning Soerensen's <svenning@post5.tele.dk>
-+# IPCOMP zlib deflate code.
-+#
-+# Revision 1.16 2000/09/08 19:12:55 rgb
-+# Change references from DEBUG_IPSEC to CONFIG_IPSEC_DEBUG.
-+#
-+# Revision 1.15 2000/05/24 19:37:13 rgb
-+# *** empty log message ***
-+#
-+# Revision 1.14 2000/05/11 21:14:57 henry
-+# just commenting the FOOBAR=y lines out is not enough
-+#
-+# Revision 1.13 2000/05/10 20:17:58 rgb
-+# Comment out netlink defaults, which are no longer needed.
-+#
-+# Revision 1.12 2000/05/10 19:13:38 rgb
-+# Added configure option to shut off no eroute passthrough.
-+#
-+# Revision 1.11 2000/03/16 07:09:46 rgb
-+# Hardcode PF_KEYv2 support.
-+# Disable IPSEC_ICMP by default.
-+# Remove DES config option from defaults file.
-+#
-+# Revision 1.10 2000/01/11 03:09:42 rgb
-+# Added a default of 'y' to PF_KEYv2 keying I/F.
-+#
-+# Revision 1.9 1999/05/08 21:23:12 rgb
-+# Added support for 2.2.x kernels.
-+#
-+# Revision 1.8 1999/04/06 04:54:25 rgb
-+# Fix/Add RCSID Id: and Log: bits to make PHMDs happy. This includes
-+# patch shell fixes.
-+#
-+#
---- /dev/null Tue Mar 11 13:02:56 2003
-+++ linux/net/ipsec/ipcomp.c Mon Feb 9 13:51:03 2004
-@@ -0,0 +1,725 @@
-+/*
-+ * IPCOMP zlib interface code.
-+ * Copyright (C) 2000 Svenning Soerensen <svenning@post5.tele.dk>
-+ * Copyright (C) 2000, 2001 Richard Guy Briggs <rgb@conscoop.ottawa.on.ca>
-+ *
-+ * 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. See <http://www.fsf.org/copyleft/gpl.txt>.
-+ *
-+ * 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.
-+ */
-+
-+char ipcomp_c_version[] = "RCSID $Id: ipcomp.c,v 1.36 2004/04/06 02:49:25 mcr Exp $";
-+
-+/* SSS */
-+
-+#include <linux/config.h>
-+#include <linux/version.h>
-+
-+#define __NO_VERSION__
-+#include <linux/module.h>
-+#include <linux/kernel.h> /* printk() */
-+
-+#include "openswan/ipsec_param.h"
-+
-+#ifdef MALLOC_SLAB
-+# include <linux/slab.h> /* kmalloc() */
-+#else /* MALLOC_SLAB */
-+# include <linux/malloc.h> /* kmalloc() */
-+#endif /* MALLOC_SLAB */
-+#include <linux/errno.h> /* error codes */
-+#include <linux/types.h>
-+#include <linux/netdevice.h>
-+#include <linux/ip.h>
-+#include <linux/skbuff.h>
-+
-+#include <linux/netdevice.h> /* struct device, and other headers */
-+#include <linux/etherdevice.h> /* eth_type_trans */
-+#include <linux/ip.h> /* struct iphdr */
-+#include <linux/skbuff.h>
-+
-+#include <openswan.h>
-+
-+#ifdef NET_21
-+# include <net/dst.h>
-+# include <asm/uaccess.h>
-+# include <linux/in6.h>
-+# define proto_priv cb
-+#endif /* NET21 */
-+#include <asm/checksum.h>
-+#include <net/ip.h>
-+
-+#include "openswan/radij.h"
-+#include "openswan/ipsec_encap.h"
-+#include "openswan/ipsec_sa.h"
-+
-+#include "openswan/ipsec_xform.h"
-+#include "openswan/ipsec_tunnel.h"
-+#include "openswan/ipsec_rcv.h" /* sysctl_ipsec_inbound_policy_check */
-+#include "openswan/ipcomp.h"
-+#include "zlib/zlib.h"
-+#include "zlib/zutil.h"
-+
-+#include <pfkeyv2.h> /* SADB_X_CALG_DEFLATE */
-+
-+#ifdef CONFIG_IPSEC_DEBUG
-+int sysctl_ipsec_debug_ipcomp = 0;
-+#endif /* CONFIG_IPSEC_DEBUG */
-+
-+static
-+struct sk_buff *skb_copy_ipcomp(struct sk_buff *skb, int data_growth, int gfp_mask);
-+
-+static
-+voidpf my_zcalloc(voidpf opaque, uInt items, uInt size)
-+{
-+ return (voidpf) kmalloc(items*size, GFP_ATOMIC);
-+}
-+
-+static
-+void my_zfree(voidpf opaque, voidpf address)
-+{
-+ kfree(address);
-+}
-+
-+struct sk_buff *skb_compress(struct sk_buff *skb, struct ipsec_sa *ips, unsigned int *flags)
-+{
-+ struct iphdr *iph;
-+ unsigned int iphlen, pyldsz, cpyldsz;
-+ unsigned char *buffer;
-+ z_stream zs;
-+ int zresult;
-+
-+ KLIPS_PRINT(sysctl_ipsec_debug_ipcomp,
-+ "klips_debug:skb_compress: .\n");
-+
-+ if(skb == NULL) {
-+ KLIPS_PRINT(sysctl_ipsec_debug_ipcomp,
-+ "klips_debug:skb_compress: "
-+ "passed in NULL skb, returning ERROR.\n");
-+ if(flags != NULL) {
-+ *flags |= IPCOMP_PARMERROR;
-+ }
-+ return skb;
-+ }
-+
-+ if(ips == NULL) {
-+ KLIPS_PRINT(sysctl_ipsec_debug_ipcomp,
-+ "klips_debug:skb_compress: "
-+ "passed in NULL ipsec_sa needed for cpi, returning ERROR.\n");
-+ if(flags) {
-+ *flags |= IPCOMP_PARMERROR;
-+ }
-+ return skb;
-+ }
-+
-+ if (flags == NULL) {
-+ KLIPS_PRINT(sysctl_ipsec_debug_ipcomp,
-+ "klips_debug:skb_compress: "
-+ "passed in NULL flags, returning ERROR.\n");
-+ ipsec_kfree_skb(skb);
-+ return NULL;
-+ }
-+
-+#ifdef NET_21
-+ iph = skb->nh.iph;
-+#else /* NET_21 */
-+ iph = skb->ip_hdr;
-+#endif /* NET_21 */
-+
-+ switch (iph->protocol) {
-+ case IPPROTO_COMP:
-+ case IPPROTO_AH:
-+ case IPPROTO_ESP:
-+ KLIPS_PRINT(sysctl_ipsec_debug_ipcomp,
-+ "klips_debug:skb_compress: "
-+ "skipping compression of packet with ip protocol %d.\n",
-+ iph->protocol);
-+ *flags |= IPCOMP_UNCOMPRESSABLE;
-+ return skb;
-+ }
-+
-+ /* Don't compress packets already fragmented */
-+ if (iph->frag_off & __constant_htons(IP_MF | IP_OFFSET)) {
-+ KLIPS_PRINT(sysctl_ipsec_debug_ipcomp,
-+ "klips_debug:skb_compress: "
-+ "skipping compression of fragmented packet.\n");
-+ *flags |= IPCOMP_UNCOMPRESSABLE;
-+ return skb;
-+ }
-+
-+ iphlen = iph->ihl << 2;
-+ pyldsz = ntohs(iph->tot_len) - iphlen;
-+
-+ /* Don't compress less than 90 bytes (rfc 2394) */
-+ if (pyldsz < 90) {
-+ KLIPS_PRINT(sysctl_ipsec_debug_ipcomp,
-+ "klips_debug:skb_compress: "
-+ "skipping compression of tiny packet, len=%d.\n",
-+ pyldsz);
-+ *flags |= IPCOMP_UNCOMPRESSABLE;
-+ return skb;
-+ }
-+
-+ /* Adaptive decision */
-+ if (ips->ips_comp_adapt_skip) {
-+ KLIPS_PRINT(sysctl_ipsec_debug_ipcomp,
-+ "klips_debug:skb_compress: "
-+ "skipping compression: ips_comp_adapt_skip=%d.\n",
-+ ips->ips_comp_adapt_skip);
-+ ips->ips_comp_adapt_skip--;
-+ *flags |= IPCOMP_UNCOMPRESSABLE;
-+ return skb;
-+ }
-+
-+ zs.zalloc = my_zcalloc;
-+ zs.zfree = my_zfree;
-+ zs.opaque = 0;
-+
-+ /* We want to use deflateInit2 because we don't want the adler
-+ header. */
-+ zresult = deflateInit2(&zs, Z_DEFAULT_COMPRESSION, Z_DEFLATED, -11,
-+ DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY);
-+ if (zresult != Z_OK) {
-+ KLIPS_PRINT(sysctl_ipsec_debug_ipcomp,
-+ "klips_error:skb_compress: "
-+ "deflateInit2() returned error %d (%s), "
-+ "skipping compression.\n",
-+ zresult,
-+ zs.msg ? zs.msg : zError(zresult));
-+ *flags |= IPCOMP_COMPRESSIONERROR;
-+ return skb;
-+ }
-+
-+
-+ /* Max output size. Result should be max this size.
-+ * Implementation specific tweak:
-+ * If it's not at least 32 bytes and 6.25% smaller than
-+ * the original packet, it's probably not worth wasting
-+ * the receiver's CPU cycles decompressing it.
-+ * Your mileage may vary.
-+ */
-+ cpyldsz = pyldsz - sizeof(struct ipcomphdr) - (pyldsz <= 512 ? 32 : pyldsz >> 4);
-+
-+ buffer = kmalloc(cpyldsz, GFP_ATOMIC);
-+ if (!buffer) {
-+ KLIPS_PRINT(sysctl_ipsec_debug_ipcomp,
-+ "klips_error:skb_compress: "
-+ "unable to kmalloc(%d, GFP_ATOMIC), "
-+ "skipping compression.\n",
-+ cpyldsz);
-+ *flags |= IPCOMP_COMPRESSIONERROR;
-+ deflateEnd(&zs);
-+ return skb;
-+ }
-+
-+#ifdef CONFIG_IPSEC_DEBUG
-+ if(sysctl_ipsec_debug_ipcomp && sysctl_ipsec_debug_verbose) {
-+ __u8 *c;
-+ int i;
-+
-+ c = (__u8*)iph + iphlen;
-+ for(i = 0; i < pyldsz; i++, c++) {
-+ if(!(i % 16)) {
-+ printk(KERN_INFO "skb_compress: before:");
-+ }
-+ printk("%02x ", *c);
-+ if(!((i + 1) % 16)) {
-+ printk("\n");
-+ }
-+ }
-+ if(i % 16) {
-+ printk("\n");
-+ }
-+ }
-+#endif /* CONFIG_IPSEC_DEBUG */
-+
-+ zs.next_in = (char *) iph + iphlen; /* start of payload */
-+ zs.avail_in = pyldsz;
-+ zs.next_out = buffer; /* start of compressed payload */
-+ zs.avail_out = cpyldsz;
-+
-+ /* Finish compression in one step */
-+ zresult = deflate(&zs, Z_FINISH);
-+
-+ /* Free all dynamically allocated buffers */
-+ deflateEnd(&zs);
-+ if (zresult != Z_STREAM_END) {
-+ *flags |= IPCOMP_UNCOMPRESSABLE;
-+ kfree(buffer);
-+
-+ /* Adjust adaptive counters */
-+ if (++(ips->ips_comp_adapt_tries) == IPCOMP_ADAPT_INITIAL_TRIES) {
-+ KLIPS_PRINT(sysctl_ipsec_debug_ipcomp,
-+ "klips_debug:skb_compress: "
-+ "first %d packets didn't compress, "
-+ "skipping next %d\n",
-+ IPCOMP_ADAPT_INITIAL_TRIES,
-+ IPCOMP_ADAPT_INITIAL_SKIP);
-+ ips->ips_comp_adapt_skip = IPCOMP_ADAPT_INITIAL_SKIP;
-+ }
-+ else if (ips->ips_comp_adapt_tries == IPCOMP_ADAPT_INITIAL_TRIES + IPCOMP_ADAPT_SUBSEQ_TRIES) {
-+ KLIPS_PRINT(sysctl_ipsec_debug_ipcomp,
-+ "klips_debug:skb_compress: "
-+ "next %d packets didn't compress, "
-+ "skipping next %d\n",
-+ IPCOMP_ADAPT_SUBSEQ_TRIES,
-+ IPCOMP_ADAPT_SUBSEQ_SKIP);
-+ ips->ips_comp_adapt_skip = IPCOMP_ADAPT_SUBSEQ_SKIP;
-+ ips->ips_comp_adapt_tries = IPCOMP_ADAPT_INITIAL_TRIES;
-+ }
-+
-+ return skb;
-+ }
-+
-+ /* resulting compressed size */
-+ cpyldsz -= zs.avail_out;
-+
-+ /* Insert IPCOMP header */
-+ ((struct ipcomphdr*) ((char*) iph + iphlen))->ipcomp_nh = iph->protocol;
-+ ((struct ipcomphdr*) ((char*) iph + iphlen))->ipcomp_flags = 0;
-+ /* use the bottom 16 bits of the spi for the cpi. The top 16 bits are
-+ for internal reference only. */
-+ ((struct ipcomphdr*) (((char*)iph) + iphlen))->ipcomp_cpi = htons((__u16)(ntohl(ips->ips_said.spi) & 0x0000ffff));
-+ KLIPS_PRINT(sysctl_ipsec_debug_ipcomp,
-+ "klips_debug:skb_compress: "
-+ "spi=%08x, spi&0xffff=%04x, cpi=%04x, payload size: raw=%d, comp=%d.\n",
-+ ntohl(ips->ips_said.spi),
-+ ntohl(ips->ips_said.spi) & 0x0000ffff,
-+ ntohs(((struct ipcomphdr*)(((char*)iph)+iphlen))->ipcomp_cpi),
-+ pyldsz,
-+ cpyldsz);
-+
-+ /* Update IP header */
-+ iph->protocol = IPPROTO_COMP;
-+ iph->tot_len = htons(iphlen + sizeof(struct ipcomphdr) + cpyldsz);
-+#if 1 /* XXX checksum is done by ipsec_tunnel ? */
-+ iph->check = 0;
-+ iph->check = ip_fast_csum((char *) iph, iph->ihl);
-+#endif
-+
-+ /* Copy compressed payload */
-+ memcpy((char *) iph + iphlen + sizeof(struct ipcomphdr),
-+ buffer,
-+ cpyldsz);
-+ kfree(buffer);
-+
-+ /* Update skb length/tail by "unputting" the shrinkage */
-+ skb_put(skb,
-+ cpyldsz + sizeof(struct ipcomphdr) - pyldsz);
-+
-+#ifdef CONFIG_IPSEC_DEBUG
-+ if(sysctl_ipsec_debug_ipcomp && sysctl_ipsec_debug_verbose) {
-+ __u8 *c;
-+ int i;
-+
-+ c = (__u8*)iph + iphlen + sizeof(struct ipcomphdr);
-+ for(i = 0; i < cpyldsz; i++, c++) {
-+ if(!(i % 16)) {
-+ printk(KERN_INFO "skb_compress: result:");
-+ }
-+ printk("%02x ", *c);
-+ if(!((i + 1) % 16)) {
-+ printk("\n");
-+ }
-+ }
-+ if(i % 16) {
-+ printk("\n");
-+ }
-+ }
-+#endif /* CONFIG_IPSEC_DEBUG */
-+
-+ ips->ips_comp_adapt_skip = 0;
-+ ips->ips_comp_adapt_tries = 0;
-+
-+ return skb;
-+}
-+
-+struct sk_buff *skb_decompress(struct sk_buff *skb, struct ipsec_sa *ips, unsigned int *flags)
-+{
-+ struct sk_buff *nskb = NULL;
-+
-+ /* original ip header */
-+ struct iphdr *oiph, *iph;
-+ unsigned int iphlen, pyldsz, cpyldsz;
-+ z_stream zs;
-+ int zresult;
-+
-+ KLIPS_PRINT(sysctl_ipsec_debug_ipcomp,
-+ "klips_debug:skb_decompress: .\n");
-+
-+ if(!skb) {
-+ KLIPS_PRINT(sysctl_ipsec_debug_ipcomp,
-+ "klips_error:skb_decompress: "
-+ "passed in NULL skb, returning ERROR.\n");
-+ if (flags) *flags |= IPCOMP_PARMERROR;
-+ return skb;
-+ }
-+
-+ if(!ips && sysctl_ipsec_inbound_policy_check) {
-+ KLIPS_PRINT(sysctl_ipsec_debug_ipcomp,
-+ "klips_error:skb_decompress: "
-+ "passed in NULL ipsec_sa needed for comp alg, returning ERROR.\n");
-+ if (flags) *flags |= IPCOMP_PARMERROR;
-+ return skb;
-+ }
-+
-+ if (!flags) {
-+ KLIPS_PRINT(sysctl_ipsec_debug_ipcomp,
-+ "klips_error:skb_decompress: "
-+ "passed in NULL flags, returning ERROR.\n");
-+ ipsec_kfree_skb(skb);
-+ return NULL;
-+ }
-+
-+#ifdef NET_21
-+ oiph = skb->nh.iph;
-+#else /* NET_21 */
-+ oiph = skb->ip_hdr;
-+#endif /* NET_21 */
-+
-+ iphlen = oiph->ihl << 2;
-+
-+ if (oiph->protocol != IPPROTO_COMP) {
-+ KLIPS_PRINT(sysctl_ipsec_debug_ipcomp,
-+ "klips_error:skb_decompress: "
-+ "called with non-IPCOMP packet (protocol=%d),"
-+ "skipping decompression.\n",
-+ oiph->protocol);
-+ *flags |= IPCOMP_PARMERROR;
-+ return skb;
-+ }
-+
-+ if ( (((struct ipcomphdr*)((char*) oiph + iphlen))->ipcomp_flags != 0)
-+ || ((((struct ipcomphdr*) ((char*) oiph + iphlen))->ipcomp_cpi
-+ != htons(SADB_X_CALG_DEFLATE))
-+ && sysctl_ipsec_inbound_policy_check
-+ && (!ips || (ips && (ips->ips_encalg != SADB_X_CALG_DEFLATE)))) ) {
-+ KLIPS_PRINT(sysctl_ipsec_debug_ipcomp,
-+ "klips_error:skb_decompress: "
-+ "called with incompatible IPCOMP packet (flags=%d, "
-+ "cpi=%d), ips-compalg=%d, skipping decompression.\n",
-+ ntohs(((struct ipcomphdr*) ((char*) oiph + iphlen))->ipcomp_flags),
-+ ntohs(((struct ipcomphdr*) ((char*) oiph + iphlen))->ipcomp_cpi),
-+ ips ? ips->ips_encalg : 0);
-+ *flags |= IPCOMP_PARMERROR;
-+
-+ return skb;
-+ }
-+
-+ if (ntohs(oiph->frag_off) & ~0x4000) {
-+ KLIPS_PRINT(sysctl_ipsec_debug_ipcomp,
-+ "klips_error:skb_decompress: "
-+ "called with fragmented IPCOMP packet, "
-+ "skipping decompression.\n");
-+ *flags |= IPCOMP_PARMERROR;
-+ return skb;
-+ }
-+
-+ /* original compressed payload size */
-+ cpyldsz = ntohs(oiph->tot_len) - iphlen - sizeof(struct ipcomphdr);
-+
-+ zs.zalloc = my_zcalloc;
-+ zs.zfree = my_zfree;
-+ zs.opaque = 0;
-+
-+ zs.next_in = (char *) oiph + iphlen + sizeof(struct ipcomphdr);
-+ zs.avail_in = cpyldsz;
-+
-+ /* Maybe we should be a bit conservative about memory
-+ requirements and use inflateInit2 */
-+ /* Beware, that this might make us unable to decompress packets
-+ from other implementations - HINT: check PGPnet source code */
-+ /* We want to use inflateInit2 because we don't want the adler
-+ header. */
-+ zresult = inflateInit2(&zs, -15);
-+ if (zresult != Z_OK) {
-+ KLIPS_PRINT(sysctl_ipsec_debug_ipcomp,
-+ "klips_error:skb_decompress: "
-+ "inflateInit2() returned error %d (%s), "
-+ "skipping decompression.\n",
-+ zresult,
-+ zs.msg ? zs.msg : zError(zresult));
-+ *flags |= IPCOMP_DECOMPRESSIONERROR;
-+
-+ return skb;
-+ }
-+
-+ /* We have no way of knowing the exact length of the resulting
-+ decompressed output before we have actually done the decompression.
-+ For now, we guess that the packet will not be bigger than the
-+ attached ipsec device's mtu or 16260, whichever is biggest.
-+ This may be wrong, since the sender's mtu may be bigger yet.
-+ XXX This must be dealt with later XXX
-+ */
-+
-+ /* max payload size */
-+ pyldsz = skb->dev ? (skb->dev->mtu < 16260 ? 16260 : skb->dev->mtu)
-+ : (65520 - iphlen);
-+ KLIPS_PRINT(sysctl_ipsec_debug_ipcomp,
-+ "klips_debug:skb_decompress: "
-+ "max payload size: %d\n", pyldsz);
-+
-+ while (pyldsz > (cpyldsz + sizeof(struct ipcomphdr)) &&
-+ (nskb = skb_copy_ipcomp(skb,
-+ pyldsz - cpyldsz - sizeof(struct ipcomphdr),
-+ GFP_ATOMIC)) == NULL) {
-+ KLIPS_PRINT(sysctl_ipsec_debug_ipcomp,
-+ "klips_error:skb_decompress: "
-+ "unable to skb_copy_ipcomp(skb, %d, GFP_ATOMIC), "
-+ "trying with less payload size.\n",
-+ (int)(pyldsz - cpyldsz - sizeof(struct ipcomphdr)));
-+ pyldsz >>=1;
-+ }
-+
-+ if (!nskb) {
-+ KLIPS_PRINT(sysctl_ipsec_debug_ipcomp,
-+ "klips_error:skb_decompress: "
-+ "unable to allocate memory, dropping packet.\n");
-+ *flags |= IPCOMP_DECOMPRESSIONERROR;
-+ inflateEnd(&zs);
-+
-+ return skb;
-+ }
-+
-+#ifdef CONFIG_IPSEC_DEBUG
-+ if(sysctl_ipsec_debug_ipcomp && sysctl_ipsec_debug_verbose) {
-+ __u8 *c;
-+ int i;
-+
-+ c = (__u8*)oiph + iphlen + sizeof(struct ipcomphdr);
-+ for(i = 0; i < cpyldsz; i++, c++) {
-+ if(!(i % 16)) {
-+ printk(KERN_INFO "skb_decompress: before:");
-+ }
-+ printk("%02x ", *c);
-+ if(!((i + 1) % 16)) {
-+ printk("\n");
-+ }
-+ }
-+ if(i % 16) {
-+ printk("\n");
-+ }
-+ }
-+#endif /* CONFIG_IPSEC_DEBUG */
-+
-+#ifdef NET_21
-+ iph = nskb->nh.iph;
-+#else /* NET_21 */
-+ iph = nskb->ip_hdr;
-+#endif /* NET_21 */
-+ zs.next_out = (char *)iph + iphlen;
-+ zs.avail_out = pyldsz;
-+
-+ zresult = inflate(&zs, Z_SYNC_FLUSH);
-+
-+ /* work around a bug in zlib, which sometimes wants to taste an extra
-+ * byte when being used in the (undocumented) raw deflate mode.
-+ */
-+ if (zresult == Z_OK && !zs.avail_in && zs.avail_out) {
-+ __u8 zerostuff = 0;
-+
-+ zs.next_in = &zerostuff;
-+ zs.avail_in = 1;
-+ zresult = inflate(&zs, Z_FINISH);
-+ }
-+
-+ inflateEnd(&zs);
-+ if (zresult != Z_STREAM_END) {
-+ KLIPS_PRINT(sysctl_ipsec_debug_ipcomp,
-+ "klips_error:skb_decompress: "
-+ "inflate() returned error %d (%s), "
-+ "skipping decompression.\n",
-+ zresult,
-+ zs.msg ? zs.msg : zError(zresult));
-+ *flags |= IPCOMP_DECOMPRESSIONERROR;
-+ ipsec_kfree_skb(nskb);
-+
-+ return skb;
-+ }
-+
-+ /* Update IP header */
-+ /* resulting decompressed size */
-+ pyldsz -= zs.avail_out;
-+ iph->tot_len = htons(iphlen + pyldsz);
-+ iph->protocol = ((struct ipcomphdr*) ((char*) oiph + iphlen))->ipcomp_nh;
-+ KLIPS_PRINT(sysctl_ipsec_debug_ipcomp,
-+ "klips_debug:skb_decompress: "
-+ "spi=%08x, spi&0xffff=%04x, cpi=%04x, payload size: comp=%d, raw=%d, nh=%d.\n",
-+ ips ? ntohl(ips->ips_said.spi) : 0,
-+ ips ? ntohl(ips->ips_said.spi) & 0x0000ffff : 0,
-+ ntohs(((struct ipcomphdr*)(((char*)oiph)+iphlen))->ipcomp_cpi),
-+ cpyldsz,
-+ pyldsz,
-+ iph->protocol);
-+
-+#if 1 /* XXX checksum is done by ipsec_rcv ? */
-+ iph->check = 0;
-+ iph->check = ip_fast_csum((char*) iph, iph->ihl);
-+#endif
-+
-+ /* Update skb length/tail by "unputting" the unused data area */
-+ skb_put(nskb, -zs.avail_out);
-+
-+ ipsec_kfree_skb(skb);
-+
-+ if (iph->protocol == IPPROTO_COMP)
-+ {
-+#ifdef CONFIG_IPSEC_DEBUG
-+ if(sysctl_ipsec_debug_ipcomp)
-+ KLIPS_PRINT(sysctl_ipsec_debug_ipcomp,
-+ "klips_debug:skb_decompress: "
-+ "Eh? inner packet is also compressed, dropping.\n");
-+#endif /* CONFIG_IPSEC_DEBUG */
-+
-+ ipsec_kfree_skb(nskb);
-+ return NULL;
-+ }
-+
-+#ifdef CONFIG_IPSEC_DEBUG
-+ if(sysctl_ipsec_debug_ipcomp && sysctl_ipsec_debug_verbose) {
-+ __u8 *c;
-+ int i;
-+
-+ c = (__u8*)iph + iphlen;
-+ for(i = 0; i < pyldsz; i++, c++) {
-+ if(!(i % 16)) {
-+ printk(KERN_INFO "skb_decompress: result:");
-+ }
-+ printk("%02x ", *c);
-+ if(!((i + 1) % 16)) {
-+ printk("\n");
-+ }
-+ }
-+ if(i % 16) {
-+ printk("\n");
-+ }
-+ }
-+#endif /* CONFIG_IPSEC_DEBUG */
-+
-+ return nskb;
-+}
-+
-+
-+/* this is derived from skb_copy() in linux 2.2.14 */
-+/* May be incompatible with other kernel versions!! */
-+static
-+struct sk_buff *skb_copy_ipcomp(struct sk_buff *skb, int data_growth, int gfp_mask)
-+{
-+ struct sk_buff *n;
-+ struct iphdr *iph;
-+ unsigned long offset;
-+ unsigned int iphlen;
-+
-+ if(!skb) {
-+ KLIPS_PRINT(sysctl_ipsec_debug_ipcomp,
-+ "klips_debug:skb_copy_ipcomp: "
-+ "passed in NULL skb, returning NULL.\n");
-+ return NULL;
-+ }
-+
-+ /*
-+ * Allocate the copy buffer
-+ */
-+
-+#ifdef NET_21
-+ iph = skb->nh.iph;
-+#else /* NET_21 */
-+ iph = skb->ip_hdr;
-+#endif /* NET_21 */
-+ if (!iph) return NULL;
-+ iphlen = iph->ihl << 2;
-+
-+ n=alloc_skb(skb->end - skb->head + data_growth, gfp_mask);
-+ if(n==NULL)
-+ return NULL;
-+
-+ /*
-+ * Shift between the two data areas in bytes
-+ */
-+
-+ offset=n->head-skb->head;
-+
-+ /* Set the data pointer */
-+ skb_reserve(n,skb->data-skb->head);
-+ /* Set the tail pointer and length */
-+ skb_put(n,skb->len+data_growth);
-+ /* Copy the bytes up to and including the ip header */
-+ memcpy(n->head,
-+ skb->head,
-+ ((char *)iph - (char *)skb->head) + iphlen);
-+ n->list=NULL;
-+ n->next=NULL;
-+ n->prev=NULL;
-+ n->sk=NULL;
-+ n->dev=skb->dev;
-+ if (skb->h.raw)
-+ n->h.raw=skb->h.raw+offset;
-+ else
-+ n->h.raw=NULL;
-+ n->protocol=skb->protocol;
-+#ifdef NET_21
-+ n->csum = 0;
-+ n->priority=skb->priority;
-+ n->dst=dst_clone(skb->dst);
-+ n->nh.raw=skb->nh.raw+offset;
-+#ifndef NETDEV_23
-+ n->is_clone=0;
-+#endif /* NETDEV_23 */
-+ atomic_set(&n->users, 1);
-+ n->destructor = NULL;
-+ n->security=skb->security;
-+ memcpy(n->cb, skb->cb, sizeof(skb->cb));
-+#ifdef CONFIG_IP_FIREWALL
-+ n->fwmark = skb->fwmark;
-+#endif
-+#else /* NET_21 */
-+ n->link3=NULL;
-+ n->when=skb->when;
-+ n->ip_hdr=(struct iphdr *)(((char *)skb->ip_hdr)+offset);
-+ n->saddr=skb->saddr;
-+ n->daddr=skb->daddr;
-+ n->raddr=skb->raddr;
-+ n->seq=skb->seq;
-+ n->end_seq=skb->end_seq;
-+ n->ack_seq=skb->ack_seq;
-+ n->acked=skb->acked;
-+ n->free=1;
-+ n->arp=skb->arp;
-+ n->tries=0;
-+ n->lock=0;
-+ n->users=0;
-+ memcpy(n->proto_priv, skb->proto_priv, sizeof(skb->proto_priv));
-+#endif /* NET_21 */
-+ if (skb->mac.raw)
-+ n->mac.raw=skb->mac.raw+offset;
-+ else
-+ n->mac.raw=NULL;
-+#ifndef NETDEV_23
-+ n->used=skb->used;
-+#endif /* !NETDEV_23 */
-+ n->pkt_type=skb->pkt_type;
-+#ifndef NETDEV_23
-+ n->pkt_bridged=skb->pkt_bridged;
-+#endif /* NETDEV_23 */
-+ n->ip_summed=0;
-+ n->stamp=skb->stamp;
-+#ifndef NETDEV_23 /* this seems to have been removed in 2.4 */
-+#if defined(CONFIG_SHAPER) || defined(CONFIG_SHAPER_MODULE)
-+ n->shapelatency=skb->shapelatency; /* Latency on frame */
-+ n->shapeclock=skb->shapeclock; /* Time it should go out */
-+ n->shapelen=skb->shapelen; /* Frame length in clocks */
-+ n->shapestamp=skb->shapestamp; /* Stamp for shaper */
-+ n->shapepend=skb->shapepend; /* Pending */
-+#endif /* defined(CONFIG_SHAPER) || defined(CONFIG_SHAPER_MODULE) */
-+#endif /* NETDEV_23 */
-+#ifdef CONFIG_HIPPI
-+ n->private.ifield=skb->private.ifield;
-+#endif /* CONFIG_HIPPI */
-+
-+ return n;
-+}
---- /dev/null Tue Mar 11 13:02:56 2003
-+++ linux/net/ipsec/ipsec_ah.c Mon Feb 9 13:51:03 2004
-@@ -0,0 +1,363 @@
-+/*
-+ * processing code for AH
-+ * Copyright (C) 2003-2004 Michael Richardson <mcr@xelerance.com>
-+ *
-+ * 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. See <http://www.fsf.org/copyleft/gpl.txt>.
-+ *
-+ * 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.
-+ */
-+
-+char ipsec_ah_c_version[] = "RCSID $Id: ipsec_ah.c,v 1.2 2004/04/06 02:49:25 mcr Exp $";
-+#include <linux/config.h>
-+#include <linux/version.h>
-+
-+#define __NO_VERSION__
-+#include <linux/module.h>
-+#include <linux/kernel.h> /* printk() */
-+
-+#include "openswan/ipsec_param.h"
-+
-+#ifdef MALLOC_SLAB
-+# include <linux/slab.h> /* kmalloc() */
-+#else /* MALLOC_SLAB */
-+# include <linux/malloc.h> /* kmalloc() */
-+#endif /* MALLOC_SLAB */
-+#include <linux/errno.h> /* error codes */
-+#include <linux/types.h> /* size_t */
-+#include <linux/interrupt.h> /* mark_bh */
-+
-+#include <linux/netdevice.h> /* struct device, and other headers */
-+#include <linux/etherdevice.h> /* eth_type_trans */
-+#include <linux/ip.h> /* struct iphdr */
-+#include <linux/skbuff.h>
-+#include <openswan.h>
-+#ifdef SPINLOCK
-+# ifdef SPINLOCK_23
-+# include <linux/spinlock.h> /* *lock* */
-+# else /* SPINLOCK_23 */
-+# include <asm/spinlock.h> /* *lock* */
-+# endif /* SPINLOCK_23 */
-+#endif /* SPINLOCK */
-+#ifdef NET_21
-+# include <asm/uaccess.h>
-+# include <linux/in6.h>
-+# define proto_priv cb
-+#endif /* NET21 */
-+#include <asm/checksum.h>
-+#include <net/ip.h>
-+
-+#include "openswan/radij.h"
-+#include "openswan/ipsec_encap.h"
-+#include "openswan/ipsec_sa.h"
-+
-+#include "openswan/ipsec_radij.h"
-+#include "openswan/ipsec_xform.h"
-+#include "openswan/ipsec_tunnel.h"
-+#include "openswan/ipsec_rcv.h"
-+#include "openswan/ipsec_xmit.h"
-+
-+#include "openswan/ipsec_auth.h"
-+
-+#ifdef CONFIG_IPSEC_AH
-+#include "openswan/ipsec_ah.h"
-+#endif /* CONFIG_IPSEC_AH */
-+
-+#include "openswan/ipsec_proto.h"
-+
-+#ifdef CONFIG_IPSEC_DEBUG
-+int debug_ah = 0;
-+#endif /* CONFIG_IPSEC_DEBUG */
-+
-+__u32 zeroes[AH_AMAX];
-+
-+#ifdef CONFIG_IPSEC_AH
-+enum ipsec_rcv_value
-+ipsec_rcv_ah_checks(struct ipsec_rcv_state *irs,
-+ struct sk_buff *skb)
-+{
-+ int ahminlen;
-+
-+ ahminlen = irs->hard_header_len + sizeof(struct iphdr);
-+
-+ /* take care not to deref this pointer until we check the minlen though */
-+ irs->protostuff.ahstuff.ahp = (struct ahhdr *) (skb->data + irs->iphlen);
-+
-+ if((skb->len < ahminlen+sizeof(struct ahhdr)) ||
-+ (skb->len < ahminlen+(irs->protostuff.ahstuff.ahp->ah_hl << 2))) {
-+ KLIPS_PRINT(debug_rcv & DB_RX_INAU,
-+ "klips_debug:ipsec_rcv: "
-+ "runt ah packet of skb->len=%d received from %s, dropped.\n",
-+ skb->len,
-+ irs->ipsaddr_txt);
-+ if(irs->stats) {
-+ irs->stats->rx_errors++;
-+ }
-+ return IPSEC_RCV_BADLEN;
-+ }
-+
-+ irs->said.spi = irs->protostuff.ahstuff.ahp->ah_spi;
-+
-+ /* XXX we only support the one 12-byte authenticator for now */
-+ if(irs->protostuff.ahstuff.ahp->ah_hl != ((AHHMAC_HASHLEN+AHHMAC_RPLLEN) >> 2)) {
-+ KLIPS_PRINT(debug_rcv & DB_RX_INAU,
-+ "klips_debug:ipsec_rcv: "
-+ "bad authenticator length %ld, expected %lu from %s.\n",
-+ (long)(irs->protostuff.ahstuff.ahp->ah_hl << 2),
-+ (unsigned long) sizeof(struct ahhdr),
-+ irs->ipsaddr_txt);
-+ if(irs->stats) {
-+ irs->stats->rx_errors++;
-+ }
-+ return IPSEC_RCV_BADLEN;
-+ }
-+
-+ return IPSEC_RCV_OK;
-+}
-+
-+
-+enum ipsec_rcv_value
-+ipsec_rcv_ah_setup_auth(struct ipsec_rcv_state *irs,
-+ struct sk_buff *skb,
-+ __u32 *replay,
-+ unsigned char **authenticator)
-+{
-+ struct ahhdr *ahp = irs->protostuff.ahstuff.ahp;
-+
-+ *replay = ntohl(ahp->ah_rpl);
-+ *authenticator = ahp->ah_data;
-+
-+ return IPSEC_RCV_OK;
-+}
-+
-+enum ipsec_rcv_value
-+ipsec_rcv_ah_authcalc(struct ipsec_rcv_state *irs,
-+ struct sk_buff *skb)
-+{
-+ struct auth_alg *aa;
-+ struct ahhdr *ahp = irs->protostuff.ahstuff.ahp;
-+ union {
-+ MD5_CTX md5;
-+ SHA1_CTX sha1;
-+ } tctx;
-+ struct iphdr ipo;
-+ int ahhlen;
-+
-+ aa = irs->authfuncs;
-+
-+ /* copy the initialized keying material */
-+ memcpy(&tctx, irs->ictx, irs->ictx_len);
-+
-+ ipo = *irs->ipp;
-+ ipo.tos = 0; /* mutable RFC 2402 3.3.3.1.1.1 */
-+ ipo.frag_off = 0;
-+ ipo.ttl = 0;
-+ ipo.check = 0;
-+
-+
-+ /* do the sanitized header */
-+ (*aa->update)((void*)&tctx, (caddr_t)&ipo, sizeof(struct iphdr));
-+
-+ /* XXX we didn't do the options here! */
-+
-+ /* now do the AH header itself */
-+ ahhlen = AH_BASIC_LEN + (ahp->ah_hl << 2);
-+ (*aa->update)((void*)&tctx, (caddr_t)ahp, ahhlen - AHHMAC_HASHLEN);
-+
-+ /* now, do some zeroes */
-+ (*aa->update)((void*)&tctx, (caddr_t)zeroes, AHHMAC_HASHLEN);
-+
-+ /* finally, do the packet contents themselves */
-+ (*aa->update)((void*)&tctx,
-+ (caddr_t)skb->data + irs->iphlen + ahhlen,
-+ skb->len - irs->iphlen - ahhlen);
-+
-+ (*aa->final)(irs->hash, (void *)&tctx);
-+
-+ memcpy(&tctx, irs->octx, irs->octx_len);
-+
-+ (*aa->update)((void *)&tctx, irs->hash, aa->hashlen);
-+ (*aa->final)(irs->hash, (void *)&tctx);
-+
-+ return IPSEC_RCV_OK;
-+}
-+
-+enum ipsec_rcv_value
-+ipsec_rcv_ah_decap(struct ipsec_rcv_state *irs)
-+{
-+ struct ahhdr *ahp = irs->protostuff.ahstuff.ahp;
-+ struct sk_buff *skb;
-+ int ahhlen;
-+
-+ skb=irs->skb;
-+
-+ ahhlen = AH_BASIC_LEN + (ahp->ah_hl << 2);
-+
-+ irs->ipp->tot_len = htons(ntohs(irs->ipp->tot_len) - ahhlen);
-+ irs->next_header = ahp->ah_nh;
-+
-+ /*
-+ * move the IP header forward by the size of the AH header, which
-+ * will remove the the AH header from the packet.
-+ */
-+ memmove((void *)(skb->data + ahhlen),
-+ (void *)(skb->data), irs->iphlen);
-+
-+ ipsec_rcv_dmp("ah postmove", skb->data, skb->len);
-+
-+ /* skb_pull below, will move up by ahhlen */
-+
-+ /* XXX not clear how this can happen, as the message indicates */
-+ if(skb->len < ahhlen) {
-+ printk(KERN_WARNING
-+ "klips_error:ipsec_rcv: "
-+ "tried to skb_pull ahhlen=%d, %d available. This should never happen, please report.\n",
-+ ahhlen,
-+ (int)(skb->len));
-+ return IPSEC_RCV_DECAPFAIL;
-+ }
-+ skb_pull(skb, ahhlen);
-+
-+ irs->ipp = (struct iphdr *)skb->data;
-+
-+ ipsec_rcv_dmp("ah postpull", skb->data, skb->len);
-+
-+ return IPSEC_RCV_OK;
-+}
-+
-+enum ipsec_xmit_value
-+ipsec_xmit_ah_setup(struct ipsec_xmit_state *ixs)
-+{
-+ struct iphdr ipo;
-+ struct ahhdr *ahp;
-+ __u8 hash[AH_AMAX];
-+ union {
-+#ifdef CONFIG_IPSEC_AUTH_HMAC_MD5
-+ MD5_CTX md5;
-+#endif /* CONFIG_IPSEC_AUTH_HMAC_MD5 */
-+#ifdef CONFIG_IPSEC_AUTH_HMAC_SHA1
-+ SHA1_CTX sha1;
-+#endif /* CONFIG_IPSEC_AUTH_HMAC_SHA1 */
-+ } tctx;
-+ unsigned char *dat = (unsigned char *)ixs->iph;
-+
-+ ahp = (struct ahhdr *)(dat + ixs->iphlen);
-+ ahp->ah_spi = ixs->ipsp->ips_said.spi;
-+ ahp->ah_rpl = htonl(++(ixs->ipsp->ips_replaywin_lastseq));
-+ ahp->ah_rv = 0;
-+ ahp->ah_nh = ixs->iph->protocol;
-+ ahp->ah_hl = (sizeof(struct ahhdr) >> 2) - sizeof(__u64)/sizeof(__u32);
-+ ixs->iph->protocol = IPPROTO_AH;
-+ ipsec_xmit_dmp("ahp", (char*)ahp, sizeof(*ahp));
-+
-+ ipo = *ixs->iph;
-+ ipo.tos = 0;
-+ ipo.frag_off = 0;
-+ ipo.ttl = 0;
-+ ipo.check = 0;
-+ ipsec_xmit_dmp("ipo", (char*)&ipo, sizeof(ipo));
-+
-+ switch(ixs->ipsp->ips_authalg) {
-+#ifdef CONFIG_IPSEC_AUTH_HMAC_MD5
-+ case AH_MD5:
-+ tctx.md5 = ((struct md5_ctx*)(ixs->ipsp->ips_key_a))->ictx;
-+ ipsec_xmit_dmp("ictx", (char*)&tctx.md5, sizeof(tctx.md5));
-+ MD5Update(&tctx.md5, (unsigned char *)&ipo, sizeof (struct iphdr));
-+ ipsec_xmit_dmp("ictx+ipo", (char*)&tctx.md5, sizeof(tctx.md5));
-+ MD5Update(&tctx.md5, (unsigned char *)ahp,
-+ sizeof(struct ahhdr) - sizeof(ahp->ah_data));
-+ ipsec_xmit_dmp("ictx+ahp", (char*)&tctx.md5, sizeof(tctx.md5));
-+ MD5Update(&tctx.md5, (unsigned char *)zeroes, AHHMAC_HASHLEN);
-+ ipsec_xmit_dmp("ictx+zeroes", (char*)&tctx.md5, sizeof(tctx.md5));
-+ MD5Update(&tctx.md5, dat + ixs->iphlen + sizeof(struct ahhdr),
-+ ixs->skb->len - ixs->iphlen - sizeof(struct ahhdr));
-+ ipsec_xmit_dmp("ictx+dat", (char*)&tctx.md5, sizeof(tctx.md5));
-+ MD5Final(hash, &tctx.md5);
-+ ipsec_xmit_dmp("ictx hash", (char*)&hash, sizeof(hash));
-+ tctx.md5 = ((struct md5_ctx*)(ixs->ipsp->ips_key_a))->octx;
-+ ipsec_xmit_dmp("octx", (char*)&tctx.md5, sizeof(tctx.md5));
-+ MD5Update(&tctx.md5, hash, AHMD596_ALEN);
-+ ipsec_xmit_dmp("octx+hash", (char*)&tctx.md5, sizeof(tctx.md5));
-+ MD5Final(hash, &tctx.md5);
-+ ipsec_xmit_dmp("octx hash", (char*)&hash, sizeof(hash));
-+
-+ memcpy(ahp->ah_data, hash, AHHMAC_HASHLEN);
-+
-+ /* paranoid */
-+ memset((caddr_t)&tctx.md5, 0, sizeof(tctx.md5));
-+ memset((caddr_t)hash, 0, sizeof(*hash));
-+ break;
-+#endif /* CONFIG_IPSEC_AUTH_HMAC_MD5 */
-+#ifdef CONFIG_IPSEC_AUTH_HMAC_SHA1
-+ case AH_SHA:
-+ tctx.sha1 = ((struct sha1_ctx*)(ixs->ipsp->ips_key_a))->ictx;
-+ SHA1Update(&tctx.sha1, (unsigned char *)&ipo, sizeof (struct iphdr));
-+ SHA1Update(&tctx.sha1, (unsigned char *)ahp, sizeof(struct ahhdr) - sizeof(ahp->ah_data));
-+ SHA1Update(&tctx.sha1, (unsigned char *)zeroes, AHHMAC_HASHLEN);
-+ SHA1Update(&tctx.sha1, dat + ixs->iphlen + sizeof(struct ahhdr),
-+ ixs->skb->len - ixs->iphlen - sizeof(struct ahhdr));
-+ SHA1Final(hash, &tctx.sha1);
-+ tctx.sha1 = ((struct sha1_ctx*)(ixs->ipsp->ips_key_a))->octx;
-+ SHA1Update(&tctx.sha1, hash, AHSHA196_ALEN);
-+ SHA1Final(hash, &tctx.sha1);
-+
-+ memcpy(ahp->ah_data, hash, AHHMAC_HASHLEN);
-+
-+ /* paranoid */
-+ memset((caddr_t)&tctx.sha1, 0, sizeof(tctx.sha1));
-+ memset((caddr_t)hash, 0, sizeof(*hash));
-+ break;
-+#endif /* CONFIG_IPSEC_AUTH_HMAC_SHA1 */
-+ default:
-+ ixs->stats->tx_errors++;
-+ return IPSEC_XMIT_AH_BADALG;
-+ }
-+#ifdef NET_21
-+ ixs->skb->h.raw = (unsigned char*)ahp;
-+#endif /* NET_21 */
-+
-+ return IPSEC_XMIT_OK;
-+}
-+
-+struct xform_functions ah_xform_funcs[]={
-+ { rcv_checks: ipsec_rcv_ah_checks,
-+ rcv_setup_auth: ipsec_rcv_ah_setup_auth,
-+ rcv_calc_auth: ipsec_rcv_ah_authcalc,
-+ rcv_decrypt: ipsec_rcv_ah_decap,
-+
-+ xmit_setup: ipsec_xmit_ah_setup,
-+ xmit_headroom: sizeof(struct ahhdr),
-+ xmit_needtailroom: 0,
-+ },
-+};
-+
-+struct inet_protocol ah_protocol =
-+{
-+ ipsec_rcv, /* AH handler */
-+ NULL, /* TUNNEL error control */
-+#ifdef NETDEV_25
-+ 1, /* no policy */
-+#else
-+ 0, /* next */
-+ IPPROTO_AH, /* protocol ID */
-+ 0, /* copy */
-+ NULL, /* data */
-+ "AH" /* name */
-+#endif
-+};
-+
-+#endif /* CONFIG_IPSEC_AH */
-+
-+/*
-+ * $Log: ipsec_ah.c,v $
-+ * Revision 1.2 2004/04/06 02:49:25 mcr
-+ * pullup of algo code from alg-branch.
-+ *
-+ *
-+ *
-+ */
---- /dev/null Tue Mar 11 13:02:56 2003
-+++ linux/net/ipsec/ipsec_alg.c Mon Feb 9 13:51:03 2004
-@@ -0,0 +1,953 @@
-+/*
-+ * Modular extensions service and registration functions
-+ *
-+ * Author: JuanJo Ciarlante <jjo-ipsec@mendoza.gov.ar>
-+ *
-+ * Version: 0.8.1
-+ *
-+ * ipsec_alg.c,v 1.1.2.1 2003/11/21 18:12:23 jjo Exp
-+ *
-+ * 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. See <http://www.fsf.org/copyleft/gpl.txt>.
-+ *
-+ * 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.
-+ *
-+ */
-+#ifdef CONFIG_IPSEC_ALG
-+#define __NO_VERSION__
-+#include <linux/module.h>
-+#include <linux/kernel.h> /* printk() */
-+
-+#include <linux/netdevice.h> /* struct device, and other headers */
-+#include <linux/etherdevice.h> /* eth_type_trans */
-+#include <linux/ip.h> /* struct iphdr */
-+#include <linux/skbuff.h>
-+#include <linux/socket.h>
-+#include <linux/in.h>
-+#include <linux/types.h>
-+#include <linux/string.h> /* memcmp() */
-+#include <linux/random.h> /* get_random_bytes() */
-+#include <linux/errno.h> /* error codes */
-+#ifdef SPINLOCK
-+# ifdef SPINLOCK_23
-+# include <linux/spinlock.h> /* *lock* */
-+# else /* SPINLOCK_23 */
-+# include <asm/spinlock.h> /* *lock* */
-+# endif /* SPINLOCK_23 */
-+#endif /* SPINLOCK */
-+#ifdef NET_21
-+# include <asm/uaccess.h>
-+# include <linux/in6.h>
-+# define proto_priv cb
-+#endif /* NET21 */
-+#include "openswan/ipsec_param.h"
-+#include <openswan.h>
-+#include "openswan/ipsec_sa.h"
-+#include "openswan/radij.h"
-+#include "openswan/ipsec_encap.h"
-+#include "openswan/ipsec_radij.h"
-+#include "openswan/ipsec_xform.h"
-+#include "openswan/ipsec_tunnel.h"
-+#include "openswan/ipsec_rcv.h"
-+#if defined(CONFIG_IPSEC_ESP) || defined(CONFIG_IPSEC_AH)
-+# include "openswan/ipsec_ah.h"
-+#endif /* defined(CONFIG_IPSEC_ESP) || defined(CONFIG_IPSEC_AH) */
-+#ifdef CONFIG_IPSEC_ESP
-+# include "openswan/ipsec_esp.h"
-+#endif /* !CONFIG_IPSEC_ESP */
-+#ifdef CONFIG_IPSEC_IPCOMP
-+# include "openswan/ipcomp.h"
-+#endif /* CONFIG_IPSEC_COMP */
-+
-+#include <pfkeyv2.h>
-+#include <pfkey.h>
-+
-+#include "openswan/ipsec_alg.h"
-+
-+#ifndef CONFIG_IPSEC_ALG
-+#error This file _MUST_ be compiled with CONFIG_IPSEC_ALG enabled !
-+#endif
-+#if SADB_EALG_MAX < 255
-+#warning Compiling with limited ESP support ( SADB_EALG_MAX < 256 )
-+#endif
-+
-+static rwlock_t ipsec_alg_lock = RW_LOCK_UNLOCKED;
-+#define IPSEC_ALG_HASHSZ 16 /* must be power of 2, even 2^0=1 */
-+static struct list_head ipsec_alg_hash_table[IPSEC_ALG_HASHSZ];
-+
-+/* Old gcc's will fail here */
-+#define barf_out(fmt, args...) do { printk(KERN_ERR "%s: (%s) " fmt, __FUNCTION__, ixt->ixt_name , ## args)\
-+ ; goto out; } while(0)
-+
-+/*
-+ * Must be already protected by lock
-+ */
-+static void __ipsec_alg_usage_inc(struct ipsec_alg *ixt) {
-+ if (ixt->ixt_module)
-+ __MOD_INC_USE_COUNT(ixt->ixt_module);
-+ atomic_inc(&ixt->ixt_refcnt);
-+}
-+static void __ipsec_alg_usage_dec(struct ipsec_alg *ixt) {
-+ atomic_dec(&ixt->ixt_refcnt);
-+ if (ixt->ixt_module)
-+ __MOD_DEC_USE_COUNT(ixt->ixt_module);
-+}
-+/*
-+ * simple hash function, optimized for 0-hash (1 list) special
-+ * case
-+ */
-+#if IPSEC_ALG_HASHSZ > 1
-+static inline unsigned ipsec_alg_hashfn(int alg_type, int alg_id) {
-+ return ((alg_type^alg_id)&(IPSEC_ALG_HASHSZ-1));
-+}
-+#else
-+#define ipsec_alg_hashfn(x,y) (0)
-+#endif
-+
-+/*****************************************************************
-+ *
-+ * INTERNAL table handling: insert, delete, find
-+ *
-+ *****************************************************************/
-+
-+/*
-+ * hash table initialization, called from ipsec_alg_init()
-+ */
-+static void ipsec_alg_hash_init(void) {
-+ struct list_head *head = ipsec_alg_hash_table;
-+ int i = IPSEC_ALG_HASHSZ;
-+ do {
-+ INIT_LIST_HEAD(head);
-+ head++;
-+ i--;
-+ } while (i);
-+}
-+/*
-+ * hash list lookup by {alg_type, alg_id} and table head,
-+ * must be already protected by lock
-+ */
-+static struct ipsec_alg *__ipsec_alg_find(unsigned alg_type, unsigned alg_id, struct list_head * head) {
-+ struct list_head *p;
-+ struct ipsec_alg *ixt=NULL;
-+ for (p=head->next; p!=head; p=p->next) {
-+ ixt = list_entry(p, struct ipsec_alg, ixt_list);
-+ if (ixt->ixt_alg_type == alg_type && ixt->ixt_alg_id==alg_id) {
-+ goto out;
-+ }
-+ }
-+ ixt=NULL;
-+out:
-+ return ixt;
-+}
-+/*
-+ * inserts (in front) a new entry in hash table,
-+ * called from ipsec_alg_register() when new algorithm is registered.
-+ */
-+static int ipsec_alg_insert(struct ipsec_alg *ixt) {
-+ int ret=-EINVAL;
-+ unsigned hashval=ipsec_alg_hashfn(ixt->ixt_alg_type, ixt->ixt_alg_id);
-+ struct list_head *head= ipsec_alg_hash_table + hashval;
-+ struct ipsec_alg *ixt_cur;
-+ /* new element must be virgin ... */
-+ if (ixt->ixt_list.next != &ixt->ixt_list ||
-+ ixt->ixt_list.prev != &ixt->ixt_list) {
-+ printk(KERN_ERR "ipsec_alg_insert: ixt object \"%s\" "
-+ "list head not initialized\n",
-+ ixt->ixt_name);
-+ return ret;
-+ }
-+ write_lock_bh(&ipsec_alg_lock);
-+ ixt_cur = __ipsec_alg_find(ixt->ixt_alg_type, ixt->ixt_alg_id, head);
-+ /* if previous (current) ipsec_alg found check excl flag of _anyone_ */
-+ if (ixt_cur && ((ixt->ixt_state|ixt_cur->ixt_state) & IPSEC_ALG_ST_EXCL))
-+ barf_out("ipsec_alg for alg_type=%d, alg_id=%d already exist. "
-+ "Not loaded (ret=%d).\n",
-+ ixt->ixt_alg_type,
-+ ixt->ixt_alg_id, ret=-EEXIST);
-+ list_add(&ixt->ixt_list, head);
-+ ixt->ixt_state |= IPSEC_ALG_ST_REGISTERED;
-+ ret=0;
-+out:
-+ write_unlock_bh(&ipsec_alg_lock);
-+ return ret;
-+}
-+/*
-+ * deletes an existing entry in hash table,
-+ * called from ipsec_alg_unregister() when algorithm is unregistered.
-+ */
-+static int ipsec_alg_delete(struct ipsec_alg *ixt) {
-+ write_lock_bh(&ipsec_alg_lock);
-+ list_del(&ixt->ixt_list);
-+ write_unlock_bh(&ipsec_alg_lock);
-+ return 0;
-+}
-+/*
-+ * here @user context (read-only when @kernel bh context)
-+ * -> no bh disabling
-+ *
-+ * called from ipsec_sa_init() -> ipsec_alg_sa_init()
-+ */
-+static struct ipsec_alg *ipsec_alg_get(int alg_type, int alg_id) {
-+ unsigned hashval=ipsec_alg_hashfn(alg_type, alg_id);
-+ struct list_head *head= ipsec_alg_hash_table + hashval;
-+ struct ipsec_alg *ixt;
-+ read_lock(&ipsec_alg_lock);
-+ ixt=__ipsec_alg_find(alg_type, alg_id, head);
-+ if (ixt) __ipsec_alg_usage_inc(ixt);
-+ read_unlock(&ipsec_alg_lock);
-+ return ixt;
-+}
-+
-+static void ipsec_alg_put(struct ipsec_alg *ixt) {
-+ __ipsec_alg_usage_dec((struct ipsec_alg *)ixt);
-+}
-+
-+/*****************************************************************
-+ *
-+ * INTERFACE for ENC services: key creation, encrypt function
-+ *
-+ *****************************************************************/
-+
-+/*
-+ * main encrypt service entry point
-+ * called from ipsec_rcv() with encrypt=IPSEC_ALG_DECRYPT and
-+ * ipsec_tunnel_start_xmit with encrypt=IPSEC_ALG_ENCRYPT
-+ */
-+int ipsec_alg_esp_encrypt(struct ipsec_sa *sa_p, __u8 * idat, int ilen, const __u8 * iv, int encrypt) {
-+ int ret;
-+ struct ipsec_alg_enc *ixt_e=sa_p->ips_alg_enc;
-+ KLIPS_PRINT(debug_rcv||debug_tunnel,
-+ "klips_debug:ipsec_alg_esp_encrypt: "
-+ "entering with encalg=%d, ixt_e=%p\n",
-+ sa_p->ips_encalg, ixt_e);
-+ if (!ixt_e) {
-+ KLIPS_PRINT(debug_rcv||debug_tunnel,
-+ "klips_debug:ipsec_alg_esp_encrypt: "
-+ "NULL ipsec_alg_enc object\n");
-+ return -1;
-+ }
-+ KLIPS_PRINT(debug_rcv||debug_tunnel,
-+ "klips_debug:ipsec_alg_esp_encrypt: "
-+ "calling cbc_encrypt encalg=%d "
-+ "ips_key_e=%p idat=%p ilen=%d iv=%p, encrypt=%d\n",
-+ sa_p->ips_encalg,
-+ sa_p->ips_key_e, idat, ilen, iv, encrypt);
-+ ret=ixt_e->ixt_e_cbc_encrypt(ixt_e, sa_p->ips_key_e, idat, ilen, iv, encrypt);
-+ KLIPS_PRINT(debug_rcv||debug_tunnel,
-+ "klips_debug:ipsec_alg_esp_encrypt: "
-+ "returned ret=%d\n",
-+ ret);
-+ return ret;
-+}
-+/*
-+ * encryption key context creation function
-+ * called from pfkey_v2_parser.c:pfkey_ips_init()
-+ */
-+int ipsec_alg_enc_key_create(struct ipsec_sa *sa_p) {
-+ int ret=-EINVAL;
-+ int keyminbits, keymaxbits;
-+ caddr_t ekp;
-+ struct ipsec_alg_enc *ixt_e=sa_p->ips_alg_enc;
-+
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:ipsec_alg_enc_key_create: "
-+ "entering with encalg=%d ixt_e=%p\n",
-+ sa_p->ips_encalg, ixt_e);
-+ if (!ixt_e) {
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:ipsec_alg_enc_key_create: "
-+ "NULL ipsec_alg_enc object\n");
-+ return -EPROTO;
-+ }
-+
-+ /*
-+ * grRRR... DES 7bits jurassic stuff ... f*ckk --jjo
-+ */
-+ switch(ixt_e->ixt_alg_id) {
-+ case ESP_3DES:
-+ keyminbits=keymaxbits=192;break;
-+ case ESP_DES:
-+ keyminbits=keymaxbits=64;break;
-+ default:
-+ keyminbits=ixt_e->ixt_keyminbits;
-+ keymaxbits=ixt_e->ixt_keymaxbits;
-+ }
-+ if(sa_p->ips_key_bits_e<keyminbits ||
-+ sa_p->ips_key_bits_e>keymaxbits) {
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:ipsec_alg_enc_key_create: "
-+ "incorrect encryption key size for id=%d: %d bits -- "
-+ "must be between %d,%d bits\n" /*octets (bytes)\n"*/,
-+ ixt_e->ixt_alg_id,
-+ sa_p->ips_key_bits_e, keyminbits, keymaxbits);
-+ ret=-EINVAL;
-+ goto ixt_out;
-+ }
-+ /* save encryption key pointer */
-+ ekp = sa_p->ips_key_e;
-+
-+
-+ if (ixt_e->ixt_e_new_key) {
-+ sa_p->ips_key_e = ixt_e->ixt_e_new_key(ixt_e,
-+ ekp, sa_p->ips_key_bits_e/8);
-+ ret = (sa_p->ips_key_e)? 0 : -EINVAL;
-+ } else {
-+ if((sa_p->ips_key_e = (caddr_t)
-+ kmalloc((sa_p->ips_key_e_size = ixt_e->ixt_e_ctx_size),
-+ GFP_ATOMIC)) == NULL) {
-+ ret=-ENOMEM;
-+ goto ixt_out;
-+ }
-+ /* zero-out key_e */
-+ memset(sa_p->ips_key_e, 0, sa_p->ips_key_e_size);
-+
-+ /* I cast here to allow more decoupling in alg module */
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:ipsec_alg_enc_key_create: about to call:"
-+ "set_key(key_e=%p, ekp=%p, key_size=%d)\n",
-+ (caddr_t)sa_p->ips_key_e, ekp, sa_p->ips_key_bits_e/8);
-+ ret = ixt_e->ixt_e_set_key(ixt_e, (caddr_t)sa_p->ips_key_e, ekp, sa_p->ips_key_bits_e/8);
-+ }
-+ /* paranoid */
-+ memset(ekp, 0, sa_p->ips_key_bits_e/8);
-+ kfree(ekp);
-+ixt_out:
-+ return ret;
-+}
-+
-+/***************************************************************
-+ *
-+ * INTERFACE for AUTH services: key creation, hash functions
-+ *
-+ ***************************************************************/
-+
-+/*
-+ * auth key context creation function
-+ * called from pfkey_v2_parser.c:pfkey_ips_init()
-+ */
-+int ipsec_alg_auth_key_create(struct ipsec_sa *sa_p) {
-+ int ret=-EINVAL;
-+ struct ipsec_alg_auth *ixt_a=sa_p->ips_alg_auth;
-+ int keyminbits, keymaxbits;
-+ unsigned char *akp;
-+ unsigned int aks;
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:ipsec_alg_auth_key_create: "
-+ "entering with authalg=%d ixt_a=%p\n",
-+ sa_p->ips_authalg, ixt_a);
-+ if (!ixt_a) {
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:ipsec_alg_auth_key_create: "
-+ "NULL ipsec_alg_auth object\n");
-+ return -EPROTO;
-+ }
-+ keyminbits=ixt_a->ixt_keyminbits;
-+ keymaxbits=ixt_a->ixt_keymaxbits;
-+ if(sa_p->ips_key_bits_a<keyminbits || sa_p->ips_key_bits_a>keymaxbits) {
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:ipsec_alg_auth_key_create: incorrect auth"
-+ "key size: %d bits -- must be between %d,%d bits\n"/*octets (bytes)\n"*/,
-+ sa_p->ips_key_bits_a, keyminbits, keymaxbits);
-+ ret=-EINVAL;
-+ goto ixt_out;
-+ }
-+ /* save auth key pointer */
-+ sa_p->ips_auth_bits = ixt_a->ixt_a_keylen * 8; /* XXX XXX */
-+ akp = sa_p->ips_key_a;
-+ aks = sa_p->ips_key_a_size;
-+
-+ /* will hold: 2 ctx and a blocksize buffer: kb */
-+ sa_p->ips_key_a_size = ixt_a->ixt_a_ctx_size;
-+ if((sa_p->ips_key_a =
-+ (caddr_t) kmalloc(sa_p->ips_key_a_size, GFP_ATOMIC)) == NULL) {
-+ ret=-ENOMEM;
-+ goto ixt_out;
-+ }
-+ ixt_a->ixt_a_hmac_set_key(ixt_a, sa_p->ips_key_a, akp, sa_p->ips_key_bits_a/8); /* XXX XXX */
-+ ret=0;
-+ memset(akp, 0, aks);
-+ kfree(akp);
-+
-+ixt_out:
-+ return ret;
-+}
-+
-+
-+int ipsec_alg_sa_esp_hash(const struct ipsec_sa *sa_p, const __u8 *espp, int len, __u8 *hash, int hashlen) {
-+ struct ipsec_alg_auth *ixt_a=sa_p->ips_alg_auth;
-+ if (!ixt_a) {
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:ipsec_sa_esp_hash: "
-+ "NULL ipsec_alg_auth object\n");
-+ return -EPROTO;
-+ }
-+ KLIPS_PRINT(debug_tunnel|debug_rcv,
-+ "klips_debug:ipsec_sa_esp_hash: "
-+ "hashing %p (%d bytes) to %p (%d bytes)\n",
-+ espp, len,
-+ hash, hashlen);
-+ ixt_a->ixt_a_hmac_hash(ixt_a,
-+ sa_p->ips_key_a,
-+ espp, len,
-+ hash, hashlen);
-+ return 0;
-+}
-+
-+/***************************************************************
-+ *
-+ * INTERFACE for module loading,testing, and unloading
-+ *
-+ ***************************************************************/
-+
-+/* validation for registering (enc) module */
-+static int check_enc(struct ipsec_alg_enc *ixt) {
-+ int ret=-EINVAL;
-+ if (ixt->ixt_alg_id==0 || ixt->ixt_alg_id > SADB_EALG_MAX)
-+ barf_out("invalid alg_id=%d >= %d\n", ixt->ixt_alg_id, SADB_EALG_MAX);
-+ if (ixt->ixt_blocksize==0) /* || ixt->ixt_blocksize%2) need for ESP_NULL */
-+ barf_out(KERN_ERR "invalid blocksize=%d\n", ixt->ixt_blocksize);
-+ if (ixt->ixt_keyminbits==0 && ixt->ixt_keymaxbits==0 && ixt->ixt_e_keylen==0)
-+ goto zero_key_ok;
-+ if (ixt->ixt_keyminbits==0)
-+ barf_out(KERN_ERR "invalid keyminbits=%d\n", ixt->ixt_keyminbits);
-+ if (ixt->ixt_keymaxbits==0)
-+ barf_out(KERN_ERR "invalid keymaxbits=%d\n", ixt->ixt_keymaxbits);
-+ if (ixt->ixt_e_keylen==0)
-+ barf_out(KERN_ERR "invalid keysize=%d\n", ixt->ixt_e_keylen);
-+zero_key_ok:
-+ if (ixt->ixt_e_ctx_size==0 && ixt->ixt_e_new_key == NULL)
-+ barf_out(KERN_ERR "invalid key_e_size=%d and ixt_e_new_key=NULL\n", ixt->ixt_e_ctx_size);
-+ if (ixt->ixt_e_cbc_encrypt==NULL)
-+ barf_out(KERN_ERR "e_cbc_encrypt() must be not NULL\n");
-+ ret=0;
-+out:
-+ return ret;
-+}
-+
-+/* validation for registering (auth) module */
-+static int check_auth(struct ipsec_alg_auth *ixt)
-+{
-+ int ret=-EINVAL;
-+ if (ixt->ixt_alg_id==0 || ixt->ixt_alg_id > SADB_AALG_MAX)
-+ barf_out("invalid alg_id=%d > %d (SADB_AALG_MAX)\n", ixt->ixt_alg_id, SADB_AALG_MAX);
-+ if (ixt->ixt_blocksize==0 || ixt->ixt_blocksize%2)
-+ barf_out(KERN_ERR "invalid blocksize=%d\n", ixt->ixt_blocksize);
-+ if (ixt->ixt_blocksize>AH_BLKLEN_MAX)
-+ barf_out(KERN_ERR "sorry blocksize=%d > %d. "
-+ "Please increase AH_BLKLEN_MAX and recompile\n",
-+ ixt->ixt_blocksize,
-+ AH_BLKLEN_MAX);
-+ if (ixt->ixt_keyminbits==0 && ixt->ixt_keymaxbits==0 && ixt->ixt_a_keylen==0)
-+ goto zero_key_ok;
-+ if (ixt->ixt_keyminbits==0)
-+ barf_out(KERN_ERR "invalid keyminbits=%d\n", ixt->ixt_keyminbits);
-+ if (ixt->ixt_keymaxbits==0)
-+ barf_out(KERN_ERR "invalid keymaxbits=%d\n", ixt->ixt_keymaxbits);
-+ if (ixt->ixt_keymaxbits!=ixt->ixt_keyminbits)
-+ barf_out(KERN_ERR "keymaxbits must equal keyminbits (not sure).\n");
-+ if (ixt->ixt_a_keylen==0)
-+ barf_out(KERN_ERR "invalid keysize=%d\n", ixt->ixt_a_keylen);
-+zero_key_ok:
-+ if (ixt->ixt_a_ctx_size==0)
-+ barf_out(KERN_ERR "invalid a_ctx_size=%d\n", ixt->ixt_a_ctx_size);
-+ if (ixt->ixt_a_hmac_set_key==NULL)
-+ barf_out(KERN_ERR "a_hmac_set_key() must be not NULL\n");
-+ if (ixt->ixt_a_hmac_hash==NULL)
-+ barf_out(KERN_ERR "a_hmac_hash() must be not NULL\n");
-+ ret=0;
-+out:
-+ return ret;
-+}
-+
-+/*
-+ * Generic (enc, auth) registration entry point
-+ */
-+int register_ipsec_alg(struct ipsec_alg *ixt) {
-+ int ret=-EINVAL;
-+ /* Validation */
-+ if (ixt==NULL)
-+ barf_out("NULL ipsec_alg object passed\n");
-+ if ((ixt->ixt_version&0xffffff00) != (IPSEC_ALG_VERSION&0xffffff00))
-+ barf_out("incorrect version: %d.%d.%d-%d, "
-+ "must be %d.%d.%d[-%d]\n",
-+ IPSEC_ALG_VERSION_QUAD(ixt->ixt_version),
-+ IPSEC_ALG_VERSION_QUAD(IPSEC_ALG_VERSION));
-+ switch(ixt->ixt_alg_type) {
-+ case IPSEC_ALG_TYPE_AUTH:
-+ if ((ret=check_auth((struct ipsec_alg_auth *)ixt)<0))
-+ goto out;
-+ break;
-+ case IPSEC_ALG_TYPE_ENCRYPT:
-+ if ((ret=check_enc((struct ipsec_alg_enc *)ixt)<0))
-+ goto out;
-+ /*
-+ * Adapted two lines below:
-+ * ivlen == 0 is possible (NULL enc has blocksize==1)
-+ *
-+ * fixed NULL support by David De Reu <DeReu@tComLabs.com>
-+ */
-+ if (ixt->ixt_ivlen == 0 && ixt->ixt_blocksize > 1)
-+ ixt->ixt_ivlen = ixt->ixt_blocksize*8;
-+ break;
-+ default:
-+ barf_out("alg_type=%d not supported\n", ixt->ixt_alg_type);
-+ }
-+ INIT_LIST_HEAD(&ixt->ixt_list);
-+ ret = ipsec_alg_insert(ixt);
-+ if (ret<0)
-+ barf_out(KERN_WARNING "ipsec_alg for alg_id=%d failed."
-+ "Not loaded (ret=%d).\n",
-+ ixt->ixt_alg_id, ret);
-+
-+ ret = pfkey_list_insert_supported((struct supported *)&ixt->ixt_support, &(pfkey_supported_list[SADB_SATYPE_ESP]));
-+ if (ret==0) {
-+ ixt->ixt_state |= IPSEC_ALG_ST_SUPP;
-+ /* send register event to userspace */
-+ pfkey_register_reply(SADB_SATYPE_ESP, NULL);
-+ } else
-+ printk(KERN_ERR "pfkey_list_insert_supported returned %d. "
-+ "Loading anyway.\n", ret);
-+ ret=0;
-+out:
-+ return ret;
-+}
-+
-+/*
-+ * unregister ipsec_alg object from own tables, if
-+ * success => calls pfkey_list_remove_supported()
-+ */
-+int unregister_ipsec_alg(struct ipsec_alg *ixt) {
-+ int ret= -EINVAL;
-+ switch(ixt->ixt_alg_type) {
-+ case IPSEC_ALG_TYPE_AUTH:
-+ case IPSEC_ALG_TYPE_ENCRYPT:
-+ break;
-+ default:
-+ /* this is not a typo :) */
-+ barf_out("frog found in list (\"%s\"): ixt_p=NULL\n",
-+ ixt->ixt_name);
-+ }
-+
-+ ret=ipsec_alg_delete(ixt);
-+ if (ixt->ixt_state&IPSEC_ALG_ST_SUPP) {
-+ ixt->ixt_state &= ~IPSEC_ALG_ST_SUPP;
-+ pfkey_list_remove_supported((struct supported *)&ixt->ixt_support, &(pfkey_supported_list[SADB_SATYPE_ESP]));
-+ /* send register event to userspace */
-+ pfkey_register_reply(SADB_SATYPE_ESP, NULL);
-+ }
-+
-+out:
-+ return ret;
-+}
-+
-+/*
-+ * Must be called from user context
-+ * used at module load type for testing algo implementation
-+ */
-+static int ipsec_alg_test_encrypt(int enc_alg, int test) {
-+ int ret;
-+ caddr_t buf = NULL;
-+ int iv_size, keysize, key_e_size;
-+ struct ipsec_alg_enc *ixt_e;
-+ void *tmp_key_e = NULL;
-+ #define BUFSZ 1024
-+ #define MARGIN 0
-+ #define test_enc (buf+MARGIN)
-+ #define test_dec (test_enc+BUFSZ+MARGIN)
-+ #define test_tmp (test_dec+BUFSZ+MARGIN)
-+ #define test_key_e (test_tmp+BUFSZ+MARGIN)
-+ #define test_iv (test_key_e+key_e_size+MARGIN)
-+ #define test_key (test_iv+iv_size+MARGIN)
-+ #define test_size (BUFSZ*3+key_e_size+iv_size+keysize+MARGIN*7)
-+ ixt_e=(struct ipsec_alg_enc *)ipsec_alg_get(IPSEC_ALG_TYPE_ENCRYPT, enc_alg);
-+ if (ixt_e==NULL) {
-+ KLIPS_PRINT(1,
-+ "klips_debug: ipsec_alg_test_encrypt: "
-+ "encalg=%d object not found\n",
-+ enc_alg);
-+ ret=-EINVAL;
-+ goto out;
-+ }
-+ iv_size=ixt_e->ixt_ivlen / 8;
-+ key_e_size=ixt_e->ixt_e_ctx_size;
-+ keysize=ixt_e->ixt_e_keylen;
-+ KLIPS_PRINT(1,
-+ "klips_debug: ipsec_alg_test_encrypt: "
-+ "enc_alg=%d blocksize=%d key_e_size=%d keysize=%d\n",
-+ enc_alg, iv_size, key_e_size, keysize);
-+ if ((buf=kmalloc (test_size, GFP_KERNEL)) == NULL) {
-+ ret= -ENOMEM;
-+ goto out;
-+ }
-+ get_random_bytes(test_key, keysize);
-+ get_random_bytes(test_iv, iv_size);
-+ if (ixt_e->ixt_e_new_key) {
-+ tmp_key_e = ixt_e->ixt_e_new_key(ixt_e, test_key, keysize);
-+ ret = tmp_key_e ? 0 : -EINVAL;
-+ } else {
-+ tmp_key_e = test_key_e;
-+ ret = ixt_e->ixt_e_set_key(ixt_e, test_key_e, test_key, keysize);
-+ }
-+ if (ret < 0)
-+ goto out;
-+ get_random_bytes(test_enc, BUFSZ);
-+ memcpy(test_tmp, test_enc, BUFSZ);
-+ ret=ixt_e->ixt_e_cbc_encrypt(ixt_e, tmp_key_e, test_enc, BUFSZ, test_iv, 1);
-+ printk(KERN_INFO
-+ "klips_info: ipsec_alg_test_encrypt: "
-+ "cbc_encrypt=1 ret=%d\n",
-+ ret);
-+ ret=memcmp(test_enc, test_tmp, BUFSZ);
-+ printk(KERN_INFO
-+ "klips_info: ipsec_alg_test_encrypt: "
-+ "memcmp(enc, tmp) ret=%d: %s\n", ret,
-+ ret!=0? "OK. (encr->DIFFers)" : "FAIL! (encr->SAME)" );
-+ memcpy(test_dec, test_enc, BUFSZ);
-+ ret=ixt_e->ixt_e_cbc_encrypt(ixt_e, tmp_key_e, test_dec, BUFSZ, test_iv, 0);
-+ printk(KERN_INFO
-+ "klips_info: ipsec_alg_test_encrypt: "
-+ "cbc_encrypt=0 ret=%d\n", ret);
-+ ret=memcmp(test_dec, test_tmp, BUFSZ);
-+ printk(KERN_INFO
-+ "klips_info: ipsec_alg_test_encrypt: "
-+ "memcmp(dec,tmp) ret=%d: %s\n", ret,
-+ ret==0? "OK. (encr->decr->SAME)" : "FAIL! (encr->decr->DIFFers)" );
-+ {
-+ /* Shamelessly taken from drivers/md sources O:) */
-+ unsigned long now;
-+ int i, count, max=0;
-+ int encrypt, speed;
-+ for (encrypt=0; encrypt <2;encrypt ++) {
-+ for (i = 0; i < 5; i++) {
-+ now = jiffies;
-+ count = 0;
-+ while (jiffies == now) {
-+ mb();
-+ ixt_e->ixt_e_cbc_encrypt(ixt_e,
-+ tmp_key_e, test_tmp,
-+ BUFSZ, test_iv, encrypt);
-+ mb();
-+ count++;
-+ mb();
-+ }
-+ if (count > max)
-+ max = count;
-+ }
-+ speed = max * (HZ * BUFSZ / 1024);
-+ printk(KERN_INFO
-+ "klips_info: ipsec_alg_test_encrypt: "
-+ "%s %s speed=%d KB/s\n",
-+ ixt_e->ixt_name,
-+ encrypt? "encrypt": "decrypt", speed);
-+ }
-+ }
-+out:
-+ if (tmp_key_e && ixt_e->ixt_e_destroy_key) ixt_e->ixt_e_destroy_key(ixt_e, tmp_key_e);
-+ if (buf) kfree(buf);
-+ if (ixt_e) ipsec_alg_put((struct ipsec_alg *)ixt_e);
-+ return ret;
-+ #undef test_enc
-+ #undef test_dec
-+ #undef test_tmp
-+ #undef test_key_e
-+ #undef test_iv
-+ #undef test_key
-+ #undef test_size
-+}
-+
-+/*
-+ * Must be called from user context
-+ * used at module load type for testing algo implementation
-+ */
-+static int ipsec_alg_test_auth(int auth_alg, int test) {
-+ int ret;
-+ caddr_t buf = NULL;
-+ int blocksize, keysize, key_a_size;
-+ struct ipsec_alg_auth *ixt_a;
-+ #define BUFSZ 1024
-+ #define MARGIN 0
-+ #define test_auth (buf+MARGIN)
-+ #define test_key_a (test_auth+BUFSZ+MARGIN)
-+ #define test_key (test_key_a+key_a_size+MARGIN)
-+ #define test_hash (test_key+keysize+MARGIN)
-+ #define test_size (BUFSZ+key_a_size+keysize+AHHMAC_HASHLEN+MARGIN*4)
-+ ixt_a=(struct ipsec_alg_auth *)ipsec_alg_get(IPSEC_ALG_TYPE_AUTH, auth_alg);
-+ if (ixt_a==NULL) {
-+ KLIPS_PRINT(1,
-+ "klips_debug: ipsec_alg_test_auth: "
-+ "encalg=%d object not found\n",
-+ auth_alg);
-+ ret=-EINVAL;
-+ goto out;
-+ }
-+ blocksize=ixt_a->ixt_blocksize;
-+ key_a_size=ixt_a->ixt_a_ctx_size;
-+ keysize=ixt_a->ixt_a_keylen;
-+ KLIPS_PRINT(1,
-+ "klips_debug: ipsec_alg_test_auth: "
-+ "auth_alg=%d blocksize=%d key_a_size=%d keysize=%d\n",
-+ auth_alg, blocksize, key_a_size, keysize);
-+ if ((buf=kmalloc (test_size, GFP_KERNEL)) == NULL) {
-+ ret= -ENOMEM;
-+ goto out;
-+ }
-+ get_random_bytes(test_key, keysize);
-+ ret = ixt_a->ixt_a_hmac_set_key(ixt_a, test_key_a, test_key, keysize);
-+ if (ret < 0 )
-+ goto out;
-+ get_random_bytes(test_auth, BUFSZ);
-+ ret=ixt_a->ixt_a_hmac_hash(ixt_a, test_key_a, test_auth, BUFSZ, test_hash, AHHMAC_HASHLEN);
-+ printk(KERN_INFO
-+ "klips_info: ipsec_alg_test_auth: "
-+ "ret=%d\n", ret);
-+ {
-+ /* Shamelessly taken from drivers/md sources O:) */
-+ unsigned long now;
-+ int i, count, max=0;
-+ int speed;
-+ for (i = 0; i < 5; i++) {
-+ now = jiffies;
-+ count = 0;
-+ while (jiffies == now) {
-+ mb();
-+ ixt_a->ixt_a_hmac_hash(ixt_a, test_key_a, test_auth, BUFSZ, test_hash, AHHMAC_HASHLEN);
-+ mb();
-+ count++;
-+ mb();
-+ }
-+ if (count > max)
-+ max = count;
-+ }
-+ speed = max * (HZ * BUFSZ / 1024);
-+ printk(KERN_INFO
-+ "klips_info: ipsec_alg_test_auth: "
-+ "%s hash speed=%d KB/s\n",
-+ ixt_a->ixt_name,
-+ speed);
-+ }
-+out:
-+ if (buf) kfree(buf);
-+ if (ixt_a) ipsec_alg_put((struct ipsec_alg *)ixt_a);
-+ return ret;
-+ #undef test_auth
-+ #undef test_key_a
-+ #undef test_key
-+ #undef test_hash
-+ #undef test_size
-+}
-+
-+int ipsec_alg_test(unsigned alg_type, unsigned alg_id, int test) {
-+ switch(alg_type) {
-+ case IPSEC_ALG_TYPE_ENCRYPT:
-+ return ipsec_alg_test_encrypt(alg_id, test);
-+ break;
-+ case IPSEC_ALG_TYPE_AUTH:
-+ return ipsec_alg_test_auth(alg_id, test);
-+ break;
-+ }
-+ printk(KERN_ERR "klips_info: ipsec_alg_test() called incorrectly: "
-+ "alg_type=%d alg_id=%d\n",
-+ alg_type, alg_id);
-+ return -EINVAL;
-+}
-+
-+int ipsec_alg_init(void) {
-+ KLIPS_PRINT(1, "klips_info:ipsec_alg_init: "
-+ "KLIPS alg v=%d.%d.%d-%d (EALG_MAX=%d, AALG_MAX=%d)\n",
-+ IPSEC_ALG_VERSION_QUAD(IPSEC_ALG_VERSION),
-+ SADB_EALG_MAX, SADB_AALG_MAX);
-+ /* Initialize tables */
-+ write_lock_bh(&ipsec_alg_lock);
-+ ipsec_alg_hash_init();
-+ write_unlock_bh(&ipsec_alg_lock);
-+
-+ /* Initialize static algos */
-+ KLIPS_PRINT(1, "klips_info:ipsec_alg_init: "
-+ "calling ipsec_alg_static_init()\n");
-+
-+ /* If we are suppose to use our AES, and don't have CryptoAPI enabled... */
-+#if defined(CONFIG_IPSEC_ENC_AES) && CONFIG_IPSEC_ENC_AES && !defined(CONFIG_IPSEC_ENC_AES_MODULE) && !CONFIG_IPSEC_ENC_CRYPTOAPI && !defined(CONFIG_IPSEC_ENC_CRYPTOAPI_MODULE)
-+ {
-+ extern int ipsec_aes_init(void);
-+ ipsec_aes_init();
-+ }
-+#endif
-+
-+ /* If we are doing CryptoAPI, then init */
-+#if defined(CONFIG_IPSEC_ENC_CRYPTOAPI) && CONFIG_IPSEC_ENC_CRYPTOAPI && !defined(CONFIG_IPSEC_ENC_CRYPTOAPI_MODULE)
-+ {
-+ extern int ipsec_cryptoapi_init(void);
-+ ipsec_cryptoapi_init();
-+ }
-+#endif
-+
-+
-+ return 0;
-+}
-+
-+/**********************************************
-+ *
-+ * INTERFACE for ipsec_sa init and wipe
-+ *
-+ **********************************************/
-+
-+/*
-+ * Called from pluto -> pfkey_v2_parser.c:pfkey_ipsec_sa_init()
-+ */
-+int ipsec_alg_sa_init(struct ipsec_sa *sa_p) {
-+ struct ipsec_alg_enc *ixt_e;
-+ struct ipsec_alg_auth *ixt_a;
-+
-+ /* Only ESP for now ... */
-+ if (sa_p->ips_said.proto != IPPROTO_ESP)
-+ return -EPROTONOSUPPORT;
-+ KLIPS_PRINT(debug_pfkey, "klips_debug: ipsec_alg_sa_init() :"
-+ "entering for encalg=%d, authalg=%d\n",
-+ sa_p->ips_encalg, sa_p->ips_authalg);
-+ if ((ixt_e=(struct ipsec_alg_enc *)
-+ ipsec_alg_get(IPSEC_ALG_TYPE_ENCRYPT, sa_p->ips_encalg))) {
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug: ipsec_alg_sa_init() :"
-+ "found ipsec_alg (ixt_e=%p) for encalg=%d\n",
-+ ixt_e, sa_p->ips_encalg);
-+ sa_p->ips_alg_enc=ixt_e;
-+ }
-+ if ((ixt_a=(struct ipsec_alg_auth *)
-+ ipsec_alg_get(IPSEC_ALG_TYPE_AUTH, sa_p->ips_authalg))) {
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug: ipsec_alg_sa_init() :"
-+ "found ipsec_alg (ixt_a=%p) for auth=%d\n",
-+ ixt_a, sa_p->ips_authalg);
-+ sa_p->ips_alg_auth=ixt_a;
-+ }
-+ return 0;
-+}
-+
-+/*
-+ * Called from pluto -> ipsec_sa.c:ipsec_sa_delchain()
-+ */
-+int ipsec_alg_sa_wipe(struct ipsec_sa *sa_p) {
-+ struct ipsec_alg *ixt;
-+ if ((ixt=(struct ipsec_alg *)sa_p->ips_alg_enc)) {
-+ KLIPS_PRINT(debug_pfkey, "klips_debug: ipsec_alg_sa_wipe() :"
-+ "unlinking for encalg=%d\n",
-+ ixt->ixt_alg_id);
-+ ipsec_alg_put(ixt);
-+ }
-+ if ((ixt=(struct ipsec_alg *)sa_p->ips_alg_auth)) {
-+ KLIPS_PRINT(debug_pfkey, "klips_debug: ipsec_alg_sa_wipe() :"
-+ "unlinking for authalg=%d\n",
-+ ixt->ixt_alg_id);
-+ ipsec_alg_put(ixt);
-+ }
-+ return 0;
-+}
-+
-+IPSEC_PROCFS_DEBUG_NO_STATIC
-+int
-+ipsec_xform_get_info(char *buffer,
-+ char **start,
-+ off_t offset,
-+ int length IPSEC_PROC_LAST_ARG)
-+{
-+ int len = 0;
-+ off_t begin = 0;
-+ int i;
-+ struct list_head *head;
-+ struct ipsec_alg *ixt;
-+
-+ KLIPS_PRINT(debug_tunnel & DB_TN_PROCFS,
-+ "klips_debug:ipsec_tncfg_get_info: "
-+ "buffer=0p%p, *start=0p%p, offset=%d, length=%d\n",
-+ buffer,
-+ *start,
-+ (int)offset,
-+ length);
-+
-+ for(i = 0, head = ipsec_alg_hash_table; i< IPSEC_ALG_HASHSZ; i++, head++)
-+ {
-+ struct list_head *p;
-+ for (p=head->next; p!=head; p=p->next)
-+ {
-+ ixt = list_entry(p, struct ipsec_alg, ixt_list);
-+ len += ipsec_snprintf(buffer+len, length-len,
-+ "VERSION=%d TYPE=%d ID=%d NAME=%s REFCNT=%d ",
-+ ixt->ixt_version, ixt->ixt_alg_type, ixt->ixt_alg_id,
-+ ixt->ixt_name, ixt->ixt_refcnt);
-+
-+ len += ipsec_snprintf(buffer+len, length-len,
-+ "STATE=%08x BLOCKSIZE=%d IVLEN=%d KEYMINBITS=%d KEYMAXBITS=%d ",
-+ ixt->ixt_state, ixt->ixt_blocksize,
-+ ixt->ixt_ivlen, ixt->ixt_keyminbits, ixt->ixt_keymaxbits);
-+
-+ len += ipsec_snprintf(buffer+len, length-len,
-+ "IVLEN=%d KEYMINBITS=%d KEYMAXBITS=%d ",
-+ ixt->ixt_ivlen, ixt->ixt_keyminbits, ixt->ixt_keymaxbits);
-+
-+ switch(ixt->ixt_alg_type)
-+ {
-+ case IPSEC_ALG_TYPE_AUTH:
-+ {
-+ struct ipsec_alg_auth *auth = (struct ipsec_alg_auth *)ixt;
-+
-+ len += ipsec_snprintf(buffer+len, length-len,
-+ "KEYLEN=%d CTXSIZE=%d AUTHLEN=%d ",
-+ auth->ixt_a_keylen, auth->ixt_a_ctx_size,
-+ auth->ixt_a_authlen);
-+ break;
-+ }
-+ case IPSEC_ALG_TYPE_ENCRYPT:
-+ {
-+ struct ipsec_alg_enc *enc = (struct ipsec_alg_enc *)ixt;
-+ len += ipsec_snprintf(buffer+len, length-len,
-+ "KEYLEN=%d CTXSIZE=%d ",
-+ enc->ixt_e_keylen, enc->ixt_e_ctx_size);
-+
-+ break;
-+ }
-+ }
-+
-+ len += ipsec_snprintf(buffer+len, length-len, "\n");
-+ }
-+ }
-+
-+ *start = buffer + (offset - begin); /* Start of wanted data */
-+ len -= (offset - begin); /* Start slop */
-+ if (len > length)
-+ len = length;
-+ return len;
-+}
-+
-+
-+/*
-+ * As the author of this module, I ONLY ALLOW using it from
-+ * GPL (or same LICENSE TERMS as kernel source) modules.
-+ *
-+ * In respect to hardware crypto engines this means:
-+ * * Closed-source device drivers ARE NOT ALLOWED to use
-+ * this interface.
-+ * * Closed-source VHDL/Verilog firmware running on
-+ * the crypto hardware device IS ALLOWED to use this interface
-+ * via a GPL (or same LICENSE TERMS as kernel source) device driver.
-+ * --Juan Jose Ciarlante 20/03/2002 (thanks RGB for the correct wording)
-+ */
-+
-+/*
-+ * These symbols can only be used from GPL modules
-+ * for now, I'm disabling this because it creates false
-+ * symbol problems for old modutils.
-+ */
-+
-+/* #ifndef EXPORT_SYMBOL_GPL */
-+#undef EXPORT_SYMBOL_GPL
-+#define EXPORT_SYMBOL_GPL EXPORT_SYMBOL
-+/* #endif */
-+EXPORT_SYMBOL_GPL(register_ipsec_alg);
-+EXPORT_SYMBOL_GPL(unregister_ipsec_alg);
-+EXPORT_SYMBOL_GPL(ipsec_alg_test);
-+#endif /* CONFIG_IPSEC_ALG */
---- /dev/null Tue Mar 11 13:02:56 2003
-+++ linux/net/ipsec/ipsec_alg_aes.c Mon Feb 9 13:51:03 2004
-@@ -0,0 +1,263 @@
-+/*
-+ * ipsec_alg AES cipher stubs
-+ *
-+ * Author: JuanJo Ciarlante <jjo-ipsec@mendoza.gov.ar>
-+ *
-+ * ipsec_alg_aes.c,v 1.1.2.1 2003/11/21 18:12:23 jjo Exp
-+ *
-+ * 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. See <http://www.fsf.org/copyleft/gpl.txt>.
-+ *
-+ * 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.
-+ *
-+ * Fixes by:
-+ * PK: Pawel Krawczyk <kravietz@aba.krakow.pl>
-+ * Fixes list:
-+ * PK: make XCBC comply with latest draft (keylength)
-+ *
-+ */
-+#include <linux/config.h>
-+#include <linux/version.h>
-+
-+/*
-+ * special case: ipsec core modular with this static algo inside:
-+ * must avoid MODULE magic for this file
-+ */
-+#if CONFIG_IPSEC_MODULE && CONFIG_IPSEC_ALG_AES
-+#undef MODULE
-+#endif
-+
-+#include <linux/module.h>
-+#include <linux/init.h>
-+
-+#include <linux/kernel.h> /* printk() */
-+#include <linux/errno.h> /* error codes */
-+#include <linux/types.h> /* size_t */
-+#include <linux/string.h>
-+
-+/* Check if __exit is defined, if not null it */
-+#ifndef __exit
-+#define __exit
-+#endif
-+
-+/* Low freeswan header coupling */
-+#include "openswan/ipsec_alg.h"
-+#include "crypto/aes_cbc.h"
-+
-+#define CONFIG_IPSEC_ALG_AES_MAC 1
-+
-+#define AES_CONTEXT_T aes_context
-+MODULE_AUTHOR("JuanJo Ciarlante <jjo-ipsec@mendoza.gov.ar>");
-+static int debug=0;
-+MODULE_PARM(debug, "i");
-+static int test=0;
-+MODULE_PARM(test, "i");
-+static int excl=0;
-+MODULE_PARM(excl, "i");
-+static int keyminbits=0;
-+MODULE_PARM(keyminbits, "i");
-+static int keymaxbits=0;
-+MODULE_PARM(keymaxbits, "i");
-+
-+#if CONFIG_IPSEC_ALG_AES_MAC
-+#include "crypto/aes_xcbc_mac.h"
-+
-+/*
-+ * Not IANA number yet (draft-ietf-ipsec-ciph-aes-xcbc-mac-00.txt).
-+ * We use 9 for non-modular algorithm and none for modular, thus
-+ * forcing user to specify one on module load. -kravietz
-+ */
-+#ifdef MODULE
-+static int auth_id=0;
-+#else
-+static int auth_id=9;
-+#endif
-+MODULE_PARM(auth_id, "i");
-+#endif
-+
-+#define ESP_AES 12 /* truely _constant_ :) */
-+
-+/* 128, 192 or 256 */
-+#define ESP_AES_KEY_SZ_MIN 16 /* 128 bit secret key */
-+#define ESP_AES_KEY_SZ_MAX 32 /* 256 bit secret key */
-+#define ESP_AES_CBC_BLK_LEN 16 /* AES-CBC block size */
-+
-+/* Values according to draft-ietf-ipsec-ciph-aes-xcbc-mac-02.txt
-+ * -kravietz
-+ */
-+#define ESP_AES_MAC_KEY_SZ 16 /* 128 bit MAC key */
-+#define ESP_AES_MAC_BLK_LEN 16 /* 128 bit block */
-+
-+static int _aes_set_key(struct ipsec_alg_enc *alg, __u8 * key_e, const __u8 * key, size_t keysize) {
-+ int ret;
-+ AES_CONTEXT_T *ctx=(AES_CONTEXT_T*)key_e;
-+ ret=AES_set_key(ctx, key, keysize)!=0? 0: -EINVAL;
-+ if (debug > 0)
-+ printk(KERN_DEBUG "klips_debug:_aes_set_key:"
-+ "ret=%d key_e=%p key=%p keysize=%d\n",
-+ ret, key_e, key, keysize);
-+ return ret;
-+}
-+static int _aes_cbc_encrypt(struct ipsec_alg_enc *alg, __u8 * key_e, __u8 * in, int ilen, const __u8 * iv, int encrypt) {
-+ AES_CONTEXT_T *ctx=(AES_CONTEXT_T*)key_e;
-+ if (debug > 0)
-+ printk(KERN_DEBUG "klips_debug:_aes_cbc_encrypt:"
-+ "key_e=%p in=%p ilen=%d iv=%p encrypt=%d\n",
-+ key_e, in, ilen, iv, encrypt);
-+ return AES_cbc_encrypt(ctx, in, in, ilen, iv, encrypt);
-+}
-+#if CONFIG_IPSEC_ALG_AES_MAC
-+static int _aes_mac_set_key(struct ipsec_alg_auth *alg, __u8 * key_a, const __u8 * key, int keylen) {
-+ aes_context_mac *ctxm=(aes_context_mac *)key_a;
-+ return AES_xcbc_mac_set_key(ctxm, key, keylen)? 0 : -EINVAL;
-+}
-+static int _aes_mac_hash(struct ipsec_alg_auth *alg, __u8 * key_a, const __u8 * dat, int len, __u8 * hash, int hashlen) {
-+ int ret;
-+ char hash_buf[16];
-+ aes_context_mac *ctxm=(aes_context_mac *)key_a;
-+ ret=AES_xcbc_mac_hash(ctxm, dat, len, hash_buf);
-+ memcpy(hash, hash_buf, hashlen);
-+ return ret;
-+}
-+static struct ipsec_alg_auth ipsec_alg_AES_MAC = {
-+ ixt_version: IPSEC_ALG_VERSION,
-+ ixt_module: THIS_MODULE,
-+ ixt_refcnt: ATOMIC_INIT(0),
-+ ixt_alg_type: IPSEC_ALG_TYPE_AUTH,
-+ ixt_alg_id: 0,
-+ ixt_name: "aes_mac",
-+ ixt_blocksize: ESP_AES_MAC_BLK_LEN,
-+ ixt_keyminbits: ESP_AES_MAC_KEY_SZ*8,
-+ ixt_keymaxbits: ESP_AES_MAC_KEY_SZ*8,
-+ ixt_a_keylen: ESP_AES_MAC_KEY_SZ,
-+ ixt_a_ctx_size: sizeof(aes_context_mac),
-+ ixt_a_hmac_set_key: _aes_mac_set_key,
-+ ixt_a_hmac_hash:_aes_mac_hash,
-+};
-+#endif /* CONFIG_IPSEC_ALG_AES_MAC */
-+static struct ipsec_alg_enc ipsec_alg_AES = {
-+ ixt_version: IPSEC_ALG_VERSION,
-+ ixt_module: THIS_MODULE,
-+ ixt_refcnt: ATOMIC_INIT(0),
-+ ixt_alg_type: IPSEC_ALG_TYPE_ENCRYPT,
-+ ixt_alg_id: ESP_AES,
-+ ixt_name: "aes",
-+ ixt_blocksize: ESP_AES_CBC_BLK_LEN,
-+ ixt_keyminbits: ESP_AES_KEY_SZ_MIN*8,
-+ ixt_keymaxbits: ESP_AES_KEY_SZ_MAX*8,
-+ ixt_e_keylen: ESP_AES_KEY_SZ_MAX,
-+ ixt_e_ctx_size: sizeof(AES_CONTEXT_T),
-+ ixt_e_set_key: _aes_set_key,
-+ ixt_e_cbc_encrypt:_aes_cbc_encrypt,
-+};
-+
-+#if defined(CONFIG_IPSEC_ENC_AES_MODULE)
-+IPSEC_ALG_MODULE_INIT_MOD( ipsec_aes_init )
-+#else
-+IPSEC_ALG_MODULE_INIT_STATIC( ipsec_aes_init )
-+#endif
-+{
-+ int ret, test_ret;
-+
-+ if (keyminbits)
-+ ipsec_alg_AES.ixt_keyminbits=keyminbits;
-+ if (keymaxbits) {
-+ ipsec_alg_AES.ixt_keymaxbits=keymaxbits;
-+ if (keymaxbits*8>ipsec_alg_AES.ixt_keymaxbits)
-+ ipsec_alg_AES.ixt_e_keylen=keymaxbits*8;
-+ }
-+ if (excl) ipsec_alg_AES.ixt_state |= IPSEC_ALG_ST_EXCL;
-+ ret=register_ipsec_alg_enc(&ipsec_alg_AES);
-+ printk("ipsec_aes_init(alg_type=%d alg_id=%d name=%s): ret=%d\n",
-+ ipsec_alg_AES.ixt_alg_type,
-+ ipsec_alg_AES.ixt_alg_id,
-+ ipsec_alg_AES.ixt_name,
-+ ret);
-+ if (ret==0 && test) {
-+ test_ret=ipsec_alg_test(
-+ ipsec_alg_AES.ixt_alg_type,
-+ ipsec_alg_AES.ixt_alg_id,
-+ test);
-+ printk("ipsec_aes_init(alg_type=%d alg_id=%d): test_ret=%d\n",
-+ ipsec_alg_AES.ixt_alg_type,
-+ ipsec_alg_AES.ixt_alg_id,
-+ test_ret);
-+ }
-+#if CONFIG_IPSEC_ALG_AES_MAC
-+ if (auth_id!=0){
-+ int ret;
-+ ipsec_alg_AES_MAC.ixt_alg_id=auth_id;
-+ ret=register_ipsec_alg_auth(&ipsec_alg_AES_MAC);
-+ printk("ipsec_aes_init(alg_type=%d alg_id=%d name=%s): ret=%d\n",
-+ ipsec_alg_AES_MAC.ixt_alg_type,
-+ ipsec_alg_AES_MAC.ixt_alg_id,
-+ ipsec_alg_AES_MAC.ixt_name,
-+ ret);
-+ if (ret==0 && test) {
-+ test_ret=ipsec_alg_test(
-+ ipsec_alg_AES_MAC.ixt_alg_type,
-+ ipsec_alg_AES_MAC.ixt_alg_id,
-+ test);
-+ printk("ipsec_aes_init(alg_type=%d alg_id=%d): test_ret=%d\n",
-+ ipsec_alg_AES_MAC.ixt_alg_type,
-+ ipsec_alg_AES_MAC.ixt_alg_id,
-+ test_ret);
-+ }
-+ } else {
-+ printk(KERN_DEBUG "klips_debug: experimental ipsec_alg_AES_MAC not registered [Ok] (auth_id=%d)\n", auth_id);
-+ }
-+#endif /* CONFIG_IPSEC_ALG_AES_MAC */
-+ return ret;
-+}
-+
-+#if defined(CONFIG_IPSEC_ENC_AES_MODULE)
-+IPSEC_ALG_MODULE_EXIT_MOD( ipsec_aes_fini )
-+#else
-+IPSEC_ALG_MODULE_EXIT_STATIC( ipsec_aes_fini )
-+#endif
-+{
-+#if CONFIG_IPSEC_ALG_AES_MAC
-+ if (auth_id) unregister_ipsec_alg_auth(&ipsec_alg_AES_MAC);
-+#endif /* CONFIG_IPSEC_ALG_AES_MAC */
-+ unregister_ipsec_alg_enc(&ipsec_alg_AES);
-+ return;
-+}
-+#ifdef MODULE_LICENSE
-+MODULE_LICENSE("GPL");
-+#endif
-+
-+#if 0+NOT_YET
-+#ifndef MODULE
-+/*
-+ * This is intended for static module setups, currently
-+ * doesn't work for modular ipsec.o with static algos inside
-+ */
-+static int setup_keybits(const char *str)
-+{
-+ unsigned aux;
-+ char *end;
-+
-+ aux = simple_strtoul(str,&end,0);
-+ if (aux != 128 && aux != 192 && aux != 256)
-+ return 0;
-+ keyminbits = aux;
-+
-+ if (*end == 0 || *end != ',')
-+ return 1;
-+ str=end+1;
-+ aux = simple_strtoul(str, NULL, 0);
-+ if (aux != 128 && aux != 192 && aux != 256)
-+ return 0;
-+ if (aux >= keyminbits)
-+ keymaxbits = aux;
-+ return 1;
-+}
-+__setup("ipsec_aes_keybits=", setup_keybits);
-+#endif
-+#endif
-+EXPORT_NO_SYMBOLS;
---- /dev/null Tue Mar 11 13:02:56 2003
-+++ linux/net/ipsec/ipsec_alg_cryptoapi.c Mon Feb 9 13:51:03 2004
-@@ -0,0 +1,421 @@
-+/*
-+ * ipsec_alg to linux cryptoapi GLUE
-+ *
-+ * Authors: CODE.ar TEAM
-+ * Harpo MAxx <harpo@linuxmendoza.org.ar>
-+ * JuanJo Ciarlante <jjo-ipsec@mendoza.gov.ar>
-+ * Luciano Ruete <docemeses@softhome.net>
-+ *
-+ * ipsec_alg_cryptoapi.c,v 1.1.2.1 2003/11/21 18:12:23 jjo Exp
-+ *
-+ * 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. See <http://www.fsf.org/copyleft/gpl.txt>.
-+ *
-+ * 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.
-+ *
-+ * Example usage:
-+ * modinfo -p ipsec_cryptoapi (quite useful info, including supported algos)
-+ * modprobe ipsec_cryptoapi
-+ * modprobe ipsec_cryptoapi test=1
-+ * modprobe ipsec_cryptoapi excl=1 (exclusive cipher/algo)
-+ * modprobe ipsec_cryptoapi noauto=1 aes=1 twofish=1 (only these ciphers)
-+ * modprobe ipsec_cryptoapi aes=128,128 (force these keylens)
-+ * modprobe ipsec_cryptoapi des_ede3=0 (everything but 3DES)
-+ */
-+#include <linux/config.h>
-+#include <linux/version.h>
-+
-+/*
-+ * special case: ipsec core modular with this static algo inside:
-+ * must avoid MODULE magic for this file
-+ */
-+#if CONFIG_IPSEC_MODULE && CONFIG_IPSEC_ALG_CRYPTOAPI
-+#undef MODULE
-+#endif
-+
-+#include <linux/module.h>
-+#include <linux/init.h>
-+
-+#include <linux/kernel.h> /* printk() */
-+#include <linux/errno.h> /* error codes */
-+#include <linux/types.h> /* size_t */
-+#include <linux/string.h>
-+
-+/* Check if __exit is defined, if not null it */
-+#ifndef __exit
-+#define __exit
-+#endif
-+
-+/* warn the innocent */
-+#if !defined (CONFIG_CRYPTO) && !defined (CONFIG_CRYPTO_MODULE)
-+#warning "No linux CryptoAPI found, install 2.4.22+ or 2.6.x"
-+#define NO_CRYPTOAPI_SUPPORT
-+#endif
-+/* Low Openswan header coupling */
-+#include "openswan/ipsec_alg.h"
-+
-+#include <linux/crypto.h>
-+#ifdef CRYPTO_API_VERSION_CODE
-+#warning "Old CryptoAPI is not supported. Only linux-2.4.22+ or linux-2.6.x are supported"
-+#define NO_CRYPTOAPI_SUPPORT
-+#endif
-+
-+#ifdef NO_CRYPTOAPI_SUPPORT
-+#warning "Building an unusable module :P"
-+/* Catch old CryptoAPI by not allowing module to load */
-+IPSEC_ALG_MODULE_INIT_STATIC( ipsec_cryptoapi_init )
-+{
-+ printk(KERN_WARNING "ipsec_cryptoapi.o was not built on stock Linux CryptoAPI (2.4.22+ or 2.6.x), not loading.\n");
-+ return -EINVAL;
-+}
-+#else
-+#include <asm/scatterlist.h>
-+#include <asm/pgtable.h>
-+#include <linux/mm.h>
-+
-+#define CIPHERNAME_AES "aes"
-+#define CIPHERNAME_3DES "des3_ede"
-+#define CIPHERNAME_BLOWFISH "blowfish"
-+#define CIPHERNAME_CAST "cast5"
-+#define CIPHERNAME_SERPENT "serpent"
-+#define CIPHERNAME_TWOFISH "twofish"
-+
-+#define ESP_3DES 3
-+#define ESP_AES 12
-+#define ESP_BLOWFISH 7 /* truely _constant_ :) */
-+#define ESP_CAST 6 /* quite constant :) */
-+#define ESP_SERPENT 252 /* from ipsec drafts */
-+#define ESP_TWOFISH 253 /* from ipsec drafts */
-+
-+#define AH_MD5 2
-+#define AH_SHA 3
-+#define DIGESTNAME_MD5 "md5"
-+#define DIGESTNAME_SHA1 "sha1"
-+
-+MODULE_AUTHOR("Juanjo Ciarlante, Harpo MAxx, Luciano Ruete");
-+static int debug=0;
-+MODULE_PARM(debug, "i");
-+static int test=0;
-+MODULE_PARM(test, "i");
-+static int excl=0;
-+MODULE_PARM(excl, "i");
-+
-+static int noauto = 0;
-+MODULE_PARM(noauto,"i");
-+MODULE_PARM_DESC(noauto, "Dont try all known algos, just setup enabled ones");
-+
-+static int des_ede3[] = {-1, -1};
-+static int aes[] = {-1, -1};
-+static int blowfish[] = {-1, -1};
-+static int cast[] = {-1, -1};
-+static int serpent[] = {-1, -1};
-+static int twofish[] = {-1, -1};
-+
-+MODULE_PARM(des_ede3,"1-2i");
-+MODULE_PARM(aes,"1-2i");
-+MODULE_PARM(blowfish,"1-2i");
-+MODULE_PARM(cast,"1-2i");
-+MODULE_PARM(serpent,"1-2i");
-+MODULE_PARM(twofish,"1-2i");
-+MODULE_PARM_DESC(des_ede3, "0: disable | 1: force_enable | min,max: dontuse");
-+MODULE_PARM_DESC(aes, "0: disable | 1: force_enable | min,max: keybitlens");
-+MODULE_PARM_DESC(blowfish, "0: disable | 1: force_enable | min,max: keybitlens");
-+MODULE_PARM_DESC(cast, "0: disable | 1: force_enable | min,max: keybitlens");
-+MODULE_PARM_DESC(serpent, "0: disable | 1: force_enable | min,max: keybitlens");
-+MODULE_PARM_DESC(twofish, "0: disable | 1: force_enable | min,max: keybitlens");
-+
-+struct ipsec_alg_capi_cipher {
-+ const char *ciphername; /* cryptoapi's ciphername */
-+ unsigned blocksize;
-+ unsigned short minbits;
-+ unsigned short maxbits;
-+ int *parm; /* lkm param for this cipher */
-+ struct ipsec_alg_enc alg; /* note it's not a pointer */
-+};
-+static struct ipsec_alg_capi_cipher alg_capi_carray[] = {
-+ { CIPHERNAME_AES , 16, 128, 256, aes , { ixt_alg_id: ESP_AES, }},
-+ { CIPHERNAME_TWOFISH , 16, 128, 256, twofish, { ixt_alg_id: ESP_TWOFISH, }},
-+ { CIPHERNAME_SERPENT , 16, 128, 256, serpent, { ixt_alg_id: ESP_SERPENT, }},
-+ { CIPHERNAME_CAST , 8, 128, 128, cast , { ixt_alg_id: ESP_CAST, }},
-+ { CIPHERNAME_BLOWFISH , 8, 96, 448, blowfish,{ ixt_alg_id: ESP_BLOWFISH, }},
-+ { CIPHERNAME_3DES , 8, 192, 192, des_ede3,{ ixt_alg_id: ESP_3DES, }},
-+ { NULL, 0, 0, 0, NULL, {} }
-+};
-+#ifdef NOT_YET
-+struct ipsec_alg_capi_digest {
-+ const char *digestname; /* cryptoapi's digestname */
-+ struct digest_implementation *di;
-+ struct ipsec_alg_auth alg; /* note it's not a pointer */
-+};
-+static struct ipsec_alg_capi_cipher alg_capi_darray[] = {
-+ { DIGESTNAME_MD5, NULL, { ixt_alg_id: AH_MD5, }},
-+ { DIGESTNAME_SHA1, NULL, { ixt_alg_id: AH_SHA, }},
-+ { NULL, NULL, {} }
-+};
-+#endif
-+/*
-+ * "generic" linux cryptoapi setup_cipher() function
-+ */
-+int setup_cipher(const char *ciphername)
-+{
-+ return crypto_alg_available(ciphername, 0);
-+}
-+
-+/*
-+ * setups ipsec_alg_capi_cipher "hyper" struct components, calling
-+ * register_ipsec_alg for cointaned ipsec_alg object
-+ */
-+static void _capi_destroy_key (struct ipsec_alg_enc *alg, __u8 *key_e);
-+static __u8 * _capi_new_key (struct ipsec_alg_enc *alg, const __u8 *key, size_t keylen);
-+static int _capi_cbc_encrypt(struct ipsec_alg_enc *alg, __u8 * key_e, __u8 * in, int ilen, const __u8 * iv, int encrypt);
-+
-+static int
-+setup_ipsec_alg_capi_cipher(struct ipsec_alg_capi_cipher *cptr)
-+{
-+ int ret;
-+ cptr->alg.ixt_version = IPSEC_ALG_VERSION;
-+ cptr->alg.ixt_module = THIS_MODULE;
-+ atomic_set (& cptr->alg.ixt_refcnt, 0);
-+ strncpy (cptr->alg.ixt_name , cptr->ciphername, sizeof (cptr->alg.ixt_name));
-+
-+ cptr->alg.ixt_blocksize=cptr->blocksize;
-+ cptr->alg.ixt_keyminbits=cptr->minbits;
-+ cptr->alg.ixt_keymaxbits=cptr->maxbits;
-+ cptr->alg.ixt_state = 0;
-+ if (excl) cptr->alg.ixt_state |= IPSEC_ALG_ST_EXCL;
-+ cptr->alg.ixt_e_keylen=cptr->alg.ixt_keymaxbits/8;
-+ cptr->alg.ixt_e_ctx_size = 0;
-+ cptr->alg.ixt_alg_type = IPSEC_ALG_TYPE_ENCRYPT;
-+ cptr->alg.ixt_e_new_key = _capi_new_key;
-+ cptr->alg.ixt_e_destroy_key = _capi_destroy_key;
-+ cptr->alg.ixt_e_cbc_encrypt = _capi_cbc_encrypt;
-+ cptr->alg.ixt_data = cptr;
-+
-+ ret=register_ipsec_alg_enc(&cptr->alg);
-+ printk("setup_ipsec_alg_capi_cipher(): "
-+ "alg_type=%d alg_id=%d name=%s "
-+ "keyminbits=%d keymaxbits=%d, ret=%d\n",
-+ cptr->alg.ixt_alg_type,
-+ cptr->alg.ixt_alg_id,
-+ cptr->alg.ixt_name,
-+ cptr->alg.ixt_keyminbits,
-+ cptr->alg.ixt_keymaxbits,
-+ ret);
-+ return ret;
-+}
-+/*
-+ * called in ipsec_sa_wipe() time, will destroy key contexts
-+ * and do 1 unbind()
-+ */
-+static void
-+_capi_destroy_key (struct ipsec_alg_enc *alg, __u8 *key_e)
-+{
-+ struct crypto_tfm *tfm=(struct crypto_tfm*)key_e;
-+
-+ if (debug > 0)
-+ printk(KERN_DEBUG "klips_debug: _capi_destroy_key:"
-+ "name=%s key_e=%p \n",
-+ alg->ixt_name, key_e);
-+ if (!key_e) {
-+ printk(KERN_ERR "klips_debug: _capi_destroy_key:"
-+ "name=%s NULL key_e!\n",
-+ alg->ixt_name);
-+ return;
-+ }
-+ crypto_free_tfm(tfm);
-+}
-+
-+/*
-+ * create new key context, need alg->ixt_data to know which
-+ * (of many) cipher inside this module is the target
-+ */
-+static __u8 *
-+_capi_new_key (struct ipsec_alg_enc *alg, const __u8 *key, size_t keylen)
-+{
-+ struct ipsec_alg_capi_cipher *cptr;
-+ struct crypto_tfm *tfm=NULL;
-+
-+ cptr = alg->ixt_data;
-+ if (!cptr) {
-+ printk(KERN_ERR "_capi_new_key(): "
-+ "NULL ixt_data (?!) for \"%s\" algo\n"
-+ , alg->ixt_name);
-+ goto err;
-+ }
-+ if (debug > 0)
-+ printk(KERN_DEBUG "klips_debug:_capi_new_key:"
-+ "name=%s cptr=%p key=%p keysize=%d\n",
-+ alg->ixt_name, cptr, key, keylen);
-+
-+ /*
-+ * alloc tfm
-+ */
-+ tfm = crypto_alloc_tfm(cptr->ciphername, CRYPTO_TFM_MODE_CBC);
-+ if (!tfm) {
-+ printk(KERN_ERR "_capi_new_key(): "
-+ "NULL tfm for \"%s\" cryptoapi (\"%s\") algo\n"
-+ , alg->ixt_name, cptr->ciphername);
-+ goto err;
-+ }
-+ if (crypto_cipher_setkey(tfm, key, keylen) < 0) {
-+ printk(KERN_ERR "_capi_new_key(): "
-+ "failed new_key() for \"%s\" cryptoapi algo (keylen=%d)\n"
-+ , alg->ixt_name, keylen);
-+ crypto_free_tfm(tfm);
-+ tfm=NULL;
-+ }
-+err:
-+ if (debug > 0)
-+ printk(KERN_DEBUG "klips_debug:_capi_new_key:"
-+ "name=%s key=%p keylen=%d tfm=%p\n",
-+ alg->ixt_name, key, keylen, tfm);
-+ return (__u8 *) tfm;
-+}
-+/*
-+ * core encryption function: will use cx->ci to call actual cipher's
-+ * cbc function
-+ */
-+static int
-+_capi_cbc_encrypt(struct ipsec_alg_enc *alg, __u8 * key_e, __u8 * in, int ilen, const __u8 * iv, int encrypt) {
-+ int error =0;
-+ struct crypto_tfm *tfm=(struct crypto_tfm *)key_e;
-+ struct scatterlist sg = {
-+ .page = virt_to_page(in),
-+ .offset = (unsigned long)(in) % PAGE_SIZE,
-+ .length=ilen,
-+ };
-+ if (debug > 1)
-+ printk(KERN_DEBUG "klips_debug:_capi_cbc_encrypt:"
-+ "key_e=%p "
-+ "in=%p out=%p ilen=%d iv=%p encrypt=%d\n"
-+ , key_e
-+ , in, in, ilen, iv, encrypt);
-+ crypto_cipher_set_iv(tfm, iv, crypto_tfm_alg_ivsize(tfm));
-+ if (encrypt)
-+ error = crypto_cipher_encrypt (tfm, &sg, &sg, ilen);
-+ else
-+ error = crypto_cipher_decrypt (tfm, &sg, &sg, ilen);
-+ if (debug > 1)
-+ printk(KERN_DEBUG "klips_debug:_capi_cbc_encrypt:"
-+ "error=%d\n"
-+ , error);
-+ return (error<0)? error : ilen;
-+}
-+/*
-+ * main initialization loop: for each cipher in list, do
-+ * 1) setup cryptoapi cipher else continue
-+ * 2) register ipsec_alg object
-+ */
-+static int
-+setup_cipher_list (struct ipsec_alg_capi_cipher* clist)
-+{
-+ struct ipsec_alg_capi_cipher *cptr;
-+ /* foreach cipher in list ... */
-+ for (cptr=clist;cptr->ciphername;cptr++) {
-+ /*
-+ * see if cipher has been disabled (0) or
-+ * if noauto set and not enabled (1)
-+ */
-+ if (cptr->parm[0] == 0 || (noauto && cptr->parm[0] < 0)) {
-+ if (debug>0)
-+ printk(KERN_INFO "setup_cipher_list(): "
-+ "ciphername=%s skipped at user request: "
-+ "noauto=%d parm[0]=%d parm[1]=%d\n"
-+ , cptr->ciphername
-+ , noauto
-+ , cptr->parm[0]
-+ , cptr->parm[1]);
-+ continue;
-+ }
-+ /*
-+ * use a local ci to avoid touching cptr->ci,
-+ * if register ipsec_alg success then bind cipher
-+ */
-+ if( setup_cipher(cptr->ciphername) ) {
-+ if (debug > 0)
-+ printk(KERN_DEBUG "klips_debug:"
-+ "setup_cipher_list():"
-+ "ciphername=%s found\n"
-+ , cptr->ciphername);
-+ if (setup_ipsec_alg_capi_cipher(cptr) == 0) {
-+
-+
-+ } else {
-+ printk(KERN_ERR "klips_debug:"
-+ "setup_cipher_list():"
-+ "ciphername=%s failed ipsec_alg_register\n"
-+ , cptr->ciphername);
-+ }
-+ } else {
-+ if (debug>0)
-+ printk(KERN_INFO "setup_cipher_list(): lookup for ciphername=%s: not found \n",
-+ cptr->ciphername);
-+ }
-+ }
-+ return 0;
-+}
-+/*
-+ * deregister ipsec_alg objects and unbind ciphers
-+ */
-+static int
-+unsetup_cipher_list (struct ipsec_alg_capi_cipher* clist)
-+{
-+ struct ipsec_alg_capi_cipher *cptr;
-+ /* foreach cipher in list ... */
-+ for (cptr=clist;cptr->ciphername;cptr++) {
-+ if (cptr->alg.ixt_state & IPSEC_ALG_ST_REGISTERED) {
-+ unregister_ipsec_alg_enc(&cptr->alg);
-+ }
-+ }
-+ return 0;
-+}
-+/*
-+ * test loop for registered algos
-+ */
-+static int
-+test_cipher_list (struct ipsec_alg_capi_cipher* clist)
-+{
-+ int test_ret;
-+ struct ipsec_alg_capi_cipher *cptr;
-+ /* foreach cipher in list ... */
-+ for (cptr=clist;cptr->ciphername;cptr++) {
-+ if (cptr->alg.ixt_state & IPSEC_ALG_ST_REGISTERED) {
-+ test_ret=ipsec_alg_test(
-+ cptr->alg.ixt_alg_type,
-+ cptr->alg.ixt_alg_id,
-+ test);
-+ printk("test_cipher_list(alg_type=%d alg_id=%d): test_ret=%d\n",
-+ cptr->alg.ixt_alg_type,
-+ cptr->alg.ixt_alg_id,
-+ test_ret);
-+ }
-+ }
-+ return 0;
-+}
-+
-+IPSEC_ALG_MODULE_INIT_STATIC( ipsec_cryptoapi_init )
-+{
-+ int ret, test_ret;
-+ if ((ret=setup_cipher_list(alg_capi_carray)) < 0)
-+ return -EPROTONOSUPPORT;
-+ if (ret==0 && test) {
-+ test_ret=test_cipher_list(alg_capi_carray);
-+ }
-+ return ret;
-+}
-+IPSEC_ALG_MODULE_EXIT_STATIC( ipsec_cryptoapi_fini )
-+{
-+ unsetup_cipher_list(alg_capi_carray);
-+ return;
-+}
-+#ifdef MODULE_LICENSE
-+MODULE_LICENSE("GPL");
-+#endif
-+
-+EXPORT_NO_SYMBOLS;
-+#endif /* NO_CRYPTOAPI_SUPPORT */
---- /dev/null Tue Mar 11 13:02:56 2003
-+++ linux/net/ipsec/ipsec_esp.c Mon Feb 9 13:51:03 2004
-@@ -0,0 +1,558 @@
-+/*
-+ * processing code for ESP
-+ * Copyright (C) 2003 Michael Richardson <mcr@sandelman.ottawa.on.ca>
-+ *
-+ * 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. See <http://www.fsf.org/copyleft/gpl.txt>.
-+ *
-+ * 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.
-+ */
-+
-+char ipsec_esp_c_version[] = "RCSID $Id: ipsec_esp.c,v 1.2 2004/04/06 02:49:25 mcr Exp $";
-+#include <linux/config.h>
-+#include <linux/version.h>
-+
-+#define __NO_VERSION__
-+#include <linux/module.h>
-+#include <linux/kernel.h> /* printk() */
-+
-+#include "openswan/ipsec_param.h"
-+
-+#ifdef MALLOC_SLAB
-+# include <linux/slab.h> /* kmalloc() */
-+#else /* MALLOC_SLAB */
-+# include <linux/malloc.h> /* kmalloc() */
-+#endif /* MALLOC_SLAB */
-+#include <linux/errno.h> /* error codes */
-+#include <linux/types.h> /* size_t */
-+#include <linux/interrupt.h> /* mark_bh */
-+
-+#include <linux/netdevice.h> /* struct device, and other headers */
-+#include <linux/etherdevice.h> /* eth_type_trans */
-+#include <linux/ip.h> /* struct iphdr */
-+#include <linux/skbuff.h>
-+#include <openswan.h>
-+#ifdef SPINLOCK
-+# ifdef SPINLOCK_23
-+# include <linux/spinlock.h> /* *lock* */
-+# else /* SPINLOCK_23 */
-+# include <asm/spinlock.h> /* *lock* */
-+# endif /* SPINLOCK_23 */
-+#endif /* SPINLOCK */
-+#ifdef NET_21
-+# include <asm/uaccess.h>
-+# include <linux/in6.h>
-+# define proto_priv cb
-+#endif /* NET21 */
-+#include <asm/checksum.h>
-+#include <net/ip.h>
-+
-+#include "openswan/radij.h"
-+#include "openswan/ipsec_encap.h"
-+#include "openswan/ipsec_sa.h"
-+
-+#include "openswan/ipsec_radij.h"
-+#include "openswan/ipsec_xform.h"
-+#include "openswan/ipsec_tunnel.h"
-+#include "openswan/ipsec_rcv.h"
-+#include "openswan/ipsec_xmit.h"
-+
-+#include "openswan/ipsec_auth.h"
-+
-+#ifdef CONFIG_IPSEC_ESP
-+#include "openswan/ipsec_esp.h"
-+#endif /* CONFIG_IPSEC_ESP */
-+
-+#include "openswan/ipsec_proto.h"
-+#include "openswan/ipsec_alg.h"
-+
-+#ifdef CONFIG_IPSEC_DEBUG
-+int debug_esp = 0;
-+#endif /* CONFIG_IPSEC_DEBUG */
-+
-+
-+#ifdef CONFIG_IPSEC_ESP
-+enum ipsec_rcv_value
-+ipsec_rcv_esp_checks(struct ipsec_rcv_state *irs,
-+ struct sk_buff *skb)
-+{
-+ __u8 proto;
-+ int len; /* packet length */
-+
-+ len = skb->len;
-+ proto = irs->ipp->protocol;
-+
-+ /* XXX this will need to be 8 for IPv6 */
-+ if ((proto == IPPROTO_ESP) && ((len - irs->iphlen) % 4)) {
-+ printk("klips_error:ipsec_rcv: "
-+ "got packet with content length = %d from %s -- should be on 4 octet boundary, packet dropped\n",
-+ len - irs->iphlen,
-+ irs->ipsaddr_txt);
-+ if(irs->stats) {
-+ irs->stats->rx_errors++;
-+ }
-+ return IPSEC_RCV_BADLEN;
-+ }
-+
-+ if(skb->len < (irs->hard_header_len + sizeof(struct iphdr) + sizeof(struct esphdr))) {
-+ KLIPS_PRINT(debug_rcv & DB_RX_INAU,
-+ "klips_debug:ipsec_rcv: "
-+ "runt esp packet of skb->len=%d received from %s, dropped.\n",
-+ skb->len,
-+ irs->ipsaddr_txt);
-+ if(irs->stats) {
-+ irs->stats->rx_errors++;
-+ }
-+ return IPSEC_RCV_BADLEN;
-+ }
-+
-+ irs->protostuff.espstuff.espp = (struct esphdr *)(skb->data + irs->iphlen);
-+ irs->said.spi = irs->protostuff.espstuff.espp->esp_spi;
-+
-+ return IPSEC_RCV_OK;
-+}
-+
-+enum ipsec_rcv_value
-+ipsec_rcv_esp_decrypt_setup(struct ipsec_rcv_state *irs,
-+ struct sk_buff *skb,
-+ __u32 *replay,
-+ unsigned char **authenticator)
-+{
-+ struct esphdr *espp = irs->protostuff.espstuff.espp;
-+
-+ KLIPS_PRINT(debug_rcv,
-+ "klips_debug:ipsec_rcv: "
-+ "packet from %s received with seq=%d (iv)=0x%08x%08x iplen=%d esplen=%d sa=%s\n",
-+ irs->ipsaddr_txt,
-+ (__u32)ntohl(espp->esp_rpl),
-+ (__u32)ntohl(*((__u32 *)(espp->esp_iv) )),
-+ (__u32)ntohl(*((__u32 *)(espp->esp_iv) + 1)),
-+ irs->len,
-+ irs->ilen,
-+ irs->sa_len ? irs->sa : " (error)");
-+
-+ *replay = ntohl(espp->esp_rpl);
-+ *authenticator = &(skb->data[irs->len - irs->authlen]);
-+
-+ return IPSEC_RCV_OK;
-+}
-+
-+enum ipsec_rcv_value
-+ipsec_rcv_esp_authcalc(struct ipsec_rcv_state *irs,
-+ struct sk_buff *skb)
-+{
-+ struct auth_alg *aa;
-+ struct esphdr *espp = irs->protostuff.espstuff.espp;
-+ union {
-+ MD5_CTX md5;
-+ SHA1_CTX sha1;
-+ } tctx;
-+
-+#ifdef CONFIG_IPSEC_ALG
-+ if (irs->ipsp->ips_alg_auth) {
-+ KLIPS_PRINT(debug_rcv,
-+ "klips_debug:ipsec_rcv: "
-+ "ipsec_alg hashing proto=%d... ",
-+ irs->said.proto);
-+ if(irs->said.proto == IPPROTO_ESP) {
-+ ipsec_alg_sa_esp_hash(irs->ipsp,
-+ (caddr_t)espp, irs->ilen,
-+ irs->hash, AHHMAC_HASHLEN);
-+ return IPSEC_RCV_OK;
-+ }
-+ return IPSEC_RCV_BADPROTO;
-+ }
-+#endif
-+ aa = irs->authfuncs;
-+
-+ /* copy the initialized keying material */
-+ memcpy(&tctx, irs->ictx, irs->ictx_len);
-+
-+ (*aa->update)((void *)&tctx, (caddr_t)espp, irs->ilen);
-+
-+ (*aa->final)(irs->hash, (void *)&tctx);
-+
-+ memcpy(&tctx, irs->octx, irs->octx_len);
-+
-+ (*aa->update)((void *)&tctx, irs->hash, aa->hashlen);
-+ (*aa->final)(irs->hash, (void *)&tctx);
-+
-+ return IPSEC_RCV_OK;
-+}
-+
-+
-+enum ipsec_rcv_value
-+ipsec_rcv_esp_decrypt(struct ipsec_rcv_state *irs)
-+{
-+ struct ipsec_sa *ipsp = irs->ipsp;
-+ struct esphdr *espp = irs->protostuff.espstuff.espp;
-+ int esphlen = 0;
-+ __u8 *idat; /* pointer to content to be decrypted/authenticated */
-+ __u32 iv[2];
-+ int pad = 0, padlen;
-+ int badpad = 0;
-+ int i;
-+ struct sk_buff *skb;
-+#ifdef CONFIG_IPSEC_ALG
-+ struct ipsec_alg_enc *ixt_e=NULL;
-+#endif /* CONFIG_IPSEC_ALG */
-+
-+ skb=irs->skb;
-+
-+ idat = skb->data + irs->iphlen;
-+
-+#ifdef CONFIG_IPSEC_ALG
-+ if ((ixt_e=ipsp->ips_alg_enc)) {
-+ esphlen = ESP_HEADER_LEN + ixt_e->ixt_ivlen/8;
-+ KLIPS_PRINT(debug_rcv,
-+ "klips_debug:ipsec_rcv: "
-+ "encalg=%d esphlen=%d\n",
-+ ipsp->ips_encalg, esphlen);
-+ } else
-+#endif /* CONFIG_IPSEC_ALG */
-+ switch(ipsp->ips_encalg) {
-+ case ESP_3DES:
-+ iv[0] = *((__u32 *)(espp->esp_iv) );
-+ iv[1] = *((__u32 *)(espp->esp_iv) + 1);
-+ esphlen = sizeof(struct esphdr);
-+ break;
-+ default:
-+ ipsp->ips_errs.ips_alg_errs += 1;
-+ if(irs->stats) {
-+ irs->stats->rx_errors++;
-+ }
-+ return IPSEC_RCV_ESP_BADALG;
-+ }
-+
-+ idat += esphlen;
-+ irs->ilen -= esphlen;
-+
-+#ifdef CONFIG_IPSEC_ALG
-+ if (ixt_e)
-+ {
-+ if (ipsec_alg_esp_encrypt(ipsp,
-+ idat, irs->ilen, espp->esp_iv,
-+ IPSEC_ALG_DECRYPT) <= 0)
-+ {
-+ printk("klips_error:ipsec_rcv: "
-+ "got packet with esplen = %d "
-+ "from %s -- should be on "
-+ "ENC(%d) octet boundary, "
-+ "packet dropped\n",
-+ irs->ilen,
-+ irs->ipsaddr_txt,
-+ ipsp->ips_encalg);
-+ if(irs->stats) {
-+ irs->stats->rx_errors++;
-+ }
-+ return IPSEC_RCV_BAD_DECRYPT;
-+ }
-+ } else
-+#endif /* CONFIG_IPSEC_ALG */
-+ switch(ipsp->ips_encalg) {
-+ case ESP_3DES:
-+ if ((irs->ilen) % 8) {
-+ ipsp->ips_errs.ips_encsize_errs += 1;
-+ printk("klips_error:ipsec_rcv: "
-+ "got packet with esplen = %d from %s -- should be on 8 octet boundary, packet dropped\n",
-+ irs->ilen,
-+ irs->ipsaddr_txt);
-+ if(irs->stats) {
-+ irs->stats->rx_errors++;
-+ }
-+ return IPSEC_RCV_3DES_BADBLOCKING;
-+ }
-+ des_ede3_cbc_encrypt((des_cblock *)idat,
-+ (des_cblock *)idat,
-+ irs->ilen,
-+ ((struct des_eks *)(ipsp->ips_key_e))[0].ks,
-+ ((struct des_eks *)(ipsp->ips_key_e))[1].ks,
-+ ((struct des_eks *)(ipsp->ips_key_e))[2].ks,
-+ (des_cblock *)iv, 0);
-+ break;
-+ }
-+
-+ ipsec_rcv_dmp("postdecrypt", skb->data, skb->len);
-+
-+ irs->next_header = idat[irs->ilen - 1];
-+ padlen = idat[irs->ilen - 2];
-+ pad = padlen + 2 + irs->authlen;
-+
-+ KLIPS_PRINT(debug_rcv & DB_RX_IPAD,
-+ "klips_debug:ipsec_rcv: "
-+ "padlen=%d, contents: 0x<offset>: 0x<value> 0x<value> ...\n",
-+ padlen);
-+
-+ for (i = 1; i <= padlen; i++) {
-+ if((i % 16) == 1) {
-+ KLIPS_PRINT(debug_rcv & DB_RX_IPAD,
-+ "klips_debug: %02x:",
-+ i - 1);
-+ }
-+ KLIPS_PRINTMORE(debug_rcv & DB_RX_IPAD,
-+ " %02x",
-+ idat[irs->ilen - 2 - padlen + i - 1]);
-+ if(i != idat[irs->ilen - 2 - padlen + i - 1]) {
-+ badpad = 1;
-+ }
-+ if((i % 16) == 0) {
-+ KLIPS_PRINTMORE(debug_rcv & DB_RX_IPAD,
-+ "\n");
-+ }
-+ }
-+ if((i % 16) != 1) {
-+ KLIPS_PRINTMORE(debug_rcv & DB_RX_IPAD,
-+ "\n");
-+ }
-+ if(badpad) {
-+ KLIPS_PRINT(debug_rcv & DB_RX_IPAD,
-+ "klips_debug:ipsec_rcv: "
-+ "warning, decrypted packet from %s has bad padding\n",
-+ irs->ipsaddr_txt);
-+ KLIPS_PRINT(debug_rcv & DB_RX_IPAD,
-+ "klips_debug:ipsec_rcv: "
-+ "...may be bad decryption -- not dropped\n");
-+ ipsp->ips_errs.ips_encpad_errs += 1;
-+ }
-+
-+ KLIPS_PRINT(debug_rcv & DB_RX_IPAD,
-+ "klips_debug:ipsec_rcv: "
-+ "packet decrypted from %s: next_header = %d, padding = %d\n",
-+ irs->ipsaddr_txt,
-+ irs->next_header,
-+ pad - 2 - irs->authlen);
-+
-+ irs->ipp->tot_len = htons(ntohs(irs->ipp->tot_len) - (esphlen + pad));
-+
-+ /*
-+ * move the IP header forward by the size of the ESP header, which
-+ * will remove the the ESP header from the packet.
-+ */
-+ memmove((void *)(skb->data + esphlen),
-+ (void *)(skb->data), irs->iphlen);
-+
-+ ipsec_rcv_dmp("esp postmove", skb->data, skb->len);
-+
-+ /* skb_pull below, will move up by esphlen */
-+
-+ /* XXX not clear how this can happen, as the message indicates */
-+ if(skb->len < esphlen) {
-+ printk(KERN_WARNING
-+ "klips_error:ipsec_rcv: "
-+ "tried to skb_pull esphlen=%d, %d available. This should never happen, please report.\n",
-+ esphlen, (int)(skb->len));
-+ return IPSEC_RCV_ESP_DECAPFAIL;
-+ }
-+ skb_pull(skb, esphlen);
-+
-+ irs->ipp = (struct iphdr *)skb->data;
-+
-+ ipsec_rcv_dmp("esp postpull", skb->data, skb->len);
-+
-+ /* now, trip off the padding from the end */
-+ KLIPS_PRINT(debug_rcv & DB_RX_PKTRX,
-+ "klips_debug:ipsec_rcv: "
-+ "trimming to %d.\n",
-+ irs->len - esphlen - pad);
-+ if(pad + esphlen <= irs->len) {
-+ skb_trim(skb, irs->len - esphlen - pad);
-+ } else {
-+ KLIPS_PRINT(debug_rcv & DB_RX_PKTRX,
-+ "klips_debug:ipsec_rcv: "
-+ "bogus packet, size is zero or negative, dropping.\n");
-+ return IPSEC_RCV_DECAPFAIL;
-+ }
-+
-+ return IPSEC_RCV_OK;
-+}
-+
-+enum ipsec_xmit_value
-+ipsec_xmit_esp_setup(struct ipsec_xmit_state *ixs)
-+{
-+ __u32 iv[2];
-+ struct esphdr *espp;
-+ int ilen = 0;
-+ int padlen = 0, i;
-+ unsigned char *dat;
-+ unsigned char *idat, *pad;
-+ __u8 hash[AH_AMAX];
-+ union {
-+#ifdef CONFIG_IPSEC_AUTH_HMAC_MD5
-+ MD5_CTX md5;
-+#endif /* CONFIG_IPSEC_AUTH_HMAC_MD5 */
-+#ifdef CONFIG_IPSEC_AUTH_HMAC_SHA1
-+ SHA1_CTX sha1;
-+#endif /* CONFIG_IPSEC_AUTH_HMAC_SHA1 */
-+ } tctx;
-+
-+ dat = (unsigned char *)ixs->iph;
-+
-+ espp = (struct esphdr *)(dat + ixs->iphlen);
-+ espp->esp_spi = ixs->ipsp->ips_said.spi;
-+ espp->esp_rpl = htonl(++(ixs->ipsp->ips_replaywin_lastseq));
-+
-+ switch(ixs->ipsp->ips_encalg) {
-+#if defined(CONFIG_IPSEC_ENC_3DES)
-+#ifdef CONFIG_IPSEC_ENC_3DES
-+ case ESP_3DES:
-+#endif /* CONFIG_IPSEC_ENC_3DES */
-+ iv[0] = *((__u32*)&(espp->esp_iv) ) =
-+ ((__u32*)(ixs->ipsp->ips_iv))[0];
-+ iv[1] = *((__u32*)&(espp->esp_iv) + 1) =
-+ ((__u32*)(ixs->ipsp->ips_iv))[1];
-+ break;
-+#endif /* defined(CONFIG_IPSEC_ENC_3DES) */
-+ default:
-+ ixs->stats->tx_errors++;
-+ return IPSEC_XMIT_ESP_BADALG;
-+ }
-+
-+ idat = dat + ixs->iphlen + sizeof(struct esphdr);
-+ ilen = ixs->skb->len - (ixs->iphlen + sizeof(struct esphdr) + ixs->authlen);
-+
-+ /* Self-describing padding */
-+ pad = &dat[ixs->skb->len - ixs->tailroom];
-+ padlen = ixs->tailroom - 2 - ixs->authlen;
-+ for (i = 0; i < padlen; i++) {
-+ pad[i] = i + 1;
-+ }
-+ dat[ixs->skb->len - ixs->authlen - 2] = padlen;
-+
-+ dat[ixs->skb->len - ixs->authlen - 1] = ixs->iph->protocol;
-+ ixs->iph->protocol = IPPROTO_ESP;
-+
-+ switch(ixs->ipsp->ips_encalg) {
-+#ifdef CONFIG_IPSEC_ENC_3DES
-+ case ESP_3DES:
-+ des_ede3_cbc_encrypt((des_cblock *)idat,
-+ (des_cblock *)idat,
-+ ilen,
-+ ((struct des_eks *)(ixs->ipsp->ips_key_e))[0].ks,
-+ ((struct des_eks *)(ixs->ipsp->ips_key_e))[1].ks,
-+ ((struct des_eks *)(ixs->ipsp->ips_key_e))[2].ks,
-+ (des_cblock *)iv, 1);
-+ break;
-+#endif /* CONFIG_IPSEC_ENC_3DES */
-+ default:
-+ ixs->stats->tx_errors++;
-+ return IPSEC_XMIT_ESP_BADALG;
-+ }
-+
-+ switch(ixs->ipsp->ips_encalg) {
-+#if defined(CONFIG_IPSEC_ENC_3DES)
-+#ifdef CONFIG_IPSEC_ENC_3DES
-+ case ESP_3DES:
-+#endif /* CONFIG_IPSEC_ENC_3DES */
-+ /* XXX update IV with the last 8 octets of the encryption */
-+#if KLIPS_IMPAIRMENT_ESPIV_CBC_ATTACK
-+ ((__u32*)(ixs->ipsp->ips_iv))[0] =
-+ ((__u32 *)(idat))[(ilen >> 2) - 2];
-+ ((__u32*)(ixs->ipsp->ips_iv))[1] =
-+ ((__u32 *)(idat))[(ilen >> 2) - 1];
-+#else /* KLIPS_IMPAIRMENT_ESPIV_CBC_ATTACK */
-+ prng_bytes(&ipsec_prng, (char *)ixs->ipsp->ips_iv, EMT_ESPDES_IV_SZ);
-+#endif /* KLIPS_IMPAIRMENT_ESPIV_CBC_ATTACK */
-+ break;
-+#endif /* defined(CONFIG_IPSEC_ENC_3DES) */
-+ default:
-+ ixs->stats->tx_errors++;
-+ return IPSEC_XMIT_ESP_BADALG;
-+ }
-+
-+ switch(ixs->ipsp->ips_authalg) {
-+#ifdef CONFIG_IPSEC_AUTH_HMAC_MD5
-+ case AH_MD5:
-+ ipsec_xmit_dmp("espp", (char*)espp, ixs->skb->len - ixs->iphlen - ixs->authlen);
-+ tctx.md5 = ((struct md5_ctx*)(ixs->ipsp->ips_key_a))->ictx;
-+ ipsec_xmit_dmp("ictx", (char*)&tctx.md5, sizeof(tctx.md5));
-+ MD5Update(&tctx.md5, (caddr_t)espp, ixs->skb->len - ixs->iphlen - ixs->authlen);
-+ ipsec_xmit_dmp("ictx+dat", (char*)&tctx.md5, sizeof(tctx.md5));
-+ MD5Final(hash, &tctx.md5);
-+ ipsec_xmit_dmp("ictx hash", (char*)&hash, sizeof(hash));
-+ tctx.md5 = ((struct md5_ctx*)(ixs->ipsp->ips_key_a))->octx;
-+ ipsec_xmit_dmp("octx", (char*)&tctx.md5, sizeof(tctx.md5));
-+ MD5Update(&tctx.md5, hash, AHMD596_ALEN);
-+ ipsec_xmit_dmp("octx+hash", (char*)&tctx.md5, sizeof(tctx.md5));
-+ MD5Final(hash, &tctx.md5);
-+ ipsec_xmit_dmp("octx hash", (char*)&hash, sizeof(hash));
-+ memcpy(&(dat[ixs->skb->len - ixs->authlen]), hash, ixs->authlen);
-+
-+ /* paranoid */
-+ memset((caddr_t)&tctx.md5, 0, sizeof(tctx.md5));
-+ memset((caddr_t)hash, 0, sizeof(*hash));
-+ break;
-+#endif /* CONFIG_IPSEC_AUTH_HMAC_MD5 */
-+#ifdef CONFIG_IPSEC_AUTH_HMAC_SHA1
-+ case AH_SHA:
-+ tctx.sha1 = ((struct sha1_ctx*)(ixs->ipsp->ips_key_a))->ictx;
-+ SHA1Update(&tctx.sha1, (caddr_t)espp, ixs->skb->len - ixs->iphlen - ixs->authlen);
-+ SHA1Final(hash, &tctx.sha1);
-+ tctx.sha1 = ((struct sha1_ctx*)(ixs->ipsp->ips_key_a))->octx;
-+ SHA1Update(&tctx.sha1, hash, AHSHA196_ALEN);
-+ SHA1Final(hash, &tctx.sha1);
-+ memcpy(&(dat[ixs->skb->len - ixs->authlen]), hash, ixs->authlen);
-+
-+ /* paranoid */
-+ memset((caddr_t)&tctx.sha1, 0, sizeof(tctx.sha1));
-+ memset((caddr_t)hash, 0, sizeof(*hash));
-+ break;
-+#endif /* CONFIG_IPSEC_AUTH_HMAC_SHA1 */
-+ case AH_NONE:
-+ break;
-+ default:
-+ ixs->stats->tx_errors++;
-+ return IPSEC_XMIT_AH_BADALG;
-+ }
-+#ifdef NET_21
-+ ixs->skb->h.raw = (unsigned char*)espp;
-+#endif /* NET_21 */
-+
-+ return IPSEC_XMIT_OK;
-+}
-+
-+
-+struct xform_functions esp_xform_funcs[]={
-+ { rcv_checks: ipsec_rcv_esp_checks,
-+ rcv_setup_auth: ipsec_rcv_esp_decrypt_setup,
-+ rcv_calc_auth: ipsec_rcv_esp_authcalc,
-+ rcv_decrypt: ipsec_rcv_esp_decrypt,
-+
-+ xmit_setup: ipsec_xmit_esp_setup,
-+ xmit_headroom: sizeof(struct esphdr),
-+ xmit_needtailroom: 1,
-+ },
-+};
-+
-+struct inet_protocol esp_protocol =
-+{
-+ ipsec_rcv, /* ESP handler */
-+ NULL, /* TUNNEL error control */
-+#ifdef NETDEV_25
-+ 1, /* no policy */
-+#else
-+ 0, /* next */
-+ IPPROTO_ESP, /* protocol ID */
-+ 0, /* copy */
-+ NULL, /* data */
-+ "ESP" /* name */
-+#endif
-+};
-+
-+
-+
-+#endif /* !CONFIG_IPSEC_ESP */
-+
-+
-+/*
-+ * $Log: ipsec_esp.c,v $
-+ * Revision 1.2 2004/04/06 02:49:25 mcr
-+ * pullup of algo code from alg-branch.
-+ *
-+ *
-+ *
-+ */
---- /dev/null Tue Mar 11 13:02:56 2003
-+++ linux/net/ipsec/ipsec_init.c Mon Feb 9 13:51:03 2004
-@@ -0,0 +1,531 @@
-+/*
-+ * @(#) Initialization code.
-+ * Copyright (C) 1996, 1997 John Ioannidis.
-+ * Copyright (C) 1998 - 2002 Richard Guy Briggs <rgb@freeswan.org>
-+ * 2001 - 2004 Michael Richardson <mcr@xelerance.com>
-+ *
-+ * 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. See <http://www.fsf.org/copyleft/gpl.txt>.
-+ *
-+ * 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.
-+ *
-+ * /proc system code was split out into ipsec_proc.c after rev. 1.70.
-+ *
-+ */
-+
-+char ipsec_init_c_version[] = "RCSID $Id: ipsec_init.c,v 1.93 2004/04/06 02:49:26 mcr Exp $";
-+
-+#include <linux/config.h>
-+#include <linux/version.h>
-+#include <linux/module.h>
-+#include <linux/kernel.h> /* printk() */
-+
-+#include "openswan/ipsec_param.h"
-+
-+#ifdef MALLOC_SLAB
-+# include <linux/slab.h> /* kmalloc() */
-+#else /* MALLOC_SLAB */
-+# include <linux/malloc.h> /* kmalloc() */
-+#endif /* MALLOC_SLAB */
-+#include <linux/errno.h> /* error codes */
-+#include <linux/types.h> /* size_t */
-+#include <linux/interrupt.h> /* mark_bh */
-+
-+#include <linux/netdevice.h> /* struct device, and other headers */
-+#include <linux/etherdevice.h> /* eth_type_trans */
-+#include <linux/ip.h> /* struct iphdr */
-+#include <linux/in.h> /* struct sockaddr_in */
-+#include <linux/skbuff.h>
-+#include <linux/random.h> /* get_random_bytes() */
-+#include <openswan.h>
-+
-+#ifdef SPINLOCK
-+# ifdef SPINLOCK_23
-+# include <linux/spinlock.h> /* *lock* */
-+# else /* 23_SPINLOCK */
-+# include <asm/spinlock.h> /* *lock* */
-+# endif /* 23_SPINLOCK */
-+#endif /* SPINLOCK */
-+
-+#ifdef NET_21
-+# include <asm/uaccess.h>
-+# include <linux/in6.h>
-+#endif /* NET_21 */
-+
-+#include <asm/checksum.h>
-+#include <net/ip.h>
-+
-+#ifdef CONFIG_PROC_FS
-+# include <linux/proc_fs.h>
-+#endif /* CONFIG_PROC_FS */
-+
-+#ifdef NETLINK_SOCK
-+# include <linux/netlink.h>
-+#else
-+# include <net/netlink.h>
-+#endif
-+
-+#include "openswan/radij.h"
-+
-+#include "openswan/ipsec_life.h"
-+#include "openswan/ipsec_stats.h"
-+#include "openswan/ipsec_sa.h"
-+
-+#include "openswan/ipsec_encap.h"
-+#include "openswan/ipsec_radij.h"
-+#include "openswan/ipsec_xform.h"
-+#include "openswan/ipsec_tunnel.h"
-+
-+#include "openswan/ipsec_rcv.h"
-+#include "openswan/ipsec_ah.h"
-+#include "openswan/ipsec_esp.h"
-+
-+#ifdef CONFIG_IPSEC_IPCOMP
-+# include "openswan/ipcomp.h"
-+#endif /* CONFIG_IPSEC_IPCOMP */
-+
-+#include "openswan/ipsec_proto.h"
-+#include "openswan/ipsec_alg.h"
-+
-+#include <pfkeyv2.h>
-+#include <pfkey.h>
-+
-+#if !defined(CONFIG_IPSEC_ESP) && !defined(CONFIG_IPSEC_AH)
-+#error "kernel configuration must include ESP or AH"
-+#endif
-+
-+/*
-+ * seems to be present in 2.4.10 (Linus), but also in some RH and other
-+ * distro kernels of a lower number.
-+ */
-+#ifdef MODULE_LICENSE
-+MODULE_LICENSE("GPL");
-+#endif
-+
-+#ifdef CONFIG_IPSEC_DEBUG
-+int debug_eroute = 0;
-+int debug_spi = 0;
-+int debug_netlink = 0;
-+#endif /* CONFIG_IPSEC_DEBUG */
-+
-+struct prng ipsec_prng;
-+
-+extern int ipsec_device_event(struct notifier_block *dnot, unsigned long event, void *ptr);
-+/*
-+ * the following structure is required so that we receive
-+ * event notifications when network devices are enabled and
-+ * disabled (ifconfig up and down).
-+ */
-+static struct notifier_block ipsec_dev_notifier={
-+ ipsec_device_event,
-+ NULL,
-+ 0
-+};
-+
-+#ifdef CONFIG_SYSCTL
-+extern int ipsec_sysctl_register(void);
-+extern void ipsec_sysctl_unregister(void);
-+#endif
-+
-+static inline int
-+openswan_inet_add_protocol(struct inet_protocol *prot, unsigned protocol)
-+{
-+#ifdef NETDEV_25
-+ return inet_add_protocol(prot, protocol);
-+#else
-+ inet_add_protocol(prot);
-+ return 0;
-+#endif
-+}
-+
-+static inline int
-+openswan_inet_del_protocol(struct inet_protocol *prot, unsigned protocol)
-+{
-+#ifdef NETDEV_25
-+ return inet_del_protocol(prot, protocol);
-+#else
-+ inet_del_protocol(prot);
-+ return 0;
-+#endif
-+}
-+
-+/* void */
-+int
-+ipsec_init(void)
-+{
-+ int error = 0;
-+ unsigned char seed[256];
-+#ifdef CONFIG_IPSEC_ENC_3DES
-+ extern int des_check_key;
-+
-+ /* turn off checking of keys */
-+ des_check_key=0;
-+#endif /* CONFIG_IPSEC_ENC_3DES */
-+
-+ KLIPS_PRINT(1, "klips_info:ipsec_init: "
-+ "KLIPS startup, Openswan KLIPS IPsec stack version: %s\n",
-+ ipsec_version_code());
-+
-+ error |= ipsec_proc_init();
-+
-+#ifdef SPINLOCK
-+ ipsec_sadb.sadb_lock = SPIN_LOCK_UNLOCKED;
-+#else /* SPINLOCK */
-+ ipsec_sadb.sadb_lock = 0;
-+#endif /* SPINLOCK */
-+
-+#ifndef SPINLOCK
-+ tdb_lock.lock = 0;
-+ eroute_lock.lock = 0;
-+#endif /* !SPINLOCK */
-+
-+ error |= ipsec_sadb_init();
-+ error |= ipsec_radijinit();
-+
-+ error |= pfkey_init();
-+
-+ error |= register_netdevice_notifier(&ipsec_dev_notifier);
-+
-+#ifdef CONFIG_IPSEC_ESP
-+ openswan_inet_add_protocol(&esp_protocol, IPPROTO_ESP);
-+#endif /* CONFIG_IPSEC_ESP */
-+
-+#ifdef CONFIG_IPSEC_AH
-+ openswan_inet_add_protocol(&ah_protocol, IPPROTO_AH);
-+#endif /* CONFIG_IPSEC_AH */
-+
-+/* we never actually link IPCOMP to the stack */
-+#ifdef IPCOMP_USED_ALONE
-+#ifdef CONFIG_IPSEC_IPCOMP
-+ openswan_inet_add_protocol(&comp_protocol, IPPROTO_COMP);
-+#endif /* CONFIG_IPSEC_IPCOMP */
-+#endif
-+
-+ error |= ipsec_tunnel_init_devices();
-+
-+
-+#ifdef CONFIG_SYSCTL
-+ error |= ipsec_sysctl_register();
-+#endif
-+
-+#ifdef CONFIG_IPSEC_ALG
-+ ipsec_alg_init();
-+#endif
-+
-+ get_random_bytes((void *)seed, sizeof(seed));
-+ prng_init(&ipsec_prng, seed, sizeof(seed));
-+
-+ return error;
-+}
-+
-+
-+/* void */
-+int
-+ipsec_cleanup(void)
-+{
-+ int error = 0;
-+
-+#ifdef CONFIG_SYSCTL
-+ ipsec_sysctl_unregister();
-+#endif
-+ KLIPS_PRINT(debug_netlink, /* debug_tunnel & DB_TN_INIT, */
-+ "klips_debug:ipsec_cleanup: "
-+ "calling ipsec_tunnel_cleanup_devices.\n");
-+ error |= ipsec_tunnel_cleanup_devices();
-+
-+ KLIPS_PRINT(debug_netlink, "called ipsec_tunnel_cleanup_devices");
-+
-+/* we never actually link IPCOMP to the stack */
-+#ifdef IPCOMP_USED_ALONE
-+#ifdef CONFIG_IPSEC_IPCOMP
-+ if (openswan_inet_del_protocol(&comp_protocol, IPPROTO_COMP) < 0)
-+ printk(KERN_INFO "klips_debug:ipsec_cleanup: "
-+ "comp close: can't remove protocol\n");
-+#endif /* CONFIG_IPSEC_IPCOMP */
-+#endif /* IPCOMP_USED_ALONE */
-+
-+#ifdef CONFIG_IPSEC_AH
-+ if (openswan_inet_del_protocol(&ah_protocol, IPPROTO_AH) < 0)
-+ printk(KERN_INFO "klips_debug:ipsec_cleanup: "
-+ "ah close: can't remove protocol\n");
-+#endif /* CONFIG_IPSEC_AH */
-+
-+#ifdef CONFIG_IPSEC_ESP
-+ if (openswan_inet_del_protocol(&esp_protocol, IPPROTO_ESP) < 0)
-+ printk(KERN_INFO "klips_debug:ipsec_cleanup: "
-+ "esp close: can't remove protocol\n");
-+#endif /* CONFIG_IPSEC_ESP */
-+
-+ error |= unregister_netdevice_notifier(&ipsec_dev_notifier);
-+
-+ KLIPS_PRINT(debug_netlink, /* debug_tunnel & DB_TN_INIT, */
-+ "klips_debug:ipsec_cleanup: "
-+ "calling ipsec_sadb_cleanup.\n");
-+ error |= ipsec_sadb_cleanup(0);
-+ error |= ipsec_sadb_free();
-+
-+ KLIPS_PRINT(debug_netlink, /* debug_tunnel & DB_TN_INIT, */
-+ "klips_debug:ipsec_cleanup: "
-+ "calling ipsec_radijcleanup.\n");
-+ error |= ipsec_radijcleanup();
-+
-+ KLIPS_PRINT(debug_pfkey, /* debug_tunnel & DB_TN_INIT, */
-+ "klips_debug:ipsec_cleanup: "
-+ "calling pfkey_cleanup.\n");
-+ error |= pfkey_cleanup();
-+
-+ ipsec_proc_cleanup();
-+
-+ prng_final(&ipsec_prng);
-+
-+ return error;
-+}
-+
-+#ifdef MODULE
-+int
-+init_module(void)
-+{
-+ int error = 0;
-+
-+ error |= ipsec_init();
-+
-+ return error;
-+}
-+
-+int
-+cleanup_module(void)
-+{
-+ int error = 0;
-+
-+ KLIPS_PRINT(debug_netlink, /* debug_tunnel & DB_TN_INIT, */
-+ "klips_debug:cleanup_module: "
-+ "calling ipsec_cleanup.\n");
-+
-+ error |= ipsec_cleanup();
-+
-+ KLIPS_PRINT(1, "klips_info:cleanup_module: "
-+ "ipsec module unloaded.\n");
-+
-+ return error;
-+}
-+#endif /* MODULE */
-+
-+/*
-+ * $Log: ipsec_init.c,v $
-+ * Revision 1.93 2004/04/06 02:49:26 mcr
-+ * pullup of algo code from alg-branch.
-+ *
-+ * Revision 1.92 2004/03/30 15:30:39 ken
-+ * Proper Capitalization
-+ *
-+ * Revision 1.91 2004/03/22 01:51:51 ken
-+ * We are open
-+ *
-+ * Revision 1.90.4.2 2004/04/05 04:30:46 mcr
-+ * patches for alg-branch to compile/work with 2.x openswan
-+ *
-+ * Revision 1.90.4.1 2003/12/22 15:25:52 jjo
-+ * Merged algo-0.8.1-rc11-test1 into alg-branch
-+ *
-+ * Revision 1.90 2003/10/31 02:27:55 mcr
-+ * pulled up port-selector patches and sa_id elimination.
-+ *
-+ * Revision 1.89.4.1 2003/10/29 01:30:41 mcr
-+ * elimited "struct sa_id".
-+ *
-+ * Revision 1.89 2003/07/31 22:47:16 mcr
-+ * preliminary (untested by FS-team) 2.5 patches.
-+ *
-+ * Revision 1.88 2003/06/22 20:05:36 mcr
-+ * clarified why IPCOMP was not being registered, and put a new
-+ * #ifdef in rather than #if 0.
-+ *
-+ * Revision 1.87 2002/09/20 15:40:51 rgb
-+ * Added a lock to the global ipsec_sadb struct for future use.
-+ * Split ipsec_sadb_cleanup from new funciton ipsec_sadb_free to avoid problem
-+ * of freeing newly created structures when clearing the reftable upon startup
-+ * to start from a known state.
-+ *
-+ * Revision 1.86 2002/08/15 18:39:15 rgb
-+ * Move ipsec_prng outside debug code.
-+ *
-+ * Revision 1.85 2002/05/14 02:35:29 rgb
-+ * Change reference to tdb to ipsa.
-+ *
-+ * Revision 1.84 2002/04/24 07:55:32 mcr
-+ * #include patches and Makefiles for post-reorg compilation.
-+ *
-+ * Revision 1.83 2002/04/24 07:36:28 mcr
-+ * Moved from ./klips/net/ipsec/ipsec_init.c,v
-+ *
-+ * Revision 1.82 2002/04/20 00:12:25 rgb
-+ * Added esp IV CBC attack fix, disabled.
-+ *
-+ * Revision 1.81 2002/04/09 16:13:32 mcr
-+ * switch license to straight GPL.
-+ *
-+ * Revision 1.80 2002/03/24 07:34:08 rgb
-+ * Sanity check for at least one of AH or ESP configured.
-+ *
-+ * Revision 1.79 2002/02/05 22:55:15 mcr
-+ * added MODULE_LICENSE declaration.
-+ * This macro does not appear in all kernel versions (see comment).
-+ *
-+ * Revision 1.78 2002/01/29 17:17:55 mcr
-+ * moved include of ipsec_param.h to after include of linux/kernel.h
-+ * otherwise, it seems that some option that is set in ipsec_param.h
-+ * screws up something subtle in the include path to kernel.h, and
-+ * it complains on the snprintf() prototype.
-+ *
-+ * Revision 1.77 2002/01/29 04:00:51 mcr
-+ * more excise of kversions.h header.
-+ *
-+ * Revision 1.76 2002/01/29 02:13:17 mcr
-+ * introduction of ipsec_kversion.h means that include of
-+ * ipsec_param.h must preceed any decisions about what files to
-+ * include to deal with differences in kernel source.
-+ *
-+ * Revision 1.75 2001/11/26 09:23:48 rgb
-+ * Merge MCR's ipsec_sa, eroute, proc and struct lifetime changes.
-+ *
-+ * Revision 1.74 2001/11/22 05:44:11 henry
-+ * new version stuff
-+ *
-+ * Revision 1.71.2.2 2001/10/22 20:51:00 mcr
-+ * explicitely set des_check_key.
-+ *
-+ * Revision 1.71.2.1 2001/09/25 02:19:39 mcr
-+ * /proc manipulation code moved to new ipsec_proc.c
-+ *
-+ * Revision 1.73 2001/11/06 19:47:17 rgb
-+ * Changed lifetime_packets to uint32 from uint64.
-+ *
-+ * Revision 1.72 2001/10/18 04:45:19 rgb
-+ * 2.4.9 kernel deprecates linux/malloc.h in favour of linux/slab.h,
-+ * lib/freeswan.h version macros moved to lib/kversions.h.
-+ * Other compiler directive cleanups.
-+ *
-+ * Revision 1.71 2001/09/20 15:32:45 rgb
-+ * Minor pfkey lifetime fixes.
-+ *
-+ * Revision 1.70 2001/07/06 19:51:21 rgb
-+ * Added inbound policy checking code for IPIP SAs.
-+ *
-+ * Revision 1.69 2001/06/14 19:33:26 rgb
-+ * Silence startup message for console, but allow it to be logged.
-+ * Update copyright date.
-+ *
-+ * Revision 1.68 2001/05/29 05:14:36 rgb
-+ * Added PMTU to /proc/net/ipsec_tncfg output. See 'man 5 ipsec_tncfg'.
-+ *
-+ * Revision 1.67 2001/05/04 16:34:52 rgb
-+ * Rremove erroneous checking of return codes for proc_net_* in 2.4.
-+ *
-+ * Revision 1.66 2001/05/03 19:40:34 rgb
-+ * Check error return codes in startup and shutdown.
-+ *
-+ * Revision 1.65 2001/02/28 05:03:27 rgb
-+ * Clean up and rationalise startup messages.
-+ *
-+ * Revision 1.64 2001/02/27 22:24:53 rgb
-+ * Re-formatting debug output (line-splitting, joining, 1arg/line).
-+ * Check for satoa() return codes.
-+ *
-+ * Revision 1.63 2000/11/29 20:14:06 rgb
-+ * Add src= to the output of /proc/net/ipsec_spi and delete dst from IPIP.
-+ *
-+ * Revision 1.62 2000/11/06 04:31:24 rgb
-+ * Ditched spin_lock_irqsave in favour of spin_lock_bh.
-+ * Fixed longlong for pre-2.4 kernels (Svenning).
-+ * Add Svenning's adaptive content compression.
-+ * Disabled registration of ipcomp handler.
-+ *
-+ * Revision 1.61 2000/10/11 13:37:54 rgb
-+ * #ifdef out debug print that causes proc/net/ipsec_version to oops.
-+ *
-+ * Revision 1.60 2000/09/20 03:59:01 rgb
-+ * Change static info functions to DEBUG_NO_STATIC to reveal function names
-+ * in oopsen.
-+ *
-+ * Revision 1.59 2000/09/16 01:06:26 rgb
-+ * Added cast of var to silence compiler warning about long fed to int
-+ * format.
-+ *
-+ * Revision 1.58 2000/09/15 11:37:01 rgb
-+ * Merge in heavily modified Svenning Soerensen's <svenning@post5.tele.dk>
-+ * IPCOMP zlib deflate code.
-+ *
-+ * Revision 1.57 2000/09/12 03:21:50 rgb
-+ * Moved radij_c_version printing to ipsec_version_get_info().
-+ * Reformatted ipsec_version_get_info().
-+ * Added sysctl_{,un}register() calls.
-+ *
-+ * Revision 1.56 2000/09/08 19:16:50 rgb
-+ * Change references from DEBUG_IPSEC to CONFIG_IPSEC_DEBUG.
-+ * Removed all references to CONFIG_IPSEC_PFKEYv2.
-+ *
-+ * Revision 1.55 2000/08/30 05:19:03 rgb
-+ * Cleaned up no longer used spi_next, netlink register/unregister, other
-+ * minor cleanup.
-+ * Removed cruft replaced by TDB_XFORM_NAME.
-+ * Removed all the rest of the references to tdb_spi, tdb_proto, tdb_dst.
-+ * Moved debug version strings to printk when /proc/net/ipsec_version is
-+ * called.
-+ *
-+ * Revision 1.54 2000/08/20 18:31:05 rgb
-+ * Changed cosmetic alignment in spi_info.
-+ * Changed addtime and usetime to use actual value which is relative
-+ * anyways, as intended. (Momchil)
-+ *
-+ * Revision 1.53 2000/08/18 17:37:03 rgb
-+ * Added an (int) cast to shut up the compiler...
-+ *
-+ * Revision 1.52 2000/08/01 14:51:50 rgb
-+ * Removed _all_ remaining traces of DES.
-+ *
-+ * Revision 1.51 2000/07/25 20:41:22 rgb
-+ * Removed duplicate parameter in spi_getinfo.
-+ *
-+ * Revision 1.50 2000/07/17 03:21:45 rgb
-+ * Removed /proc/net/ipsec_spinew.
-+ *
-+ * Revision 1.49 2000/06/28 05:46:51 rgb
-+ * Renamed ivlen to iv_bits for consistency.
-+ * Changed output of add and use times to be relative to now.
-+ *
-+ * Revision 1.48 2000/05/11 18:26:10 rgb
-+ * Commented out calls to netlink_attach/detach to avoid activating netlink
-+ * in the kenrel config.
-+ *
-+ * Revision 1.47 2000/05/10 22:35:26 rgb
-+ * Comment out most of the startup version information.
-+ *
-+ * Revision 1.46 2000/03/22 16:15:36 rgb
-+ * Fixed renaming of dev_get (MB).
-+ *
-+ * Revision 1.45 2000/03/16 06:40:48 rgb
-+ * Hardcode PF_KEYv2 support.
-+ *
-+ * Revision 1.44 2000/01/22 23:19:20 rgb
-+ * Simplified code to use existing macro TDB_XFORM_NAME().
-+ *
-+ * Revision 1.43 2000/01/21 06:14:04 rgb
-+ * Print individual stats only if non-zero.
-+ * Removed 'bits' from each keylength for brevity.
-+ * Shortened lifetimes legend for brevity.
-+ * Changed wording from 'last_used' to the clearer 'idle'.
-+ *
-+ * Revision 1.42 1999/12/31 14:57:19 rgb
-+ * MB fix for new dummy-less proc_get_info in 2.3.35.
-+ *
-+ *
-+ * Local variables:
-+ * c-file-style: "linux"
-+ * End:
-+ *
-+ */
---- /dev/null Tue Mar 11 13:02:56 2003
-+++ linux/net/ipsec/ipsec_ipcomp.c Mon Feb 9 13:51:03 2004
-@@ -0,0 +1,276 @@
-+/*
-+ * processing code for IPCOMP
-+ * Copyright (C) 2003 Michael Richardson <mcr@sandelman.ottawa.on.ca>
-+ *
-+ * 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. See <http://www.fsf.org/copyleft/gpl.txt>.
-+ *
-+ * 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.
-+ */
-+
-+char ipsec_ipcomp_c_version[] = "RCSID $Id: ipsec_ipcomp.c,v 1.2 2004/04/06 02:49:26 mcr Exp $";
-+#include <linux/config.h>
-+#include <linux/version.h>
-+
-+#define __NO_VERSION__
-+#include <linux/module.h>
-+#include <linux/kernel.h> /* printk() */
-+
-+#include "openswan/ipsec_param.h"
-+
-+#ifdef MALLOC_SLAB
-+# include <linux/slab.h> /* kmalloc() */
-+#else /* MALLOC_SLAB */
-+# include <linux/malloc.h> /* kmalloc() */
-+#endif /* MALLOC_SLAB */
-+#include <linux/errno.h> /* error codes */
-+#include <linux/types.h> /* size_t */
-+#include <linux/interrupt.h> /* mark_bh */
-+
-+#include <linux/netdevice.h> /* struct device, and other headers */
-+#include <linux/etherdevice.h> /* eth_type_trans */
-+#include <linux/ip.h> /* struct iphdr */
-+#include <linux/skbuff.h>
-+#include <openswan.h>
-+#ifdef SPINLOCK
-+# ifdef SPINLOCK_23
-+# include <linux/spinlock.h> /* *lock* */
-+# else /* SPINLOCK_23 */
-+# include <asm/spinlock.h> /* *lock* */
-+# endif /* SPINLOCK_23 */
-+#endif /* SPINLOCK */
-+#ifdef NET_21
-+# include <asm/uaccess.h>
-+# include <linux/in6.h>
-+# define proto_priv cb
-+#endif /* NET21 */
-+#include <asm/checksum.h>
-+#include <net/ip.h>
-+
-+#include "openswan/radij.h"
-+#include "openswan/ipsec_encap.h"
-+#include "openswan/ipsec_sa.h"
-+
-+#include "openswan/ipsec_radij.h"
-+#include "openswan/ipsec_xform.h"
-+#include "openswan/ipsec_tunnel.h"
-+#include "openswan/ipsec_rcv.h"
-+#include "openswan/ipsec_xmit.h"
-+
-+#include "openswan/ipsec_auth.h"
-+
-+#ifdef CONFIG_IPSEC_IPCOMP
-+#include "openswan/ipsec_ipcomp.h"
-+#endif /* CONFIG_IPSEC_IPCOMP */
-+
-+#include "openswan/ipsec_proto.h"
-+
-+#ifdef CONFIG_IPSEC_DEBUG
-+int debug_ipcomp = 0;
-+#endif /* CONFIG_IPSEC_DEBUG */
-+
-+
-+#ifdef CONFIG_IPSEC_IPCOMP
-+enum ipsec_rcv_value
-+ipsec_rcv_ipcomp_checks(struct ipsec_rcv_state *irs,
-+ struct sk_buff *skb)
-+{
-+ int ipcompminlen;
-+
-+ ipcompminlen = irs->hard_header_len + sizeof(struct iphdr);
-+
-+ if(skb->len < (ipcompminlen + sizeof(struct ipcomphdr))) {
-+ KLIPS_PRINT(debug_rcv & DB_RX_INAU,
-+ "klips_debug:ipsec_rcv: "
-+ "runt comp packet of skb->len=%d received from %s, dropped.\n",
-+ skb->len,
-+ irs->ipsaddr_txt);
-+ if(irs->stats) {
-+ irs->stats->rx_errors++;
-+ }
-+ return IPSEC_RCV_BADLEN;
-+ }
-+
-+ irs->protostuff.ipcompstuff.compp = (struct ipcomphdr *)(skb->data + irs->iphlen);
-+ irs->said.spi = htonl((__u32)ntohs(irs->protostuff.ipcompstuff.compp->ipcomp_cpi));
-+ return IPSEC_RCV_OK;
-+}
-+
-+enum ipsec_rcv_value
-+ipsec_rcv_ipcomp_decomp(struct ipsec_rcv_state *irs)
-+{
-+ unsigned int flags = 0;
-+ struct ipsec_sa *ipsp = irs->ipsp;
-+ struct sk_buff *skb;
-+
-+ skb=irs->skb;
-+
-+ ipsec_xmit_dmp("ipcomp", skb->data, skb->len);
-+
-+ if(ipsp == NULL) {
-+ return IPSEC_RCV_SAIDNOTFOUND;
-+ }
-+
-+#if 0
-+ /* we want to check that this wasn't the first SA on the list, because
-+ * we don't support bare IPCOMP, for unexplained reasons. MCR
-+ */
-+ if (ipsp->ips_onext != NULL) {
-+ KLIPS_PRINT(debug_rcv,
-+ "klips_debug:ipsec_rcv: "
-+ "Incoming packet with outer IPCOMP header SA:%s: not yet supported by KLIPS, dropped\n",
-+ irs->sa_len ? irs->sa : " (error)");
-+ if(irs->stats) {
-+ irs->stats->rx_dropped++;
-+ }
-+
-+ return IPSEC_RCV_IPCOMPALONE;
-+ }
-+#endif
-+
-+ if(sysctl_ipsec_inbound_policy_check &&
-+ ((((ntohl(ipsp->ips_said.spi) & 0x0000ffff) != ntohl(irs->said.spi)) &&
-+ (ipsp->ips_encalg != ntohl(irs->said.spi)) /* this is a workaround for peer non-compliance with rfc2393 */
-+ ))) {
-+ char sa2[SATOT_BUF];
-+ size_t sa_len2 = 0;
-+
-+ sa_len2 = satot(&ipsp->ips_said, 0, sa2, sizeof(sa2));
-+
-+ KLIPS_PRINT(debug_rcv,
-+ "klips_debug:ipsec_rcv: "
-+ "Incoming packet with SA(IPCA):%s does not match policy SA(IPCA):%s cpi=%04x cpi->spi=%08x spi=%08x, spi->cpi=%04x for SA grouping, dropped.\n",
-+ irs->sa_len ? irs->sa : " (error)",
-+ ipsp != NULL ? (sa_len2 ? sa2 : " (error)") : "NULL",
-+ ntohs(irs->protostuff.ipcompstuff.compp->ipcomp_cpi),
-+ (__u32)ntohl(irs->said.spi),
-+ ipsp != NULL ? (__u32)ntohl((ipsp->ips_said.spi)) : 0,
-+ ipsp != NULL ? (__u16)(ntohl(ipsp->ips_said.spi) & 0x0000ffff) : 0);
-+ if(irs->stats) {
-+ irs->stats->rx_dropped++;
-+ }
-+ return IPSEC_RCV_SAIDNOTFOUND;
-+ }
-+
-+ ipsp->ips_comp_ratio_cbytes += ntohs(irs->ipp->tot_len);
-+ irs->next_header = irs->protostuff.ipcompstuff.compp->ipcomp_nh;
-+
-+ skb = skb_decompress(skb, ipsp, &flags);
-+ if (!skb || flags) {
-+ spin_unlock(&tdb_lock);
-+ KLIPS_PRINT(debug_rcv,
-+ "klips_debug:ipsec_rcv: "
-+ "skb_decompress() returned error flags=%x, dropped.\n",
-+ flags);
-+ if (irs->stats) {
-+ if (flags)
-+ irs->stats->rx_errors++;
-+ else
-+ irs->stats->rx_dropped++;
-+ }
-+ return IPSEC_RCV_IPCOMPFAILED;
-+ }
-+
-+ /* make sure we update the pointer */
-+ irs->skb = skb;
-+
-+#ifdef NET_21
-+ irs->ipp = skb->nh.iph;
-+#else /* NET_21 */
-+ irs->ipp = skb->ip_hdr;
-+#endif /* NET_21 */
-+
-+ ipsp->ips_comp_ratio_dbytes += ntohs(irs->ipp->tot_len);
-+
-+ KLIPS_PRINT(debug_rcv,
-+ "klips_debug:ipsec_rcv: "
-+ "packet decompressed SA(IPCA):%s cpi->spi=%08x spi=%08x, spi->cpi=%04x, nh=%d.\n",
-+ irs->sa_len ? irs->sa : " (error)",
-+ (__u32)ntohl(irs->said.spi),
-+ ipsp != NULL ? (__u32)ntohl((ipsp->ips_said.spi)) : 0,
-+ ipsp != NULL ? (__u16)(ntohl(ipsp->ips_said.spi) & 0x0000ffff) : 0,
-+ irs->next_header);
-+ KLIPS_IP_PRINT(debug_rcv & DB_RX_PKTRX, irs->ipp);
-+
-+ return IPSEC_RCV_OK;
-+}
-+
-+enum ipsec_xmit_value
-+ipsec_xmit_ipcomp_setup(struct ipsec_xmit_state *ixs)
-+{
-+ unsigned int flags = 0;
-+#ifdef CONFIG_IPSEC_DEBUG
-+ unsigned int old_tot_len = ntohs(ixs->iph->tot_len);
-+#endif /* CONFIG_IPSEC_DEBUG */
-+
-+ ixs->ipsp->ips_comp_ratio_dbytes += ntohs(ixs->iph->tot_len);
-+
-+ ixs->skb = skb_compress(ixs->skb, ixs->ipsp, &flags);
-+
-+#ifdef NET_21
-+ ixs->iph = ixs->skb->nh.iph;
-+#else /* NET_21 */
-+ ixs->iph = ixs->skb->ip_hdr;
-+#endif /* NET_21 */
-+
-+ ixs->ipsp->ips_comp_ratio_cbytes += ntohs(ixs->iph->tot_len);
-+
-+#ifdef CONFIG_IPSEC_DEBUG
-+ if (debug_tunnel & DB_TN_CROUT)
-+ {
-+ if (old_tot_len > ntohs(ixs->iph->tot_len))
-+ KLIPS_PRINT(debug_tunnel & DB_TN_CROUT,
-+ "klips_debug:ipsec_xmit_encap_once: "
-+ "packet shrunk from %d to %d bytes after compression, cpi=%04x (should be from spi=%08x, spi&0xffff=%04x.\n",
-+ old_tot_len, ntohs(ixs->iph->tot_len),
-+ ntohs(((struct ipcomphdr*)(((char*)ixs->iph) + ((ixs->iph->ihl) << 2)))->ipcomp_cpi),
-+ ntohl(ixs->ipsp->ips_said.spi),
-+ (__u16)(ntohl(ixs->ipsp->ips_said.spi) & 0x0000ffff));
-+ else
-+ KLIPS_PRINT(debug_tunnel & DB_TN_CROUT,
-+ "klips_debug:ipsec_xmit_encap_once: "
-+ "packet did not compress (flags = %d).\n",
-+ flags);
-+ }
-+#endif /* CONFIG_IPSEC_DEBUG */
-+
-+ return IPSEC_XMIT_OK;
-+}
-+
-+struct xform_functions ipcomp_xform_funcs[]={
-+ {rcv_checks: ipsec_rcv_ipcomp_checks,
-+ rcv_decrypt: ipsec_rcv_ipcomp_decomp,
-+ xmit_setup: ipsec_xmit_ipcomp_setup,
-+ xmit_headroom: 0,
-+ xmit_needtailroom: 0,
-+ },
-+};
-+
-+#if 0
-+/* We probably don't want to install a pure IPCOMP protocol handler, but
-+ only want to handle IPCOMP if it is encapsulated inside an ESP payload
-+ (which is already handled) */
-+#ifdef CONFIG_IPSEC_IPCOMP
-+struct inet_protocol comp_protocol =
-+{
-+ ipsec_rcv, /* COMP handler */
-+ NULL, /* COMP error control */
-+#ifdef NETDEV_25
-+ 1, /* no policy */
-+#else
-+ 0, /* next */
-+ IPPROTO_COMP, /* protocol ID */
-+ 0, /* copy */
-+ NULL, /* data */
-+ "COMP" /* name */
-+#endif
-+};
-+#endif /* CONFIG_IPSEC_IPCOMP */
-+#endif
-+
-+#endif /* CONFIG_IPSEC_IPCOMP */
---- /dev/null Tue Mar 11 13:02:56 2003
-+++ linux/net/ipsec/ipsec_ipip.c Mon Feb 9 13:51:03 2004
-@@ -0,0 +1,133 @@
-+/*
-+ * processing code for IPIP
-+ * Copyright (C) 2003 Michael Richardson <mcr@sandelman.ottawa.on.ca>
-+ *
-+ * 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. See <http://www.fsf.org/copyleft/gpl.txt>.
-+ *
-+ * 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.
-+ */
-+
-+char ipsec_ipip_c_version[] = "RCSID $Id: ipsec_ipip.c,v 1.2 2004/04/06 02:49:26 mcr Exp $";
-+#include <linux/config.h>
-+#include <linux/version.h>
-+
-+#define __NO_VERSION__
-+#include <linux/module.h>
-+#include <linux/kernel.h> /* printk() */
-+
-+#include "openswan/ipsec_param.h"
-+
-+#ifdef MALLOC_SLAB
-+# include <linux/slab.h> /* kmalloc() */
-+#else /* MALLOC_SLAB */
-+# include <linux/malloc.h> /* kmalloc() */
-+#endif /* MALLOC_SLAB */
-+#include <linux/errno.h> /* error codes */
-+#include <linux/types.h> /* size_t */
-+#include <linux/interrupt.h> /* mark_bh */
-+
-+#include <linux/netdevice.h> /* struct device, and other headers */
-+#include <linux/etherdevice.h> /* eth_type_trans */
-+#include <linux/ip.h> /* struct iphdr */
-+#include <linux/skbuff.h>
-+#include <openswan.h>
-+#ifdef SPINLOCK
-+# ifdef SPINLOCK_23
-+# include <linux/spinlock.h> /* *lock* */
-+# else /* SPINLOCK_23 */
-+# include <asm/spinlock.h> /* *lock* */
-+# endif /* SPINLOCK_23 */
-+#endif /* SPINLOCK */
-+#ifdef NET_21
-+# include <asm/uaccess.h>
-+# include <linux/in6.h>
-+# define proto_priv cb
-+#endif /* NET21 */
-+#include <asm/checksum.h>
-+#include <net/ip.h>
-+
-+#include "openswan/radij.h"
-+#include "openswan/ipsec_encap.h"
-+#include "openswan/ipsec_sa.h"
-+
-+#include "openswan/ipsec_radij.h"
-+#include "openswan/ipsec_xform.h"
-+#include "openswan/ipsec_tunnel.h"
-+#include "openswan/ipsec_rcv.h"
-+#include "openswan/ipsec_xmit.h"
-+
-+#include "openswan/ipsec_auth.h"
-+#include "openswan/ipsec_ipip.h"
-+#include "openswan/ipsec_param.h"
-+
-+#include "openswan/ipsec_proto.h"
-+
-+enum ipsec_xmit_value
-+ipsec_xmit_ipip_setup(struct ipsec_xmit_state *ixs)
-+{
-+ ixs->iph->version = 4;
-+
-+ switch(sysctl_ipsec_tos) {
-+ case 0:
-+#ifdef NET_21
-+ ixs->iph->tos = ixs->skb->nh.iph->tos;
-+#else /* NET_21 */
-+ ixs->iph->tos = ixs->skb->ip_hdr->tos;
-+#endif /* NET_21 */
-+ break;
-+ case 1:
-+ ixs->iph->tos = 0;
-+ break;
-+ default:
-+ break;
-+ }
-+#ifdef NET_21
-+#ifdef NETDEV_23
-+ ixs->iph->ttl = sysctl_ip_default_ttl;
-+#else /* NETDEV_23 */
-+ ixs->iph->ttl = ip_statistics.IpDefaultTTL;
-+#endif /* NETDEV_23 */
-+#else /* NET_21 */
-+ ixs->iph->ttl = 64; /* ip_statistics.IpDefaultTTL; */
-+#endif /* NET_21 */
-+ ixs->iph->frag_off = 0;
-+ ixs->iph->saddr = ((struct sockaddr_in*)(ixs->ipsp->ips_addr_s))->sin_addr.s_addr;
-+ ixs->iph->daddr = ((struct sockaddr_in*)(ixs->ipsp->ips_addr_d))->sin_addr.s_addr;
-+ ixs->iph->protocol = IPPROTO_IPIP;
-+ ixs->iph->ihl = sizeof(struct iphdr) >> 2;
-+
-+ KLIPS_IP_SELECT_IDENT(ixs->iph, ixs->skb);
-+
-+ ixs->newdst = (__u32)ixs->iph->daddr;
-+ ixs->newsrc = (__u32)ixs->iph->saddr;
-+
-+#ifdef NET_21
-+ ixs->skb->h.ipiph = ixs->skb->nh.iph;
-+#endif /* NET_21 */
-+ return IPSEC_XMIT_OK;
-+}
-+
-+struct xform_functions ipip_xform_funcs[]={
-+ { rcv_checks: NULL,
-+ rcv_setup_auth: NULL,
-+ rcv_calc_auth: NULL,
-+ rcv_decrypt: NULL,
-+
-+ xmit_setup: ipsec_xmit_ipip_setup,
-+ xmit_headroom: sizeof(struct iphdr),
-+ xmit_needtailroom: 0,
-+ },
-+};
-+
-+
-+
-+
-+
-+
-+
---- /dev/null Tue Mar 11 13:02:56 2003
-+++ linux/net/ipsec/ipsec_life.c Mon Feb 9 13:51:03 2004
-@@ -0,0 +1,263 @@
-+/*
-+ * @(#) lifetime structure utilities
-+ *
-+ * Copyright (C) 2001 Richard Guy Briggs <rgb@freeswan.org>
-+ * and Michael Richardson <mcr@freeswan.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. See <http://www.fsf.org/copyleft/gpl.txt>.
-+ *
-+ * 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.
-+ *
-+ * RCSID $Id: ipsec_life.c,v 1.12 2004/04/23 20:44:35 ken Exp $
-+ *
-+ */
-+
-+/*
-+ * This provides series of utility functions for dealing with lifetime
-+ * structures.
-+ *
-+ * ipsec_check_lifetime - returns -1 hard lifetime exceeded
-+ * 0 soft lifetime exceeded
-+ * 1 everything is okay
-+ * based upon whether or not the count exceeds hard/soft
-+ *
-+ */
-+
-+#define __NO_VERSION__
-+#include <linux/module.h>
-+#include <linux/config.h> /* for CONFIG_IP_FORWARD */
-+#include <linux/version.h>
-+#include <linux/kernel.h> /* printk() */
-+
-+#include "openswan/ipsec_param.h"
-+
-+#include <linux/netdevice.h> /* struct device, struct net_device_stats and other headers */
-+#include <linux/etherdevice.h> /* eth_type_trans */
-+#include <linux/skbuff.h>
-+#include <openswan.h>
-+
-+#include "openswan/radij.h"
-+#include "openswan/ipsec_life.h"
-+#include "openswan/ipsec_xform.h"
-+#include "openswan/ipsec_eroute.h"
-+#include "openswan/ipsec_encap.h"
-+#include "openswan/ipsec_radij.h"
-+
-+#include "openswan/ipsec_sa.h"
-+#include "openswan/ipsec_tunnel.h"
-+#include "openswan/ipsec_ipe4.h"
-+#include "openswan/ipsec_ah.h"
-+#include "openswan/ipsec_esp.h"
-+
-+#ifdef CONFIG_IPSEC_IPCOMP
-+#include "openswan/ipcomp.h"
-+#endif /* CONFIG_IPSEC_IPCOMP */
-+
-+#include <pfkeyv2.h>
-+#include <pfkey.h>
-+
-+#include "openswan/ipsec_proto.h"
-+
-+
-+enum ipsec_life_alive
-+ipsec_lifetime_check(struct ipsec_lifetime64 *il64,
-+ const char *lifename,
-+ const char *saname,
-+ enum ipsec_life_type ilt,
-+ enum ipsec_direction idir,
-+ struct ipsec_sa *ips)
-+{
-+ __u64 count;
-+ const char *dir;
-+
-+ if(saname == NULL) {
-+ saname = "unknown-SA";
-+ }
-+
-+ if(idir == ipsec_incoming) {
-+ dir = "incoming";
-+ } else {
-+ dir = "outgoing";
-+ }
-+
-+
-+ if(ilt == ipsec_life_timebased) {
-+ count = jiffies/HZ - il64->ipl_count;
-+ } else {
-+ count = il64->ipl_count;
-+ }
-+
-+ if(il64->ipl_hard &&
-+ (count > il64->ipl_hard)) {
-+ KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
-+ "klips_debug:ipsec_lifetime_check: "
-+ "hard %s lifetime of SA:<%s%s%s> %s has been reached, SA expired, "
-+ "%s packet dropped.\n",
-+ lifename,
-+ IPS_XFORM_NAME(ips),
-+ saname,
-+ dir);
-+
-+ pfkey_expire(ips, 1);
-+ return ipsec_life_harddied;
-+ }
-+
-+ if(il64->ipl_soft &&
-+ (count > il64->ipl_soft)) {
-+ KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
-+ "klips_debug:ipsec_lifetime_check: "
-+ "soft %s lifetime of SA:<%s%s%s> %s has been reached, SA expiring, "
-+ "soft expire message sent up, %s packet still processed.\n",
-+ lifename,
-+ IPS_XFORM_NAME(ips),
-+ saname,
-+ dir);
-+
-+ if(ips->ips_state != SADB_SASTATE_DYING) {
-+ pfkey_expire(ips, 0);
-+ }
-+ ips->ips_state = SADB_SASTATE_DYING;
-+
-+ return ipsec_life_softdied;
-+ }
-+ return ipsec_life_okay;
-+}
-+
-+
-+/*
-+ * This function takes a buffer (with length), a lifetime name and type,
-+ * and formats a string to represent the current values of the lifetime.
-+ *
-+ * It returns the number of bytes that the format took (or would take,
-+ * if the buffer were large enough: snprintf semantics).
-+ * This is used in /proc routines and in debug output.
-+ */
-+int
-+ipsec_lifetime_format(char *buffer,
-+ int buflen,
-+ char *lifename,
-+ enum ipsec_life_type timebaselife,
-+ struct ipsec_lifetime64 *lifetime)
-+{
-+ int len = 0;
-+ __u64 count;
-+
-+ if(timebaselife == ipsec_life_timebased) {
-+ count = jiffies/HZ - lifetime->ipl_count;
-+ } else {
-+ count = lifetime->ipl_count;
-+ }
-+
-+ if(lifetime->ipl_count > 1 ||
-+ lifetime->ipl_soft ||
-+ lifetime->ipl_hard) {
-+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0))
-+ len = ipsec_snprintf(buffer, buflen,
-+ "%s(%Lu,%Lu,%Lu)",
-+ lifename,
-+ count,
-+ lifetime->ipl_soft,
-+ lifetime->ipl_hard);
-+#else /* XXX high 32 bits are not displayed */
-+ len = ipsec_snprintf(buffer, buflen,
-+ "%s(%lu,%lu,%lu)",
-+ lifename,
-+ (unsigned long)count,
-+ (unsigned long)lifetime->ipl_soft,
-+ (unsigned long)lifetime->ipl_hard);
-+#endif
-+ }
-+
-+ return len;
-+}
-+
-+void
-+ipsec_lifetime_update_hard(struct ipsec_lifetime64 *lifetime,
-+ __u64 newvalue)
-+{
-+ if(newvalue &&
-+ (!lifetime->ipl_hard ||
-+ (newvalue < lifetime->ipl_hard))) {
-+ lifetime->ipl_hard = newvalue;
-+
-+ if(!lifetime->ipl_soft &&
-+ (lifetime->ipl_hard < lifetime->ipl_soft)) {
-+ lifetime->ipl_soft = lifetime->ipl_hard;
-+ }
-+ }
-+}
-+
-+void
-+ipsec_lifetime_update_soft(struct ipsec_lifetime64 *lifetime,
-+ __u64 newvalue)
-+{
-+ if(newvalue &&
-+ (!lifetime->ipl_soft ||
-+ (newvalue < lifetime->ipl_soft))) {
-+ lifetime->ipl_soft = newvalue;
-+
-+ if(lifetime->ipl_hard &&
-+ (lifetime->ipl_hard < lifetime->ipl_soft)) {
-+ lifetime->ipl_soft = lifetime->ipl_hard;
-+ }
-+ }
-+}
-+
-+
-+/*
-+ * $Log: ipsec_life.c,v $
-+ * Revision 1.12 2004/04/23 20:44:35 ken
-+ * Update comments
-+ *
-+ * Revision 1.11 2004/04/06 02:49:26 mcr
-+ * pullup of algo code from alg-branch.
-+ *
-+ * Revision 1.10 2004/03/30 11:03:10 paul
-+ * two more occurances of snprintf, found by Sam from a users oops msg.
-+ *
-+ * Revision 1.9 2003/10/31 02:27:55 mcr
-+ * pulled up port-selector patches and sa_id elimination.
-+ *
-+ * Revision 1.8.4.1 2003/10/29 01:30:41 mcr
-+ * elimited "struct sa_id".
-+ *
-+ * Revision 1.8 2003/02/06 02:00:10 rgb
-+ * Fixed incorrect debugging text label
-+ *
-+ * Revision 1.7 2002/05/23 07:16:26 rgb
-+ * Fixed absolute/relative reference to lifetime count printout.
-+ *
-+ * Revision 1.6 2002/04/24 07:55:32 mcr
-+ * #include patches and Makefiles for post-reorg compilation.
-+ *
-+ * Revision 1.5 2002/04/24 07:36:28 mcr
-+ * Moved from ./klips/net/ipsec/ipsec_life.c,v
-+ *
-+ * Revision 1.4 2002/01/29 17:17:55 mcr
-+ * moved include of ipsec_param.h to after include of linux/kernel.h
-+ * otherwise, it seems that some option that is set in ipsec_param.h
-+ * screws up something subtle in the include path to kernel.h, and
-+ * it complains on the snprintf() prototype.
-+ *
-+ * Revision 1.3 2002/01/29 02:13:17 mcr
-+ * introduction of ipsec_kversion.h means that include of
-+ * ipsec_param.h must preceed any decisions about what files to
-+ * include to deal with differences in kernel source.
-+ *
-+ * Revision 1.2 2001/11/26 09:16:14 rgb
-+ * Merge MCR's ipsec_sa, eroute, proc and struct lifetime changes.
-+ *
-+ * Revision 1.1.2.1 2001/09/25 02:25:57 mcr
-+ * lifetime structure created and common functions created.
-+ *
-+ * Local variables:
-+ * c-file-style: "linux"
-+ * End:
-+ *
-+ */
---- /dev/null Tue Mar 11 13:02:56 2003
-+++ linux/net/ipsec/ipsec_mast.c Mon Feb 9 13:51:03 2004
-@@ -0,0 +1,1080 @@
-+/*
-+ * IPSEC MAST code.
-+ * Copyright (C) 1996, 1997 John Ioannidis.
-+ * Copyright (C) 1998, 1999, 2000, 2001, 2002 Richard Guy Briggs.
-+ *
-+ * 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. See <http://www.fsf.org/copyleft/gpl.txt>.
-+ *
-+ * 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.
-+ */
-+
-+char ipsec_mast_c_version[] = "RCSID $Id: ipsec_mast.c,v 1.3 2003/10/31 02:27:55 mcr Exp $";
-+
-+#define __NO_VERSION__
-+#include <linux/module.h>
-+#include <linux/config.h> /* for CONFIG_IP_FORWARD */
-+#include <linux/version.h>
-+#include <linux/kernel.h> /* printk() */
-+
-+#include "freeswan/ipsec_param.h"
-+
-+#ifdef MALLOC_SLAB
-+# include <linux/slab.h> /* kmalloc() */
-+#else /* MALLOC_SLAB */
-+# include <linux/malloc.h> /* kmalloc() */
-+#endif /* MALLOC_SLAB */
-+#include <linux/errno.h> /* error codes */
-+#include <linux/types.h> /* size_t */
-+#include <linux/interrupt.h> /* mark_bh */
-+
-+#include <linux/netdevice.h> /* struct device, struct net_device_stats, dev_queue_xmit() and other headers */
-+#include <linux/etherdevice.h> /* eth_type_trans */
-+#include <linux/ip.h> /* struct iphdr */
-+#include <linux/tcp.h> /* struct tcphdr */
-+#include <linux/udp.h> /* struct udphdr */
-+#include <linux/skbuff.h>
-+#include <freeswan.h>
-+#include <asm/uaccess.h>
-+#include <linux/in6.h>
-+#include <net/dst.h>
-+#undef dev_kfree_skb
-+#define dev_kfree_skb(a,b) kfree_skb(a)
-+#define PHYSDEV_TYPE
-+#include <asm/checksum.h>
-+#include <net/icmp.h> /* icmp_send() */
-+#include <net/ip.h>
-+#include <linux/netfilter_ipv4.h>
-+
-+#include <linux/if_arp.h>
-+
-+#include "freeswan/radij.h"
-+#include "freeswan/ipsec_life.h"
-+#include "freeswan/ipsec_xform.h"
-+#include "freeswan/ipsec_eroute.h"
-+#include "freeswan/ipsec_encap.h"
-+#include "freeswan/ipsec_radij.h"
-+#include "freeswan/ipsec_sa.h"
-+#include "freeswan/ipsec_tunnel.h"
-+#include "freeswan/ipsec_mast.h"
-+#include "freeswan/ipsec_ipe4.h"
-+#include "freeswan/ipsec_ah.h"
-+#include "freeswan/ipsec_esp.h"
-+
-+#include <pfkeyv2.h>
-+#include <pfkey.h>
-+
-+#include "freeswan/ipsec_proto.h"
-+
-+int ipsec_maxdevice_count = -1;
-+
-+DEBUG_NO_STATIC int
-+ipsec_mast_open(struct device *dev)
-+{
-+ struct ipsecpriv *prv = dev->priv;
-+
-+ /*
-+ * Can't open until attached.
-+ */
-+
-+ KLIPS_PRINT(debug_mast & DB_MAST_INIT,
-+ "klips_debug:ipsec_mast_open: "
-+ "dev = %s, prv->dev = %s\n",
-+ dev->name, prv->dev?prv->dev->name:"NONE");
-+
-+ if (prv->dev == NULL)
-+ return -ENODEV;
-+
-+ MOD_INC_USE_COUNT;
-+ return 0;
-+}
-+
-+DEBUG_NO_STATIC int
-+ipsec_mast_close(struct device *dev)
-+{
-+ MOD_DEC_USE_COUNT;
-+ return 0;
-+}
-+
-+static inline int ipsec_mast_xmit2(struct sk_buff *skb)
-+{
-+ return ip_send(skb);
-+}
-+
-+enum ipsec_xmit_value
-+ipsec_mast_send(struct ipsec_xmit_state*ixs)
-+{
-+ /* new route/dst cache code from James Morris */
-+ ixs->skb->dev = ixs->physdev;
-+ /*skb_orphan(ixs->skb);*/
-+ if((ixs->error = ip_route_output(&ixs->route,
-+ ixs->skb->nh.iph->daddr,
-+ ixs->pass ? 0 : ixs->skb->nh.iph->saddr,
-+ RT_TOS(ixs->skb->nh.iph->tos),
-+ ixs->physdev->iflink /* rgb: should this be 0? */))) {
-+ ixs->stats->tx_errors++;
-+ KLIPS_PRINT(debug_mast & DB_MAST_XMIT,
-+ "klips_debug:ipsec_xmit_send: "
-+ "ip_route_output failed with error code %d, rt->u.dst.dev=%s, dropped\n",
-+ ixs->error,
-+ ixs->route->u.dst.dev->name);
-+ return IPSEC_XMIT_ROUTEERR;
-+ }
-+ if(ixs->dev == ixs->route->u.dst.dev) {
-+ ip_rt_put(ixs->route);
-+ /* This is recursion, drop it. */
-+ ixs->stats->tx_errors++;
-+ KLIPS_PRINT(debug_mast & DB_MAST_XMIT,
-+ "klips_debug:ipsec_xmit_send: "
-+ "suspect recursion, dev=rt->u.dst.dev=%s, dropped\n",
-+ ixs->dev->name);
-+ return IPSEC_XMIT_RECURSDETECT;
-+ }
-+ dst_release(ixs->skb->dst);
-+ ixs->skb->dst = &ixs->route->u.dst;
-+ ixs->stats->tx_bytes += ixs->skb->len;
-+ if(ixs->skb->len < ixs->skb->nh.raw - ixs->skb->data) {
-+ ixs->stats->tx_errors++;
-+ printk(KERN_WARNING
-+ "klips_error:ipsec_xmit_send: "
-+ "tried to __skb_pull nh-data=%ld, %d available. This should never happen, please report.\n",
-+ (unsigned long)(ixs->skb->nh.raw - ixs->skb->data),
-+ ixs->skb->len);
-+ return IPSEC_XMIT_PUSHPULLERR;
-+ }
-+ __skb_pull(ixs->skb, ixs->skb->nh.raw - ixs->skb->data);
-+#ifdef SKB_RESET_NFCT
-+ nf_conntrack_put(ixs->skb->nfct);
-+ ixs->skb->nfct = NULL;
-+#ifdef CONFIG_NETFILTER_DEBUG
-+ ixs->skb->nf_debug = 0;
-+#endif /* CONFIG_NETFILTER_DEBUG */
-+#endif /* SKB_RESET_NFCT */
-+ KLIPS_PRINT(debug_mast & DB_MAST_XMIT,
-+ "klips_debug:ipsec_xmit_send: "
-+ "...done, calling ip_send() on device:%s\n",
-+ ixs->skb->dev ? ixs->skb->dev->name : "NULL");
-+ KLIPS_IP_PRINT(debug_mast & DB_MAST_XMIT, ixs->skb->nh.iph);
-+ {
-+ int err;
-+
-+ err = NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, ixs->skb, NULL, ixs->route->u.dst.dev,
-+ ipsec_mast_xmit2);
-+ if(err != NET_XMIT_SUCCESS && err != NET_XMIT_CN) {
-+ if(net_ratelimit())
-+ printk(KERN_ERR
-+ "klips_error:ipsec_xmit_send: "
-+ "ip_send() failed, err=%d\n",
-+ -err);
-+ ixs->stats->tx_errors++;
-+ ixs->stats->tx_aborted_errors++;
-+ ixs->skb = NULL;
-+ return IPSEC_XMIT_IPSENDFAILURE;
-+ }
-+ }
-+ ixs->stats->tx_packets++;
-+
-+ ixs->skb = NULL;
-+
-+ return IPSEC_XMIT_OK;
-+}
-+
-+void
-+ipsec_mast_cleanup(struct ipsec_xmit_state*ixs)
-+{
-+#if defined(HAS_NETIF_QUEUE) || defined (HAVE_NETIF_QUEUE)
-+ netif_wake_queue(ixs->dev);
-+#else /* defined(HAS_NETIF_QUEUE) || defined (HAVE_NETIF_QUEUE) */
-+ ixs->dev->tbusy = 0;
-+#endif /* defined(HAS_NETIF_QUEUE) || defined (HAVE_NETIF_QUEUE) */
-+ if(ixs->saved_header) {
-+ kfree(ixs->saved_header);
-+ }
-+ if(ixs->skb) {
-+ dev_kfree_skb(ixs->skb, FREE_WRITE);
-+ }
-+ if(ixs->oskb) {
-+ dev_kfree_skb(ixs->oskb, FREE_WRITE);
-+ }
-+ if (ixs->ips.ips_ident_s.data) {
-+ kfree(ixs->ips.ips_ident_s.data);
-+ }
-+ if (ixs->ips.ips_ident_d.data) {
-+ kfree(ixs->ips.ips_ident_d.data);
-+ }
-+}
-+
-+#if 0
-+/*
-+ * This function assumes it is being called from dev_queue_xmit()
-+ * and that skb is filled properly by that function.
-+ */
-+int
-+ipsec_mast_start_xmit(struct sk_buff *skb, struct device *dev, IPsecSAref_t SAref)
-+{
-+ struct ipsec_xmit_state ixs_mem;
-+ struct ipsec_xmit_state *ixs = &ixs_mem;
-+ enum ipsec_xmit_value stat = IPSEC_XMIT_OK;
-+
-+ /* dev could be a mast device, but should be optional, I think... */
-+ /* SAref is also optional, but one of the two must be present. */
-+ /* I wonder if it could accept no device or saref and guess? */
-+
-+/* ipsec_xmit_sanity_check_dev(ixs); */
-+
-+ ipsec_xmit_sanity_check_skb(ixs);
-+
-+ ipsec_xmit_adjust_hard_header(ixs);
-+
-+ stat = ipsec_xmit_encap_bundle(ixs);
-+ if(stat != IPSEC_XMIT_OK) {
-+ /* SA processing failed */
-+ }
-+
-+ ipsec_xmit_hard_header_restore();
-+}
-+#endif
-+
-+DEBUG_NO_STATIC struct net_device_stats *
-+ipsec_mast_get_stats(struct device *dev)
-+{
-+ return &(((struct ipsecpriv *)(dev->priv))->mystats);
-+}
-+
-+/*
-+ * Revectored calls.
-+ * For each of these calls, a field exists in our private structure.
-+ */
-+
-+DEBUG_NO_STATIC int
-+ipsec_mast_hard_header(struct sk_buff *skb, struct device *dev,
-+ unsigned short type, void *daddr, void *saddr, unsigned len)
-+{
-+ struct ipsecpriv *prv = dev->priv;
-+ struct device *tmp;
-+ int ret;
-+ struct net_device_stats *stats; /* This device's statistics */
-+
-+ if(skb == NULL) {
-+ KLIPS_PRINT(debug_mast & DB_MAST_REVEC,
-+ "klips_debug:ipsec_mast_hard_header: "
-+ "no skb...\n");
-+ return -ENODATA;
-+ }
-+
-+ if(dev == NULL) {
-+ KLIPS_PRINT(debug_mast & DB_MAST_REVEC,
-+ "klips_debug:ipsec_mast_hard_header: "
-+ "no device...\n");
-+ return -ENODEV;
-+ }
-+
-+ KLIPS_PRINT(debug_mast & DB_MAST_REVEC,
-+ "klips_debug:ipsec_mast_hard_header: "
-+ "skb->dev=%s dev=%s.\n",
-+ skb->dev ? skb->dev->name : "NULL",
-+ dev->name);
-+
-+ if(prv == NULL) {
-+ KLIPS_PRINT(debug_mast & DB_MAST_REVEC,
-+ "klips_debug:ipsec_mast_hard_header: "
-+ "no private space associated with dev=%s\n",
-+ dev->name ? dev->name : "NULL");
-+ return -ENODEV;
-+ }
-+
-+ stats = (struct net_device_stats *) &(prv->mystats);
-+
-+ if(prv->dev == NULL) {
-+ KLIPS_PRINT(debug_mast & DB_MAST_REVEC,
-+ "klips_debug:ipsec_mast_hard_header: "
-+ "no physical device associated with dev=%s\n",
-+ dev->name ? dev->name : "NULL");
-+ stats->tx_dropped++;
-+ return -ENODEV;
-+ }
-+
-+ /* check if we have to send a IPv6 packet. It might be a Router
-+ Solicitation, where the building of the packet happens in
-+ reverse order:
-+ 1. ll hdr,
-+ 2. IPv6 hdr,
-+ 3. ICMPv6 hdr
-+ -> skb->nh.raw is still uninitialized when this function is
-+ called!! If this is no IPv6 packet, we can print debugging
-+ messages, otherwise we skip all debugging messages and just
-+ build the ll header */
-+ if(type != ETH_P_IPV6) {
-+ /* execute this only, if we don't have to build the
-+ header for a IPv6 packet */
-+ if(!prv->hard_header) {
-+ KLIPS_PRINT(debug_mast & DB_MAST_REVEC,
-+ "klips_debug:ipsec_mast_hard_header: "
-+ "physical device has been detached, packet dropped 0p%p->0p%p len=%d type=%d dev=%s->NULL ",
-+ saddr,
-+ daddr,
-+ len,
-+ type,
-+ dev->name);
-+ KLIPS_PRINTMORE(debug_mast & DB_MAST_REVEC,
-+ "ip=%08x->%08x\n",
-+ (__u32)ntohl(skb->nh.iph->saddr),
-+ (__u32)ntohl(skb->nh.iph->daddr) );
-+ stats->tx_dropped++;
-+ return -ENODEV;
-+ }
-+
-+#define da ((struct device *)(prv->dev))->dev_addr
-+ KLIPS_PRINT(debug_mast & DB_MAST_REVEC,
-+ "klips_debug:ipsec_mast_hard_header: "
-+ "Revectored 0p%p->0p%p len=%d type=%d dev=%s->%s dev_addr=%02x:%02x:%02x:%02x:%02x:%02x ",
-+ saddr,
-+ daddr,
-+ len,
-+ type,
-+ dev->name,
-+ prv->dev->name,
-+ da[0], da[1], da[2], da[3], da[4], da[5]);
-+ KLIPS_PRINTMORE(debug_mast & DB_MAST_REVEC,
-+ "ip=%08x->%08x\n",
-+ (__u32)ntohl(skb->nh.iph->saddr),
-+ (__u32)ntohl(skb->nh.iph->daddr) );
-+ } else {
-+ KLIPS_PRINT(debug_mast,
-+ "klips_debug:ipsec_mast_hard_header: "
-+ "is IPv6 packet, skip debugging messages, only revector and build linklocal header.\n");
-+ }
-+ tmp = skb->dev;
-+ skb->dev = prv->dev;
-+ ret = prv->hard_header(skb, prv->dev, type, (void *)daddr, (void *)saddr, len);
-+ skb->dev = tmp;
-+ return ret;
-+}
-+
-+DEBUG_NO_STATIC int
-+ipsec_mast_rebuild_header(struct sk_buff *skb)
-+{
-+ struct ipsecpriv *prv = skb->dev->priv;
-+ struct device *tmp;
-+ int ret;
-+ struct net_device_stats *stats; /* This device's statistics */
-+
-+ if(skb->dev == NULL) {
-+ KLIPS_PRINT(debug_mast & DB_MAST_REVEC,
-+ "klips_debug:ipsec_mast_rebuild_header: "
-+ "no device...");
-+ return -ENODEV;
-+ }
-+
-+ if(prv == NULL) {
-+ KLIPS_PRINT(debug_mast & DB_MAST_REVEC,
-+ "klips_debug:ipsec_mast_rebuild_header: "
-+ "no private space associated with dev=%s",
-+ skb->dev->name ? skb->dev->name : "NULL");
-+ return -ENODEV;
-+ }
-+
-+ stats = (struct net_device_stats *) &(prv->mystats);
-+
-+ if(prv->dev == NULL) {
-+ KLIPS_PRINT(debug_mast & DB_MAST_REVEC,
-+ "klips_debug:ipsec_mast_rebuild_header: "
-+ "no physical device associated with dev=%s",
-+ skb->dev->name ? skb->dev->name : "NULL");
-+ stats->tx_dropped++;
-+ return -ENODEV;
-+ }
-+
-+ if(!prv->rebuild_header) {
-+ KLIPS_PRINT(debug_mast & DB_MAST_REVEC,
-+ "klips_debug:ipsec_mast_rebuild_header: "
-+ "physical device has been detached, packet dropped skb->dev=%s->NULL ",
-+ skb->dev->name);
-+ KLIPS_PRINT(debug_mast & DB_MAST_REVEC,
-+ "ip=%08x->%08x\n",
-+ (__u32)ntohl(skb->nh.iph->saddr),
-+ (__u32)ntohl(skb->nh.iph->daddr) );
-+ stats->tx_dropped++;
-+ return -ENODEV;
-+ }
-+
-+ KLIPS_PRINT(debug_mast & DB_MAST_REVEC,
-+ "klips_debug:ipsec_mast: "
-+ "Revectored rebuild_header dev=%s->%s ",
-+ skb->dev->name, prv->dev->name);
-+ KLIPS_PRINT(debug_mast & DB_MAST_REVEC,
-+ "ip=%08x->%08x\n",
-+ (__u32)ntohl(skb->nh.iph->saddr),
-+ (__u32)ntohl(skb->nh.iph->daddr) );
-+ tmp = skb->dev;
-+ skb->dev = prv->dev;
-+
-+ ret = prv->rebuild_header(skb);
-+ skb->dev = tmp;
-+ return ret;
-+}
-+
-+DEBUG_NO_STATIC int
-+ipsec_mast_set_mac_address(struct device *dev, void *addr)
-+{
-+ struct ipsecpriv *prv = dev->priv;
-+
-+ struct net_device_stats *stats; /* This device's statistics */
-+
-+ if(dev == NULL) {
-+ KLIPS_PRINT(debug_mast & DB_MAST_REVEC,
-+ "klips_debug:ipsec_mast_set_mac_address: "
-+ "no device...");
-+ return -ENODEV;
-+ }
-+
-+ if(prv == NULL) {
-+ KLIPS_PRINT(debug_mast & DB_MAST_REVEC,
-+ "klips_debug:ipsec_mast_set_mac_address: "
-+ "no private space associated with dev=%s",
-+ dev->name ? dev->name : "NULL");
-+ return -ENODEV;
-+ }
-+
-+ stats = (struct net_device_stats *) &(prv->mystats);
-+
-+ if(prv->dev == NULL) {
-+ KLIPS_PRINT(debug_mast & DB_MAST_REVEC,
-+ "klips_debug:ipsec_mast_set_mac_address: "
-+ "no physical device associated with dev=%s",
-+ dev->name ? dev->name : "NULL");
-+ stats->tx_dropped++;
-+ return -ENODEV;
-+ }
-+
-+ if(!prv->set_mac_address) {
-+ KLIPS_PRINT(debug_mast & DB_MAST_REVEC,
-+ "klips_debug:ipsec_mast_set_mac_address: "
-+ "physical device has been detached, cannot set - skb->dev=%s->NULL\n",
-+ dev->name);
-+ return -ENODEV;
-+ }
-+
-+ KLIPS_PRINT(debug_mast & DB_MAST_REVEC,
-+ "klips_debug:ipsec_mast_set_mac_address: "
-+ "Revectored dev=%s->%s addr=0p%p\n",
-+ dev->name, prv->dev->name, addr);
-+ return prv->set_mac_address(prv->dev, addr);
-+
-+}
-+
-+DEBUG_NO_STATIC void
-+ipsec_mast_cache_update(struct hh_cache *hh, struct device *dev, unsigned char * haddr)
-+{
-+ struct ipsecpriv *prv = dev->priv;
-+
-+ struct net_device_stats *stats; /* This device's statistics */
-+
-+ if(dev == NULL) {
-+ KLIPS_PRINT(debug_mast & DB_MAST_REVEC,
-+ "klips_debug:ipsec_mast_cache_update: "
-+ "no device...");
-+ return;
-+ }
-+
-+ if(prv == NULL) {
-+ KLIPS_PRINT(debug_mast & DB_MAST_REVEC,
-+ "klips_debug:ipsec_mast_cache_update: "
-+ "no private space associated with dev=%s",
-+ dev->name ? dev->name : "NULL");
-+ return;
-+ }
-+
-+ stats = (struct net_device_stats *) &(prv->mystats);
-+
-+ if(prv->dev == NULL) {
-+ KLIPS_PRINT(debug_mast & DB_MAST_REVEC,
-+ "klips_debug:ipsec_mast_cache_update: "
-+ "no physical device associated with dev=%s",
-+ dev->name ? dev->name : "NULL");
-+ stats->tx_dropped++;
-+ return;
-+ }
-+
-+ if(!prv->header_cache_update) {
-+ KLIPS_PRINT(debug_mast & DB_MAST_REVEC,
-+ "klips_debug:ipsec_mast_cache_update: "
-+ "physical device has been detached, cannot set - skb->dev=%s->NULL\n",
-+ dev->name);
-+ return;
-+ }
-+
-+ KLIPS_PRINT(debug_mast & DB_MAST_REVEC,
-+ "klips_debug:ipsec_mast: "
-+ "Revectored cache_update\n");
-+ prv->header_cache_update(hh, prv->dev, haddr);
-+ return;
-+}
-+
-+DEBUG_NO_STATIC int
-+ipsec_mast_neigh_setup(struct neighbour *n)
-+{
-+ KLIPS_PRINT(debug_mast & DB_MAST_REVEC,
-+ "klips_debug:ipsec_mast_neigh_setup:\n");
-+
-+ if (n->nud_state == NUD_NONE) {
-+ n->ops = &arp_broken_ops;
-+ n->output = n->ops->output;
-+ }
-+ return 0;
-+}
-+
-+DEBUG_NO_STATIC int
-+ipsec_mast_neigh_setup_dev(struct device *dev, struct neigh_parms *p)
-+{
-+ KLIPS_PRINT(debug_mast & DB_MAST_REVEC,
-+ "klips_debug:ipsec_mast_neigh_setup_dev: "
-+ "setting up %s\n",
-+ dev ? dev->name : "NULL");
-+
-+ if (p->tbl->family == AF_INET) {
-+ p->neigh_setup = ipsec_mast_neigh_setup;
-+ p->ucast_probes = 0;
-+ p->mcast_probes = 0;
-+ }
-+ return 0;
-+}
-+
-+/*
-+ * We call the attach routine to attach another device.
-+ */
-+
-+DEBUG_NO_STATIC int
-+ipsec_mast_attach(struct device *dev, struct device *physdev)
-+{
-+ int i;
-+ struct ipsecpriv *prv = dev->priv;
-+
-+ if(dev == NULL) {
-+ KLIPS_PRINT(debug_mast & DB_MAST_REVEC,
-+ "klips_debug:ipsec_mast_attach: "
-+ "no device...");
-+ return -ENODEV;
-+ }
-+
-+ if(prv == NULL) {
-+ KLIPS_PRINT(debug_mast & DB_MAST_REVEC,
-+ "klips_debug:ipsec_mast_attach: "
-+ "no private space associated with dev=%s",
-+ dev->name ? dev->name : "NULL");
-+ return -ENODATA;
-+ }
-+
-+ prv->dev = physdev;
-+ prv->hard_start_xmit = physdev->hard_start_xmit;
-+ prv->get_stats = physdev->get_stats;
-+
-+ if (physdev->hard_header) {
-+ prv->hard_header = physdev->hard_header;
-+ dev->hard_header = ipsec_mast_hard_header;
-+ } else
-+ dev->hard_header = NULL;
-+
-+ if (physdev->rebuild_header) {
-+ prv->rebuild_header = physdev->rebuild_header;
-+ dev->rebuild_header = ipsec_mast_rebuild_header;
-+ } else
-+ dev->rebuild_header = NULL;
-+
-+ if (physdev->set_mac_address) {
-+ prv->set_mac_address = physdev->set_mac_address;
-+ dev->set_mac_address = ipsec_mast_set_mac_address;
-+ } else
-+ dev->set_mac_address = NULL;
-+
-+ if (physdev->header_cache_update) {
-+ prv->header_cache_update = physdev->header_cache_update;
-+ dev->header_cache_update = ipsec_mast_cache_update;
-+ } else
-+ dev->header_cache_update = NULL;
-+
-+ dev->hard_header_len = physdev->hard_header_len;
-+
-+/* prv->neigh_setup = physdev->neigh_setup; */
-+ dev->neigh_setup = ipsec_mast_neigh_setup_dev;
-+ dev->mtu = 16260; /* 0xfff0; */ /* dev->mtu; */
-+ prv->mtu = physdev->mtu;
-+
-+#ifdef PHYSDEV_TYPE
-+ dev->type = physdev->type; /* ARPHRD_MAST; */
-+#endif /* PHYSDEV_TYPE */
-+
-+ dev->addr_len = physdev->addr_len;
-+ for (i=0; i<dev->addr_len; i++) {
-+ dev->dev_addr[i] = physdev->dev_addr[i];
-+ }
-+#ifdef CONFIG_IPSEC_DEBUG
-+ if(debug_mast & DB_MAST_INIT) {
-+ printk(KERN_INFO "klips_debug:ipsec_mast_attach: "
-+ "physical device %s being attached has HW address: %2x",
-+ physdev->name, physdev->dev_addr[0]);
-+ for (i=1; i < physdev->addr_len; i++) {
-+ printk(":%02x", physdev->dev_addr[i]);
-+ }
-+ printk("\n");
-+ }
-+#endif /* CONFIG_IPSEC_DEBUG */
-+
-+ return 0;
-+}
-+
-+/*
-+ * We call the detach routine to detach the ipsec mast from another device.
-+ */
-+
-+DEBUG_NO_STATIC int
-+ipsec_mast_detach(struct device *dev)
-+{
-+ int i;
-+ struct ipsecpriv *prv = dev->priv;
-+
-+ if(dev == NULL) {
-+ KLIPS_PRINT(debug_mast & DB_MAST_REVEC,
-+ "klips_debug:ipsec_mast_detach: "
-+ "no device...");
-+ return -ENODEV;
-+ }
-+
-+ if(prv == NULL) {
-+ KLIPS_PRINT(debug_mast & DB_MAST_REVEC,
-+ "klips_debug:ipsec_mast_detach: "
-+ "no private space associated with dev=%s",
-+ dev->name ? dev->name : "NULL");
-+ return -ENODATA;
-+ }
-+
-+ KLIPS_PRINT(debug_mast & DB_MAST_INIT,
-+ "klips_debug:ipsec_mast_detach: "
-+ "physical device %s being detached from virtual device %s\n",
-+ prv->dev ? prv->dev->name : "NULL",
-+ dev->name);
-+
-+ prv->dev = NULL;
-+ prv->hard_start_xmit = NULL;
-+ prv->get_stats = NULL;
-+
-+ prv->hard_header = NULL;
-+#ifdef DETACH_AND_DOWN
-+ dev->hard_header = NULL;
-+#endif /* DETACH_AND_DOWN */
-+
-+ prv->rebuild_header = NULL;
-+#ifdef DETACH_AND_DOWN
-+ dev->rebuild_header = NULL;
-+#endif /* DETACH_AND_DOWN */
-+
-+ prv->set_mac_address = NULL;
-+#ifdef DETACH_AND_DOWN
-+ dev->set_mac_address = NULL;
-+#endif /* DETACH_AND_DOWN */
-+
-+ prv->header_cache_update = NULL;
-+#ifdef DETACH_AND_DOWN
-+ dev->header_cache_update = NULL;
-+#endif /* DETACH_AND_DOWN */
-+
-+#ifdef DETACH_AND_DOWN
-+ dev->neigh_setup = NULL;
-+#endif /* DETACH_AND_DOWN */
-+
-+ dev->hard_header_len = 0;
-+#ifdef DETACH_AND_DOWN
-+ dev->mtu = 0;
-+#endif /* DETACH_AND_DOWN */
-+ prv->mtu = 0;
-+ for (i=0; i<MAX_ADDR_LEN; i++) {
-+ dev->dev_addr[i] = 0;
-+ }
-+ dev->addr_len = 0;
-+#ifdef PHYSDEV_TYPE
-+ dev->type = ARPHRD_VOID; /* ARPHRD_MAST; */
-+#endif /* PHYSDEV_TYPE */
-+
-+ return 0;
-+}
-+
-+/*
-+ * We call the clear routine to detach all ipsec masts from other devices.
-+ */
-+DEBUG_NO_STATIC int
-+ipsec_mast_clear(void)
-+{
-+ int i;
-+ struct device *ipsecdev = NULL, *prvdev;
-+ struct ipsecpriv *prv;
-+ char name[9];
-+ int ret;
-+
-+ KLIPS_PRINT(debug_mast & DB_MAST_INIT,
-+ "klips_debug:ipsec_mast_clear: .\n");
-+
-+ for(i = 0; i < IPSEC_NUM_IF; i++) {
-+ sprintf(name, IPSEC_DEV_FORMAT, i);
-+ if((ipsecdev = ipsec_dev_get(name)) != NULL) {
-+ if((prv = (struct ipsecpriv *)(ipsecdev->priv))) {
-+ prvdev = (struct device *)(prv->dev);
-+ if(prvdev) {
-+ KLIPS_PRINT(debug_mast & DB_MAST_INIT,
-+ "klips_debug:ipsec_mast_clear: "
-+ "physical device for device %s is %s\n",
-+ name, prvdev->name);
-+ if((ret = ipsec_mast_detach(ipsecdev))) {
-+ KLIPS_PRINT(debug_mast & DB_MAST_INIT,
-+ "klips_debug:ipsec_mast_clear: "
-+ "error %d detatching device %s from device %s.\n",
-+ ret, name, prvdev->name);
-+ return ret;
-+ }
-+ }
-+ }
-+ }
-+ }
-+ return 0;
-+}
-+
-+DEBUG_NO_STATIC int
-+ipsec_mast_ioctl(struct device *dev, struct ifreq *ifr, int cmd)
-+{
-+ struct ipsecmastconf *cf = (struct ipsecmastconf *)&ifr->ifr_data;
-+ struct ipsecpriv *prv = dev->priv;
-+ struct device *them; /* physical device */
-+#ifdef CONFIG_IP_ALIAS
-+ char *colon;
-+ char realphysname[IFNAMSIZ];
-+#endif /* CONFIG_IP_ALIAS */
-+
-+ if(dev == NULL) {
-+ KLIPS_PRINT(debug_mast & DB_MAST_INIT,
-+ "klips_debug:ipsec_mast_ioctl: "
-+ "device not supplied.\n");
-+ return -ENODEV;
-+ }
-+
-+ KLIPS_PRINT(debug_mast & DB_MAST_INIT,
-+ "klips_debug:ipsec_mast_ioctl: "
-+ "tncfg service call #%d for dev=%s\n",
-+ cmd,
-+ dev->name ? dev->name : "NULL");
-+ switch (cmd) {
-+ /* attach a virtual ipsec? device to a physical device */
-+ case IPSEC_SET_DEV:
-+ KLIPS_PRINT(debug_mast & DB_MAST_INIT,
-+ "klips_debug:ipsec_mast_ioctl: "
-+ "calling ipsec_mast_attatch...\n");
-+#ifdef CONFIG_IP_ALIAS
-+ /* If this is an IP alias interface, get its real physical name */
-+ strncpy(realphysname, cf->cf_name, IFNAMSIZ);
-+ realphysname[IFNAMSIZ-1] = 0;
-+ colon = strchr(realphysname, ':');
-+ if (colon) *colon = 0;
-+ them = ipsec_dev_get(realphysname);
-+#else /* CONFIG_IP_ALIAS */
-+ them = ipsec_dev_get(cf->cf_name);
-+#endif /* CONFIG_IP_ALIAS */
-+
-+ if (them == NULL) {
-+ KLIPS_PRINT(debug_mast & DB_MAST_INIT,
-+ "klips_debug:ipsec_mast_ioctl: "
-+ "physical device %s requested is null\n",
-+ cf->cf_name);
-+ return -ENXIO;
-+ }
-+
-+#if 0
-+ if (them->flags & IFF_UP) {
-+ KLIPS_PRINT(debug_mast & DB_MAST_INIT,
-+ "klips_debug:ipsec_mast_ioctl: "
-+ "physical device %s requested is not up.\n",
-+ cf->cf_name);
-+ return -ENXIO;
-+ }
-+#endif
-+
-+ if (prv && prv->dev) {
-+ KLIPS_PRINT(debug_mast & DB_MAST_INIT,
-+ "klips_debug:ipsec_mast_ioctl: "
-+ "virtual device is already connected to %s.\n",
-+ prv->dev->name ? prv->dev->name : "NULL");
-+ return -EBUSY;
-+ }
-+ return ipsec_mast_attach(dev, them);
-+
-+ case IPSEC_DEL_DEV:
-+ KLIPS_PRINT(debug_mast & DB_MAST_INIT,
-+ "klips_debug:ipsec_mast_ioctl: "
-+ "calling ipsec_mast_detatch.\n");
-+ if (! prv->dev) {
-+ KLIPS_PRINT(debug_mast & DB_MAST_INIT,
-+ "klips_debug:ipsec_mast_ioctl: "
-+ "physical device not connected.\n");
-+ return -ENODEV;
-+ }
-+ return ipsec_mast_detach(dev);
-+
-+ case IPSEC_CLR_DEV:
-+ KLIPS_PRINT(debug_mast & DB_MAST_INIT,
-+ "klips_debug:ipsec_mast_ioctl: "
-+ "calling ipsec_mast_clear.\n");
-+ return ipsec_mast_clear();
-+
-+ default:
-+ KLIPS_PRINT(debug_mast & DB_MAST_INIT,
-+ "klips_debug:ipsec_mast_ioctl: "
-+ "unknown command %d.\n",
-+ cmd);
-+ return -EOPNOTSUPP;
-+ }
-+}
-+
-+int
-+ipsec_mast_device_event(struct notifier_block *unused, unsigned long event, void *ptr)
-+{
-+ struct device *dev = ptr;
-+ struct device *ipsec_dev;
-+ struct ipsecpriv *priv;
-+ char name[9];
-+ int i;
-+
-+ if (dev == NULL) {
-+ KLIPS_PRINT(debug_mast & DB_MAST_INIT,
-+ "klips_debug:ipsec_mast_device_event: "
-+ "dev=NULL for event type %ld.\n",
-+ event);
-+ return(NOTIFY_DONE);
-+ }
-+
-+ /* check for loopback devices */
-+ if (dev && (dev->flags & IFF_LOOPBACK)) {
-+ return(NOTIFY_DONE);
-+ }
-+
-+ switch (event) {
-+ case NETDEV_DOWN:
-+ /* look very carefully at the scope of these compiler
-+ directives before changing anything... -- RGB */
-+
-+ case NETDEV_UNREGISTER:
-+ switch (event) {
-+ case NETDEV_DOWN:
-+ KLIPS_PRINT(debug_mast & DB_MAST_INIT,
-+ "klips_debug:ipsec_mast_device_event: "
-+ "NETDEV_DOWN dev=%s flags=%x\n",
-+ dev->name,
-+ dev->flags);
-+ if(strncmp(dev->name, "ipsec", strlen("ipsec")) == 0) {
-+ printk(KERN_CRIT "IPSEC EVENT: KLIPS device %s shut down.\n",
-+ dev->name);
-+ }
-+ break;
-+ case NETDEV_UNREGISTER:
-+ KLIPS_PRINT(debug_mast & DB_MAST_INIT,
-+ "klips_debug:ipsec_mast_device_event: "
-+ "NETDEV_UNREGISTER dev=%s flags=%x\n",
-+ dev->name,
-+ dev->flags);
-+ break;
-+ }
-+
-+ /* find the attached physical device and detach it. */
-+ for(i = 0; i < IPSEC_NUM_IF; i++) {
-+ sprintf(name, IPSEC_DEV_FORMAT, i);
-+ ipsec_dev = ipsec_dev_get(name);
-+ if(ipsec_dev) {
-+ priv = (struct ipsecpriv *)(ipsec_dev->priv);
-+ if(priv) {
-+ ;
-+ if(((struct device *)(priv->dev)) == dev) {
-+ /* dev_close(ipsec_dev); */
-+ /* return */ ipsec_mast_detach(ipsec_dev);
-+ KLIPS_PRINT(debug_mast & DB_MAST_INIT,
-+ "klips_debug:ipsec_mast_device_event: "
-+ "device '%s' has been detached.\n",
-+ ipsec_dev->name);
-+ break;
-+ }
-+ } else {
-+ KLIPS_PRINT(debug_mast & DB_MAST_INIT,
-+ "klips_debug:ipsec_mast_device_event: "
-+ "device '%s' has no private data space!\n",
-+ ipsec_dev->name);
-+ }
-+ }
-+ }
-+ break;
-+ case NETDEV_UP:
-+ KLIPS_PRINT(debug_mast & DB_MAST_INIT,
-+ "klips_debug:ipsec_mast_device_event: "
-+ "NETDEV_UP dev=%s\n",
-+ dev->name);
-+ break;
-+ case NETDEV_REBOOT:
-+ KLIPS_PRINT(debug_mast & DB_MAST_INIT,
-+ "klips_debug:ipsec_mast_device_event: "
-+ "NETDEV_REBOOT dev=%s\n",
-+ dev->name);
-+ break;
-+ case NETDEV_CHANGE:
-+ KLIPS_PRINT(debug_mast & DB_MAST_INIT,
-+ "klips_debug:ipsec_mast_device_event: "
-+ "NETDEV_CHANGE dev=%s flags=%x\n",
-+ dev->name,
-+ dev->flags);
-+ break;
-+ case NETDEV_REGISTER:
-+ KLIPS_PRINT(debug_mast & DB_MAST_INIT,
-+ "klips_debug:ipsec_mast_device_event: "
-+ "NETDEV_REGISTER dev=%s\n",
-+ dev->name);
-+ break;
-+ case NETDEV_CHANGEMTU:
-+ KLIPS_PRINT(debug_mast & DB_MAST_INIT,
-+ "klips_debug:ipsec_mast_device_event: "
-+ "NETDEV_CHANGEMTU dev=%s to mtu=%d\n",
-+ dev->name,
-+ dev->mtu);
-+ break;
-+ case NETDEV_CHANGEADDR:
-+ KLIPS_PRINT(debug_mast & DB_MAST_INIT,
-+ "klips_debug:ipsec_mast_device_event: "
-+ "NETDEV_CHANGEADDR dev=%s\n",
-+ dev->name);
-+ break;
-+ case NETDEV_GOING_DOWN:
-+ KLIPS_PRINT(debug_mast & DB_MAST_INIT,
-+ "klips_debug:ipsec_mast_device_event: "
-+ "NETDEV_GOING_DOWN dev=%s\n",
-+ dev->name);
-+ break;
-+ case NETDEV_CHANGENAME:
-+ KLIPS_PRINT(debug_mast & DB_MAST_INIT,
-+ "klips_debug:ipsec_mast_device_event: "
-+ "NETDEV_CHANGENAME dev=%s\n",
-+ dev->name);
-+ break;
-+ default:
-+ KLIPS_PRINT(debug_mast & DB_MAST_INIT,
-+ "klips_debug:ipsec_mast_device_event: "
-+ "event type %ld unrecognised for dev=%s\n",
-+ event,
-+ dev->name);
-+ break;
-+ }
-+ return NOTIFY_DONE;
-+}
-+
-+/*
-+ * Called when an ipsec mast device is initialized.
-+ * The ipsec mast device structure is passed to us.
-+ */
-+
-+int
-+ipsec_mast_init(struct device *dev)
-+{
-+ int i;
-+
-+ KLIPS_PRINT(debug_mast,
-+ "klips_debug:ipsec_mast_init: "
-+ "allocating %lu bytes initialising device: %s\n",
-+ (unsigned long) sizeof(struct ipsecpriv),
-+ dev->name ? dev->name : "NULL");
-+
-+ /* Add our mast functions to the device */
-+ dev->open = ipsec_mast_open;
-+ dev->stop = ipsec_mast_close;
-+ dev->hard_start_xmit = ipsec_mast_start_xmit;
-+ dev->get_stats = ipsec_mast_get_stats;
-+
-+ dev->priv = kmalloc(sizeof(struct ipsecpriv), GFP_KERNEL);
-+ if (dev->priv == NULL)
-+ return -ENOMEM;
-+ memset((caddr_t)(dev->priv), 0, sizeof(struct ipsecpriv));
-+
-+ for(i = 0; i < sizeof(zeroes); i++) {
-+ ((__u8*)(zeroes))[i] = 0;
-+ }
-+
-+ dev->set_multicast_list = NULL;
-+ dev->do_ioctl = ipsec_mast_ioctl;
-+ dev->hard_header = NULL;
-+ dev->rebuild_header = NULL;
-+ dev->set_mac_address = NULL;
-+ dev->header_cache_update= NULL;
-+ dev->neigh_setup = ipsec_mast_neigh_setup_dev;
-+ dev->hard_header_len = 0;
-+ dev->mtu = 0;
-+ dev->addr_len = 0;
-+ dev->type = ARPHRD_VOID; /* ARPHRD_MAST; */ /* ARPHRD_ETHER; */
-+ dev->tx_queue_len = 10; /* Small queue */
-+ memset((caddr_t)(dev->broadcast),0xFF, ETH_ALEN); /* what if this is not attached to ethernet? */
-+
-+ /* New-style flags. */
-+ dev->flags = IFF_NOARP /* 0 */ /* Petr Novak */;
-+ dev_init_buffers(dev);
-+
-+ /* We're done. Have I forgotten anything? */
-+ return 0;
-+}
-+
-+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
-+/* Module specific interface (but it links with the rest of IPSEC) */
-+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
-+
-+int
-+ipsec_mast_probe(struct device *dev)
-+{
-+ ipsec_mast_init(dev);
-+ return 0;
-+}
-+
-+int
-+ipsec_mast_init_devices(void)
-+{
-+ return 0;
-+}
-+
-+/* void */
-+int
-+ipsec_mast_cleanup_devices(void)
-+{
-+ int error = 0;
-+ int i;
-+ char name[10];
-+ struct device *dev_mast;
-+
-+ for(i = 0; i < ipsec_mastdevice_count; i++) {
-+ sprintf(name, MAST_DEV_FORMAT, i);
-+ if((dev_mast = ipsec_dev_get(name)) == NULL) {
-+ break;
-+ }
-+ unregister_netdev(dev_mast);
-+ kfree(dev_mast->priv);
-+ dev_mast->priv=NULL;
-+ }
-+ return error;
-+}
-+
-+/*
-+ * $Log: ipsec_mast.c,v $
-+ * Revision 1.3 2003/10/31 02:27:55 mcr
-+ * pulled up port-selector patches and sa_id elimination.
-+ *
-+ * Revision 1.2.4.1 2003/10/29 01:30:41 mcr
-+ * elimited "struct sa_id".
-+ *
-+ * Revision 1.2 2003/06/22 20:06:17 mcr
-+ * refactored mast code still had lots of ipsecX junk in it.
-+ *
-+ * Revision 1.1 2003/02/12 19:31:12 rgb
-+ * Refactored from ipsec_tunnel.c
-+ *
-+ */
---- /dev/null Tue Mar 11 13:02:56 2003
-+++ linux/net/ipsec/ipsec_md5c.c Mon Feb 9 13:51:03 2004
-@@ -0,0 +1,448 @@
-+/*
-+ * RCSID $Id: ipsec_md5c.c,v 1.8 2004/04/06 02:49:26 mcr Exp $
-+ */
-+
-+/*
-+ * The rest of the code is derived from MD5C.C by RSADSI. Minor cosmetic
-+ * changes to accomodate it in the kernel by ji.
-+ */
-+
-+#include <asm/byteorder.h>
-+#include <linux/string.h>
-+
-+#include "openswan/ipsec_md5h.h"
-+
-+/* MD5C.C - RSA Data Security, Inc., MD5 message-digest algorithm
-+ */
-+
-+/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
-+rights reserved.
-+
-+License to copy and use this software is granted provided that it
-+is identified as the "RSA Data Security, Inc. MD5 Message-Digest
-+Algorithm" in all material mentioning or referencing this software
-+or this function.
-+
-+License is also granted to make and use derivative works provided
-+that such works are identified as "derived from the RSA Data
-+Security, Inc. MD5 Message-Digest Algorithm" in all material
-+mentioning or referencing the derived work.
-+
-+RSA Data Security, Inc. makes no representations concerning either
-+the merchantability of this software or the suitability of this
-+software for any particular purpose. It is provided "as is"
-+without express or implied warranty of any kind.
-+
-+These notices must be retained in any copies of any part of this
-+documentation and/or software.
-+ */
-+
-+/*
-+ * Additions by JI
-+ *
-+ * HAVEMEMCOPY is defined if mem* routines are available
-+ *
-+ * HAVEHTON is defined if htons() and htonl() can be used
-+ * for big/little endian conversions
-+ *
-+ */
-+
-+#define HAVEMEMCOPY
-+#ifdef __LITTLE_ENDIAN
-+#define LITTLENDIAN
-+#endif
-+#ifdef __BIG_ENDIAN
-+#define BIGENDIAN
-+#endif
-+
-+/* Constants for MD5Transform routine.
-+ */
-+
-+#define S11 7
-+#define S12 12
-+#define S13 17
-+#define S14 22
-+#define S21 5
-+#define S22 9
-+#define S23 14
-+#define S24 20
-+#define S31 4
-+#define S32 11
-+#define S33 16
-+#define S34 23
-+#define S41 6
-+#define S42 10
-+#define S43 15
-+#define S44 21
-+
-+static void MD5Transform PROTO_LIST ((UINT4 [4], unsigned char [64]));
-+
-+#ifdef LITTLEENDIAN
-+#define Encode MD5_memcpy
-+#define Decode MD5_memcpy
-+#else
-+static void Encode PROTO_LIST
-+ ((unsigned char *, UINT4 *, unsigned int));
-+static void Decode PROTO_LIST
-+ ((UINT4 *, unsigned char *, unsigned int));
-+#endif
-+
-+#ifdef HAVEMEMCOPY
-+/* no need to include <memory.h> here; <linux/string.h> defines these */
-+#define MD5_memcpy memcpy
-+#define MD5_memset memset
-+#else
-+#ifdef HAVEBCOPY
-+#define MD5_memcpy(_a,_b,_c) bcopy((_b),(_a),(_c))
-+#define MD5_memset(_a,_b,_c) bzero((_a),(_c))
-+#else
-+static void MD5_memcpy PROTO_LIST ((POINTER, POINTER, unsigned int));
-+static void MD5_memset PROTO_LIST ((POINTER, int, unsigned int));
-+#endif
-+#endif
-+static unsigned char PADDING[64] = {
-+ 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
-+};
-+
-+/* F, G, H and I are basic MD5 functions.
-+ */
-+#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
-+#define G(x, y, z) (((x) & (z)) | ((y) & (~z)))
-+#define H(x, y, z) ((x) ^ (y) ^ (z))
-+#define I(x, y, z) ((y) ^ ((x) | (~z)))
-+
-+/* ROTATE_LEFT rotates x left n bits.
-+ */
-+#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
-+
-+/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4.
-+Rotation is separate from addition to prevent recomputation.
-+ */
-+#define FF(a, b, c, d, x, s, ac) { \
-+ (a) += F ((b), (c), (d)) + (x) + (UINT4)(ac); \
-+ (a) = ROTATE_LEFT ((a), (s)); \
-+ (a) += (b); \
-+ }
-+#define GG(a, b, c, d, x, s, ac) { \
-+ (a) += G ((b), (c), (d)) + (x) + (UINT4)(ac); \
-+ (a) = ROTATE_LEFT ((a), (s)); \
-+ (a) += (b); \
-+ }
-+#define HH(a, b, c, d, x, s, ac) { \
-+ (a) += H ((b), (c), (d)) + (x) + (UINT4)(ac); \
-+ (a) = ROTATE_LEFT ((a), (s)); \
-+ (a) += (b); \
-+ }
-+#define II(a, b, c, d, x, s, ac) { \
-+ (a) += I ((b), (c), (d)) + (x) + (UINT4)(ac); \
-+ (a) = ROTATE_LEFT ((a), (s)); \
-+ (a) += (b); \
-+ }
-+
-+/*
-+ * MD5 initialization. Begins an MD5 operation, writing a new context.
-+ */
-+void MD5Init(void *vcontext)
-+{
-+ MD5_CTX *context = vcontext;
-+
-+ context->count[0] = context->count[1] = 0;
-+ /* Load magic initialization constants.
-+*/
-+ context->state[0] = 0x67452301;
-+ context->state[1] = 0xefcdab89;
-+ context->state[2] = 0x98badcfe;
-+ context->state[3] = 0x10325476;
-+}
-+
-+/* MD5 block update operation. Continues an MD5 message-digest
-+ operation, processing another message block, and updating the
-+ context.
-+ */
-+void MD5Update (vcontext, input, inputLen)
-+ void *vcontext;
-+ unsigned char *input; /* input block */
-+ __u32 inputLen; /* length of input block */
-+{
-+ MD5_CTX *context = vcontext;
-+ __u32 i;
-+ unsigned int index, partLen;
-+
-+ /* Compute number of bytes mod 64 */
-+ index = (unsigned int)((context->count[0] >> 3) & 0x3F);
-+
-+ /* Update number of bits */
-+ if ((context->count[0] += ((UINT4)inputLen << 3))
-+ < ((UINT4)inputLen << 3))
-+ context->count[1]++;
-+ context->count[1] += ((UINT4)inputLen >> 29);
-+
-+ partLen = 64 - index;
-+
-+ /* Transform as many times as possible.
-+*/
-+ if (inputLen >= partLen) {
-+ MD5_memcpy
-+ ((POINTER)&context->buffer[index], (POINTER)input, partLen);
-+ MD5Transform (context->state, context->buffer);
-+
-+ for (i = partLen; i + 63 < inputLen; i += 64)
-+ MD5Transform (context->state, &input[i]);
-+
-+ index = 0;
-+ }
-+ else
-+ i = 0;
-+
-+ /* Buffer remaining input */
-+ MD5_memcpy
-+ ((POINTER)&context->buffer[index], (POINTER)&input[i],
-+ inputLen-i);
-+}
-+
-+/* MD5 finalization. Ends an MD5 message-digest operation, writing the
-+ the message digest and zeroizing the context.
-+ */
-+void MD5Final (digest, vcontext)
-+unsigned char digest[16]; /* message digest */
-+void *vcontext; /* context */
-+{
-+ MD5_CTX *context = vcontext;
-+ unsigned char bits[8];
-+ unsigned int index, padLen;
-+
-+ /* Save number of bits */
-+ Encode (bits, context->count, 8);
-+
-+ /* Pad out to 56 mod 64.
-+*/
-+ index = (unsigned int)((context->count[0] >> 3) & 0x3f);
-+ padLen = (index < 56) ? (56 - index) : (120 - index);
-+ MD5Update (context, PADDING, padLen);
-+
-+ /* Append length (before padding) */
-+ MD5Update (context, bits, 8);
-+
-+ if (digest != NULL) /* Bill Simpson's padding */
-+ {
-+ /* store state in digest */
-+ Encode (digest, context->state, 16);
-+
-+ /* Zeroize sensitive information.
-+ */
-+ MD5_memset ((POINTER)context, 0, sizeof (*context));
-+ }
-+}
-+
-+/* MD5 basic transformation. Transforms state based on block.
-+ */
-+static void MD5Transform (state, block)
-+UINT4 state[4];
-+unsigned char block[64];
-+{
-+ UINT4 a = state[0], b = state[1], c = state[2], d = state[3], x[16];
-+
-+ Decode (x, block, 64);
-+
-+ /* Round 1 */
-+ FF (a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */
-+ FF (d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */
-+ FF (c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */
-+ FF (b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */
-+ FF (a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */
-+ FF (d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */
-+ FF (c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */
-+ FF (b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */
-+ FF (a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */
-+ FF (d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */
-+ FF (c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */
-+ FF (b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */
-+ FF (a, b, c, d, x[12], S11, 0x6b901122); /* 13 */
-+ FF (d, a, b, c, x[13], S12, 0xfd987193); /* 14 */
-+ FF (c, d, a, b, x[14], S13, 0xa679438e); /* 15 */
-+ FF (b, c, d, a, x[15], S14, 0x49b40821); /* 16 */
-+
-+ /* Round 2 */
-+ GG (a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */
-+ GG (d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */
-+ GG (c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */
-+ GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */
-+ GG (a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */
-+ GG (d, a, b, c, x[10], S22, 0x2441453); /* 22 */
-+ GG (c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */
-+ GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */
-+ GG (a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */
-+ GG (d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */
-+ GG (c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */
-+ GG (b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */
-+ GG (a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */
-+ GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */
-+ GG (c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */
-+ GG (b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */
-+
-+ /* Round 3 */
-+ HH (a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */
-+ HH (d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */
-+ HH (c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */
-+ HH (b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */
-+ HH (a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */
-+ HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */
-+ HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */
-+ HH (b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */
-+ HH (a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */
-+ HH (d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */
-+ HH (c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */
-+ HH (b, c, d, a, x[ 6], S34, 0x4881d05); /* 44 */
-+ HH (a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */
-+ HH (d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */
-+ HH (c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */
-+ HH (b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */
-+
-+ /* Round 4 */
-+ II (a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */
-+ II (d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */
-+ II (c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */
-+ II (b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */
-+ II (a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */
-+ II (d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */
-+ II (c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */
-+ II (b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */
-+ II (a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */
-+ II (d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */
-+ II (c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */
-+ II (b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */
-+ II (a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */
-+ II (d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */
-+ II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */
-+ II (b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */
-+
-+ state[0] += a;
-+ state[1] += b;
-+ state[2] += c;
-+ state[3] += d;
-+
-+ /* Zeroize sensitive information.
-+*/
-+ MD5_memset ((POINTER)x, 0, sizeof (x));
-+}
-+
-+#ifndef LITTLEENDIAN
-+
-+/* Encodes input (UINT4) into output (unsigned char). Assumes len is
-+ a multiple of 4.
-+ */
-+static void Encode (output, input, len)
-+unsigned char *output;
-+UINT4 *input;
-+unsigned int len;
-+{
-+ unsigned int i, j;
-+
-+ for (i = 0, j = 0; j < len; i++, j += 4) {
-+ output[j] = (unsigned char)(input[i] & 0xff);
-+ output[j+1] = (unsigned char)((input[i] >> 8) & 0xff);
-+ output[j+2] = (unsigned char)((input[i] >> 16) & 0xff);
-+ output[j+3] = (unsigned char)((input[i] >> 24) & 0xff);
-+ }
-+}
-+
-+/* Decodes input (unsigned char) into output (UINT4). Assumes len is
-+ a multiple of 4.
-+ */
-+static void Decode (output, input, len)
-+UINT4 *output;
-+unsigned char *input;
-+unsigned int len;
-+{
-+ unsigned int i, j;
-+
-+ for (i = 0, j = 0; j < len; i++, j += 4)
-+ output[i] = ((UINT4)input[j]) | (((UINT4)input[j+1]) << 8) |
-+ (((UINT4)input[j+2]) << 16) | (((UINT4)input[j+3]) << 24);
-+}
-+
-+#endif
-+
-+#ifndef HAVEMEMCOPY
-+#ifndef HAVEBCOPY
-+/* Note: Replace "for loop" with standard memcpy if possible.
-+ */
-+
-+static void MD5_memcpy (output, input, len)
-+POINTER output;
-+POINTER input;
-+unsigned int len;
-+{
-+ unsigned int i;
-+
-+ for (i = 0; i < len; i++)
-+
-+ output[i] = input[i];
-+}
-+
-+/* Note: Replace "for loop" with standard memset if possible.
-+ */
-+
-+static void MD5_memset (output, value, len)
-+POINTER output;
-+int value;
-+unsigned int len;
-+{
-+ unsigned int i;
-+
-+ for (i = 0; i < len; i++)
-+ ((char *)output)[i] = (char)value;
-+}
-+#endif
-+#endif
-+
-+/*
-+ * $Log: ipsec_md5c.c,v $
-+ * Revision 1.8 2004/04/06 02:49:26 mcr
-+ * pullup of algo code from alg-branch.
-+ *
-+ * Revision 1.7 2002/09/10 01:45:14 mcr
-+ * changed type of MD5_CTX and SHA1_CTX to void * so that
-+ * the function prototypes would match, and could be placed
-+ * into a pointer to a function.
-+ *
-+ * Revision 1.6 2002/04/24 07:55:32 mcr
-+ * #include patches and Makefiles for post-reorg compilation.
-+ *
-+ * Revision 1.5 2002/04/24 07:36:28 mcr
-+ * Moved from ./klips/net/ipsec/ipsec_md5c.c,v
-+ *
-+ * Revision 1.4 1999/12/13 13:59:12 rgb
-+ * Quick fix to argument size to Update bugs.
-+ *
-+ * Revision 1.3 1999/05/21 18:09:28 henry
-+ * unnecessary <memory.h> include causes trouble in 2.2
-+ *
-+ * Revision 1.2 1999/04/06 04:54:26 rgb
-+ * Fix/Add RCSID Id: and Log: bits to make PHMDs happy. This includes
-+ * patch shell fixes.
-+ *
-+ * Revision 1.1 1998/06/18 21:27:48 henry
-+ * move sources from klips/src to klips/net/ipsec, to keep stupid
-+ * kernel-build scripts happier in the presence of symlinks
-+ *
-+ * Revision 1.2 1998/04/23 20:54:02 rgb
-+ * Fixed md5 and sha1 include file nesting issues, to be cleaned up when
-+ * verified.
-+ *
-+ * Revision 1.1 1998/04/09 03:06:08 henry
-+ * sources moved up from linux/net/ipsec
-+ *
-+ * Revision 1.1.1.1 1998/04/08 05:35:04 henry
-+ * RGB's ipsec-0.8pre2.tar.gz ipsec-0.8
-+ *
-+ * Revision 0.3 1996/11/20 14:48:53 ji
-+ * Release update only.
-+ *
-+ * Revision 0.2 1996/11/02 00:18:33 ji
-+ * First limited release.
-+ *
-+ *
-+ */
---- /dev/null Tue Mar 11 13:02:56 2003
-+++ linux/net/ipsec/ipsec_proc.c Mon Feb 9 13:51:03 2004
-@@ -0,0 +1,1127 @@
-+/*
-+ * @(#) /proc file system interface code.
-+ *
-+ * Copyright (C) 1996, 1997 John Ioannidis.
-+ * Copyright (C) 1998, 1999, 2000, 2001 Richard Guy Briggs <rgb@freeswan.org>
-+ * 2001 Michael Richardson <mcr@freeswan.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. See <http://www.fsf.org/copyleft/gpl.txt>.
-+ *
-+ * 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.
-+ *
-+ * Split out from ipsec_init.c version 1.70.
-+ */
-+
-+char ipsec_proc_c_version[] = "RCSID $Id: ipsec_proc.c,v 1.30 2004/04/25 21:23:11 ken Exp $";
-+
-+
-+#include <linux/config.h>
-+#include <linux/version.h>
-+#define __NO_VERSION__
-+#include <linux/module.h>
-+#include <linux/kernel.h> /* printk() */
-+
-+#include "openswan/ipsec_param.h"
-+
-+#ifdef MALLOC_SLAB
-+# include <linux/slab.h> /* kmalloc() */
-+#else /* MALLOC_SLAB */
-+# include <linux/malloc.h> /* kmalloc() */
-+#endif /* MALLOC_SLAB */
-+#include <linux/errno.h> /* error codes */
-+#include <linux/types.h> /* size_t */
-+#include <linux/interrupt.h> /* mark_bh */
-+
-+#include <linux/netdevice.h> /* struct device, and other headers */
-+#include <linux/etherdevice.h> /* eth_type_trans */
-+#include <linux/ip.h> /* struct iphdr */
-+#include <linux/in.h> /* struct sockaddr_in */
-+#include <linux/skbuff.h>
-+#include <openswan.h>
-+#ifdef SPINLOCK
-+#ifdef SPINLOCK_23
-+#include <linux/spinlock.h> /* *lock* */
-+#else /* SPINLOCK_23 */
-+#include <asm/spinlock.h> /* *lock* */
-+#endif /* SPINLOCK_23 */
-+#endif /* SPINLOCK */
-+#ifdef NET_21
-+#include <asm/uaccess.h>
-+#include <linux/in6.h>
-+#endif /* NET_21 */
-+#include <asm/checksum.h>
-+#include <net/ip.h>
-+#ifdef CONFIG_PROC_FS
-+#include <linux/proc_fs.h>
-+#endif /* CONFIG_PROC_FS */
-+#ifdef NETLINK_SOCK
-+#include <linux/netlink.h>
-+#else
-+#include <net/netlink.h>
-+#endif
-+
-+#include "openswan/radij.h"
-+
-+#include "openswan/ipsec_life.h"
-+#include "openswan/ipsec_stats.h"
-+#include "openswan/ipsec_sa.h"
-+
-+#include "openswan/ipsec_encap.h"
-+#include "openswan/ipsec_radij.h"
-+#include "openswan/ipsec_xform.h"
-+#include "openswan/ipsec_tunnel.h"
-+#include "openswan/ipsec_xmit.h"
-+
-+#include "openswan/ipsec_rcv.h"
-+#include "openswan/ipsec_ah.h"
-+#include "openswan/ipsec_esp.h"
-+
-+#ifdef CONFIG_IPSEC_IPCOMP
-+#include "openswan/ipcomp.h"
-+#endif /* CONFIG_IPSEC_IPCOMP */
-+
-+#include "openswan/ipsec_proto.h"
-+
-+#include <pfkeyv2.h>
-+#include <pfkey.h>
-+
-+#ifdef CONFIG_PROC_FS
-+
-+#ifdef IPSEC_PROC_SUBDIRS
-+static struct proc_dir_entry *proc_net_ipsec_dir = NULL;
-+static struct proc_dir_entry *proc_eroute_dir = NULL;
-+static struct proc_dir_entry *proc_spi_dir = NULL;
-+static struct proc_dir_entry *proc_spigrp_dir = NULL;
-+static struct proc_dir_entry *proc_birth_dir = NULL;
-+static struct proc_dir_entry *proc_stats_dir = NULL;
-+#endif
-+
-+struct ipsec_birth_reply ipsec_ipv4_birth_packet;
-+struct ipsec_birth_reply ipsec_ipv6_birth_packet;
-+
-+#define DECREMENT_UNSIGNED(X, amount) ((amount < (X)) ? (X)-amount : 0)
-+
-+extern int ipsec_xform_get_info(char *buffer, char **start,
-+ off_t offset, int length IPSEC_PROC_LAST_ARG);
-+
-+
-+/* ipsec_snprintf: like snprintf except
-+ * - size is signed and a negative value is treated as if it were 0
-+ * - the returned result is never negative --
-+ * an error generates a "?" or null output (depending on space).
-+ * (Our callers are too lazy to check for an error return.)
-+ *
-+ * @param buf String buffer
-+ * @param size Size of the string
-+ * @param fmt printf string
-+ * @param ... Variables to be displayed in fmt
-+ * @return int Return code
-+ */
-+int ipsec_snprintf(char *buf, ssize_t size, const char *fmt, ...)
-+{
-+ va_list args;
-+ int i;
-+ size_t possize = size < 0? 0 : size;
-+ va_start(args, fmt);
-+ i = vsnprintf(buf,possize,fmt,args);
-+ va_end(args);
-+ if (i < 0) {
-+ /* create empty output in place of error */
-+ i = 0;
-+ if (size > 0) {
-+ *buf = '\0';
-+ }
-+ }
-+ return i;
-+}
-+
-+
-+IPSEC_PROCFS_DEBUG_NO_STATIC
-+int
-+ipsec_eroute_get_info(char *buffer,
-+ char **start,
-+ off_t offset,
-+ int length IPSEC_PROC_LAST_ARG)
-+{
-+ struct wsbuf w = {buffer, length, offset, 0, 0};
-+
-+#ifdef CONFIG_IPSEC_DEBUG
-+ if (debug_radij & DB_RJ_DUMPTREES)
-+ rj_dumptrees(); /* XXXXXXXXX */
-+#endif /* CONFIG_IPSEC_DEBUG */
-+
-+ KLIPS_PRINT(debug_tunnel & DB_TN_PROCFS,
-+ "klips_debug:ipsec_eroute_get_info: "
-+ "buffer=0p%p, *start=0p%p, offset=%d, length=%d\n",
-+ buffer,
-+ *start,
-+ (int)offset,
-+ length);
-+
-+ spin_lock_bh(&eroute_lock);
-+
-+ rj_walktree(rnh, ipsec_rj_walker_procprint, &w);
-+/* rj_walktree(mask_rjhead, ipsec_rj_walker_procprint, &w); */
-+
-+ spin_unlock_bh(&eroute_lock);
-+
-+ *start = buffer + (offset - w.begin); /* Start of wanted data */
-+ return w.len - (offset - w.begin);
-+}
-+
-+IPSEC_PROCFS_DEBUG_NO_STATIC
-+int
-+ipsec_spi_get_info(char *buffer,
-+ char **start,
-+ off_t offset,
-+ int length IPSEC_PROC_LAST_ARG)
-+{
-+ const int max_content = length > 0? length-1 : 0;
-+ int len = 0;
-+ off_t begin = 0;
-+ int i;
-+ struct ipsec_sa *sa_p;
-+ char sa[SATOT_BUF];
-+ char buf_s[SUBNETTOA_BUF];
-+ char buf_d[SUBNETTOA_BUF];
-+ size_t sa_len;
-+
-+ KLIPS_PRINT(debug_tunnel & DB_TN_PROCFS,
-+ "klips_debug:ipsec_spi_get_info: "
-+ "buffer=0p%p, *start=0p%p, offset=%d, length=%d\n",
-+ buffer,
-+ *start,
-+ (int)offset,
-+ length);
-+
-+ spin_lock_bh(&tdb_lock);
-+
-+ for (i = 0; i < SADB_HASHMOD; i++) {
-+ for (sa_p = ipsec_sadb_hash[i];
-+ sa_p;
-+ sa_p = sa_p->ips_hnext) {
-+ atomic_inc(&sa_p->ips_refcount);
-+ sa_len = satot(&sa_p->ips_said, 'x', sa, sizeof(sa));
-+ len += ipsec_snprintf(buffer+len, length-len, "%s ",
-+ sa_len ? sa : " (error)");
-+
-+ len += ipsec_snprintf(buffer+len, length-len, "%s%s%s",
-+ IPS_XFORM_NAME(sa_p));
-+
-+ len += ipsec_snprintf(buffer+len, length-len, ": dir=%s",
-+ (sa_p->ips_flags & EMT_INBOUND) ?
-+ "in " : "out");
-+
-+ if(sa_p->ips_addr_s) {
-+ addrtoa(((struct sockaddr_in*)(sa_p->ips_addr_s))->sin_addr,
-+ 0, buf_s, sizeof(buf_s));
-+ len += ipsec_snprintf(buffer+len, length-len, " src=%s",
-+ buf_s);
-+ }
-+
-+ if((sa_p->ips_said.proto == IPPROTO_IPIP)
-+ && (sa_p->ips_flags & SADB_X_SAFLAGS_INFLOW)) {
-+ subnettoa(sa_p->ips_flow_s.u.v4.sin_addr,
-+ sa_p->ips_mask_s.u.v4.sin_addr,
-+ 0,
-+ buf_s,
-+ sizeof(buf_s));
-+
-+ subnettoa(sa_p->ips_flow_d.u.v4.sin_addr,
-+ sa_p->ips_mask_d.u.v4.sin_addr,
-+ 0,
-+ buf_d,
-+ sizeof(buf_d));
-+
-+ len += ipsec_snprintf(buffer+len, length-len, " policy=%s->%s",
-+ buf_s, buf_d);
-+ }
-+
-+ if(sa_p->ips_iv_bits) {
-+ int j;
-+ len += ipsec_snprintf(buffer+len, length-len, " iv_bits=%dbits iv=0x",
-+ sa_p->ips_iv_bits);
-+
-+ for(j = 0; j < sa_p->ips_iv_bits / 8; j++) {
-+ len += ipsec_snprintf(buffer+len, length-len, "%02x",
-+ (__u32)((__u8*)(sa_p->ips_iv))[j]);
-+ }
-+ }
-+
-+ if(sa_p->ips_encalg || sa_p->ips_authalg) {
-+ if(sa_p->ips_replaywin) {
-+ len += ipsec_snprintf(buffer+len, length-len, " ooowin=%d",
-+ sa_p->ips_replaywin);
-+ }
-+ if(sa_p->ips_errs.ips_replaywin_errs) {
-+ len += ipsec_snprintf(buffer+len, length-len, " ooo_errs=%d",
-+ sa_p->ips_errs.ips_replaywin_errs);
-+ }
-+ if(sa_p->ips_replaywin_lastseq) {
-+ len += ipsec_snprintf(buffer+len, length-len, " seq=%d",
-+ sa_p->ips_replaywin_lastseq);
-+ }
-+ if(sa_p->ips_replaywin_bitmap) {
-+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0)
-+ len += ipsec_snprintf(buffer+len, length-len, " bit=0x%Lx",
-+ sa_p->ips_replaywin_bitmap);
-+#else
-+ len += ipsec_snprintf(buffer+len, length-len, " bit=0x%x%08x",
-+ (__u32)(sa_p->ips_replaywin_bitmap >> 32),
-+ (__u32)sa_p->ips_replaywin_bitmap);
-+#endif
-+ }
-+ if(sa_p->ips_replaywin_maxdiff) {
-+ len += ipsec_snprintf(buffer+len, length-len, " max_seq_diff=%d",
-+ sa_p->ips_replaywin_maxdiff);
-+ }
-+ }
-+ if(sa_p->ips_flags & ~EMT_INBOUND) {
-+ len += ipsec_snprintf(buffer+len, length-len, " flags=0x%x",
-+ sa_p->ips_flags & ~EMT_INBOUND);
-+ len += ipsec_snprintf(buffer+len, length-len, "<");
-+ /* flag printing goes here */
-+ len += ipsec_snprintf(buffer+len, length-len, ">");
-+ }
-+ if(sa_p->ips_auth_bits) {
-+ len += ipsec_snprintf(buffer+len, length-len, " alen=%d",
-+ sa_p->ips_auth_bits);
-+ }
-+ if(sa_p->ips_key_bits_a) {
-+ len += ipsec_snprintf(buffer+len, length-len, " aklen=%d",
-+ sa_p->ips_key_bits_a);
-+ }
-+ if(sa_p->ips_errs.ips_auth_errs) {
-+ len += ipsec_snprintf(buffer+len, length-len, " auth_errs=%d",
-+ sa_p->ips_errs.ips_auth_errs);
-+ }
-+ if(sa_p->ips_key_bits_e) {
-+ len += ipsec_snprintf(buffer+len, length-len, " eklen=%d",
-+ sa_p->ips_key_bits_e);
-+ }
-+ if(sa_p->ips_errs.ips_encsize_errs) {
-+ len += ipsec_snprintf(buffer+len, length-len, " encr_size_errs=%d",
-+ sa_p->ips_errs.ips_encsize_errs);
-+ }
-+ if(sa_p->ips_errs.ips_encpad_errs) {
-+ len += ipsec_snprintf(buffer+len, length-len, " encr_pad_errs=%d",
-+ sa_p->ips_errs.ips_encpad_errs);
-+ }
-+
-+ len += ipsec_snprintf(buffer+len, length-len, " life(c,s,h)=");
-+
-+ len += ipsec_lifetime_format(buffer + len,
-+ length - len,
-+ "alloc",
-+ ipsec_life_countbased,
-+ &sa_p->ips_life.ipl_allocations);
-+
-+ len += ipsec_lifetime_format(buffer + len,
-+ length - len,
-+ "bytes",
-+ ipsec_life_countbased,
-+ &sa_p->ips_life.ipl_bytes);
-+
-+ len += ipsec_lifetime_format(buffer + len,
-+ length - len,
-+ "addtime",
-+ ipsec_life_timebased,
-+ &sa_p->ips_life.ipl_addtime);
-+
-+ len += ipsec_lifetime_format(buffer + len,
-+ length - len,
-+ "usetime",
-+ ipsec_life_timebased,
-+ &sa_p->ips_life.ipl_usetime);
-+
-+ len += ipsec_lifetime_format(buffer + len,
-+ length - len,
-+ "packets",
-+ ipsec_life_countbased,
-+ &sa_p->ips_life.ipl_packets);
-+
-+ if(sa_p->ips_life.ipl_usetime.ipl_last) { /* XXX-MCR should be last? */
-+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0)
-+ len += ipsec_snprintf(buffer+len, length-len, " idle=%Ld",
-+ jiffies / HZ - sa_p->ips_life.ipl_usetime.ipl_last);
-+#else
-+ len += ipsec_snprintf(buffer+len, length-len, " idle=%lu",
-+ jiffies / HZ - (unsigned long)sa_p->ips_life.ipl_usetime.ipl_last);
-+#endif
-+ }
-+
-+#ifdef CONFIG_IPSEC_IPCOMP
-+ if(sa_p->ips_said.proto == IPPROTO_COMP &&
-+ (sa_p->ips_comp_ratio_dbytes ||
-+ sa_p->ips_comp_ratio_cbytes)) {
-+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0)
-+ len += ipsec_snprintf(buffer+len, length-len, " ratio=%Ld:%Ld",
-+ sa_p->ips_comp_ratio_dbytes,
-+ sa_p->ips_comp_ratio_cbytes);
-+#else
-+ len += ipsec_snprintf(buffer+len, length-len, " ratio=%lu:%lu",
-+ (unsigned long)sa_p->ips_comp_ratio_dbytes,
-+ (unsigned long)sa_p->ips_comp_ratio_cbytes);
-+#endif
-+ }
-+#endif /* CONFIG_IPSEC_IPCOMP */
-+
-+#ifdef CONFIG_IPSEC_NAT_TRAVERSAL
-+ if(sa_p->ips_natt_type != 0) {
-+ char *natttype_name;
-+
-+ switch(sa_p->ips_natt_type)
-+ {
-+ case ESPINUDP_WITH_NON_IKE:
-+ natttype_name="nonike";
-+ break;
-+ case ESPINUDP_WITH_NON_ESP:
-+ natttype_name="nonesp";
-+ break;
-+ default:
-+ natttype_name = "unknown";
-+ break;
-+ }
-+
-+ len += ipsec_snprintf(buffer + len, length-len, " natencap=%s",
-+ natttype_name);
-+
-+ len += ipsec_snprintf(buffer + len, length-len, " natsport=%d",
-+ sa_p->ips_natt_sport);
-+
-+ len += ipsec_snprintf(buffer + len,length-len, " natdport=%d",
-+ sa_p->ips_natt_dport);
-+ }
-+#endif /* CONFIG_IPSEC_NAT_TRAVERSAL */
-+
-+ len += ipsec_snprintf(buffer + len,length-len, " refcount=%d",
-+ atomic_read(&sa_p->ips_refcount));
-+
-+ len += ipsec_snprintf(buffer+len, length-len, " ref=%d",
-+ sa_p->ips_ref);
-+#ifdef CONFIG_IPSEC_DEBUG
-+ if(debug_xform) {
-+ len += ipsec_snprintf(buffer+len, length-len, " reftable=%lu refentry=%lu",
-+ (unsigned long)IPsecSAref2table(sa_p->ips_ref),
-+ (unsigned long)IPsecSAref2entry(sa_p->ips_ref));
-+ }
-+#endif /* CONFIG_IPSEC_DEBUG */
-+
-+ len += ipsec_snprintf(buffer+len, length-len, "\n");
-+
-+ atomic_dec(&sa_p->ips_refcount);
-+
-+ if (len >= max_content) {
-+ /* we've done all that can fit -- stop loops */
-+ len = max_content; /* truncate crap */
-+ goto done_spi_i;
-+ } else {
-+ const off_t pos = begin + len; /* file position of end of what we've generated */
-+
-+ if (pos <= offset) {
-+ /* all is before first interesting character:
-+ * discard, but note where we are.
-+ */
-+ len = 0;
-+ begin = pos;
-+ }
-+ }
-+ }
-+ }
-+
-+done_spi_i:
-+ spin_unlock_bh(&tdb_lock);
-+
-+ *start = buffer + (offset - begin); /* Start of wanted data */
-+ return len - (offset - begin);
-+}
-+
-+IPSEC_PROCFS_DEBUG_NO_STATIC
-+int
-+ipsec_spigrp_get_info(char *buffer,
-+ char **start,
-+ off_t offset,
-+ int length IPSEC_PROC_LAST_ARG)
-+{
-+ /* Limit of useful snprintf output */
-+ const int max_content = length > 0? length-1 : 0;
-+
-+ int len = 0;
-+ off_t begin = 0;
-+ int i;
-+ struct ipsec_sa *sa_p, *sa_p2;
-+ char sa[SATOT_BUF];
-+ size_t sa_len;
-+
-+ KLIPS_PRINT(debug_tunnel & DB_TN_PROCFS,
-+ "klips_debug:ipsec_spigrp_get_info: "
-+ "buffer=0p%p, *start=0p%p, offset=%d, length=%d\n",
-+ buffer,
-+ *start,
-+ (int)offset,
-+ length);
-+
-+ spin_lock_bh(&tdb_lock);
-+
-+ for (i = 0; i < SADB_HASHMOD; i++) {
-+ for (sa_p = ipsec_sadb_hash[i];
-+ sa_p != NULL;
-+ sa_p = sa_p->ips_hnext)
-+ {
-+ atomic_inc(&sa_p->ips_refcount);
-+ if(sa_p->ips_inext == NULL) {
-+ sa_p2 = sa_p;
-+ while(sa_p2 != NULL) {
-+ atomic_inc(&sa_p2->ips_refcount);
-+ sa_len = satot(&sa_p2->ips_said,
-+ 'x', sa, sizeof(sa));
-+
-+ len += ipsec_snprintf(buffer+len, length-len, "%s ",
-+ sa_len ? sa : " (error)");
-+ atomic_dec(&sa_p2->ips_refcount);
-+ sa_p2 = sa_p2->ips_onext;
-+ }
-+ len += ipsec_snprintf(buffer+len, length-len, "\n");
-+ }
-+
-+ atomic_dec(&sa_p->ips_refcount);
-+
-+ if (len >= max_content) {
-+ /* we've done all that can fit -- stop loops */
-+ len = max_content; /* truncate crap */
-+ goto done_spigrp_i;
-+ } else {
-+ const off_t pos = begin + len;
-+
-+ if (pos <= offset) {
-+ /* all is before first interesting character:
-+ * discard, but note where we are.
-+ */
-+ len = 0;
-+ begin = pos;
-+ }
-+ }
-+ }
-+ }
-+
-+done_spigrp_i:
-+ spin_unlock_bh(&tdb_lock);
-+
-+ *start = buffer + (offset - begin); /* Start of wanted data */
-+ return len - (offset - begin);
-+}
-+
-+
-+IPSEC_PROCFS_DEBUG_NO_STATIC
-+int
-+ipsec_tncfg_get_info(char *buffer,
-+ char **start,
-+ off_t offset,
-+ int length IPSEC_PROC_LAST_ARG)
-+{
-+ /* limit of useful snprintf output */
-+ const int max_content = length > 0? length-1 : 0;
-+ int len = 0;
-+ off_t begin = 0;
-+ int i;
-+ char name[9];
-+ struct device *dev, *privdev;
-+ struct ipsecpriv *priv;
-+
-+ KLIPS_PRINT(debug_tunnel & DB_TN_PROCFS,
-+ "klips_debug:ipsec_tncfg_get_info: "
-+ "buffer=0p%p, *start=0p%p, offset=%d, length=%d\n",
-+ buffer,
-+ *start,
-+ (int)offset,
-+ length);
-+
-+ for(i = 0; i < IPSEC_NUM_IF; i++) {
-+ ipsec_snprintf(name, (ssize_t) sizeof(name), IPSEC_DEV_FORMAT, i);
-+ dev = __ipsec_dev_get(name);
-+ if(dev) {
-+ priv = (struct ipsecpriv *)(dev->priv);
-+ len += ipsec_snprintf(buffer+len, length-len, "%s",
-+ dev->name);
-+ if(priv) {
-+ privdev = (struct device *)(priv->dev);
-+ len += ipsec_snprintf(buffer+len, length-len, " -> %s",
-+ privdev ? privdev->name : "NULL");
-+ len += ipsec_snprintf(buffer+len, length-len, " mtu=%d(%d) -> %d",
-+ dev->mtu,
-+ priv->mtu,
-+ privdev ? privdev->mtu : 0);
-+ } else {
-+ KLIPS_PRINT(debug_tunnel & DB_TN_PROCFS,
-+ "klips_debug:ipsec_tncfg_get_info: device '%s' has no private data space!\n",
-+ dev->name);
-+ }
-+ len += ipsec_snprintf(buffer+len, length-len, "\n");
-+
-+ if (len >= max_content) {
-+ /* we've done all that can fit -- stop loop */
-+ len = max_content; /* truncate crap */
-+ break;
-+ } else {
-+ const off_t pos = begin + len;
-+ if (pos <= offset) {
-+ len = 0;
-+ begin = pos;
-+ }
-+ }
-+ }
-+ }
-+ *start = buffer + (offset - begin); /* Start of wanted data */
-+ len -= (offset - begin); /* Start slop */
-+ if (len > length)
-+ len = length;
-+ return len;
-+}
-+
-+IPSEC_PROCFS_DEBUG_NO_STATIC
-+int
-+ipsec_version_get_info(char *buffer,
-+ char **start,
-+ off_t offset,
-+ int length IPSEC_PROC_LAST_ARG)
-+{
-+ int len = 0;
-+ off_t begin = 0;
-+
-+ KLIPS_PRINT(debug_tunnel & DB_TN_PROCFS,
-+ "klips_debug:ipsec_version_get_info: "
-+ "buffer=0p%p, *start=0p%p, offset=%d, length=%d\n",
-+ buffer,
-+ *start,
-+ (int)offset,
-+ length);
-+
-+ len += ipsec_snprintf(buffer + len,length-len, "Openswan version: %s\n",
-+ ipsec_version_code());
-+#if 0
-+ KLIPS_PRINT(debug_tunnel & DB_TN_PROCFS,
-+ "klips_debug:ipsec_version_get_info: "
-+ "ipsec_init version: %s\n",
-+ ipsec_init_c_version);
-+ KLIPS_PRINT(debug_tunnel & DB_TN_PROCFS,
-+ "klips_debug:ipsec_version_get_info: "
-+ "ipsec_tunnel version: %s\n",
-+ ipsec_tunnel_c_version);
-+ KLIPS_PRINT(debug_tunnel & DB_TN_PROCFS,
-+ "klips_debug:ipsec_version_get_info: "
-+ "ipsec_netlink version: %s\n",
-+ ipsec_netlink_c_version);
-+ KLIPS_PRINT(debug_tunnel & DB_TN_PROCFS,
-+ "klips_debug:ipsec_version_get_info: "
-+ "radij_c_version: %s\n",
-+ radij_c_version);
-+#endif
-+
-+
-+ *start = buffer + (offset - begin); /* Start of wanted data */
-+ len -= (offset - begin); /* Start slop */
-+ if (len > length)
-+ len = length;
-+ return len;
-+}
-+
-+IPSEC_PROCFS_DEBUG_NO_STATIC
-+int
-+ipsec_birth_info(char *page,
-+ char **start,
-+ off_t offset,
-+ int count,
-+ int *eof,
-+ void *data)
-+{
-+ struct ipsec_birth_reply *ibr = (struct ipsec_birth_reply *)data;
-+ int len;
-+
-+ if(offset >= ibr->packet_template_len) {
-+ if(eof) {
-+ *eof=1;
-+ }
-+ return 0;
-+ }
-+
-+ len = ibr->packet_template_len;
-+ len -= offset;
-+ if (len > count)
-+ len = count;
-+
-+ memcpy(page + offset, ibr->packet_template+offset, len);
-+
-+ return len;
-+}
-+
-+IPSEC_PROCFS_DEBUG_NO_STATIC
-+int
-+ipsec_birth_set(struct file *file, const char *buffer,
-+ unsigned long count, void *data)
-+{
-+ struct ipsec_birth_reply *ibr = (struct ipsec_birth_reply *)data;
-+ int len;
-+
-+ MOD_INC_USE_COUNT;
-+ if(count > IPSEC_BIRTH_TEMPLATE_MAXLEN) {
-+ len = IPSEC_BIRTH_TEMPLATE_MAXLEN;
-+ } else {
-+ len = count;
-+ }
-+
-+ if(copy_from_user(ibr->packet_template, buffer, len)) {
-+ MOD_DEC_USE_COUNT;
-+ return -EFAULT;
-+ }
-+ ibr->packet_template_len = len;
-+
-+ MOD_DEC_USE_COUNT;
-+
-+ return len;
-+}
-+
-+
-+#ifdef CONFIG_IPSEC_DEBUG
-+IPSEC_PROCFS_DEBUG_NO_STATIC
-+int
-+ipsec_klipsdebug_get_info(char *buffer,
-+ char **start,
-+ off_t offset,
-+ int length IPSEC_PROC_LAST_ARG)
-+{
-+ int len = 0;
-+ off_t begin = 0;
-+
-+ KLIPS_PRINT(debug_tunnel & DB_TN_PROCFS,
-+ "klips_debug:ipsec_klipsdebug_get_info: "
-+ "buffer=0p%p, *start=0p%p, offset=%d, length=%d\n",
-+ buffer,
-+ *start,
-+ (int)offset,
-+ length);
-+
-+ len += ipsec_snprintf(buffer+len, length-len, "debug_tunnel=%08x.\n", debug_tunnel);
-+ len += ipsec_snprintf(buffer+len, length-len, "debug_xform=%08x.\n", debug_xform);
-+ len += ipsec_snprintf(buffer+len, length-len, "debug_eroute=%08x.\n", debug_eroute);
-+ len += ipsec_snprintf(buffer+len, length-len, "debug_spi=%08x.\n", debug_spi);
-+ len += ipsec_snprintf(buffer+len, length-len, "debug_radij=%08x.\n", debug_radij);
-+ len += ipsec_snprintf(buffer+len, length-len, "debug_esp=%08x.\n", debug_esp);
-+ len += ipsec_snprintf(buffer+len, length-len, "debug_ah=%08x.\n", debug_ah);
-+ len += ipsec_snprintf(buffer+len, length-len, "debug_rcv=%08x.\n", debug_rcv);
-+ len += ipsec_snprintf(buffer+len, length-len, "debug_pfkey=%08x.\n", debug_pfkey);
-+
-+ *start = buffer + (offset - begin); /* Start of wanted data */
-+ len -= (offset - begin); /* Start slop */
-+ if (len > length)
-+ len = length;
-+ return len;
-+}
-+#endif /* CONFIG_IPSEC_DEBUG */
-+
-+IPSEC_PROCFS_DEBUG_NO_STATIC
-+int
-+ipsec_stats_get_int_info(char *buffer,
-+ char **start,
-+ off_t offset,
-+ int length,
-+ int *eof,
-+ void *data)
-+{
-+
-+ const int max_content = length > 0? length-1 : 0;
-+ int len = 0;
-+ int *thing;
-+
-+ thing = (int *)data;
-+
-+ len = ipsec_snprintf(buffer+len, length-len, "%08x\n", *thing);
-+
-+ if (len >= max_content)
-+ len = max_content; /* truncate crap */
-+
-+ *start = buffer + offset; /* Start of wanted data */
-+ return len > offset? len - offset : 0;
-+
-+}
-+
-+#ifndef PROC_FS_2325
-+struct proc_dir_entry ipsec_eroute =
-+{
-+ 0,
-+ 12, "ipsec_eroute",
-+ S_IFREG | S_IRUGO, 1, 0, 0, 0,
-+ &proc_net_inode_operations,
-+ ipsec_eroute_get_info,
-+ NULL, NULL, NULL, NULL, NULL
-+};
-+
-+struct proc_dir_entry ipsec_spi =
-+{
-+ 0,
-+ 9, "ipsec_spi",
-+ S_IFREG | S_IRUGO, 1, 0, 0, 0,
-+ &proc_net_inode_operations,
-+ ipsec_spi_get_info,
-+ NULL, NULL, NULL, NULL, NULL
-+};
-+
-+struct proc_dir_entry ipsec_spigrp =
-+{
-+ 0,
-+ 12, "ipsec_spigrp",
-+ S_IFREG | S_IRUGO, 1, 0, 0, 0,
-+ &proc_net_inode_operations,
-+ ipsec_spigrp_get_info,
-+ NULL, NULL, NULL, NULL, NULL
-+};
-+
-+struct proc_dir_entry ipsec_tncfg =
-+{
-+ 0,
-+ 11, "ipsec_tncfg",
-+ S_IFREG | S_IRUGO, 1, 0, 0, 0,
-+ &proc_net_inode_operations,
-+ ipsec_tncfg_get_info,
-+ NULL, NULL, NULL, NULL, NULL
-+};
-+
-+struct proc_dir_entry ipsec_version =
-+{
-+ 0,
-+ 13, "ipsec_version",
-+ S_IFREG | S_IRUGO, 1, 0, 0, 0,
-+ &proc_net_inode_operations,
-+ ipsec_version_get_info,
-+ NULL, NULL, NULL, NULL, NULL
-+};
-+
-+#ifdef CONFIG_IPSEC_DEBUG
-+struct proc_dir_entry ipsec_klipsdebug =
-+{
-+ 0,
-+ 16, "ipsec_klipsdebug",
-+ S_IFREG | S_IRUGO, 1, 0, 0, 0,
-+ &proc_net_inode_operations,
-+ ipsec_klipsdebug_get_info,
-+ NULL, NULL, NULL, NULL, NULL
-+};
-+#endif /* CONFIG_IPSEC_DEBUG */
-+#endif /* !PROC_FS_2325 */
-+#endif /* CONFIG_PROC_FS */
-+
-+#if defined(PROC_FS_2325)
-+struct ipsec_proc_list {
-+ char *name;
-+ struct proc_dir_entry **parent;
-+ struct proc_dir_entry **dir;
-+ read_proc_t *readthing;
-+ write_proc_t *writething;
-+ void *data;
-+};
-+static struct ipsec_proc_list proc_items[]={
-+#ifdef CONFIG_IPSEC_DEBUG
-+ {"klipsdebug", &proc_net_ipsec_dir, NULL, ipsec_klipsdebug_get_info, NULL, NULL},
-+#endif
-+ {"eroute", &proc_net_ipsec_dir, &proc_eroute_dir, NULL, NULL, NULL},
-+ {"all", &proc_eroute_dir, NULL, ipsec_eroute_get_info, NULL, NULL},
-+ {"spi", &proc_net_ipsec_dir, &proc_spi_dir, NULL, NULL, NULL},
-+ {"all", &proc_spi_dir, NULL, ipsec_spi_get_info, NULL, NULL},
-+ {"spigrp", &proc_net_ipsec_dir, &proc_spigrp_dir, NULL, NULL, NULL},
-+ {"all", &proc_spigrp_dir, NULL, ipsec_spigrp_get_info, NULL, NULL},
-+ {"birth", &proc_net_ipsec_dir, &proc_birth_dir, NULL, NULL, NULL},
-+ {"ipv4", &proc_birth_dir, NULL, ipsec_birth_info, ipsec_birth_set, (void *)&ipsec_ipv4_birth_packet},
-+ {"ipv6", &proc_birth_dir, NULL, ipsec_birth_info, ipsec_birth_set, (void *)&ipsec_ipv6_birth_packet},
-+ {"tncfg", &proc_net_ipsec_dir, NULL, ipsec_tncfg_get_info, NULL, NULL},
-+ {"xforms", &proc_net_ipsec_dir, NULL, ipsec_xform_get_info, NULL, NULL},
-+ {"stats", &proc_net_ipsec_dir, &proc_stats_dir, NULL, NULL, NULL},
-+ {"trap_count", &proc_stats_dir, NULL, ipsec_stats_get_int_info, NULL, &ipsec_xmit_trap_count},
-+ {"trap_sendcount", &proc_stats_dir, NULL, ipsec_stats_get_int_info, NULL, &ipsec_xmit_trap_sendcount},
-+ {"version", &proc_net_ipsec_dir, NULL, ipsec_version_get_info, NULL, NULL},
-+ {NULL, NULL, NULL, NULL, NULL, NULL}
-+};
-+#endif
-+
-+int
-+ipsec_proc_init()
-+{
-+ int error = 0;
-+#ifdef IPSEC_PROC_SUBDIRS
-+ struct proc_dir_entry *item;
-+#endif
-+
-+ /*
-+ * just complain because pluto won't run without /proc!
-+ */
-+#ifndef CONFIG_PROC_FS
-+#error You must have PROC_FS built in to use KLIPS
-+#endif
-+
-+ /* for 2.0 kernels */
-+#if !defined(PROC_FS_2325) && !defined(PROC_FS_21)
-+ error |= proc_register_dynamic(&proc_net, &ipsec_eroute);
-+ error |= proc_register_dynamic(&proc_net, &ipsec_spi);
-+ error |= proc_register_dynamic(&proc_net, &ipsec_spigrp);
-+ error |= proc_register_dynamic(&proc_net, &ipsec_tncfg);
-+ error |= proc_register_dynamic(&proc_net, &ipsec_version);
-+#ifdef CONFIG_IPSEC_DEBUG
-+ error |= proc_register_dynamic(&proc_net, &ipsec_klipsdebug);
-+#endif /* CONFIG_IPSEC_DEBUG */
-+#endif
-+
-+ /* for 2.2 kernels */
-+#if !defined(PROC_FS_2325) && defined(PROC_FS_21)
-+ error |= proc_register(proc_net, &ipsec_eroute);
-+ error |= proc_register(proc_net, &ipsec_spi);
-+ error |= proc_register(proc_net, &ipsec_spigrp);
-+ error |= proc_register(proc_net, &ipsec_tncfg);
-+ error |= proc_register(proc_net, &ipsec_version);
-+#ifdef CONFIG_IPSEC_DEBUG
-+ error |= proc_register(proc_net, &ipsec_klipsdebug);
-+#endif /* CONFIG_IPSEC_DEBUG */
-+#endif
-+
-+ /* for 2.4 kernels */
-+#if defined(PROC_FS_2325)
-+ /* create /proc/net/ipsec */
-+
-+ /* zero these out before we initialize /proc/net/ipsec/birth/stuff */
-+ memset(&ipsec_ipv4_birth_packet, 0, sizeof(struct ipsec_birth_reply));
-+ memset(&ipsec_ipv6_birth_packet, 0, sizeof(struct ipsec_birth_reply));
-+
-+ proc_net_ipsec_dir = proc_mkdir("ipsec", proc_net);
-+ if(proc_net_ipsec_dir == NULL) {
-+ /* no point in continuing */
-+ return 1;
-+ }
-+
-+ {
-+ struct ipsec_proc_list *it;
-+
-+ it=proc_items;
-+ while(it->name!=NULL) {
-+ if(it->dir) {
-+ /* make a dir instead */
-+ item = proc_mkdir(it->name, *it->parent);
-+ *it->dir = item;
-+ } else {
-+ item = create_proc_entry(it->name, 0400, *it->parent);
-+ }
-+ if(item) {
-+ item->read_proc = it->readthing;
-+ item->write_proc = it->writething;
-+ item->data = it->data;
-+#ifdef MODULE
-+ item->owner = THIS_MODULE;
-+#endif
-+ } else {
-+ error |= 1;
-+ }
-+ it++;
-+ }
-+ }
-+
-+ /* now create some symlinks to provide compatibility */
-+ proc_symlink("ipsec_eroute", proc_net, "ipsec/eroute/all");
-+ proc_symlink("ipsec_spi", proc_net, "ipsec/spi/all");
-+ proc_symlink("ipsec_spigrp", proc_net, "ipsec/spigrp/all");
-+ proc_symlink("ipsec_tncfg", proc_net, "ipsec/tncfg");
-+ proc_symlink("ipsec_version",proc_net, "ipsec/version");
-+ proc_symlink("ipsec_klipsdebug",proc_net,"ipsec/klipsdebug");
-+
-+#endif /* !PROC_FS_2325 */
-+
-+ return error;
-+}
-+
-+void
-+ipsec_proc_cleanup()
-+{
-+
-+ /* for 2.0 and 2.2 kernels */
-+#if !defined(PROC_FS_2325)
-+
-+#ifdef CONFIG_IPSEC_DEBUG
-+ if (proc_net_unregister(ipsec_klipsdebug.low_ino) != 0)
-+ printk("klips_debug:ipsec_cleanup: "
-+ "cannot unregister /proc/net/ipsec_klipsdebug\n");
-+#endif /* CONFIG_IPSEC_DEBUG */
-+
-+ if (proc_net_unregister(ipsec_version.low_ino) != 0)
-+ printk("klips_debug:ipsec_cleanup: "
-+ "cannot unregister /proc/net/ipsec_version\n");
-+ if (proc_net_unregister(ipsec_eroute.low_ino) != 0)
-+ printk("klips_debug:ipsec_cleanup: "
-+ "cannot unregister /proc/net/ipsec_eroute\n");
-+ if (proc_net_unregister(ipsec_spi.low_ino) != 0)
-+ printk("klips_debug:ipsec_cleanup: "
-+ "cannot unregister /proc/net/ipsec_spi\n");
-+ if (proc_net_unregister(ipsec_spigrp.low_ino) != 0)
-+ printk("klips_debug:ipsec_cleanup: "
-+ "cannot unregister /proc/net/ipsec_spigrp\n");
-+ if (proc_net_unregister(ipsec_tncfg.low_ino) != 0)
-+ printk("klips_debug:ipsec_cleanup: "
-+ "cannot unregister /proc/net/ipsec_tncfg\n");
-+#endif
-+
-+ /* for 2.4 kernels */
-+#if defined(PROC_FS_2325)
-+ {
-+ struct ipsec_proc_list *it;
-+
-+ /* find end of list */
-+ it=proc_items;
-+ while(it->name!=NULL) {
-+ it++;
-+ }
-+ it--;
-+
-+ do {
-+ remove_proc_entry(it->name, *it->parent);
-+ it--;
-+ } while(it > proc_items);
-+ }
-+
-+
-+#ifdef CONFIG_IPSEC_DEBUG
-+ remove_proc_entry("ipsec_klipsdebug", proc_net);
-+#endif /* CONFIG_IPSEC_DEBUG */
-+ remove_proc_entry("ipsec_eroute", proc_net);
-+ remove_proc_entry("ipsec_spi", proc_net);
-+ remove_proc_entry("ipsec_spigrp", proc_net);
-+ remove_proc_entry("ipsec_tncfg", proc_net);
-+ remove_proc_entry("ipsec_version", proc_net);
-+ remove_proc_entry("ipsec", proc_net);
-+#endif /* 2.4 kernel */
-+}
-+
-+/*
-+ * $Log: ipsec_proc.c,v $
-+ * Revision 1.30 2004/04/25 21:23:11 ken
-+ * Pull in dhr's changes from FreeS/WAN 2.06
-+ *
-+ * Revision 1.29 2004/04/06 02:49:26 mcr
-+ * pullup of algo code from alg-branch.
-+ *
-+ * Revision 1.28 2004/03/28 20:29:58 paul
-+ * <hugh_> ssize_t, not ssized_t
-+ *
-+ * Revision 1.27 2004/03/28 20:27:20 paul
-+ * Included tested and confirmed fixes mcr made and dhr verified for
-+ * snprint statements. Changed one other snprintf to use ipsec_snprintf
-+ * so it wouldnt break compatibility with 2.0/2.2 kernels. Verified with
-+ * dhr. (thanks dhr!)
-+ *
-+ * Revision 1.26 2004/02/09 22:07:06 mcr
-+ * added information about nat-traversal setting to spi-output.
-+ *
-+ * Revision 1.25.4.1 2004/04/05 04:30:46 mcr
-+ * patches for alg-branch to compile/work with 2.x openswan
-+ *
-+ * Revision 1.25 2003/10/31 02:27:55 mcr
-+ * pulled up port-selector patches and sa_id elimination.
-+ *
-+ * Revision 1.24.4.1 2003/10/29 01:30:41 mcr
-+ * elimited "struct sa_id".
-+ *
-+ * Revision 1.24 2003/06/20 01:42:21 mcr
-+ * added counters to measure how many ACQUIREs we send to pluto,
-+ * and how many are successfully sent.
-+ *
-+ * Revision 1.23 2003/04/03 17:38:09 rgb
-+ * Centralised ipsec_kfree_skb and ipsec_dev_{get,put}.
-+ *
-+ * Revision 1.22 2002/09/20 15:40:57 rgb
-+ * Renamed saref macros for consistency and brevity.
-+ *
-+ * Revision 1.21 2002/09/20 05:01:35 rgb
-+ * Print ref and reftable, refentry seperately.
-+ *
-+ * Revision 1.20 2002/09/19 02:35:39 mcr
-+ * do not define structures needed by /proc/net/ipsec/ if we
-+ * aren't going create that directory.
-+ *
-+ * Revision 1.19 2002/09/10 01:43:25 mcr
-+ * fixed problem in /-* comment.
-+ *
-+ * Revision 1.18 2002/09/03 16:22:11 mcr
-+ * fixed initialization of birth/stuff values - some simple
-+ * screw ups in the code.
-+ * removed debugging that was left in by mistake.
-+ *
-+ * Revision 1.17 2002/09/02 17:54:53 mcr
-+ * changed how the table driven /proc entries are created so that
-+ * making subdirs is now explicit rather than implicit.
-+ *
-+ * Revision 1.16 2002/08/30 01:23:37 mcr
-+ * reorganized /proc creating code to clear up ifdefs,
-+ * make the 2.4 code table driven, and put things into
-+ * /proc/net/ipsec subdir. Symlinks are left for compatibility.
-+ *
-+ * Revision 1.15 2002/08/13 19:01:25 mcr
-+ * patches from kenb to permit compilation of FreeSWAN on ia64.
-+ * des library patched to use proper DES_LONG type for ia64.
-+ *
-+ * Revision 1.14 2002/07/26 08:48:31 rgb
-+ * Added SA ref table code.
-+ *
-+ * Revision 1.13 2002/07/24 18:44:54 rgb
-+ * Type fiddling to tame ia64 compiler.
-+ *
-+ * Revision 1.12 2002/05/27 18:56:07 rgb
-+ * Convert to dynamic ipsec device allocation.
-+ *
-+ * Revision 1.11 2002/05/23 07:14:50 rgb
-+ * Added refcount code.
-+ * Cleaned up %p variants to 0p%p for test suite cleanup.
-+ * Convert "usecount" to "refcount" to remove ambiguity.
-+ *
-+ * Revision 1.10 2002/04/24 07:55:32 mcr
-+ * #include patches and Makefiles for post-reorg compilation.
-+ *
-+ * Revision 1.9 2002/04/24 07:36:28 mcr
-+ * Moved from ./klips/net/ipsec/ipsec_proc.c,v
-+ *
-+ * Revision 1.8 2002/01/29 17:17:55 mcr
-+ * moved include of ipsec_param.h to after include of linux/kernel.h
-+ * otherwise, it seems that some option that is set in ipsec_param.h
-+ * screws up something subtle in the include path to kernel.h, and
-+ * it complains on the snprintf() prototype.
-+ *
-+ * Revision 1.7 2002/01/29 04:00:52 mcr
-+ * more excise of kversions.h header.
-+ *
-+ * Revision 1.6 2002/01/29 02:13:17 mcr
-+ * introduction of ipsec_kversion.h means that include of
-+ * ipsec_param.h must preceed any decisions about what files to
-+ * include to deal with differences in kernel source.
-+ *
-+ * Revision 1.5 2002/01/12 02:54:30 mcr
-+ * beginnings of /proc/net/ipsec dir.
-+ *
-+ * Revision 1.4 2001/12/11 02:21:05 rgb
-+ * Don't include module version here, fixing 2.2 compile bug.
-+ *
-+ * Revision 1.3 2001/12/05 07:19:44 rgb
-+ * Fixed extraneous #include "version.c" bug causing modular KLIPS failure.
-+ *
-+ * Revision 1.2 2001/11/26 09:16:14 rgb
-+ * Merge MCR's ipsec_sa, eroute, proc and struct lifetime changes.
-+ *
-+ * Revision 1.74 2001/11/22 05:44:11 henry
-+ * new version stuff
-+ *
-+ * Revision 1.1.2.1 2001/09/25 02:19:40 mcr
-+ * /proc manipulation code moved to new ipsec_proc.c
-+ *
-+ *
-+ * Local variables:
-+ * c-file-style: "linux"
-+ * End:
-+ *
-+ */
---- /dev/null Tue Mar 11 13:02:56 2003
-+++ linux/net/ipsec/ipsec_radij.c Mon Feb 9 13:51:03 2004
-@@ -0,0 +1,869 @@
-+/*
-+ * Interface between the IPSEC code and the radix (radij) tree code
-+ * Copyright (C) 1996, 1997 John Ioannidis.
-+ * Copyright (C) 1998, 1999, 2000, 2001 Richard Guy Briggs.
-+ *
-+ * 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. See <http://www.fsf.org/copyleft/gpl.txt>.
-+ *
-+ * 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.
-+ *
-+ * RCSID $Id: ipsec_radij.c,v 1.70 2004/04/25 21:10:52 ken Exp $
-+ */
-+
-+#include <linux/config.h>
-+#include <linux/version.h>
-+#include <linux/kernel.h> /* printk() */
-+
-+#include "openswan/ipsec_param.h"
-+
-+#ifdef MALLOC_SLAB
-+# include <linux/slab.h> /* kmalloc() */
-+#else /* MALLOC_SLAB */
-+# include <linux/malloc.h> /* kmalloc() */
-+#endif /* MALLOC_SLAB */
-+#include <linux/errno.h> /* error codes */
-+#include <linux/types.h> /* size_t */
-+#include <linux/interrupt.h> /* mark_bh */
-+
-+#include <linux/netdevice.h> /* struct device, struct net_device_stats and other headers */
-+#include <linux/etherdevice.h> /* eth_type_trans */
-+#include <linux/ip.h> /* struct iphdr */
-+#include <linux/skbuff.h>
-+#include <openswan.h>
-+#ifdef SPINLOCK
-+# ifdef SPINLOCK_23
-+# include <linux/spinlock.h> /* *lock* */
-+# else /* 23_SPINLOCK */
-+# include <asm/spinlock.h> /* *lock* */
-+# endif /* 23_SPINLOCK */
-+#endif /* SPINLOCK */
-+#ifdef NET_21
-+# include <asm/uaccess.h>
-+# include <linux/in6.h>
-+#endif
-+#include <asm/checksum.h>
-+#include <net/ip.h>
-+
-+#include "openswan/ipsec_eroute.h"
-+#include "openswan/ipsec_sa.h"
-+
-+#include "openswan/radij.h"
-+#include "openswan/ipsec_encap.h"
-+#include "openswan/radij.h"
-+#include "openswan/ipsec_encap.h"
-+#include "openswan/ipsec_radij.h"
-+#include "openswan/ipsec_tunnel.h" /* struct ipsecpriv */
-+#include "openswan/ipsec_xform.h"
-+
-+#include <pfkeyv2.h>
-+#include <pfkey.h>
-+
-+#include "openswan/ipsec_proto.h"
-+
-+#ifdef CONFIG_IPSEC_DEBUG
-+int debug_radij = 0;
-+#endif /* CONFIG_IPSEC_DEBUG */
-+
-+struct radij_node_head *rnh = NULL;
-+#ifdef SPINLOCK
-+spinlock_t eroute_lock = SPIN_LOCK_UNLOCKED;
-+#else /* SPINLOCK */
-+spinlock_t eroute_lock;
-+#endif /* SPINLOCK */
-+
-+int
-+ipsec_radijinit(void)
-+{
-+ maj_keylen = sizeof (struct sockaddr_encap);
-+
-+ rj_init();
-+
-+ if (rj_inithead((void **)&rnh, /*16*/offsetof(struct sockaddr_encap, sen_type) * sizeof(__u8)) == 0) /* 16 is bit offset of sen_type */
-+ return -1;
-+ return 0;
-+}
-+
-+int
-+ipsec_radijcleanup(void)
-+{
-+ int error;
-+
-+ spin_lock_bh(&eroute_lock);
-+
-+ error = radijcleanup();
-+
-+ spin_unlock_bh(&eroute_lock);
-+
-+ return error;
-+}
-+
-+int
-+ipsec_cleareroutes(void)
-+{
-+ int error;
-+
-+ spin_lock_bh(&eroute_lock);
-+
-+ error = radijcleartree();
-+
-+ spin_unlock_bh(&eroute_lock);
-+
-+ return error;
-+}
-+
-+int
-+ipsec_breakroute(struct sockaddr_encap *eaddr,
-+ struct sockaddr_encap *emask,
-+ struct sk_buff **first,
-+ struct sk_buff **last)
-+{
-+ struct eroute *ro;
-+ struct radij_node *rn;
-+ int error;
-+#ifdef CONFIG_IPSEC_DEBUG
-+
-+ if (debug_eroute) {
-+ char buf1[SUBNETTOA_BUF], buf2[SUBNETTOA_BUF];
-+ subnettoa(eaddr->sen_ip_src, emask->sen_ip_src, 0, buf1, sizeof(buf1));
-+ subnettoa(eaddr->sen_ip_dst, emask->sen_ip_dst, 0, buf2, sizeof(buf2));
-+ KLIPS_PRINT(debug_eroute,
-+ "klips_debug:ipsec_breakroute: "
-+ "attempting to delete eroute for %s:%d->%s:%d %d\n",
-+ buf1, ntohs(eaddr->sen_sport),
-+ buf2, ntohs(eaddr->sen_dport), eaddr->sen_proto);
-+ }
-+#endif /* CONFIG_IPSEC_DEBUG */
-+
-+ spin_lock_bh(&eroute_lock);
-+
-+ if ((error = rj_delete(eaddr, emask, rnh, &rn)) != 0) {
-+ spin_unlock_bh(&eroute_lock);
-+ KLIPS_PRINT(debug_eroute,
-+ "klips_debug:ipsec_breakroute: "
-+ "node not found, eroute delete failed.\n");
-+ return error;
-+ }
-+
-+ spin_unlock_bh(&eroute_lock);
-+
-+ ro = (struct eroute *)rn;
-+
-+ KLIPS_PRINT(debug_eroute,
-+ "klips_debug:ipsec_breakroute: "
-+ "deleted eroute=0p%p, ident=0p%p->0p%p, first=0p%p, last=0p%p\n",
-+ ro,
-+ ro->er_ident_s.data,
-+ ro->er_ident_d.data,
-+ ro->er_first,
-+ ro->er_last);
-+
-+ if (ro->er_ident_s.data != NULL) {
-+ kfree(ro->er_ident_s.data);
-+ }
-+ if (ro->er_ident_d.data != NULL) {
-+ kfree(ro->er_ident_d.data);
-+ }
-+ if (ro->er_first != NULL) {
-+#if 0
-+ struct net_device_stats *stats = (struct net_device_stats *) &(((struct ipsecpriv *)(ro->er_first->dev->priv))->mystats);
-+ stats->tx_dropped--;
-+#endif
-+ *first = ro->er_first;
-+ }
-+ if (ro->er_last != NULL) {
-+#if 0
-+ struct net_device_stats *stats = (struct net_device_stats *) &(((struct ipsecpriv *)(ro->er_last->dev->priv))->mystats);
-+ stats->tx_dropped--;
-+#endif
-+ *last = ro->er_last;
-+ }
-+
-+ if (rn->rj_flags & (RJF_ACTIVE | RJF_ROOT))
-+ panic ("ipsec_breakroute RMT_DELEROUTE root or active node\n");
-+ memset((caddr_t)rn, 0, sizeof (struct eroute));
-+ kfree(rn);
-+
-+ return 0;
-+}
-+
-+int
-+ipsec_makeroute(struct sockaddr_encap *eaddr,
-+ struct sockaddr_encap *emask,
-+ ip_said said,
-+ uint32_t pid,
-+ struct sk_buff *skb,
-+ struct ident *ident_s,
-+ struct ident *ident_d)
-+{
-+ struct eroute *retrt;
-+ int error;
-+ char sa[SATOT_BUF];
-+ size_t sa_len;
-+
-+#ifdef CONFIG_IPSEC_DEBUG
-+
-+ if (debug_eroute) {
-+
-+ {
-+ char buf1[SUBNETTOA_BUF], buf2[SUBNETTOA_BUF];
-+
-+ subnettoa(eaddr->sen_ip_src, emask->sen_ip_src, 0, buf1, sizeof(buf1));
-+ subnettoa(eaddr->sen_ip_dst, emask->sen_ip_dst, 0, buf2, sizeof(buf2));
-+ sa_len = satot(&said, 0, sa, sizeof(sa));
-+ KLIPS_PRINT(debug_eroute,
-+ "klips_debug:ipsec_makeroute: "
-+ "attempting to allocate %lu bytes to insert eroute for %s->%s, SA: %s, PID:%d, skb=0p%p, ident:%s->%s\n",
-+ (unsigned long) sizeof(struct eroute),
-+ buf1,
-+ buf2,
-+ sa_len ? sa : " (error)",
-+ pid,
-+ skb,
-+ (ident_s ? (ident_s->data ? ident_s->data : "NULL") : "NULL"),
-+ (ident_d ? (ident_d->data ? ident_d->data : "NULL") : "NULL"));
-+ }
-+ {
-+ char buf1[sizeof(struct sockaddr_encap)*2 + 1],
-+ buf2[sizeof(struct sockaddr_encap)*2 + 1];
-+ int i;
-+ unsigned char *b1 = buf1,
-+ *b2 = buf2,
-+ *ea = (unsigned char *)eaddr,
-+ *em = (unsigned char *)emask;
-+
-+
-+ for (i=0; i<sizeof(struct sockaddr_encap); i++) {
-+ sprintf(b1, "%02x", ea[i]);
-+ sprintf(b2, "%02x", em[i]);
-+ b1+=2;
-+ b2+=2;
-+ }
-+ KLIPS_PRINT(debug_eroute, "klips_debug:ipsec_makeroute: %s / %s \n", buf1, buf2);
-+ }
-+
-+ }
-+#endif /* CONFIG_IPSEC_DEBUG */
-+
-+ retrt = (struct eroute *)kmalloc(sizeof (struct eroute), GFP_ATOMIC);
-+ if (retrt == NULL) {
-+ printk("klips_error:ipsec_makeroute: "
-+ "not able to allocate kernel memory");
-+ return -ENOMEM;
-+ }
-+ memset((caddr_t)retrt, 0, sizeof (struct eroute));
-+
-+ retrt->er_eaddr = *eaddr;
-+ retrt->er_emask = *emask;
-+ retrt->er_said = said;
-+ retrt->er_pid = pid;
-+ retrt->er_count = 0;
-+ retrt->er_lasttime = jiffies/HZ;
-+ rd_key((&(retrt->er_rjt))) = &(retrt->er_eaddr);
-+
-+ if (ident_s && ident_s->type != SADB_IDENTTYPE_RESERVED) {
-+ int data_len = ident_s->len * IPSEC_PFKEYv2_ALIGN - sizeof(struct sadb_ident);
-+
-+ retrt->er_ident_s.type = ident_s->type;
-+ retrt->er_ident_s.id = ident_s->id;
-+ retrt->er_ident_s.len = ident_s->len;
-+ if(data_len) {
-+ KLIPS_PRINT(debug_eroute,
-+ "klips_debug:ipsec_makeroute: "
-+ "attempting to allocate %u bytes for ident_s.\n",
-+ data_len);
-+ if(!(retrt->er_ident_s.data = kmalloc(data_len, GFP_KERNEL))) {
-+ kfree(retrt);
-+ printk("klips_error:ipsec_makeroute: not able to allocate kernel memory (%d)\n", data_len);
-+ return ENOMEM;
-+ }
-+ memcpy(retrt->er_ident_s.data, ident_s->data, data_len);
-+ } else {
-+ retrt->er_ident_s.data = NULL;
-+ }
-+ }
-+
-+ if (ident_d && ident_d->type != SADB_IDENTTYPE_RESERVED) {
-+ int data_len = ident_d->len * IPSEC_PFKEYv2_ALIGN - sizeof(struct sadb_ident);
-+
-+ retrt->er_ident_d.type = ident_d->type;
-+ retrt->er_ident_d.id = ident_d->id;
-+ retrt->er_ident_d.len = ident_d->len;
-+ if(data_len) {
-+ KLIPS_PRINT(debug_eroute,
-+ "klips_debug:ipsec_makeroute: "
-+ "attempting to allocate %u bytes for ident_d.\n",
-+ data_len);
-+ if(!(retrt->er_ident_d.data = kmalloc(data_len, GFP_KERNEL))) {
-+ if (retrt->er_ident_s.data)
-+ kfree(retrt->er_ident_s.data);
-+ kfree(retrt);
-+ printk("klips_error:ipsec_makeroute: not able to allocate kernel memory (%d)\n", data_len);
-+ return ENOMEM;
-+ }
-+ memcpy(retrt->er_ident_d.data, ident_d->data, data_len);
-+ } else {
-+ retrt->er_ident_d.data = NULL;
-+ }
-+ }
-+ retrt->er_first = skb;
-+ retrt->er_last = NULL;
-+
-+ KLIPS_PRINT(debug_eroute,
-+ "klips_debug:ipsec_makeroute: "
-+ "calling rj_addroute now\n");
-+
-+ spin_lock_bh(&eroute_lock);
-+
-+ error = rj_addroute(&(retrt->er_eaddr), &(retrt->er_emask),
-+ rnh, retrt->er_rjt.rd_nodes);
-+
-+ spin_unlock_bh(&eroute_lock);
-+
-+ if(error) {
-+ sa_len = satot(&said, 0, sa, sizeof(sa));
-+ KLIPS_PRINT(debug_eroute,
-+ "klips_debug:ipsec_makeroute: "
-+ "rj_addroute not able to insert eroute for SA:%s (error:%d)\n",
-+ sa_len ? sa : " (error)", error);
-+ if (retrt->er_ident_s.data)
-+ kfree(retrt->er_ident_s.data);
-+ if (retrt->er_ident_d.data)
-+ kfree(retrt->er_ident_d.data);
-+
-+ kfree(retrt);
-+
-+ return error;
-+ }
-+
-+#ifdef CONFIG_IPSEC_DEBUG
-+ if (debug_eroute) {
-+ char buf1[SUBNETTOA_BUF], buf2[SUBNETTOA_BUF];
-+/*
-+ subnettoa(eaddr->sen_ip_src, emask->sen_ip_src, 0, buf1, sizeof(buf1));
-+ subnettoa(eaddr->sen_ip_dst, emask->sen_ip_dst, 0, buf2, sizeof(buf2));
-+*/
-+ subnettoa(rd_key((&(retrt->er_rjt)))->sen_ip_src, rd_mask((&(retrt->er_rjt)))->sen_ip_src, 0, buf1, sizeof(buf1));
-+ subnettoa(rd_key((&(retrt->er_rjt)))->sen_ip_dst, rd_mask((&(retrt->er_rjt)))->sen_ip_dst, 0, buf2, sizeof(buf2));
-+ sa_len = satot(&retrt->er_said, 0, sa, sizeof(sa));
-+
-+ KLIPS_PRINT(debug_eroute,
-+ "klips_debug:ipsec_makeroute: "
-+ "pid=%05d "
-+ "count=%10d "
-+ "lasttime=%6d "
-+ "%-18s -> %-18s => %s\n",
-+ retrt->er_pid,
-+ retrt->er_count,
-+ (int)(jiffies/HZ - retrt->er_lasttime),
-+ buf1,
-+ buf2,
-+ sa_len ? sa : " (error)");
-+ }
-+#endif /* CONFIG_IPSEC_DEBUG */
-+ KLIPS_PRINT(debug_eroute,
-+ "klips_debug:ipsec_makeroute: "
-+ "succeeded.\n");
-+ return 0;
-+}
-+
-+struct eroute *
-+ipsec_findroute(struct sockaddr_encap *eaddr)
-+{
-+ struct radij_node *rn;
-+#ifdef CONFIG_IPSEC_DEBUG
-+ char buf1[ADDRTOA_BUF], buf2[ADDRTOA_BUF];
-+
-+ if (debug_radij & DB_RJ_FINDROUTE) {
-+ addrtoa(eaddr->sen_ip_src, 0, buf1, sizeof(buf1));
-+ addrtoa(eaddr->sen_ip_dst, 0, buf2, sizeof(buf2));
-+ KLIPS_PRINT(debug_eroute,
-+ "klips_debug:ipsec_findroute: "
-+ "%s:%d->%s:%d %d\n",
-+ buf1, ntohs(eaddr->sen_sport),
-+ buf2, ntohs(eaddr->sen_dport),
-+ eaddr->sen_proto);
-+ }
-+#endif /* CONFIG_IPSEC_DEBUG */
-+ rn = rj_match((caddr_t)eaddr, rnh);
-+ if(rn) {
-+ KLIPS_PRINT(debug_eroute && sysctl_ipsec_debug_verbose,
-+ "klips_debug:ipsec_findroute: "
-+ "found, points to proto=%d, spi=%x, dst=%x.\n",
-+ ((struct eroute*)rn)->er_said.proto,
-+ ntohl(((struct eroute*)rn)->er_said.spi),
-+ ntohl(((struct eroute*)rn)->er_said.dst.u.v4.sin_addr.s_addr));
-+ }
-+ return (struct eroute *)rn;
-+}
-+
-+#ifdef CONFIG_PROC_FS
-+/** ipsec_rj_walker_procprint: print one line of eroute table output.
-+ *
-+ * Theoretical BUG: if w->length is less than the length
-+ * of some line we should produce, that line will never
-+ * be finished. In effect, the "file" will stop part way
-+ * through that line.
-+ */
-+int
-+ipsec_rj_walker_procprint(struct radij_node *rn, void *w0)
-+{
-+ struct eroute *ro = (struct eroute *)rn;
-+ struct rjtentry *rd = (struct rjtentry *)rn;
-+ struct wsbuf *w = (struct wsbuf *)w0;
-+ char buf1[SUBNETTOA_BUF], buf2[SUBNETTOA_BUF];
-+ char buf3[16];
-+ char sa[SATOT_BUF];
-+ size_t sa_len, buf_len;
-+ struct sockaddr_encap *key, *mask;
-+
-+ KLIPS_PRINT(debug_radij,
-+ "klips_debug:ipsec_rj_walker_procprint: "
-+ "rn=0p%p, w0=0p%p\n",
-+ rn,
-+ w0);
-+ if (rn->rj_b >= 0) {
-+ return 0;
-+ }
-+
-+ key = rd_key(rd);
-+ mask = rd_mask(rd);
-+
-+ if (key == NULL || mask == NULL) {
-+ return 0;
-+ }
-+
-+ buf_len = subnettoa(key->sen_ip_src, mask->sen_ip_src, 0, buf1, sizeof(buf1));
-+ if(key->sen_sport != 0) {
-+ sprintf(buf1+buf_len-1, ":%d", ntohs(key->sen_sport));
-+ }
-+
-+ buf_len = subnettoa(key->sen_ip_dst, mask->sen_ip_dst, 0, buf2, sizeof(buf2));
-+ if(key->sen_dport != 0) {
-+ sprintf(buf2+buf_len-1, ":%d", ntohs(key->sen_dport));
-+ }
-+
-+ buf3[0]='\0';
-+ if(key->sen_proto != 0) {
-+ sprintf(buf3, ":%d", key->sen_proto);
-+ }
-+
-+ sa_len = satot(&ro->er_said, 'x', sa, sizeof(sa));
-+ w->len += ipsec_snprintf(w->buffer + w->len,
-+ w->length - w->len,
-+ "%-10d "
-+ "%-18s -> %-18s => %s%s\n",
-+ ro->er_count,
-+ buf1,
-+ buf2,
-+ sa_len ? sa : " (error)",
-+ buf3);
-+
-+ {
-+ /* snprintf can only fill the last character with NUL
-+ * so the maximum useful character is w->length-1.
-+ * However, if w->length == 0, we cannot go back.
-+ * (w->length surely cannot be negative.)
-+ */
-+ int max_content = w->length > 0? w->length-1 : 0;
-+
-+ if (w->len >= max_content) {
-+ /* we've done all that can fit -- stop treewalking */
-+ w->len = max_content; /* truncate crap */
-+ return -ENOBUFS;
-+ } else {
-+ const off_t pos = w->begin + w->len; /* file position of end of what we've generated */
-+
-+ if (pos <= w->offset) {
-+ /* all is before first interesting character:
-+ * discard, but note where we are.
-+ */
-+ w->len = 0;
-+ w->begin = pos;
-+ }
-+ return 0;
-+ }
-+ }
-+}
-+#endif /* CONFIG_PROC_FS */
-+
-+int
-+ipsec_rj_walker_delete(struct radij_node *rn, void *w0)
-+{
-+ struct eroute *ro;
-+ struct rjtentry *rd = (struct rjtentry *)rn;
-+ struct radij_node *rn2;
-+ int error;
-+ struct sockaddr_encap *key, *mask;
-+
-+ key = rd_key(rd);
-+ mask = rd_mask(rd);
-+
-+ if(!key || !mask) {
-+ return -ENODATA;
-+ }
-+#ifdef CONFIG_IPSEC_DEBUG
-+ if(debug_radij) {
-+ char buf1[SUBNETTOA_BUF], buf2[SUBNETTOA_BUF];
-+ subnettoa(key->sen_ip_src, mask->sen_ip_src, 0, buf1, sizeof(buf1));
-+ subnettoa(key->sen_ip_dst, mask->sen_ip_dst, 0, buf2, sizeof(buf2));
-+ KLIPS_PRINT(debug_radij,
-+ "klips_debug:ipsec_rj_walker_delete: "
-+ "deleting: %s -> %s\n",
-+ buf1,
-+ buf2);
-+ }
-+#endif /* CONFIG_IPSEC_DEBUG */
-+
-+ if((error = rj_delete(key, mask, rnh, &rn2))) {
-+ KLIPS_PRINT(debug_radij,
-+ "klips_debug:ipsec_rj_walker_delete: "
-+ "rj_delete failed with error=%d.\n", error);
-+ return error;
-+ }
-+
-+ if(rn2 != rn) {
-+ printk("klips_debug:ipsec_rj_walker_delete: "
-+ "tried to delete a different node?!? This should never happen!\n");
-+ }
-+
-+ ro = (struct eroute *)rn;
-+
-+ if (ro->er_ident_s.data)
-+ kfree(ro->er_ident_s.data);
-+ if (ro->er_ident_d.data)
-+ kfree(ro->er_ident_d.data);
-+
-+ memset((caddr_t)rn, 0, sizeof (struct eroute));
-+ kfree(rn);
-+
-+ return 0;
-+}
-+
-+/*
-+ * $Log: ipsec_radij.c,v $
-+ * Revision 1.70 2004/04/25 21:10:52 ken
-+ * Pull in dhr's changes from FreeS/WAN 2.06
-+ *
-+ * Revision 1.69 2004/04/06 02:49:26 mcr
-+ * pullup of algo code from alg-branch.
-+ *
-+ * Revision 1.68 2004/03/28 20:27:20 paul
-+ * Included tested and confirmed fixes mcr made and dhr verified for
-+ * snprint statements. Changed one other snprintf to use ipsec_snprintf
-+ * so it wouldnt break compatibility with 2.0/2.2 kernels. Verified with
-+ * dhr. (thanks dhr!)
-+ *
-+ * Revision 1.67.4.1 2004/04/05 04:30:46 mcr
-+ * patches for alg-branch to compile/work with 2.x openswan
-+ *
-+ * Revision 1.67 2003/10/31 02:27:55 mcr
-+ * pulled up port-selector patches and sa_id elimination.
-+ *
-+ * Revision 1.66.24.2 2003/10/29 01:30:41 mcr
-+ * elimited "struct sa_id".
-+ *
-+ * Revision 1.66.24.1 2003/09/21 13:59:56 mcr
-+ * pre-liminary X.509 patch - does not yet pass tests.
-+ *
-+ * Revision 1.66 2002/10/12 23:11:53 dhr
-+ *
-+ * [KenB + DHR] more 64-bit cleanup
-+ *
-+ * Revision 1.65 2002/09/20 05:01:40 rgb
-+ * Added memory allocation debugging.
-+ *
-+ * Revision 1.64 2002/05/31 01:46:05 mcr
-+ * added && sysctl_ipsec_debug_verbose verbose to ipsec_findroute
-+ * as requested in PR#14.
-+ *
-+ * Revision 1.63 2002/05/23 07:14:11 rgb
-+ * Cleaned up %p variants to 0p%p for test suite cleanup.
-+ *
-+ * Revision 1.62 2002/04/24 07:55:32 mcr
-+ * #include patches and Makefiles for post-reorg compilation.
-+ *
-+ * Revision 1.61 2002/04/24 07:36:29 mcr
-+ * Moved from ./klips/net/ipsec/ipsec_radij.c,v
-+ *
-+ * Revision 1.60 2002/02/19 23:59:45 rgb
-+ * Removed redundant compiler directives.
-+ *
-+ * Revision 1.59 2002/02/06 04:13:47 mcr
-+ * missing #ifdef CONFIG_IPSEC_DEBUG.
-+ *
-+ * Revision 1.58 2002/01/29 17:17:56 mcr
-+ * moved include of ipsec_param.h to after include of linux/kernel.h
-+ * otherwise, it seems that some option that is set in ipsec_param.h
-+ * screws up something subtle in the include path to kernel.h, and
-+ * it complains on the snprintf() prototype.
-+ *
-+ * Revision 1.57 2002/01/29 04:00:52 mcr
-+ * more excise of kversions.h header.
-+ *
-+ * Revision 1.56 2002/01/29 02:13:17 mcr
-+ * introduction of ipsec_kversion.h means that include of
-+ * ipsec_param.h must preceed any decisions about what files to
-+ * include to deal with differences in kernel source.
-+ *
-+ * Revision 1.55 2001/11/26 09:23:48 rgb
-+ * Merge MCR's ipsec_sa, eroute, proc and struct lifetime changes.
-+ *
-+ * Revision 1.53.2.1 2001/09/25 02:26:32 mcr
-+ * headers adjusted for new usage.
-+ *
-+ * Revision 1.54 2001/10/18 04:45:20 rgb
-+ * 2.4.9 kernel deprecates linux/malloc.h in favour of linux/slab.h,
-+ * lib/freeswan.h version macros moved to lib/kversions.h.
-+ * Other compiler directive cleanups.
-+ *
-+ * Revision 1.53 2001/09/19 17:19:40 rgb
-+ * Debug output bugfix for NetCelo's PF_KEY ident patch.
-+ *
-+ * Revision 1.52 2001/09/19 16:33:37 rgb
-+ * Temporarily disable ident fields to /proc/net/ipsec_eroute.
-+ *
-+ * Revision 1.51 2001/09/15 16:24:04 rgb
-+ * Re-inject first and last HOLD packet when an eroute REPLACE is done.
-+ *
-+ * Revision 1.50 2001/09/14 16:58:36 rgb
-+ * Added support for storing the first and last packets through a HOLD.
-+ *
-+ * Revision 1.49 2001/09/08 21:13:32 rgb
-+ * Added pfkey ident extension support for ISAKMPd. (NetCelo)
-+ *
-+ * Revision 1.48 2001/06/15 04:12:56 rgb
-+ * Fixed kernel memory allocation error return code polarity bug.
-+ *
-+ * Revision 1.47 2001/06/14 19:35:09 rgb
-+ * Update copyright date.
-+ *
-+ * Revision 1.46 2001/06/08 08:47:18 rgb
-+ * Fixed for debug disabled.
-+ *
-+ * Revision 1.45 2001/05/27 06:12:11 rgb
-+ * Added structures for pid, packet count and last access time to eroute.
-+ * Added packet count to beginning of /proc/net/ipsec_eroute.
-+ *
-+ * Revision 1.44 2001/05/03 19:41:01 rgb
-+ * Initialise error return variable.
-+ * Use more appropriate return value for ipsec_rj_walker_delete().
-+ *
-+ * Revision 1.43 2001/02/27 22:24:54 rgb
-+ * Re-formatting debug output (line-splitting, joining, 1arg/line).
-+ * Check for satoa() return codes.
-+ *
-+ * Revision 1.42 2001/02/27 06:21:57 rgb
-+ * Added findroute success instrumentation.
-+ *
-+ * Revision 1.41 2000/11/06 04:32:08 rgb
-+ * Ditched spin_lock_irqsave in favour of spin_lock_bh.
-+ *
-+ * Revision 1.40 2000/09/08 19:12:56 rgb
-+ * Change references from DEBUG_IPSEC to CONFIG_IPSEC_DEBUG.
-+ *
-+ * Revision 1.39 2000/08/30 05:25:20 rgb
-+ * Correct debug text in ipsec_breakroute() from incorrect
-+ * "ipsec_callback".
-+ *
-+ * Revision 1.38 2000/07/28 14:58:31 rgb
-+ * Changed kfree_s to kfree, eliminating extra arg to fix 2.4.0-test5.
-+ *
-+ * Revision 1.37 2000/03/16 14:02:50 rgb
-+ * Fixed debug scope to enable compilation with debug off.
-+ *
-+ * Revision 1.36 2000/01/21 06:14:46 rgb
-+ * Added debugging text to ipsec_rj_walker_delete().
-+ * Set return code to negative for consistency.
-+ *
-+ * Revision 1.35 1999/11/23 23:05:24 rgb
-+ * Use provided macro ADDRTOA_BUF instead of hardcoded value.
-+ *
-+ * Revision 1.34 1999/11/18 04:13:56 rgb
-+ * Replaced all kernel version macros to shorter, readable form.
-+ * Added CONFIG_PROC_FS compiler directives in case it is shut off.
-+ *
-+ * Revision 1.33 1999/11/17 15:53:39 rgb
-+ * Changed all occurrences of #include "../../../lib/freeswan.h"
-+ * to #include <freeswan.h> which works due to -Ilibfreeswan in the
-+ * klips/net/ipsec/Makefile.
-+ *
-+ * Revision 1.32 1999/10/26 13:58:33 rgb
-+ * Put spinlock flags variable declaration outside the debug compiler
-+ * directive to enable compilation with debug shut off.
-+ *
-+ * Revision 1.31 1999/10/15 22:13:29 rgb
-+ * Clean out cruft.
-+ * Align /proc/net/ipsec_eroute output for easier readability.
-+ * Fix double linefeed in radij debug output.
-+ * Fix double locking bug that locks up 2.0.36 but not 2.0.38.
-+ *
-+ * Revision 1.30 1999/10/08 18:37:33 rgb
-+ * Fix end-of-line spacing to sate whining PHMs.
-+ *
-+ * Revision 1.29 1999/10/03 18:52:45 rgb
-+ * Spinlock support for 2.0.xx.
-+ * Dumb return code spin_unlock fix.
-+ *
-+ * Revision 1.28 1999/10/01 16:22:24 rgb
-+ * Switch from assignment init. to functional init. of spinlocks.
-+ *
-+ * Revision 1.27 1999/10/01 15:44:53 rgb
-+ * Move spinlock header include to 2.1> scope.
-+ *
-+ * Revision 1.26 1999/10/01 00:01:23 rgb
-+ * Added eroute structure locking.
-+ *
-+ * Revision 1.25 1999/06/10 16:07:30 rgb
-+ * Silence delete eroute on no debug.
-+ *
-+ * Revision 1.24 1999/05/09 03:25:36 rgb
-+ * Fix bug introduced by 2.2 quick-and-dirty patch.
-+ *
-+ * Revision 1.23 1999/05/05 22:02:31 rgb
-+ * Add a quick and dirty port to 2.2 kernels by Marc Boucher <marc@mbsi.ca>.
-+ *
-+ * Revision 1.22 1999/04/29 15:17:23 rgb
-+ * Add return values to init and cleanup functions.
-+ * Add sanity checking for null pointer arguments.
-+ *
-+ * Revision 1.21 1999/04/11 00:28:58 henry
-+ * GPL boilerplate
-+ *
-+ * Revision 1.20 1999/04/06 04:54:26 rgb
-+ * Fix/Add RCSID Id: and Log: bits to make PHMDs happy. This includes
-+ * patch shell fixes.
-+ *
-+ * Revision 1.19 1999/02/17 16:50:35 rgb
-+ * Clean out unused cruft.
-+ * Consolidate for space and speed efficiency.
-+ * Convert DEBUG_IPSEC to KLIPS_PRINT
-+ *
-+ * Revision 1.18 1999/01/22 06:22:06 rgb
-+ * Cruft clean-out.
-+ * 64-bit clean-up.
-+ *
-+ * Revision 1.17 1998/12/02 03:09:39 rgb
-+ * Clean up debug printing conditionals to compile with debugging off.
-+ *
-+ * Revision 1.16 1998/12/01 13:49:39 rgb
-+ * Wrap version info printing in debug switches.
-+ *
-+ * Revision 1.15 1998/11/30 13:22:54 rgb
-+ * Rationalised all the klips kernel file headers. They are much shorter
-+ * now and won't conflict under RH5.2.
-+ *
-+ * Revision 1.14 1998/10/31 06:48:17 rgb
-+ * Fixed up comments in #endif directives.
-+ *
-+ * Revision 1.13 1998/10/27 13:48:09 rgb
-+ * Cleaned up /proc/net/ipsec_* filesystem for easy parsing by scripts.
-+ * Fixed less(1) truncated output bug.
-+ * Code clean-up.
-+ *
-+ * Revision 1.12 1998/10/25 02:41:36 rgb
-+ * Change return type on ipsec_breakroute and ipsec_makeroute and add an
-+ * argument to be able to transmit more infomation about errors.
-+ * Fix cut-and-paste debug statement identifier.
-+ *
-+ * Revision 1.11 1998/10/22 06:45:39 rgb
-+ * Cleaned up cruft.
-+ * Convert to use satoa for printk.
-+ *
-+ * Revision 1.10 1998/10/19 14:44:28 rgb
-+ * Added inclusion of freeswan.h.
-+ * sa_id structure implemented and used: now includes protocol.
-+ *
-+ * Revision 1.9 1998/10/09 04:30:52 rgb
-+ * Added 'klips_debug' prefix to all klips printk debug statements.
-+ * Deleted old commented out cruft.
-+ *
-+ * Revision 1.8 1998/08/06 17:24:23 rgb
-+ * Fix addrtoa return code bug from stale manpage advice preventing packets
-+ * from being erouted.
-+ *
-+ * Revision 1.7 1998/08/06 07:44:59 rgb
-+ * Fixed /proc/net/ipsec_eroute subnettoa and addrtoa return value bug that
-+ * ended up in nothing being printed.
-+ *
-+ * Revision 1.6 1998/08/05 22:16:41 rgb
-+ * Cleanup to prevent cosmetic errors (ie. debug output) from being fatal.
-+ *
-+ * Revision 1.5 1998/07/29 20:38:44 rgb
-+ * Debug and fix subnettoa and addrtoa output.
-+ *
-+ * Revision 1.4 1998/07/28 00:02:39 rgb
-+ * Converting to exclusive use of addrtoa.
-+ * Fix eroute delete.
-+ *
-+ * Revision 1.3 1998/07/14 18:21:26 rgb
-+ * Add function to clear the eroute table.
-+ *
-+ * Revision 1.2 1998/06/23 02:59:14 rgb
-+ * Added debugging output to eroute add/delete routines.
-+ *
-+ * Revision 1.9 1998/06/18 21:29:06 henry
-+ * move sources from klips/src to klips/net/ipsec, to keep stupid kernel
-+ * build scripts happier in presence of symbolic links
-+ *
-+ * Revision 1.8 1998/06/05 02:32:26 rgb
-+ * Fix spi ntoh kernel debug output.
-+ *
-+ * Revision 1.7 1998/05/25 20:30:37 rgb
-+ * Remove temporary ipsec_walk, rj_deltree and rj_delnodes functions.
-+ *
-+ * Rename ipsec_rj_walker (ipsec_walk) to ipsec_rj_walker_procprint and
-+ * add ipsec_rj_walker_delete.
-+ *
-+ * Revision 1.6 1998/05/21 13:08:57 rgb
-+ * Rewrote procinfo subroutines to avoid *bad things* when more that 3k of
-+ * information is available for printout.
-+ *
-+ * Revision 1.5 1998/05/18 21:35:55 rgb
-+ * Clean up output for numerical consistency and readability. Zero freed
-+ * eroute memory.
-+ *
-+ * Revision 1.4 1998/04/21 21:28:58 rgb
-+ * Rearrange debug switches to change on the fly debug output from user
-+ * space. Only kernel changes checked in at this time. radij.c was also
-+ * changed to temporarily remove buggy debugging code in rj_delete causing
-+ * an OOPS and hence, netlink device open errors.
-+ *
-+ * Revision 1.3 1998/04/14 17:30:39 rgb
-+ * Fix up compiling errors for radij tree memory reclamation.
-+ *
-+ * Revision 1.2 1998/04/12 22:03:23 rgb
-+ * Updated ESP-3DES-HMAC-MD5-96,
-+ * ESP-DES-HMAC-MD5-96,
-+ * AH-HMAC-MD5-96,
-+ * AH-HMAC-SHA1-96 since Henry started freeswan cvs repository
-+ * from old standards (RFC182[5-9] to new (as of March 1998) drafts.
-+ *
-+ * Fixed eroute references in /proc/net/ipsec*.
-+ *
-+ * Started to patch module unloading memory leaks in ipsec_netlink and
-+ * radij tree unloading.
-+ *
-+ * Revision 1.1 1998/04/09 03:06:10 henry
-+ * sources moved up from linux/net/ipsec
-+ *
-+ * Revision 1.1.1.1 1998/04/08 05:35:03 henry
-+ * RGB's ipsec-0.8pre2.tar.gz ipsec-0.8
-+ *
-+ * Revision 0.4 1997/01/15 01:28:15 ji
-+ * No changes.
-+ *
-+ * Revision 0.3 1996/11/20 14:39:04 ji
-+ * Minor cleanups.
-+ * Rationalized debugging code.
-+ *
-+ * Revision 0.2 1996/11/02 00:18:33 ji
-+ * First limited release.
-+ *
-+ *
-+ */
---- /dev/null Tue Mar 11 13:02:56 2003
-+++ linux/net/ipsec/ipsec_rcv.c Mon Feb 9 13:51:03 2004
-@@ -0,0 +1,1922 @@
-+/*
-+ * receive code
-+ * Copyright (C) 1996, 1997 John Ioannidis.
-+ * Copyright (C) 1998-2003 Richard Guy Briggs.
-+ * Copyright (C) 2004 Michael Richardson <mcr@xelerance.com>
-+ *
-+ * 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. See <http://www.fsf.org/copyleft/gpl.txt>.
-+ *
-+ * 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.
-+ */
-+
-+char ipsec_rcv_c_version[] = "RCSID $Id: ipsec_rcv.c,v 1.143.4.2 2004/08/22 03:29:06 mcr Exp $";
-+
-+#include <linux/config.h>
-+#include <linux/version.h>
-+
-+#define __NO_VERSION__
-+#include <linux/module.h>
-+#include <linux/kernel.h> /* printk() */
-+
-+#include "openswan/ipsec_param.h"
-+
-+#ifdef MALLOC_SLAB
-+# include <linux/slab.h> /* kmalloc() */
-+#else /* MALLOC_SLAB */
-+# include <linux/malloc.h> /* kmalloc() */
-+#endif /* MALLOC_SLAB */
-+#include <linux/errno.h> /* error codes */
-+#include <linux/types.h> /* size_t */
-+#include <linux/interrupt.h> /* mark_bh */
-+
-+#include <net/udp.h>
-+
-+#include <linux/netdevice.h> /* struct device, and other headers */
-+#include <linux/etherdevice.h> /* eth_type_trans */
-+#include <linux/ip.h> /* struct iphdr */
-+#include <linux/skbuff.h>
-+#include <openswan.h>
-+#ifdef SPINLOCK
-+# ifdef SPINLOCK_23
-+# include <linux/spinlock.h> /* *lock* */
-+# else /* SPINLOCK_23 */
-+# include <asm/spinlock.h> /* *lock* */
-+# endif /* SPINLOCK_23 */
-+#endif /* SPINLOCK */
-+#ifdef NET_21
-+# include <asm/uaccess.h>
-+# include <linux/in6.h>
-+# define proto_priv cb
-+#endif /* NET21 */
-+#include <asm/checksum.h>
-+#include <net/ip.h>
-+
-+#include "openswan/radij.h"
-+#include "openswan/ipsec_encap.h"
-+#include "openswan/ipsec_sa.h"
-+
-+#include "openswan/ipsec_radij.h"
-+#include "openswan/ipsec_xform.h"
-+#include "openswan/ipsec_tunnel.h"
-+#include "openswan/ipsec_rcv.h"
-+
-+#include "openswan/ipsec_auth.h"
-+
-+#include "openswan/ipsec_esp.h"
-+
-+#ifdef CONFIG_IPSEC_AH
-+#include "openswan/ipsec_ah.h"
-+#endif /* CONFIG_IPSEC_AH */
-+
-+#ifdef CONFIG_IPSEC_IPCOMP
-+#include "openswan/ipsec_ipcomp.h"
-+#endif /* CONFIG_IPSEC_COMP */
-+
-+#include <pfkeyv2.h>
-+#include <pfkey.h>
-+
-+#include "openswan/ipsec_proto.h"
-+#include "openswan/ipsec_alg.h"
-+
-+#ifdef CONFIG_IPSEC_DEBUG
-+int debug_rcv = 0;
-+#endif /* CONFIG_IPSEC_DEBUG */
-+
-+int sysctl_ipsec_inbound_policy_check = 1;
-+
-+/* This is a private use protocol, and AT&T should be ashamed. They should have
-+ * used protocol # 59, which is "no next header" instead of 0xFE.
-+ */
-+#ifndef IPPROTO_ATT_HEARTBEAT
-+#define IPPROTO_ATT_HEARTBEAT 0xFE
-+#endif
-+
-+#ifdef CONFIG_IPSEC_DEBUG
-+void
-+ipsec_dmp(char *s, caddr_t bb, int len)
-+{
-+ int i;
-+ unsigned char *b = bb;
-+
-+
-+ printk(KERN_INFO "klips_debug:ipsec_tunnel_:dmp: "
-+ "at %s, len=%d:",
-+ s,
-+ len);
-+ for (i=0; i < len; i++) {
-+ if(!(i%16)){
-+ printk("\nklips_debug: ");
-+ }
-+ printk(" %02x", *b++);
-+ }
-+ printk("\n");
-+}
-+#endif /* CONFIG_IPSEC_DEBUG */
-+
-+/*
-+ * Check-replay-window routine, adapted from the original
-+ * by J. Hughes, from draft-ietf-ipsec-esp-des-md5-03.txt
-+ *
-+ * This is a routine that implements a 64 packet window. This is intend-
-+ * ed on being an implementation sample.
-+ */
-+
-+DEBUG_NO_STATIC int
-+ipsec_checkreplaywindow(struct ipsec_sa*ipsp, __u32 seq)
-+{
-+ __u32 diff;
-+
-+ if (ipsp->ips_replaywin == 0) /* replay shut off */
-+ return 1;
-+ if (seq == 0)
-+ return 0; /* first == 0 or wrapped */
-+
-+ /* new larger sequence number */
-+ if (seq > ipsp->ips_replaywin_lastseq) {
-+ return 1; /* larger is good */
-+ }
-+ diff = ipsp->ips_replaywin_lastseq - seq;
-+
-+ /* too old or wrapped */ /* if wrapped, kill off SA? */
-+ if (diff >= ipsp->ips_replaywin) {
-+ return 0;
-+ }
-+ /* this packet already seen */
-+ if (ipsp->ips_replaywin_bitmap & (1 << diff))
-+ return 0;
-+ return 1; /* out of order but good */
-+}
-+
-+DEBUG_NO_STATIC int
-+ipsec_updatereplaywindow(struct ipsec_sa*ipsp, __u32 seq)
-+{
-+ __u32 diff;
-+
-+ if (ipsp->ips_replaywin == 0) /* replay shut off */
-+ return 1;
-+ if (seq == 0)
-+ return 0; /* first == 0 or wrapped */
-+
-+ /* new larger sequence number */
-+ if (seq > ipsp->ips_replaywin_lastseq) {
-+ diff = seq - ipsp->ips_replaywin_lastseq;
-+
-+ /* In win, set bit for this pkt */
-+ if (diff < ipsp->ips_replaywin)
-+ ipsp->ips_replaywin_bitmap =
-+ (ipsp->ips_replaywin_bitmap << diff) | 1;
-+ else
-+ /* This packet has way larger seq num */
-+ ipsp->ips_replaywin_bitmap = 1;
-+
-+ if(seq - ipsp->ips_replaywin_lastseq - 1 > ipsp->ips_replaywin_maxdiff) {
-+ ipsp->ips_replaywin_maxdiff = seq - ipsp->ips_replaywin_lastseq - 1;
-+ }
-+ ipsp->ips_replaywin_lastseq = seq;
-+ return 1; /* larger is good */
-+ }
-+ diff = ipsp->ips_replaywin_lastseq - seq;
-+
-+ /* too old or wrapped */ /* if wrapped, kill off SA? */
-+ if (diff >= ipsp->ips_replaywin) {
-+/*
-+ if(seq < 0.25*max && ipsp->ips_replaywin_lastseq > 0.75*max) {
-+ ipsec_sa_delchain(ipsp);
-+ }
-+*/
-+ return 0;
-+ }
-+ /* this packet already seen */
-+ if (ipsp->ips_replaywin_bitmap & (1 << diff))
-+ return 0;
-+ ipsp->ips_replaywin_bitmap |= (1 << diff); /* mark as seen */
-+ return 1; /* out of order but good */
-+}
-+
-+#ifdef CONFIG_IPSEC_AUTH_HMAC_MD5
-+struct auth_alg ipsec_rcv_md5[]={
-+ {MD5Init, MD5Update, MD5Final, AHMD596_ALEN}
-+};
-+
-+#endif /* CONFIG_IPSEC_AUTH_HMAC_MD5 */
-+
-+#ifdef CONFIG_IPSEC_AUTH_HMAC_SHA1
-+struct auth_alg ipsec_rcv_sha1[]={
-+ {SHA1Init, SHA1Update, SHA1Final, AHSHA196_ALEN}
-+};
-+#endif /* CONFIG_IPSEC_AUTH_HMAC_MD5 */
-+
-+enum ipsec_rcv_value
-+ipsec_rcv_decap_once(struct ipsec_rcv_state *irs, struct xform_functions *proto_funcs)
-+{
-+ int iphlen;
-+ unsigned char *dat;
-+ __u8 proto;
-+ struct in_addr ipsaddr;
-+ struct in_addr ipdaddr;
-+ int replay = 0; /* replay value in AH or ESP packet */
-+ struct ipsec_sa* ipsnext = NULL; /* next SA towards inside of packet */
-+ struct ipsec_sa *newipsp;
-+ struct iphdr *ipp;
-+ struct sk_buff *skb;
-+#ifdef CONFIG_IPSEC_ALG
-+ struct ipsec_alg_auth *ixt_a=NULL;
-+#endif /* CONFIG_IPSEC_ALG */
-+
-+ skb = irs->skb;
-+ irs->len = skb->len;
-+ dat = skb->data;
-+ ipp = irs->ipp;
-+ proto = ipp->protocol;
-+ ipsaddr.s_addr = ipp->saddr;
-+ addrtoa(ipsaddr, 0, irs->ipsaddr_txt, sizeof(irs->ipsaddr_txt));
-+ ipdaddr.s_addr = ipp->daddr;
-+ addrtoa(ipdaddr, 0, irs->ipdaddr_txt, sizeof(irs->ipdaddr_txt));
-+
-+ iphlen = ipp->ihl << 2;
-+ irs->iphlen=iphlen;
-+ ipp->check = 0; /* we know the sum is good */
-+
-+ KLIPS_PRINT(debug_rcv,
-+ "klips_debug:ipsec_rcv_decap_once: "
-+ "decap (%d) from %s -> %s\n",
-+ proto, irs->ipsaddr_txt, irs->ipdaddr_txt);
-+
-+ /*
-+ * Find tunnel control block and (indirectly) call the
-+ * appropriate tranform routine. The resulting sk_buf
-+ * is a valid IP packet ready to go through input processing.
-+ */
-+
-+ irs->said.dst.u.v4.sin_addr.s_addr = ipp->daddr;
-+ irs->said.dst.u.v4.sin_family = AF_INET;
-+
-+ if(proto_funcs->rcv_checks) {
-+ enum ipsec_rcv_value retval =
-+ (*proto_funcs->rcv_checks)(irs, skb);
-+
-+ if(retval < 0) {
-+ return retval;
-+ }
-+ }
-+
-+ irs->said.proto = proto;
-+ irs->sa_len = satot(&irs->said, 0, irs->sa, sizeof(irs->sa));
-+ if(irs->sa_len == 0) {
-+ strcpy(irs->sa, "(error)");
-+ }
-+
-+ newipsp = ipsec_sa_getbyid(&irs->said);
-+ if (newipsp == NULL) {
-+ KLIPS_PRINT(debug_rcv,
-+ "klips_debug:ipsec_rcv: "
-+ "no ipsec_sa for SA:%s: incoming packet with no SA dropped\n",
-+ irs->sa_len ? irs->sa : " (error)");
-+ if(irs->stats) {
-+ irs->stats->rx_dropped++;
-+ }
-+ return IPSEC_RCV_SAIDNOTFOUND;
-+ }
-+
-+ /* MCR - XXX this is bizarre. ipsec_sa_getbyid returned it, having incremented the refcount,
-+ * why in the world would we decrement it here?
-+
-+ ipsec_sa_put(irs->ipsp);*/ /* incomplete */
-+
-+ /* If it is in larval state, drop the packet, we cannot process yet. */
-+ if(newipsp->ips_state == SADB_SASTATE_LARVAL) {
-+ KLIPS_PRINT(debug_rcv,
-+ "klips_debug:ipsec_rcv: "
-+ "ipsec_sa in larval state, cannot be used yet, dropping packet.\n");
-+ if(irs->stats) {
-+ irs->stats->rx_dropped++;
-+ }
-+ ipsec_sa_put(newipsp);
-+ return IPSEC_RCV_SAIDNOTLIVE;
-+ }
-+
-+ if(newipsp->ips_state == SADB_SASTATE_DEAD) {
-+ KLIPS_PRINT(debug_rcv,
-+ "klips_debug:ipsec_rcv: "
-+ "ipsec_sa in dead state, cannot be used any more, dropping packet.\n");
-+ if(irs->stats) {
-+ irs->stats->rx_dropped++;
-+ }
-+ ipsec_sa_put(newipsp);
-+ return IPSEC_RCV_SAIDNOTLIVE;
-+ }
-+
-+ if(sysctl_ipsec_inbound_policy_check) {
-+ if(irs->ipp->saddr != ((struct sockaddr_in*)(newipsp->ips_addr_s))->sin_addr.s_addr) {
-+ KLIPS_PRINT(debug_rcv,
-+ "klips_debug:ipsec_rcv: "
-+ "SA:%s, src=%s of pkt does not agree with expected SA source address policy.\n",
-+ irs->sa_len ? irs->sa : " (error)",
-+ irs->ipsaddr_txt);
-+ if(irs->stats) {
-+ irs->stats->rx_dropped++;
-+ }
-+ ipsec_sa_put(newipsp);
-+ return IPSEC_RCV_FAILEDINBOUND;
-+ }
-+
-+ KLIPS_PRINT(debug_rcv,
-+ "klips_debug:ipsec_rcv: "
-+ "SA:%s, src=%s of pkt agrees with expected SA source address policy.\n",
-+ irs->sa_len ? irs->sa : " (error)",
-+ irs->ipsaddr_txt);
-+
-+ /*
-+ * at this point, we have looked up a new SA, and we want to make sure that if this
-+ * isn't the first SA in the list, that the previous SA actually points at this one.
-+ */
-+ if(irs->ipsp) {
-+ if(irs->ipsp->ips_inext != newipsp) {
-+ KLIPS_PRINT(debug_rcv,
-+ "klips_debug:ipsec_rcv: "
-+ "unexpected SA:%s: does not agree with ips->inext policy, dropped\n",
-+ irs->sa_len ? irs->sa : " (error)");
-+ if(irs->stats) {
-+ irs->stats->rx_dropped++;
-+ }
-+ ipsec_sa_put(newipsp);
-+ return IPSEC_RCV_FAILEDINBOUND;
-+ }
-+ KLIPS_PRINT(debug_rcv,
-+ "klips_debug:ipsec_rcv: "
-+ "SA:%s grouping from previous SA is OK.\n",
-+ irs->sa_len ? irs->sa : " (error)");
-+ } else {
-+ KLIPS_PRINT(debug_rcv,
-+ "klips_debug:ipsec_rcv: "
-+ "SA:%s First SA in group.\n",
-+ irs->sa_len ? irs->sa : " (error)");
-+ }
-+
-+ /*
-+ * previously, at this point, we checked if the back pointer from the new SA that
-+ * we just found matched the back pointer. But, we won't do this check anymore,
-+ * because we want to be able to nest SAs
-+ */
-+#ifdef CONFIG_IPSEC_NAT_TRAVERSAL
-+ KLIPS_PRINT(debug_rcv,
-+ "klips_debug:ipsec_rcv: "
-+ "natt_type=%u tdbp->ips_natt_type=%u : %s\n",
-+ irs->natt_type, newipsp->ips_natt_type,
-+ (irs->natt_type==newipsp->ips_natt_type)?"ok":"bad");
-+ if (irs->natt_type != newipsp->ips_natt_type) {
-+ KLIPS_PRINT(debug_rcv,
-+ "klips_debug:ipsec_rcv: "
-+ "SA:%s does not agree with expected NAT-T policy.\n",
-+ irs->sa_len ? irs->sa : " (error)");
-+ if(irs->stats) {
-+ irs->stats->rx_dropped++;
-+ }
-+ ipsec_sa_put(newipsp);
-+ return IPSEC_RCV_FAILEDINBOUND;
-+ }
-+#endif
-+ }
-+
-+ /* okay, SA checks out, so free any previous SA, and record a new one */
-+
-+ if(irs->ipsp) {
-+ ipsec_sa_put(irs->ipsp);
-+ }
-+ irs->ipsp=newipsp;
-+
-+ /* note that the outer code will free the irs->ipsp if there is an error */
-+
-+
-+ /* now check the lifetimes */
-+ if(ipsec_lifetime_check(&irs->ipsp->ips_life.ipl_bytes, "bytes",
-+ irs->sa, ipsec_life_countbased, ipsec_incoming,
-+ irs->ipsp) == ipsec_life_harddied ||
-+ ipsec_lifetime_check(&irs->ipsp->ips_life.ipl_addtime, "addtime",
-+ irs->sa, ipsec_life_timebased, ipsec_incoming,
-+ irs->ipsp) == ipsec_life_harddied ||
-+ ipsec_lifetime_check(&irs->ipsp->ips_life.ipl_addtime, "usetime",
-+ irs->sa, ipsec_life_timebased, ipsec_incoming,
-+ irs->ipsp) == ipsec_life_harddied ||
-+ ipsec_lifetime_check(&irs->ipsp->ips_life.ipl_packets, "packets",
-+ irs->sa, ipsec_life_countbased, ipsec_incoming,
-+ irs->ipsp) == ipsec_life_harddied) {
-+ ipsec_sa_delchain(irs->ipsp);
-+ if(irs->stats) {
-+ irs->stats->rx_dropped++;
-+ }
-+
-+ KLIPS_PRINT(debug_rcv,
-+ "klips_debug:ipsec_rcv_decap_once: "
-+ "decap (%d) failed lifetime check\n",
-+ proto);
-+
-+ return IPSEC_RCV_LIFETIMEFAILED;
-+ }
-+
-+#ifdef CONFIG_IPSEC_NAT_TRAVERSAL
-+ if ((irs->natt_type) &&
-+ ( (irs->ipp->saddr != (((struct sockaddr_in*)(newipsp->ips_addr_s))->sin_addr.s_addr)) ||
-+ (irs->natt_sport != newipsp->ips_natt_sport)
-+ )) {
-+ struct sockaddr sipaddr;
-+ /** Advertise NAT-T addr change to pluto **/
-+ sipaddr.sa_family = AF_INET;
-+ ((struct sockaddr_in*)&sipaddr)->sin_addr.s_addr = irs->ipp->saddr;
-+ ((struct sockaddr_in*)&sipaddr)->sin_port = htons(irs->natt_sport);
-+ pfkey_nat_t_new_mapping(newipsp, &sipaddr, irs->natt_sport);
-+ /**
-+ * Then allow or block packet depending on
-+ * sysctl_ipsec_inbound_policy_check.
-+ *
-+ * In all cases, pluto will update SA if new mapping is
-+ * accepted.
-+ */
-+ if (sysctl_ipsec_inbound_policy_check) {
-+ KLIPS_PRINT(debug_rcv,
-+ "klips_debug:ipsec_rcv: "
-+ "SA:%s, src=%s:%u of pkt does not agree with expected "
-+ "SA source address policy (pluto has been informed).\n",
-+ irs->sa_len ? irs->sa : " (error)",
-+ irs->ipsaddr_txt, irs->natt_sport);
-+ if(irs->stats) {
-+ irs->stats->rx_dropped++;
-+ }
-+ ipsec_sa_put(newipsp);
-+ return IPSEC_RCV_FAILEDINBOUND;
-+ }
-+ }
-+#endif
-+
-+ irs->authfuncs=NULL;
-+ /* authenticate, if required */
-+#ifdef CONFIG_IPSEC_ALG
-+ if ((ixt_a=irs->ipsp->ips_alg_auth)) {
-+ irs->authlen = AHHMAC_HASHLEN;
-+ irs->authfuncs = NULL;
-+ irs->ictx = NULL;
-+ irs->octx = NULL;
-+ irs->ictx_len = 0;
-+ irs->octx_len = 0;
-+ KLIPS_PRINT(debug_rcv,
-+ "klips_debug:ipsec_rcv: "
-+ "authalg=%d authlen=%d\n",
-+ irs->ipsp->ips_authalg,
-+ irs->authlen);
-+ } else
-+#endif /* CONFIG_IPSEC_ALG */
-+ switch(irs->ipsp->ips_authalg) {
-+#ifdef CONFIG_IPSEC_AUTH_HMAC_MD5
-+ case AH_MD5:
-+ irs->authlen = AHHMAC_HASHLEN;
-+ irs->authfuncs = ipsec_rcv_md5;
-+ irs->ictx = (void *)&((struct md5_ctx*)(irs->ipsp->ips_key_a))->ictx;
-+ irs->octx = (void *)&((struct md5_ctx*)(irs->ipsp->ips_key_a))->octx;
-+ irs->ictx_len = sizeof(((struct md5_ctx*)(irs->ipsp->ips_key_a))->ictx);
-+ irs->octx_len = sizeof(((struct md5_ctx*)(irs->ipsp->ips_key_a))->octx);
-+ break;
-+#endif /* CONFIG_IPSEC_AUTH_HMAC_MD5 */
-+#ifdef CONFIG_IPSEC_AUTH_HMAC_SHA1
-+ case AH_SHA:
-+ irs->authlen = AHHMAC_HASHLEN;
-+ irs->authfuncs = ipsec_rcv_sha1;
-+ irs->ictx = (void *)&((struct sha1_ctx*)(irs->ipsp->ips_key_a))->ictx;
-+ irs->octx = (void *)&((struct sha1_ctx*)(irs->ipsp->ips_key_a))->octx;
-+ irs->ictx_len = sizeof(((struct sha1_ctx*)(irs->ipsp->ips_key_a))->ictx);
-+ irs->octx_len = sizeof(((struct sha1_ctx*)(irs->ipsp->ips_key_a))->octx);
-+ break;
-+#endif /* CONFIG_IPSEC_AUTH_HMAC_SHA1 */
-+ case AH_NONE:
-+ irs->authlen = 0;
-+ irs->authfuncs = NULL;
-+ irs->ictx = NULL;
-+ irs->octx = NULL;
-+ irs->ictx_len = 0;
-+ irs->octx_len = 0;
-+ break;
-+ default:
-+ irs->ipsp->ips_errs.ips_alg_errs += 1;
-+ if(irs->stats) {
-+ irs->stats->rx_errors++;
-+ }
-+ return IPSEC_RCV_BADAUTH;
-+ }
-+
-+ irs->ilen = irs->len - iphlen - irs->authlen;
-+ if(irs->ilen <= 0) {
-+ KLIPS_PRINT(debug_rcv,
-+ "klips_debug:ipsec_rcv: "
-+ "runt %s packet with no data, dropping.\n",
-+ (proto == IPPROTO_ESP ? "esp" : "ah"));
-+ if(irs->stats) {
-+ irs->stats->rx_dropped++;
-+ }
-+ return IPSEC_RCV_BADLEN;
-+ }
-+
-+#ifdef CONFIG_IPSEC_ALG
-+ if(irs->authfuncs || ixt_a) {
-+#else
-+ if(irs->authfuncs) {
-+#endif
-+ unsigned char *authenticator = NULL;
-+
-+ if(proto_funcs->rcv_setup_auth) {
-+ enum ipsec_rcv_value retval
-+ = (*proto_funcs->rcv_setup_auth)(irs, skb,
-+ &replay,
-+ &authenticator);
-+ if(retval < 0) {
-+ return retval;
-+ }
-+ }
-+
-+ if(!authenticator) {
-+ irs->ipsp->ips_errs.ips_auth_errs += 1;
-+ if(irs->stats) {
-+ irs->stats->rx_dropped++;
-+ }
-+ return IPSEC_RCV_BADAUTH;
-+ }
-+
-+ if(!ipsec_checkreplaywindow(irs->ipsp, replay)) {
-+ irs->ipsp->ips_errs.ips_replaywin_errs += 1;
-+ KLIPS_PRINT(debug_rcv & DB_RX_REPLAY,
-+ "klips_debug:ipsec_rcv: "
-+ "duplicate frame from %s, packet dropped\n",
-+ irs->ipsaddr_txt);
-+ if(irs->stats) {
-+ irs->stats->rx_dropped++;
-+ }
-+ return IPSEC_RCV_REPLAYFAILED;
-+ }
-+
-+ /*
-+ * verify authenticator
-+ */
-+
-+ KLIPS_PRINT(debug_rcv,
-+ "klips_debug:ipsec_rcv: "
-+ "encalg = %d, authalg = %d.\n",
-+ irs->ipsp->ips_encalg,
-+ irs->ipsp->ips_authalg);
-+
-+ /* calculate authenticator */
-+ if(proto_funcs->rcv_calc_auth == NULL) {
-+ return IPSEC_RCV_BADAUTH;
-+ }
-+ (*proto_funcs->rcv_calc_auth)(irs, skb);
-+
-+ if (memcmp(irs->hash, authenticator, irs->authlen)) {
-+ irs->ipsp->ips_errs.ips_auth_errs += 1;
-+ KLIPS_PRINT(debug_rcv & DB_RX_INAU,
-+ "klips_debug:ipsec_rcv: "
-+ "auth failed on incoming packet from %s: hash=%08x%08x%08x auth=%08x%08x%08x, dropped\n",
-+ irs->ipsaddr_txt,
-+ ntohl(*(__u32*)&irs->hash[0]),
-+ ntohl(*(__u32*)&irs->hash[4]),
-+ ntohl(*(__u32*)&irs->hash[8]),
-+ ntohl(*(__u32*)authenticator),
-+ ntohl(*((__u32*)authenticator + 1)),
-+ ntohl(*((__u32*)authenticator + 2)));
-+ if(irs->stats) {
-+ irs->stats->rx_dropped++;
-+ }
-+ return IPSEC_RCV_AUTHFAILED;
-+ } else {
-+ KLIPS_PRINT(debug_rcv,
-+ "klips_debug:ipsec_rcv: "
-+ "authentication successful.\n");
-+ }
-+
-+ /* Crypto hygiene: clear memory used to calculate autheticator.
-+ * The length varies with the algorithm.
-+ */
-+ memset(irs->hash, 0, irs->authlen);
-+
-+ /* If the sequence number == 0, expire SA, it had rolled */
-+ if(irs->ipsp->ips_replaywin && !replay /* !irs->ipsp->ips_replaywin_lastseq */) {
-+ ipsec_sa_delchain(irs->ipsp);
-+ KLIPS_PRINT(debug_rcv,
-+ "klips_debug:ipsec_rcv: "
-+ "replay window counter rolled, expiring SA.\n");
-+ if(irs->stats) {
-+ irs->stats->rx_dropped++;
-+ }
-+ return IPSEC_RCV_REPLAYROLLED;
-+ }
-+
-+ /* now update the replay counter */
-+ if (!ipsec_updatereplaywindow(irs->ipsp, replay)) {
-+ irs->ipsp->ips_errs.ips_replaywin_errs += 1;
-+ KLIPS_PRINT(debug_rcv & DB_RX_REPLAY,
-+ "klips_debug:ipsec_rcv: "
-+ "duplicate frame from %s, packet dropped\n",
-+ irs->ipsaddr_txt);
-+ if(irs->stats) {
-+ irs->stats->rx_dropped++;
-+ }
-+ return IPSEC_RCV_REPLAYROLLED;
-+ }
-+ }
-+
-+ if(proto_funcs->rcv_decrypt) {
-+ enum ipsec_rcv_value retval =
-+ (*proto_funcs->rcv_decrypt)(irs);
-+
-+ if(retval != IPSEC_RCV_OK) {
-+ return retval;
-+ }
-+ }
-+
-+ /*
-+ * Adjust pointers
-+ */
-+ skb = irs->skb;
-+ irs->len = skb->len;
-+ dat = skb->data;
-+
-+#ifdef NET_21
-+/* skb->h.ipiph=(struct iphdr *)skb->data; */
-+ skb->nh.raw = skb->data;
-+ skb->h.raw = skb->nh.raw + (skb->nh.iph->ihl << 2);
-+
-+ memset(&(IPCB(skb)->opt), 0, sizeof(struct ip_options));
-+#else /* NET_21 */
-+ skb->h.iph=(struct iphdr *)skb->data;
-+ skb->ip_hdr=(struct iphdr *)skb->data;
-+ memset(skb->proto_priv, 0, sizeof(struct options));
-+#endif /* NET_21 */
-+
-+ ipp = (struct iphdr *)dat;
-+ ipsaddr.s_addr = ipp->saddr;
-+ addrtoa(ipsaddr, 0, irs->ipsaddr_txt, sizeof(irs->ipsaddr_txt));
-+ ipdaddr.s_addr = ipp->daddr;
-+ addrtoa(ipdaddr, 0, irs->ipdaddr_txt, sizeof(irs->ipdaddr_txt));
-+ /*
-+ * Discard the original ESP/AH header
-+ */
-+ ipp->protocol = irs->next_header;
-+
-+ ipp->check = 0; /* NOTE: this will be included in checksum */
-+ ipp->check = ip_fast_csum((unsigned char *)dat, iphlen >> 2);
-+
-+ KLIPS_PRINT(debug_rcv & DB_RX_PKTRX,
-+ "klips_debug:ipsec_rcv: "
-+ "after <%s%s%s>, SA:%s:\n",
-+ IPS_XFORM_NAME(irs->ipsp),
-+ irs->sa_len ? irs->sa : " (error)");
-+ KLIPS_IP_PRINT(debug_rcv & DB_RX_PKTRX, ipp);
-+
-+ skb->protocol = htons(ETH_P_IP);
-+ skb->ip_summed = 0;
-+
-+ ipsnext = irs->ipsp->ips_inext;
-+ if(sysctl_ipsec_inbound_policy_check) {
-+ if(ipsnext) {
-+ if(
-+ ipp->protocol != IPPROTO_AH
-+ && ipp->protocol != IPPROTO_ESP
-+#ifdef CONFIG_IPSEC_IPCOMP
-+ && ipp->protocol != IPPROTO_COMP
-+ && (ipsnext->ips_said.proto != IPPROTO_COMP
-+ || ipsnext->ips_inext)
-+#endif /* CONFIG_IPSEC_IPCOMP */
-+ && ipp->protocol != IPPROTO_IPIP
-+ && ipp->protocol != 0xFE /* added to support heartbeats to AT&T SIG/GIG */
-+ ) {
-+ KLIPS_PRINT(debug_rcv,
-+ "klips_debug:ipsec_rcv: "
-+ "packet with incomplete policy dropped, last successful SA:%s.\n",
-+ irs->sa_len ? irs->sa : " (error)");
-+ if(irs->stats) {
-+ irs->stats->rx_dropped++;
-+ }
-+ return IPSEC_RCV_FAILEDINBOUND;
-+ }
-+ KLIPS_PRINT(debug_rcv,
-+ "klips_debug:ipsec_rcv: "
-+ "SA:%s, Another IPSEC header to process.\n",
-+ irs->sa_len ? irs->sa : " (error)");
-+ } else {
-+ KLIPS_PRINT(debug_rcv,
-+ "klips_debug:ipsec_rcv: "
-+ "No ips_inext from this SA:%s.\n",
-+ irs->sa_len ? irs->sa : " (error)");
-+ }
-+ }
-+
-+#ifdef CONFIG_IPSEC_IPCOMP
-+ /* update ipcomp ratio counters, even if no ipcomp packet is present */
-+ if (ipsnext
-+ && ipsnext->ips_said.proto == IPPROTO_COMP
-+ && ipp->protocol != IPPROTO_COMP) {
-+ ipsnext->ips_comp_ratio_cbytes += ntohs(ipp->tot_len);
-+ ipsnext->ips_comp_ratio_dbytes += ntohs(ipp->tot_len);
-+ }
-+#endif /* CONFIG_IPSEC_IPCOMP */
-+
-+ irs->ipsp->ips_life.ipl_bytes.ipl_count += irs->len;
-+ irs->ipsp->ips_life.ipl_bytes.ipl_last = irs->len;
-+
-+ if(!irs->ipsp->ips_life.ipl_usetime.ipl_count) {
-+ irs->ipsp->ips_life.ipl_usetime.ipl_count = jiffies / HZ;
-+ }
-+ irs->ipsp->ips_life.ipl_usetime.ipl_last = jiffies / HZ;
-+ irs->ipsp->ips_life.ipl_packets.ipl_count += 1;
-+
-+#ifdef CONFIG_NETFILTER
-+ if(proto == IPPROTO_ESP || proto == IPPROTO_AH) {
-+ skb->nfmark = (skb->nfmark & (~(IPsecSAref2NFmark(IPSEC_SA_REF_MASK))))
-+ | IPsecSAref2NFmark(IPsecSA2SAref(irs->ipsp));
-+ KLIPS_PRINT(debug_rcv & DB_RX_PKTRX,
-+ "klips_debug:ipsec_rcv: "
-+ "%s SA sets skb->nfmark=0x%x.\n",
-+ proto == IPPROTO_ESP ? "ESP" : "AH",
-+ (unsigned)skb->nfmark);
-+ }
-+#endif /* CONFIG_NETFILTER */
-+
-+ return IPSEC_RCV_OK;
-+}
-+
-+
-+int
-+#ifdef PROTO_HANDLER_SINGLE_PARM
-+ipsec_rcv(struct sk_buff *skb)
-+#else /* PROTO_HANDLER_SINGLE_PARM */
-+#ifdef NET_21
-+ipsec_rcv(struct sk_buff *skb, unsigned short xlen)
-+#else /* NET_21 */
-+ipsec_rcv(struct sk_buff *skb, struct device *dev, struct options *opt,
-+ __u32 daddr_unused, unsigned short xlen, __u32 saddr,
-+ int redo, struct inet_protocol *protocol)
-+#endif /* NET_21 */
-+#endif /* PROTO_HANDLER_SINGLE_PARM */
-+{
-+#ifdef NET_21
-+#ifdef CONFIG_IPSEC_DEBUG
-+ struct device *dev = skb->dev;
-+#endif /* CONFIG_IPSEC_DEBUG */
-+#endif /* NET_21 */
-+ unsigned char protoc;
-+ struct iphdr *ipp;
-+ struct ipsec_sa *ipsp = NULL;
-+ struct net_device_stats *stats = NULL; /* This device's statistics */
-+ struct device *ipsecdev = NULL, *prvdev;
-+ struct ipsecpriv *prv;
-+ char name[9];
-+ int i;
-+ struct in_addr ipsaddr;
-+ struct in_addr ipdaddr;
-+
-+ struct ipsec_sa* ipsnext = NULL; /* next SA towards inside of packet */
-+ struct ipsec_rcv_state irs;
-+
-+ /* Don't unlink in the middle of a turnaround */
-+ MOD_INC_USE_COUNT;
-+
-+ memset(&irs, 0, sizeof(struct ipsec_rcv_state));
-+
-+ if (skb == NULL) {
-+ KLIPS_PRINT(debug_rcv,
-+ "klips_debug:ipsec_rcv: "
-+ "NULL skb passed in.\n");
-+ goto rcvleave;
-+ }
-+
-+ if (skb->data == NULL) {
-+ KLIPS_PRINT(debug_rcv,
-+ "klips_debug:ipsec_rcv: "
-+ "NULL skb->data passed in, packet is bogus, dropping.\n");
-+ goto rcvleave;
-+ }
-+
-+#ifdef CONFIG_IPSEC_NAT_TRAVERSAL
-+ if (skb->sk && skb->nh.iph && skb->nh.iph->protocol==IPPROTO_UDP) {
-+ /**
-+ * Packet comes from udp_queue_rcv_skb so it is already defrag,
-+ * checksum verified, ... (ie safe to use)
-+ *
-+ * If the packet is not for us, return -1 and udp_queue_rcv_skb
-+ * will continue to handle it (do not kfree skb !!).
-+ */
-+#ifndef UDP_OPT_IN_SOCK
-+ struct udp_opt {
-+ __u32 esp_in_udp;
-+ };
-+ struct udp_opt *tp = (struct udp_opt *)&(skb->sk->tp_pinfo.af_tcp);
-+#else
-+ struct udp_opt *tp = &(skb->sk->tp_pinfo.af_udp);
-+#endif
-+ struct iphdr *ip = (struct iphdr *)skb->nh.iph;
-+ struct udphdr *udp = (struct udphdr *)((__u32 *)ip+ip->ihl);
-+ __u8 *udpdata = (__u8 *)udp + sizeof(struct udphdr);
-+ __u32 *udpdata32 = (__u32 *)udpdata;
-+
-+ irs.natt_sport = ntohs(udp->source);
-+ irs.natt_dport = ntohs(udp->dest);
-+
-+ KLIPS_PRINT(debug_rcv,
-+ "klips_debug:ipsec_rcv: "
-+ "suspected ESPinUDP packet (NAT-Traversal) [%d].\n",
-+ tp->esp_in_udp);
-+ KLIPS_IP_PRINT(debug_rcv, ip);
-+
-+ if (udpdata < skb->tail) {
-+ unsigned int len = skb->tail - udpdata;
-+ if ((len==1) && (udpdata[0]==0xff)) {
-+ KLIPS_PRINT(debug_rcv,
-+ "klips_debug:ipsec_rcv: "
-+ /* not IPv6 compliant message */
-+ "NAT-keepalive from %d.%d.%d.%d.\n", NIPQUAD(ip->saddr));
-+ goto rcvleave;
-+ }
-+ else if ( (tp->esp_in_udp == ESPINUDP_WITH_NON_IKE) &&
-+ (len > (2*sizeof(__u32) + sizeof(struct esphdr))) &&
-+ (udpdata32[0]==0) && (udpdata32[1]==0) ) {
-+ /* ESP Packet with Non-IKE header */
-+ KLIPS_PRINT(debug_rcv,
-+ "klips_debug:ipsec_rcv: "
-+ "ESPinUDP pkt with Non-IKE - spi=0x%x\n",
-+ ntohl(udpdata32[2]));
-+ irs.natt_type = ESPINUDP_WITH_NON_IKE;
-+ irs.natt_len = sizeof(struct udphdr)+(2*sizeof(__u32));
-+ }
-+ else if ( (tp->esp_in_udp == ESPINUDP_WITH_NON_ESP) &&
-+ (len > sizeof(struct esphdr)) &&
-+ (udpdata32[0]!=0) ) {
-+ /* ESP Packet without Non-ESP header */
-+ irs.natt_type = ESPINUDP_WITH_NON_ESP;
-+ irs.natt_len = sizeof(struct udphdr);
-+ KLIPS_PRINT(debug_rcv,
-+ "klips_debug:ipsec_rcv: "
-+ "ESPinUDP pkt without Non-ESP - spi=0x%x\n",
-+ ntohl(udpdata32[0]));
-+ }
-+ else {
-+ KLIPS_PRINT(debug_rcv,
-+ "klips_debug:ipsec_rcv: "
-+ "IKE packet - not handled here\n");
-+ MOD_DEC_USE_COUNT;
-+ return -1;
-+ }
-+ }
-+ else {
-+ MOD_DEC_USE_COUNT;
-+ return -1;
-+ }
-+ }
-+#endif
-+
-+#ifdef IPH_is_SKB_PULLED
-+ /* In Linux 2.4.4, the IP header has been skb_pull()ed before the
-+ packet is passed to us. So we'll skb_push() to get back to it. */
-+ if (skb->data == skb->h.raw) {
-+ skb_push(skb, skb->h.raw - skb->nh.raw);
-+ }
-+#endif /* IPH_is_SKB_PULLED */
-+
-+ /* dev->hard_header_len is unreliable and should not be used */
-+ irs.hard_header_len = skb->mac.raw ? (skb->data - skb->mac.raw) : 0;
-+ if((irs.hard_header_len < 0) || (irs.hard_header_len > skb_headroom(skb)))
-+ irs.hard_header_len = 0;
-+
-+#ifdef NET_21
-+ /* if skb was cloned (most likely due to a packet sniffer such as
-+ tcpdump being momentarily attached to the interface), make
-+ a copy of our own to modify */
-+ if(skb_cloned(skb)) {
-+ /* include any mac header while copying.. */
-+ if(skb_headroom(skb) < irs.hard_header_len) {
-+ printk(KERN_WARNING "klips_error:ipsec_rcv: "
-+ "tried to skb_push hhlen=%d, %d available. This should never happen, please report.\n",
-+ irs.hard_header_len,
-+ skb_headroom(skb));
-+ goto rcvleave;
-+ }
-+ skb_push(skb, irs.hard_header_len);
-+ if
-+#ifdef SKB_COW_NEW
-+ (skb_cow(skb, skb_headroom(skb)) != 0)
-+#else /* SKB_COW_NEW */
-+ ((skb = skb_cow(skb, skb_headroom(skb))) == NULL)
-+#endif /* SKB_COW_NEW */
-+ {
-+ goto rcvleave;
-+ }
-+ if(skb->len < irs.hard_header_len) {
-+ printk(KERN_WARNING "klips_error:ipsec_rcv: "
-+ "tried to skb_pull hhlen=%d, %d available. This should never happen, please report.\n",
-+ irs.hard_header_len,
-+ skb->len);
-+ goto rcvleave;
-+ }
-+ skb_pull(skb, irs.hard_header_len);
-+ }
-+
-+#endif /* NET_21 */
-+
-+#if IP_FRAGMENT_LINEARIZE
-+ /* In Linux 2.4.4, we may have to reassemble fragments. They are
-+ not assembled automatically to save TCP from having to copy
-+ twice.
-+ */
-+ if (skb_is_nonlinear(skb)) {
-+ if (skb_linearize(skb, GFP_ATOMIC) != 0) {
-+ goto rcvleave;
-+ }
-+ }
-+#endif /* IP_FRAGMENT_LINEARIZE */
-+
-+#ifdef CONFIG_IPSEC_NAT_TRAVERSAL
-+ if (irs.natt_len) {
-+ /**
-+ * Now, we are sure packet is ESPinUDP. Remove natt_len bytes from
-+ * packet and modify protocol to ESP.
-+ */
-+ if (((unsigned char *)skb->data > (unsigned char *)skb->nh.iph) &&
-+ ((unsigned char *)skb->nh.iph > (unsigned char *)skb->head)) {
-+ unsigned int _len = (unsigned char *)skb->data -
-+ (unsigned char *)skb->nh.iph;
-+ KLIPS_PRINT(debug_rcv,
-+ "klips_debug:ipsec_rcv: adjusting skb: skb_push(%u)\n",
-+ _len);
-+ skb_push(skb, _len);
-+ }
-+ KLIPS_PRINT(debug_rcv,
-+ "klips_debug:ipsec_rcv: "
-+ "removing %d bytes from ESPinUDP packet\n", irs.natt_len);
-+ ipp = (struct iphdr *)skb->data;
-+ irs.iphlen = ipp->ihl << 2;
-+ ipp->tot_len = htons(ntohs(ipp->tot_len) - irs.natt_len);
-+ if (skb->len < irs.iphlen + irs.natt_len) {
-+ printk(KERN_WARNING
-+ "klips_error:ipsec_rcv: "
-+ "ESPinUDP packet is too small (%d < %d+%d). "
-+ "This should never happen, please report.\n",
-+ (int)(skb->len), irs.iphlen, irs.natt_len);
-+ goto rcvleave;
-+ }
-+ memmove(skb->data + irs.natt_len, skb->data, irs.iphlen);
-+ skb_pull(skb, irs.natt_len);
-+
-+ /* update nh.iph */
-+ ipp = skb->nh.iph = (struct iphdr *)skb->data;
-+
-+ /* modify protocol */
-+ ipp->protocol = IPPROTO_ESP;
-+
-+ skb->sk = NULL;
-+
-+ KLIPS_IP_PRINT(debug_rcv, skb->nh.iph);
-+ }
-+#endif
-+
-+ ipp = skb->nh.iph;
-+ ipsaddr.s_addr = ipp->saddr;
-+ addrtoa(ipsaddr, 0, irs.ipsaddr_txt, sizeof(irs.ipsaddr_txt));
-+ ipdaddr.s_addr = ipp->daddr;
-+ addrtoa(ipdaddr, 0, irs.ipdaddr_txt, sizeof(irs.ipdaddr_txt));
-+ irs.iphlen = ipp->ihl << 2;
-+
-+ KLIPS_PRINT(debug_rcv,
-+ "klips_debug:ipsec_rcv: "
-+ "<<< Info -- ");
-+ KLIPS_PRINTMORE(debug_rcv && skb->dev, "skb->dev=%s ",
-+ skb->dev->name ? skb->dev->name : "NULL");
-+ KLIPS_PRINTMORE(debug_rcv && dev, "dev=%s ",
-+ dev->name ? dev->name : "NULL");
-+ KLIPS_PRINTMORE(debug_rcv, "\n");
-+
-+ KLIPS_PRINT(debug_rcv && !(skb->dev && dev && (skb->dev == dev)),
-+ "klips_debug:ipsec_rcv: "
-+ "Informational -- **if this happens, find out why** skb->dev:%s is not equal to dev:%s\n",
-+ skb->dev ? (skb->dev->name ? skb->dev->name : "NULL") : "NULL",
-+ dev ? (dev->name ? dev->name : "NULL") : "NULL");
-+
-+ protoc = ipp->protocol;
-+#ifndef NET_21
-+ if((!protocol) || (protocol->protocol != protoc)) {
-+ KLIPS_PRINT(debug_rcv & DB_RX_IPSA,
-+ "klips_debug:ipsec_rcv: "
-+ "protocol arg is NULL or unequal to the packet contents, this is odd, using value in packet.\n");
-+ }
-+#endif /* !NET_21 */
-+
-+ if( (protoc != IPPROTO_AH) &&
-+#ifdef CONFIG_IPSEC_IPCOMP_disabled_until_we_register_IPCOMP_HANDLER
-+ (protoc != IPPROTO_COMP) &&
-+#endif /* CONFIG_IPSEC_IPCOMP */
-+ (protoc != IPPROTO_ESP) ) {
-+ KLIPS_PRINT(debug_rcv & DB_RX_IPSA,
-+ "klips_debug:ipsec_rcv: Why the hell is someone "
-+ "passing me a non-ipsec protocol = %d packet? -- dropped.\n",
-+ protoc);
-+ goto rcvleave;
-+ }
-+
-+ if(skb->dev) {
-+ for(i = 0; i < IPSEC_NUM_IF; i++) {
-+ sprintf(name, IPSEC_DEV_FORMAT, i);
-+ if(!strcmp(name, skb->dev->name)) {
-+ prv = (struct ipsecpriv *)(skb->dev->priv);
-+ if(prv) {
-+ stats = (struct net_device_stats *) &(prv->mystats);
-+ }
-+ ipsecdev = skb->dev;
-+ KLIPS_PRINT(debug_rcv,
-+ "klips_debug:ipsec_rcv: "
-+ "Info -- pkt already proc'ed a group of ipsec headers, processing next group of ipsec headers.\n");
-+ break;
-+ }
-+ if((ipsecdev = __ipsec_dev_get(name)) == NULL) {
-+ KLIPS_PRINT(debug_rcv,
-+ "klips_error:ipsec_rcv: "
-+ "device %s does not exist\n",
-+ name);
-+ }
-+ prv = ipsecdev ? (struct ipsecpriv *)(ipsecdev->priv) : NULL;
-+ prvdev = prv ? (struct device *)(prv->dev) : NULL;
-+
-+#if 0
-+ KLIPS_PRINT(debug_rcv && prvdev,
-+ "klips_debug:ipsec_rcv: "
-+ "physical device for device %s is %s\n",
-+ name,
-+ prvdev->name);
-+#endif
-+ if(prvdev && skb->dev &&
-+ !strcmp(prvdev->name, skb->dev->name)) {
-+ stats = prv ? ((struct net_device_stats *) &(prv->mystats)) : NULL;
-+ skb->dev = ipsecdev;
-+ KLIPS_PRINT(debug_rcv && prvdev,
-+ "klips_debug:ipsec_rcv: "
-+ "assigning packet ownership to virtual device %s from physical device %s.\n",
-+ name, prvdev->name);
-+ if(stats) {
-+ stats->rx_packets++;
-+ }
-+ break;
-+ }
-+ }
-+ } else {
-+ KLIPS_PRINT(debug_rcv,
-+ "klips_debug:ipsec_rcv: "
-+ "device supplied with skb is NULL\n");
-+ }
-+
-+ if(stats == NULL) {
-+ KLIPS_PRINT((debug_rcv),
-+ "klips_error:ipsec_rcv: "
-+ "packet received from physical I/F (%s) not connected to ipsec I/F. Cannot record stats. May not have SA for decoding. Is IPSEC traffic expected on this I/F? Check routing.\n",
-+ skb->dev ? (skb->dev->name ? skb->dev->name : "NULL") : "NULL");
-+ }
-+
-+ KLIPS_IP_PRINT(debug_rcv, ipp);
-+
-+ /* begin decapsulating loop here */
-+
-+ /*
-+ The spinlock is to prevent any other process from
-+ accessing or deleting the ipsec_sa hash table or any of the
-+ ipsec_sa s while we are using and updating them.
-+
-+ This is not optimal, but was relatively straightforward
-+ at the time. A better way to do it has been planned for
-+ more than a year, to lock the hash table and put reference
-+ counts on each ipsec_sa instead. This is not likely to happen
-+ in KLIPS1 unless a volunteer contributes it, but will be
-+ designed into KLIPS2.
-+ */
-+ spin_lock(&tdb_lock);
-+
-+ /* set up for decap loop */
-+ irs.stats= stats;
-+ irs.ipp = ipp;
-+ irs.ipsp = NULL;
-+ irs.ilen = 0;
-+ irs.authlen=0;
-+ irs.authfuncs=NULL;
-+ irs.skb = skb;
-+
-+ do {
-+ int decap_stat;
-+ struct xform_functions *proto_funcs;
-+
-+ switch(irs.ipp->protocol) {
-+ case IPPROTO_ESP:
-+ proto_funcs = esp_xform_funcs;
-+ break;
-+
-+#ifdef CONFIG_IPSEC_AH
-+ case IPPROTO_AH:
-+ proto_funcs = ah_xform_funcs;
-+ break;
-+#endif /* !CONFIG_IPSEC_AH */
-+
-+#ifdef CONFIG_IPSEC_IPCOMP
-+ case IPPROTO_COMP:
-+ proto_funcs = ipcomp_xform_funcs;
-+ break;
-+#endif /* !CONFIG_IPSEC_IPCOMP */
-+ default:
-+ if(irs.stats) {
-+ irs.stats->rx_errors++;
-+ }
-+ decap_stat = IPSEC_RCV_BADPROTO;
-+ goto rcvleave;
-+ }
-+
-+ decap_stat = ipsec_rcv_decap_once(&irs, proto_funcs);
-+
-+ if(decap_stat != IPSEC_RCV_OK) {
-+ spin_unlock(&tdb_lock);
-+ KLIPS_PRINT(debug_rcv,
-+ "klips_debug:ipsec_rcv: decap_once failed: %d\n",
-+ decap_stat);
-+
-+ goto rcvleave;
-+ }
-+ /* end decapsulation loop here */
-+ } while( (irs.ipp->protocol == IPPROTO_ESP )
-+ || (irs.ipp->protocol == IPPROTO_AH )
-+#ifdef CONFIG_IPSEC_IPCOMP
-+ || (irs.ipp->protocol == IPPROTO_COMP)
-+#endif /* CONFIG_IPSEC_IPCOMP */
-+ );
-+
-+ /* set up for decap loop */
-+ ipp =irs.ipp;
-+ ipsp =irs.ipsp;
-+ ipsnext = ipsp->ips_inext;
-+ skb = irs.skb;
-+
-+ /* if there is an IPCOMP, but we don't have an IPPROTO_COMP,
-+ * then we can just skip it
-+ */
-+#ifdef CONFIG_IPSEC_IPCOMP
-+ if(ipsnext && ipsnext->ips_said.proto == IPPROTO_COMP) {
-+ ipsp = ipsnext;
-+ ipsnext = ipsp->ips_inext;
-+ }
-+#endif /* CONFIG_IPSEC_IPCOMP */
-+
-+#ifdef CONFIG_IPSEC_NAT_TRAVERSAL
-+ if ((irs.natt_type) && (ipp->protocol != IPPROTO_IPIP)) {
-+ /**
-+ * NAT-Traversal and Transport Mode:
-+ * we need to correct TCP/UDP checksum
-+ *
-+ * If we've got NAT-OA, we can fix checksum without recalculation.
-+ */
-+ __u32 natt_oa = ipsp->ips_natt_oa ?
-+ ((struct sockaddr_in*)(ipsp->ips_natt_oa))->sin_addr.s_addr : 0;
-+ __u16 pkt_len = skb->tail - (unsigned char *)ipp;
-+ __u16 data_len = pkt_len - (ipp->ihl << 2);
-+
-+ switch (ipp->protocol) {
-+ case IPPROTO_TCP:
-+ if (data_len >= sizeof(struct tcphdr)) {
-+ struct tcphdr *tcp = (struct tcphdr *)((__u32 *)ipp+ipp->ihl);
-+ if (natt_oa) {
-+ __u32 buff[2] = { ~natt_oa, ipp->saddr };
-+ KLIPS_PRINT(debug_rcv,
-+ "klips_debug:ipsec_rcv: "
-+ "NAT-T & TRANSPORT: "
-+ "fix TCP checksum using NAT-OA\n");
-+ tcp->check = csum_fold(
-+ csum_partial((unsigned char *)buff, sizeof(buff),
-+ tcp->check^0xffff));
-+ }
-+ else {
-+ KLIPS_PRINT(debug_rcv,
-+ "klips_debug:ipsec_rcv: "
-+ "NAT-T & TRANSPORT: recalc TCP checksum\n");
-+ if (pkt_len > (ntohs(ipp->tot_len)))
-+ data_len -= (pkt_len - ntohs(ipp->tot_len));
-+ tcp->check = 0;
-+ tcp->check = csum_tcpudp_magic(ipp->saddr, ipp->daddr,
-+ data_len, IPPROTO_TCP,
-+ csum_partial((unsigned char *)tcp, data_len, 0));
-+ }
-+ }
-+ else {
-+ KLIPS_PRINT(debug_rcv,
-+ "klips_debug:ipsec_rcv: "
-+ "NAT-T & TRANSPORT: can't fix TCP checksum\n");
-+ }
-+ break;
-+ case IPPROTO_UDP:
-+ if (data_len >= sizeof(struct udphdr)) {
-+ struct udphdr *udp = (struct udphdr *)((__u32 *)ipp+ipp->ihl);
-+ if (udp->check == 0) {
-+ KLIPS_PRINT(debug_rcv,
-+ "klips_debug:ipsec_rcv: "
-+ "NAT-T & TRANSPORT: UDP checksum already 0\n");
-+ }
-+ else if (natt_oa) {
-+ __u32 buff[2] = { ~natt_oa, ipp->saddr };
-+ KLIPS_PRINT(debug_rcv,
-+ "klips_debug:ipsec_rcv: "
-+ "NAT-T & TRANSPORT: "
-+ "fix UDP checksum using NAT-OA\n");
-+ udp->check = csum_fold(
-+ csum_partial((unsigned char *)buff, sizeof(buff),
-+ udp->check^0xffff));
-+ }
-+ else {
-+ KLIPS_PRINT(debug_rcv,
-+ "klips_debug:ipsec_rcv: "
-+ "NAT-T & TRANSPORT: zero UDP checksum\n");
-+ udp->check = 0;
-+ }
-+ }
-+ else {
-+ KLIPS_PRINT(debug_rcv,
-+ "klips_debug:ipsec_rcv: "
-+ "NAT-T & TRANSPORT: can't fix UDP checksum\n");
-+ }
-+ break;
-+ default:
-+ KLIPS_PRINT(debug_rcv,
-+ "klips_debug:ipsec_rcv: "
-+ "NAT-T & TRANSPORT: non TCP/UDP packet -- do nothing\n");
-+ break;
-+ }
-+ }
-+#endif
-+
-+ /*
-+ * XXX this needs to be locked from when it was first looked
-+ * up in the decapsulation loop. Perhaps it is better to put
-+ * the IPIP decap inside the loop.
-+ */
-+ if(ipsnext) {
-+ ipsp = ipsnext;
-+ irs.sa_len = satot(&irs.said, 0, irs.sa, sizeof(irs.sa));
-+ if((ipp->protocol != IPPROTO_IPIP) &&
-+ ( 0xFE != ipp->protocol)) { /* added to support AT&T heartbeats to SIG/GIG */
-+ spin_unlock(&tdb_lock);
-+ KLIPS_PRINT(debug_rcv,
-+ "klips_debug:ipsec_rcv: "
-+ "SA:%s, Hey! How did this get through? Dropped.\n",
-+ irs.sa_len ? irs.sa : " (error)");
-+ if(stats) {
-+ stats->rx_dropped++;
-+ }
-+ goto rcvleave;
-+ }
-+ if(sysctl_ipsec_inbound_policy_check) {
-+ if((ipsnext = ipsp->ips_inext)) {
-+ char sa2[SATOT_BUF];
-+ size_t sa_len2;
-+ sa_len2 = satot(&ipsnext->ips_said, 0, sa2, sizeof(sa2));
-+ spin_unlock(&tdb_lock);
-+ KLIPS_PRINT(debug_rcv,
-+ "klips_debug:ipsec_rcv: "
-+ "unexpected SA:%s after IPIP SA:%s\n",
-+ sa_len2 ? sa2 : " (error)",
-+ irs.sa_len ? irs.sa : " (error)");
-+ if(stats) {
-+ stats->rx_dropped++;
-+ }
-+ goto rcvleave;
-+ }
-+ if(ipp->saddr != ((struct sockaddr_in*)(ipsp->ips_addr_s))->sin_addr.s_addr) {
-+ spin_unlock(&tdb_lock);
-+ KLIPS_PRINT(debug_rcv,
-+ "klips_debug:ipsec_rcv: "
-+ "SA:%s, src=%s of pkt does not agree with expected SA source address policy.\n",
-+ irs.sa_len ? irs.sa : " (error)",
-+ irs.ipsaddr_txt);
-+ if(stats) {
-+ stats->rx_dropped++;
-+ }
-+ goto rcvleave;
-+ }
-+ }
-+
-+ if(ipp->protocol == IPPROTO_IPIP) /* added to support AT&T heartbeats to SIG/GIG */
-+ {
-+ /*
-+ * XXX this needs to be locked from when it was first looked
-+ * up in the decapsulation loop. Perhaps it is better to put
-+ * the IPIP decap inside the loop.
-+ */
-+ ipsp->ips_life.ipl_bytes.ipl_count += skb->len;
-+ ipsp->ips_life.ipl_bytes.ipl_last = skb->len;
-+
-+ if(!ipsp->ips_life.ipl_usetime.ipl_count) {
-+ ipsp->ips_life.ipl_usetime.ipl_count = jiffies / HZ;
-+ }
-+ ipsp->ips_life.ipl_usetime.ipl_last = jiffies / HZ;
-+ ipsp->ips_life.ipl_packets.ipl_count += 1;
-+
-+ if(skb->len < irs.iphlen) {
-+ spin_unlock(&tdb_lock);
-+ printk(KERN_WARNING "klips_debug:ipsec_rcv: "
-+ "tried to skb_pull iphlen=%d, %d available. This should never happen, please report.\n",
-+ irs.iphlen,
-+ (int)(skb->len));
-+
-+ goto rcvleave;
-+ }
-+ skb_pull(skb, irs.iphlen);
-+
-+#ifdef NET_21
-+ ipp = (struct iphdr *)skb->nh.raw = skb->data;
-+ skb->h.raw = skb->nh.raw + (skb->nh.iph->ihl << 2);
-+
-+ memset(&(IPCB(skb)->opt), 0, sizeof(struct ip_options));
-+#else /* NET_21 */
-+ ipp = skb->ip_hdr = skb->h.iph = (struct iphdr *)skb->data;
-+
-+ memset(skb->proto_priv, 0, sizeof(struct options));
-+#endif /* NET_21 */
-+ ipsaddr.s_addr = ipp->saddr;
-+ addrtoa(ipsaddr, 0, irs.ipsaddr_txt, sizeof(irs.ipsaddr_txt));
-+ ipdaddr.s_addr = ipp->daddr;
-+ addrtoa(ipdaddr, 0, irs.ipdaddr_txt, sizeof(irs.ipdaddr_txt));
-+
-+ skb->protocol = htons(ETH_P_IP);
-+ skb->ip_summed = 0;
-+ KLIPS_PRINT(debug_rcv & DB_RX_PKTRX,
-+ "klips_debug:ipsec_rcv: "
-+ "IPIP tunnel stripped.\n");
-+ KLIPS_IP_PRINT(debug_rcv & DB_RX_PKTRX, ipp);
-+ }
-+
-+ if(sysctl_ipsec_inbound_policy_check
-+ /*
-+ Note: "xor" (^) logically replaces "not equal"
-+ (!=) and "bitwise or" (|) logically replaces
-+ "boolean or" (||). This is done to speed up
-+ execution by doing only bitwise operations and
-+ no branch operations
-+ */
-+ && (((ipp->saddr & ipsp->ips_mask_s.u.v4.sin_addr.s_addr)
-+ ^ ipsp->ips_flow_s.u.v4.sin_addr.s_addr)
-+ | ((ipp->daddr & ipsp->ips_mask_d.u.v4.sin_addr.s_addr)
-+ ^ ipsp->ips_flow_d.u.v4.sin_addr.s_addr)) )
-+ {
-+ char sflow_txt[SUBNETTOA_BUF], dflow_txt[SUBNETTOA_BUF];
-+
-+ subnettoa(ipsp->ips_flow_s.u.v4.sin_addr,
-+ ipsp->ips_mask_s.u.v4.sin_addr,
-+ 0, sflow_txt, sizeof(sflow_txt));
-+ subnettoa(ipsp->ips_flow_d.u.v4.sin_addr,
-+ ipsp->ips_mask_d.u.v4.sin_addr,
-+ 0, dflow_txt, sizeof(dflow_txt));
-+ spin_unlock(&tdb_lock);
-+ KLIPS_PRINT(debug_rcv,
-+ "klips_debug:ipsec_rcv: "
-+ "SA:%s, inner tunnel policy [%s -> %s] does not agree with pkt contents [%s -> %s].\n",
-+ irs.sa_len ? irs.sa : " (error)",
-+ sflow_txt,
-+ dflow_txt,
-+ irs.ipsaddr_txt,
-+ irs.ipdaddr_txt);
-+ if(stats) {
-+ stats->rx_dropped++;
-+ }
-+ goto rcvleave;
-+ }
-+#ifdef CONFIG_NETFILTER
-+ skb->nfmark = (skb->nfmark & (~(IPsecSAref2NFmark(IPSEC_SA_REF_TABLE_MASK))))
-+ | IPsecSAref2NFmark(IPsecSA2SAref(ipsp));
-+ KLIPS_PRINT(debug_rcv & DB_RX_PKTRX,
-+ "klips_debug:ipsec_rcv: "
-+ "IPIP SA sets skb->nfmark=0x%x.\n",
-+ (unsigned)skb->nfmark);
-+#endif /* CONFIG_NETFILTER */
-+ }
-+
-+ spin_unlock(&tdb_lock);
-+
-+#ifdef NET_21
-+ if(stats) {
-+ stats->rx_bytes += skb->len;
-+ }
-+ if(skb->dst) {
-+ dst_release(skb->dst);
-+ skb->dst = NULL;
-+ }
-+ skb->pkt_type = PACKET_HOST;
-+ if(irs.hard_header_len &&
-+ (skb->mac.raw != (skb->data - irs.hard_header_len)) &&
-+ (irs.hard_header_len <= skb_headroom(skb))) {
-+ /* copy back original MAC header */
-+ memmove(skb->data - irs.hard_header_len, skb->mac.raw, irs.hard_header_len);
-+ skb->mac.raw = skb->data - irs.hard_header_len;
-+ }
-+#endif /* NET_21 */
-+
-+#ifdef CONFIG_IPSEC_IPCOMP
-+ if(ipp->protocol == IPPROTO_COMP) {
-+ unsigned int flags = 0;
-+
-+ if(sysctl_ipsec_inbound_policy_check) {
-+ KLIPS_PRINT(debug_rcv & DB_RX_PKTRX,
-+ "klips_debug:ipsec_rcv: "
-+ "inbound policy checking enabled, IPCOMP follows IPIP, dropped.\n");
-+ if (stats) {
-+ stats->rx_errors++;
-+ }
-+ goto rcvleave;
-+ }
-+ /*
-+ XXX need a ipsec_sa for updating ratio counters but it is not
-+ following policy anyways so it is not a priority
-+ */
-+ skb = skb_decompress(skb, NULL, &flags);
-+ if (!skb || flags) {
-+ KLIPS_PRINT(debug_rcv & DB_RX_PKTRX,
-+ "klips_debug:ipsec_rcv: "
-+ "skb_decompress() returned error flags: %d, dropped.\n",
-+ flags);
-+ if (stats) {
-+ stats->rx_errors++;
-+ }
-+ goto rcvleave;
-+ }
-+ }
-+#endif /* CONFIG_IPSEC_IPCOMP */
-+
-+#ifdef SKB_RESET_NFCT
-+ nf_conntrack_put(skb->nfct);
-+ skb->nfct = NULL;
-+#ifdef CONFIG_NETFILTER_DEBUG
-+ skb->nf_debug = 0;
-+#endif /* CONFIG_NETFILTER_DEBUG */
-+#endif /* SKB_RESET_NFCT */
-+ KLIPS_PRINT(debug_rcv & DB_RX_PKTRX,
-+ "klips_debug:ipsec_rcv: "
-+ "netif_rx() called.\n");
-+ netif_rx(skb);
-+
-+ MOD_DEC_USE_COUNT;
-+ return(0);
-+
-+ rcvleave:
-+ if(skb) {
-+ ipsec_kfree_skb(skb);
-+ }
-+
-+ MOD_DEC_USE_COUNT;
-+ return(0);
-+}
-+
-+/*
-+ * $Log: ipsec_rcv.c,v $
-+ * Revision 1.143.4.2 2004/08/22 03:29:06 mcr
-+ * include udp.h regardless of nat-t support.
-+ *
-+ * Revision 1.143.4.1 2004/08/21 02:14:58 ken
-+ * Patch from Jochen Eisinger for AT&T MTS Heartbeat packet support
-+ *
-+ * Revision 1.143 2004/05/10 22:27:00 mcr
-+ * fix for ESP-3DES-noauth test case.
-+ *
-+ * Revision 1.142 2004/05/10 22:25:57 mcr
-+ * reformat of calls to ipsec_lifetime_check().
-+ *
-+ * Revision 1.141 2004/04/06 02:49:26 mcr
-+ * pullup of algo code from alg-branch.
-+ *
-+ * Revision 1.140 2004/02/03 03:12:53 mcr
-+ * removed erroneously, double patched code.
-+ *
-+ * Revision 1.139 2004/01/05 23:21:29 mcr
-+ * initialize sin_family in ipsec_rcv.c
-+ *
-+ * Revision 1.138 2003/12/24 19:46:52 mcr
-+ * if sock.h patch has not been applied, then define appropriate
-+ * structure so we can use it. This is serious inferior, and
-+ * depends upon the concept that the structure in question is
-+ * smaller than the other members of that union.
-+ * getting rid of differing methods is a better solution.
-+ *
-+ * Revision 1.137 2003/12/22 19:40:57 mcr
-+ * NAT-T patches 0.6c.
-+ *
-+ * Revision 1.136 2003/12/15 18:13:12 mcr
-+ * when compiling with NAT traversal, don't assume that the
-+ * kernel has been patched, unless CONFIG_IPSEC_NAT_NON_ESP
-+ * is set.
-+ *
-+ * Revision 1.135 2003/12/13 19:10:21 mcr
-+ * refactored rcv and xmit code - same as FS 2.05.
-+ *
-+ * Revision 1.134.2.1 2003/12/22 15:25:52 jjo
-+ * Merged algo-0.8.1-rc11-test1 into alg-branch
-+ *
-+ * Revision 1.134 2003/12/10 01:14:27 mcr
-+ * NAT-traversal patches to KLIPS.
-+ *
-+ * Revision 1.133 2003/10/31 02:27:55 mcr
-+ * pulled up port-selector patches and sa_id elimination.
-+ *
-+ * Revision 1.132.2.1 2003/10/29 01:30:41 mcr
-+ * elimited "struct sa_id".
-+ *
-+ * Revision 1.132 2003/09/02 19:51:48 mcr
-+ * fixes for PR#252.
-+ *
-+ * Revision 1.131 2003/07/31 22:47:16 mcr
-+ * preliminary (untested by FS-team) 2.5 patches.
-+ *
-+ * Revision 1.130 2003/04/03 17:38:25 rgb
-+ * Centralised ipsec_kfree_skb and ipsec_dev_{get,put}.
-+ * Clarified logic for non-connected devices.
-+ *
-+ * Revision 1.129 2003/02/06 02:21:34 rgb
-+ *
-+ * Moved "struct auth_alg" from ipsec_rcv.c to ipsec_ah.h .
-+ * Changed "struct ah" to "struct ahhdr" and "struct esp" to "struct esphdr".
-+ * Removed "#ifdef INBOUND_POLICY_CHECK_eroute" dead code.
-+ *
-+ * Revision 1.128 2002/12/13 20:58:03 rgb
-+ * Relegated MCR's recent "_dmp" routine to debug_verbose.
-+ * Cleaned up printing of source and destination addresses in debug output.
-+ *
-+ * Revision 1.127 2002/12/04 16:00:16 rgb
-+ *
-+ * Fixed AH decapsulation pointer update bug and added some comments and
-+ * debugging.
-+ * This bug was caught by west-ah-0[12].
-+ *
-+ * Revision 1.126 2002/11/04 05:03:43 mcr
-+ * fixes for IPCOMP. There were two problems:
-+ * 1) the irs->ipp pointer was not being updated properly after
-+ * the ESP descryption. The meant nothing for IPIP, as the
-+ * later IP header overwrote the earlier one.
-+ * 2) the more serious problem was that skb_decompress will
-+ * usually allocate a new SKB, so we have to make sure that
-+ * it doesn't get lost.
-+ * #2 meant removing the skb argument from the ->decrypt routine
-+ * and moving it to the irs->skb, so it could be value/result.
-+ *
-+ * Revision 1.125 2002/11/01 01:53:35 dhr
-+ *
-+ * fix typo
-+ *
-+ * Revision 1.124 2002/10/31 22:49:01 dhr
-+ *
-+ * - eliminate unused variable "hash"
-+ * - reduce scope of variable "authenticator"
-+ * - add comment on a couple of tricky bits
-+ *
-+ * Revision 1.123 2002/10/31 22:39:56 dhr
-+ *
-+ * use correct type for result of function calls
-+ *
-+ * Revision 1.122 2002/10/31 22:36:25 dhr
-+ *
-+ * simplify complex test
-+ *
-+ * Revision 1.121 2002/10/31 22:34:04 dhr
-+ *
-+ * ipsprev is never used: ditch it
-+ *
-+ * Revision 1.120 2002/10/31 22:30:21 dhr
-+ *
-+ * eliminate redundant assignments
-+ *
-+ * Revision 1.119 2002/10/31 22:27:43 dhr
-+ *
-+ * make whitespace canonical
-+ *
-+ * Revision 1.118 2002/10/30 05:47:17 rgb
-+ * Fixed cut-and-paste error mis-identifying comp runt as ah.
-+ *
-+ * Revision 1.117 2002/10/17 16:37:45 rgb
-+ * Remove compp intermediate variable and in-line its contents
-+ * where used
-+ *
-+ * Revision 1.116 2002/10/12 23:11:53 dhr
-+ *
-+ * [KenB + DHR] more 64-bit cleanup
-+ *
-+ * Revision 1.115 2002/10/07 19:06:58 rgb
-+ * Minor fixups and activation to west-rcv-nfmark-set-01 test to check for SA reference properly set on incoming.
-+ *
-+ * Revision 1.114 2002/10/07 18:31:31 rgb
-+ * Set saref on incoming packets.
-+ *
-+ * Revision 1.113 2002/09/16 21:28:12 mcr
-+ * adjust hash length for HMAC calculation - must look at whether
-+ * it is MD5 or SHA1.
-+ *
-+ * Revision 1.112 2002/09/16 21:19:15 mcr
-+ * fixes for west-ah-icmp-01 - length of AH header must be
-+ * calculated properly, and next_header field properly copied.
-+ *
-+ * Revision 1.111 2002/09/10 02:45:56 mcr
-+ * re-factored the ipsec_rcv function into several functions,
-+ * ipsec_rcv_decap_once, and a set of functions for AH, ESP and IPCOMP.
-+ * In addition, the MD5 and SHA1 functions are replaced with pointers.
-+ *
-+ * Revision 1.110 2002/08/30 06:34:33 rgb
-+ * Fix scope of shift in AH header length check.
-+ *
-+ * Revision 1.109 2002/08/27 16:49:20 rgb
-+ * Fixed ESP short packet DOS (and AH and IPCOMP).
-+ *
-+ * Revision 1.108 2002/07/24 18:44:54 rgb
-+ * Type fiddling to tame ia64 compiler.
-+ *
-+ * Revision 1.107 2002/05/27 18:58:18 rgb
-+ * Convert to dynamic ipsec device allocation.
-+ * Remove final vistiges of tdb references via IPSEC_KLIPS1_COMPAT.
-+ *
-+ * Revision 1.106 2002/05/23 07:15:21 rgb
-+ * Pointer clean-up.
-+ * Added refcount code.
-+ *
-+ * Revision 1.105 2002/05/14 02:35:06 rgb
-+ * Change all references to tdb, TDB or Tunnel Descriptor Block to ips,
-+ * ipsec_sa or ipsec_sa.
-+ * Change references to _TDB to _IPSA.
-+ *
-+ * Revision 1.104 2002/04/24 07:55:32 mcr
-+ * #include patches and Makefiles for post-reorg compilation.
-+ *
-+ * Revision 1.103 2002/04/24 07:36:30 mcr
-+ * Moved from ./klips/net/ipsec/ipsec_rcv.c,v
-+ *
-+ * Revision 1.102 2002/01/29 17:17:56 mcr
-+ * moved include of ipsec_param.h to after include of linux/kernel.h
-+ * otherwise, it seems that some option that is set in ipsec_param.h
-+ * screws up something subtle in the include path to kernel.h, and
-+ * it complains on the snprintf() prototype.
-+ *
-+ * Revision 1.101 2002/01/29 04:00:52 mcr
-+ * more excise of kversions.h header.
-+ *
-+ * Revision 1.100 2002/01/29 02:13:17 mcr
-+ * introduction of ipsec_kversion.h means that include of
-+ * ipsec_param.h must preceed any decisions about what files to
-+ * include to deal with differences in kernel source.
-+ *
-+ * Revision 1.99 2002/01/28 21:40:59 mcr
-+ * should use #if to test boolean option rather than #ifdef.
-+ *
-+ * Revision 1.98 2002/01/20 20:19:36 mcr
-+ * renamed option to IP_FRAGMENT_LINEARIZE.
-+ *
-+ * Revision 1.97 2002/01/12 02:55:36 mcr
-+ * fix for post-2.4.4 to linearize skb's when ESP packet
-+ * was assembled from fragments.
-+ *
-+ * Revision 1.96 2001/11/26 09:23:49 rgb
-+ * Merge MCR's ipsec_sa, eroute, proc and struct lifetime changes.
-+ *
-+ * Revision 1.93.2.2 2001/10/22 20:54:07 mcr
-+ * include des.h, removed phony prototypes and fixed calling
-+ * conventions to match real prototypes.
-+ *
-+ * Revision 1.93.2.1 2001/09/25 02:22:22 mcr
-+ * struct tdb -> struct ipsec_sa.
-+ * lifetime checks moved to ipsec_life.c
-+ * some sa(tdb) manipulation functions renamed.
-+ *
-+ * Revision 1.95 2001/11/06 19:49:07 rgb
-+ * Added variable descriptions.
-+ * Removed unauthenticated sequence==0 check to prevent DoS.
-+ *
-+ * Revision 1.94 2001/10/18 04:45:20 rgb
-+ * 2.4.9 kernel deprecates linux/malloc.h in favour of linux/slab.h,
-+ * lib/freeswan.h version macros moved to lib/kversions.h.
-+ * Other compiler directive cleanups.
-+ *
-+ * Revision 1.93 2001/09/07 22:17:24 rgb
-+ * Fix for removal of transport layer protocol handler arg in 2.4.4.
-+ * Fix to accomodate peer non-conformance to IPCOMP rfc2393.
-+ *
-+ * Revision 1.92 2001/08/27 19:44:41 rgb
-+ * Fix error in comment.
-+ *
-+ * Revision 1.91 2001/07/20 19:31:48 dhr
-+ * [DHR] fix source and destination subnets of policy in diagnostic
-+ *
-+ * Revision 1.90 2001/07/06 19:51:09 rgb
-+ * Added inbound policy checking code for IPIP SAs.
-+ * Renamed unused function argument for ease and intuitive naming.
-+ *
-+ * Revision 1.89 2001/06/22 19:35:23 rgb
-+ * Disable ipcomp processing if we are handed a ipcomp packet with no esp
-+ * or ah header.
-+ * Print protocol if we are handed a non-ipsec packet.
-+ *
-+ * Revision 1.88 2001/06/20 06:30:47 rgb
-+ * Fixed transport mode IPCOMP policy check bug.
-+ *
-+ * Revision 1.87 2001/06/13 20:58:40 rgb
-+ * Added parentheses around assignment used as truth value to silence
-+ * compiler.
-+ *
-+ * Revision 1.86 2001/06/07 22:25:23 rgb
-+ * Added a source address policy check for tunnel mode. It still does
-+ * not check client addresses and masks.
-+ * Only decapsulate IPIP if it is expected.
-+ *
-+ * Revision 1.85 2001/05/30 08:14:02 rgb
-+ * Removed vestiges of esp-null transforms.
-+ *
-+ * Revision 1.84 2001/05/27 06:12:11 rgb
-+ * Added structures for pid, packet count and last access time to eroute.
-+ * Added packet count to beginning of /proc/net/ipsec_eroute.
-+ *
-+ * Revision 1.83 2001/05/04 16:45:47 rgb
-+ * Remove unneeded code. ipp is not used after this point.
-+ *
-+ * Revision 1.82 2001/05/04 16:36:00 rgb
-+ * Fix skb_cow() call for 2.4.4. (SS)
-+ *
-+ * Revision 1.81 2001/05/02 14:46:53 rgb
-+ * Fix typo for compiler directive to pull IPH back.
-+ *
-+ * Revision 1.80 2001/04/30 19:46:34 rgb
-+ * Update for 2.4.4. We now receive the skb with skb->data pointing to
-+ * h.raw.
-+ *
-+ * Revision 1.79 2001/04/23 15:01:15 rgb
-+ * Added spin_lock() check to prevent double-locking for multiple
-+ * transforms and hence kernel lock-ups with SMP kernels.
-+ * Minor spin_unlock() adjustments to unlock before non-dependant prints
-+ * and IPSEC device stats updates.
-+ *
-+ * Revision 1.78 2001/04/21 23:04:24 rgb
-+ * Check if soft expire has already been sent before sending another to
-+ * prevent ACQUIRE flooding.
-+ *
-+ * Revision 1.77 2001/03/16 07:35:20 rgb
-+ * Ditch extra #if 1 around now permanent policy checking code.
-+ *
-+ * Revision 1.76 2001/02/27 22:24:54 rgb
-+ * Re-formatting debug output (line-splitting, joining, 1arg/line).
-+ * Check for satoa() return codes.
-+ *
-+ * Revision 1.75 2001/02/19 22:28:30 rgb
-+ * Minor change to virtual device discovery code to assert which I/F has
-+ * been found.
-+ *
-+ * Revision 1.74 2000/11/25 03:50:36 rgb
-+ * Oops fix by minor re-arrangement of code to avoid accessing a freed tdb.
-+ *
-+ * Revision 1.73 2000/11/09 20:52:15 rgb
-+ * More spinlock shuffling, locking earlier and unlocking later in rcv to
-+ * include ipcomp and prevent races, renaming some tdb variables that got
-+ * forgotten, moving some unlocks to include tdbs and adding a missing
-+ * unlock. Thanks to Svenning for some of these.
-+ *
-+ * Revision 1.72 2000/11/09 20:11:22 rgb
-+ * Minor shuffles to fix non-standard kernel config option selection.
-+ *
-+ * Revision 1.71 2000/11/06 04:36:18 rgb
-+ * Ditched spin_lock_irqsave in favour of spin_lock.
-+ * Minor initial protocol check rewrite.
-+ * Clean up debug printing.
-+ * Clean up tdb handling on ipcomp.
-+ * Fixed transport mode null pointer de-reference without ipcomp.
-+ * Add Svenning's adaptive content compression.
-+ * Disabled registration of ipcomp handler.
-+ *
-+ * Revision 1.70 2000/10/30 23:41:43 henry
-+ * Hans-Joerg Hoexer's null-pointer fix
-+ *
-+ * Revision 1.69 2000/10/10 18:54:16 rgb
-+ * Added a fix for incoming policy check with ipcomp enabled but
-+ * uncompressible.
-+ *
-+ * Revision 1.68 2000/09/22 17:53:12 rgb
-+ * Fixed ipcomp tdb pointers update for policy checking.
-+ *
-+ * Revision 1.67 2000/09/21 03:40:58 rgb
-+ * Added more debugging to try and track down the cpi outward copy problem.
-+ *
-+ * Revision 1.66 2000/09/20 04:00:10 rgb
-+ * Changed static functions to DEBUG_NO_STATIC to reveal function names for
-+ * debugging oopsen.
-+ *
-+ * Revision 1.65 2000/09/19 07:07:16 rgb
-+ * Added debugging to inbound policy check for ipcomp.
-+ * Added missing spin_unlocks (thanks Svenning!).
-+ * Fixed misplaced tdbnext pointers causing mismatched ipip policy check.
-+ * Protect ipcomp policy check following ipip decap with sysctl switch.
-+ *
-+ * Revision 1.64 2000/09/18 21:27:29 rgb
-+ * 2.0 fixes.
-+ *
-+ * Revision 1.63 2000/09/18 02:35:50 rgb
-+ * Added policy checking to ipcomp and re-enabled policy checking by
-+ * default.
-+ * Optimised satoa calls.
-+ *
-+ * Revision 1.62 2000/09/17 21:02:32 rgb
-+ * Clean up debugging, removing slow timestamp debug code.
-+ *
-+ * Revision 1.61 2000/09/16 01:07:55 rgb
-+ * Fixed erroneous ref from struct ipcomp to struct ipcomphdr.
-+ *
-+ * Revision 1.60 2000/09/15 11:37:01 rgb
-+ * Merge in heavily modified Svenning Soerensen's <svenning@post5.tele.dk>
-+ * IPCOMP zlib deflate code.
-+ *
-+ * Revision 1.59 2000/09/15 04:56:20 rgb
-+ * Remove redundant satoa() call, reformat comment.
-+ *
-+ * Revision 1.58 2000/09/13 08:00:52 rgb
-+ * Flick on inbound policy checking.
-+ *
-+ * Revision 1.57 2000/09/12 03:22:19 rgb
-+ * Converted inbound_policy_check to sysctl.
-+ * Re-enabled policy backcheck.
-+ * Moved policy checks to top and within tdb lock.
-+ *
-+ * Revision 1.56 2000/09/08 19:12:56 rgb
-+ * Change references from DEBUG_IPSEC to CONFIG_IPSEC_DEBUG.
-+ *
-+ * Revision 1.55 2000/08/28 18:15:46 rgb
-+ * Added MB's nf-debug reset patch.
-+ *
-+ * Revision 1.54 2000/08/27 01:41:26 rgb
-+ * More minor tweaks to the bad padding debug code.
-+ *
-+ * Revision 1.53 2000/08/24 16:54:16 rgb
-+ * Added KLIPS_PRINTMORE macro to continue lines without KERN_INFO level
-+ * info.
-+ * Tidied up device reporting at the start of ipsec_rcv.
-+ * Tidied up bad padding debugging and processing.
-+ *
-+ * Revision 1.52 2000/08/20 21:36:03 rgb
-+ * Activated pfkey_expire() calls.
-+ * Added a hard/soft expiry parameter to pfkey_expire().
-+ * Added sanity checking to avoid propagating zero or smaller-length skbs
-+ * from a bogus decryption.
-+ * Re-arranged the order of soft and hard expiry to conform to RFC2367.
-+ * Clean up references to CONFIG_IPSEC_PFKEYv2.
-+ *
-+ * Revision 1.51 2000/08/18 21:23:30 rgb
-+ * Improve bad padding warning so that the printk buffer doesn't get
-+ * trampled.
-+ *
-+ * Revision 1.50 2000/08/01 14:51:51 rgb
-+ * Removed _all_ remaining traces of DES.
-+ *
-+ * Revision 1.49 2000/07/28 13:50:53 rgb
-+ * Changed enet_statistics to net_device_stats and added back compatibility
-+ * for pre-2.1.19.
-+ *
-+ * Revision 1.48 2000/05/10 19:14:40 rgb
-+ * Only check usetime against soft and hard limits if the tdb has been
-+ * used.
-+ * Cast output of ntohl so that the broken prototype doesn't make our
-+ * compile noisy.
-+ *
-+ * Revision 1.47 2000/05/09 17:45:43 rgb
-+ * Fix replay bitmap corruption bug upon receipt of bogus packet
-+ * with correct SPI. This was a DoS.
-+ *
-+ * Revision 1.46 2000/03/27 02:31:58 rgb
-+ * Fixed authentication failure printout bug.
-+ *
-+ * Revision 1.45 2000/03/22 16:15:37 rgb
-+ * Fixed renaming of dev_get (MB).
-+ *
-+ * Revision 1.44 2000/03/16 08:17:24 rgb
-+ * Hardcode PF_KEYv2 support.
-+ * Fixed minor bug checking AH header length.
-+ *
-+ * Revision 1.43 2000/03/14 12:26:59 rgb
-+ * Added skb->nfct support for clearing netfilter conntrack bits (MB).
-+ *
-+ * Revision 1.42 2000/01/26 10:04:04 rgb
-+ * Fixed inbound policy checking on transport mode bug.
-+ * Fixed noisy 2.0 printk arguments.
-+ *
-+ * Revision 1.41 2000/01/24 20:58:02 rgb
-+ * Improve debugging/reporting support for (disabled) inbound
-+ * policy checking.
-+ *
-+ * Revision 1.40 2000/01/22 23:20:10 rgb
-+ * Fixed up inboud policy checking code.
-+ * Cleaned out unused crud.
-+ *
-+ * Revision 1.39 2000/01/21 06:15:29 rgb
-+ * Added sanity checks on skb_push(), skb_pull() to prevent panics.
-+ * Fixed cut-and-paste debug_tunnel to debug_rcv.
-+ * Added inbound policy checking code, disabled.
-+ * Simplified output code by updating ipp to post-IPIP decapsulation.
-+ *
-+ * elided pre-2000 comments. Use "cvs log"
-+ *
-+ *
-+ */
---- /dev/null Tue Mar 11 13:02:56 2003
-+++ linux/net/ipsec/ipsec_sa.c Mon Feb 9 13:51:03 2004
-@@ -0,0 +1,1383 @@
-+/*
-+ * Common routines for IPsec SA maintenance routines.
-+ *
-+ * Copyright (C) 1996, 1997 John Ioannidis.
-+ * Copyright (C) 1998, 1999, 2000, 2001, 2002 Richard Guy Briggs.
-+ *
-+ * 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. See <http://www.fsf.org/copyleft/gpl.txt>.
-+ *
-+ * 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.
-+ *
-+ * RCSID $Id: ipsec_sa.c,v 1.23 2004/04/06 02:49:26 mcr Exp $
-+ *
-+ * This is the file formerly known as "ipsec_xform.h"
-+ *
-+ */
-+
-+#include <linux/config.h>
-+#include <linux/version.h>
-+#include <linux/kernel.h> /* printk() */
-+
-+#include "openswan/ipsec_param.h"
-+
-+#ifdef MALLOC_SLAB
-+# include <linux/slab.h> /* kmalloc() */
-+#else /* MALLOC_SLAB */
-+# include <linux/malloc.h> /* kmalloc() */
-+#endif /* MALLOC_SLAB */
-+#include <linux/vmalloc.h> /* vmalloc() */
-+#include <linux/errno.h> /* error codes */
-+#include <linux/types.h> /* size_t */
-+#include <linux/interrupt.h> /* mark_bh */
-+
-+#include <linux/netdevice.h> /* struct device, and other headers */
-+#include <linux/etherdevice.h> /* eth_type_trans */
-+#include <linux/ip.h> /* struct iphdr */
-+#include <linux/skbuff.h>
-+#include <openswan.h>
-+#ifdef SPINLOCK
-+#ifdef SPINLOCK_23
-+#include <linux/spinlock.h> /* *lock* */
-+#else /* SPINLOCK_23 */
-+#include <asm/spinlock.h> /* *lock* */
-+#endif /* SPINLOCK_23 */
-+#endif /* SPINLOCK */
-+#ifdef NET_21
-+#include <asm/uaccess.h>
-+#include <linux/in6.h>
-+#endif
-+#include <asm/checksum.h>
-+#include <net/ip.h>
-+
-+#include "openswan/radij.h"
-+
-+#include "openswan/ipsec_stats.h"
-+#include "openswan/ipsec_life.h"
-+#include "openswan/ipsec_sa.h"
-+#include "openswan/ipsec_xform.h"
-+
-+#include "openswan/ipsec_encap.h"
-+#include "openswan/ipsec_radij.h"
-+#include "openswan/ipsec_xform.h"
-+#include "openswan/ipsec_ipe4.h"
-+#include "openswan/ipsec_ah.h"
-+#include "openswan/ipsec_esp.h"
-+
-+#include <pfkeyv2.h>
-+#include <pfkey.h>
-+
-+#include "openswan/ipsec_proto.h"
-+#include "openswan/ipsec_alg.h"
-+
-+
-+#ifdef CONFIG_IPSEC_DEBUG
-+int debug_xform = 0;
-+#endif /* CONFIG_IPSEC_DEBUG */
-+
-+#define SENDERR(_x) do { error = -(_x); goto errlab; } while (0)
-+
-+struct ipsec_sa *ipsec_sadb_hash[SADB_HASHMOD];
-+#ifdef SPINLOCK
-+spinlock_t tdb_lock = SPIN_LOCK_UNLOCKED;
-+#else /* SPINLOCK */
-+spinlock_t tdb_lock;
-+#endif /* SPINLOCK */
-+
-+struct ipsec_sadb ipsec_sadb;
-+
-+#if IPSEC_SA_REF_CODE
-+
-+/* the sub table must be narrower (or equal) in bits than the variable type
-+ in the main table to count the number of unused entries in it. */
-+typedef struct {
-+ int testSizeOf_refSubTable :
-+ ((sizeof(IPsecRefTableUnusedCount) * 8) < IPSEC_SA_REF_SUBTABLE_IDX_WIDTH ? -1 : 1);
-+} dummy;
-+
-+
-+/* The field where the saref will be hosted in the skb must be wide enough to
-+ accomodate the information it needs to store. */
-+typedef struct {
-+ int testSizeOf_refField :
-+ (IPSEC_SA_REF_HOST_FIELD_WIDTH < IPSEC_SA_REF_TABLE_IDX_WIDTH ? -1 : 1 );
-+} dummy2;
-+
-+
-+#define IPS_HASH(said) (((said)->spi + (said)->dst.u.v4.sin_addr.s_addr + (said)->proto) % SADB_HASHMOD)
-+
-+
-+void
-+ipsec_SAtest(void)
-+{
-+ IPsecSAref_t SAref = 258;
-+ struct ipsec_sa ips;
-+ ips.ips_ref = 772;
-+
-+ printk("klips_debug:ipsec_SAtest: "
-+ "IPSEC_SA_REF_SUBTABLE_IDX_WIDTH=%u\n"
-+ "IPSEC_SA_REF_MAINTABLE_NUM_ENTRIES=%u\n"
-+ "IPSEC_SA_REF_SUBTABLE_NUM_ENTRIES=%u\n"
-+ "IPSEC_SA_REF_HOST_FIELD_WIDTH=%lu\n"
-+ "IPSEC_SA_REF_TABLE_MASK=%x\n"
-+ "IPSEC_SA_REF_ENTRY_MASK=%x\n"
-+ "IPsecSAref2table(%d)=%u\n"
-+ "IPsecSAref2entry(%d)=%u\n"
-+ "IPsecSAref2NFmark(%d)=%u\n"
-+ "IPsecSAref2SA(%d)=%p\n"
-+ "IPsecSA2SAref(%p)=%d\n"
-+ ,
-+ IPSEC_SA_REF_SUBTABLE_IDX_WIDTH,
-+ IPSEC_SA_REF_MAINTABLE_NUM_ENTRIES,
-+ IPSEC_SA_REF_SUBTABLE_NUM_ENTRIES,
-+ (unsigned long) IPSEC_SA_REF_HOST_FIELD_WIDTH,
-+ IPSEC_SA_REF_TABLE_MASK,
-+ IPSEC_SA_REF_ENTRY_MASK,
-+ SAref, IPsecSAref2table(SAref),
-+ SAref, IPsecSAref2entry(SAref),
-+ SAref, IPsecSAref2NFmark(SAref),
-+ SAref, IPsecSAref2SA(SAref),
-+ (&ips), IPsecSA2SAref((&ips))
-+ );
-+ return;
-+}
-+
-+int
-+ipsec_SAref_recycle(void)
-+{
-+ int table;
-+ int entry;
-+ int error = 0;
-+
-+ ipsec_sadb.refFreeListHead = -1;
-+ ipsec_sadb.refFreeListTail = -1;
-+
-+ if(ipsec_sadb.refFreeListCont == IPSEC_SA_REF_MAINTABLE_NUM_ENTRIES * IPSEC_SA_REF_SUBTABLE_NUM_ENTRIES) {
-+ KLIPS_PRINT(debug_xform,
-+ "klips_debug:ipsec_SAref_recycle: "
-+ "end of table reached, continuing at start..\n");
-+ ipsec_sadb.refFreeListCont = 0;
-+ }
-+
-+ KLIPS_PRINT(debug_xform,
-+ "klips_debug:ipsec_SAref_recycle: "
-+ "recycling, continuing from SAref=%d (0p%p), table=%d, entry=%d.\n",
-+ ipsec_sadb.refFreeListCont,
-+ (ipsec_sadb.refTable[IPsecSAref2table(ipsec_sadb.refFreeListCont)] != NULL) ? IPsecSAref2SA(ipsec_sadb.refFreeListCont) : NULL,
-+ IPsecSAref2table(ipsec_sadb.refFreeListCont),
-+ IPsecSAref2entry(ipsec_sadb.refFreeListCont));
-+
-+ for(table = IPsecSAref2table(ipsec_sadb.refFreeListCont);
-+ table < IPSEC_SA_REF_MAINTABLE_NUM_ENTRIES;
-+ table++) {
-+ if(ipsec_sadb.refTable[table] == NULL) {
-+ error = ipsec_SArefSubTable_alloc(table);
-+ if(error) {
-+ return error;
-+ }
-+ }
-+ for(entry = IPsecSAref2entry(ipsec_sadb.refFreeListCont);
-+ entry < IPSEC_SA_REF_SUBTABLE_NUM_ENTRIES;
-+ entry++) {
-+ if(ipsec_sadb.refTable[table]->entry[entry] == NULL) {
-+ ipsec_sadb.refFreeList[++ipsec_sadb.refFreeListTail] = IPsecSArefBuild(table, entry);
-+ if(ipsec_sadb.refFreeListTail == (IPSEC_SA_REF_FREELIST_NUM_ENTRIES - 1)) {
-+ ipsec_sadb.refFreeListHead = 0;
-+ ipsec_sadb.refFreeListCont = ipsec_sadb.refFreeList[ipsec_sadb.refFreeListTail] + 1;
-+ KLIPS_PRINT(debug_xform,
-+ "klips_debug:ipsec_SAref_recycle: "
-+ "SArefFreeList refilled.\n");
-+ return 0;
-+ }
-+ }
-+ }
-+ }
-+
-+ if(ipsec_sadb.refFreeListTail == -1) {
-+ KLIPS_PRINT(debug_xform,
-+ "klips_debug:ipsec_SAref_recycle: "
-+ "out of room in the SArefTable.\n");
-+
-+ return(-ENOSPC);
-+ }
-+
-+ ipsec_sadb.refFreeListHead = 0;
-+ ipsec_sadb.refFreeListCont = ipsec_sadb.refFreeList[ipsec_sadb.refFreeListTail] + 1;
-+ KLIPS_PRINT(debug_xform,
-+ "klips_debug:ipsec_SAref_recycle: "
-+ "SArefFreeList partly refilled to %d of %d.\n",
-+ ipsec_sadb.refFreeListTail,
-+ IPSEC_SA_REF_FREELIST_NUM_ENTRIES);
-+ return 0;
-+}
-+
-+int
-+ipsec_SArefSubTable_alloc(unsigned table)
-+{
-+ unsigned entry;
-+ struct IPsecSArefSubTable* SArefsub;
-+
-+ KLIPS_PRINT(debug_xform,
-+ "klips_debug:ipsec_SArefSubTable_alloc: "
-+ "allocating %lu bytes for table %u of %u.\n",
-+ (unsigned long) (IPSEC_SA_REF_SUBTABLE_NUM_ENTRIES * sizeof(struct ipsec_sa *)),
-+ table,
-+ IPSEC_SA_REF_MAINTABLE_NUM_ENTRIES);
-+
-+ /* allocate another sub-table */
-+ SArefsub = vmalloc(IPSEC_SA_REF_SUBTABLE_NUM_ENTRIES * sizeof(struct ipsec_sa *));
-+ if(SArefsub == NULL) {
-+ KLIPS_PRINT(debug_xform,
-+ "klips_debug:ipsec_SArefSubTable_alloc: "
-+ "error allocating memory for table %u of %u!\n",
-+ table,
-+ IPSEC_SA_REF_MAINTABLE_NUM_ENTRIES);
-+ return -ENOMEM;
-+ }
-+
-+ /* add this sub-table to the main table */
-+ ipsec_sadb.refTable[table] = SArefsub;
-+
-+ /* initialise each element to NULL */
-+ KLIPS_PRINT(debug_xform,
-+ "klips_debug:ipsec_SArefSubTable_alloc: "
-+ "initialising %u elements (2 ^ %u) of table %u.\n",
-+ IPSEC_SA_REF_SUBTABLE_NUM_ENTRIES,
-+ IPSEC_SA_REF_SUBTABLE_IDX_WIDTH,
-+ table);
-+ for(entry = 0; entry < IPSEC_SA_REF_SUBTABLE_NUM_ENTRIES; entry++) {
-+ SArefsub->entry[entry] = NULL;
-+ }
-+
-+ return 0;
-+}
-+#endif /* IPSEC_SA_REF_CODE */
-+
-+int
-+ipsec_saref_freelist_init(void)
-+{
-+ int i;
-+
-+ KLIPS_PRINT(debug_xform,
-+ "klips_debug:ipsec_saref_freelist_init: "
-+ "initialising %u elements of FreeList.\n",
-+ IPSEC_SA_REF_FREELIST_NUM_ENTRIES);
-+
-+ for(i = 0; i < IPSEC_SA_REF_FREELIST_NUM_ENTRIES; i++) {
-+ ipsec_sadb.refFreeList[i] = IPSEC_SAREF_NULL;
-+ }
-+ ipsec_sadb.refFreeListHead = -1;
-+ ipsec_sadb.refFreeListCont = 0;
-+ ipsec_sadb.refFreeListTail = -1;
-+
-+ return 0;
-+}
-+
-+int
-+ipsec_sadb_init(void)
-+{
-+ int error = 0;
-+ unsigned i;
-+
-+ for(i = 0; i < SADB_HASHMOD; i++) {
-+ ipsec_sadb_hash[i] = NULL;
-+ }
-+ /* parts above are for the old style SADB hash table */
-+
-+
-+#if IPSEC_SA_REF_CODE
-+ /* initialise SA reference table */
-+
-+ /* initialise the main table */
-+ KLIPS_PRINT(debug_xform,
-+ "klips_debug:ipsec_sadb_init: "
-+ "initialising main table of size %u (2 ^ %u).\n",
-+ IPSEC_SA_REF_MAINTABLE_NUM_ENTRIES,
-+ IPSEC_SA_REF_MAINTABLE_IDX_WIDTH);
-+ {
-+ unsigned table;
-+ for(table = 0; table < IPSEC_SA_REF_MAINTABLE_NUM_ENTRIES; table++) {
-+ ipsec_sadb.refTable[table] = NULL;
-+ }
-+ }
-+
-+ /* allocate the first sub-table */
-+ error = ipsec_SArefSubTable_alloc(0);
-+ if(error) {
-+ return error;
-+ }
-+
-+ error = ipsec_saref_freelist_init();
-+#endif /* IPSEC_SA_REF_CODE */
-+ return error;
-+}
-+
-+#if IPSEC_SA_REF_CODE
-+IPsecSAref_t
-+ipsec_SAref_alloc(int*error) /* pass in error var by pointer */
-+{
-+ IPsecSAref_t SAref;
-+
-+ KLIPS_PRINT(debug_xform,
-+ "klips_debug:ipsec_SAref_alloc: "
-+ "SAref requested... head=%d, cont=%d, tail=%d, listsize=%d.\n",
-+ ipsec_sadb.refFreeListHead,
-+ ipsec_sadb.refFreeListCont,
-+ ipsec_sadb.refFreeListTail,
-+ IPSEC_SA_REF_FREELIST_NUM_ENTRIES);
-+
-+ if(ipsec_sadb.refFreeListHead == -1) {
-+ KLIPS_PRINT(debug_xform,
-+ "klips_debug:ipsec_SAref_alloc: "
-+ "FreeList empty, recycling...\n");
-+ *error = ipsec_SAref_recycle();
-+ if(*error) {
-+ return IPSEC_SAREF_NULL;
-+ }
-+ }
-+
-+ SAref = ipsec_sadb.refFreeList[ipsec_sadb.refFreeListHead];
-+ if(SAref == IPSEC_SAREF_NULL) {
-+ KLIPS_PRINT(debug_xform,
-+ "klips_debug:ipsec_SAref_alloc: "
-+ "unexpected error, refFreeListHead = %d points to invalid entry.\n",
-+ ipsec_sadb.refFreeListHead);
-+ *error = -ESPIPE;
-+ return IPSEC_SAREF_NULL;
-+ }
-+
-+ KLIPS_PRINT(debug_xform,
-+ "klips_debug:ipsec_SAref_alloc: "
-+ "allocating SAref=%d, table=%u, entry=%u of %u.\n",
-+ SAref,
-+ IPsecSAref2table(SAref),
-+ IPsecSAref2entry(SAref),
-+ IPSEC_SA_REF_MAINTABLE_NUM_ENTRIES * IPSEC_SA_REF_SUBTABLE_NUM_ENTRIES);
-+
-+ ipsec_sadb.refFreeList[ipsec_sadb.refFreeListHead] = IPSEC_SAREF_NULL;
-+ ipsec_sadb.refFreeListHead++;
-+ if(ipsec_sadb.refFreeListHead > ipsec_sadb.refFreeListTail) {
-+ KLIPS_PRINT(debug_xform,
-+ "klips_debug:ipsec_SAref_alloc: "
-+ "last FreeList entry allocated, resetting list head to empty.\n");
-+ ipsec_sadb.refFreeListHead = -1;
-+ }
-+
-+ return SAref;
-+}
-+#endif /* IPSEC_SA_REF_CODE */
-+
-+int
-+ipsec_sa_print(struct ipsec_sa *ips)
-+{
-+ char sa[SATOT_BUF];
-+ size_t sa_len;
-+
-+ printk(KERN_INFO "klips_debug: SA:");
-+ if(ips == NULL) {
-+ printk("NULL\n");
-+ return -ENOENT;
-+ }
-+ printk(" ref=%d", ips->ips_ref);
-+ printk(" refcount=%d", atomic_read(&ips->ips_refcount));
-+ if(ips->ips_hnext != NULL) {
-+ printk(" hnext=0p%p", ips->ips_hnext);
-+ }
-+ if(ips->ips_inext != NULL) {
-+ printk(" inext=0p%p", ips->ips_inext);
-+ }
-+ if(ips->ips_onext != NULL) {
-+ printk(" onext=0p%p", ips->ips_onext);
-+ }
-+ sa_len = satot(&ips->ips_said, 0, sa, sizeof(sa));
-+ printk(" said=%s", sa_len ? sa : " (error)");
-+ if(ips->ips_seq) {
-+ printk(" seq=%u", ips->ips_seq);
-+ }
-+ if(ips->ips_pid) {
-+ printk(" pid=%u", ips->ips_pid);
-+ }
-+ if(ips->ips_authalg) {
-+ printk(" authalg=%u", ips->ips_authalg);
-+ }
-+ if(ips->ips_encalg) {
-+ printk(" encalg=%u", ips->ips_encalg);
-+ }
-+ printk(" XFORM=%s%s%s", IPS_XFORM_NAME(ips));
-+ if(ips->ips_replaywin) {
-+ printk(" ooowin=%u", ips->ips_replaywin);
-+ }
-+ if(ips->ips_flags) {
-+ printk(" flags=%u", ips->ips_flags);
-+ }
-+ if(ips->ips_addr_s) {
-+ char buf[SUBNETTOA_BUF];
-+ addrtoa(((struct sockaddr_in*)(ips->ips_addr_s))->sin_addr,
-+ 0, buf, sizeof(buf));
-+ printk(" src=%s", buf);
-+ }
-+ if(ips->ips_addr_d) {
-+ char buf[SUBNETTOA_BUF];
-+ addrtoa(((struct sockaddr_in*)(ips->ips_addr_s))->sin_addr,
-+ 0, buf, sizeof(buf));
-+ printk(" dst=%s", buf);
-+ }
-+ if(ips->ips_addr_p) {
-+ char buf[SUBNETTOA_BUF];
-+ addrtoa(((struct sockaddr_in*)(ips->ips_addr_p))->sin_addr,
-+ 0, buf, sizeof(buf));
-+ printk(" proxy=%s", buf);
-+ }
-+ if(ips->ips_key_bits_a) {
-+ printk(" key_bits_a=%u", ips->ips_key_bits_a);
-+ }
-+ if(ips->ips_key_bits_e) {
-+ printk(" key_bits_e=%u", ips->ips_key_bits_e);
-+ }
-+
-+ printk("\n");
-+ return 0;
-+}
-+
-+struct ipsec_sa*
-+ipsec_sa_alloc(int*error) /* pass in error var by pointer */
-+{
-+ struct ipsec_sa* ips;
-+
-+ if((ips = kmalloc(sizeof(*ips), GFP_ATOMIC) ) == NULL) {
-+ KLIPS_PRINT(debug_xform,
-+ "klips_debug:ipsec_sa_alloc: "
-+ "memory allocation error\n");
-+ *error = -ENOMEM;
-+ return NULL;
-+ }
-+ memset((caddr_t)ips, 0, sizeof(*ips));
-+#if IPSEC_SA_REF_CODE
-+ ips->ips_ref = ipsec_SAref_alloc(error); /* pass in error return by pointer */
-+ KLIPS_PRINT(debug_xform,
-+ "klips_debug:ipsec_sa_alloc: "
-+ "allocated %lu bytes for ipsec_sa struct=0p%p ref=%d.\n",
-+ (unsigned long) sizeof(*ips),
-+ ips,
-+ ips->ips_ref);
-+ if(ips->ips_ref == IPSEC_SAREF_NULL) {
-+ kfree(ips);
-+ KLIPS_PRINT(debug_xform,
-+ "klips_debug:ipsec_sa_alloc: "
-+ "SAref allocation error\n");
-+ return NULL;
-+ }
-+
-+ atomic_inc(&ips->ips_refcount);
-+ IPsecSAref2SA(ips->ips_ref) = ips;
-+#endif /* IPSEC_SA_REF_CODE */
-+
-+ *error = 0;
-+ return(ips);
-+}
-+
-+int
-+ipsec_sa_free(struct ipsec_sa* ips)
-+{
-+ return ipsec_sa_wipe(ips);
-+}
-+
-+struct ipsec_sa *
-+ipsec_sa_getbyid(ip_said *said)
-+{
-+ int hashval;
-+ struct ipsec_sa *ips;
-+ char sa[SATOT_BUF];
-+ size_t sa_len;
-+
-+ if(said == NULL) {
-+ KLIPS_PRINT(debug_xform,
-+ "klips_error:ipsec_sa_getbyid: "
-+ "null pointer passed in!\n");
-+ return NULL;
-+ }
-+
-+ sa_len = satot(said, 0, sa, sizeof(sa));
-+
-+ hashval = IPS_HASH(said);
-+
-+ KLIPS_PRINT(debug_xform,
-+ "klips_debug:ipsec_sa_getbyid: "
-+ "linked entry in ipsec_sa table for hash=%d of SA:%s requested.\n",
-+ hashval,
-+ sa_len ? sa : " (error)");
-+
-+ if((ips = ipsec_sadb_hash[hashval]) == NULL) {
-+ KLIPS_PRINT(debug_xform,
-+ "klips_debug:ipsec_sa_getbyid: "
-+ "no entries in ipsec_sa table for hash=%d of SA:%s.\n",
-+ hashval,
-+ sa_len ? sa : " (error)");
-+ return NULL;
-+ }
-+
-+ for (; ips; ips = ips->ips_hnext) {
-+ if ((ips->ips_said.spi == said->spi) &&
-+ (ips->ips_said.dst.u.v4.sin_addr.s_addr == said->dst.u.v4.sin_addr.s_addr) &&
-+ (ips->ips_said.proto == said->proto)) {
-+ atomic_inc(&ips->ips_refcount);
-+ return ips;
-+ }
-+ }
-+
-+ KLIPS_PRINT(debug_xform,
-+ "klips_debug:ipsec_sa_getbyid: "
-+ "no entry in linked list for hash=%d of SA:%s.\n",
-+ hashval,
-+ sa_len ? sa : " (error)");
-+ return NULL;
-+}
-+
-+int
-+ipsec_sa_put(struct ipsec_sa *ips)
-+{
-+ char sa[SATOT_BUF];
-+ size_t sa_len;
-+
-+ if(ips == NULL) {
-+ KLIPS_PRINT(debug_xform,
-+ "klips_error:ipsec_sa_put: "
-+ "null pointer passed in!\n");
-+ return -1;
-+ }
-+
-+ sa_len = satot(&ips->ips_said, 0, sa, sizeof(sa));
-+
-+ KLIPS_PRINT(debug_xform,
-+ "klips_debug:ipsec_sa_put: "
-+ "ipsec_sa SA:%s, ref:%d reference count decremented.\n",
-+ sa_len ? sa : " (error)",
-+ ips->ips_ref);
-+
-+ atomic_dec(&ips->ips_refcount);
-+
-+ return 0;
-+}
-+
-+/*
-+ The ipsec_sa table better *NOT* be locked before it is handed in, or SMP locks will happen
-+*/
-+int
-+ipsec_sa_add(struct ipsec_sa *ips)
-+{
-+ int error = 0;
-+ unsigned int hashval;
-+
-+ if(ips == NULL) {
-+ KLIPS_PRINT(debug_xform,
-+ "klips_error:ipsec_sa_add: "
-+ "null pointer passed in!\n");
-+ return -ENODATA;
-+ }
-+ hashval = IPS_HASH(&ips->ips_said);
-+
-+ atomic_inc(&ips->ips_refcount);
-+ spin_lock_bh(&tdb_lock);
-+
-+ ips->ips_hnext = ipsec_sadb_hash[hashval];
-+ ipsec_sadb_hash[hashval] = ips;
-+
-+ spin_unlock_bh(&tdb_lock);
-+
-+ return error;
-+}
-+
-+/*
-+ The ipsec_sa table better be locked before it is handed in, or races might happen
-+*/
-+int
-+ipsec_sa_del(struct ipsec_sa *ips)
-+{
-+ unsigned int hashval;
-+ struct ipsec_sa *ipstp;
-+ char sa[SATOT_BUF];
-+ size_t sa_len;
-+
-+ if(ips == NULL) {
-+ KLIPS_PRINT(debug_xform,
-+ "klips_error:ipsec_sa_del: "
-+ "null pointer passed in!\n");
-+ return -ENODATA;
-+ }
-+
-+ sa_len = satot(&ips->ips_said, 0, sa, sizeof(sa));
-+ if(ips->ips_inext || ips->ips_onext) {
-+ KLIPS_PRINT(debug_xform,
-+ "klips_error:ipsec_sa_del: "
-+ "SA:%s still linked!\n",
-+ sa_len ? sa : " (error)");
-+ return -EMLINK;
-+ }
-+
-+ hashval = IPS_HASH(&ips->ips_said);
-+
-+ KLIPS_PRINT(debug_xform,
-+ "klips_debug:ipsec_sa_del: "
-+ "deleting SA:%s, hashval=%d.\n",
-+ sa_len ? sa : " (error)",
-+ hashval);
-+ if(ipsec_sadb_hash[hashval] == NULL) {
-+ KLIPS_PRINT(debug_xform,
-+ "klips_debug:ipsec_sa_del: "
-+ "no entries in ipsec_sa table for hash=%d of SA:%s.\n",
-+ hashval,
-+ sa_len ? sa : " (error)");
-+ return -ENOENT;
-+ }
-+
-+ if (ips == ipsec_sadb_hash[hashval]) {
-+ ipsec_sadb_hash[hashval] = ipsec_sadb_hash[hashval]->ips_hnext;
-+ ips->ips_hnext = NULL;
-+ atomic_dec(&ips->ips_refcount);
-+ KLIPS_PRINT(debug_xform,
-+ "klips_debug:ipsec_sa_del: "
-+ "successfully deleted first ipsec_sa in chain.\n");
-+ return 0;
-+ } else {
-+ for (ipstp = ipsec_sadb_hash[hashval];
-+ ipstp;
-+ ipstp = ipstp->ips_hnext) {
-+ if (ipstp->ips_hnext == ips) {
-+ ipstp->ips_hnext = ips->ips_hnext;
-+ ips->ips_hnext = NULL;
-+ atomic_dec(&ips->ips_refcount);
-+ KLIPS_PRINT(debug_xform,
-+ "klips_debug:ipsec_sa_del: "
-+ "successfully deleted link in ipsec_sa chain.\n");
-+ return 0;
-+ }
-+ }
-+ }
-+
-+ KLIPS_PRINT(debug_xform,
-+ "klips_debug:ipsec_sa_del: "
-+ "no entries in linked list for hash=%d of SA:%s.\n",
-+ hashval,
-+ sa_len ? sa : " (error)");
-+ return -ENOENT;
-+}
-+
-+/*
-+ The ipsec_sa table better be locked before it is handed in, or races
-+ might happen
-+*/
-+int
-+ipsec_sa_delchain(struct ipsec_sa *ips)
-+{
-+ struct ipsec_sa *ipsdel;
-+ int error = 0;
-+ char sa[SATOT_BUF];
-+ size_t sa_len;
-+
-+ if(ips == NULL) {
-+ KLIPS_PRINT(debug_xform,
-+ "klips_error:ipsec_sa_delchain: "
-+ "null pointer passed in!\n");
-+ return -ENODATA;
-+ }
-+
-+ sa_len = satot(&ips->ips_said, 0, sa, sizeof(sa));
-+ KLIPS_PRINT(debug_xform,
-+ "klips_debug:ipsec_sa_delchain: "
-+ "passed SA:%s\n",
-+ sa_len ? sa : " (error)");
-+ while(ips->ips_onext != NULL) {
-+ ips = ips->ips_onext;
-+ }
-+
-+ while(ips) {
-+ /* XXX send a pfkey message up to advise of deleted ipsec_sa */
-+ sa_len = satot(&ips->ips_said, 0, sa, sizeof(sa));
-+ KLIPS_PRINT(debug_xform,
-+ "klips_debug:ipsec_sa_delchain: "
-+ "unlinking and delting SA:%s",
-+ sa_len ? sa : " (error)");
-+ ipsdel = ips;
-+ ips = ips->ips_inext;
-+ if(ips != NULL) {
-+ sa_len = satot(&ips->ips_said, 0, sa, sizeof(sa));
-+ KLIPS_PRINT(debug_xform,
-+ ", inext=%s",
-+ sa_len ? sa : " (error)");
-+ atomic_dec(&ipsdel->ips_refcount);
-+ ipsdel->ips_inext = NULL;
-+ atomic_dec(&ips->ips_refcount);
-+ ips->ips_onext = NULL;
-+ }
-+ KLIPS_PRINT(debug_xform,
-+ ".\n");
-+ if((error = ipsec_sa_del(ipsdel))) {
-+ KLIPS_PRINT(debug_xform,
-+ "klips_debug:ipsec_sa_delchain: "
-+ "ipsec_sa_del returned error %d.\n", -error);
-+ return error;
-+ }
-+ if((error = ipsec_sa_wipe(ipsdel))) {
-+ KLIPS_PRINT(debug_xform,
-+ "klips_debug:ipsec_sa_delchain: "
-+ "ipsec_sa_wipe returned error %d.\n", -error);
-+ return error;
-+ }
-+ }
-+ return error;
-+}
-+
-+int
-+ipsec_sadb_cleanup(__u8 proto)
-+{
-+ unsigned i;
-+ int error = 0;
-+ struct ipsec_sa *ips, **ipsprev, *ipsdel;
-+ char sa[SATOT_BUF];
-+ size_t sa_len;
-+
-+ KLIPS_PRINT(debug_xform,
-+ "klips_debug:ipsec_sadb_cleanup: "
-+ "cleaning up proto=%d.\n",
-+ proto);
-+
-+ spin_lock_bh(&tdb_lock);
-+
-+ for (i = 0; i < SADB_HASHMOD; i++) {
-+ ipsprev = &(ipsec_sadb_hash[i]);
-+ ips = ipsec_sadb_hash[i];
-+ if(ips != NULL) {
-+ atomic_inc(&ips->ips_refcount);
-+ }
-+ for(; ips != NULL;) {
-+ sa_len = satot(&ips->ips_said, 0, sa, sizeof(sa));
-+ KLIPS_PRINT(debug_xform,
-+ "klips_debug:ipsec_sadb_cleanup: "
-+ "checking SA:%s, hash=%d, ref=%d",
-+ sa_len ? sa : " (error)",
-+ i,
-+ ips->ips_ref);
-+ ipsdel = ips;
-+ ips = ipsdel->ips_hnext;
-+ if(ips != NULL) {
-+ atomic_inc(&ips->ips_refcount);
-+ sa_len = satot(&ips->ips_said, 0, sa, sizeof(sa));
-+ KLIPS_PRINT(debug_xform,
-+ ", hnext=%s",
-+ sa_len ? sa : " (error)");
-+ }
-+ if(*ipsprev != NULL) {
-+ sa_len = satot(&(*ipsprev)->ips_said, 0, sa, sizeof(sa));
-+ KLIPS_PRINT(debug_xform,
-+ ", *ipsprev=%s",
-+ sa_len ? sa : " (error)");
-+ if((*ipsprev)->ips_hnext) {
-+ sa_len = satot(&(*ipsprev)->ips_hnext->ips_said, 0, sa, sizeof(sa));
-+ KLIPS_PRINT(debug_xform,
-+ ", *ipsprev->ips_hnext=%s",
-+ sa_len ? sa : " (error)");
-+ }
-+ }
-+ KLIPS_PRINT(debug_xform,
-+ ".\n");
-+ if(proto == 0 || (proto == ipsdel->ips_said.proto)) {
-+ sa_len = satot(&ipsdel->ips_said, 0, sa, sizeof(sa));
-+ KLIPS_PRINT(debug_xform,
-+ "klips_debug:ipsec_sadb_cleanup: "
-+ "deleting SA chain:%s.\n",
-+ sa_len ? sa : " (error)");
-+ if((error = ipsec_sa_delchain(ipsdel))) {
-+ SENDERR(-error);
-+ }
-+ ipsprev = &(ipsec_sadb_hash[i]);
-+ ips = ipsec_sadb_hash[i];
-+
-+ KLIPS_PRINT(debug_xform,
-+ "klips_debug:ipsec_sadb_cleanup: "
-+ "deleted SA chain:%s",
-+ sa_len ? sa : " (error)");
-+ if(ips != NULL) {
-+ sa_len = satot(&ips->ips_said, 0, sa, sizeof(sa));
-+ KLIPS_PRINT(debug_xform,
-+ ", ipsec_sadb_hash[%d]=%s",
-+ i,
-+ sa_len ? sa : " (error)");
-+ }
-+ if(*ipsprev != NULL) {
-+ sa_len = satot(&(*ipsprev)->ips_said, 0, sa, sizeof(sa));
-+ KLIPS_PRINT(debug_xform,
-+ ", *ipsprev=%s",
-+ sa_len ? sa : " (error)");
-+ if((*ipsprev)->ips_hnext != NULL) {
-+ sa_len = satot(&(*ipsprev)->ips_hnext->ips_said, 0, sa, sizeof(sa));
-+ KLIPS_PRINT(debug_xform,
-+ ", *ipsprev->ips_hnext=%s",
-+ sa_len ? sa : " (error)");
-+ }
-+ }
-+ KLIPS_PRINT(debug_xform,
-+ ".\n");
-+ } else {
-+ ipsprev = &ipsdel;
-+ }
-+ if(ipsdel != NULL) {
-+ ipsec_sa_put(ipsdel);
-+ }
-+ }
-+ }
-+ errlab:
-+
-+ spin_unlock_bh(&tdb_lock);
-+
-+
-+#if IPSEC_SA_REF_CODE
-+ /* clean up SA reference table */
-+
-+ /* go through the ref table and clean out all the SAs */
-+ KLIPS_PRINT(debug_xform,
-+ "klips_debug:ipsec_sadb_cleanup: "
-+ "removing SAref entries and tables.");
-+ {
-+ unsigned table, entry;
-+ for(table = 0; table < IPSEC_SA_REF_MAINTABLE_NUM_ENTRIES; table++) {
-+ KLIPS_PRINT(debug_xform,
-+ "klips_debug:ipsec_sadb_cleanup: "
-+ "cleaning SAref table=%u.\n",
-+ table);
-+ if(ipsec_sadb.refTable[table] == NULL) {
-+ printk("\n");
-+ KLIPS_PRINT(debug_xform,
-+ "klips_debug:ipsec_sadb_cleanup: "
-+ "cleaned %u used refTables.\n",
-+ table);
-+ break;
-+ }
-+ for(entry = 0; entry < IPSEC_SA_REF_SUBTABLE_NUM_ENTRIES; entry++) {
-+ if(ipsec_sadb.refTable[table]->entry[entry] != NULL) {
-+ ipsec_sa_delchain(ipsec_sadb.refTable[table]->entry[entry]);
-+ ipsec_sadb.refTable[table]->entry[entry] = NULL;
-+ }
-+ }
-+ }
-+ }
-+#endif /* IPSEC_SA_REF_CODE */
-+
-+ return(error);
-+}
-+
-+int
-+ipsec_sadb_free(void)
-+{
-+ int error = 0;
-+
-+ KLIPS_PRINT(debug_xform,
-+ "klips_debug:ipsec_sadb_free: "
-+ "freeing SArefTable memory.\n");
-+
-+ /* clean up SA reference table */
-+
-+ /* go through the ref table and clean out all the SAs if any are
-+ left and free table memory */
-+ KLIPS_PRINT(debug_xform,
-+ "klips_debug:ipsec_sadb_free: "
-+ "removing SAref entries and tables.\n");
-+ {
-+ unsigned table, entry;
-+ for(table = 0; table < IPSEC_SA_REF_MAINTABLE_NUM_ENTRIES; table++) {
-+ KLIPS_PRINT(debug_xform,
-+ "klips_debug:ipsec_sadb_free: "
-+ "removing SAref table=%u.\n",
-+ table);
-+ if(ipsec_sadb.refTable[table] == NULL) {
-+ KLIPS_PRINT(debug_xform,
-+ "klips_debug:ipsec_sadb_free: "
-+ "removed %u used refTables.\n",
-+ table);
-+ break;
-+ }
-+ for(entry = 0; entry < IPSEC_SA_REF_SUBTABLE_NUM_ENTRIES; entry++) {
-+ if(ipsec_sadb.refTable[table]->entry[entry] != NULL) {
-+ ipsec_sa_delchain(ipsec_sadb.refTable[table]->entry[entry]);
-+ ipsec_sadb.refTable[table]->entry[entry] = NULL;
-+ }
-+ }
-+ vfree(ipsec_sadb.refTable[table]);
-+ ipsec_sadb.refTable[table] = NULL;
-+ }
-+ }
-+
-+ return(error);
-+}
-+
-+int
-+ipsec_sa_wipe(struct ipsec_sa *ips)
-+{
-+ if(ips == NULL) {
-+ return -ENODATA;
-+ }
-+
-+ /* if(atomic_dec_and_test(ips)) {
-+ }; */
-+
-+#if IPSEC_SA_REF_CODE
-+ /* remove me from the SArefTable */
-+ {
-+ char sa[SATOT_BUF];
-+ size_t sa_len;
-+ sa_len = satot(&ips->ips_said, 0, sa, sizeof(sa));
-+ KLIPS_PRINT(debug_xform,
-+ "klips_debug:ipsec_sa_wipe: "
-+ "removing SA=%s(0p%p), SAref=%d, table=%d(0p%p), entry=%d from the refTable.\n",
-+ sa_len ? sa : " (error)",
-+ ips,
-+ ips->ips_ref,
-+ IPsecSAref2table(IPsecSA2SAref(ips)),
-+ ipsec_sadb.refTable[IPsecSAref2table(IPsecSA2SAref(ips))],
-+ IPsecSAref2entry(IPsecSA2SAref(ips)));
-+ }
-+ if(ips->ips_ref == IPSEC_SAREF_NULL) {
-+ KLIPS_PRINT(debug_xform,
-+ "klips_debug:ipsec_sa_wipe: "
-+ "why does this SA not have a valid SAref?.\n");
-+ }
-+ ipsec_sadb.refTable[IPsecSAref2table(IPsecSA2SAref(ips))]->entry[IPsecSAref2entry(IPsecSA2SAref(ips))] = NULL;
-+ ips->ips_ref = IPSEC_SAREF_NULL;
-+ ipsec_sa_put(ips);
-+#endif /* IPSEC_SA_REF_CODE */
-+
-+ /* paranoid clean up */
-+ if(ips->ips_addr_s != NULL) {
-+ memset((caddr_t)(ips->ips_addr_s), 0, ips->ips_addr_s_size);
-+ kfree(ips->ips_addr_s);
-+ }
-+ ips->ips_addr_s = NULL;
-+
-+ if(ips->ips_addr_d != NULL) {
-+ memset((caddr_t)(ips->ips_addr_d), 0, ips->ips_addr_d_size);
-+ kfree(ips->ips_addr_d);
-+ }
-+ ips->ips_addr_d = NULL;
-+
-+ if(ips->ips_addr_p != NULL) {
-+ memset((caddr_t)(ips->ips_addr_p), 0, ips->ips_addr_p_size);
-+ kfree(ips->ips_addr_p);
-+ }
-+ ips->ips_addr_p = NULL;
-+
-+#ifdef CONFIG_IPSEC_NAT_TRAVERSAL
-+ if(ips->ips_natt_oa) {
-+ memset((caddr_t)(ips->ips_natt_oa), 0, ips->ips_natt_oa_size);
-+ kfree(ips->ips_natt_oa);
-+ }
-+ ips->ips_natt_oa = NULL;
-+#endif
-+
-+ if(ips->ips_key_a != NULL) {
-+ memset((caddr_t)(ips->ips_key_a), 0, ips->ips_key_a_size);
-+ kfree(ips->ips_key_a);
-+ }
-+ ips->ips_key_a = NULL;
-+
-+ if(ips->ips_key_e != NULL) {
-+#ifdef CONFIG_IPSEC_ALG
-+ if (ips->ips_alg_enc&&ips->ips_alg_enc->ixt_e_destroy_key) {
-+ ips->ips_alg_enc->ixt_e_destroy_key(ips->ips_alg_enc,
-+ ips->ips_key_e);
-+ } else {
-+#endif /* CONFIG_IPSEC_ALG */
-+ memset((caddr_t)(ips->ips_key_e), 0, ips->ips_key_e_size);
-+ kfree(ips->ips_key_e);
-+#ifdef CONFIG_IPSEC_ALG
-+ }
-+#endif /* CONFIG_IPSEC_ALG */
-+ }
-+ ips->ips_key_e = NULL;
-+
-+ if(ips->ips_iv != NULL) {
-+ memset((caddr_t)(ips->ips_iv), 0, ips->ips_iv_size);
-+ kfree(ips->ips_iv);
-+ }
-+ ips->ips_iv = NULL;
-+
-+ if(ips->ips_ident_s.data != NULL) {
-+ memset((caddr_t)(ips->ips_ident_s.data),
-+ 0,
-+ ips->ips_ident_s.len * IPSEC_PFKEYv2_ALIGN - sizeof(struct sadb_ident));
-+ kfree(ips->ips_ident_s.data);
-+ }
-+ ips->ips_ident_s.data = NULL;
-+
-+ if(ips->ips_ident_d.data != NULL) {
-+ memset((caddr_t)(ips->ips_ident_d.data),
-+ 0,
-+ ips->ips_ident_d.len * IPSEC_PFKEYv2_ALIGN - sizeof(struct sadb_ident));
-+ kfree(ips->ips_ident_d.data);
-+ }
-+ ips->ips_ident_d.data = NULL;
-+
-+#ifdef CONFIG_IPSEC_ALG
-+ if (ips->ips_alg_enc||ips->ips_alg_auth) {
-+ ipsec_alg_sa_wipe(ips);
-+ }
-+#endif /* CONFIG_IPSEC_ALG */
-+
-+ memset((caddr_t)ips, 0, sizeof(*ips));
-+ kfree(ips);
-+ ips = NULL;
-+
-+ return 0;
-+}
-+
-+/*
-+ * $Log: ipsec_sa.c,v $
-+ * Revision 1.23 2004/04/06 02:49:26 mcr
-+ * pullup of algo code from alg-branch.
-+ *
-+ * Revision 1.22.2.1 2003/12/22 15:25:52 jjo
-+ * . Merged algo-0.8.1-rc11-test1 into alg-branch
-+ *
-+ * Revision 1.22 2003/12/10 01:14:27 mcr
-+ * NAT-traversal patches to KLIPS.
-+ *
-+ * Revision 1.21 2003/10/31 02:27:55 mcr
-+ * pulled up port-selector patches and sa_id elimination.
-+ *
-+ * Revision 1.20.4.1 2003/10/29 01:30:41 mcr
-+ * elimited "struct sa_id".
-+ *
-+ * Revision 1.20 2003/02/06 01:50:34 rgb
-+ * Fixed initialisation bug for first sadb hash bucket that would only manifest itself on platforms where NULL != 0.
-+ *
-+ * Revision 1.19 2003/01/30 02:32:22 rgb
-+ *
-+ * Rename SAref table macro names for clarity.
-+ * Transmit error code through to caller from callee for better diagnosis of problems.
-+ * Convert IPsecSAref_t from signed to unsigned to fix apparent SAref exhaustion bug.
-+ *
-+ * Revision 1.18 2002/10/12 23:11:53 dhr
-+ *
-+ * [KenB + DHR] more 64-bit cleanup
-+ *
-+ * Revision 1.17 2002/10/07 18:31:43 rgb
-+ * Move field width sanity checks to ipsec_sa.c
-+ *
-+ * Revision 1.16 2002/09/20 15:41:02 rgb
-+ * Re-wrote most of the SAref code to eliminate Entry pointers.
-+ * Added SAref code compiler directive switch.
-+ * Added a saref test function for testing macros.
-+ * Switch from pfkey_alloc_ipsec_sa() to ipsec_sa_alloc().
-+ * Split ipsec_sadb_cleanup from new funciton ipsec_sadb_free to avoid problem
-+ * of freeing newly created structures when clearing the reftable upon startup
-+ * to start from a known state.
-+ * Place all ipsec sadb globals into one struct.
-+ * Rework saref freelist.
-+ * Added memory allocation debugging.
-+ *
-+ * Revision 1.15 2002/09/20 05:01:44 rgb
-+ * Update copyright date.
-+ *
-+ * Revision 1.14 2002/08/13 19:01:25 mcr
-+ * patches from kenb to permit compilation of FreeSWAN on ia64.
-+ * des library patched to use proper DES_LONG type for ia64.
-+ *
-+ * Revision 1.13 2002/07/29 03:06:20 mcr
-+ * get rid of variable not used warnings.
-+ *
-+ * Revision 1.12 2002/07/26 08:48:31 rgb
-+ * Added SA ref table code.
-+ *
-+ * Revision 1.11 2002/06/04 16:48:49 rgb
-+ * Tidied up pointer code for processor independance.
-+ *
-+ * Revision 1.10 2002/05/23 07:16:17 rgb
-+ * Added ipsec_sa_put() for releasing an ipsec_sa refcount.
-+ * Pointer clean-up.
-+ * Added refcount code.
-+ * Convert "usecount" to "refcount" to remove ambiguity.
-+ *
-+ * Revision 1.9 2002/05/14 02:34:49 rgb
-+ * Converted reference from ipsec_sa_put to ipsec_sa_add to avoid confusion
-+ * with "put" usage in the kernel.
-+ * Change all references to tdb, TDB or Tunnel Descriptor Block to ips,
-+ * ipsec_sa or ipsec_sa.
-+ * Added some preliminary refcount code.
-+ *
-+ * Revision 1.8 2002/04/24 07:55:32 mcr
-+ * #include patches and Makefiles for post-reorg compilation.
-+ *
-+ * Revision 1.7 2002/04/24 07:36:30 mcr
-+ * Moved from ./klips/net/ipsec/ipsec_sa.c,v
-+ *
-+ * Revision 1.6 2002/04/20 00:12:25 rgb
-+ * Added esp IV CBC attack fix, disabled.
-+ *
-+ * Revision 1.5 2002/01/29 17:17:56 mcr
-+ * moved include of ipsec_param.h to after include of linux/kernel.h
-+ * otherwise, it seems that some option that is set in ipsec_param.h
-+ * screws up something subtle in the include path to kernel.h, and
-+ * it complains on the snprintf() prototype.
-+ *
-+ * Revision 1.4 2002/01/29 04:00:52 mcr
-+ * more excise of kversions.h header.
-+ *
-+ * Revision 1.3 2002/01/29 02:13:18 mcr
-+ * introduction of ipsec_kversion.h means that include of
-+ * ipsec_param.h must preceed any decisions about what files to
-+ * include to deal with differences in kernel source.
-+ *
-+ * Revision 1.2 2001/11/26 09:16:15 rgb
-+ * Merge MCR's ipsec_sa, eroute, proc and struct lifetime changes.
-+ *
-+ * Revision 1.1.2.2 2001/10/22 21:05:41 mcr
-+ * removed phony prototype for des_set_key.
-+ *
-+ * Revision 1.1.2.1 2001/09/25 02:24:57 mcr
-+ * struct tdb -> struct ipsec_sa.
-+ * sa(tdb) manipulation functions renamed and moved to ipsec_sa.c
-+ * ipsec_xform.c removed. header file still contains useful things.
-+ *
-+ *
-+ *
-+ * CLONED from ipsec_xform.c:
-+ * Revision 1.53 2001/09/08 21:13:34 rgb
-+ * Added pfkey ident extension support for ISAKMPd. (NetCelo)
-+ *
-+ * Revision 1.52 2001/06/14 19:35:11 rgb
-+ * Update copyright date.
-+ *
-+ * Revision 1.51 2001/05/30 08:14:03 rgb
-+ * Removed vestiges of esp-null transforms.
-+ *
-+ * Revision 1.50 2001/05/03 19:43:18 rgb
-+ * Initialise error return variable.
-+ * Update SENDERR macro.
-+ * Fix sign of error return code for ipsec_tdbcleanup().
-+ * Use more appropriate return code for ipsec_tdbwipe().
-+ *
-+ * Revision 1.49 2001/04/19 18:56:17 rgb
-+ * Fixed tdb table locking comments.
-+ *
-+ * Revision 1.48 2001/02/27 22:24:55 rgb
-+ * Re-formatting debug output (line-splitting, joining, 1arg/line).
-+ * Check for satoa() return codes.
-+ *
-+ * Revision 1.47 2000/11/06 04:32:08 rgb
-+ * Ditched spin_lock_irqsave in favour of spin_lock_bh.
-+ *
-+ * Revision 1.46 2000/09/20 16:21:57 rgb
-+ * Cleaned up ident string alloc/free.
-+ *
-+ * Revision 1.45 2000/09/08 19:16:51 rgb
-+ * Change references from DEBUG_IPSEC to CONFIG_IPSEC_DEBUG.
-+ * Removed all references to CONFIG_IPSEC_PFKEYv2.
-+ *
-+ * Revision 1.44 2000/08/30 05:29:04 rgb
-+ * Compiler-define out no longer used tdb_init() in ipsec_xform.c.
-+ *
-+ * Revision 1.43 2000/08/18 21:30:41 rgb
-+ * Purged all tdb_spi, tdb_proto and tdb_dst macros. They are unclear.
-+ *
-+ * Revision 1.42 2000/08/01 14:51:51 rgb
-+ * Removed _all_ remaining traces of DES.
-+ *
-+ * Revision 1.41 2000/07/28 14:58:31 rgb
-+ * Changed kfree_s to kfree, eliminating extra arg to fix 2.4.0-test5.
-+ *
-+ * Revision 1.40 2000/06/28 05:50:11 rgb
-+ * Actually set iv_bits.
-+ *
-+ * Revision 1.39 2000/05/10 23:11:09 rgb
-+ * Added netlink debugging output.
-+ * Added a cast to quiet down the ntohl bug.
-+ *
-+ * Revision 1.38 2000/05/10 19:18:42 rgb
-+ * Cast output of ntohl so that the broken prototype doesn't make our
-+ * compile noisy.
-+ *
-+ * Revision 1.37 2000/03/16 14:04:59 rgb
-+ * Hardwired CONFIG_IPSEC_PFKEYv2 on.
-+ *
-+ * Revision 1.36 2000/01/26 10:11:28 rgb
-+ * Fixed spacing in error text causing run-in words.
-+ *
-+ * Revision 1.35 2000/01/21 06:17:16 rgb
-+ * Tidied up compiler directive indentation for readability.
-+ * Added ictx,octx vars for simplification.(kravietz)
-+ * Added macros for HMAC padding magic numbers.(kravietz)
-+ * Fixed missing key length reporting bug.
-+ * Fixed bug in tdbwipe to return immediately on NULL tdbp passed in.
-+ *
-+ * Revision 1.34 1999/12/08 00:04:19 rgb
-+ * Fixed SA direction overwriting bug for netlink users.
-+ *
-+ * Revision 1.33 1999/12/01 22:16:44 rgb
-+ * Minor formatting changes in ESP MD5 initialisation.
-+ *
-+ * Revision 1.32 1999/11/25 09:06:36 rgb
-+ * Fixed error return messages, should be returning negative numbers.
-+ * Implemented SENDERR macro for propagating error codes.
-+ * Added debug message and separate error code for algorithms not compiled
-+ * in.
-+ *
-+ * Revision 1.31 1999/11/23 23:06:26 rgb
-+ * Sort out pfkey and freeswan headers, putting them in a library path.
-+ *
-+ * Revision 1.30 1999/11/18 04:09:20 rgb
-+ * Replaced all kernel version macros to shorter, readable form.
-+ *
-+ * Revision 1.29 1999/11/17 15:53:40 rgb
-+ * Changed all occurrences of #include "../../../lib/freeswan.h"
-+ * to #include <freeswan.h> which works due to -Ilibfreeswan in the
-+ * klips/net/ipsec/Makefile.
-+ *
-+ * Revision 1.28 1999/10/18 20:04:01 rgb
-+ * Clean-out unused cruft.
-+ *
-+ * Revision 1.27 1999/10/03 19:01:03 rgb
-+ * Spinlock support for 2.3.xx and 2.0.xx kernels.
-+ *
-+ * Revision 1.26 1999/10/01 16:22:24 rgb
-+ * Switch from assignment init. to functional init. of spinlocks.
-+ *
-+ * Revision 1.25 1999/10/01 15:44:54 rgb
-+ * Move spinlock header include to 2.1> scope.
-+ *
-+ * Revision 1.24 1999/10/01 00:03:46 rgb
-+ * Added tdb structure locking.
-+ * Minor formatting changes.
-+ * Add function to initialize tdb hash table.
-+ *
-+ * Revision 1.23 1999/05/25 22:42:12 rgb
-+ * Add deltdbchain() debugging.
-+ *
-+ * Revision 1.22 1999/05/25 21:24:31 rgb
-+ * Add debugging statements to deltdbchain().
-+ *
-+ * Revision 1.21 1999/05/25 03:51:48 rgb
-+ * Refix error return code.
-+ *
-+ * Revision 1.20 1999/05/25 03:34:07 rgb
-+ * Fix error return for flush.
-+ *
-+ * Revision 1.19 1999/05/09 03:25:37 rgb
-+ * Fix bug introduced by 2.2 quick-and-dirty patch.
-+ *
-+ * Revision 1.18 1999/05/05 22:02:32 rgb
-+ * Add a quick and dirty port to 2.2 kernels by Marc Boucher <marc@mbsi.ca>.
-+ *
-+ * Revision 1.17 1999/04/29 15:20:16 rgb
-+ * Change gettdb parameter to a pointer to reduce stack loading and
-+ * facilitate parameter sanity checking.
-+ * Add sanity checking for null pointer arguments.
-+ * Add debugging instrumentation.
-+ * Add function deltdbchain() which will take care of unlinking,
-+ * zeroing and deleting a chain of tdbs.
-+ * Add a parameter to tdbcleanup to be able to delete a class of SAs.
-+ * tdbwipe now actually zeroes the tdb as well as any of its pointed
-+ * structures.
-+ *
-+ * Revision 1.16 1999/04/16 15:36:29 rgb
-+ * Fix cut-and-paste error causing a memory leak in IPIP TDB freeing.
-+ *
-+ * Revision 1.15 1999/04/11 00:29:01 henry
-+ * GPL boilerplate
-+ *
-+ * Revision 1.14 1999/04/06 04:54:28 rgb
-+ * Fix/Add RCSID Id: and Log: bits to make PHMDs happy. This includes
-+ * patch shell fixes.
-+ *
-+ * Revision 1.13 1999/02/19 18:23:01 rgb
-+ * Nix debug off compile warning.
-+ *
-+ * Revision 1.12 1999/02/17 16:52:16 rgb
-+ * Consolidate satoa()s for space and speed efficiency.
-+ * Convert DEBUG_IPSEC to KLIPS_PRINT
-+ * Clean out unused cruft.
-+ * Ditch NET_IPIP dependancy.
-+ * Loop for 3des key setting.
-+ *
-+ * Revision 1.11 1999/01/26 02:09:05 rgb
-+ * Remove ah/esp/IPIP switching on include files.
-+ * Removed CONFIG_IPSEC_ALGO_SWITCH macro.
-+ * Removed dead code.
-+ * Clean up debug code when switched off.
-+ * Remove references to INET_GET_PROTOCOL.
-+ * Added code exclusion macros to reduce code from unused algorithms.
-+ *
-+ * Revision 1.10 1999/01/22 06:28:55 rgb
-+ * Cruft clean-out.
-+ * Put random IV generation in kernel.
-+ * Added algorithm switch code.
-+ * Enhanced debugging.
-+ * 64-bit clean-up.
-+ *
-+ * Revision 1.9 1998/11/30 13:22:55 rgb
-+ * Rationalised all the klips kernel file headers. They are much shorter
-+ * now and won't conflict under RH5.2.
-+ *
-+ * Revision 1.8 1998/11/25 04:59:06 rgb
-+ * Add conditionals for no IPIP tunnel code.
-+ * Delete commented out code.
-+ *
-+ * Revision 1.7 1998/10/31 06:50:41 rgb
-+ * Convert xform ASCII names to no spaces.
-+ * Fixed up comments in #endif directives.
-+ *
-+ * Revision 1.6 1998/10/19 14:44:28 rgb
-+ * Added inclusion of freeswan.h.
-+ * sa_id structure implemented and used: now includes protocol.
-+ *
-+ * Revision 1.5 1998/10/09 04:32:19 rgb
-+ * Added 'klips_debug' prefix to all klips printk debug statements.
-+ *
-+ * Revision 1.4 1998/08/12 00:11:31 rgb
-+ * Added new xform functions to the xform table.
-+ * Fixed minor debug output spelling error.
-+ *
-+ * Revision 1.3 1998/07/09 17:45:31 rgb
-+ * Clarify algorithm not available message.
-+ *
-+ * Revision 1.2 1998/06/23 03:00:51 rgb
-+ * Check for presence of IPIP protocol if it is setup one way (we don't
-+ * know what has been set up the other way and can only assume it will be
-+ * symmetrical with the exception of keys).
-+ *
-+ * Revision 1.1 1998/06/18 21:27:51 henry
-+ * move sources from klips/src to klips/net/ipsec, to keep stupid
-+ * kernel-build scripts happier in the presence of symlinks
-+ *
-+ * Revision 1.3 1998/06/11 05:54:59 rgb
-+ * Added transform version string pointer to xformsw initialisations.
-+ *
-+ * Revision 1.2 1998/04/21 21:28:57 rgb
-+ * Rearrange debug switches to change on the fly debug output from user
-+ * space. Only kernel changes checked in at this time. radij.c was also
-+ * changed to temporarily remove buggy debugging code in rj_delete causing
-+ * an OOPS and hence, netlink device open errors.
-+ *
-+ * Revision 1.1 1998/04/09 03:06:13 henry
-+ * sources moved up from linux/net/ipsec
-+ *
-+ * Revision 1.1.1.1 1998/04/08 05:35:02 henry
-+ * RGB's ipsec-0.8pre2.tar.gz ipsec-0.8
-+ *
-+ * Revision 0.5 1997/06/03 04:24:48 ji
-+ * Added ESP-3DES-MD5-96
-+ *
-+ * Revision 0.4 1997/01/15 01:28:15 ji
-+ * Added new transforms.
-+ *
-+ * Revision 0.3 1996/11/20 14:39:04 ji
-+ * Minor cleanups.
-+ * Rationalized debugging code.
-+ *
-+ * Revision 0.2 1996/11/02 00:18:33 ji
-+ * First limited release.
-+ *
-+ *
-+ */
---- /dev/null Tue Mar 11 13:02:56 2003
-+++ linux/net/ipsec/ipsec_sha1.c Mon Feb 9 13:51:03 2004
-@@ -0,0 +1,219 @@
-+/*
-+ * RCSID $Id: ipsec_sha1.c,v 1.9 2004/04/06 02:49:26 mcr Exp $
-+ */
-+
-+/*
-+ * The rest of the code is derived from sha1.c by Steve Reid, which is
-+ * public domain.
-+ * Minor cosmetic changes to accomodate it in the Linux kernel by ji.
-+ */
-+
-+#include <asm/byteorder.h>
-+#include <linux/string.h>
-+
-+#include "openswan/ipsec_sha1.h"
-+
-+#if defined(rol)
-+#undef rol
-+#endif
-+
-+#define SHA1HANDSOFF
-+
-+#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits))))
-+
-+/* blk0() and blk() perform the initial expand. */
-+/* I got the idea of expanding during the round function from SSLeay */
-+#ifdef __LITTLE_ENDIAN
-+#define blk0(i) (block->l[i] = (rol(block->l[i],24)&0xFF00FF00) \
-+ |(rol(block->l[i],8)&0x00FF00FF))
-+#else
-+#define blk0(i) block->l[i]
-+#endif
-+#define blk(i) (block->l[i&15] = rol(block->l[(i+13)&15]^block->l[(i+8)&15] \
-+ ^block->l[(i+2)&15]^block->l[i&15],1))
-+
-+/* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */
-+#define R0(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk0(i)+0x5A827999+rol(v,5);w=rol(w,30);
-+#define R1(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=rol(w,30);
-+#define R2(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30);
-+#define R3(v,w,x,y,z,i) z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30);
-+#define R4(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30);
-+
-+
-+/* Hash a single 512-bit block. This is the core of the algorithm. */
-+
-+void SHA1Transform(__u32 state[5], __u8 buffer[64])
-+{
-+__u32 a, b, c, d, e;
-+typedef union {
-+ unsigned char c[64];
-+ __u32 l[16];
-+} CHAR64LONG16;
-+CHAR64LONG16* block;
-+#ifdef SHA1HANDSOFF
-+static unsigned char workspace[64];
-+ block = (CHAR64LONG16*)workspace;
-+ memcpy(block, buffer, 64);
-+#else
-+ block = (CHAR64LONG16*)buffer;
-+#endif
-+ /* Copy context->state[] to working vars */
-+ a = state[0];
-+ b = state[1];
-+ c = state[2];
-+ d = state[3];
-+ e = state[4];
-+ /* 4 rounds of 20 operations each. Loop unrolled. */
-+ R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3);
-+ R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7);
-+ R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11);
-+ R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15);
-+ R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19);
-+ R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23);
-+ R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27);
-+ R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31);
-+ R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35);
-+ R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39);
-+ R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43);
-+ R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47);
-+ R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51);
-+ R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55);
-+ R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59);
-+ R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63);
-+ R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67);
-+ R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71);
-+ R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75);
-+ R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79);
-+ /* Add the working vars back into context.state[] */
-+ state[0] += a;
-+ state[1] += b;
-+ state[2] += c;
-+ state[3] += d;
-+ state[4] += e;
-+ /* Wipe variables */
-+ a = b = c = d = e = 0;
-+}
-+
-+
-+/* SHA1Init - Initialize new context */
-+
-+void SHA1Init(void *vcontext)
-+{
-+ SHA1_CTX* context = vcontext;
-+
-+ /* SHA1 initialization constants */
-+ context->state[0] = 0x67452301;
-+ context->state[1] = 0xEFCDAB89;
-+ context->state[2] = 0x98BADCFE;
-+ context->state[3] = 0x10325476;
-+ context->state[4] = 0xC3D2E1F0;
-+ context->count[0] = context->count[1] = 0;
-+}
-+
-+
-+/* Run your data through this. */
-+
-+void SHA1Update(void *vcontext, unsigned char* data, __u32 len)
-+{
-+ SHA1_CTX* context = vcontext;
-+ __u32 i, j;
-+
-+ j = context->count[0];
-+ if ((context->count[0] += len << 3) < j)
-+ context->count[1]++;
-+ context->count[1] += (len>>29);
-+ j = (j >> 3) & 63;
-+ if ((j + len) > 63) {
-+ memcpy(&context->buffer[j], data, (i = 64-j));
-+ SHA1Transform(context->state, context->buffer);
-+ for ( ; i + 63 < len; i += 64) {
-+ SHA1Transform(context->state, &data[i]);
-+ }
-+ j = 0;
-+ }
-+ else i = 0;
-+ memcpy(&context->buffer[j], &data[i], len - i);
-+}
-+
-+
-+/* Add padding and return the message digest. */
-+
-+void SHA1Final(unsigned char digest[20], void *vcontext)
-+{
-+ __u32 i, j;
-+ unsigned char finalcount[8];
-+ SHA1_CTX* context = vcontext;
-+
-+ for (i = 0; i < 8; i++) {
-+ finalcount[i] = (unsigned char)((context->count[(i >= 4 ? 0 : 1)]
-+ >> ((3-(i & 3)) * 8) ) & 255); /* Endian independent */
-+ }
-+ SHA1Update(context, (unsigned char *)"\200", 1);
-+ while ((context->count[0] & 504) != 448) {
-+ SHA1Update(context, (unsigned char *)"\0", 1);
-+ }
-+ SHA1Update(context, finalcount, 8); /* Should cause a SHA1Transform() */
-+ for (i = 0; i < 20; i++) {
-+ digest[i] = (unsigned char)
-+ ((context->state[i>>2] >> ((3-(i & 3)) * 8) ) & 255);
-+ }
-+ /* Wipe variables */
-+ i = j = 0;
-+ memset(context->buffer, 0, 64);
-+ memset(context->state, 0, 20);
-+ memset(context->count, 0, 8);
-+ memset(&finalcount, 0, 8);
-+#ifdef SHA1HANDSOFF /* make SHA1Transform overwrite its own static vars */
-+ SHA1Transform(context->state, context->buffer);
-+#endif
-+}
-+
-+
-+/*
-+ * $Log: ipsec_sha1.c,v $
-+ * Revision 1.9 2004/04/06 02:49:26 mcr
-+ * pullup of algo code from alg-branch.
-+ *
-+ * Revision 1.8 2002/09/10 01:45:14 mcr
-+ * changed type of MD5_CTX and SHA1_CTX to void * so that
-+ * the function prototypes would match, and could be placed
-+ * into a pointer to a function.
-+ *
-+ * Revision 1.7 2002/04/24 07:55:32 mcr
-+ * #include patches and Makefiles for post-reorg compilation.
-+ *
-+ * Revision 1.6 2002/04/24 07:36:30 mcr
-+ * Moved from ./klips/net/ipsec/ipsec_sha1.c,v
-+ *
-+ * Revision 1.5 1999/12/13 13:59:13 rgb
-+ * Quick fix to argument size to Update bugs.
-+ *
-+ * Revision 1.4 1999/04/11 00:29:00 henry
-+ * GPL boilerplate
-+ *
-+ * Revision 1.3 1999/04/06 04:54:27 rgb
-+ * Fix/Add RCSID Id: and Log: bits to make PHMDs happy. This includes
-+ * patch shell fixes.
-+ *
-+ * Revision 1.2 1999/01/22 06:55:50 rgb
-+ * 64-bit clean-up.
-+ *
-+ * Revision 1.1 1998/06/18 21:27:50 henry
-+ * move sources from klips/src to klips/net/ipsec, to keep stupid
-+ * kernel-build scripts happier in the presence of symlinks
-+ *
-+ * Revision 1.2 1998/04/23 20:54:04 rgb
-+ * Fixed md5 and sha1 include file nesting issues, to be cleaned up when
-+ * verified.
-+ *
-+ * Revision 1.1 1998/04/09 03:06:11 henry
-+ * sources moved up from linux/net/ipsec
-+ *
-+ * Revision 1.1.1.1 1998/04/08 05:35:05 henry
-+ * RGB's ipsec-0.8pre2.tar.gz ipsec-0.8
-+ *
-+ * Revision 0.4 1997/01/15 01:28:15 ji
-+ * New transform
-+ *
-+ *
-+ */
---- /dev/null Tue Mar 11 13:02:56 2003
-+++ linux/net/ipsec/ipsec_tunnel.c Mon Feb 9 13:51:03 2004
-@@ -0,0 +1,2645 @@
-+/*
-+ * IPSEC Tunneling code. Heavily based on drivers/net/new_tunnel.c
-+ * Copyright (C) 1996, 1997 John Ioannidis.
-+ * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 Richard Guy Briggs.
-+ *
-+ * 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. See <http://www.fsf.org/copyleft/gpl.txt>.
-+ *
-+ * 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.
-+ */
-+
-+char ipsec_tunnel_c_version[] = "RCSID $Id: ipsec_tunnel.c,v 1.220 2004/04/06 02:49:26 mcr Exp $";
-+
-+#define __NO_VERSION__
-+#include <linux/module.h>
-+#include <linux/config.h> /* for CONFIG_IP_FORWARD */
-+#include <linux/version.h>
-+#include <linux/kernel.h> /* printk() */
-+
-+#include "openswan/ipsec_param.h"
-+
-+#ifdef MALLOC_SLAB
-+# include <linux/slab.h> /* kmalloc() */
-+#else /* MALLOC_SLAB */
-+# include <linux/malloc.h> /* kmalloc() */
-+#endif /* MALLOC_SLAB */
-+#include <linux/errno.h> /* error codes */
-+#include <linux/types.h> /* size_t */
-+#include <linux/interrupt.h> /* mark_bh */
-+
-+#include <linux/netdevice.h> /* struct device, struct net_device_stats, dev_queue_xmit() and other headers */
-+#include <linux/etherdevice.h> /* eth_type_trans */
-+#include <linux/ip.h> /* struct iphdr */
-+#include <linux/tcp.h> /* struct tcphdr */
-+#include <linux/udp.h> /* struct udphdr */
-+#include <linux/skbuff.h>
-+#include <openswan.h>
-+#ifdef NET_21
-+# include <asm/uaccess.h>
-+# include <linux/in6.h>
-+# define ip_chk_addr inet_addr_type
-+# define IS_MYADDR RTN_LOCAL
-+# include <net/dst.h>
-+# undef dev_kfree_skb
-+# define dev_kfree_skb(a,b) kfree_skb(a)
-+# define PHYSDEV_TYPE
-+#endif /* NET_21 */
-+#include <asm/checksum.h>
-+#include <net/icmp.h> /* icmp_send() */
-+#include <net/ip.h>
-+#ifdef NETDEV_23
-+# include <linux/netfilter_ipv4.h>
-+#endif /* NETDEV_23 */
-+
-+#include <linux/if_arp.h>
-+
-+#include "openswan/radij.h"
-+#include "openswan/ipsec_life.h"
-+#include "openswan/ipsec_xform.h"
-+#include "openswan/ipsec_eroute.h"
-+#include "openswan/ipsec_encap.h"
-+#include "openswan/ipsec_radij.h"
-+#include "openswan/ipsec_sa.h"
-+#include "openswan/ipsec_tunnel.h"
-+#include "openswan/ipsec_xmit.h"
-+#include "openswan/ipsec_ipe4.h"
-+#include "openswan/ipsec_ah.h"
-+#include "openswan/ipsec_esp.h"
-+
-+#include <pfkeyv2.h>
-+#include <pfkey.h>
-+
-+#include "openswan/ipsec_proto.h"
-+#ifdef CONFIG_IPSEC_NAT_TRAVERSAL
-+#include <linux/udp.h>
-+#endif
-+
-+static __u32 zeroes[64];
-+
-+#ifdef CONFIG_IPSEC_DEBUG
-+int debug_tunnel = 0;
-+#endif /* CONFIG_IPSEC_DEBUG */
-+
-+DEBUG_NO_STATIC int
-+ipsec_tunnel_open(struct device *dev)
-+{
-+ struct ipsecpriv *prv = dev->priv;
-+
-+ /*
-+ * Can't open until attached.
-+ */
-+
-+ KLIPS_PRINT(debug_tunnel & DB_TN_INIT,
-+ "klips_debug:ipsec_tunnel_open: "
-+ "dev = %s, prv->dev = %s\n",
-+ dev->name, prv->dev?prv->dev->name:"NONE");
-+
-+ if (prv->dev == NULL)
-+ return -ENODEV;
-+
-+ MOD_INC_USE_COUNT;
-+ return 0;
-+}
-+
-+DEBUG_NO_STATIC int
-+ipsec_tunnel_close(struct device *dev)
-+{
-+ MOD_DEC_USE_COUNT;
-+ return 0;
-+}
-+
-+#ifdef NETDEV_23
-+static inline int ipsec_tunnel_xmit2(struct sk_buff *skb)
-+{
-+#ifdef NETDEV_25 /* 2.6 kernels */
-+ return dst_output(skb);
-+#else
-+ return ip_send(skb);
-+#endif
-+}
-+#endif /* NETDEV_23 */
-+
-+enum ipsec_xmit_value
-+ipsec_tunnel_strip_hard_header(struct ipsec_xmit_state *ixs)
-+{
-+ /* ixs->physdev->hard_header_len is unreliable and should not be used */
-+ ixs->hard_header_len = (unsigned char *)(ixs->iph) - ixs->skb->data;
-+
-+ if(ixs->hard_header_len < 0) {
-+ KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
-+ "klips_error:ipsec_xmit_strip_hard_header: "
-+ "Negative hard_header_len (%d)?!\n", ixs->hard_header_len);
-+ ixs->stats->tx_dropped++;
-+ return IPSEC_XMIT_BADHHLEN;
-+ }
-+
-+ /* while ixs->physdev->hard_header_len is unreliable and
-+ * should not be trusted, it accurate and required for ATM, GRE and
-+ * some other interfaces to work. Thanks to Willy Tarreau
-+ * <willy@w.ods.org>.
-+ */
-+ if(ixs->hard_header_len == 0) { /* no hard header present */
-+ ixs->hard_header_stripped = 1;
-+ ixs->hard_header_len = ixs->physdev->hard_header_len;
-+ }
-+
-+#ifdef CONFIG_IPSEC_DEBUG
-+ if (debug_tunnel & DB_TN_XMIT) {
-+ int i;
-+ char c;
-+
-+ printk(KERN_INFO "klips_debug:ipsec_xmit_strip_hard_header: "
-+ ">>> skb->len=%ld hard_header_len:%d",
-+ (unsigned long int)ixs->skb->len, ixs->hard_header_len);
-+ c = ' ';
-+ for (i=0; i < ixs->hard_header_len; i++) {
-+ printk("%c%02x", c, ixs->skb->data[i]);
-+ c = ':';
-+ }
-+ printk(" \n");
-+ }
-+#endif /* CONFIG_IPSEC_DEBUG */
-+
-+ KLIPS_IP_PRINT(debug_tunnel & DB_TN_XMIT, ixs->iph);
-+
-+ KLIPS_PRINT(debug_tunnel & DB_TN_CROUT,
-+ "klips_debug:ipsec_xmit_strip_hard_header: "
-+ "Original head,tailroom: %d,%d\n",
-+ skb_headroom(ixs->skb), skb_tailroom(ixs->skb));
-+
-+ return IPSEC_XMIT_OK;
-+}
-+
-+enum ipsec_xmit_value
-+ipsec_tunnel_SAlookup(struct ipsec_xmit_state *ixs)
-+{
-+ /*
-+ * First things first -- look us up in the erouting tables.
-+ */
-+ ixs->matcher.sen_len = sizeof (struct sockaddr_encap);
-+ ixs->matcher.sen_family = AF_ENCAP;
-+ ixs->matcher.sen_type = SENT_IP4;
-+ ixs->matcher.sen_ip_src.s_addr = ixs->iph->saddr;
-+ ixs->matcher.sen_ip_dst.s_addr = ixs->iph->daddr;
-+ ixs->matcher.sen_proto = ixs->iph->protocol;
-+ ipsec_extract_ports(ixs->iph, &ixs->matcher);
-+
-+ /*
-+ * The spinlock is to prevent any other process from accessing or deleting
-+ * the eroute while we are using and updating it.
-+ */
-+ spin_lock(&eroute_lock);
-+
-+ ixs->eroute = ipsec_findroute(&ixs->matcher);
-+
-+ if(ixs->iph->protocol == IPPROTO_UDP) {
-+ if(ixs->skb->sk) {
-+ ixs->sport=ntohs(ixs->skb->sk->sport);
-+ ixs->dport=ntohs(ixs->skb->sk->dport);
-+ } else if((ntohs(ixs->iph->frag_off) & IP_OFFSET) == 0 &&
-+ ((ixs->skb->len - ixs->hard_header_len) >=
-+ ((ixs->iph->ihl << 2) + sizeof(struct udphdr)))) {
-+ ixs->sport=ntohs(((struct udphdr*)((caddr_t)ixs->iph+(ixs->iph->ihl<<2)))->source);
-+ ixs->dport=ntohs(((struct udphdr*)((caddr_t)ixs->iph + (ixs->iph->ihl<<2)))->dest);
-+ } else {
-+ ixs->sport=0; ixs->dport=0;
-+ }
-+ }
-+
-+ /* default to a %drop eroute */
-+ ixs->outgoing_said.proto = IPPROTO_INT;
-+ ixs->outgoing_said.spi = htonl(SPI_DROP);
-+ ixs->outgoing_said.dst.u.v4.sin_addr.s_addr = INADDR_ANY;
-+ KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
-+ "klips_debug:ipsec_xmit_SAlookup: "
-+ "checking for local udp/500 IKE packet "
-+ "saddr=%x, er=0p%p, daddr=%x, er_dst=%x, proto=%d sport=%d dport=%d\n",
-+ ntohl((unsigned int)ixs->iph->saddr),
-+ ixs->eroute,
-+ ntohl((unsigned int)ixs->iph->daddr),
-+ ixs->eroute ? ntohl((unsigned int)ixs->eroute->er_said.dst.u.v4.sin_addr.s_addr) : 0,
-+ ixs->iph->protocol,
-+ ixs->sport,
-+ ixs->dport);
-+
-+ /*
-+ * Quick cheat for now...are we udp/500? If so, let it through
-+ * without interference since it is most likely an IKE packet.
-+ */
-+
-+ if (ip_chk_addr((unsigned long)ixs->iph->saddr) == IS_MYADDR
-+ && (!ixs->eroute
-+ || ixs->iph->daddr == ixs->eroute->er_said.dst.u.v4.sin_addr.s_addr
-+ || INADDR_ANY == ixs->eroute->er_said.dst.u.v4.sin_addr.s_addr)
-+
-+ && ((ixs->sport == 500) || (ixs->sport == 4500))) {
-+ /* Whatever the eroute, this is an IKE message
-+ * from us (i.e. not being forwarded).
-+ * Furthermore, if there is a tunnel eroute,
-+ * the destination is the peer for this eroute.
-+ * So %pass the packet: modify the default %drop.
-+ */
-+ ixs->outgoing_said.spi = htonl(SPI_PASS);
-+ if(!(ixs->skb->sk) && ((ntohs(ixs->iph->frag_off) & IP_MF) != 0)) {
-+ KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
-+ "klips_debug:ipsec_xmit_SAlookup: "
-+ "local UDP/500 (probably IKE) passthrough: base fragment, rest of fragments will probably get filtered.\n");
-+ }
-+ } else if (ixs->eroute) {
-+ ixs->eroute->er_count++;
-+ ixs->eroute->er_lasttime = jiffies/HZ;
-+ if(ixs->eroute->er_said.proto==IPPROTO_INT
-+ && ixs->eroute->er_said.spi==htonl(SPI_HOLD)) {
-+ KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
-+ "klips_debug:ipsec_xmit_SAlookup: "
-+ "shunt SA of HOLD: skb stored in HOLD.\n");
-+ if(ixs->eroute->er_last != NULL) {
-+ kfree_skb(ixs->eroute->er_last);
-+ }
-+ ixs->eroute->er_last = ixs->skb;
-+ ixs->skb = NULL;
-+ ixs->stats->tx_dropped++;
-+ spin_unlock(&eroute_lock);
-+ return IPSEC_XMIT_STOLEN;
-+ }
-+ ixs->outgoing_said = ixs->eroute->er_said;
-+ ixs->eroute_pid = ixs->eroute->er_pid;
-+ /* Copy of the ident for the TRAP/TRAPSUBNET eroutes */
-+ if(ixs->outgoing_said.proto==IPPROTO_INT
-+ && (ixs->outgoing_said.spi==htonl(SPI_TRAP)
-+ || (ixs->outgoing_said.spi==htonl(SPI_TRAPSUBNET)))) {
-+ int len;
-+
-+ ixs->ips.ips_ident_s.type = ixs->eroute->er_ident_s.type;
-+ ixs->ips.ips_ident_s.id = ixs->eroute->er_ident_s.id;
-+ ixs->ips.ips_ident_s.len = ixs->eroute->er_ident_s.len;
-+ if (ixs->ips.ips_ident_s.len) {
-+ len = ixs->ips.ips_ident_s.len * IPSEC_PFKEYv2_ALIGN - sizeof(struct sadb_ident);
-+ KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
-+ "klips_debug:ipsec_xmit_SAlookup: "
-+ "allocating %d bytes for ident_s shunt SA of HOLD: skb stored in HOLD.\n",
-+ len);
-+ if ((ixs->ips.ips_ident_s.data = kmalloc(len, GFP_ATOMIC)) == NULL) {
-+ printk(KERN_WARNING "klips_debug:ipsec_xmit_SAlookup: "
-+ "Failed, tried to allocate %d bytes for source ident.\n",
-+ len);
-+ ixs->stats->tx_dropped++;
-+ spin_unlock(&eroute_lock);
-+ return IPSEC_XMIT_ERRMEMALLOC;
-+ }
-+ memcpy(ixs->ips.ips_ident_s.data, ixs->eroute->er_ident_s.data, len);
-+ }
-+ ixs->ips.ips_ident_d.type = ixs->eroute->er_ident_d.type;
-+ ixs->ips.ips_ident_d.id = ixs->eroute->er_ident_d.id;
-+ ixs->ips.ips_ident_d.len = ixs->eroute->er_ident_d.len;
-+ if (ixs->ips.ips_ident_d.len) {
-+ len = ixs->ips.ips_ident_d.len * IPSEC_PFKEYv2_ALIGN - sizeof(struct sadb_ident);
-+ KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
-+ "klips_debug:ipsec_xmit_SAlookup: "
-+ "allocating %d bytes for ident_d shunt SA of HOLD: skb stored in HOLD.\n",
-+ len);
-+ if ((ixs->ips.ips_ident_d.data = kmalloc(len, GFP_ATOMIC)) == NULL) {
-+ printk(KERN_WARNING "klips_debug:ipsec_xmit_SAlookup: "
-+ "Failed, tried to allocate %d bytes for dest ident.\n",
-+ len);
-+ ixs->stats->tx_dropped++;
-+ spin_unlock(&eroute_lock);
-+ return IPSEC_XMIT_ERRMEMALLOC;
-+ }
-+ memcpy(ixs->ips.ips_ident_d.data, ixs->eroute->er_ident_d.data, len);
-+ }
-+ }
-+ }
-+
-+ spin_unlock(&eroute_lock);
-+ return IPSEC_XMIT_OK;
-+}
-+
-+enum ipsec_xmit_value
-+ipsec_tunnel_restore_hard_header(struct ipsec_xmit_state*ixs)
-+{
-+ KLIPS_PRINT(debug_tunnel & DB_TN_CROUT,
-+ "klips_debug:ipsec_xmit_restore_hard_header: "
-+ "After recursive xforms -- head,tailroom: %d,%d\n",
-+ skb_headroom(ixs->skb),
-+ skb_tailroom(ixs->skb));
-+
-+ if(ixs->saved_header) {
-+ if(skb_headroom(ixs->skb) < ixs->hard_header_len) {
-+ printk(KERN_WARNING
-+ "klips_error:ipsec_xmit_restore_hard_header: "
-+ "tried to skb_push hhlen=%d, %d available. This should never happen, please report.\n",
-+ ixs->hard_header_len,
-+ skb_headroom(ixs->skb));
-+ ixs->stats->tx_errors++;
-+ return IPSEC_XMIT_PUSHPULLERR;
-+
-+ }
-+ skb_push(ixs->skb, ixs->hard_header_len);
-+ {
-+ int i;
-+ for (i = 0; i < ixs->hard_header_len; i++) {
-+ ixs->skb->data[i] = ixs->saved_header[i];
-+ }
-+ }
-+ }
-+#ifdef CONFIG_IPSEC_NAT_TRAVERSAL
-+ if (ixs->natt_type && ixs->natt_head) {
-+ struct iphdr *ipp = ixs->skb->nh.iph;
-+ struct udphdr *udp;
-+ KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
-+ "klips_debug:ipsec_tunnel_start_xmit: "
-+ "encapsuling packet into UDP (NAT-Traversal) (%d %d)\n",
-+ ixs->natt_type, ixs->natt_head);
-+
-+ ixs->iphlen = ipp->ihl << 2;
-+ ipp->tot_len =
-+ htons(ntohs(ipp->tot_len) + ixs->natt_head);
-+ if(skb_tailroom(ixs->skb) < ixs->natt_head) {
-+ printk(KERN_WARNING "klips_error:ipsec_tunnel_start_xmit: "
-+ "tried to skb_put %d, %d available. "
-+ "This should never happen, please report.\n",
-+ ixs->natt_head,
-+ skb_tailroom(ixs->skb));
-+ ixs->stats->tx_errors++;
-+ return IPSEC_XMIT_ESPUDP;
-+ }
-+ skb_put(ixs->skb, ixs->natt_head);
-+
-+ udp = (struct udphdr *)((char *)ipp + ixs->iphlen);
-+
-+ /* move ESP hdr after UDP hdr */
-+ memmove((void *)((char *)udp + ixs->natt_head),
-+ (void *)(udp),
-+ ntohs(ipp->tot_len) - ixs->iphlen - ixs->natt_head);
-+
-+ /* clear UDP & Non-IKE Markers (if any) */
-+ memset(udp, 0, ixs->natt_head);
-+
-+ /* fill UDP with usefull informations ;-) */
-+ udp->source = htons(ixs->natt_sport);
-+ udp->dest = htons(ixs->natt_dport);
-+ udp->len = htons(ntohs(ipp->tot_len) - ixs->iphlen);
-+
-+ /* set protocol */
-+ ipp->protocol = IPPROTO_UDP;
-+
-+ /* fix IP checksum */
-+ ipp->check = 0;
-+ ipp->check = ip_fast_csum((unsigned char *)ipp, ipp->ihl);
-+ }
-+#endif
-+ KLIPS_PRINT(debug_tunnel & DB_TN_CROUT,
-+ "klips_debug:ipsec_xmit_restore_hard_header: "
-+ "With hard_header, final head,tailroom: %d,%d\n",
-+ skb_headroom(ixs->skb),
-+ skb_tailroom(ixs->skb));
-+
-+ return IPSEC_XMIT_OK;
-+}
-+
-+enum ipsec_xmit_value
-+ipsec_tunnel_send(struct ipsec_xmit_state*ixs)
-+{
-+#ifdef NETDEV_25
-+ struct flowi fl;
-+#endif
-+
-+#ifdef NET_21 /* 2.2 and 2.4 kernels */
-+ /* new route/dst cache code from James Morris */
-+ ixs->skb->dev = ixs->physdev;
-+#ifdef NETDEV_25
-+ fl.oif = ixs->physdev->iflink;
-+ fl.nl_u.ip4_u.daddr = ixs->skb->nh.iph->daddr;
-+ fl.nl_u.ip4_u.saddr = ixs->pass ? 0 : ixs->skb->nh.iph->saddr;
-+ fl.nl_u.ip4_u.tos = RT_TOS(ixs->skb->nh.iph->tos);
-+ fl.proto = ixs->skb->nh.iph->protocol;
-+ if ((ixs->error = ip_route_output_key(&ixs->route, &fl))) {
-+#else
-+ /*skb_orphan(ixs->skb);*/
-+ if((ixs->error = ip_route_output(&ixs->route,
-+ ixs->skb->nh.iph->daddr,
-+ ixs->pass ? 0 : ixs->skb->nh.iph->saddr,
-+ RT_TOS(ixs->skb->nh.iph->tos),
-+ /* mcr->rgb: should this be 0 instead? */
-+ ixs->physdev->iflink))) {
-+#endif
-+ ixs->stats->tx_errors++;
-+ KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
-+ "klips_debug:ipsec_xmit_send: "
-+ "ip_route_output failed with error code %d, rt->u.dst.dev=%s, dropped\n",
-+ ixs->error,
-+ ixs->route->u.dst.dev->name);
-+ return IPSEC_XMIT_ROUTEERR;
-+ }
-+ if(ixs->dev == ixs->route->u.dst.dev) {
-+ ip_rt_put(ixs->route);
-+ /* This is recursion, drop it. */
-+ ixs->stats->tx_errors++;
-+ KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
-+ "klips_debug:ipsec_xmit_send: "
-+ "suspect recursion, dev=rt->u.dst.dev=%s, dropped\n",
-+ ixs->dev->name);
-+ return IPSEC_XMIT_RECURSDETECT;
-+ }
-+ dst_release(ixs->skb->dst);
-+ ixs->skb->dst = &ixs->route->u.dst;
-+ ixs->stats->tx_bytes += ixs->skb->len;
-+ if(ixs->skb->len < ixs->skb->nh.raw - ixs->skb->data) {
-+ ixs->stats->tx_errors++;
-+ printk(KERN_WARNING
-+ "klips_error:ipsec_xmit_send: "
-+ "tried to __skb_pull nh-data=%ld, %d available. This should never happen, please report.\n",
-+ (unsigned long)(ixs->skb->nh.raw - ixs->skb->data),
-+ ixs->skb->len);
-+ return IPSEC_XMIT_PUSHPULLERR;
-+ }
-+ __skb_pull(ixs->skb, ixs->skb->nh.raw - ixs->skb->data);
-+#ifdef SKB_RESET_NFCT
-+ if(!ixs->pass) {
-+ nf_conntrack_put(ixs->skb->nfct);
-+ ixs->skb->nfct = NULL;
-+ }
-+#ifdef CONFIG_NETFILTER_DEBUG
-+ ixs->skb->nf_debug = 0;
-+#endif /* CONFIG_NETFILTER_DEBUG */
-+#endif /* SKB_RESET_NFCT */
-+ KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
-+ "klips_debug:ipsec_xmit_send: "
-+ "...done, calling ip_send() on device:%s\n",
-+ ixs->skb->dev ? ixs->skb->dev->name : "NULL");
-+ KLIPS_IP_PRINT(debug_tunnel & DB_TN_XMIT, ixs->skb->nh.iph);
-+#ifdef NETDEV_23 /* 2.4 kernels */
-+ {
-+ int err;
-+
-+ err = NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, ixs->skb, NULL, ixs->route->u.dst.dev,
-+ ipsec_tunnel_xmit2);
-+ if(err != NET_XMIT_SUCCESS && err != NET_XMIT_CN) {
-+ if(net_ratelimit())
-+ printk(KERN_ERR
-+ "klips_error:ipsec_xmit_send: "
-+ "ip_send() failed, err=%d\n",
-+ -err);
-+ ixs->stats->tx_errors++;
-+ ixs->stats->tx_aborted_errors++;
-+ ixs->skb = NULL;
-+ return IPSEC_XMIT_IPSENDFAILURE;
-+ }
-+ }
-+#else /* NETDEV_23 */ /* 2.2 kernels */
-+ ip_send(ixs->skb);
-+#endif /* NETDEV_23 */
-+#else /* NET_21 */ /* 2.0 kernels */
-+ ixs->skb->arp = 1;
-+ /* ISDN/ASYNC PPP from Matjaz Godec. */
-+ /* skb->protocol = htons(ETH_P_IP); */
-+ KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
-+ "klips_debug:ipsec_xmit_send: "
-+ "...done, calling dev_queue_xmit() or ip_fragment().\n");
-+ IP_SEND(ixs->skb, ixs->physdev);
-+#endif /* NET_21 */
-+ ixs->stats->tx_packets++;
-+
-+ ixs->skb = NULL;
-+
-+ return IPSEC_XMIT_OK;
-+}
-+
-+void
-+ipsec_tunnel_cleanup(struct ipsec_xmit_state*ixs)
-+{
-+#if defined(HAS_NETIF_QUEUE) || defined (HAVE_NETIF_QUEUE)
-+ netif_wake_queue(ixs->dev);
-+#else /* defined(HAS_NETIF_QUEUE) || defined (HAVE_NETIF_QUEUE) */
-+ ixs->dev->tbusy = 0;
-+#endif /* defined(HAS_NETIF_QUEUE) || defined (HAVE_NETIF_QUEUE) */
-+ if(ixs->saved_header) {
-+ kfree(ixs->saved_header);
-+ }
-+ if(ixs->skb) {
-+ dev_kfree_skb(ixs->skb, FREE_WRITE);
-+ }
-+ if(ixs->oskb) {
-+ dev_kfree_skb(ixs->oskb, FREE_WRITE);
-+ }
-+ if (ixs->ips.ips_ident_s.data) {
-+ kfree(ixs->ips.ips_ident_s.data);
-+ }
-+ if (ixs->ips.ips_ident_d.data) {
-+ kfree(ixs->ips.ips_ident_d.data);
-+ }
-+}
-+
-+/*
-+ * This function assumes it is being called from dev_queue_xmit()
-+ * and that skb is filled properly by that function.
-+ */
-+int
-+ipsec_tunnel_start_xmit(struct sk_buff *skb, struct device *dev)
-+{
-+ struct ipsec_xmit_state ixs_mem;
-+ struct ipsec_xmit_state *ixs = &ixs_mem;
-+ enum ipsec_xmit_value stat;
-+
-+#ifdef CONFIG_IPSEC_NAT_TRAVERSAL
-+ ixs->natt_type = 0, ixs->natt_head = 0;
-+ ixs->natt_sport = 0, ixs->natt_dport = 0;
-+#endif
-+
-+ memset((caddr_t)ixs, 0, sizeof(*ixs));
-+ ixs->oskb = NULL;
-+ ixs->saved_header = NULL; /* saved copy of the hard header */
-+ ixs->route = NULL;
-+ memset((caddr_t)&(ixs->ips), 0, sizeof(ixs->ips));
-+ ixs->dev = dev;
-+ ixs->skb = skb;
-+
-+ stat = ipsec_xmit_sanity_check_dev(ixs);
-+ if(stat != IPSEC_XMIT_OK) {
-+ goto cleanup;
-+ }
-+
-+ stat = ipsec_xmit_sanity_check_skb(ixs);
-+ if(stat != IPSEC_XMIT_OK) {
-+ goto cleanup;
-+ }
-+
-+ stat = ipsec_tunnel_strip_hard_header(ixs);
-+ if(stat != IPSEC_XMIT_OK) {
-+ goto cleanup;
-+ }
-+
-+ stat = ipsec_tunnel_SAlookup(ixs);
-+ if(stat != IPSEC_XMIT_OK) {
-+ KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
-+ "klips_debug:ipsec_tunnel_start_xmit: SAlookup failed: %d\n",
-+ stat);
-+ goto cleanup;
-+ }
-+
-+ ixs->innersrc = ixs->iph->saddr;
-+ /* start encapsulation loop here XXX */
-+ do {
-+ stat = ipsec_xmit_encap_bundle(ixs);
-+ if(stat != IPSEC_XMIT_OK) {
-+ if(stat == IPSEC_XMIT_PASS) {
-+ goto bypass;
-+ }
-+
-+ KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
-+ "klips_debug:ipsec_tunnel_start_xmit: encap_bundle failed: %d\n",
-+ stat);
-+ goto cleanup;
-+ }
-+
-+ ixs->matcher.sen_ip_src.s_addr = ixs->iph->saddr;
-+ ixs->matcher.sen_ip_dst.s_addr = ixs->iph->daddr;
-+ ixs->matcher.sen_proto = ixs->iph->protocol;
-+ ipsec_extract_ports(ixs->iph, &ixs->matcher);
-+
-+ spin_lock(&eroute_lock);
-+ ixs->eroute = ipsec_findroute(&ixs->matcher);
-+ if(ixs->eroute) {
-+ ixs->outgoing_said = ixs->eroute->er_said;
-+ ixs->eroute_pid = ixs->eroute->er_pid;
-+ ixs->eroute->er_count++;
-+ ixs->eroute->er_lasttime = jiffies/HZ;
-+ }
-+ spin_unlock(&eroute_lock);
-+
-+ KLIPS_PRINT((debug_tunnel & DB_TN_XMIT) &&
-+ /* ((ixs->orgdst != ixs->newdst) || (ixs->orgsrc != ixs->newsrc)) */
-+ (ixs->orgedst != ixs->outgoing_said.dst.u.v4.sin_addr.s_addr) &&
-+ ixs->outgoing_said.dst.u.v4.sin_addr.s_addr &&
-+ ixs->eroute,
-+ "klips_debug:ipsec_tunnel_start_xmit: "
-+ "We are recursing here.\n");
-+
-+ } while(/*((ixs->orgdst != ixs->newdst) || (ixs->orgsrc != ixs->newsrc))*/
-+ (ixs->orgedst != ixs->outgoing_said.dst.u.v4.sin_addr.s_addr) &&
-+ ixs->outgoing_said.dst.u.v4.sin_addr.s_addr &&
-+ ixs->eroute);
-+
-+ stat = ipsec_tunnel_restore_hard_header(ixs);
-+ if(stat != IPSEC_XMIT_OK) {
-+ goto cleanup;
-+ }
-+
-+ bypass:
-+ stat = ipsec_tunnel_send(ixs);
-+
-+ cleanup:
-+ ipsec_tunnel_cleanup(ixs);
-+
-+ return 0;
-+}
-+
-+DEBUG_NO_STATIC struct net_device_stats *
-+ipsec_tunnel_get_stats(struct device *dev)
-+{
-+ return &(((struct ipsecpriv *)(dev->priv))->mystats);
-+}
-+
-+/*
-+ * Revectored calls.
-+ * For each of these calls, a field exists in our private structure.
-+ */
-+
-+DEBUG_NO_STATIC int
-+ipsec_tunnel_hard_header(struct sk_buff *skb, struct device *dev,
-+ unsigned short type, void *daddr, void *saddr, unsigned len)
-+{
-+ struct ipsecpriv *prv = dev->priv;
-+ struct device *tmp;
-+ int ret;
-+ struct net_device_stats *stats; /* This device's statistics */
-+
-+ if(skb == NULL) {
-+ KLIPS_PRINT(debug_tunnel & DB_TN_REVEC,
-+ "klips_debug:ipsec_tunnel_hard_header: "
-+ "no skb...\n");
-+ return -ENODATA;
-+ }
-+
-+ if(dev == NULL) {
-+ KLIPS_PRINT(debug_tunnel & DB_TN_REVEC,
-+ "klips_debug:ipsec_tunnel_hard_header: "
-+ "no device...\n");
-+ return -ENODEV;
-+ }
-+
-+ KLIPS_PRINT(debug_tunnel & DB_TN_REVEC,
-+ "klips_debug:ipsec_tunnel_hard_header: "
-+ "skb->dev=%s dev=%s.\n",
-+ skb->dev ? skb->dev->name : "NULL",
-+ dev->name);
-+
-+ if(prv == NULL) {
-+ KLIPS_PRINT(debug_tunnel & DB_TN_REVEC,
-+ "klips_debug:ipsec_tunnel_hard_header: "
-+ "no private space associated with dev=%s\n",
-+ dev->name ? dev->name : "NULL");
-+ return -ENODEV;
-+ }
-+
-+ stats = (struct net_device_stats *) &(prv->mystats);
-+
-+ if(prv->dev == NULL) {
-+ KLIPS_PRINT(debug_tunnel & DB_TN_REVEC,
-+ "klips_debug:ipsec_tunnel_hard_header: "
-+ "no physical device associated with dev=%s\n",
-+ dev->name ? dev->name : "NULL");
-+ stats->tx_dropped++;
-+ return -ENODEV;
-+ }
-+
-+ /* check if we have to send a IPv6 packet. It might be a Router
-+ Solicitation, where the building of the packet happens in
-+ reverse order:
-+ 1. ll hdr,
-+ 2. IPv6 hdr,
-+ 3. ICMPv6 hdr
-+ -> skb->nh.raw is still uninitialized when this function is
-+ called!! If this is no IPv6 packet, we can print debugging
-+ messages, otherwise we skip all debugging messages and just
-+ build the ll header */
-+ if(type != ETH_P_IPV6) {
-+ /* execute this only, if we don't have to build the
-+ header for a IPv6 packet */
-+ if(!prv->hard_header) {
-+ KLIPS_PRINT(debug_tunnel & DB_TN_REVEC,
-+ "klips_debug:ipsec_tunnel_hard_header: "
-+ "physical device has been detached, packet dropped 0p%p->0p%p len=%d type=%d dev=%s->NULL ",
-+ saddr,
-+ daddr,
-+ len,
-+ type,
-+ dev->name);
-+#ifdef NET_21
-+ KLIPS_PRINTMORE(debug_tunnel & DB_TN_REVEC,
-+ "ip=%08x->%08x\n",
-+ (__u32)ntohl(skb->nh.iph->saddr),
-+ (__u32)ntohl(skb->nh.iph->daddr) );
-+#else /* NET_21 */
-+ KLIPS_PRINTMORE(debug_tunnel & DB_TN_REVEC,
-+ "ip=%08x->%08x\n",
-+ (__u32)ntohl(skb->ip_hdr->saddr),
-+ (__u32)ntohl(skb->ip_hdr->daddr) );
-+#endif /* NET_21 */
-+ stats->tx_dropped++;
-+ return -ENODEV;
-+ }
-+
-+#define da ((struct device *)(prv->dev))->dev_addr
-+ KLIPS_PRINT(debug_tunnel & DB_TN_REVEC,
-+ "klips_debug:ipsec_tunnel_hard_header: "
-+ "Revectored 0p%p->0p%p len=%d type=%d dev=%s->%s dev_addr=%02x:%02x:%02x:%02x:%02x:%02x ",
-+ saddr,
-+ daddr,
-+ len,
-+ type,
-+ dev->name,
-+ prv->dev->name,
-+ da[0], da[1], da[2], da[3], da[4], da[5]);
-+#ifdef NET_21
-+ KLIPS_PRINTMORE(debug_tunnel & DB_TN_REVEC,
-+ "ip=%08x->%08x\n",
-+ (__u32)ntohl(skb->nh.iph->saddr),
-+ (__u32)ntohl(skb->nh.iph->daddr) );
-+#else /* NET_21 */
-+ KLIPS_PRINTMORE(debug_tunnel & DB_TN_REVEC,
-+ "ip=%08x->%08x\n",
-+ (__u32)ntohl(skb->ip_hdr->saddr),
-+ (__u32)ntohl(skb->ip_hdr->daddr) );
-+#endif /* NET_21 */
-+ } else {
-+ KLIPS_PRINT(debug_tunnel,
-+ "klips_debug:ipsec_tunnel_hard_header: "
-+ "is IPv6 packet, skip debugging messages, only revector and build linklocal header.\n");
-+ }
-+ tmp = skb->dev;
-+ skb->dev = prv->dev;
-+ ret = prv->hard_header(skb, prv->dev, type, (void *)daddr, (void *)saddr, len);
-+ skb->dev = tmp;
-+ return ret;
-+}
-+
-+DEBUG_NO_STATIC int
-+#ifdef NET_21
-+ipsec_tunnel_rebuild_header(struct sk_buff *skb)
-+#else /* NET_21 */
-+ipsec_tunnel_rebuild_header(void *buff, struct device *dev,
-+ unsigned long raddr, struct sk_buff *skb)
-+#endif /* NET_21 */
-+{
-+ struct ipsecpriv *prv = skb->dev->priv;
-+ struct device *tmp;
-+ int ret;
-+ struct net_device_stats *stats; /* This device's statistics */
-+
-+ if(skb->dev == NULL) {
-+ KLIPS_PRINT(debug_tunnel & DB_TN_REVEC,
-+ "klips_debug:ipsec_tunnel_rebuild_header: "
-+ "no device...");
-+ return -ENODEV;
-+ }
-+
-+ if(prv == NULL) {
-+ KLIPS_PRINT(debug_tunnel & DB_TN_REVEC,
-+ "klips_debug:ipsec_tunnel_rebuild_header: "
-+ "no private space associated with dev=%s",
-+ skb->dev->name ? skb->dev->name : "NULL");
-+ return -ENODEV;
-+ }
-+
-+ stats = (struct net_device_stats *) &(prv->mystats);
-+
-+ if(prv->dev == NULL) {
-+ KLIPS_PRINT(debug_tunnel & DB_TN_REVEC,
-+ "klips_debug:ipsec_tunnel_rebuild_header: "
-+ "no physical device associated with dev=%s",
-+ skb->dev->name ? skb->dev->name : "NULL");
-+ stats->tx_dropped++;
-+ return -ENODEV;
-+ }
-+
-+ if(!prv->rebuild_header) {
-+ KLIPS_PRINT(debug_tunnel & DB_TN_REVEC,
-+ "klips_debug:ipsec_tunnel_rebuild_header: "
-+ "physical device has been detached, packet dropped skb->dev=%s->NULL ",
-+ skb->dev->name);
-+#ifdef NET_21
-+ KLIPS_PRINT(debug_tunnel & DB_TN_REVEC,
-+ "ip=%08x->%08x\n",
-+ (__u32)ntohl(skb->nh.iph->saddr),
-+ (__u32)ntohl(skb->nh.iph->daddr) );
-+#else /* NET_21 */
-+ KLIPS_PRINT(debug_tunnel & DB_TN_REVEC,
-+ "ip=%08x->%08x\n",
-+ (__u32)ntohl(skb->ip_hdr->saddr),
-+ (__u32)ntohl(skb->ip_hdr->daddr) );
-+#endif /* NET_21 */
-+ stats->tx_dropped++;
-+ return -ENODEV;
-+ }
-+
-+ KLIPS_PRINT(debug_tunnel & DB_TN_REVEC,
-+ "klips_debug:ipsec_tunnel: "
-+ "Revectored rebuild_header dev=%s->%s ",
-+ skb->dev->name, prv->dev->name);
-+#ifdef NET_21
-+ KLIPS_PRINT(debug_tunnel & DB_TN_REVEC,
-+ "ip=%08x->%08x\n",
-+ (__u32)ntohl(skb->nh.iph->saddr),
-+ (__u32)ntohl(skb->nh.iph->daddr) );
-+#else /* NET_21 */
-+ KLIPS_PRINT(debug_tunnel & DB_TN_REVEC,
-+ "ip=%08x->%08x\n",
-+ (__u32)ntohl(skb->ip_hdr->saddr),
-+ (__u32)ntohl(skb->ip_hdr->daddr) );
-+#endif /* NET_21 */
-+ tmp = skb->dev;
-+ skb->dev = prv->dev;
-+
-+#ifdef NET_21
-+ ret = prv->rebuild_header(skb);
-+#else /* NET_21 */
-+ ret = prv->rebuild_header(buff, prv->dev, raddr, skb);
-+#endif /* NET_21 */
-+ skb->dev = tmp;
-+ return ret;
-+}
-+
-+DEBUG_NO_STATIC int
-+ipsec_tunnel_set_mac_address(struct device *dev, void *addr)
-+{
-+ struct ipsecpriv *prv = dev->priv;
-+
-+ struct net_device_stats *stats; /* This device's statistics */
-+
-+ if(dev == NULL) {
-+ KLIPS_PRINT(debug_tunnel & DB_TN_REVEC,
-+ "klips_debug:ipsec_tunnel_set_mac_address: "
-+ "no device...");
-+ return -ENODEV;
-+ }
-+
-+ if(prv == NULL) {
-+ KLIPS_PRINT(debug_tunnel & DB_TN_REVEC,
-+ "klips_debug:ipsec_tunnel_set_mac_address: "
-+ "no private space associated with dev=%s",
-+ dev->name ? dev->name : "NULL");
-+ return -ENODEV;
-+ }
-+
-+ stats = (struct net_device_stats *) &(prv->mystats);
-+
-+ if(prv->dev == NULL) {
-+ KLIPS_PRINT(debug_tunnel & DB_TN_REVEC,
-+ "klips_debug:ipsec_tunnel_set_mac_address: "
-+ "no physical device associated with dev=%s",
-+ dev->name ? dev->name : "NULL");
-+ stats->tx_dropped++;
-+ return -ENODEV;
-+ }
-+
-+ if(!prv->set_mac_address) {
-+ KLIPS_PRINT(debug_tunnel & DB_TN_REVEC,
-+ "klips_debug:ipsec_tunnel_set_mac_address: "
-+ "physical device has been detached, cannot set - skb->dev=%s->NULL\n",
-+ dev->name);
-+ return -ENODEV;
-+ }
-+
-+ KLIPS_PRINT(debug_tunnel & DB_TN_REVEC,
-+ "klips_debug:ipsec_tunnel_set_mac_address: "
-+ "Revectored dev=%s->%s addr=0p%p\n",
-+ dev->name, prv->dev->name, addr);
-+ return prv->set_mac_address(prv->dev, addr);
-+
-+}
-+
-+#ifndef NET_21
-+DEBUG_NO_STATIC void
-+ipsec_tunnel_cache_bind(struct hh_cache **hhp, struct device *dev,
-+ unsigned short htype, __u32 daddr)
-+{
-+ struct ipsecpriv *prv = dev->priv;
-+
-+ struct net_device_stats *stats; /* This device's statistics */
-+
-+ if(dev == NULL) {
-+ KLIPS_PRINT(debug_tunnel & DB_TN_REVEC,
-+ "klips_debug:ipsec_tunnel_cache_bind: "
-+ "no device...");
-+ return;
-+ }
-+
-+ if(prv == NULL) {
-+ KLIPS_PRINT(debug_tunnel & DB_TN_REVEC,
-+ "klips_debug:ipsec_tunnel_cache_bind: "
-+ "no private space associated with dev=%s",
-+ dev->name ? dev->name : "NULL");
-+ return;
-+ }
-+
-+ stats = (struct net_device_stats *) &(prv->mystats);
-+
-+ if(prv->dev == NULL) {
-+ KLIPS_PRINT(debug_tunnel & DB_TN_REVEC,
-+ "klips_debug:ipsec_tunnel_cache_bind: "
-+ "no physical device associated with dev=%s",
-+ dev->name ? dev->name : "NULL");
-+ stats->tx_dropped++;
-+ return;
-+ }
-+
-+ if(!prv->header_cache_bind) {
-+ KLIPS_PRINT(debug_tunnel & DB_TN_REVEC,
-+ "klips_debug:ipsec_tunnel_cache_bind: "
-+ "physical device has been detached, cannot set - skb->dev=%s->NULL\n",
-+ dev->name);
-+ stats->tx_dropped++;
-+ return;
-+ }
-+
-+ KLIPS_PRINT(debug_tunnel & DB_TN_REVEC,
-+ "klips_debug:ipsec_tunnel_cache_bind: "
-+ "Revectored \n");
-+ prv->header_cache_bind(hhp, prv->dev, htype, daddr);
-+ return;
-+}
-+#endif /* !NET_21 */
-+
-+
-+DEBUG_NO_STATIC void
-+ipsec_tunnel_cache_update(struct hh_cache *hh, struct device *dev, unsigned char * haddr)
-+{
-+ struct ipsecpriv *prv = dev->priv;
-+
-+ struct net_device_stats *stats; /* This device's statistics */
-+
-+ if(dev == NULL) {
-+ KLIPS_PRINT(debug_tunnel & DB_TN_REVEC,
-+ "klips_debug:ipsec_tunnel_cache_update: "
-+ "no device...");
-+ return;
-+ }
-+
-+ if(prv == NULL) {
-+ KLIPS_PRINT(debug_tunnel & DB_TN_REVEC,
-+ "klips_debug:ipsec_tunnel_cache_update: "
-+ "no private space associated with dev=%s",
-+ dev->name ? dev->name : "NULL");
-+ return;
-+ }
-+
-+ stats = (struct net_device_stats *) &(prv->mystats);
-+
-+ if(prv->dev == NULL) {
-+ KLIPS_PRINT(debug_tunnel & DB_TN_REVEC,
-+ "klips_debug:ipsec_tunnel_cache_update: "
-+ "no physical device associated with dev=%s",
-+ dev->name ? dev->name : "NULL");
-+ stats->tx_dropped++;
-+ return;
-+ }
-+
-+ if(!prv->header_cache_update) {
-+ KLIPS_PRINT(debug_tunnel & DB_TN_REVEC,
-+ "klips_debug:ipsec_tunnel_cache_update: "
-+ "physical device has been detached, cannot set - skb->dev=%s->NULL\n",
-+ dev->name);
-+ return;
-+ }
-+
-+ KLIPS_PRINT(debug_tunnel & DB_TN_REVEC,
-+ "klips_debug:ipsec_tunnel: "
-+ "Revectored cache_update\n");
-+ prv->header_cache_update(hh, prv->dev, haddr);
-+ return;
-+}
-+
-+#ifdef NET_21
-+DEBUG_NO_STATIC int
-+ipsec_tunnel_neigh_setup(struct neighbour *n)
-+{
-+ KLIPS_PRINT(debug_tunnel & DB_TN_REVEC,
-+ "klips_debug:ipsec_tunnel_neigh_setup:\n");
-+
-+ if (n->nud_state == NUD_NONE) {
-+ n->ops = &arp_broken_ops;
-+ n->output = n->ops->output;
-+ }
-+ return 0;
-+}
-+
-+DEBUG_NO_STATIC int
-+ipsec_tunnel_neigh_setup_dev(struct device *dev, struct neigh_parms *p)
-+{
-+ KLIPS_PRINT(debug_tunnel & DB_TN_REVEC,
-+ "klips_debug:ipsec_tunnel_neigh_setup_dev: "
-+ "setting up %s\n",
-+ dev ? dev->name : "NULL");
-+
-+ if (p->tbl->family == AF_INET) {
-+ p->neigh_setup = ipsec_tunnel_neigh_setup;
-+ p->ucast_probes = 0;
-+ p->mcast_probes = 0;
-+ }
-+ return 0;
-+}
-+#endif /* NET_21 */
-+
-+/*
-+ * We call the attach routine to attach another device.
-+ */
-+
-+DEBUG_NO_STATIC int
-+ipsec_tunnel_attach(struct device *dev, struct device *physdev)
-+{
-+ int i;
-+ struct ipsecpriv *prv = dev->priv;
-+
-+ if(dev == NULL) {
-+ KLIPS_PRINT(debug_tunnel & DB_TN_REVEC,
-+ "klips_debug:ipsec_tunnel_attach: "
-+ "no device...");
-+ return -ENODEV;
-+ }
-+
-+ if(prv == NULL) {
-+ KLIPS_PRINT(debug_tunnel & DB_TN_REVEC,
-+ "klips_debug:ipsec_tunnel_attach: "
-+ "no private space associated with dev=%s",
-+ dev->name ? dev->name : "NULL");
-+ return -ENODATA;
-+ }
-+
-+ prv->dev = physdev;
-+ prv->hard_start_xmit = physdev->hard_start_xmit;
-+ prv->get_stats = physdev->get_stats;
-+
-+ if (physdev->hard_header) {
-+ prv->hard_header = physdev->hard_header;
-+ dev->hard_header = ipsec_tunnel_hard_header;
-+ } else
-+ dev->hard_header = NULL;
-+
-+ if (physdev->rebuild_header) {
-+ prv->rebuild_header = physdev->rebuild_header;
-+ dev->rebuild_header = ipsec_tunnel_rebuild_header;
-+ } else
-+ dev->rebuild_header = NULL;
-+
-+ if (physdev->set_mac_address) {
-+ prv->set_mac_address = physdev->set_mac_address;
-+ dev->set_mac_address = ipsec_tunnel_set_mac_address;
-+ } else
-+ dev->set_mac_address = NULL;
-+
-+#ifndef NET_21
-+ if (physdev->header_cache_bind) {
-+ prv->header_cache_bind = physdev->header_cache_bind;
-+ dev->header_cache_bind = ipsec_tunnel_cache_bind;
-+ } else
-+ dev->header_cache_bind = NULL;
-+#endif /* !NET_21 */
-+
-+ if (physdev->header_cache_update) {
-+ prv->header_cache_update = physdev->header_cache_update;
-+ dev->header_cache_update = ipsec_tunnel_cache_update;
-+ } else
-+ dev->header_cache_update = NULL;
-+
-+ dev->hard_header_len = physdev->hard_header_len;
-+
-+#ifdef NET_21
-+/* prv->neigh_setup = physdev->neigh_setup; */
-+ dev->neigh_setup = ipsec_tunnel_neigh_setup_dev;
-+#endif /* NET_21 */
-+ dev->mtu = 16260; /* 0xfff0; */ /* dev->mtu; */
-+ prv->mtu = physdev->mtu;
-+
-+#ifdef PHYSDEV_TYPE
-+ dev->type = physdev->type; /* ARPHRD_TUNNEL; */
-+#endif /* PHYSDEV_TYPE */
-+
-+ dev->addr_len = physdev->addr_len;
-+ for (i=0; i<dev->addr_len; i++) {
-+ dev->dev_addr[i] = physdev->dev_addr[i];
-+ }
-+#ifdef CONFIG_IPSEC_DEBUG
-+ if(debug_tunnel & DB_TN_INIT) {
-+ printk(KERN_INFO "klips_debug:ipsec_tunnel_attach: "
-+ "physical device %s being attached has HW address: %2x",
-+ physdev->name, physdev->dev_addr[0]);
-+ for (i=1; i < physdev->addr_len; i++) {
-+ printk(":%02x", physdev->dev_addr[i]);
-+ }
-+ printk("\n");
-+ }
-+#endif /* CONFIG_IPSEC_DEBUG */
-+
-+ return 0;
-+}
-+
-+/*
-+ * We call the detach routine to detach the ipsec tunnel from another device.
-+ */
-+
-+DEBUG_NO_STATIC int
-+ipsec_tunnel_detach(struct device *dev)
-+{
-+ int i;
-+ struct ipsecpriv *prv = dev->priv;
-+
-+ if(dev == NULL) {
-+ KLIPS_PRINT(debug_tunnel & DB_TN_REVEC,
-+ "klips_debug:ipsec_tunnel_detach: "
-+ "no device...");
-+ return -ENODEV;
-+ }
-+
-+ if(prv == NULL) {
-+ KLIPS_PRINT(debug_tunnel & DB_TN_REVEC,
-+ "klips_debug:ipsec_tunnel_detach: "
-+ "no private space associated with dev=%s",
-+ dev->name ? dev->name : "NULL");
-+ return -ENODATA;
-+ }
-+
-+ KLIPS_PRINT(debug_tunnel & DB_TN_INIT,
-+ "klips_debug:ipsec_tunnel_detach: "
-+ "physical device %s being detached from virtual device %s\n",
-+ prv->dev ? prv->dev->name : "NULL",
-+ dev->name);
-+
-+ ipsec_dev_put(prv->dev);
-+ prv->dev = NULL;
-+ prv->hard_start_xmit = NULL;
-+ prv->get_stats = NULL;
-+
-+ prv->hard_header = NULL;
-+#ifdef DETACH_AND_DOWN
-+ dev->hard_header = NULL;
-+#endif /* DETACH_AND_DOWN */
-+
-+ prv->rebuild_header = NULL;
-+#ifdef DETACH_AND_DOWN
-+ dev->rebuild_header = NULL;
-+#endif /* DETACH_AND_DOWN */
-+
-+ prv->set_mac_address = NULL;
-+#ifdef DETACH_AND_DOWN
-+ dev->set_mac_address = NULL;
-+#endif /* DETACH_AND_DOWN */
-+
-+#ifndef NET_21
-+ prv->header_cache_bind = NULL;
-+#ifdef DETACH_AND_DOWN
-+ dev->header_cache_bind = NULL;
-+#endif /* DETACH_AND_DOWN */
-+#endif /* !NET_21 */
-+
-+ prv->header_cache_update = NULL;
-+#ifdef DETACH_AND_DOWN
-+ dev->header_cache_update = NULL;
-+#endif /* DETACH_AND_DOWN */
-+
-+#ifdef NET_21
-+/* prv->neigh_setup = NULL; */
-+#ifdef DETACH_AND_DOWN
-+ dev->neigh_setup = NULL;
-+#endif /* DETACH_AND_DOWN */
-+#endif /* NET_21 */
-+ dev->hard_header_len = 0;
-+#ifdef DETACH_AND_DOWN
-+ dev->mtu = 0;
-+#endif /* DETACH_AND_DOWN */
-+ prv->mtu = 0;
-+ for (i=0; i<MAX_ADDR_LEN; i++) {
-+ dev->dev_addr[i] = 0;
-+ }
-+ dev->addr_len = 0;
-+#ifdef PHYSDEV_TYPE
-+ dev->type = ARPHRD_VOID; /* ARPHRD_TUNNEL; */
-+#endif /* PHYSDEV_TYPE */
-+
-+ return 0;
-+}
-+
-+/*
-+ * We call the clear routine to detach all ipsec tunnels from other devices.
-+ */
-+DEBUG_NO_STATIC int
-+ipsec_tunnel_clear(void)
-+{
-+ int i;
-+ struct device *ipsecdev = NULL, *prvdev;
-+ struct ipsecpriv *prv;
-+ char name[9];
-+ int ret;
-+
-+ KLIPS_PRINT(debug_tunnel & DB_TN_INIT,
-+ "klips_debug:ipsec_tunnel_clear: .\n");
-+
-+ for(i = 0; i < IPSEC_NUM_IF; i++) {
-+ ipsecdev = ipsecdevices[i];
-+ if(ipsecdev != NULL) {
-+ if((prv = (struct ipsecpriv *)(ipsecdev->priv))) {
-+ prvdev = (struct device *)(prv->dev);
-+ if(prvdev) {
-+ KLIPS_PRINT(debug_tunnel & DB_TN_INIT,
-+ "klips_debug:ipsec_tunnel_clear: "
-+ "physical device for device %s is %s\n",
-+ name, prvdev->name);
-+ if((ret = ipsec_tunnel_detach(ipsecdev))) {
-+ KLIPS_PRINT(debug_tunnel & DB_TN_INIT,
-+ "klips_debug:ipsec_tunnel_clear: "
-+ "error %d detatching device %s from device %s.\n",
-+ ret, name, prvdev->name);
-+ return ret;
-+ }
-+ }
-+ }
-+ }
-+ }
-+ return 0;
-+}
-+
-+DEBUG_NO_STATIC int
-+ipsec_tunnel_ioctl(struct device *dev, struct ifreq *ifr, int cmd)
-+{
-+ struct ipsectunnelconf *cf = (struct ipsectunnelconf *)&ifr->ifr_data;
-+ struct ipsecpriv *prv = dev->priv;
-+ struct device *them; /* physical device */
-+#ifdef CONFIG_IP_ALIAS
-+ char *colon;
-+ char realphysname[IFNAMSIZ];
-+#endif /* CONFIG_IP_ALIAS */
-+
-+ if(dev == NULL) {
-+ KLIPS_PRINT(debug_tunnel & DB_TN_INIT,
-+ "klips_debug:ipsec_tunnel_ioctl: "
-+ "device not supplied.\n");
-+ return -ENODEV;
-+ }
-+
-+ KLIPS_PRINT(debug_tunnel & DB_TN_INIT,
-+ "klips_debug:ipsec_tunnel_ioctl: "
-+ "tncfg service call #%d for dev=%s\n",
-+ cmd,
-+ dev->name ? dev->name : "NULL");
-+ switch (cmd) {
-+ /* attach a virtual ipsec? device to a physical device */
-+ case IPSEC_SET_DEV:
-+ KLIPS_PRINT(debug_tunnel & DB_TN_INIT,
-+ "klips_debug:ipsec_tunnel_ioctl: "
-+ "calling ipsec_tunnel_attatch...\n");
-+#ifdef CONFIG_IP_ALIAS
-+ /* If this is an IP alias interface, get its real physical name */
-+ strncpy(realphysname, cf->cf_name, IFNAMSIZ);
-+ realphysname[IFNAMSIZ-1] = 0;
-+ colon = strchr(realphysname, ':');
-+ if (colon) *colon = 0;
-+ them = ipsec_dev_get(realphysname);
-+#else /* CONFIG_IP_ALIAS */
-+ them = ipsec_dev_get(cf->cf_name);
-+#endif /* CONFIG_IP_ALIAS */
-+
-+ if (them == NULL) {
-+ KLIPS_PRINT(debug_tunnel & DB_TN_INIT,
-+ "klips_debug:ipsec_tunnel_ioctl: "
-+ "physical device %s requested is null\n",
-+ cf->cf_name);
-+ ipsec_dev_put(them);
-+ return -ENXIO;
-+ }
-+
-+#if 0
-+ if (them->flags & IFF_UP) {
-+ KLIPS_PRINT(debug_tunnel & DB_TN_INIT,
-+ "klips_debug:ipsec_tunnel_ioctl: "
-+ "physical device %s requested is not up.\n",
-+ cf->cf_name);
-+ ipsec_dev_put(them);
-+ return -ENXIO;
-+ }
-+#endif
-+
-+ if (prv && prv->dev) {
-+ KLIPS_PRINT(debug_tunnel & DB_TN_INIT,
-+ "klips_debug:ipsec_tunnel_ioctl: "
-+ "virtual device is already connected to %s.\n",
-+ prv->dev->name ? prv->dev->name : "NULL");
-+ ipsec_dev_put(them);
-+ return -EBUSY;
-+ }
-+ return ipsec_tunnel_attach(dev, them);
-+
-+ case IPSEC_DEL_DEV:
-+ KLIPS_PRINT(debug_tunnel & DB_TN_INIT,
-+ "klips_debug:ipsec_tunnel_ioctl: "
-+ "calling ipsec_tunnel_detatch.\n");
-+ if (! prv->dev) {
-+ KLIPS_PRINT(debug_tunnel & DB_TN_INIT,
-+ "klips_debug:ipsec_tunnel_ioctl: "
-+ "physical device not connected.\n");
-+ return -ENODEV;
-+ }
-+ return ipsec_tunnel_detach(dev);
-+
-+ case IPSEC_CLR_DEV:
-+ KLIPS_PRINT(debug_tunnel & DB_TN_INIT,
-+ "klips_debug:ipsec_tunnel_ioctl: "
-+ "calling ipsec_tunnel_clear.\n");
-+ return ipsec_tunnel_clear();
-+
-+ default:
-+ KLIPS_PRINT(debug_tunnel & DB_TN_INIT,
-+ "klips_debug:ipsec_tunnel_ioctl: "
-+ "unknown command %d.\n",
-+ cmd);
-+ return -EOPNOTSUPP;
-+ }
-+}
-+
-+int
-+ipsec_device_event(struct notifier_block *unused, unsigned long event, void *ptr)
-+{
-+ struct device *dev = ptr;
-+ struct device *ipsec_dev;
-+ struct ipsecpriv *priv;
-+ int i;
-+
-+ if (dev == NULL) {
-+ KLIPS_PRINT(debug_tunnel & DB_TN_INIT,
-+ "klips_debug:ipsec_device_event: "
-+ "dev=NULL for event type %ld.\n",
-+ event);
-+ return(NOTIFY_DONE);
-+ }
-+
-+ /* check for loopback devices */
-+ if (dev && (dev->flags & IFF_LOOPBACK)) {
-+ return(NOTIFY_DONE);
-+ }
-+
-+ switch (event) {
-+ case NETDEV_DOWN:
-+ /* look very carefully at the scope of these compiler
-+ directives before changing anything... -- RGB */
-+#ifdef NET_21
-+ case NETDEV_UNREGISTER:
-+ switch (event) {
-+ case NETDEV_DOWN:
-+#endif /* NET_21 */
-+ KLIPS_PRINT(debug_tunnel & DB_TN_INIT,
-+ "klips_debug:ipsec_device_event: "
-+ "NETDEV_DOWN dev=%s flags=%x\n",
-+ dev->name,
-+ dev->flags);
-+ if(strncmp(dev->name, "ipsec", strlen("ipsec")) == 0) {
-+ printk(KERN_CRIT "IPSEC EVENT: KLIPS device %s shut down.\n",
-+ dev->name);
-+ }
-+#ifdef NET_21
-+ break;
-+ case NETDEV_UNREGISTER:
-+ KLIPS_PRINT(debug_tunnel & DB_TN_INIT,
-+ "klips_debug:ipsec_device_event: "
-+ "NETDEV_UNREGISTER dev=%s flags=%x\n",
-+ dev->name,
-+ dev->flags);
-+ break;
-+ }
-+#endif /* NET_21 */
-+
-+ /* find the attached physical device and detach it. */
-+ for(i = 0; i < IPSEC_NUM_IF; i++) {
-+ ipsec_dev = ipsecdevices[i];
-+
-+ if(ipsec_dev) {
-+ priv = (struct ipsecpriv *)(ipsec_dev->priv);
-+ if(priv) {
-+ ;
-+ if(((struct device *)(priv->dev)) == dev) {
-+ /* dev_close(ipsec_dev); */
-+ /* return */ ipsec_tunnel_detach(ipsec_dev);
-+ KLIPS_PRINT(debug_tunnel & DB_TN_INIT,
-+ "klips_debug:ipsec_device_event: "
-+ "device '%s' has been detached.\n",
-+ ipsec_dev->name);
-+ break;
-+ }
-+ } else {
-+ KLIPS_PRINT(debug_tunnel & DB_TN_INIT,
-+ "klips_debug:ipsec_device_event: "
-+ "device '%s' has no private data space!\n",
-+ ipsec_dev->name);
-+ }
-+ }
-+ }
-+ break;
-+ case NETDEV_UP:
-+ KLIPS_PRINT(debug_tunnel & DB_TN_INIT,
-+ "klips_debug:ipsec_device_event: "
-+ "NETDEV_UP dev=%s\n",
-+ dev->name);
-+ break;
-+#ifdef NET_21
-+ case NETDEV_REBOOT:
-+ KLIPS_PRINT(debug_tunnel & DB_TN_INIT,
-+ "klips_debug:ipsec_device_event: "
-+ "NETDEV_REBOOT dev=%s\n",
-+ dev->name);
-+ break;
-+ case NETDEV_CHANGE:
-+ KLIPS_PRINT(debug_tunnel & DB_TN_INIT,
-+ "klips_debug:ipsec_device_event: "
-+ "NETDEV_CHANGE dev=%s flags=%x\n",
-+ dev->name,
-+ dev->flags);
-+ break;
-+ case NETDEV_REGISTER:
-+ KLIPS_PRINT(debug_tunnel & DB_TN_INIT,
-+ "klips_debug:ipsec_device_event: "
-+ "NETDEV_REGISTER dev=%s\n",
-+ dev->name);
-+ break;
-+ case NETDEV_CHANGEMTU:
-+ KLIPS_PRINT(debug_tunnel & DB_TN_INIT,
-+ "klips_debug:ipsec_device_event: "
-+ "NETDEV_CHANGEMTU dev=%s to mtu=%d\n",
-+ dev->name,
-+ dev->mtu);
-+ break;
-+ case NETDEV_CHANGEADDR:
-+ KLIPS_PRINT(debug_tunnel & DB_TN_INIT,
-+ "klips_debug:ipsec_device_event: "
-+ "NETDEV_CHANGEADDR dev=%s\n",
-+ dev->name);
-+ break;
-+ case NETDEV_GOING_DOWN:
-+ KLIPS_PRINT(debug_tunnel & DB_TN_INIT,
-+ "klips_debug:ipsec_device_event: "
-+ "NETDEV_GOING_DOWN dev=%s\n",
-+ dev->name);
-+ break;
-+ case NETDEV_CHANGENAME:
-+ KLIPS_PRINT(debug_tunnel & DB_TN_INIT,
-+ "klips_debug:ipsec_device_event: "
-+ "NETDEV_CHANGENAME dev=%s\n",
-+ dev->name);
-+ break;
-+#endif /* NET_21 */
-+ default:
-+ KLIPS_PRINT(debug_tunnel & DB_TN_INIT,
-+ "klips_debug:ipsec_device_event: "
-+ "event type %ld unrecognised for dev=%s\n",
-+ event,
-+ dev->name);
-+ break;
-+ }
-+ return NOTIFY_DONE;
-+}
-+
-+/*
-+ * Called when an ipsec tunnel device is initialized.
-+ * The ipsec tunnel device structure is passed to us.
-+ */
-+
-+int
-+ipsec_tunnel_init(struct device *dev)
-+{
-+ int i;
-+
-+ KLIPS_PRINT(debug_tunnel,
-+ "klips_debug:ipsec_tunnel_init: "
-+ "allocating %lu bytes initialising device: %s\n",
-+ (unsigned long) sizeof(struct ipsecpriv),
-+ dev->name ? dev->name : "NULL");
-+
-+ /* Add our tunnel functions to the device */
-+ dev->open = ipsec_tunnel_open;
-+ dev->stop = ipsec_tunnel_close;
-+ dev->hard_start_xmit = ipsec_tunnel_start_xmit;
-+ dev->get_stats = ipsec_tunnel_get_stats;
-+
-+ dev->priv = kmalloc(sizeof(struct ipsecpriv), GFP_KERNEL);
-+ if (dev->priv == NULL)
-+ return -ENOMEM;
-+ memset((caddr_t)(dev->priv), 0, sizeof(struct ipsecpriv));
-+
-+ for(i = 0; i < sizeof(zeroes); i++) {
-+ ((__u8*)(zeroes))[i] = 0;
-+ }
-+
-+#ifndef NET_21
-+ /* Initialize the tunnel device structure */
-+ for (i = 0; i < DEV_NUMBUFFS; i++)
-+ skb_queue_head_init(&dev->buffs[i]);
-+#endif /* !NET_21 */
-+
-+ dev->set_multicast_list = NULL;
-+ dev->do_ioctl = ipsec_tunnel_ioctl;
-+ dev->hard_header = NULL;
-+ dev->rebuild_header = NULL;
-+ dev->set_mac_address = NULL;
-+#ifndef NET_21
-+ dev->header_cache_bind = NULL;
-+#endif /* !NET_21 */
-+ dev->header_cache_update= NULL;
-+
-+#ifdef NET_21
-+/* prv->neigh_setup = NULL; */
-+ dev->neigh_setup = ipsec_tunnel_neigh_setup_dev;
-+#endif /* NET_21 */
-+ dev->hard_header_len = 0;
-+ dev->mtu = 0;
-+ dev->addr_len = 0;
-+ dev->type = ARPHRD_VOID; /* ARPHRD_TUNNEL; */ /* ARPHRD_ETHER; */
-+ dev->tx_queue_len = 10; /* Small queue */
-+ memset((caddr_t)(dev->broadcast),0xFF, ETH_ALEN); /* what if this is not attached to ethernet? */
-+
-+ /* New-style flags. */
-+ dev->flags = IFF_NOARP /* 0 */ /* Petr Novak */;
-+#ifdef NET_21
-+ dev_init_buffers(dev);
-+#else /* NET_21 */
-+ dev->family = AF_INET;
-+ dev->pa_addr = 0;
-+ dev->pa_brdaddr = 0;
-+ dev->pa_mask = 0;
-+ dev->pa_alen = 4;
-+#endif /* NET_21 */
-+
-+ /* We're done. Have I forgotten anything? */
-+ return 0;
-+}
-+
-+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
-+/* Module specific interface (but it links with the rest of IPSEC) */
-+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
-+
-+int
-+ipsec_tunnel_probe(struct device *dev)
-+{
-+ ipsec_tunnel_init(dev);
-+ return 0;
-+}
-+
-+struct device *ipsecdevices[IPSEC_NUM_IF];
-+
-+int
-+ipsec_tunnel_init_devices(void)
-+{
-+ int i;
-+ char name[IFNAMSIZ];
-+ struct device *dev_ipsec;
-+
-+ KLIPS_PRINT(debug_tunnel & DB_TN_INIT,
-+ "klips_debug:ipsec_tunnel_init_devices: "
-+ "creating and registering IPSEC_NUM_IF=%u devices, allocating %lu per device, IFNAMSIZ=%u.\n",
-+ IPSEC_NUM_IF,
-+ (unsigned long) (sizeof(struct device) + IFNAMSIZ),
-+ IFNAMSIZ);
-+
-+ for(i = 0; i < IPSEC_NUM_IF; i++) {
-+ sprintf(name, IPSEC_DEV_FORMAT, i);
-+ dev_ipsec = (struct device*)kmalloc(sizeof(struct device), GFP_KERNEL);
-+ if (dev_ipsec == NULL) {
-+ KLIPS_PRINT(debug_tunnel & DB_TN_INIT,
-+ "klips_debug:ipsec_tunnel_init_devices: "
-+ "failed to allocate memory for device %s, quitting device init.\n",
-+ name);
-+ return -ENOMEM;
-+ }
-+ memset((caddr_t)dev_ipsec, 0, sizeof(struct device));
-+#ifdef NETDEV_23
-+ strncpy(dev_ipsec->name, name, sizeof(dev_ipsec->name));
-+#else /* NETDEV_23 */
-+ dev_ipsec->name = (char*)kmalloc(IFNAMSIZ, GFP_KERNEL);
-+ if (dev_ipsec->name == NULL) {
-+ KLIPS_PRINT(debug_tunnel & DB_TN_INIT,
-+ "klips_debug:ipsec_tunnel_init_devices: "
-+ "failed to allocate memory for device %s name, quitting device init.\n",
-+ name);
-+ return -ENOMEM;
-+ }
-+ memset((caddr_t)dev_ipsec->name, 0, IFNAMSIZ);
-+ strncpy(dev_ipsec->name, name, IFNAMSIZ);
-+#endif /* NETDEV_23 */
-+ dev_ipsec->next = NULL;
-+ dev_ipsec->init = &ipsec_tunnel_probe;
-+ KLIPS_PRINT(debug_tunnel & DB_TN_INIT,
-+ "klips_debug:ipsec_tunnel_init_devices: "
-+ "registering device %s\n",
-+ dev_ipsec->name);
-+
-+ /* reference and hold the device reference */
-+ dev_hold(dev_ipsec);
-+ ipsecdevices[i]=dev_ipsec;
-+
-+ if (register_netdev(dev_ipsec) != 0) {
-+ KLIPS_PRINT(1 || debug_tunnel & DB_TN_INIT,
-+ "klips_debug:ipsec_tunnel_init_devices: "
-+ "registering device %s failed, quitting device init.\n",
-+ dev_ipsec->name);
-+ return -EIO;
-+ } else {
-+ KLIPS_PRINT(debug_tunnel & DB_TN_INIT,
-+ "klips_debug:ipsec_tunnel_init_devices: "
-+ "registering device %s succeeded, continuing...\n",
-+ dev_ipsec->name);
-+ }
-+ }
-+ return 0;
-+}
-+
-+/* void */
-+int
-+ipsec_tunnel_cleanup_devices(void)
-+{
-+ int error = 0;
-+ int i;
-+ char name[32];
-+ struct device *dev_ipsec;
-+
-+ for(i = 0; i < IPSEC_NUM_IF; i++) {
-+ dev_ipsec = ipsecdevices[i];
-+ if(dev_ipsec == NULL) {
-+ continue;
-+ }
-+
-+ /* release reference */
-+ ipsecdevices[i]=NULL;
-+ ipsec_dev_put(dev_ipsec);
-+
-+ KLIPS_PRINT(debug_tunnel, "Unregistering %s (refcnt=%d)\n",
-+ name,
-+ atomic_read(&dev_ipsec->refcnt));
-+ unregister_netdev(dev_ipsec);
-+ KLIPS_PRINT(debug_tunnel, "Unregisted %s\n", name);
-+#ifndef NETDEV_23
-+ kfree(dev_ipsec->name);
-+ dev_ipsec->name=NULL;
-+#endif /* !NETDEV_23 */
-+ kfree(dev_ipsec->priv);
-+ dev_ipsec->priv=NULL;
-+ }
-+ return error;
-+}
-+
-+/*
-+ * $Log: ipsec_tunnel.c,v $
-+ * Revision 1.220 2004/04/06 02:49:26 mcr
-+ * pullup of algo code from alg-branch.
-+ *
-+ * Revision 1.219 2004/02/03 03:13:17 mcr
-+ * minor edits for readability, and error reporting.
-+ *
-+ * Revision 1.218 2004/01/27 20:29:20 mcr
-+ * fix for unregister_netdev() problem for underlying eth0.
-+ *
-+ * Revision 1.217 2003/12/10 01:14:27 mcr
-+ * NAT-traversal patches to KLIPS.
-+ *
-+ * Revision 1.216 2003/12/04 23:01:17 mcr
-+ * removed ipsec_netlink.h
-+ *
-+ * Revision 1.215 2003/12/04 16:35:16 ken
-+ * Fix for ATM devices where physdev->hard_header_len *is* correct
-+ *
-+ * Revision 1.214 2003/11/25 23:52:37 mcr
-+ * fix typo in patch - ixs-> needed.
-+ *
-+ * Revision 1.213 2003/11/24 18:25:49 mcr
-+ * patch from willy@w.ods.org to fix problems with ATM interfaces.
-+ *
-+ * Revision 1.212 2003/10/31 02:27:55 mcr
-+ * pulled up port-selector patches and sa_id elimination.
-+ *
-+ * Revision 1.211.2.2 2003/10/29 01:30:41 mcr
-+ * elimited "struct sa_id".
-+ *
-+ * Revision 1.211.2.1 2003/09/21 13:59:56 mcr
-+ * pre-liminary X.509 patch - does not yet pass tests.
-+ *
-+ * Revision 1.211 2003/09/10 16:46:30 mcr
-+ * patches for 2.4 backport/2.6 existence.
-+ *
-+ * Revision 1.210 2003/07/31 22:47:16 mcr
-+ * preliminary (untested by FS-team) 2.5 patches.
-+ *
-+ * Revision 1.209 2003/06/22 21:28:43 mcr
-+ * inability to unload module was caused by calls to dev_get
-+ * (ipsec_dev_get), to gather a device from a name. There is
-+ * simply no reason to look the devices up - they should be kept
-+ * in a nice array, ready for use.
-+ *
-+ * Revision 1.208 2003/06/22 21:25:07 mcr
-+ * all staticly counted ipsecXXX device support removed.
-+ *
-+ * Revision 1.207 2003/04/02 20:15:37 mcr
-+ * fix for PR#204 - do not clear connection tracking info if we
-+ * the packet is being sent in the clear.
-+ *
-+ * Revision 1.206 2003/02/12 19:32:51 rgb
-+ * Refactored file to:
-+ * ipsec_xmit.c
-+ * ipsec_xmit.h
-+ * ipsec_mast.c
-+ *
-+ * Revision 1.205 2003/02/06 17:47:00 rgb
-+ *
-+ * Remove unused ipsec_tunnel_lock() and ipsec_tunnel_unlock() code.
-+ * Refactor ipsec_tunnel_start_xmit() further into:
-+ * ipsec_xmit_sanity_check_dev()
-+ * ipsec_xmit_sanity_check_skb()
-+ * ipsec_xmit_strip_hard_header()
-+ * ipsec_xmit_restore_hard_header()
-+ * ipsec_xmit_send()
-+ * ipsec_xmit_cleanup()
-+ * and start a skeletal ipsec_mast_start_xmit() .
-+ *
-+ * Revision 1.204 2003/02/06 06:43:46 rgb
-+ *
-+ * Refactor ipsec_tunnel_start_xmit, bringing out:
-+ * ipsec_xmit_SAlookup
-+ * ipsec_xmit_encap_once
-+ * ipsec_xmit_encap_bundle
-+ *
-+ * Revision 1.203 2003/02/06 02:21:34 rgb
-+ *
-+ * Moved "struct auth_alg" from ipsec_rcv.c to ipsec_ah.h .
-+ * Changed "struct ah" to "struct ahhdr" and "struct esp" to "struct esphdr".
-+ * Removed "#ifdef INBOUND_POLICY_CHECK_eroute" dead code.
-+ *
-+ * Revision 1.202 2003/01/03 07:38:01 rgb
-+ *
-+ * Start to refactor ipsec_tunnel_start_xmit() by putting local variables
-+ * into struct ipsec_xmit_state and renaming a few variables to give more
-+ * unique or searchable names.
-+ *
-+ * Revision 1.201 2003/01/03 00:31:28 rgb
-+ *
-+ * Clean up memset usage, including fixing 2 places where keys were not
-+ * properly wiped.
-+ *
-+ * Revision 1.200 2002/12/06 02:24:02 mcr
-+ * patches for compiling against SUSE 8.1 kernels. Requires
-+ * an additional -DSUSE_LINUX_2_4_19_IS_STUPID.
-+ *
-+ * Revision 1.199 2002/10/12 23:11:53 dhr
-+ *
-+ * [KenB + DHR] more 64-bit cleanup
-+ *
-+ * Revision 1.198 2002/10/05 05:02:58 dhr
-+ *
-+ * C labels go on statements
-+ *
-+ * Revision 1.197 2002/09/20 05:01:50 rgb
-+ * Added compiler directive to switch on IP options and fix IP options bug.
-+ * Make ip->ihl treatment consistent using shifts rather than multiplications.
-+ * Check for large enough packet before accessing udp header for IKE bypass.
-+ * Added memory allocation debugging.
-+ * Fixed potential memory allocation failure-induced oops.
-+ *
-+ * Revision 1.196 2002/07/24 18:44:54 rgb
-+ * Type fiddling to tame ia64 compiler.
-+ *
-+ * Revision 1.195 2002/07/23 03:36:07 rgb
-+ * Fixed 2.2 device initialisation hang.
-+ *
-+ * Revision 1.194 2002/05/27 21:40:34 rgb
-+ * Set unused ipsec devices to ARPHRD_VOID to avoid confusing iproute2.
-+ * Cleaned up intermediate step to dynamic device allocation.
-+ *
-+ * Revision 1.193 2002/05/27 19:31:36 rgb
-+ * Convert to dynamic ipsec device allocation.
-+ * Remove final vistiges of tdb references via IPSEC_KLIPS1_COMPAT.
-+ *
-+ * Revision 1.192 2002/05/23 07:14:28 rgb
-+ * Added refcount code.
-+ * Cleaned up %p variants to 0p%p for test suite cleanup.
-+ *
-+ * Revision 1.191 2002/05/14 02:34:37 rgb
-+ * Change all references to tdb, TDB or Tunnel Descriptor Block to ips,
-+ * ipsec_sa or ipsec_sa.
-+ *
-+ * Revision 1.190 2002/04/24 07:55:32 mcr
-+ * #include patches and Makefiles for post-reorg compilation.
-+ *
-+ * Revision 1.189 2002/04/24 07:36:32 mcr
-+ * Moved from ./klips/net/ipsec/ipsec_tunnel.c,v
-+ *
-+ * Revision 1.188 2002/04/20 00:12:25 rgb
-+ * Added esp IV CBC attack fix, disabled.
-+ *
-+ * Revision 1.187 2002/03/23 19:55:17 rgb
-+ * Fix for 2.2 local IKE fragmentation blackhole. Still won't work if
-+ * iptraf or another pcap app is running.
-+ *
-+ * Revision 1.186 2002/03/19 03:26:22 rgb
-+ * Applied DHR's tunnel patch to streamline IKE/specialSA processing.
-+ *
-+ * Revision 1.185 2002/02/20 04:13:05 rgb
-+ * Send back ICMP_PKT_FILTERED upon %reject.
-+ *
-+ * Revision 1.184 2002/01/29 17:17:56 mcr
-+ * moved include of ipsec_param.h to after include of linux/kernel.h
-+ * otherwise, it seems that some option that is set in ipsec_param.h
-+ * screws up something subtle in the include path to kernel.h, and
-+ * it complains on the snprintf() prototype.
-+ *
-+ * Revision 1.183 2002/01/29 04:00:53 mcr
-+ * more excise of kversions.h header.
-+ *
-+ * Revision 1.182 2002/01/29 02:13:18 mcr
-+ * introduction of ipsec_kversion.h means that include of
-+ * ipsec_param.h must preceed any decisions about what files to
-+ * include to deal with differences in kernel source.
-+ *
-+ * Revision 1.181 2002/01/07 20:00:33 rgb
-+ * Added IKE destination port debugging.
-+ *
-+ * Revision 1.180 2001/12/21 21:49:54 rgb
-+ * Fixed bug as a result of moving IKE bypass above %trap/%hold code.
-+ *
-+ * Revision 1.179 2001/12/19 21:08:14 rgb
-+ * Added transport protocol ports to ipsec_print_ip().
-+ * Update eroute info for non-SA targets.
-+ * Added obey DF code disabled.
-+ * Fixed formatting bugs in ipsec_tunnel_hard_header().
-+ *
-+ * Revision 1.178 2001/12/05 09:36:10 rgb
-+ * Moved the UDP/500 IKE check just above the %hold/%trap checks to avoid
-+ * IKE packets being stolen by the %hold (and returned to the sending KMd
-+ * in an ACQUIRE, ironically ;-).
-+ *
-+ * Revision 1.177 2001/11/26 09:23:50 rgb
-+ * Merge MCR's ipsec_sa, eroute, proc and struct lifetime changes.
-+ *
-+ * Revision 1.170.2.1 2001/09/25 02:28:27 mcr
-+ * struct tdb -> struct ipsec_sa.
-+ * lifetime checks moved to common routines.
-+ * cleaned up includes.
-+ *
-+ * Revision 1.170.2.2 2001/10/22 21:08:01 mcr
-+ * include des.h, removed phony prototypes and fixed calling
-+ * conventions to match real prototypes.
-+ *
-+ * Revision 1.176 2001/11/09 18:32:31 rgb
-+ * Added Hans Schultz' fragmented UDP/500 IKE socket port selector.
-+ *
-+ * Revision 1.175 2001/11/06 20:47:00 rgb
-+ * Added Eric Espie's TRAPSUBNET fix, minus spin-lock-bh dabbling.
-+ *
-+ * Revision 1.174 2001/11/06 19:50:43 rgb
-+ * Moved IP_SEND, ICMP_SEND, DEV_QUEUE_XMIT macros to ipsec_tunnel.h for
-+ * use also by pfkey_v2_parser.c
-+ *
-+ * Revision 1.173 2001/10/29 21:53:44 henry
-+ * tone down the device-down message slightly, until we can make it smarter
-+ *
-+ * Revision 1.172 2001/10/26 04:59:37 rgb
-+ * Added a critical level syslog message if an ipsec device goes down.
-+ *
-+ * Revision 1.171 2001/10/18 04:45:21 rgb
-+ * 2.4.9 kernel deprecates linux/malloc.h in favour of linux/slab.h,
-+ * lib/freeswan.h version macros moved to lib/kversions.h.
-+ * Other compiler directive cleanups.
-+ *
-+ * Revision 1.170 2001/09/25 00:09:50 rgb
-+ * Added NetCelo's TRAPSUBNET code to convert a new type TRAPSUBNET into a
-+ * HOLD.
-+ *
-+ * Revision 1.169 2001/09/15 16:24:05 rgb
-+ * Re-inject first and last HOLD packet when an eroute REPLACE is done.
-+ *
-+ * Revision 1.168 2001/09/14 16:58:37 rgb
-+ * Added support for storing the first and last packets through a HOLD.
-+ *
-+ * Revision 1.167 2001/09/08 21:13:33 rgb
-+ * Added pfkey ident extension support for ISAKMPd. (NetCelo)
-+ *
-+ * Revision 1.166 2001/08/27 19:47:59 rgb
-+ * Clear tdb before usage.
-+ * Added comment: clear IF before calling routing?
-+ *
-+ * Revision 1.165 2001/07/03 01:23:53 rgb
-+ * Send back ICMP iff DF set, !ICMP, offset==0, sysctl_icmp, iph->tot_len >
-+ * emtu, and don't drop.
-+ *
-+ * Revision 1.164 2001/06/14 19:35:10 rgb
-+ * Update copyright date.
-+ *
-+ * Revision 1.163 2001/06/06 20:28:51 rgb
-+ * Added sanity checks for NULL skbs and devices.
-+ * Added more debugging output to various functions.
-+ * Removed redundant dev->priv argument to ipsec_tunnel_{at,de}tach().
-+ * Renamed ipsec_tunnel_attach() virtual and physical device arguments.
-+ * Corrected neigh_setup() device function assignment.
-+ * Keep valid pointers to ipsec_tunnel_*() on detach.
-+ * Set dev->type to the originally-initiallised value.
-+ *
-+ * Revision 1.162 2001/06/01 07:28:04 rgb
-+ * Added sanity checks for detached devices. Don't down virtual devices
-+ * to prevent packets going out in the clear if the detached device comes
-+ * back up.
-+ *
-+ * Revision 1.161 2001/05/30 08:14:52 rgb
-+ * Removed vestiges of esp-null transforms.
-+ * NetDev Notifier instrumentation to track down disappearing devices.
-+ *
-+ * Revision 1.160 2001/05/29 05:15:12 rgb
-+ * Added SS' PMTU patch which notifies sender if packet doesn't fit
-+ * physical MTU (if it wasn't ICMP) and then drops it.
-+ *
-+ * Revision 1.159 2001/05/27 06:12:12 rgb
-+ * Added structures for pid, packet count and last access time to eroute.
-+ * Added packet count to beginning of /proc/net/ipsec_eroute.
-+ *
-+ * Revision 1.158 2001/05/24 05:39:33 rgb
-+ * Applied source zeroing to 2.2 ip_route_output() call as well to enable
-+ * PASS eroutes for opportunism.
-+ *
-+ * Revision 1.157 2001/05/23 22:35:28 rgb
-+ * 2.4 source override simplification.
-+ *
-+ * Revision 1.156 2001/05/23 21:41:31 rgb
-+ * Added error return code printing on ip_route_output().
-+ *
-+ * Revision 1.155 2001/05/23 05:09:13 rgb
-+ * Fixed incorrect ip_route_output() failure message.
-+ *
-+ * Revision 1.154 2001/05/21 14:53:31 rgb
-+ * Added debug statement for case when ip_route_output() fails, causing
-+ * packet to be dropped, but log looked ok.
-+ *
-+ * Revision 1.153 2001/05/19 02:37:54 rgb
-+ * Fixed missing comment termination.
-+ *
-+ * Revision 1.152 2001/05/19 02:35:50 rgb
-+ * Debug code optimisation for non-debug speed.
-+ * Kernel version compiler define comments.
-+ * 2.2 and 2.4 kernel ip_send device and ip debug output added.
-+ *
-+ * Revision 1.151 2001/05/18 16:17:35 rgb
-+ * Changed reference from "magic" to "shunt" SAs.
-+ *
-+ * Revision 1.150 2001/05/18 16:12:19 rgb
-+ * Changed UDP/500 bypass test from 3 nested ifs to one anded if.
-+ *
-+ * Revision 1.149 2001/05/16 04:39:33 rgb
-+ * Add default == eroute.dest to IKE bypass conditions for magic eroutes.
-+ *
-+ * Revision 1.148 2001/05/05 03:31:41 rgb
-+ * IP frag debugging updates and enhancements.
-+ *
-+ * Revision 1.147 2001/05/03 19:41:40 rgb
-+ * Added SS' skb_cow fix for 2.4.4.
-+ *
-+ * Revision 1.146 2001/04/30 19:28:16 rgb
-+ * Update for 2.4.4. ip_select_ident() now has 3 args.
-+ *
-+ * Revision 1.145 2001/04/23 14:56:10 rgb
-+ * Added spin_lock() check to prevent double-locking for multiple
-+ * transforms and hence kernel lock-ups with SMP kernels.
-+ *
-+ * Revision 1.144 2001/04/21 23:04:45 rgb
-+ * Define out skb->used for 2.4 kernels.
-+ * Check if soft expire has already been sent before sending another to
-+ * prevent ACQUIRE flooding.
-+ *
-+ * Revision 1.143 2001/03/16 07:37:21 rgb
-+ * Added comments to all #endifs.
-+ *
-+ * Revision 1.142 2001/02/28 05:03:27 rgb
-+ * Clean up and rationalise startup messages.
-+ *
-+ * Revision 1.141 2001/02/27 22:24:54 rgb
-+ * Re-formatting debug output (line-splitting, joining, 1arg/line).
-+ * Check for satoa() return codes.
-+ *
-+ * Revision 1.140 2001/02/27 06:40:12 rgb
-+ * Fixed TRAP->HOLD eroute byte order.
-+ *
-+ * Revision 1.139 2001/02/26 20:38:59 rgb
-+ * Added compiler defines for 2.4.x-specific code.
-+ *
-+ * Revision 1.138 2001/02/26 19:57:27 rgb
-+ * Implement magic SAs %drop, %reject, %trap, %hold, %pass as part
-+ * of the new SPD and to support opportunistic.
-+ * Drop sysctl_ipsec_{no_eroute_pass,opportunistic}, replaced by magic SAs.
-+ *
-+ * Revision 1.137 2001/02/19 22:29:49 rgb
-+ * Fixes for presence of active ipv6 segments which share ipsec physical
-+ * device (gg).
-+ *
-+ * Revision 1.136 2001/01/29 22:30:38 rgb
-+ * Fixed minor acquire debug printing bug.
-+ *
-+ * Revision 1.135 2001/01/29 22:19:45 rgb
-+ * Zero source address for 2.4 bypass route lookup.
-+ *
-+ * Revision 1.134 2001/01/23 20:19:49 rgb
-+ * 2.4 fix to remove removed is_clone member.
-+ *
-+ * Revision 1.133 2000/12/09 22:08:35 rgb
-+ * Fix NET_23 bug, should be NETDEV_23.
-+ *
-+ * Revision 1.132 2000/12/01 06:54:50 rgb
-+ * Fix for new 2.4 IP TTL default variable name.
-+ *
-+ * Revision 1.131 2000/11/09 20:52:15 rgb
-+ * More spinlock shuffling, locking earlier and unlocking later in rcv to
-+ * include ipcomp and prevent races, renaming some tdb variables that got
-+ * forgotten, moving some unlocks to include tdbs and adding a missing
-+ * unlock. Thanks to Svenning for some of these.
-+ *
-+ * Revision 1.130 2000/11/09 20:11:22 rgb
-+ * Minor shuffles to fix non-standard kernel config option selection.
-+ *
-+ * Revision 1.129 2000/11/06 04:32:49 rgb
-+ * Clean up debug printing.
-+ * Copy skb->protocol for all kernel versions.
-+ * Ditched spin_lock_irqsave in favour of spin_lock.
-+ * Disabled TTL decrement, done in ip_forward.
-+ * Added debug printing before pfkey_acquire().
-+ * Fixed printk-deltdbchain-spin_lock races (Svenning).
-+ * Use defaultTTL for 2.1+ kernels.
-+ * Add Svenning's adaptive content compression.
-+ * Fix up debug display arguments.
-+ *
-+ * Revision 1.128 2000/09/28 00:58:57 rgb
-+ * Moved the IKE passthrough check after the eroute lookup so we can pass
-+ * IKE through intermediate tunnels.
-+ *
-+ * Revision 1.127 2000/09/22 17:52:11 rgb
-+ * Fixed misleading ipcomp debug output.
-+ *
-+ * Revision 1.126 2000/09/22 04:22:56 rgb
-+ * Fixed dumb spi->cpi conversion error.
-+ *
-+ * Revision 1.125 2000/09/21 04:34:48 rgb
-+ * A few debug-specific things should be hidden under
-+ * CONFIG_IPSEC_DEBUG.(MB)
-+ * Improved ip_send() error handling.(MB)
-+ *
-+ * Revision 1.124 2000/09/21 03:40:58 rgb
-+ * Added more debugging to try and track down the cpi outward copy problem.
-+ *
-+ * Revision 1.123 2000/09/19 07:08:49 rgb
-+ * Added debugging to outgoing compression report.
-+ *
-+ * Revision 1.122 2000/09/18 19:21:26 henry
-+ * RGB-supplied fix for RH5.2 problem
-+ *
-+ * Revision 1.121 2000/09/17 21:05:09 rgb
-+ * Added tdb to skb_compress call to write in cpi.
-+ *
-+ * Revision 1.120 2000/09/17 16:57:16 rgb
-+ * Added Svenning's patch to remove restriction of ipcomp to innermost
-+ * transform.
-+ *
-+ * Revision 1.119 2000/09/15 11:37:01 rgb
-+ * Merge in heavily modified Svenning Soerensen's <svenning@post5.tele.dk>
-+ * IPCOMP zlib deflate code.
-+ *
-+ * Revision 1.118 2000/09/15 04:57:16 rgb
-+ * Moved debug output after sanity check.
-+ * Added tos copy sysctl.
-+ *
-+ * Revision 1.117 2000/09/12 03:22:51 rgb
-+ * Converted ipsec_icmp, no_eroute_pass, opportunistic and #if0 debugs to
-+ * sysctl.
-+ *
-+ * Revision 1.116 2000/09/08 19:18:19 rgb
-+ * Change references from DEBUG_IPSEC to CONFIG_IPSEC_DEBUG.
-+ * Added outgoing opportunistic hook, ifdef'ed out.
-+ *
-+ * Revision 1.115 2000/08/30 05:27:29 rgb
-+ * Removed all the rest of the references to tdb_spi, tdb_proto, tdb_dst.
-+ * Kill remainder of tdb_xform, tdb_xdata, xformsw.
-+ *
-+ * Revision 1.114 2000/08/28 18:15:46 rgb
-+ * Added MB's nf-debug reset patch.
-+ *
-+ * Revision 1.113 2000/08/27 02:26:40 rgb
-+ * Send all no-eroute-bypass, pluto-bypass and passthrough packets through
-+ * fragmentation machinery for 2.0, 2.2 and 2.4 kernels.
-+ *
-+ * Revision 1.112 2000/08/20 21:37:33 rgb
-+ * Activated pfkey_expire() calls.
-+ * Added a hard/soft expiry parameter to pfkey_expire(). (Momchil)
-+ * Re-arranged the order of soft and hard expiry to conform to RFC2367.
-+ * Clean up references to CONFIG_IPSEC_PFKEYv2.
-+ *
-+ * Revision 1.111 2000/08/01 14:51:51 rgb
-+ * Removed _all_ remaining traces of DES.
-+ *
-+ * Revision 1.110 2000/07/28 14:58:31 rgb
-+ * Changed kfree_s to kfree, eliminating extra arg to fix 2.4.0-test5.
-+ *
-+ * Revision 1.109 2000/07/28 13:50:54 rgb
-+ * Changed enet_statistics to net_device_stats and added back compatibility
-+ * for pre-2.1.19.
-+ *
-+ * Revision 1.108 2000/05/16 03:03:11 rgb
-+ * Updates for 2.3.99pre8 from MB.
-+ *
-+ * Revision 1.107 2000/05/10 23:08:21 rgb
-+ * Print a debug warning about bogus packets received by the outgoing
-+ * processing machinery only when klipsdebug is not set to none.
-+ * Comment out the device initialisation informational messages.
-+ *
-+ * Revision 1.106 2000/05/10 19:17:14 rgb
-+ * Define an IP_SEND macro, intending to have all packet passthroughs
-+ * use fragmentation. This didn't quite work, but is a step in the
-+ * right direction.
-+ * Added buffer allocation debugging statements.
-+ * Added configure option to shut off no eroute passthrough.
-+ * Only check usetime against soft and hard limits if the tdb has been
-+ * used.
-+ * Cast output of ntohl so that the broken prototype doesn't make our
-+ * compile noisy.
-+ *
-+ * Revision 1.105 2000/03/22 16:15:37 rgb
-+ * Fixed renaming of dev_get (MB).
-+ *
-+ * Revision 1.104 2000/03/16 14:04:15 rgb
-+ * Indented headers for readability.
-+ * Fixed debug scope to enable compilation with debug off.
-+ * Added macros for ip_chk_addr and IS_MYADDR for identifying self.
-+ *
-+ * Revision 1.103 2000/03/16 07:11:07 rgb
-+ * Hardcode PF_KEYv2 support.
-+ * Fixed bug which allowed UDP/500 packet from another machine
-+ * through in the clear.
-+ * Added disabled skb->protocol fix for ISDN/ASYNC PPP from Matjaz Godec.
-+ *
-+ * Revision 1.102 2000/03/14 12:26:59 rgb
-+ * Added skb->nfct support for clearing netfilter conntrack bits (MB).
-+ *
-+ * Revision 1.101 2000/02/14 21:05:22 rgb
-+ * Added MB's netif_queue fix for kernels 2.3.43+.
-+ *
-+ * Revision 1.100 2000/01/26 10:04:57 rgb
-+ * Fixed noisy 2.0 printk arguments.
-+ *
-+ * Revision 1.99 2000/01/21 06:16:25 rgb
-+ * Added sanity checks on skb_push(), skb_pull() to prevent panics.
-+ * Switched to AF_ENCAP macro.
-+ * Shortened debug output per packet and re-arranging debug_tunnel
-+ * bitmap flags, while retaining necessary information to avoid
-+ * trampling the kernel print ring buffer.
-+ * Reformatted recursion switch code.
-+ * Changed all references to tdb_proto to tdb_said.proto for clarity.
-+ *
-+ * Revision 1.98 2000/01/13 08:09:31 rgb
-+ * Shuffled debug_tunnel switches to focus output.
-+ * Fixed outgoing recursion bug, limiting to recursing only if the remote
-+ * SG changes and if it is valid, ie. not passthrough.
-+ * Clarified a number of debug messages.
-+ *
-+ * Revision 1.97 2000/01/10 16:37:16 rgb
-+ * MB support for new ip_select_ident() upon disappearance of
-+ * ip_id_count in 2.3.36+.
-+ *
-+ * Revision 1.96 1999/12/31 14:59:08 rgb
-+ * MB fix to use new skb_copy_expand in kernel 2.3.35.
-+ *
-+ * Revision 1.95 1999/12/29 21:15:44 rgb
-+ * Fix tncfg to aliased device bug.
-+ *
-+ * Revision 1.94 1999/12/22 04:26:06 rgb
-+ * Converted all 'static' functions to 'DEBUG_NO_STATIC' to enable
-+ * debugging by providing external labels to all functions with debugging
-+ * turned on.
-+ *
-+ * Revision 1.93 1999/12/13 13:30:14 rgb
-+ * Changed MTU reports and HW address reporting back to debug only.
-+ *
-+ * Revision 1.92 1999/12/07 18:57:56 rgb
-+ * Fix PFKEY symbol compile error (SADB_*) without pfkey enabled.
-+ *
-+ * Revision 1.91 1999/12/01 22:15:36 rgb
-+ * Add checks for LARVAL and DEAD SAs.
-+ * Change state of SA from MATURE to DYING when a soft lifetime is
-+ * reached and print debug warning.
-+ *
-+ * Revision 1.90 1999/11/23 23:04:04 rgb
-+ * Use provided macro ADDRTOA_BUF instead of hardcoded value.
-+ * Sort out pfkey and freeswan headers, putting them in a library path.
-+ *
-+ * Revision 1.89 1999/11/18 18:50:59 rgb
-+ * Changed all device registrations for static linking to
-+ * dynamic to reduce the number and size of patches.
-+ *
-+ * Revision 1.88 1999/11/18 04:09:19 rgb
-+ * Replaced all kernel version macros to shorter, readable form.
-+ *
-+ * Revision 1.87 1999/11/17 15:53:40 rgb
-+ * Changed all occurrences of #include "../../../lib/freeswan.h"
-+ * to #include <freeswan.h> which works due to -Ilibfreeswan in the
-+ * klips/net/ipsec/Makefile.
-+ *
-+ * Revision 1.86 1999/10/16 18:25:37 rgb
-+ * Moved SA lifetime expiry checks before packet processing.
-+ * Expire SA on replay counter rollover.
-+ *
-+ * Revision 1.85 1999/10/16 04:24:31 rgb
-+ * Add stats for time since last packet.
-+ *
-+ * Revision 1.84 1999/10/16 00:30:47 rgb
-+ * Added SA lifetime counting.
-+ *
-+ * Revision 1.83 1999/10/15 22:15:57 rgb
-+ * Clean out cruft.
-+ * Add debugging.
-+ *
-+ * Revision 1.82 1999/10/08 18:26:19 rgb
-+ * Fix 2.0.3x outgoing fragmented packet memory leak.
-+ *
-+ * Revision 1.81 1999/10/05 02:38:54 rgb
-+ * Lower the default mtu of virtual devices to 16260.
-+ *
-+ * Revision 1.80 1999/10/03 18:56:41 rgb
-+ * Spinlock support for 2.3.xx.
-+ * Don't forget to undo spinlocks on error!
-+ * Check for valid eroute before copying the structure.
-+ *
-+ * Revision 1.79 1999/10/01 15:44:53 rgb
-+ * Move spinlock header include to 2.1> scope.
-+ *
-+ * Revision 1.78 1999/10/01 00:02:43 rgb
-+ * Added tdb structure locking.
-+ * Added eroute structure locking.
-+ *
-+ * Revision 1.77 1999/09/30 02:52:29 rgb
-+ * Add Marc Boucher's Copy-On-Write code (same as ipsec_rcv.c).
-+ *
-+ * Revision 1.76 1999/09/25 19:31:27 rgb
-+ * Refine MSS hack to affect SYN, but not SYN+ACK packets.
-+ *
-+ * Revision 1.75 1999/09/24 22:52:38 rgb
-+ * Fix two things broken in 2.0.38 by trying to fix network notifiers.
-+ *
-+ * Revision 1.74 1999/09/24 00:30:37 rgb
-+ * Add test for changed source as well as destination to check for
-+ * recursion.
-+ *
-+ * Revision 1.73 1999/09/23 20:52:24 rgb
-+ * Add James Morris' MSS hack patch, disabled.
-+ *
-+ * Revision 1.72 1999/09/23 20:22:40 rgb
-+ * Enable, tidy and fix network notifier code.
-+ *
-+ * Revision 1.71 1999/09/23 18:09:05 rgb
-+ * Clean up 2.2.x fragmenting traces.
-+ * Disable dev->type switching, forcing ARPHRD_TUNNEL.
-+ *
-+ * Revision 1.70 1999/09/22 14:14:24 rgb
-+ * Add sanity checks for revectored calls to prevent calling a downed I/F.
-+ *
-+ * Revision 1.69 1999/09/21 15:00:57 rgb
-+ * Add Marc Boucher's packet size check.
-+ * Flesh out network device notifier code.
-+ *
-+ * Revision 1.68 1999/09/18 11:39:57 rgb
-+ * Start to add (disabled) netdevice notifier code.
-+ *
-+ * Revision 1.67 1999/09/17 23:44:40 rgb
-+ * Add a comment warning potential code hackers to stay away from mac.raw.
-+ *
-+ * Revision 1.66 1999/09/17 18:04:02 rgb
-+ * Add fix for unpredictable hard_header_len for ISDN folks (thanks MB).
-+ * Ditch TTL decrement in 2.2 (MB).
-+ *
-+ * Revision 1.65 1999/09/15 23:15:35 henry
-+ * Marc Boucher's PPP fixes
-+ *
-+ * Revision 1.64 1999/09/07 13:40:53 rgb
-+ * Ditch unreliable references to skb->mac.raw.
-+ *
-+ * Revision 1.63 1999/08/28 11:33:09 rgb
-+ * Check for null skb->mac pointer.
-+ *
-+ * Revision 1.62 1999/08/28 02:02:30 rgb
-+ * Add Marc Boucher's fix for properly dealing with skb->sk.
-+ *
-+ * Revision 1.61 1999/08/27 05:23:05 rgb
-+ * Clean up skb->data/raw/nh/h manipulation.
-+ * Add Marc Boucher's mods to aid tcpdump.
-+ * Add sanity checks to skb->raw/nh/h pointer copies in skb_copy_expand.
-+ * Re-order hard_header stripping -- might be able to remove it...
-+ *
-+ * Revision 1.60 1999/08/26 20:01:02 rgb
-+ * Tidy up compiler directives and macros.
-+ * Re-enable ICMP for tunnels where inner_dst != outer_dst.
-+ * Remove unnecessary skb->dev = physdev assignment affecting 2.2.x.
-+ *
-+ * Revision 1.59 1999/08/25 15:44:41 rgb
-+ * Clean up from 2.2.x instrumenting for compilation under 2.0.36.
-+ *
-+ * Revision 1.58 1999/08/25 15:00:54 rgb
-+ * Add dst cache code for 2.2.xx.
-+ * Add sanity check for skb packet header pointers.
-+ * Add/modify debugging instrumentation to *_start_xmit, *_hard_header and
-+ * *_rebuild_header.
-+ * Add neigh_* cache code.
-+ * Change dev->type back to ARPHRD_TUNNEL.
-+ *
-+ * Revision 1.57 1999/08/17 21:50:23 rgb
-+ * Fixed minor debug output bugs.
-+ * Regrouped error recovery exit code.
-+ * Added compiler directives to remove unwanted code and symbols.
-+ * Shut off ICMP messages: to be refined to only send ICMP to remote systems.
-+ * Add debugging code for output function addresses.
-+ * Fix minor bug in (possibly unused) header_cache_bind function.
-+ * Add device neighbour caching code.
-+ * Change dev->type from ARPHRD_TUNNEL to physdev->type.
-+ *
-+ * Revision 1.56 1999/08/03 17:22:56 rgb
-+ * Debug output clarification using KERN_* macros. Other inactive changes
-+ * added.
-+ *
-+ * Revision 1.55 1999/08/03 16:58:46 rgb
-+ * Fix skb_copy_expand size bug. Was getting incorrect size.
-+ *
-+ * Revision 1.54 1999/07/14 19:32:38 rgb
-+ * Fix oversize packet crash and ssh stalling in 2.2.x kernels.
-+ *
-+ * Revision 1.53 1999/06/10 15:44:02 rgb
-+ * Minor reformatting and clean-up.
-+ *
-+ * Revision 1.52 1999/05/09 03:25:36 rgb
-+ * Fix bug introduced by 2.2 quick-and-dirty patch.
-+ *
-+ * Revision 1.51 1999/05/08 21:24:59 rgb
-+ * Add casting to silence the 2.2.x compile.
-+ *
-+ * Revision 1.50 1999/05/05 22:02:32 rgb
-+ * Add a quick and dirty port to 2.2 kernels by Marc Boucher <marc@mbsi.ca>.
-+ *
-+ * Revision 1.49 1999/04/29 15:18:52 rgb
-+ * Change gettdb parameter to a pointer to reduce stack loading and
-+ * facilitate parameter sanity checking.
-+ * Fix undetected bug that might have tried to access a null pointer.
-+ * Eliminate unnessessary usage of tdb_xform member to further switch
-+ * away from the transform switch to the algorithm switch.
-+ * Add return values to init and cleanup functions.
-+ *
-+ * Revision 1.48 1999/04/16 15:38:00 rgb
-+ * Minor rearrangement of freeing code to avoid memory leaks with impossible or
-+ * rare situations.
-+ *
-+ * Revision 1.47 1999/04/15 15:37:25 rgb
-+ * Forward check changes from POST1_00 branch.
-+ *
-+ * Revision 1.32.2.4 1999/04/13 21:00:18 rgb
-+ * Ditch 'things I wish I had known before...'.
-+ *
-+ * Revision 1.32.2.3 1999/04/13 20:34:38 rgb
-+ * Free skb after fragmentation.
-+ * Use stats more effectively.
-+ * Add I/F to mtu notch-down reporting.
-+ *
-+ * Revision 1.32.2.2 1999/04/02 04:26:14 rgb
-+ * Backcheck from HEAD, pre1.0.
-+ *
-+ * Revision 1.46 1999/04/11 00:29:00 henry
-+ * GPL boilerplate
-+ *
-+ * Revision 1.45 1999/04/07 15:42:01 rgb
-+ * Fix mtu/ping bug AGAIN!
-+ *
-+ * Revision 1.44 1999/04/06 04:54:27 rgb
-+ * Fix/Add RCSID Id: and Log: bits to make PHMDs happy. This includes
-+ * patch shell fixes.
-+ *
-+ * Revision 1.43 1999/04/04 03:57:07 rgb
-+ * ip_fragment() doesn't free the supplied skb. Freed.
-+ *
-+ * Revision 1.42 1999/04/01 23:27:15 rgb
-+ * Preload size of virtual mtu.
-+ *
-+ * Revision 1.41 1999/04/01 09:31:23 rgb
-+ * Invert meaning of ICMP PMTUD config option and clarify.
-+ * Code clean-up.
-+ *
-+ * Revision 1.40 1999/04/01 04:37:17 rgb
-+ * SSH stalling bug fix.
-+ *
-+ * Revision 1.39 1999/03/31 23:44:28 rgb
-+ * Don't send ICMP on DF and frag_off.
-+ *
-+ * Revision 1.38 1999/03/31 15:20:10 rgb
-+ * Quiet down debugging.
-+ *
-+ * Revision 1.37 1999/03/31 08:30:31 rgb
-+ * Add switch to shut off ICMP PMTUD packets.
-+ *
-+ * Revision 1.36 1999/03/31 05:44:47 rgb
-+ * Keep PMTU reduction private.
-+ *
-+ * Revision 1.35 1999/03/27 15:13:02 rgb
-+ * PMTU/fragmentation bug fix.
-+ *
-+ * Revision 1.34 1999/03/17 21:19:26 rgb
-+ * Fix kmalloc nonatomic bug.
-+ *
-+ * Revision 1.33 1999/03/17 15:38:42 rgb
-+ * Code clean-up.
-+ * ESP_NULL IV bug fix.
-+ *
-+ * Revision 1.32 1999/03/01 20:44:25 rgb
-+ * Code clean-up.
-+ * Memory leak bug fix.
-+ *
-+ * Revision 1.31 1999/02/27 00:02:09 rgb
-+ * Tune to report the MTU reduction once, rather than after every recursion
-+ * through the encapsulating code, preventing tcp stream stalling.
-+ *
-+ * Revision 1.30 1999/02/24 20:21:01 rgb
-+ * Reformat debug printk's.
-+ * Fix recursive encapsulation, dynamic MTU bugs and add debugging code.
-+ * Clean-up.
-+ *
-+ * Revision 1.29 1999/02/22 17:08:14 rgb
-+ * Fix recursive encapsulation code.
-+ *
-+ * Revision 1.28 1999/02/19 18:27:02 rgb
-+ * Improve DF, fragmentation and PMTU behaviour and add dynamic MTU discovery.
-+ *
-+ * Revision 1.27 1999/02/17 16:51:37 rgb
-+ * Clean out unused cruft.
-+ * Temporarily tone down volume of debug output.
-+ * Temporarily shut off fragment rejection.
-+ * Disabled temporary failed recursive encapsulation loop.
-+ *
-+ * Revision 1.26 1999/02/12 21:21:26 rgb
-+ * Move KLIPS_PRINT to ipsec_netlink.h for accessibility.
-+ *
-+ * Revision 1.25 1999/02/11 19:38:27 rgb
-+ * More clean-up.
-+ * Add sanity checking for skb_copy_expand() to prevent kernel panics on
-+ * skb_put() values out of range.
-+ * Fix head/tailroom calculation causing skb_put() out-of-range values.
-+ * Fix return values to prevent 'nonatomic alloc_skb' warnings.
-+ * Allocate new skb iff needed.
-+ * Added more debug statements.
-+ * Make headroom depend on structure, not hard-coded values.
-+ *
-+ * Revision 1.24 1999/02/10 23:20:33 rgb
-+ * Shut up annoying 'statement has no effect' compiler warnings with
-+ * debugging compiled out.
-+ *
-+ * Revision 1.23 1999/02/10 22:36:30 rgb
-+ * Clean-up obsolete, unused and messy code.
-+ * Converted most IPSEC_DEBUG statements to KLIPS_PRINT macros.
-+ * Rename ipsec_tunnel_do_xmit to ipsec_tunnel_start_xmit and eliminated
-+ * original ipsec_tunnel_start_xmit.
-+ * Send all packet with different inner and outer destinations directly to
-+ * the attached physical device, rather than back through ip_forward,
-+ * preventing disappearing routes problems.
-+ * Do sanity checking before investing too much CPU in allocating new
-+ * structures.
-+ * Fail on IP header options: We cannot process them yet.
-+ * Add some helpful comments.
-+ * Use virtual device for parameters instead of physical device.
-+ *
-+ * Revision 1.22 1999/02/10 03:03:02 rgb
-+ * Duh. Fixed the TTL bug: forgot to update the checksum.
-+ *
-+ * Revision 1.21 1999/02/09 23:17:53 rgb
-+ * Add structure members to ipsec_print_ip debug function.
-+ * Temporarily fix TTL bug preventing tunnel mode from functioning.
-+ *
-+ * Revision 1.20 1999/02/09 00:14:25 rgb
-+ * Add KLIPSPRINT macro. (Not used yet, though.)
-+ * Delete old ip_tunnel code (BADCODE).
-+ * Decrement TTL in outgoing packet.
-+ * Set TTL on new IPIP_TUNNEL to default, not existing packet TTL.
-+ * Delete ethernet only feature and fix hard-coded hard_header_len.
-+ *
-+ * Revision 1.19 1999/01/29 17:56:22 rgb
-+ * 64-bit re-fix submitted by Peter Onion.
-+ *
-+ * Revision 1.18 1999/01/28 22:43:24 rgb
-+ * Fixed bug in ipsec_print_ip that caused an OOPS, found by P.Onion.
-+ *
-+ * Revision 1.17 1999/01/26 02:08:16 rgb
-+ * Removed CONFIG_IPSEC_ALGO_SWITCH macro.
-+ * Removed dead code.
-+ *
-+ * Revision 1.16 1999/01/22 06:25:26 rgb
-+ * Cruft clean-out.
-+ * Added algorithm switch code.
-+ * 64-bit clean-up.
-+ * Passthrough on IPIP protocol, spi 0x0 fix.
-+ * Enhanced debugging.
-+ *
-+ * Revision 1.15 1998/12/01 13:22:04 rgb
-+ * Added support for debug printing of version info.
-+ *
-+ * Revision 1.14 1998/11/30 13:22:55 rgb
-+ * Rationalised all the klips kernel file headers. They are much shorter
-+ * now and won't conflict under RH5.2.
-+ *
-+ * Revision 1.13 1998/11/17 21:13:52 rgb
-+ * Put IKE port bypass debug output in user-switched debug statements.
-+ *
-+ * Revision 1.12 1998/11/13 13:20:25 rgb
-+ * Fixed ntohs bug in udp/500 hole for IKE.
-+ *
-+ * Revision 1.11 1998/11/10 08:01:19 rgb
-+ * Kill tcp/500 hole, keep udp/500 hole.
-+ *
-+ * Revision 1.10 1998/11/09 21:29:26 rgb
-+ * If no eroute is found, discard packet and incr. tx_error.
-+ *
-+ * Revision 1.9 1998/10/31 06:50:00 rgb
-+ * Add tcp/udp/500 bypass.
-+ * Fixed up comments in #endif directives.
-+ *
-+ * Revision 1.8 1998/10/27 00:34:31 rgb
-+ * Reformat debug output of IP headers.
-+ * Newlines added before calls to ipsec_print_ip.
-+ *
-+ * Revision 1.7 1998/10/19 14:44:28 rgb
-+ * Added inclusion of freeswan.h.
-+ * sa_id structure implemented and used: now includes protocol.
-+ *
-+ * Revision 1.6 1998/10/09 04:31:35 rgb
-+ * Added 'klips_debug' prefix to all klips printk debug statements.
-+ *
-+ * Revision 1.5 1998/08/28 03:09:51 rgb
-+ * Prevent kernel log spam with default route through ipsec.
-+ *
-+ * Revision 1.4 1998/08/05 22:23:09 rgb
-+ * Change setdev return code to ENXIO for a non-existant physical device.
-+ *
-+ * Revision 1.3 1998/07/29 20:41:11 rgb
-+ * Add ipsec_tunnel_clear to clear all tunnel attachments.
-+ *
-+ * Revision 1.2 1998/06/25 20:00:33 rgb
-+ * Clean up #endif comments.
-+ * Rename dev_ipsec to dev_ipsec0 for consistency.
-+ * Document ipsec device fields.
-+ * Make ipsec_tunnel_probe visible from rest of kernel for static linking.
-+ * Get debugging report for *every* ipsec device initialisation.
-+ * Comment out redundant code.
-+ *
-+ * Revision 1.1 1998/06/18 21:27:50 henry
-+ * move sources from klips/src to klips/net/ipsec, to keep stupid
-+ * kernel-build scripts happier in the presence of symlinks
-+ *
-+ * Revision 1.8 1998/06/14 23:49:40 rgb
-+ * Clarify version reporting on module loading.
-+ *
-+ * Revision 1.7 1998/05/27 23:19:20 rgb
-+ * Added version reporting.
-+ *
-+ * Revision 1.6 1998/05/18 21:56:23 rgb
-+ * Clean up for numerical consistency of output and cleaning up debug code.
-+ *
-+ * Revision 1.5 1998/05/12 02:44:23 rgb
-+ * Clarifying 'no e-route to host' message.
-+ *
-+ * Revision 1.4 1998/04/30 15:34:35 rgb
-+ * Enclosed most remaining debugging statements in #ifdef's to make it quieter.
-+ *
-+ * Revision 1.3 1998/04/21 21:28:54 rgb
-+ * Rearrange debug switches to change on the fly debug output from user
-+ * space. Only kernel changes checked in at this time. radij.c was also
-+ * changed to temporarily remove buggy debugging code in rj_delete causing
-+ * an OOPS and hence, netlink device open errors.
-+ *
-+ * Revision 1.2 1998/04/12 22:03:24 rgb
-+ * Updated ESP-3DES-HMAC-MD5-96,
-+ * ESP-DES-HMAC-MD5-96,
-+ * AH-HMAC-MD5-96,
-+ * AH-HMAC-SHA1-96 since Henry started freeswan cvs repository
-+ * from old standards (RFC182[5-9] to new (as of March 1998) drafts.
-+ *
-+ * Fixed eroute references in /proc/net/ipsec*.
-+ *
-+ * Started to patch module unloading memory leaks in ipsec_netlink and
-+ * radij tree unloading.
-+ *
-+ * Revision 1.1 1998/04/09 03:06:12 henry
-+ * sources moved up from linux/net/ipsec
-+ *
-+ * Revision 1.1.1.1 1998/04/08 05:35:04 henry
-+ * RGB's ipsec-0.8pre2.tar.gz ipsec-0.8
-+ *
-+ * Revision 0.5 1997/06/03 04:24:48 ji
-+ * Added transport mode.
-+ * Changed the way routing is done.
-+ * Lots of bug fixes.
-+ *
-+ * Revision 0.4 1997/01/15 01:28:15 ji
-+ * No changes.
-+ *
-+ * Revision 0.3 1996/11/20 14:39:04 ji
-+ * Minor cleanups.
-+ * Rationalized debugging code.
-+ *
-+ * Revision 0.2 1996/11/02 00:18:33 ji
-+ * First limited release.
-+ *
-+ * Local Variables:
-+ * c-style: linux
-+ * End:
-+ */
---- /dev/null Tue Mar 11 13:02:56 2003
-+++ linux/net/ipsec/ipsec_xform.c Mon Feb 9 13:51:03 2004
-@@ -0,0 +1,351 @@
-+/*
-+ * Common routines for IPSEC transformations.
-+ * Copyright (C) 1996, 1997 John Ioannidis.
-+ * Copyright (C) 1998, 1999, 2000, 2001 Richard Guy Briggs.
-+ *
-+ * 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. See <http://www.fsf.org/copyleft/gpl.txt>.
-+ *
-+ * 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.
-+ *
-+ * RCSID $Id: ipsec_xform.c,v 1.63 2003/10/31 02:27:55 mcr Exp $
-+ */
-+
-+#include <linux/config.h>
-+#include <linux/version.h>
-+#include <linux/kernel.h> /* printk() */
-+
-+#include "freeswan/ipsec_param.h"
-+
-+#ifdef MALLOC_SLAB
-+# include <linux/slab.h> /* kmalloc() */
-+#else /* MALLOC_SLAB */
-+# include <linux/malloc.h> /* kmalloc() */
-+#endif /* MALLOC_SLAB */
-+#include <linux/errno.h> /* error codes */
-+#include <linux/types.h> /* size_t */
-+#include <linux/interrupt.h> /* mark_bh */
-+
-+#include <linux/netdevice.h> /* struct device, and other headers */
-+#include <linux/etherdevice.h> /* eth_type_trans */
-+#include <linux/ip.h> /* struct iphdr */
-+#include <linux/skbuff.h>
-+#include <linux/random.h> /* get_random_bytes() */
-+#include <freeswan.h>
-+#ifdef SPINLOCK
-+# ifdef SPINLOCK_23
-+# include <linux/spinlock.h> /* *lock* */
-+# else /* SPINLOCK_23 */
-+# include <asm/spinlock.h> /* *lock* */
-+# endif /* SPINLOCK_23 */
-+#endif /* SPINLOCK */
-+#ifdef NET_21
-+# include <asm/uaccess.h>
-+# include <linux/in6.h>
-+#endif
-+#include <asm/checksum.h>
-+#include <net/ip.h>
-+
-+#include "freeswan/radij.h"
-+#include "freeswan/ipsec_encap.h"
-+#include "freeswan/ipsec_radij.h"
-+#include "freeswan/ipsec_xform.h"
-+#include "freeswan/ipsec_ipe4.h"
-+#include "freeswan/ipsec_ah.h"
-+#include "freeswan/ipsec_esp.h"
-+
-+#include <pfkeyv2.h>
-+#include <pfkey.h>
-+
-+#ifdef CONFIG_IPSEC_DEBUG
-+int debug_xform = 0;
-+#endif /* CONFIG_IPSEC_DEBUG */
-+
-+#ifdef SPINLOCK
-+spinlock_t tdb_lock = SPIN_LOCK_UNLOCKED;
-+#else /* SPINLOCK */
-+spinlock_t tdb_lock;
-+#endif /* SPINLOCK */
-+
-+/*
-+ * $Log: ipsec_xform.c,v $
-+ * Revision 1.63 2003/10/31 02:27:55 mcr
-+ * pulled up port-selector patches and sa_id elimination.
-+ *
-+ * Revision 1.62.30.1 2003/10/29 01:30:41 mcr
-+ * elimited "struct sa_id".
-+ *
-+ * Revision 1.62 2002/05/14 02:34:21 rgb
-+ * Delete stale code.
-+ *
-+ * Revision 1.61 2002/04/24 07:55:32 mcr
-+ * #include patches and Makefiles for post-reorg compilation.
-+ *
-+ * Revision 1.60 2002/04/24 07:36:33 mcr
-+ * Moved from ./klips/net/ipsec/ipsec_xform.c,v
-+ *
-+ * Revision 1.59 2002/03/29 15:01:36 rgb
-+ * Delete decommissioned code.
-+ *
-+ * Revision 1.58 2002/01/29 17:17:57 mcr
-+ * moved include of ipsec_param.h to after include of linux/kernel.h
-+ * otherwise, it seems that some option that is set in ipsec_param.h
-+ * screws up something subtle in the include path to kernel.h, and
-+ * it complains on the snprintf() prototype.
-+ *
-+ * Revision 1.57 2002/01/29 04:00:53 mcr
-+ * more excise of kversions.h header.
-+ *
-+ * Revision 1.56 2001/11/27 05:17:22 mcr
-+ * turn off the worst of the per-packet debugging.
-+ *
-+ * Revision 1.55 2001/11/26 09:23:50 rgb
-+ * Merge MCR's ipsec_sa, eroute, proc and struct lifetime changes.
-+ *
-+ * Revision 1.54 2001/10/18 04:45:21 rgb
-+ * 2.4.9 kernel deprecates linux/malloc.h in favour of linux/slab.h,
-+ * lib/freeswan.h version macros moved to lib/kversions.h.
-+ * Other compiler directive cleanups.
-+ *
-+ * Revision 1.53 2001/09/08 21:13:34 rgb
-+ * Added pfkey ident extension support for ISAKMPd. (NetCelo)
-+ *
-+ * Revision 1.52 2001/06/14 19:35:11 rgb
-+ * Update copyright date.
-+ *
-+ * Revision 1.51 2001/05/30 08:14:03 rgb
-+ * Removed vestiges of esp-null transforms.
-+ *
-+ * Revision 1.50 2001/05/03 19:43:18 rgb
-+ * Initialise error return variable.
-+ * Update SENDERR macro.
-+ * Fix sign of error return code for ipsec_tdbcleanup().
-+ * Use more appropriate return code for ipsec_tdbwipe().
-+ *
-+ * Revision 1.49 2001/04/19 18:56:17 rgb
-+ * Fixed tdb table locking comments.
-+ *
-+ * Revision 1.48 2001/02/27 22:24:55 rgb
-+ * Re-formatting debug output (line-splitting, joining, 1arg/line).
-+ * Check for satoa() return codes.
-+ *
-+ * Revision 1.47 2000/11/06 04:32:08 rgb
-+ * Ditched spin_lock_irqsave in favour of spin_lock_bh.
-+ *
-+ * Revision 1.46 2000/09/20 16:21:57 rgb
-+ * Cleaned up ident string alloc/free.
-+ *
-+ * Revision 1.45 2000/09/08 19:16:51 rgb
-+ * Change references from DEBUG_IPSEC to CONFIG_IPSEC_DEBUG.
-+ * Removed all references to CONFIG_IPSEC_PFKEYv2.
-+ *
-+ * Revision 1.44 2000/08/30 05:29:04 rgb
-+ * Compiler-define out no longer used tdb_init() in ipsec_xform.c.
-+ *
-+ * Revision 1.43 2000/08/18 21:30:41 rgb
-+ * Purged all tdb_spi, tdb_proto and tdb_dst macros. They are unclear.
-+ *
-+ * Revision 1.42 2000/08/01 14:51:51 rgb
-+ * Removed _all_ remaining traces of DES.
-+ *
-+ * Revision 1.41 2000/07/28 14:58:31 rgb
-+ * Changed kfree_s to kfree, eliminating extra arg to fix 2.4.0-test5.
-+ *
-+ * Revision 1.40 2000/06/28 05:50:11 rgb
-+ * Actually set iv_bits.
-+ *
-+ * Revision 1.39 2000/05/10 23:11:09 rgb
-+ * Added netlink debugging output.
-+ * Added a cast to quiet down the ntohl bug.
-+ *
-+ * Revision 1.38 2000/05/10 19:18:42 rgb
-+ * Cast output of ntohl so that the broken prototype doesn't make our
-+ * compile noisy.
-+ *
-+ * Revision 1.37 2000/03/16 14:04:59 rgb
-+ * Hardwired CONFIG_IPSEC_PFKEYv2 on.
-+ *
-+ * Revision 1.36 2000/01/26 10:11:28 rgb
-+ * Fixed spacing in error text causing run-in words.
-+ *
-+ * Revision 1.35 2000/01/21 06:17:16 rgb
-+ * Tidied up compiler directive indentation for readability.
-+ * Added ictx,octx vars for simplification.(kravietz)
-+ * Added macros for HMAC padding magic numbers.(kravietz)
-+ * Fixed missing key length reporting bug.
-+ * Fixed bug in tdbwipe to return immediately on NULL tdbp passed in.
-+ *
-+ * Revision 1.34 1999/12/08 00:04:19 rgb
-+ * Fixed SA direction overwriting bug for netlink users.
-+ *
-+ * Revision 1.33 1999/12/01 22:16:44 rgb
-+ * Minor formatting changes in ESP MD5 initialisation.
-+ *
-+ * Revision 1.32 1999/11/25 09:06:36 rgb
-+ * Fixed error return messages, should be returning negative numbers.
-+ * Implemented SENDERR macro for propagating error codes.
-+ * Added debug message and separate error code for algorithms not compiled
-+ * in.
-+ *
-+ * Revision 1.31 1999/11/23 23:06:26 rgb
-+ * Sort out pfkey and freeswan headers, putting them in a library path.
-+ *
-+ * Revision 1.30 1999/11/18 04:09:20 rgb
-+ * Replaced all kernel version macros to shorter, readable form.
-+ *
-+ * Revision 1.29 1999/11/17 15:53:40 rgb
-+ * Changed all occurrences of #include "../../../lib/freeswan.h"
-+ * to #include <freeswan.h> which works due to -Ilibfreeswan in the
-+ * klips/net/ipsec/Makefile.
-+ *
-+ * Revision 1.28 1999/10/18 20:04:01 rgb
-+ * Clean-out unused cruft.
-+ *
-+ * Revision 1.27 1999/10/03 19:01:03 rgb
-+ * Spinlock support for 2.3.xx and 2.0.xx kernels.
-+ *
-+ * Revision 1.26 1999/10/01 16:22:24 rgb
-+ * Switch from assignment init. to functional init. of spinlocks.
-+ *
-+ * Revision 1.25 1999/10/01 15:44:54 rgb
-+ * Move spinlock header include to 2.1> scope.
-+ *
-+ * Revision 1.24 1999/10/01 00:03:46 rgb
-+ * Added tdb structure locking.
-+ * Minor formatting changes.
-+ * Add function to initialize tdb hash table.
-+ *
-+ * Revision 1.23 1999/05/25 22:42:12 rgb
-+ * Add deltdbchain() debugging.
-+ *
-+ * Revision 1.22 1999/05/25 21:24:31 rgb
-+ * Add debugging statements to deltdbchain().
-+ *
-+ * Revision 1.21 1999/05/25 03:51:48 rgb
-+ * Refix error return code.
-+ *
-+ * Revision 1.20 1999/05/25 03:34:07 rgb
-+ * Fix error return for flush.
-+ *
-+ * Revision 1.19 1999/05/09 03:25:37 rgb
-+ * Fix bug introduced by 2.2 quick-and-dirty patch.
-+ *
-+ * Revision 1.18 1999/05/05 22:02:32 rgb
-+ * Add a quick and dirty port to 2.2 kernels by Marc Boucher <marc@mbsi.ca>.
-+ *
-+ * Revision 1.17 1999/04/29 15:20:16 rgb
-+ * Change gettdb parameter to a pointer to reduce stack loading and
-+ * facilitate parameter sanity checking.
-+ * Add sanity checking for null pointer arguments.
-+ * Add debugging instrumentation.
-+ * Add function deltdbchain() which will take care of unlinking,
-+ * zeroing and deleting a chain of tdbs.
-+ * Add a parameter to tdbcleanup to be able to delete a class of SAs.
-+ * tdbwipe now actually zeroes the tdb as well as any of its pointed
-+ * structures.
-+ *
-+ * Revision 1.16 1999/04/16 15:36:29 rgb
-+ * Fix cut-and-paste error causing a memory leak in IPIP TDB freeing.
-+ *
-+ * Revision 1.15 1999/04/11 00:29:01 henry
-+ * GPL boilerplate
-+ *
-+ * Revision 1.14 1999/04/06 04:54:28 rgb
-+ * Fix/Add RCSID Id: and Log: bits to make PHMDs happy. This includes
-+ * patch shell fixes.
-+ *
-+ * Revision 1.13 1999/02/19 18:23:01 rgb
-+ * Nix debug off compile warning.
-+ *
-+ * Revision 1.12 1999/02/17 16:52:16 rgb
-+ * Consolidate satoa()s for space and speed efficiency.
-+ * Convert DEBUG_IPSEC to KLIPS_PRINT
-+ * Clean out unused cruft.
-+ * Ditch NET_IPIP dependancy.
-+ * Loop for 3des key setting.
-+ *
-+ * Revision 1.11 1999/01/26 02:09:05 rgb
-+ * Remove ah/esp/IPIP switching on include files.
-+ * Removed CONFIG_IPSEC_ALGO_SWITCH macro.
-+ * Removed dead code.
-+ * Clean up debug code when switched off.
-+ * Remove references to INET_GET_PROTOCOL.
-+ * Added code exclusion macros to reduce code from unused algorithms.
-+ *
-+ * Revision 1.10 1999/01/22 06:28:55 rgb
-+ * Cruft clean-out.
-+ * Put random IV generation in kernel.
-+ * Added algorithm switch code.
-+ * Enhanced debugging.
-+ * 64-bit clean-up.
-+ *
-+ * Revision 1.9 1998/11/30 13:22:55 rgb
-+ * Rationalised all the klips kernel file headers. They are much shorter
-+ * now and won't conflict under RH5.2.
-+ *
-+ * Revision 1.8 1998/11/25 04:59:06 rgb
-+ * Add conditionals for no IPIP tunnel code.
-+ * Delete commented out code.
-+ *
-+ * Revision 1.7 1998/10/31 06:50:41 rgb
-+ * Convert xform ASCII names to no spaces.
-+ * Fixed up comments in #endif directives.
-+ *
-+ * Revision 1.6 1998/10/19 14:44:28 rgb
-+ * Added inclusion of freeswan.h.
-+ * sa_id structure implemented and used: now includes protocol.
-+ *
-+ * Revision 1.5 1998/10/09 04:32:19 rgb
-+ * Added 'klips_debug' prefix to all klips printk debug statements.
-+ *
-+ * Revision 1.4 1998/08/12 00:11:31 rgb
-+ * Added new xform functions to the xform table.
-+ * Fixed minor debug output spelling error.
-+ *
-+ * Revision 1.3 1998/07/09 17:45:31 rgb
-+ * Clarify algorithm not available message.
-+ *
-+ * Revision 1.2 1998/06/23 03:00:51 rgb
-+ * Check for presence of IPIP protocol if it is setup one way (we don't
-+ * know what has been set up the other way and can only assume it will be
-+ * symmetrical with the exception of keys).
-+ *
-+ * Revision 1.1 1998/06/18 21:27:51 henry
-+ * move sources from klips/src to klips/net/ipsec, to keep stupid
-+ * kernel-build scripts happier in the presence of symlinks
-+ *
-+ * Revision 1.3 1998/06/11 05:54:59 rgb
-+ * Added transform version string pointer to xformsw initialisations.
-+ *
-+ * Revision 1.2 1998/04/21 21:28:57 rgb
-+ * Rearrange debug switches to change on the fly debug output from user
-+ * space. Only kernel changes checked in at this time. radij.c was also
-+ * changed to temporarily remove buggy debugging code in rj_delete causing
-+ * an OOPS and hence, netlink device open errors.
-+ *
-+ * Revision 1.1 1998/04/09 03:06:13 henry
-+ * sources moved up from linux/net/ipsec
-+ *
-+ * Revision 1.1.1.1 1998/04/08 05:35:02 henry
-+ * RGB's ipsec-0.8pre2.tar.gz ipsec-0.8
-+ *
-+ * Revision 0.5 1997/06/03 04:24:48 ji
-+ * Added ESP-3DES-MD5-96
-+ *
-+ * Revision 0.4 1997/01/15 01:28:15 ji
-+ * Added new transforms.
-+ *
-+ * Revision 0.3 1996/11/20 14:39:04 ji
-+ * Minor cleanups.
-+ * Rationalized debugging code.
-+ *
-+ * Revision 0.2 1996/11/02 00:18:33 ji
-+ * First limited release.
-+ *
-+ *
-+ */
---- /dev/null Tue Mar 11 13:02:56 2003
-+++ linux/net/ipsec/ipsec_xmit.c Mon Feb 9 13:51:03 2004
-@@ -0,0 +1,1869 @@
-+/*
-+ * IPSEC Transmit code.
-+ * Copyright (C) 1996, 1997 John Ioannidis.
-+ * Copyright (C) 1998-2003 Richard Guy Briggs.
-+ * Copyright (C) 2004 Michael Richardson <mcr@xelerance.com>
-+ *
-+ * 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. See <http://www.fsf.org/copyleft/gpl.txt>.
-+ *
-+ * 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.
-+ */
-+
-+char ipsec_xmit_c_version[] = "RCSID $Id: ipsec_xmit.c,v 1.8 2004/04/06 02:49:26 mcr Exp $";
-+
-+#define __NO_VERSION__
-+#include <linux/module.h>
-+#include <linux/config.h> /* for CONFIG_IP_FORWARD */
-+#include <linux/version.h>
-+#include <linux/kernel.h> /* printk() */
-+
-+#include "openswan/ipsec_param.h"
-+
-+#ifdef MALLOC_SLAB
-+# include <linux/slab.h> /* kmalloc() */
-+#else /* MALLOC_SLAB */
-+# include <linux/malloc.h> /* kmalloc() */
-+#endif /* MALLOC_SLAB */
-+#include <linux/errno.h> /* error codes */
-+#include <linux/types.h> /* size_t */
-+#include <linux/interrupt.h> /* mark_bh */
-+
-+#include <linux/netdevice.h> /* struct device, struct net_device_stats, dev_queue_xmit() and other headers */
-+#include <linux/etherdevice.h> /* eth_type_trans */
-+#include <linux/ip.h> /* struct iphdr */
-+#include <linux/tcp.h> /* struct tcphdr */
-+#include <linux/udp.h> /* struct udphdr */
-+#include <linux/skbuff.h>
-+#include <openswan.h>
-+#ifdef NET_21
-+# define MSS_HACK_ /* experimental */
-+# include <asm/uaccess.h>
-+# include <linux/in6.h>
-+# include <net/dst.h>
-+# define proto_priv cb
-+#endif /* NET_21 */
-+#include <asm/checksum.h>
-+#include <net/icmp.h> /* icmp_send() */
-+#include <net/ip.h>
-+#ifdef NETDEV_23
-+# include <linux/netfilter_ipv4.h>
-+#endif /* NETDEV_23 */
-+
-+#include <linux/if_arp.h>
-+#ifdef MSS_HACK
-+# include <net/tcp.h> /* TCP options */
-+#endif /* MSS_HACK */
-+
-+#include "openswan/radij.h"
-+#include "openswan/ipsec_life.h"
-+#include "openswan/ipsec_xform.h"
-+#include "openswan/ipsec_eroute.h"
-+#include "openswan/ipsec_encap.h"
-+#include "openswan/ipsec_radij.h"
-+#include "openswan/ipsec_xmit.h"
-+#include "openswan/ipsec_sa.h"
-+#include "openswan/ipsec_tunnel.h"
-+#include "openswan/ipsec_ipe4.h"
-+#include "openswan/ipsec_ah.h"
-+#include "openswan/ipsec_esp.h"
-+
-+#ifdef CONFIG_IPSEC_IPCOMP
-+#include "openswan/ipcomp.h"
-+#endif /* CONFIG_IPSEC_IPCOMP */
-+
-+#include <pfkeyv2.h>
-+#include <pfkey.h>
-+
-+#include "openswan/ipsec_proto.h"
-+#include "openswan/ipsec_alg.h"
-+
-+
-+/*
-+ * Stupid kernel API differences in APIs. Not only do some
-+ * kernels not have ip_select_ident, but some have differing APIs,
-+ * and SuSE has one with one parameter, but no way of checking to
-+ * see what is really what.
-+ */
-+
-+#ifdef SUSE_LINUX_2_4_19_IS_STUPID
-+#define KLIPS_IP_SELECT_IDENT(iph, skb) ip_select_ident(iph)
-+#else
-+
-+/* simplest case, nothing */
-+#if !defined(IP_SELECT_IDENT)
-+#define KLIPS_IP_SELECT_IDENT(iph, skb) do { iph->id = htons(ip_id_count++); } while(0)
-+#endif
-+
-+/* kernels > 2.3.37-ish */
-+#if defined(IP_SELECT_IDENT) && !defined(IP_SELECT_IDENT_NEW)
-+#define KLIPS_IP_SELECT_IDENT(iph, skb) ip_select_ident(iph, skb->dst)
-+#endif
-+
-+/* kernels > 2.4.2 */
-+#if defined(IP_SELECT_IDENT) && defined(IP_SELECT_IDENT_NEW)
-+#define KLIPS_IP_SELECT_IDENT(iph, skb) ip_select_ident(iph, skb->dst, NULL)
-+#endif
-+
-+#endif /* SUSE_LINUX_2_4_19_IS_STUPID */
-+
-+
-+static __u32 zeroes[64];
-+
-+#ifdef CONFIG_IPSEC_DEBUG
-+int sysctl_ipsec_debug_verbose = 0;
-+#endif /* CONFIG_IPSEC_DEBUG */
-+
-+int ipsec_xmit_trap_count = 0;
-+int ipsec_xmit_trap_sendcount = 0;
-+
-+int sysctl_ipsec_icmp = 0;
-+int sysctl_ipsec_tos = 0;
-+
-+#ifdef CONFIG_IPSEC_DEBUG_
-+DEBUG_NO_STATIC void
-+dmp(char *s, caddr_t bb, int len)
-+{
-+ int i;
-+ unsigned char *b = bb;
-+
-+ if (debug_tunnel) {
-+ printk(KERN_INFO "klips_debug:ipsec_tunnel_:dmp: "
-+ "at %s, len=%d:",
-+ s,
-+ len);
-+ for (i=0; i < len; i++) {
-+ if(!(i%16)){
-+ printk("\nklips_debug: ");
-+ }
-+ printk(" %02x", *b++);
-+ }
-+ printk("\n");
-+ }
-+}
-+#else /* CONFIG_IPSEC_DEBUG */
-+#define dmp(_x, _y, _z)
-+#endif /* CONFIG_IPSEC_DEBUG */
-+
-+#ifndef SKB_COPY_EXPAND
-+/*
-+ * This is mostly skbuff.c:skb_copy().
-+ */
-+struct sk_buff *
-+skb_copy_expand(struct sk_buff *skb, int headroom, int tailroom, int priority)
-+{
-+ struct sk_buff *n;
-+ unsigned long offset;
-+
-+ /*
-+ * Do sanity checking
-+ */
-+ if((headroom < 0) || (tailroom < 0) || ((headroom+tailroom) < 0)) {
-+ printk(KERN_WARNING
-+ "klips_error:skb_copy_expand: "
-+ "Illegal negative head,tailroom %d,%d\n",
-+ headroom,
-+ tailroom);
-+ return NULL;
-+ }
-+ /*
-+ * Allocate the copy buffer
-+ */
-+
-+#ifndef NET_21
-+ IS_SKB(skb);
-+#endif /* !NET_21 */
-+
-+
-+ n=alloc_skb(skb->end - skb->head + headroom + tailroom, priority);
-+
-+ KLIPS_PRINT(debug_tunnel & DB_TN_CROUT,
-+ "klips_debug:skb_copy_expand: "
-+ "allocating %d bytes, head=0p%p data=0p%p tail=0p%p end=0p%p end-head=%d tail-data=%d\n",
-+ skb->end - skb->head + headroom + tailroom,
-+ skb->head,
-+ skb->data,
-+ skb->tail,
-+ skb->end,
-+ skb->end - skb->head,
-+ skb->tail - skb->data);
-+
-+ if(n==NULL)
-+ return NULL;
-+
-+ /*
-+ * Shift between the two data areas in bytes
-+ */
-+
-+ /* Set the data pointer */
-+ skb_reserve(n,skb->data-skb->head+headroom);
-+ /* Set the tail pointer and length */
-+ if(skb_tailroom(n) < skb->len) {
-+ printk(KERN_WARNING "klips_error:skb_copy_expand: "
-+ "tried to skb_put %ld, %d available. This should never happen, please report.\n",
-+ (unsigned long int)skb->len,
-+ skb_tailroom(n));
-+ ipsec_kfree_skb(n);
-+ return NULL;
-+ }
-+ skb_put(n,skb->len);
-+
-+ offset=n->head + headroom - skb->head;
-+
-+ /* Copy the bytes */
-+ memcpy(n->head + headroom, skb->head,skb->end-skb->head);
-+#ifdef NET_21
-+ n->csum=skb->csum;
-+ n->priority=skb->priority;
-+ n->dst=dst_clone(skb->dst);
-+ if(skb->nh.raw)
-+ n->nh.raw=skb->nh.raw+offset;
-+#ifndef NETDEV_23
-+ n->is_clone=0;
-+#endif /* NETDEV_23 */
-+ atomic_set(&n->users, 1);
-+ n->destructor = NULL;
-+ n->security=skb->security;
-+#else /* NET_21 */
-+ n->link3=NULL;
-+ n->when=skb->when;
-+ if(skb->ip_hdr)
-+ n->ip_hdr=(struct iphdr *)(((char *)skb->ip_hdr)+offset);
-+ n->saddr=skb->saddr;
-+ n->daddr=skb->daddr;
-+ n->raddr=skb->raddr;
-+ n->seq=skb->seq;
-+ n->end_seq=skb->end_seq;
-+ n->ack_seq=skb->ack_seq;
-+ n->acked=skb->acked;
-+ n->free=1;
-+ n->arp=skb->arp;
-+ n->tries=0;
-+ n->lock=0;
-+ n->users=0;
-+#endif /* NET_21 */
-+ n->protocol=skb->protocol;
-+ n->list=NULL;
-+ n->sk=NULL;
-+ n->dev=skb->dev;
-+ if(skb->h.raw)
-+ n->h.raw=skb->h.raw+offset;
-+ if(skb->mac.raw)
-+ n->mac.raw=skb->mac.raw+offset;
-+ memcpy(n->proto_priv, skb->proto_priv, sizeof(skb->proto_priv));
-+#ifndef NETDEV_23
-+ n->used=skb->used;
-+#endif /* !NETDEV_23 */
-+ n->pkt_type=skb->pkt_type;
-+ n->stamp=skb->stamp;
-+
-+#ifndef NET_21
-+ IS_SKB(n);
-+#endif /* !NET_21 */
-+ return n;
-+}
-+#endif /* !SKB_COPY_EXPAND */
-+
-+#ifdef CONFIG_IPSEC_DEBUG
-+void
-+ipsec_print_ip(struct iphdr *ip)
-+{
-+ char buf[ADDRTOA_BUF];
-+
-+ printk(KERN_INFO "klips_debug: IP:");
-+ printk(" ihl:%d", ip->ihl << 2);
-+ printk(" ver:%d", ip->version);
-+ printk(" tos:%d", ip->tos);
-+ printk(" tlen:%d", ntohs(ip->tot_len));
-+ printk(" id:%d", ntohs(ip->id));
-+ printk(" %s%s%sfrag_off:%d",
-+ ip->frag_off & __constant_htons(IP_CE) ? "CE " : "",
-+ ip->frag_off & __constant_htons(IP_DF) ? "DF " : "",
-+ ip->frag_off & __constant_htons(IP_MF) ? "MF " : "",
-+ (ntohs(ip->frag_off) & IP_OFFSET) << 3);
-+ printk(" ttl:%d", ip->ttl);
-+ printk(" proto:%d", ip->protocol);
-+ if(ip->protocol == IPPROTO_UDP)
-+ printk(" (UDP)");
-+ if(ip->protocol == IPPROTO_TCP)
-+ printk(" (TCP)");
-+ if(ip->protocol == IPPROTO_ICMP)
-+ printk(" (ICMP)");
-+ printk(" chk:%d", ntohs(ip->check));
-+ addrtoa(*((struct in_addr*)(&ip->saddr)), 0, buf, sizeof(buf));
-+ printk(" saddr:%s", buf);
-+ if(ip->protocol == IPPROTO_UDP)
-+ printk(":%d",
-+ ntohs(((struct udphdr*)((caddr_t)ip + (ip->ihl << 2)))->source));
-+ if(ip->protocol == IPPROTO_TCP)
-+ printk(":%d",
-+ ntohs(((struct tcphdr*)((caddr_t)ip + (ip->ihl << 2)))->source));
-+ addrtoa(*((struct in_addr*)(&ip->daddr)), 0, buf, sizeof(buf));
-+ printk(" daddr:%s", buf);
-+ if(ip->protocol == IPPROTO_UDP)
-+ printk(":%d",
-+ ntohs(((struct udphdr*)((caddr_t)ip + (ip->ihl << 2)))->dest));
-+ if(ip->protocol == IPPROTO_TCP)
-+ printk(":%d",
-+ ntohs(((struct tcphdr*)((caddr_t)ip + (ip->ihl << 2)))->dest));
-+ if(ip->protocol == IPPROTO_ICMP)
-+ printk(" type:code=%d:%d",
-+ ((struct icmphdr*)((caddr_t)ip + (ip->ihl << 2)))->type,
-+ ((struct icmphdr*)((caddr_t)ip + (ip->ihl << 2)))->code);
-+ printk("\n");
-+
-+ if(sysctl_ipsec_debug_verbose) {
-+ __u8 *c;
-+ int i;
-+
-+ c = ((__u8*)ip) + ip->ihl*4;
-+ for(i = 0; i < ntohs(ip->tot_len) - ip->ihl*4; i++ /*, c++*/) {
-+ if(!(i % 16)) {
-+ printk(KERN_INFO
-+ "klips_debug: @%03x:",
-+ i);
-+ }
-+ printk(" %02x", /***/c[i]);
-+ if(!((i + 1) % 16)) {
-+ printk("\n");
-+ }
-+ }
-+ if(i % 16) {
-+ printk("\n");
-+ }
-+ }
-+}
-+#endif /* CONFIG_IPSEC_DEBUG */
-+
-+#ifdef MSS_HACK
-+/*
-+ * Issues:
-+ * 1) Fragments arriving in the tunnel should probably be rejected.
-+ * 2) How does this affect syncookies, mss_cache, dst cache ?
-+ * 3) Path MTU discovery handling needs to be reviewed. For example,
-+ * if we receive an ICMP 'packet too big' message from an intermediate
-+ * router specifying it's next hop MTU, our stack may process this and
-+ * adjust the MSS without taking our AH/ESP overheads into account.
-+ */
-+
-+
-+/*
-+ * Recaclulate checksum using differences between changed datum,
-+ * borrowed from netfilter.
-+ */
-+DEBUG_NO_STATIC u_int16_t
-+ipsec_fast_csum(u_int32_t oldvalinv, u_int32_t newval, u_int16_t oldcheck)
-+{
-+ u_int32_t diffs[] = { oldvalinv, newval };
-+ return csum_fold(csum_partial((char *)diffs, sizeof(diffs),
-+ oldcheck^0xFFFF));
-+}
-+
-+/*
-+ * Determine effective MSS.
-+ *
-+ * Note that we assume that there is always an MSS option for our own
-+ * SYN segments, which is mentioned in tcp_syn_build_options(), kernel 2.2.x.
-+ * This could change, and we should probably parse TCP options instead.
-+ *
-+ */
-+DEBUG_NO_STATIC u_int8_t
-+ipsec_adjust_mss(struct sk_buff *skb, struct tcphdr *tcph, u_int16_t mtu)
-+{
-+ u_int16_t oldmss, newmss;
-+ u_int32_t *mssp;
-+ struct sock *sk = skb->sk;
-+
-+ newmss = tcp_sync_mss(sk, mtu);
-+ printk(KERN_INFO "klips: setting mss to %u\n", newmss);
-+ mssp = (u_int32_t *)tcph + sizeof(struct tcphdr) / sizeof(u_int32_t);
-+ oldmss = ntohl(*mssp) & 0x0000FFFF;
-+ *mssp = htonl((TCPOPT_MSS << 24) | (TCPOLEN_MSS << 16) | newmss);
-+ tcph->check = ipsec_fast_csum(htons(~oldmss),
-+ htons(newmss), tcph->check);
-+ return 1;
-+}
-+#endif /* MSS_HACK */
-+
-+/*
-+ * Sanity checks
-+ */
-+enum ipsec_xmit_value
-+ipsec_xmit_sanity_check_dev(struct ipsec_xmit_state *ixs)
-+{
-+
-+ if (ixs->dev == NULL) {
-+ KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
-+ "klips_error:ipsec_xmit_sanity_check_dev: "
-+ "No device associated with skb!\n" );
-+ return IPSEC_XMIT_NODEV;
-+ }
-+
-+ ixs->prv = ixs->dev->priv;
-+ if (ixs->prv == NULL) {
-+ KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
-+ "klips_error:ipsec_xmit_sanity_check_dev: "
-+ "Device has no private structure!\n" );
-+ return IPSEC_XMIT_NOPRIVDEV;
-+ }
-+
-+ ixs->physdev = ixs->prv->dev;
-+ if (ixs->physdev == NULL) {
-+ KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
-+ "klips_error:ipsec_xmit_sanity_check_dev: "
-+ "Device is not attached to physical device!\n" );
-+ return IPSEC_XMIT_NOPHYSDEV;
-+ }
-+
-+ ixs->physmtu = ixs->physdev->mtu;
-+
-+ ixs->stats = (struct net_device_stats *) &(ixs->prv->mystats);
-+
-+ return IPSEC_XMIT_OK;
-+}
-+
-+enum ipsec_xmit_value
-+ipsec_xmit_sanity_check_skb(struct ipsec_xmit_state *ixs)
-+{
-+ /*
-+ * Return if there is nothing to do. (Does this ever happen?) XXX
-+ */
-+ if (ixs->skb == NULL) {
-+ KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
-+ "klips_error:ipsec_xmit_sanity_check_skb: "
-+ "Nothing to do!\n" );
-+ return IPSEC_XMIT_NOSKB;
-+ }
-+#ifdef NET_21
-+ /* if skb was cloned (most likely due to a packet sniffer such as
-+ tcpdump being momentarily attached to the interface), make
-+ a copy of our own to modify */
-+ if(skb_cloned(ixs->skb)) {
-+ if
-+#ifdef SKB_COW_NEW
-+ (skb_cow(ixs->skb, skb_headroom(ixs->skb)) != 0)
-+#else /* SKB_COW_NEW */
-+ ((ixs->skb = skb_cow(ixs->skb, skb_headroom(ixs->skb))) == NULL)
-+#endif /* SKB_COW_NEW */
-+ {
-+ KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
-+ "klips_error:ipsec_xmit_sanity_check_skb: "
-+ "skb_cow failed to allocate buffer, dropping.\n" );
-+ ixs->stats->tx_dropped++;
-+ return IPSEC_XMIT_ERRSKBALLOC;
-+ }
-+ }
-+#endif /* NET_21 */
-+
-+#ifdef NET_21
-+ ixs->iph = ixs->skb->nh.iph;
-+#else /* NET_21 */
-+ ixs->iph = ixs->skb->ip_hdr;
-+#endif /* NET_21 */
-+
-+ /* sanity check for IP version as we can't handle IPv6 right now */
-+ if (ixs->iph->version != 4) {
-+ KLIPS_PRINT(debug_tunnel,
-+ "klips_debug:ipsec_xmit_sanity_check_skb: "
-+ "found IP Version %d but cannot process other IP versions than v4.\n",
-+ ixs->iph->version); /* XXX */
-+ ixs->stats->tx_dropped++;
-+ return IPSEC_XMIT_NOIPV6;
-+ }
-+
-+#if IPSEC_DISALLOW_IPOPTIONS
-+ if ((ixs->iph->ihl << 2) != sizeof (struct iphdr)) {
-+ KLIPS_PRINT(debug_tunnel,
-+ "klips_debug:ipsec_xmit_sanity_check_skb: "
-+ "cannot process IP header options yet. May be mal-formed packet.\n"); /* XXX */
-+ ixs->stats->tx_dropped++;
-+ return IPSEC_XMIT_NOIPOPTIONS;
-+ }
-+#endif /* IPSEC_DISALLOW_IPOPTIONS */
-+
-+#ifndef NET_21
-+ if (ixs->iph->ttl <= 0) {
-+ /* Tell the sender its packet died... */
-+ ICMP_SEND(ixs->skb, ICMP_TIME_EXCEEDED, ICMP_EXC_TTL, 0, ixs->physdev);
-+
-+ KLIPS_PRINT(debug_tunnel, "klips_debug:ipsec_xmit_sanity_check_skb: "
-+ "TTL=0, too many hops!\n");
-+ ixs->stats->tx_dropped++;
-+ return IPSEC_XMIT_TTLEXPIRED;
-+ }
-+#endif /* !NET_21 */
-+
-+ return IPSEC_XMIT_OK;
-+}
-+
-+enum ipsec_xmit_value
-+ipsec_xmit_encap_once(struct ipsec_xmit_state *ixs)
-+{
-+#ifdef CONFIG_IPSEC_ESP
-+ struct esphdr *espp;
-+#ifdef CONFIG_IPSEC_ENC_3DES
-+ __u32 iv[ESP_IV_MAXSZ_INT];
-+#endif /* !CONFIG_IPSEC_ENC_3DES */
-+ unsigned char *idat, *pad;
-+ int authlen = 0, padlen = 0, i;
-+#endif /* !CONFIG_IPSEC_ESP */
-+#ifdef CONFIG_IPSEC_AH
-+ struct iphdr ipo;
-+ struct ahhdr *ahp;
-+#endif /* CONFIG_IPSEC_AH */
-+#if defined(CONFIG_IPSEC_AUTH_HMAC_MD5) || defined(CONFIG_IPSEC_AUTH_HMAC_SHA1)
-+ union {
-+#ifdef CONFIG_IPSEC_AUTH_HMAC_MD5
-+ MD5_CTX md5;
-+#endif /* CONFIG_IPSEC_AUTH_HMAC_MD5 */
-+#ifdef CONFIG_IPSEC_AUTH_HMAC_SHA1
-+ SHA1_CTX sha1;
-+#endif /* CONFIG_IPSEC_AUTH_HMAC_SHA1 */
-+ } tctx;
-+ __u8 hash[AH_AMAX];
-+#endif /* defined(CONFIG_IPSEC_AUTH_HMAC_MD5) || defined(CONFIG_IPSEC_AUTH_HMAC_SHA1) */
-+ int headroom = 0, tailroom = 0, ilen = 0, len = 0;
-+ unsigned char *dat;
-+ int blocksize = 8; /* XXX: should be inside ixs --jjo */
-+#ifdef CONFIG_IPSEC_ALG
-+ struct ipsec_alg_enc *ixt_e = NULL;
-+ struct ipsec_alg_auth *ixt_a = NULL;
-+#endif /* CONFIG_IPSEC_ALG */
-+
-+ ixs->iphlen = ixs->iph->ihl << 2;
-+ ixs->pyldsz = ntohs(ixs->iph->tot_len) - ixs->iphlen;
-+ ixs->sa_len = satot(&ixs->ipsp->ips_said, 0, ixs->sa_txt, SATOT_BUF);
-+ KLIPS_PRINT(debug_tunnel & DB_TN_OXFS,
-+ "klips_debug:ipsec_xmit_encap_once: "
-+ "calling output for <%s%s%s>, SA:%s\n",
-+ IPS_XFORM_NAME(ixs->ipsp),
-+ ixs->sa_len ? ixs->sa_txt : " (error)");
-+
-+ switch(ixs->ipsp->ips_said.proto) {
-+#ifdef CONFIG_IPSEC_AH
-+ case IPPROTO_AH:
-+ headroom += sizeof(struct ahhdr);
-+ break;
-+#endif /* CONFIG_IPSEC_AH */
-+#ifdef CONFIG_IPSEC_ESP
-+ case IPPROTO_ESP:
-+#ifdef CONFIG_IPSEC_ALG
-+ if ((ixt_e=ixs->ipsp->ips_alg_enc)) {
-+ blocksize = ixt_e->ixt_blocksize;
-+ headroom += ESP_HEADER_LEN + ixt_e->ixt_ivlen/8;
-+ } else
-+#endif /* CONFIG_IPSEC_ALG */
-+ switch(ixs->ipsp->ips_encalg) {
-+#ifdef CONFIG_IPSEC_ENC_3DES
-+ case ESP_3DES:
-+ headroom += sizeof(struct esphdr);
-+ break;
-+#endif /* CONFIG_IPSEC_ENC_3DES */
-+ default:
-+ ixs->stats->tx_errors++;
-+ return IPSEC_XMIT_ESP_BADALG;
-+ }
-+#ifdef CONFIG_IPSEC_ALG
-+ if ((ixt_a=ixs->ipsp->ips_alg_auth)) {
-+ tailroom += AHHMAC_HASHLEN;
-+ } else
-+#endif /* CONFIG_IPSEC_ALG */
-+ switch(ixs->ipsp->ips_authalg) {
-+#ifdef CONFIG_IPSEC_AUTH_HMAC_MD5
-+ case AH_MD5:
-+ authlen = AHHMAC_HASHLEN;
-+ break;
-+#endif /* CONFIG_IPSEC_AUTH_HMAC_MD5 */
-+#ifdef CONFIG_IPSEC_AUTH_HMAC_SHA1
-+ case AH_SHA:
-+ authlen = AHHMAC_HASHLEN;
-+ break;
-+#endif /* CONFIG_IPSEC_AUTH_HMAC_SHA1 */
-+ case AH_NONE:
-+ break;
-+ default:
-+ ixs->stats->tx_errors++;
-+ return IPSEC_XMIT_ESP_BADALG;
-+ }
-+#ifdef CONFIG_IPSEC_ALG
-+ tailroom += blocksize != 1 ?
-+ ((blocksize - ((ixs->pyldsz + 2) % blocksize)) % blocksize) + 2 :
-+ ((4 - ((ixs->pyldsz + 2) % 4)) % 4) + 2;
-+#else
-+ tailroom += ((8 - ((ixs->pyldsz + 2 * sizeof(unsigned char)) % 8)) % 8) + 2;
-+#endif /* CONFIG_IPSEC_ALG */
-+ tailroom += authlen;
-+ break;
-+#endif /* !CONFIG_IPSEC_ESP */
-+#ifdef CONFIG_IPSEC_IPIP
-+ case IPPROTO_IPIP:
-+ headroom += sizeof(struct iphdr);
-+ ixs->iphlen = sizeof(struct iphdr);
-+ break;
-+#endif /* !CONFIG_IPSEC_IPIP */
-+#ifdef CONFIG_IPSEC_IPCOMP
-+ case IPPROTO_COMP:
-+ break;
-+#endif /* CONFIG_IPSEC_IPCOMP */
-+ default:
-+ ixs->stats->tx_errors++;
-+ return IPSEC_XMIT_BADPROTO;
-+ }
-+
-+ KLIPS_PRINT(debug_tunnel & DB_TN_CROUT,
-+ "klips_debug:ipsec_xmit_encap_once: "
-+ "pushing %d bytes, putting %d, proto %d.\n",
-+ headroom, tailroom, ixs->ipsp->ips_said.proto);
-+ if(skb_headroom(ixs->skb) < headroom) {
-+ printk(KERN_WARNING
-+ "klips_error:ipsec_xmit_encap_once: "
-+ "tried to skb_push headroom=%d, %d available. This should never happen, please report.\n",
-+ headroom, skb_headroom(ixs->skb));
-+ ixs->stats->tx_errors++;
-+ return IPSEC_XMIT_ESP_PUSHPULLERR;
-+ }
-+ dat = skb_push(ixs->skb, headroom);
-+ ilen = ixs->skb->len - tailroom;
-+ if(skb_tailroom(ixs->skb) < tailroom) {
-+ printk(KERN_WARNING
-+ "klips_error:ipsec_xmit_encap_once: "
-+ "tried to skb_put %d, %d available. This should never happen, please report.\n",
-+ tailroom, skb_tailroom(ixs->skb));
-+ ixs->stats->tx_errors++;
-+ return IPSEC_XMIT_ESP_PUSHPULLERR;
-+ }
-+ skb_put(ixs->skb, tailroom);
-+ KLIPS_PRINT(debug_tunnel & DB_TN_CROUT,
-+ "klips_debug:ipsec_xmit_encap_once: "
-+ "head,tailroom: %d,%d before xform.\n",
-+ skb_headroom(ixs->skb), skb_tailroom(ixs->skb));
-+ len = ixs->skb->len;
-+ if(len > 0xfff0) {
-+ printk(KERN_WARNING "klips_error:ipsec_xmit_encap_once: "
-+ "tot_len (%d) > 65520. This should never happen, please report.\n",
-+ len);
-+ ixs->stats->tx_errors++;
-+ return IPSEC_XMIT_BADLEN;
-+ }
-+ memmove((void *)dat, (void *)(dat + headroom), ixs->iphlen);
-+ ixs->iph = (struct iphdr *)dat;
-+ ixs->iph->tot_len = htons(ixs->skb->len);
-+
-+ switch(ixs->ipsp->ips_said.proto) {
-+#ifdef CONFIG_IPSEC_ESP
-+ case IPPROTO_ESP:
-+ espp = (struct esphdr *)(dat + ixs->iphlen);
-+ espp->esp_spi = ixs->ipsp->ips_said.spi;
-+ espp->esp_rpl = htonl(++(ixs->ipsp->ips_replaywin_lastseq));
-+
-+#ifdef CONFIG_IPSEC_ALG
-+ if (!ixt_e)
-+#endif /* CONFIG_IPSEC_ALG */
-+ switch(ixs->ipsp->ips_encalg) {
-+#if defined(CONFIG_IPSEC_ENC_3DES)
-+#ifdef CONFIG_IPSEC_ENC_3DES
-+ case ESP_3DES:
-+#endif /* CONFIG_IPSEC_ENC_3DES */
-+ iv[0] = *((__u32*)&(espp->esp_iv) ) =
-+ ((__u32*)(ixs->ipsp->ips_iv))[0];
-+ iv[1] = *((__u32*)&(espp->esp_iv) + 1) =
-+ ((__u32*)(ixs->ipsp->ips_iv))[1];
-+ break;
-+#endif /* defined(CONFIG_IPSEC_ENC_3DES) */
-+ default:
-+ ixs->stats->tx_errors++;
-+ return IPSEC_XMIT_ESP_BADALG;
-+ }
-+
-+ idat = dat + ixs->iphlen + headroom;
-+ ilen = len - (ixs->iphlen + headroom + authlen);
-+
-+ /* Self-describing padding */
-+ pad = &dat[len - tailroom];
-+ padlen = tailroom - 2 - authlen;
-+ for (i = 0; i < padlen; i++) {
-+ pad[i] = i + 1;
-+ }
-+ dat[len - authlen - 2] = padlen;
-+
-+ dat[len - authlen - 1] = ixs->iph->protocol;
-+ ixs->iph->protocol = IPPROTO_ESP;
-+
-+#ifdef CONFIG_IPSEC_ALG
-+ /* Do all operations here:
-+ * copy IV->ESP, encrypt, update ips IV
-+ */
-+ if (ixt_e) {
-+ int ret;
-+ memcpy(espp->esp_iv,
-+ ixs->ipsp->ips_iv,
-+ ixt_e->ixt_ivlen/8);
-+ ret=ipsec_alg_esp_encrypt(ixs->ipsp,
-+ idat, ilen, espp->esp_iv,
-+ IPSEC_ALG_ENCRYPT);
-+ memcpy(ixs->ipsp->ips_iv,
-+ idat + ilen - ixt_e->ixt_ivlen/8,
-+ ixt_e->ixt_ivlen/8);
-+ } else
-+#endif /* CONFIG_IPSEC_ALG */
-+ switch(ixs->ipsp->ips_encalg) {
-+#ifdef CONFIG_IPSEC_ENC_3DES
-+ case ESP_3DES:
-+ des_ede3_cbc_encrypt((des_cblock *)idat,
-+ (des_cblock *)idat,
-+ ilen,
-+ ((struct des_eks *)(ixs->ipsp->ips_key_e))[0].ks,
-+ ((struct des_eks *)(ixs->ipsp->ips_key_e))[1].ks,
-+ ((struct des_eks *)(ixs->ipsp->ips_key_e))[2].ks,
-+ (des_cblock *)iv, 1);
-+ break;
-+#endif /* CONFIG_IPSEC_ENC_3DES */
-+ default:
-+ ixs->stats->tx_errors++;
-+ return IPSEC_XMIT_ESP_BADALG;
-+ }
-+
-+#ifdef CONFIG_IPSEC_ALG
-+ if (!ixt_e)
-+#endif /* CONFIG_IPSEC_ALG */
-+ switch(ixs->ipsp->ips_encalg) {
-+#if defined(CONFIG_IPSEC_ENC_3DES)
-+#ifdef CONFIG_IPSEC_ENC_3DES
-+ case ESP_3DES:
-+#endif /* CONFIG_IPSEC_ENC_3DES */
-+ /* XXX update IV with the last 8 octets of the encryption */
-+#if KLIPS_IMPAIRMENT_ESPIV_CBC_ATTACK
-+ ((__u32*)(ixs->ipsp->ips_iv))[0] =
-+ ((__u32 *)(idat))[(ilen >> 2) - 2];
-+ ((__u32*)(ixs->ipsp->ips_iv))[1] =
-+ ((__u32 *)(idat))[(ilen >> 2) - 1];
-+#else /* KLIPS_IMPAIRMENT_ESPIV_CBC_ATTACK */
-+ prng_bytes(&ipsec_prng, (char *)ixs->ipsp->ips_iv, EMT_ESPDES_IV_SZ);
-+#endif /* KLIPS_IMPAIRMENT_ESPIV_CBC_ATTACK */
-+ break;
-+#endif /* defined(CONFIG_IPSEC_ENC_3DES) */
-+ default:
-+ ixs->stats->tx_errors++;
-+ return IPSEC_XMIT_ESP_BADALG;
-+ }
-+
-+#ifdef CONFIG_IPSEC_ALG
-+ if (ixt_a) {
-+ ipsec_alg_sa_esp_hash(ixs->ipsp,
-+ (caddr_t)espp, len - ixs->iphlen - authlen,
-+ &(dat[len - authlen]), authlen);
-+
-+ } else
-+#endif /* CONFIG_IPSEC_ALG */
-+ switch(ixs->ipsp->ips_authalg) {
-+#ifdef CONFIG_IPSEC_AUTH_HMAC_MD5
-+ case AH_MD5:
-+ dmp("espp", (char*)espp, len - ixs->iphlen - authlen);
-+ tctx.md5 = ((struct md5_ctx*)(ixs->ipsp->ips_key_a))->ictx;
-+ dmp("ictx", (char*)&tctx.md5, sizeof(tctx.md5));
-+ MD5Update(&tctx.md5, (caddr_t)espp, len - ixs->iphlen - authlen);
-+ dmp("ictx+dat", (char*)&tctx.md5, sizeof(tctx.md5));
-+ MD5Final(hash, &tctx.md5);
-+ dmp("ictx hash", (char*)&hash, sizeof(hash));
-+ tctx.md5 = ((struct md5_ctx*)(ixs->ipsp->ips_key_a))->octx;
-+ dmp("octx", (char*)&tctx.md5, sizeof(tctx.md5));
-+ MD5Update(&tctx.md5, hash, AHMD596_ALEN);
-+ dmp("octx+hash", (char*)&tctx.md5, sizeof(tctx.md5));
-+ MD5Final(hash, &tctx.md5);
-+ dmp("octx hash", (char*)&hash, sizeof(hash));
-+ memcpy(&(dat[len - authlen]), hash, authlen);
-+
-+ /* paranoid */
-+ memset((caddr_t)&tctx.md5, 0, sizeof(tctx.md5));
-+ memset((caddr_t)hash, 0, sizeof(*hash));
-+ break;
-+#endif /* CONFIG_IPSEC_AUTH_HMAC_MD5 */
-+#ifdef CONFIG_IPSEC_AUTH_HMAC_SHA1
-+ case AH_SHA:
-+ tctx.sha1 = ((struct sha1_ctx*)(ixs->ipsp->ips_key_a))->ictx;
-+ SHA1Update(&tctx.sha1, (caddr_t)espp, len - ixs->iphlen - authlen);
-+ SHA1Final(hash, &tctx.sha1);
-+ tctx.sha1 = ((struct sha1_ctx*)(ixs->ipsp->ips_key_a))->octx;
-+ SHA1Update(&tctx.sha1, hash, AHSHA196_ALEN);
-+ SHA1Final(hash, &tctx.sha1);
-+ memcpy(&(dat[len - authlen]), hash, authlen);
-+
-+ /* paranoid */
-+ memset((caddr_t)&tctx.sha1, 0, sizeof(tctx.sha1));
-+ memset((caddr_t)hash, 0, sizeof(*hash));
-+ break;
-+#endif /* CONFIG_IPSEC_AUTH_HMAC_SHA1 */
-+ case AH_NONE:
-+ break;
-+ default:
-+ ixs->stats->tx_errors++;
-+ return IPSEC_XMIT_AH_BADALG;
-+ }
-+#ifdef NET_21
-+ ixs->skb->h.raw = (unsigned char*)espp;
-+#endif /* NET_21 */
-+ break;
-+#endif /* !CONFIG_IPSEC_ESP */
-+#ifdef CONFIG_IPSEC_AH
-+ case IPPROTO_AH:
-+ ahp = (struct ahhdr *)(dat + ixs->iphlen);
-+ ahp->ah_spi = ixs->ipsp->ips_said.spi;
-+ ahp->ah_rpl = htonl(++(ixs->ipsp->ips_replaywin_lastseq));
-+ ahp->ah_rv = 0;
-+ ahp->ah_nh = ixs->iph->protocol;
-+ ahp->ah_hl = (headroom >> 2) - sizeof(__u64)/sizeof(__u32);
-+ ixs->iph->protocol = IPPROTO_AH;
-+ dmp("ahp", (char*)ahp, sizeof(*ahp));
-+
-+ ipo = *ixs->iph;
-+ ipo.tos = 0;
-+ ipo.frag_off = 0;
-+ ipo.ttl = 0;
-+ ipo.check = 0;
-+ dmp("ipo", (char*)&ipo, sizeof(ipo));
-+
-+ switch(ixs->ipsp->ips_authalg) {
-+#ifdef CONFIG_IPSEC_AUTH_HMAC_MD5
-+ case AH_MD5:
-+ tctx.md5 = ((struct md5_ctx*)(ixs->ipsp->ips_key_a))->ictx;
-+ dmp("ictx", (char*)&tctx.md5, sizeof(tctx.md5));
-+ MD5Update(&tctx.md5, (unsigned char *)&ipo, sizeof (struct iphdr));
-+ dmp("ictx+ipo", (char*)&tctx.md5, sizeof(tctx.md5));
-+ MD5Update(&tctx.md5, (unsigned char *)ahp, headroom - sizeof(ahp->ah_data));
-+ dmp("ictx+ahp", (char*)&tctx.md5, sizeof(tctx.md5));
-+ MD5Update(&tctx.md5, (unsigned char *)zeroes, AHHMAC_HASHLEN);
-+ dmp("ictx+zeroes", (char*)&tctx.md5, sizeof(tctx.md5));
-+ MD5Update(&tctx.md5, dat + ixs->iphlen + headroom, len - ixs->iphlen - headroom);
-+ dmp("ictx+dat", (char*)&tctx.md5, sizeof(tctx.md5));
-+ MD5Final(hash, &tctx.md5);
-+ dmp("ictx hash", (char*)&hash, sizeof(hash));
-+ tctx.md5 = ((struct md5_ctx*)(ixs->ipsp->ips_key_a))->octx;
-+ dmp("octx", (char*)&tctx.md5, sizeof(tctx.md5));
-+ MD5Update(&tctx.md5, hash, AHMD596_ALEN);
-+ dmp("octx+hash", (char*)&tctx.md5, sizeof(tctx.md5));
-+ MD5Final(hash, &tctx.md5);
-+ dmp("octx hash", (char*)&hash, sizeof(hash));
-+
-+ memcpy(ahp->ah_data, hash, AHHMAC_HASHLEN);
-+
-+ /* paranoid */
-+ memset((caddr_t)&tctx.md5, 0, sizeof(tctx.md5));
-+ memset((caddr_t)hash, 0, sizeof(*hash));
-+ break;
-+#endif /* CONFIG_IPSEC_AUTH_HMAC_MD5 */
-+#ifdef CONFIG_IPSEC_AUTH_HMAC_SHA1
-+ case AH_SHA:
-+ tctx.sha1 = ((struct sha1_ctx*)(ixs->ipsp->ips_key_a))->ictx;
-+ SHA1Update(&tctx.sha1, (unsigned char *)&ipo, sizeof (struct iphdr));
-+ SHA1Update(&tctx.sha1, (unsigned char *)ahp, headroom - sizeof(ahp->ah_data));
-+ SHA1Update(&tctx.sha1, (unsigned char *)zeroes, AHHMAC_HASHLEN);
-+ SHA1Update(&tctx.sha1, dat + ixs->iphlen + headroom, len - ixs->iphlen - headroom);
-+ SHA1Final(hash, &tctx.sha1);
-+ tctx.sha1 = ((struct sha1_ctx*)(ixs->ipsp->ips_key_a))->octx;
-+ SHA1Update(&tctx.sha1, hash, AHSHA196_ALEN);
-+ SHA1Final(hash, &tctx.sha1);
-+
-+ memcpy(ahp->ah_data, hash, AHHMAC_HASHLEN);
-+
-+ /* paranoid */
-+ memset((caddr_t)&tctx.sha1, 0, sizeof(tctx.sha1));
-+ memset((caddr_t)hash, 0, sizeof(*hash));
-+ break;
-+#endif /* CONFIG_IPSEC_AUTH_HMAC_SHA1 */
-+ default:
-+ ixs->stats->tx_errors++;
-+ return IPSEC_XMIT_AH_BADALG;
-+ }
-+#ifdef NET_21
-+ ixs->skb->h.raw = (unsigned char*)ahp;
-+#endif /* NET_21 */
-+ break;
-+#endif /* CONFIG_IPSEC_AH */
-+#ifdef CONFIG_IPSEC_IPIP
-+ case IPPROTO_IPIP:
-+ ixs->iph->version = 4;
-+ switch(sysctl_ipsec_tos) {
-+ case 0:
-+#ifdef NET_21
-+ ixs->iph->tos = ixs->skb->nh.iph->tos;
-+#else /* NET_21 */
-+ ixs->iph->tos = ixs->skb->ip_hdr->tos;
-+#endif /* NET_21 */
-+ break;
-+ case 1:
-+ ixs->iph->tos = 0;
-+ break;
-+ default:
-+ break;
-+ }
-+#ifdef NET_21
-+#ifdef NETDEV_23
-+ ixs->iph->ttl = sysctl_ip_default_ttl;
-+#else /* NETDEV_23 */
-+ ixs->iph->ttl = ip_statistics.IpDefaultTTL;
-+#endif /* NETDEV_23 */
-+#else /* NET_21 */
-+ ixs->iph->ttl = 64; /* ip_statistics.IpDefaultTTL; */
-+#endif /* NET_21 */
-+ ixs->iph->frag_off = 0;
-+ ixs->iph->saddr = ((struct sockaddr_in*)(ixs->ipsp->ips_addr_s))->sin_addr.s_addr;
-+ ixs->iph->daddr = ((struct sockaddr_in*)(ixs->ipsp->ips_addr_d))->sin_addr.s_addr;
-+ ixs->iph->protocol = IPPROTO_IPIP;
-+ ixs->iph->ihl = sizeof(struct iphdr) >> 2;
-+
-+ KLIPS_IP_SELECT_IDENT(ixs->iph, ixs->skb);
-+
-+ ixs->newdst = (__u32)ixs->iph->daddr;
-+ ixs->newsrc = (__u32)ixs->iph->saddr;
-+
-+#ifdef NET_21
-+ ixs->skb->h.ipiph = ixs->skb->nh.iph;
-+#endif /* NET_21 */
-+ break;
-+#endif /* !CONFIG_IPSEC_IPIP */
-+#ifdef CONFIG_IPSEC_IPCOMP
-+ case IPPROTO_COMP:
-+ {
-+ unsigned int flags = 0;
-+#ifdef CONFIG_IPSEC_DEBUG
-+ unsigned int old_tot_len = ntohs(ixs->iph->tot_len);
-+#endif /* CONFIG_IPSEC_DEBUG */
-+ ixs->ipsp->ips_comp_ratio_dbytes += ntohs(ixs->iph->tot_len);
-+
-+ ixs->skb = skb_compress(ixs->skb, ixs->ipsp, &flags);
-+
-+#ifdef NET_21
-+ ixs->iph = ixs->skb->nh.iph;
-+#else /* NET_21 */
-+ ixs->iph = ixs->skb->ip_hdr;
-+#endif /* NET_21 */
-+
-+ ixs->ipsp->ips_comp_ratio_cbytes += ntohs(ixs->iph->tot_len);
-+
-+#ifdef CONFIG_IPSEC_DEBUG
-+ if (debug_tunnel & DB_TN_CROUT)
-+ {
-+ if (old_tot_len > ntohs(ixs->iph->tot_len))
-+ KLIPS_PRINT(debug_tunnel & DB_TN_CROUT,
-+ "klips_debug:ipsec_xmit_encap_once: "
-+ "packet shrunk from %d to %d bytes after compression, cpi=%04x (should be from spi=%08x, spi&0xffff=%04x.\n",
-+ old_tot_len, ntohs(ixs->iph->tot_len),
-+ ntohs(((struct ipcomphdr*)(((char*)ixs->iph) + ((ixs->iph->ihl) << 2)))->ipcomp_cpi),
-+ ntohl(ixs->ipsp->ips_said.spi),
-+ (__u16)(ntohl(ixs->ipsp->ips_said.spi) & 0x0000ffff));
-+ else
-+ KLIPS_PRINT(debug_tunnel & DB_TN_CROUT,
-+ "klips_debug:ipsec_xmit_encap_once: "
-+ "packet did not compress (flags = %d).\n",
-+ flags);
-+ }
-+#endif /* CONFIG_IPSEC_DEBUG */
-+ }
-+ break;
-+#endif /* CONFIG_IPSEC_IPCOMP */
-+ default:
-+ ixs->stats->tx_errors++;
-+ return IPSEC_XMIT_BADPROTO;
-+ }
-+
-+#ifdef NET_21
-+ ixs->skb->nh.raw = ixs->skb->data;
-+#else /* NET_21 */
-+ ixs->skb->ip_hdr = ixs->skb->h.iph = (struct iphdr *) ixs->skb->data;
-+#endif /* NET_21 */
-+ ixs->iph->check = 0;
-+ ixs->iph->check = ip_fast_csum((unsigned char *)ixs->iph, ixs->iph->ihl);
-+
-+ KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
-+ "klips_debug:ipsec_xmit_encap_once: "
-+ "after <%s%s%s>, SA:%s:\n",
-+ IPS_XFORM_NAME(ixs->ipsp),
-+ ixs->sa_len ? ixs->sa_txt : " (error)");
-+ KLIPS_IP_PRINT(debug_tunnel & DB_TN_XMIT, ixs->iph);
-+
-+ ixs->ipsp->ips_life.ipl_bytes.ipl_count += len;
-+ ixs->ipsp->ips_life.ipl_bytes.ipl_last = len;
-+
-+ if(!ixs->ipsp->ips_life.ipl_usetime.ipl_count) {
-+ ixs->ipsp->ips_life.ipl_usetime.ipl_count = jiffies / HZ;
-+ }
-+ ixs->ipsp->ips_life.ipl_usetime.ipl_last = jiffies / HZ;
-+ ixs->ipsp->ips_life.ipl_packets.ipl_count++;
-+
-+ ixs->ipsp = ixs->ipsp->ips_onext;
-+
-+ return IPSEC_XMIT_OK;
-+}
-+
-+/*
-+ * If the IP packet (iph) is a carrying TCP/UDP, then set the encaps
-+ * source and destination ports to those from the TCP/UDP header.
-+ */
-+void ipsec_extract_ports(struct iphdr * iph, struct sockaddr_encap * er)
-+{
-+ struct udphdr *udp;
-+
-+ switch (iph->protocol) {
-+ case IPPROTO_UDP:
-+ case IPPROTO_TCP:
-+ /*
-+ * The ports are at the same offsets in a TCP and UDP
-+ * header so hack it ...
-+ */
-+ udp = (struct udphdr*)(((char*)iph)+(iph->ihl<<2));
-+ er->sen_sport = udp->source;
-+ er->sen_dport = udp->dest;
-+ break;
-+ default:
-+ er->sen_sport = 0;
-+ er->sen_dport = 0;
-+ break;
-+ }
-+}
-+
-+/*
-+ * A TRAP eroute is installed and we want to replace it with a HOLD
-+ * eroute.
-+ */
-+static int create_hold_eroute(struct eroute *origtrap,
-+ struct sk_buff * skb, struct iphdr * iph,
-+ uint32_t eroute_pid)
-+{
-+ struct eroute hold_eroute;
-+ ip_said hold_said;
-+ struct sk_buff *first, *last;
-+ int error;
-+
-+ first = last = NULL;
-+ memset((caddr_t)&hold_eroute, 0, sizeof(hold_eroute));
-+ memset((caddr_t)&hold_said, 0, sizeof(hold_said));
-+
-+ hold_said.proto = IPPROTO_INT;
-+ hold_said.spi = htonl(SPI_HOLD);
-+ hold_said.dst.u.v4.sin_addr.s_addr = INADDR_ANY;
-+
-+ hold_eroute.er_eaddr.sen_len = sizeof(struct sockaddr_encap);
-+ hold_eroute.er_emask.sen_len = sizeof(struct sockaddr_encap);
-+ hold_eroute.er_eaddr.sen_family = AF_ENCAP;
-+ hold_eroute.er_emask.sen_family = AF_ENCAP;
-+ hold_eroute.er_eaddr.sen_type = SENT_IP4;
-+ hold_eroute.er_emask.sen_type = 255;
-+
-+ hold_eroute.er_eaddr.sen_ip_src.s_addr = iph->saddr;
-+ hold_eroute.er_eaddr.sen_ip_dst.s_addr = iph->daddr;
-+ hold_eroute.er_emask.sen_ip_src.s_addr = INADDR_BROADCAST;
-+ hold_eroute.er_emask.sen_ip_dst.s_addr = INADDR_BROADCAST;
-+ hold_eroute.er_emask.sen_sport = 0;
-+ hold_eroute.er_emask.sen_dport = 0;
-+ hold_eroute.er_pid = eroute_pid;
-+ hold_eroute.er_count = 0;
-+ hold_eroute.er_lasttime = jiffies/HZ;
-+
-+ /*
-+ * if it wasn't captured by a wildcard, then don't record it as
-+ * a wildcard.
-+ */
-+ if(origtrap->er_eaddr.sen_proto != 0) {
-+ hold_eroute.er_eaddr.sen_proto = iph->protocol;
-+
-+ if((iph->protocol == IPPROTO_TCP ||
-+ iph->protocol == IPPROTO_UDP) &&
-+ (origtrap->er_eaddr.sen_sport != 0 ||
-+ origtrap->er_eaddr.sen_dport != 0)) {
-+
-+ if(origtrap->er_eaddr.sen_sport != 0)
-+ hold_eroute.er_emask.sen_sport = ~0;
-+
-+ if(origtrap->er_eaddr.sen_dport != 0)
-+ hold_eroute.er_emask.sen_dport = ~0;
-+
-+ ipsec_extract_ports(iph, &hold_eroute.er_eaddr);
-+ }
-+ }
-+
-+#ifdef CONFIG_IPSEC_DEBUG
-+ if (debug_pfkey) {
-+ char buf1[64], buf2[64];
-+ subnettoa(hold_eroute.er_eaddr.sen_ip_src,
-+ hold_eroute.er_emask.sen_ip_src, 0, buf1, sizeof(buf1));
-+ subnettoa(hold_eroute.er_eaddr.sen_ip_dst,
-+ hold_eroute.er_emask.sen_ip_dst, 0, buf2, sizeof(buf2));
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:ipsec_tunnel_start_xmit: "
-+ "calling breakeroute and makeroute for %s:%d->%s:%d %d HOLD eroute.\n",
-+ buf1, ntohs(hold_eroute.er_eaddr.sen_sport),
-+ buf2, ntohs(hold_eroute.er_eaddr.sen_dport),
-+ hold_eroute.er_eaddr.sen_proto);
-+ }
-+#endif /* CONFIG_IPSEC_DEBUG */
-+
-+ if (ipsec_breakroute(&(hold_eroute.er_eaddr), &(hold_eroute.er_emask),
-+ &first, &last)) {
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:ipsec_tunnel_start_xmit: "
-+ "HOLD breakeroute found nothing.\n");
-+ } else {
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:ipsec_tunnel_start_xmit: "
-+ "HOLD breakroute deleted %u.%u.%u.%u:%u -> %u.%u.%u.%u:%u %u\n",
-+ NIPQUAD(hold_eroute.er_eaddr.sen_ip_src),
-+ ntohs(hold_eroute.er_eaddr.sen_sport),
-+ NIPQUAD(hold_eroute.er_eaddr.sen_ip_dst),
-+ ntohs(hold_eroute.er_eaddr.sen_dport),
-+ hold_eroute.er_eaddr.sen_proto);
-+ }
-+ if (first != NULL)
-+ kfree_skb(first);
-+ if (last != NULL)
-+ kfree_skb(last);
-+
-+ error = ipsec_makeroute(&(hold_eroute.er_eaddr),
-+ &(hold_eroute.er_emask),
-+ hold_said, eroute_pid, skb, NULL, NULL);
-+ if (error) {
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:ipsec_tunnel_start_xmit: "
-+ "HOLD makeroute returned %d, failed.\n", error);
-+ } else {
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:ipsec_tunnel_start_xmit: "
-+ "HOLD makeroute call successful.\n");
-+ }
-+ return (error == 0);
-+}
-+
-+enum ipsec_xmit_value
-+ipsec_xmit_encap_bundle(struct ipsec_xmit_state *ixs)
-+{
-+#ifdef CONFIG_IPSEC_ALG
-+ struct ipsec_alg_enc *ixt_e = NULL;
-+ struct ipsec_alg_auth *ixt_a = NULL;
-+ int blocksize = 8;
-+#endif /* CONFIG_IPSEC_ALG */
-+ enum ipsec_xmit_value bundle_stat = IPSEC_XMIT_OK;
-+
-+ ixs->newdst = ixs->orgdst = ixs->iph->daddr;
-+ ixs->newsrc = ixs->orgsrc = ixs->iph->saddr;
-+ ixs->orgedst = ixs->outgoing_said.dst.u.v4.sin_addr.s_addr;
-+ ixs->iphlen = ixs->iph->ihl << 2;
-+ ixs->pyldsz = ntohs(ixs->iph->tot_len) - ixs->iphlen;
-+ ixs->max_headroom = ixs->max_tailroom = 0;
-+
-+ if (ixs->outgoing_said.proto == IPPROTO_INT) {
-+ switch (ntohl(ixs->outgoing_said.spi)) {
-+ case SPI_DROP:
-+ KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
-+ "klips_debug:ipsec_xmit_encap_bundle: "
-+ "shunt SA of DROP or no eroute: dropping.\n");
-+ ixs->stats->tx_dropped++;
-+ break;
-+
-+ case SPI_REJECT:
-+ KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
-+ "klips_debug:ipsec_xmit_encap_bundle: "
-+ "shunt SA of REJECT: notifying and dropping.\n");
-+ ICMP_SEND(ixs->skb,
-+ ICMP_DEST_UNREACH,
-+ ICMP_PKT_FILTERED,
-+ 0,
-+ ixs->physdev);
-+ ixs->stats->tx_dropped++;
-+ break;
-+
-+ case SPI_PASS:
-+#ifdef NET_21
-+ ixs->pass = 1;
-+#endif /* NET_21 */
-+ KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
-+ "klips_debug:ipsec_xmit_encap_bundle: "
-+ "PASS: calling dev_queue_xmit\n");
-+ return IPSEC_XMIT_PASS;
-+ goto cleanup;
-+
-+ case SPI_HOLD:
-+ KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
-+ "klips_debug:ipsec_xmit_encap_bundle: "
-+ "shunt SA of HOLD: this does not make sense here, dropping.\n");
-+ ixs->stats->tx_dropped++;
-+ break;
-+
-+ case SPI_TRAP:
-+ case SPI_TRAPSUBNET:
-+ {
-+ struct sockaddr_in src, dst;
-+#ifdef CONFIG_IPSEC_DEBUG
-+ char bufsrc[ADDRTOA_BUF], bufdst[ADDRTOA_BUF];
-+#endif /* CONFIG_IPSEC_DEBUG */
-+
-+ /* Signal all listening KMds with a PF_KEY ACQUIRE */
-+
-+ src.sin_family = AF_INET;
-+ dst.sin_family = AF_INET;
-+ src.sin_addr.s_addr = ixs->iph->saddr;
-+ dst.sin_addr.s_addr = ixs->iph->daddr;
-+
-+ ixs->ips.ips_transport_protocol = 0;
-+ src.sin_port = 0;
-+ dst.sin_port = 0;
-+ {
-+ int i;
-+ for(i = 0;
-+ i < sizeof(struct sockaddr_in)
-+ - offsetof(struct sockaddr_in, sin_zero);
-+ i++) {
-+ src.sin_zero[i] = 0;
-+ dst.sin_zero[i] = 0;
-+ }
-+ }
-+
-+ if(ixs->eroute->er_eaddr.sen_proto != 0) {
-+ ixs->ips.ips_transport_protocol = ixs->iph->protocol;
-+
-+ if(ixs->eroute->er_eaddr.sen_sport != 0) {
-+ src.sin_port =
-+ (ixs->iph->protocol == IPPROTO_UDP
-+ ? ((struct udphdr*) (((caddr_t)ixs->iph) + (ixs->iph->ihl << 2)))->source
-+ : (ixs->iph->protocol == IPPROTO_TCP
-+ ? ((struct tcphdr*)((caddr_t)ixs->iph + (ixs->iph->ihl << 2)))->source
-+ : 0));
-+ }
-+ if(ixs->eroute->er_eaddr.sen_dport != 0) {
-+ dst.sin_port =
-+ (ixs->iph->protocol == IPPROTO_UDP
-+ ? ((struct udphdr*) (((caddr_t)ixs->iph) + (ixs->iph->ihl << 2)))->dest
-+ : (ixs->iph->protocol == IPPROTO_TCP
-+ ? ((struct tcphdr*)((caddr_t)ixs->iph + (ixs->iph->ihl << 2)))->dest
-+ : 0));
-+ }
-+ }
-+
-+ ixs->ips.ips_addr_s = (struct sockaddr*)(&src);
-+ ixs->ips.ips_addr_d = (struct sockaddr*)(&dst);
-+ KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
-+ "klips_debug:ipsec_xmit_encap_bundle: "
-+ "SADB_ACQUIRE sent with src=%s:%d, dst=%s:%d, proto=%d.\n",
-+ addrtoa(((struct sockaddr_in*)(ixs->ips.ips_addr_s))->sin_addr, 0, bufsrc, sizeof(bufsrc)) <= ADDRTOA_BUF ? bufsrc : "BAD_ADDR",
-+ ntohs(((struct sockaddr_in*)(ixs->ips.ips_addr_s))->sin_port),
-+ addrtoa(((struct sockaddr_in*)(ixs->ips.ips_addr_d))->sin_addr, 0, bufdst, sizeof(bufdst)) <= ADDRTOA_BUF ? bufdst : "BAD_ADDR",
-+ ntohs(((struct sockaddr_in*)(ixs->ips.ips_addr_d))->sin_port),
-+ ixs->ips.ips_said.proto);
-+
-+ /* increment count of total traps needed */
-+ ipsec_xmit_trap_count++;
-+
-+ if (pfkey_acquire(&ixs->ips) == 0) {
-+
-+ /* note that we succeeded */
-+ ipsec_xmit_trap_sendcount++;
-+
-+ if (ixs->outgoing_said.spi==htonl(SPI_TRAPSUBNET)) {
-+ /*
-+ * The spinlock is to prevent any other
-+ * process from accessing or deleting
-+ * the eroute while we are using and
-+ * updating it.
-+ */
-+ spin_lock(&eroute_lock);
-+ ixs->eroute = ipsec_findroute(&ixs->matcher);
-+ if(ixs->eroute) {
-+ ixs->eroute->er_said.spi = htonl(SPI_HOLD);
-+ ixs->eroute->er_first = ixs->skb;
-+ ixs->skb = NULL;
-+ }
-+ spin_unlock(&eroute_lock);
-+ } else if (create_hold_eroute(ixs->eroute,
-+ ixs->skb,
-+ ixs->iph,
-+ ixs->eroute_pid)) {
-+ ixs->skb = NULL;
-+ }
-+ /* whether or not the above succeeded, we continue */
-+
-+ }
-+ ixs->stats->tx_dropped++;
-+ }
-+ default:
-+ /* XXX what do we do with an unknown shunt spi? */
-+ break;
-+ } /* switch (ntohl(ixs->outgoing_said.spi)) */
-+ return IPSEC_XMIT_STOLEN;
-+ } /* if (ixs->outgoing_said.proto == IPPROTO_INT) */
-+
-+ /*
-+ The spinlock is to prevent any other process from
-+ accessing or deleting the ipsec_sa hash table or any of the
-+ ipsec_sa s while we are using and updating them.
-+
-+ This is not optimal, but was relatively straightforward
-+ at the time. A better way to do it has been planned for
-+ more than a year, to lock the hash table and put reference
-+ counts on each ipsec_sa instead. This is not likely to happen
-+ in KLIPS1 unless a volunteer contributes it, but will be
-+ designed into KLIPS2.
-+ */
-+ spin_lock(&tdb_lock);
-+
-+ ixs->ipsp = ipsec_sa_getbyid(&ixs->outgoing_said);
-+ ixs->sa_len = satot(&ixs->outgoing_said, 0, ixs->sa_txt, sizeof(ixs->sa_txt));
-+
-+ if (ixs->ipsp == NULL) {
-+ KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
-+ "klips_debug:ipsec_xmit_encap_bundle: "
-+ "no ipsec_sa for SA%s: outgoing packet with no SA, dropped.\n",
-+ ixs->sa_len ? ixs->sa_txt : " (error)");
-+ ixs->stats->tx_dropped++;
-+ bundle_stat = IPSEC_XMIT_SAIDNOTFOUND;
-+ goto cleanup;
-+ }
-+
-+ ipsec_sa_put(ixs->ipsp); /* incomplete */
-+
-+ KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
-+ "klips_debug:ipsec_xmit_encap_bundle: "
-+ "found ipsec_sa -- SA:<%s%s%s> %s\n",
-+ IPS_XFORM_NAME(ixs->ipsp),
-+ ixs->sa_len ? ixs->sa_txt : " (error)");
-+
-+ /*
-+ * How much headroom do we need to be able to apply
-+ * all the grouped transforms?
-+ */
-+ ixs->ipsq = ixs->ipsp; /* save the head of the ipsec_sa chain */
-+ while (ixs->ipsp) {
-+ ixs->sa_len = satot(&ixs->ipsp->ips_said, 0, ixs->sa_txt, sizeof(ixs->sa_txt));
-+ if(ixs->sa_len == 0) {
-+ strcpy(ixs->sa_txt, "(error)");
-+ }
-+
-+ /* If it is in larval state, drop the packet, we cannot process yet. */
-+ if(ixs->ipsp->ips_state == SADB_SASTATE_LARVAL) {
-+ KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
-+ "klips_debug:ipsec_xmit_encap_bundle: "
-+ "ipsec_sa in larval state for SA:<%s%s%s> %s, cannot be used yet, dropping packet.\n",
-+ IPS_XFORM_NAME(ixs->ipsp),
-+ ixs->sa_len ? ixs->sa_txt : " (error)");
-+ ixs->stats->tx_errors++;
-+ bundle_stat = IPSEC_XMIT_SAIDNOTLIVE;
-+ goto cleanup;
-+ }
-+
-+ if(ixs->ipsp->ips_state == SADB_SASTATE_DEAD) {
-+ KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
-+ "klips_debug:ipsec_xmit_encap_bundle: "
-+ "ipsec_sa in dead state for SA:<%s%s%s> %s, can no longer be used, dropping packet.\n",
-+ IPS_XFORM_NAME(ixs->ipsp),
-+ ixs->sa_len ? ixs->sa_txt : " (error)");
-+ ixs->stats->tx_errors++;
-+ bundle_stat = IPSEC_XMIT_SAIDNOTLIVE;
-+ goto cleanup;
-+ }
-+
-+ /* If the replay window counter == -1, expire SA, it will roll */
-+ if(ixs->ipsp->ips_replaywin && ixs->ipsp->ips_replaywin_lastseq == -1) {
-+ pfkey_expire(ixs->ipsp, 1);
-+ KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
-+ "klips_debug:ipsec_xmit_encap_bundle: "
-+ "replay window counter rolled for SA:<%s%s%s> %s, packet dropped, expiring SA.\n",
-+ IPS_XFORM_NAME(ixs->ipsp),
-+ ixs->sa_len ? ixs->sa_txt : " (error)");
-+ ipsec_sa_delchain(ixs->ipsp);
-+ ixs->stats->tx_errors++;
-+ bundle_stat = IPSEC_XMIT_REPLAYROLLED;
-+ goto cleanup;
-+ }
-+
-+ /*
-+ * if this is the first time we are using this SA, mark start time,
-+ * and offset hard/soft counters by "now" for later checking.
-+ */
-+#if 0
-+ if(ixs->ipsp->ips_life.ipl_usetime.count == 0) {
-+ ixs->ipsp->ips_life.ipl_usetime.count = jiffies;
-+ ixs->ipsp->ips_life.ipl_usetime.hard += jiffies;
-+ ixs->ipsp->ips_life.ipl_usetime.soft += jiffies;
-+ }
-+#endif
-+
-+
-+ if(ipsec_lifetime_check(&ixs->ipsp->ips_life.ipl_bytes, "bytes", ixs->sa_txt,
-+ ipsec_life_countbased, ipsec_outgoing, ixs->ipsp) == ipsec_life_harddied ||
-+ ipsec_lifetime_check(&ixs->ipsp->ips_life.ipl_addtime, "addtime",ixs->sa_txt,
-+ ipsec_life_timebased, ipsec_outgoing, ixs->ipsp) == ipsec_life_harddied ||
-+ ipsec_lifetime_check(&ixs->ipsp->ips_life.ipl_usetime, "usetime",ixs->sa_txt,
-+ ipsec_life_timebased, ipsec_outgoing, ixs->ipsp) == ipsec_life_harddied ||
-+ ipsec_lifetime_check(&ixs->ipsp->ips_life.ipl_packets, "packets",ixs->sa_txt,
-+ ipsec_life_countbased, ipsec_outgoing, ixs->ipsp) == ipsec_life_harddied) {
-+
-+ ipsec_sa_delchain(ixs->ipsp);
-+ ixs->stats->tx_errors++;
-+ bundle_stat = IPSEC_XMIT_LIFETIMEFAILED;
-+ goto cleanup;
-+ }
-+
-+
-+ ixs->headroom = ixs->tailroom = 0;
-+ KLIPS_PRINT(debug_tunnel & DB_TN_CROUT,
-+ "klips_debug:ipsec_xmit_encap_bundle: "
-+ "calling room for <%s%s%s>, SA:%s\n",
-+ IPS_XFORM_NAME(ixs->ipsp),
-+ ixs->sa_len ? ixs->sa_txt : " (error)");
-+ switch(ixs->ipsp->ips_said.proto) {
-+#ifdef CONFIG_IPSEC_AH
-+ case IPPROTO_AH:
-+ ixs->headroom += sizeof(struct ahhdr);
-+ break;
-+#endif /* CONFIG_IPSEC_AH */
-+#ifdef CONFIG_IPSEC_ESP
-+ case IPPROTO_ESP:
-+#ifdef CONFIG_IPSEC_ALG
-+ if ((ixt_e=ixs->ipsp->ips_alg_enc)) {
-+ blocksize = ixt_e->ixt_blocksize;
-+ ixs->headroom += ESP_HEADER_LEN + ixt_e->ixt_ivlen/8;
-+ } else
-+#endif /* CONFIG_IPSEC_ALG */
-+ switch(ixs->ipsp->ips_encalg) {
-+#ifdef CONFIG_IPSEC_ENC_3DES
-+ case ESP_3DES:
-+ ixs->headroom += sizeof(struct esphdr);
-+ break;
-+#endif /* CONFIG_IPSEC_ENC_3DES */
-+ default:
-+ ixs->stats->tx_errors++;
-+ bundle_stat = IPSEC_XMIT_ESP_BADALG;
-+ goto cleanup;
-+ }
-+#ifdef CONFIG_IPSEC_ALG
-+ if ((ixt_a=ixs->ipsp->ips_alg_auth)) {
-+ ixs->tailroom += AHHMAC_HASHLEN;
-+ } else
-+#endif /* CONFIG_IPSEC_ALG */
-+ switch(ixs->ipsp->ips_authalg) {
-+#ifdef CONFIG_IPSEC_AUTH_HMAC_MD5
-+ case AH_MD5:
-+ ixs->tailroom += AHHMAC_HASHLEN;
-+ break;
-+#endif /* CONFIG_IPSEC_AUTH_HMAC_MD5 */
-+#ifdef CONFIG_IPSEC_AUTH_HMAC_SHA1
-+ case AH_SHA:
-+ ixs->tailroom += AHHMAC_HASHLEN;
-+ break;
-+#endif /* CONFIG_IPSEC_AUTH_HMAC_SHA1 */
-+ case AH_NONE:
-+ break;
-+ default:
-+ ixs->stats->tx_errors++;
-+ bundle_stat = IPSEC_XMIT_AH_BADALG;
-+ goto cleanup;
-+ }
-+#ifdef CONFIG_IPSEC_ALG
-+ ixs->tailroom += blocksize != 1 ?
-+ ((blocksize - ((ixs->pyldsz + 2) % blocksize)) % blocksize) + 2 :
-+ ((4 - ((ixs->pyldsz + 2) % 4)) % 4) + 2;
-+#else
-+ ixs->tailroom += ((8 - ((ixs->pyldsz + 2 * sizeof(unsigned char)) % 8)) % 8) + 2;
-+#endif /* CONFIG_IPSEC_ALG */
-+#ifdef CONFIG_IPSEC_NAT_TRAVERSAL
-+ if ((ixs->ipsp->ips_natt_type) && (!ixs->natt_type)) {
-+ ixs->natt_type = ixs->ipsp->ips_natt_type;
-+ ixs->natt_sport = ixs->ipsp->ips_natt_sport;
-+ ixs->natt_dport = ixs->ipsp->ips_natt_dport;
-+ switch (ixs->natt_type) {
-+ case ESPINUDP_WITH_NON_IKE:
-+ ixs->natt_head = sizeof(struct udphdr)+(2*sizeof(__u32));
-+ break;
-+
-+ case ESPINUDP_WITH_NON_ESP:
-+ ixs->natt_head = sizeof(struct udphdr);
-+ break;
-+
-+ default:
-+ KLIPS_PRINT(debug_tunnel & DB_TN_CROUT
-+ , "klips_xmit: invalid nat-t type %d"
-+ , ixs->natt_type);
-+ bundle_stat = IPSEC_XMIT_ESPUDP_BADTYPE;
-+ goto cleanup;
-+
-+ break;
-+ }
-+ ixs->tailroom += ixs->natt_head;
-+ }
-+#endif
-+ break;
-+#endif /* !CONFIG_IPSEC_ESP */
-+#ifdef CONFIG_IPSEC_IPIP
-+ case IPPROTO_IPIP:
-+ ixs->headroom += sizeof(struct iphdr);
-+ break;
-+#endif /* !CONFIG_IPSEC_IPIP */
-+ case IPPROTO_COMP:
-+#ifdef CONFIG_IPSEC_IPCOMP
-+ /*
-+ We can't predict how much the packet will
-+ shrink without doing the actual compression.
-+ We could do it here, if we were the first
-+ encapsulation in the chain. That might save
-+ us a skb_copy_expand, since we might fit
-+ into the existing skb then. However, this
-+ would be a bit unclean (and this hack has
-+ bit us once), so we better not do it. After
-+ all, the skb_copy_expand is cheap in
-+ comparison to the actual compression.
-+ At least we know the packet will not grow.
-+ */
-+ break;
-+#endif /* CONFIG_IPSEC_IPCOMP */
-+ default:
-+ ixs->stats->tx_errors++;
-+ bundle_stat = IPSEC_XMIT_BADPROTO;
-+ goto cleanup;
-+ }
-+ ixs->ipsp = ixs->ipsp->ips_onext;
-+ KLIPS_PRINT(debug_tunnel & DB_TN_CROUT,
-+ "klips_debug:ipsec_xmit_encap_bundle: "
-+ "Required head,tailroom: %d,%d\n",
-+ ixs->headroom, ixs->tailroom);
-+ ixs->max_headroom += ixs->headroom;
-+ ixs->max_tailroom += ixs->tailroom;
-+ ixs->pyldsz += (ixs->headroom + ixs->tailroom);
-+ }
-+ ixs->ipsp = ixs->ipsq; /* restore the head of the ipsec_sa chain */
-+
-+ KLIPS_PRINT(debug_tunnel & DB_TN_CROUT,
-+ "klips_debug:ipsec_xmit_encap_bundle: "
-+ "existing head,tailroom: %d,%d before applying xforms with head,tailroom: %d,%d .\n",
-+ skb_headroom(ixs->skb), skb_tailroom(ixs->skb),
-+ ixs->max_headroom, ixs->max_tailroom);
-+
-+ ixs->tot_headroom += ixs->max_headroom;
-+ ixs->tot_tailroom += ixs->max_tailroom;
-+
-+ ixs->mtudiff = ixs->prv->mtu + ixs->tot_headroom + ixs->tot_tailroom - ixs->physmtu;
-+
-+ KLIPS_PRINT(debug_tunnel & DB_TN_CROUT,
-+ "klips_debug:ipsec_xmit_encap_bundle: "
-+ "mtu:%d physmtu:%d tothr:%d tottr:%d mtudiff:%d ippkttotlen:%d\n",
-+ ixs->prv->mtu, ixs->physmtu,
-+ ixs->tot_headroom, ixs->tot_tailroom, ixs->mtudiff, ntohs(ixs->iph->tot_len));
-+ if(ixs->mtudiff > 0) {
-+ int newmtu = ixs->physmtu - (ixs->tot_headroom + ((ixs->tot_tailroom + 2) & ~7) + 5);
-+
-+ KLIPS_PRINT(debug_tunnel & DB_TN_CROUT,
-+ "klips_info:ipsec_xmit_encap_bundle: "
-+ "dev %s mtu of %d decreased by %d to %d\n",
-+ ixs->dev->name,
-+ ixs->prv->mtu,
-+ ixs->prv->mtu - newmtu,
-+ newmtu);
-+ ixs->prv->mtu = newmtu;
-+#ifdef NET_21
-+#if 0
-+ ixs->skb->dst->pmtu = ixs->prv->mtu; /* RGB */
-+#endif /* 0 */
-+#else /* NET_21 */
-+#if 0
-+ ixs->dev->mtu = ixs->prv->mtu; /* RGB */
-+#endif /* 0 */
-+#endif /* NET_21 */
-+ }
-+
-+ /*
-+ If the sender is doing PMTU discovery, and the
-+ packet doesn't fit within ixs->prv->mtu, notify him
-+ (unless it was an ICMP packet, or it was not the
-+ zero-offset packet) and send it anyways.
-+
-+ Note: buggy firewall configuration may prevent the
-+ ICMP packet from getting back.
-+ */
-+ if(sysctl_ipsec_icmp
-+ && ixs->prv->mtu < ntohs(ixs->iph->tot_len)
-+ && (ixs->iph->frag_off & __constant_htons(IP_DF)) ) {
-+ int notify = ixs->iph->protocol != IPPROTO_ICMP
-+ && (ixs->iph->frag_off & __constant_htons(IP_OFFSET)) == 0;
-+
-+#ifdef IPSEC_obey_DF
-+ KLIPS_PRINT(debug_tunnel & DB_TN_CROUT,
-+ "klips_debug:ipsec_xmit_encap_bundle: "
-+ "fragmentation needed and DF set; %sdropping packet\n",
-+ notify ? "sending ICMP and " : "");
-+ if (notify)
-+ ICMP_SEND(ixs->skb,
-+ ICMP_DEST_UNREACH,
-+ ICMP_FRAG_NEEDED,
-+ ixs->prv->mtu,
-+ ixs->physdev);
-+ ixs->stats->tx_errors++;
-+ bundle_stat = IPSEC_XMIT_CANNOTFRAG;
-+ goto cleanup;
-+#else /* IPSEC_obey_DF */
-+ KLIPS_PRINT(debug_tunnel & DB_TN_CROUT,
-+ "klips_debug:ipsec_xmit_encap_bundle: "
-+ "fragmentation needed and DF set; %spassing packet\n",
-+ notify ? "sending ICMP and " : "");
-+ if (notify)
-+ ICMP_SEND(ixs->skb,
-+ ICMP_DEST_UNREACH,
-+ ICMP_FRAG_NEEDED,
-+ ixs->prv->mtu,
-+ ixs->physdev);
-+#endif /* IPSEC_obey_DF */
-+ }
-+
-+#ifdef MSS_HACK
-+ /*
-+ * If this is a transport mode TCP packet with
-+ * SYN set, determine an effective MSS based on
-+ * AH/ESP overheads determined above.
-+ */
-+ if (ixs->iph->protocol == IPPROTO_TCP
-+ && ixs->outgoing_said.proto != IPPROTO_IPIP) {
-+ struct tcphdr *tcph = ixs->skb->h.th;
-+ if (tcph->syn && !tcph->ack) {
-+ if(!ipsec_adjust_mss(ixs->skb, tcph, ixs->prv->mtu)) {
-+ printk(KERN_WARNING
-+ "klips_warning:ipsec_xmit_encap_bundle: "
-+ "ipsec_adjust_mss() failed\n");
-+ ixs->stats->tx_errors++;
-+ bundle_stat = IPSEC_XMIT_MSSERR;
-+ goto cleanup;
-+ }
-+ }
-+ }
-+#endif /* MSS_HACK */
-+
-+#ifdef CONFIG_IPSEC_NAT_TRAVERSAL
-+ if ((ixs->natt_type) && (ixs->outgoing_said.proto != IPPROTO_IPIP)) {
-+ /**
-+ * NAT-Traversal and Transport Mode:
-+ * we need to correct TCP/UDP checksum
-+ *
-+ * If we've got NAT-OA, we can fix checksum without recalculation.
-+ * If we don't we can zero udp checksum.
-+ */
-+ __u32 natt_oa = ixs->ipsp->ips_natt_oa ?
-+ ((struct sockaddr_in*)(ixs->ipsp->ips_natt_oa))->sin_addr.s_addr : 0;
-+ __u16 pkt_len = ixs->skb->tail - (unsigned char *)ixs->iph;
-+ __u16 data_len = pkt_len - (ixs->iph->ihl << 2);
-+ switch (ixs->iph->protocol) {
-+ case IPPROTO_TCP:
-+ if (data_len >= sizeof(struct tcphdr)) {
-+ struct tcphdr *tcp = (struct tcphdr *)((__u32 *)ixs->iph+ixs->iph->ihl);
-+ if (natt_oa) {
-+ __u32 buff[2] = { ~ixs->iph->daddr, natt_oa };
-+ KLIPS_PRINT(debug_tunnel,
-+ "klips_debug:ipsec_tunnel_start_xmit: "
-+ "NAT-T & TRANSPORT: "
-+ "fix TCP checksum using NAT-OA\n");
-+ tcp->check = csum_fold(
-+ csum_partial((unsigned char *)buff, sizeof(buff),
-+ tcp->check^0xffff));
-+ }
-+ else {
-+ KLIPS_PRINT(debug_tunnel,
-+ "klips_debug:ipsec_tunnel_start_xmit: "
-+ "NAT-T & TRANSPORT: do not recalc TCP checksum\n");
-+ }
-+ }
-+ else {
-+ KLIPS_PRINT(debug_tunnel,
-+ "klips_debug:ipsec_tunnel_start_xmit: "
-+ "NAT-T & TRANSPORT: can't fix TCP checksum\n");
-+ }
-+ break;
-+ case IPPROTO_UDP:
-+ if (data_len >= sizeof(struct udphdr)) {
-+ struct udphdr *udp = (struct udphdr *)((__u32 *)ixs->iph+ixs->iph->ihl);
-+ if (udp->check == 0) {
-+ KLIPS_PRINT(debug_tunnel,
-+ "klips_debug:ipsec_tunnel_start_xmit: "
-+ "NAT-T & TRANSPORT: UDP checksum already 0\n");
-+ }
-+ else if (natt_oa) {
-+ __u32 buff[2] = { ~ixs->iph->daddr, natt_oa };
-+ KLIPS_PRINT(debug_tunnel,
-+ "klips_debug:ipsec_tunnel_start_xmit: "
-+ "NAT-T & TRANSPORT: "
-+ "fix UDP checksum using NAT-OA\n");
-+ udp->check = csum_fold(
-+ csum_partial((unsigned char *)buff, sizeof(buff),
-+ udp->check^0xffff));
-+ }
-+ else {
-+ KLIPS_PRINT(debug_tunnel,
-+ "klips_debug:ipsec_tunnel_start_xmit: "
-+ "NAT-T & TRANSPORT: zero UDP checksum\n");
-+ udp->check = 0;
-+ }
-+ }
-+ else {
-+ KLIPS_PRINT(debug_tunnel,
-+ "klips_debug:ipsec_tunnel_start_xmit: "
-+ "NAT-T & TRANSPORT: can't fix UDP checksum\n");
-+ }
-+ break;
-+ default:
-+ KLIPS_PRINT(debug_tunnel,
-+ "klips_debug:ipsec_tunnel_start_xmit: "
-+ "NAT-T & TRANSPORT: non TCP/UDP packet -- do nothing\n");
-+ break;
-+ }
-+ }
-+#endif /* CONFIG_IPSEC_NAT_TRAVERSAL */
-+
-+ if(!ixs->hard_header_stripped) {
-+ KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
-+ "klips_debug:ipsec_xmit_encap_bundle: "
-+ "allocating %d bytes for hardheader.\n",
-+ ixs->hard_header_len);
-+ if((ixs->saved_header = kmalloc(ixs->hard_header_len, GFP_ATOMIC)) == NULL) {
-+ printk(KERN_WARNING "klips_debug:ipsec_xmit_encap_bundle: "
-+ "Failed, tried to allocate %d bytes for temp hard_header.\n",
-+ ixs->hard_header_len);
-+ ixs->stats->tx_errors++;
-+ bundle_stat = IPSEC_XMIT_ERRMEMALLOC;
-+ goto cleanup;
-+ }
-+ {
-+ int i;
-+ for (i = 0; i < ixs->hard_header_len; i++) {
-+ ixs->saved_header[i] = ixs->skb->data[i];
-+ }
-+ }
-+ if(ixs->skb->len < ixs->hard_header_len) {
-+ printk(KERN_WARNING "klips_error:ipsec_xmit_encap_bundle: "
-+ "tried to skb_pull hhlen=%d, %d available. This should never happen, please report.\n",
-+ ixs->hard_header_len, (int)(ixs->skb->len));
-+ ixs->stats->tx_errors++;
-+ bundle_stat = IPSEC_XMIT_ESP_PUSHPULLERR;
-+ goto cleanup;
-+ }
-+ skb_pull(ixs->skb, ixs->hard_header_len);
-+ ixs->hard_header_stripped = 1;
-+
-+/* ixs->iph = (struct iphdr *) (ixs->skb->data); */
-+ KLIPS_PRINT(debug_tunnel & DB_TN_CROUT,
-+ "klips_debug:ipsec_xmit_encap_bundle: "
-+ "head,tailroom: %d,%d after hard_header stripped.\n",
-+ skb_headroom(ixs->skb), skb_tailroom(ixs->skb));
-+ KLIPS_IP_PRINT(debug_tunnel & DB_TN_CROUT, ixs->iph);
-+ } else {
-+ KLIPS_PRINT(debug_tunnel & DB_TN_CROUT,
-+ "klips_debug:ipsec_xmit_encap_bundle: "
-+ "hard header already stripped.\n");
-+ }
-+
-+ ixs->ll_headroom = (ixs->hard_header_len + 15) & ~15;
-+
-+ if ((skb_headroom(ixs->skb) >= ixs->max_headroom + 2 * ixs->ll_headroom) &&
-+ (skb_tailroom(ixs->skb) >= ixs->max_tailroom)
-+#ifndef NET_21
-+ && ixs->skb->free
-+#endif /* !NET_21 */
-+ ) {
-+ KLIPS_PRINT(debug_tunnel & DB_TN_CROUT,
-+ "klips_debug:ipsec_xmit_encap_bundle: "
-+ "data fits in existing skb\n");
-+ } else {
-+ struct sk_buff* tskb;
-+
-+ if(!ixs->oskb) {
-+ ixs->oskb = ixs->skb;
-+ }
-+
-+ tskb = skb_copy_expand(ixs->skb,
-+ /* The need for 2 * link layer length here remains unexplained...RGB */
-+ ixs->max_headroom + 2 * ixs->ll_headroom,
-+ ixs->max_tailroom,
-+ GFP_ATOMIC);
-+#ifdef NET_21
-+ if(tskb && ixs->skb->sk) {
-+ skb_set_owner_w(tskb, ixs->skb->sk);
-+ }
-+#endif /* NET_21 */
-+ if(ixs->skb != ixs->oskb) {
-+ ipsec_kfree_skb(ixs->skb);
-+ }
-+ ixs->skb = tskb;
-+ if (!ixs->skb) {
-+ printk(KERN_WARNING
-+ "klips_debug:ipsec_xmit_encap_bundle: "
-+ "Failed, tried to allocate %d head and %d tailroom\n",
-+ ixs->max_headroom, ixs->max_tailroom);
-+ ixs->stats->tx_errors++;
-+ bundle_stat = IPSEC_XMIT_ERRSKBALLOC;
-+ goto cleanup;
-+ }
-+ KLIPS_PRINT(debug_tunnel & DB_TN_CROUT,
-+ "klips_debug:ipsec_xmit_encap_bundle: "
-+ "head,tailroom: %d,%d after allocation\n",
-+ skb_headroom(ixs->skb), skb_tailroom(ixs->skb));
-+ }
-+
-+ /*
-+ * Apply grouped transforms to packet
-+ */
-+ while (ixs->ipsp) {
-+ enum ipsec_xmit_value encap_stat = IPSEC_XMIT_OK;
-+
-+ encap_stat = ipsec_xmit_encap_once(ixs);
-+ if(encap_stat != IPSEC_XMIT_OK) {
-+ KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
-+ "klips_debug:ipsec_xmit_encap_bundle: encap_once failed: %d\n",
-+ encap_stat);
-+
-+ bundle_stat = IPSEC_XMIT_ENCAPFAIL;
-+ goto cleanup;
-+ }
-+ }
-+ /* end encapsulation loop here XXX */
-+ cleanup:
-+ spin_unlock(&tdb_lock);
-+ return bundle_stat;
-+}
-+
-+/*
-+ * $Log: ipsec_xmit.c,v $
-+ * Revision 1.8 2004/04/06 02:49:26 mcr
-+ * pullup of algo code from alg-branch.
-+ *
-+ * Revision 1.7 2004/02/03 03:13:41 mcr
-+ * mark invalid encapsulation states.
-+ *
-+ * Revision 1.6.2.1 2003/12/22 15:25:52 jjo
-+ * Merged algo-0.8.1-rc11-test1 into alg-branch
-+ *
-+ * Revision 1.6 2003/12/10 01:14:27 mcr
-+ * NAT-traversal patches to KLIPS.
-+ *
-+ * Revision 1.5 2003/10/31 02:27:55 mcr
-+ * pulled up port-selector patches and sa_id elimination.
-+ *
-+ * Revision 1.4.4.2 2003/10/29 01:37:39 mcr
-+ * when creating %hold from %trap, only make the %hold as
-+ * specific as the %trap was - so if the protocol and ports
-+ * were wildcards, then the %hold will be too.
-+ *
-+ * Revision 1.4.4.1 2003/09/21 13:59:56 mcr
-+ * pre-liminary X.509 patch - does not yet pass tests.
-+ *
-+ * Revision 1.4 2003/06/20 02:28:10 mcr
-+ * misstype of variable name, not detected by module build.
-+ *
-+ * Revision 1.3 2003/06/20 01:42:21 mcr
-+ * added counters to measure how many ACQUIREs we send to pluto,
-+ * and how many are successfully sent.
-+ *
-+ * Revision 1.2 2003/04/03 17:38:35 rgb
-+ * Centralised ipsec_kfree_skb and ipsec_dev_{get,put}.
-+ * Normalised coding style.
-+ * Simplified logic and reduced duplication of code.
-+ *
-+ * Revision 1.1 2003/02/12 19:31:23 rgb
-+ * Refactored from ipsec_tunnel.c
-+ *
-+ */
---- /dev/null Tue Mar 11 13:02:56 2003
-+++ linux/net/ipsec/pfkey_v2.c Mon Feb 9 13:51:03 2004
-@@ -0,0 +1,2126 @@
-+/*
-+ * @(#) RFC2367 PF_KEYv2 Key management API domain socket I/F
-+ * Copyright (C) 1999, 2000, 2001 Richard Guy Briggs.
-+ *
-+ * 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. See <http://www.fsf.org/copyleft/gpl.txt>.
-+ *
-+ * 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.
-+ *
-+ * RCSID $Id: pfkey_v2.c,v 1.81 2004/04/25 21:23:11 ken Exp $
-+ */
-+
-+/*
-+ * Template from /usr/src/linux-2.0.36/net/unix/af_unix.c.
-+ * Hints from /usr/src/linux-2.0.36/net/ipv4/udp.c.
-+ */
-+
-+#define __NO_VERSION__
-+#include <linux/module.h>
-+#include <linux/version.h>
-+#include <linux/config.h>
-+#include <linux/kernel.h>
-+
-+#include "openswan/ipsec_param.h"
-+
-+#include <linux/major.h>
-+#include <linux/signal.h>
-+#include <linux/sched.h>
-+#include <linux/errno.h>
-+#include <linux/string.h>
-+#include <linux/stat.h>
-+#include <linux/socket.h>
-+#include <linux/un.h>
-+#include <linux/fcntl.h>
-+#include <linux/termios.h>
-+#include <linux/socket.h>
-+#include <linux/sockios.h>
-+#include <linux/net.h> /* struct socket */
-+#include <linux/in.h>
-+#include <linux/fs.h>
-+#ifdef MALLOC_SLAB
-+# include <linux/slab.h> /* kmalloc() */
-+#else /* MALLOC_SLAB */
-+# include <linux/malloc.h> /* kmalloc() */
-+#endif /* MALLOC_SLAB */
-+#include <asm/segment.h>
-+#include <linux/skbuff.h>
-+#include <linux/netdevice.h>
-+#include <net/sock.h> /* struct sock */
-+/* #include <net/tcp.h> */
-+#include <net/af_unix.h>
-+#ifdef CONFIG_PROC_FS
-+# include <linux/proc_fs.h>
-+#endif /* CONFIG_PROC_FS */
-+
-+#include <linux/types.h>
-+
-+#include <openswan.h>
-+#ifdef NET_21
-+# include <asm/uaccess.h>
-+# include <linux/in6.h>
-+#endif /* NET_21 */
-+
-+#include "openswan/radij.h"
-+#include "openswan/ipsec_encap.h"
-+#include "openswan/ipsec_sa.h"
-+
-+#include <pfkeyv2.h>
-+#include <pfkey.h>
-+
-+#include "openswan/ipsec_proto.h"
-+
-+#ifdef CONFIG_IPSEC_DEBUG
-+int debug_pfkey = 0;
-+extern int sysctl_ipsec_debug_verbose;
-+#endif /* CONFIG_IPSEC_DEBUG */
-+
-+#define SENDERR(_x) do { error = -(_x); goto errlab; } while (0)
-+
-+#ifndef SOCKOPS_WRAPPED
-+#define SOCKOPS_WRAPPED(name) name
-+#endif /* SOCKOPS_WRAPPED */
-+
-+extern struct proto_ops pfkey_ops;
-+struct sock *pfkey_sock_list = NULL;
-+struct supported_list *pfkey_supported_list[SADB_SATYPE_MAX+1];
-+
-+struct socket_list *pfkey_open_sockets = NULL;
-+struct socket_list *pfkey_registered_sockets[SADB_SATYPE_MAX+1];
-+
-+int pfkey_msg_interp(struct sock *, struct sadb_msg *, struct sadb_msg **);
-+
-+int
-+pfkey_list_remove_socket(struct socket *socketp, struct socket_list **sockets)
-+{
-+ struct socket_list *socket_listp,*prev;
-+
-+ if(!socketp) {
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_list_remove_socket: "
-+ "NULL socketp handed in, failed.\n");
-+ return -EINVAL;
-+ }
-+
-+ if(!sockets) {
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_list_remove_socket: "
-+ "NULL sockets list handed in, failed.\n");
-+ return -EINVAL;
-+ }
-+
-+ socket_listp = *sockets;
-+ prev = NULL;
-+
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_list_remove_socket: "
-+ "removing sock=0p%p\n",
-+ socketp);
-+
-+ while(socket_listp != NULL) {
-+ if(socket_listp->socketp == socketp) {
-+ if(prev != NULL) {
-+ prev->next = socket_listp->next;
-+ } else {
-+ *sockets = socket_listp->next;
-+ }
-+
-+ kfree((void*)socket_listp);
-+
-+ break;
-+ }
-+ prev = socket_listp;
-+ socket_listp = socket_listp->next;
-+ }
-+
-+ return 0;
-+}
-+
-+int
-+pfkey_list_insert_socket(struct socket *socketp, struct socket_list **sockets)
-+{
-+ struct socket_list *socket_listp;
-+
-+ if(!socketp) {
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_list_insert_socket: "
-+ "NULL socketp handed in, failed.\n");
-+ return -EINVAL;
-+ }
-+
-+ if(!sockets) {
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_list_insert_socket: "
-+ "NULL sockets list handed in, failed.\n");
-+ return -EINVAL;
-+ }
-+
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_list_insert_socket: "
-+ "allocating %lu bytes for socketp=0p%p\n",
-+ (unsigned long) sizeof(struct socket_list),
-+ socketp);
-+
-+ if((socket_listp = (struct socket_list *)kmalloc(sizeof(struct socket_list), GFP_KERNEL)) == NULL) {
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_list_insert_socket: "
-+ "memory allocation error.\n");
-+ return -ENOMEM;
-+ }
-+
-+ socket_listp->socketp = socketp;
-+ socket_listp->next = *sockets;
-+ *sockets = socket_listp;
-+
-+ return 0;
-+}
-+
-+int
-+pfkey_list_remove_supported(struct supported *supported, struct supported_list **supported_list)
-+{
-+ struct supported_list *supported_listp = *supported_list, *prev = NULL;
-+
-+ if(!supported) {
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_list_remove_supported: "
-+ "NULL supported handed in, failed.\n");
-+ return -EINVAL;
-+ }
-+
-+ if(!supported_list) {
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_list_remove_supported: "
-+ "NULL supported_list handed in, failed.\n");
-+ return -EINVAL;
-+ }
-+
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_list_remove_supported: "
-+ "removing supported=0p%p\n",
-+ supported);
-+
-+ while(supported_listp != NULL) {
-+ if(supported_listp->supportedp == supported) {
-+ if(prev != NULL) {
-+ prev->next = supported_listp->next;
-+ } else {
-+ *supported_list = supported_listp->next;
-+ }
-+
-+ kfree((void*)supported_listp);
-+
-+ break;
-+ }
-+ prev = supported_listp;
-+ supported_listp = supported_listp->next;
-+ }
-+
-+ return 0;
-+}
-+
-+int
-+pfkey_list_insert_supported(struct supported *supported, struct supported_list **supported_list)
-+{
-+ struct supported_list *supported_listp;
-+
-+ if(!supported) {
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_list_insert_supported: "
-+ "NULL supported handed in, failed.\n");
-+ return -EINVAL;
-+ }
-+
-+ if(!supported_list) {
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_list_insert_supported: "
-+ "NULL supported_list handed in, failed.\n");
-+ return -EINVAL;
-+ }
-+
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_list_insert_supported: "
-+ "allocating %lu bytes for incoming, supported=0p%p, supported_list=0p%p\n",
-+ (unsigned long) sizeof(struct supported_list),
-+ supported,
-+ supported_list);
-+
-+ supported_listp = (struct supported_list *)kmalloc(sizeof(struct supported_list), GFP_KERNEL);
-+ if(supported_listp == NULL) {
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_list_insert_supported: "
-+ "memory allocation error.\n");
-+ return -ENOMEM;
-+ }
-+
-+ supported_listp->supportedp = supported;
-+ supported_listp->next = *supported_list;
-+ *supported_list = supported_listp;
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_list_insert_supported: "
-+ "outgoing, supported=0p%p, supported_list=0p%p\n",
-+ supported,
-+ supported_list);
-+
-+ return 0;
-+}
-+
-+#ifndef NET_21
-+DEBUG_NO_STATIC void
-+pfkey_state_change(struct sock *sk)
-+{
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_state_change: .\n");
-+ if(!sk->dead) {
-+ wake_up_interruptible(sk->sleep);
-+ }
-+}
-+#endif /* !NET_21 */
-+
-+#ifndef NET_21
-+DEBUG_NO_STATIC void
-+pfkey_data_ready(struct sock *sk, int len)
-+{
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_data_ready: "
-+ "sk=0p%p len=%d\n",
-+ sk,
-+ len);
-+ if(!sk->dead) {
-+ wake_up_interruptible(sk->sleep);
-+ sock_wake_async(sk->socket, 1);
-+ }
-+}
-+
-+DEBUG_NO_STATIC void
-+pfkey_write_space(struct sock *sk)
-+{
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_write_space: .\n");
-+ if(!sk->dead) {
-+ wake_up_interruptible(sk->sleep);
-+ sock_wake_async(sk->socket, 2);
-+ }
-+}
-+#endif /* !NET_21 */
-+
-+DEBUG_NO_STATIC void
-+pfkey_insert_socket(struct sock *sk)
-+{
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_insert_socket: "
-+ "sk=0p%p\n",
-+ sk);
-+ cli();
-+ sk->next=pfkey_sock_list;
-+ pfkey_sock_list=sk;
-+ sti();
-+}
-+
-+DEBUG_NO_STATIC void
-+pfkey_remove_socket(struct sock *sk)
-+{
-+ struct sock **s;
-+
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_remove_socket: .\n");
-+ cli();
-+ s=&pfkey_sock_list;
-+
-+ while(*s!=NULL) {
-+ if(*s==sk) {
-+ *s=sk->next;
-+ sk->next=NULL;
-+ sti();
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_remove_socket: "
-+ "succeeded.\n");
-+ return;
-+ }
-+ s=&((*s)->next);
-+ }
-+ sti();
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_remove_socket: "
-+ "not found.\n");
-+ return;
-+}
-+
-+DEBUG_NO_STATIC void
-+pfkey_destroy_socket(struct sock *sk)
-+{
-+ struct sk_buff *skb;
-+
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_destroy_socket: .\n");
-+ pfkey_remove_socket(sk);
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_destroy_socket: "
-+ "pfkey_remove_socket called.\n");
-+
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_destroy_socket: "
-+ "sk(0p%p)->(&0p%p)receive_queue.{next=0p%p,prev=0p%p}.\n",
-+ sk,
-+ &(sk->receive_queue),
-+ sk->receive_queue.next,
-+ sk->receive_queue.prev);
-+ while(sk && ((skb=skb_dequeue(&(sk->receive_queue)))!=NULL)) {
-+#ifdef NET_21
-+#ifdef CONFIG_IPSEC_DEBUG
-+ if(debug_pfkey && sysctl_ipsec_debug_verbose) {
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_destroy_socket: "
-+ "skb=0p%p dequeued.\n", skb);
-+ printk(KERN_INFO "klips_debug:pfkey_destroy_socket: "
-+ "pfkey_skb contents:");
-+ printk(" next:0p%p", skb->next);
-+ printk(" prev:0p%p", skb->prev);
-+ printk(" list:0p%p", skb->list);
-+ printk(" sk:0p%p", skb->sk);
-+ printk(" stamp:%ld.%ld", skb->stamp.tv_sec, skb->stamp.tv_usec);
-+ printk(" dev:0p%p", skb->dev);
-+ if(skb->dev) {
-+ if(skb->dev->name) {
-+ printk(" dev->name:%s", skb->dev->name);
-+ } else {
-+ printk(" dev->name:NULL?");
-+ }
-+ } else {
-+ printk(" dev:NULL");
-+ }
-+ printk(" h:0p%p", skb->h.raw);
-+ printk(" nh:0p%p", skb->nh.raw);
-+ printk(" mac:0p%p", skb->mac.raw);
-+ printk(" dst:0p%p", skb->dst);
-+ if(sysctl_ipsec_debug_verbose) {
-+ int i;
-+
-+ printk(" cb");
-+ for(i=0; i<48; i++) {
-+ printk(":%2x", skb->cb[i]);
-+ }
-+ }
-+ printk(" len:%d", skb->len);
-+ printk(" csum:%d", skb->csum);
-+#ifndef NETDEV_23
-+ printk(" used:%d", skb->used);
-+ printk(" is_clone:%d", skb->is_clone);
-+#endif /* NETDEV_23 */
-+ printk(" cloned:%d", skb->cloned);
-+ printk(" pkt_type:%d", skb->pkt_type);
-+ printk(" ip_summed:%d", skb->ip_summed);
-+ printk(" priority:%d", skb->priority);
-+ printk(" protocol:%d", skb->protocol);
-+ printk(" security:%d", skb->security);
-+ printk(" truesize:%d", skb->truesize);
-+ printk(" head:0p%p", skb->head);
-+ printk(" data:0p%p", skb->data);
-+ printk(" tail:0p%p", skb->tail);
-+ printk(" end:0p%p", skb->end);
-+ if(sysctl_ipsec_debug_verbose) {
-+ unsigned char* i;
-+ printk(" data");
-+ for(i = skb->head; i < skb->end; i++) {
-+ printk(":%2x", (unsigned char)(*(i)));
-+ }
-+ }
-+ printk(" destructor:0p%p", skb->destructor);
-+ printk("\n");
-+ }
-+#endif /* CONFIG_IPSEC_DEBUG */
-+#endif /* NET_21 */
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_destroy_socket: "
-+ "skb=0p%p freed.\n",
-+ skb);
-+ ipsec_kfree_skb(skb);
-+ }
-+
-+ sk->dead = 1;
-+ sk_free(sk);
-+
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_destroy_socket: destroyed.\n");
-+}
-+
-+int
-+pfkey_upmsg(struct socket *sock, struct sadb_msg *pfkey_msg)
-+{
-+ int error = 0;
-+ struct sk_buff * skb = NULL;
-+ struct sock *sk;
-+
-+ if(sock == NULL) {
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_upmsg: "
-+ "NULL socket passed in.\n");
-+ return -EINVAL;
-+ }
-+
-+ if(pfkey_msg == NULL) {
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_upmsg: "
-+ "NULL pfkey_msg passed in.\n");
-+ return -EINVAL;
-+ }
-+
-+#ifdef NET_21
-+ sk = sock->sk;
-+#else /* NET_21 */
-+ sk = sock->data;
-+#endif /* NET_21 */
-+
-+ if(sk == NULL) {
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_upmsg: "
-+ "NULL sock passed in.\n");
-+ return -EINVAL;
-+ }
-+
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_upmsg: "
-+ "allocating %d bytes...\n",
-+ (int)(pfkey_msg->sadb_msg_len * IPSEC_PFKEYv2_ALIGN));
-+ if(!(skb = alloc_skb(pfkey_msg->sadb_msg_len * IPSEC_PFKEYv2_ALIGN, GFP_ATOMIC) )) {
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_upmsg: "
-+ "no buffers left to send up a message.\n");
-+ return -ENOBUFS;
-+ }
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_upmsg: "
-+ "...allocated at 0p%p.\n",
-+ skb);
-+
-+ skb->dev = NULL;
-+
-+ if(skb_tailroom(skb) < pfkey_msg->sadb_msg_len * IPSEC_PFKEYv2_ALIGN) {
-+ printk(KERN_WARNING "klips_error:pfkey_upmsg: "
-+ "tried to skb_put %ld, %d available. This should never happen, please report.\n",
-+ (unsigned long int)pfkey_msg->sadb_msg_len * IPSEC_PFKEYv2_ALIGN,
-+ skb_tailroom(skb));
-+ ipsec_kfree_skb(skb);
-+ return -ENOBUFS;
-+ }
-+ skb->h.raw = skb_put(skb, pfkey_msg->sadb_msg_len * IPSEC_PFKEYv2_ALIGN);
-+ memcpy(skb->h.raw, pfkey_msg, pfkey_msg->sadb_msg_len * IPSEC_PFKEYv2_ALIGN);
-+
-+#ifndef NET_21
-+ skb->free = 1;
-+#endif /* !NET_21 */
-+
-+ if((error = sock_queue_rcv_skb(sk, skb)) < 0) {
-+ skb->sk=NULL;
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_upmsg: "
-+ "error=%d calling sock_queue_rcv_skb with skb=0p%p.\n",
-+ error,
-+ skb);
-+ ipsec_kfree_skb(skb);
-+ return error;
-+ }
-+ return error;
-+}
-+
-+DEBUG_NO_STATIC int
-+pfkey_create(struct socket *sock, int protocol)
-+{
-+ struct sock *sk;
-+
-+ if(sock == NULL) {
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_create: "
-+ "socket NULL.\n");
-+ return -EINVAL;
-+ }
-+
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_create: "
-+ "sock=0p%p type:%d state:%d flags:%ld protocol:%d\n",
-+ sock,
-+ sock->type,
-+ (unsigned int)(sock->state),
-+ sock->flags, protocol);
-+
-+ if(sock->type != SOCK_RAW) {
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_create: "
-+ "only SOCK_RAW supported.\n");
-+ return -ESOCKTNOSUPPORT;
-+ }
-+
-+ if(protocol != PF_KEY_V2) {
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_create: "
-+ "protocol not PF_KEY_V2.\n");
-+ return -EPROTONOSUPPORT;
-+ }
-+
-+ if((current->uid != 0)) {
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_create: "
-+ "must be root to open pfkey sockets.\n");
-+ return -EACCES;
-+ }
-+
-+#ifdef NET_21
-+ sock->state = SS_UNCONNECTED;
-+#endif /* NET_21 */
-+ MOD_INC_USE_COUNT;
-+#ifdef NET_21
-+ if((sk=(struct sock *)sk_alloc(PF_KEY, GFP_KERNEL, 1)) == NULL)
-+#else /* NET_21 */
-+ if((sk=(struct sock *)sk_alloc(GFP_KERNEL)) == NULL)
-+#endif /* NET_21 */
-+ {
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_create: "
-+ "Out of memory trying to allocate.\n");
-+ MOD_DEC_USE_COUNT;
-+ return -ENOMEM;
-+ }
-+
-+#ifndef NET_21
-+ memset(sk, 0, sizeof(*sk));
-+#endif /* !NET_21 */
-+
-+#ifdef NET_21
-+ sock_init_data(sock, sk);
-+
-+ sk->destruct = NULL;
-+ sk->reuse = 1;
-+ sock->ops = &pfkey_ops;
-+
-+ sk->zapped=0;
-+ sk->family = PF_KEY;
-+/* sk->num = protocol; */
-+ sk->protocol = protocol;
-+ key_pid(sk) = current->pid;
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_create: "
-+ "sock->fasync_list=0p%p sk->sleep=0p%p.\n",
-+ sock->fasync_list,
-+ sk->sleep);
-+#else /* NET_21 */
-+ sk->type=sock->type;
-+ init_timer(&sk->timer);
-+ skb_queue_head_init(&sk->write_queue);
-+ skb_queue_head_init(&sk->receive_queue);
-+ skb_queue_head_init(&sk->back_log);
-+ sk->rcvbuf=SK_RMEM_MAX;
-+ sk->sndbuf=SK_WMEM_MAX;
-+ sk->allocation=GFP_KERNEL;
-+ sk->state=TCP_CLOSE;
-+ sk->priority=SOPRI_NORMAL;
-+ sk->state_change=pfkey_state_change;
-+ sk->data_ready=pfkey_data_ready;
-+ sk->write_space=pfkey_write_space;
-+ sk->error_report=pfkey_state_change;
-+ sk->mtu=4096;
-+ sk->socket=sock;
-+ sock->data=(void *)sk;
-+ sk->sleep=sock->wait;
-+#endif /* NET_21 */
-+
-+ pfkey_insert_socket(sk);
-+ pfkey_list_insert_socket(sock, &pfkey_open_sockets);
-+
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_create: "
-+ "Socket sock=0p%p sk=0p%p initialised.\n", sock, sk);
-+ return 0;
-+}
-+
-+#ifndef NET_21
-+DEBUG_NO_STATIC int
-+pfkey_dup(struct socket *newsock, struct socket *oldsock)
-+{
-+ struct sock *sk;
-+
-+ if(newsock==NULL) {
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_dup: "
-+ "No new socket attached.\n");
-+ return -EINVAL;
-+ }
-+
-+ if(oldsock==NULL) {
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_dup: "
-+ "No old socket attached.\n");
-+ return -EINVAL;
-+ }
-+
-+#ifdef NET_21
-+ sk=oldsock->sk;
-+#else /* NET_21 */
-+ sk=oldsock->data;
-+#endif /* NET_21 */
-+
-+ /* May not have data attached */
-+ if(sk==NULL) {
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_dup: "
-+ "No sock attached to old socket.\n");
-+ return -EINVAL;
-+ }
-+
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_dup: .\n");
-+
-+ return pfkey_create(newsock, sk->protocol);
-+}
-+#endif /* !NET_21 */
-+
-+DEBUG_NO_STATIC int
-+#ifdef NETDEV_23
-+pfkey_release(struct socket *sock)
-+#else /* NETDEV_23 */
-+pfkey_release(struct socket *sock, struct socket *peersock)
-+#endif /* NETDEV_23 */
-+{
-+ struct sock *sk;
-+ int i;
-+
-+ if(sock==NULL) {
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_release: "
-+ "No socket attached.\n");
-+ return 0; /* -EINVAL; */
-+ }
-+
-+#ifdef NET_21
-+ sk=sock->sk;
-+#else /* NET_21 */
-+ sk=sock->data;
-+#endif /* NET_21 */
-+
-+ /* May not have data attached */
-+ if(sk==NULL) {
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_release: "
-+ "No sk attached to sock=0p%p.\n", sock);
-+ return 0; /* -EINVAL; */
-+ }
-+
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_release: "
-+ "sock=0p%p sk=0p%p\n", sock, sk);
-+
-+#ifdef NET_21
-+ if(!sk->dead)
-+#endif /* NET_21 */
-+ if(sk->state_change) {
-+ sk->state_change(sk);
-+ }
-+
-+#ifdef NET_21
-+ sock->sk = NULL;
-+#else /* NET_21 */
-+ sock->data = NULL;
-+#endif /* NET_21 */
-+
-+ /* Try to flush out this socket. Throw out buffers at least */
-+ pfkey_destroy_socket(sk);
-+ pfkey_list_remove_socket(sock, &pfkey_open_sockets);
-+ for(i = SADB_SATYPE_UNSPEC; i <= SADB_SATYPE_MAX; i++) {
-+ pfkey_list_remove_socket(sock, &(pfkey_registered_sockets[i]));
-+ }
-+
-+ MOD_DEC_USE_COUNT;
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_release: "
-+ "succeeded.\n");
-+
-+ return 0;
-+}
-+
-+#ifndef NET_21
-+DEBUG_NO_STATIC int
-+pfkey_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
-+{
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_bind: "
-+ "operation not supported.\n");
-+ return -EINVAL;
-+}
-+
-+DEBUG_NO_STATIC int
-+pfkey_connect(struct socket *sock, struct sockaddr *uaddr, int addr_len, int flags)
-+{
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_connect: "
-+ "operation not supported.\n");
-+ return -EINVAL;
-+}
-+
-+DEBUG_NO_STATIC int
-+pfkey_socketpair(struct socket *a, struct socket *b)
-+{
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_socketpair: "
-+ "operation not supported.\n");
-+ return -EINVAL;
-+}
-+
-+DEBUG_NO_STATIC int
-+pfkey_accept(struct socket *sock, struct socket *newsock, int flags)
-+{
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_aaccept: "
-+ "operation not supported.\n");
-+ return -EINVAL;
-+}
-+
-+DEBUG_NO_STATIC int
-+pfkey_getname(struct socket *sock, struct sockaddr *uaddr, int *uaddr_len,
-+ int peer)
-+{
-+ struct sockaddr *ska = (struct sockaddr*)uaddr;
-+
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_getname: .\n");
-+ ska->sa_family = PF_KEY;
-+ *uaddr_len = sizeof(*ska);
-+ return 0;
-+}
-+
-+DEBUG_NO_STATIC int
-+pfkey_select(struct socket *sock, int sel_type, select_table *wait)
-+{
-+
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_select: "
-+ ".sock=0p%p sk=0p%p sel_type=%d\n",
-+ sock,
-+ sock->data,
-+ sel_type);
-+ if(sock == NULL) {
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_select: "
-+ "Null socket passed in.\n");
-+ return -EINVAL;
-+ }
-+ return datagram_select(sock->data, sel_type, wait);
-+}
-+
-+DEBUG_NO_STATIC int
-+pfkey_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
-+{
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_ioctl: "
-+ "not supported.\n");
-+ return -EINVAL;
-+}
-+
-+DEBUG_NO_STATIC int
-+pfkey_listen(struct socket *sock, int backlog)
-+{
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_listen: "
-+ "not supported.\n");
-+ return -EINVAL;
-+}
-+#endif /* !NET_21 */
-+
-+DEBUG_NO_STATIC int
-+pfkey_shutdown(struct socket *sock, int mode)
-+{
-+ struct sock *sk;
-+
-+ if(sock == NULL) {
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_shutdown: "
-+ "NULL socket passed in.\n");
-+ return -EINVAL;
-+ }
-+
-+#ifdef NET_21
-+ sk=sock->sk;
-+#else /* NET_21 */
-+ sk=sock->data;
-+#endif /* NET_21 */
-+
-+ if(sk == NULL) {
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_shutdown: "
-+ "No sock attached to socket.\n");
-+ return -EINVAL;
-+ }
-+
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_shutdown: "
-+ "mode=%x.\n", mode);
-+ mode++;
-+
-+ if(mode&SEND_SHUTDOWN) {
-+ sk->shutdown|=SEND_SHUTDOWN;
-+ sk->state_change(sk);
-+ }
-+
-+ if(mode&RCV_SHUTDOWN) {
-+ sk->shutdown|=RCV_SHUTDOWN;
-+ sk->state_change(sk);
-+ }
-+ return 0;
-+}
-+
-+#ifndef NET_21
-+DEBUG_NO_STATIC int
-+pfkey_setsockopt(struct socket *sock, int level, int optname, char *optval, int optlen)
-+{
-+#ifndef NET_21
-+ struct sock *sk;
-+
-+ if(sock == NULL) {
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_setsockopt: "
-+ "Null socket passed in.\n");
-+ return -EINVAL;
-+ }
-+
-+ sk=sock->data;
-+
-+ if(sk == NULL) {
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_setsockopt: "
-+ "Null sock passed in.\n");
-+ return -EINVAL;
-+ }
-+#endif /* !NET_21 */
-+
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_setsockopt: .\n");
-+ if(level!=SOL_SOCKET) {
-+ return -EOPNOTSUPP;
-+ }
-+#ifdef NET_21
-+ return sock_setsockopt(sock, level, optname, optval, optlen);
-+#else /* NET_21 */
-+ return sock_setsockopt(sk, level, optname, optval, optlen);
-+#endif /* NET_21 */
-+}
-+
-+DEBUG_NO_STATIC int
-+pfkey_getsockopt(struct socket *sock, int level, int optname, char *optval, int *optlen)
-+{
-+#ifndef NET_21
-+ struct sock *sk;
-+
-+ if(sock == NULL) {
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_setsockopt: "
-+ "Null socket passed in.\n");
-+ return -EINVAL;
-+ }
-+
-+ sk=sock->data;
-+
-+ if(sk == NULL) {
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_setsockopt: "
-+ "Null sock passed in.\n");
-+ return -EINVAL;
-+ }
-+#endif /* !NET_21 */
-+
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_getsockopt: .\n");
-+ if(level!=SOL_SOCKET) {
-+ return -EOPNOTSUPP;
-+ }
-+#ifdef NET_21
-+ return sock_getsockopt(sock, level, optname, optval, optlen);
-+#else /* NET_21 */
-+ return sock_getsockopt(sk, level, optname, optval, optlen);
-+#endif /* NET_21 */
-+}
-+
-+DEBUG_NO_STATIC int
-+pfkey_fcntl(struct socket *sock, unsigned int cmd, unsigned long arg)
-+{
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_fcntl: "
-+ "not supported.\n");
-+ return -EINVAL;
-+}
-+#endif /* !NET_21 */
-+
-+/*
-+ * Send PF_KEY data down.
-+ */
-+
-+DEBUG_NO_STATIC int
-+#ifdef NET_21
-+pfkey_sendmsg(struct socket *sock, struct msghdr *msg, int len, struct scm_cookie *scm)
-+#else /* NET_21 */
-+pfkey_sendmsg(struct socket *sock, struct msghdr *msg, int len, int nonblock, int flags)
-+#endif /* NET_21 */
-+{
-+ struct sock *sk;
-+ int error = 0;
-+ struct sadb_msg *pfkey_msg = NULL, *pfkey_reply = NULL;
-+
-+ if(sock == NULL) {
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_sendmsg: "
-+ "Null socket passed in.\n");
-+ SENDERR(EINVAL);
-+ }
-+
-+#ifdef NET_21
-+ sk = sock->sk;
-+#else /* NET_21 */
-+ sk = sock->data;
-+#endif /* NET_21 */
-+
-+ if(sk == NULL) {
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_sendmsg: "
-+ "Null sock passed in.\n");
-+ SENDERR(EINVAL);
-+ }
-+
-+ if(msg == NULL) {
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_sendmsg: "
-+ "Null msghdr passed in.\n");
-+ SENDERR(EINVAL);
-+ }
-+
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_sendmsg: .\n");
-+ if(sk->err) {
-+ error = sock_error(sk);
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_sendmsg: "
-+ "sk->err is non-zero, returns %d.\n",
-+ error);
-+ SENDERR(-error);
-+ }
-+
-+ if((current->uid != 0)) {
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_sendmsg: "
-+ "must be root to send messages to pfkey sockets.\n");
-+ SENDERR(EACCES);
-+ }
-+
-+#ifdef NET_21
-+ if(msg->msg_control)
-+#else /* NET_21 */
-+ if(flags || msg->msg_control)
-+#endif /* NET_21 */
-+ {
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_sendmsg: "
-+ "can't set flags or set msg_control.\n");
-+ SENDERR(EINVAL);
-+ }
-+
-+ if(sk->shutdown & SEND_SHUTDOWN) {
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_sendmsg: "
-+ "shutdown.\n");
-+ send_sig(SIGPIPE, current, 0);
-+ SENDERR(EPIPE);
-+ }
-+
-+ if(len < sizeof(struct sadb_msg)) {
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_sendmsg: "
-+ "bogus msg len of %d, too small.\n", len);
-+ SENDERR(EMSGSIZE);
-+ }
-+
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_sendmsg: "
-+ "allocating %d bytes for downward message.\n",
-+ len);
-+ if((pfkey_msg = (struct sadb_msg*)kmalloc(len, GFP_KERNEL)) == NULL) {
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_sendmsg: "
-+ "memory allocation error.\n");
-+ SENDERR(ENOBUFS);
-+ }
-+
-+ memcpy_fromiovec((void *)pfkey_msg, msg->msg_iov, len);
-+
-+ if(pfkey_msg->sadb_msg_version != PF_KEY_V2) {
-+ KLIPS_PRINT(1 || debug_pfkey,
-+ "klips_debug:pfkey_sendmsg: "
-+ "not PF_KEY_V2 msg, found %d, should be %d.\n",
-+ pfkey_msg->sadb_msg_version,
-+ PF_KEY_V2);
-+ kfree((void*)pfkey_msg);
-+ return -EINVAL;
-+ }
-+
-+ if(len != pfkey_msg->sadb_msg_len * IPSEC_PFKEYv2_ALIGN) {
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_sendmsg: "
-+ "bogus msg len of %d, not %d byte aligned.\n",
-+ len, (int)IPSEC_PFKEYv2_ALIGN);
-+ SENDERR(EMSGSIZE);
-+ }
-+
-+#if 0
-+ /* This check is questionable, since a downward message could be
-+ the result of an ACQUIRE either from kernel (PID==0) or
-+ userspace (some other PID). */
-+ /* check PID */
-+ if(pfkey_msg->sadb_msg_pid != current->pid) {
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_sendmsg: "
-+ "pid (%d) does not equal sending process pid (%d).\n",
-+ pfkey_msg->sadb_msg_pid, current->pid);
-+ SENDERR(EINVAL);
-+ }
-+#endif
-+
-+ if(pfkey_msg->sadb_msg_reserved) {
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_sendmsg: "
-+ "reserved field must be zero, set to %d.\n",
-+ pfkey_msg->sadb_msg_reserved);
-+ SENDERR(EINVAL);
-+ }
-+
-+ if((pfkey_msg->sadb_msg_type > SADB_MAX) || (!pfkey_msg->sadb_msg_type)){
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_sendmsg: "
-+ "msg type too large or small:%d.\n",
-+ pfkey_msg->sadb_msg_type);
-+ SENDERR(EINVAL);
-+ }
-+
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_sendmsg: "
-+ "msg sent for parsing.\n");
-+
-+ if((error = pfkey_msg_interp(sk, pfkey_msg, &pfkey_reply))) {
-+ struct socket_list *pfkey_socketsp;
-+
-+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_sendmsg: "
-+ "pfkey_msg_parse returns %d.\n",
-+ error);
-+
-+ if((pfkey_reply = (struct sadb_msg*)kmalloc(sizeof(struct sadb_msg), GFP_KERNEL)) == NULL) {
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_sendmsg: "
-+ "memory allocation error.\n");
-+ SENDERR(ENOBUFS);
-+ }
-+ memcpy((void*)pfkey_reply, (void*)pfkey_msg, sizeof(struct sadb_msg));
-+ pfkey_reply->sadb_msg_errno = -error;
-+ pfkey_reply->sadb_msg_len = sizeof(struct sadb_msg) / IPSEC_PFKEYv2_ALIGN;
-+
-+ for(pfkey_socketsp = pfkey_open_sockets;
-+ pfkey_socketsp;
-+ pfkey_socketsp = pfkey_socketsp->next) {
-+ int error_upmsg = 0;
-+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_sendmsg: "
-+ "sending up error=%d message=0p%p to socket=0p%p.\n",
-+ error,
-+ pfkey_reply,
-+ pfkey_socketsp->socketp);
-+ if((error_upmsg = pfkey_upmsg(pfkey_socketsp->socketp, pfkey_reply))) {
-+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_sendmsg: "
-+ "sending up error message to socket=0p%p failed with error=%d.\n",
-+ pfkey_socketsp->socketp,
-+ error_upmsg);
-+ /* pfkey_msg_free(&pfkey_reply); */
-+ /* SENDERR(-error); */
-+ }
-+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_sendmsg: "
-+ "sending up error message to socket=0p%p succeeded.\n",
-+ pfkey_socketsp->socketp);
-+ }
-+
-+ pfkey_msg_free(&pfkey_reply);
-+
-+ SENDERR(-error);
-+ }
-+
-+ errlab:
-+ if (pfkey_msg) {
-+ kfree((void*)pfkey_msg);
-+ }
-+
-+ if(error) {
-+ return error;
-+ } else {
-+ return len;
-+ }
-+}
-+
-+/*
-+ * Receive PF_KEY data up.
-+ */
-+
-+DEBUG_NO_STATIC int
-+#ifdef NET_21
-+pfkey_recvmsg(struct socket *sock, struct msghdr *msg, int size, int flags, struct scm_cookie *scm)
-+#else /* NET_21 */
-+pfkey_recvmsg(struct socket *sock, struct msghdr *msg, int size, int noblock, int flags, int *addr_len)
-+#endif /* NET_21 */
-+{
-+ struct sock *sk;
-+#ifdef NET_21
-+ int noblock = flags & MSG_DONTWAIT;
-+#endif /* NET_21 */
-+ struct sk_buff *skb;
-+ int error;
-+
-+ if(sock == NULL) {
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_recvmsg: "
-+ "Null socket passed in.\n");
-+ return -EINVAL;
-+ }
-+
-+#ifdef NET_21
-+ sk = sock->sk;
-+#else /* NET_21 */
-+ sk = sock->data;
-+#endif /* NET_21 */
-+
-+ if(sk == NULL) {
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_recvmsg: "
-+ "Null sock passed in for sock=0p%p.\n", sock);
-+ return -EINVAL;
-+ }
-+
-+ if(msg == NULL) {
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_recvmsg: "
-+ "Null msghdr passed in for sock=0p%p, sk=0p%p.\n",
-+ sock, sk);
-+ return -EINVAL;
-+ }
-+
-+ KLIPS_PRINT(debug_pfkey && sysctl_ipsec_debug_verbose,
-+ "klips_debug:pfkey_recvmsg: sock=0p%p sk=0p%p msg=0p%p size=%d.\n",
-+ sock, sk, msg, size);
-+ if(flags & ~MSG_PEEK) {
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_sendmsg: "
-+ "flags (%d) other than MSG_PEEK not supported.\n",
-+ flags);
-+ return -EOPNOTSUPP;
-+ }
-+
-+#ifdef NET_21
-+ msg->msg_namelen = 0; /* sizeof(*ska); */
-+#else /* NET_21 */
-+ if(addr_len) {
-+ *addr_len = 0; /* sizeof(*ska); */
-+ }
-+#endif /* NET_21 */
-+
-+ if(sk->err) {
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_sendmsg: "
-+ "sk->err=%d.\n", sk->err);
-+ return sock_error(sk);
-+ }
-+
-+ if((skb = skb_recv_datagram(sk, flags, noblock, &error) ) == NULL) {
-+ return error;
-+ }
-+
-+ if(size > skb->len) {
-+ size = skb->len;
-+ }
-+#ifdef NET_21
-+ else if(size <skb->len) {
-+ msg->msg_flags |= MSG_TRUNC;
-+ }
-+#endif /* NET_21 */
-+
-+ skb_copy_datagram_iovec(skb, 0, msg->msg_iov, size);
-+ sk->stamp=skb->stamp;
-+
-+ skb_free_datagram(sk, skb);
-+ return size;
-+}
-+
-+#ifdef NET_21
-+struct net_proto_family pfkey_family_ops = {
-+ PF_KEY,
-+ pfkey_create
-+};
-+
-+struct proto_ops SOCKOPS_WRAPPED(pfkey_ops) = {
-+#ifdef NETDEV_23
-+ family: PF_KEY,
-+ release: pfkey_release,
-+ bind: sock_no_bind,
-+ connect: sock_no_connect,
-+ socketpair: sock_no_socketpair,
-+ accept: sock_no_accept,
-+ getname: sock_no_getname,
-+ poll: datagram_poll,
-+ ioctl: sock_no_ioctl,
-+ listen: sock_no_listen,
-+ shutdown: pfkey_shutdown,
-+ setsockopt: sock_no_setsockopt,
-+ getsockopt: sock_no_getsockopt,
-+ sendmsg: pfkey_sendmsg,
-+ recvmsg: pfkey_recvmsg,
-+ mmap: sock_no_mmap,
-+#else /* NETDEV_23 */
-+ PF_KEY,
-+ sock_no_dup,
-+ pfkey_release,
-+ sock_no_bind,
-+ sock_no_connect,
-+ sock_no_socketpair,
-+ sock_no_accept,
-+ sock_no_getname,
-+ datagram_poll,
-+ sock_no_ioctl,
-+ sock_no_listen,
-+ pfkey_shutdown,
-+ sock_no_setsockopt,
-+ sock_no_getsockopt,
-+ sock_no_fcntl,
-+ pfkey_sendmsg,
-+ pfkey_recvmsg
-+#endif /* NETDEV_23 */
-+};
-+
-+#ifdef NETDEV_23
-+#include <linux/smp_lock.h>
-+SOCKOPS_WRAP(pfkey, PF_KEY);
-+#endif /* NETDEV_23 */
-+
-+#else /* NET_21 */
-+struct proto_ops pfkey_proto_ops = {
-+ PF_KEY,
-+ pfkey_create,
-+ pfkey_dup,
-+ pfkey_release,
-+ pfkey_bind,
-+ pfkey_connect,
-+ pfkey_socketpair,
-+ pfkey_accept,
-+ pfkey_getname,
-+ pfkey_select,
-+ pfkey_ioctl,
-+ pfkey_listen,
-+ pfkey_shutdown,
-+ pfkey_setsockopt,
-+ pfkey_getsockopt,
-+ pfkey_fcntl,
-+ pfkey_sendmsg,
-+ pfkey_recvmsg
-+};
-+#endif /* NET_21 */
-+
-+#ifdef CONFIG_PROC_FS
-+#ifndef PROC_FS_2325
-+DEBUG_NO_STATIC
-+#endif /* PROC_FS_2325 */
-+int
-+pfkey_get_info(char *buffer, char **start, off_t offset, int length
-+#ifndef PROC_NO_DUMMY
-+, int dummy
-+#endif /* !PROC_NO_DUMMY */
-+)
-+{
-+ const int max_content = length > 0? length-1 : 0;
-+ off_t begin=0;
-+ int len=0;
-+ struct sock *sk=pfkey_sock_list;
-+
-+#ifdef CONFIG_IPSEC_DEBUG
-+ if(!sysctl_ipsec_debug_verbose) {
-+#endif /* CONFIG_IPSEC_DEBUG */
-+ len+= snprintf(buffer,length,
-+ " sock pid socket next prev e n p sndbf Flags Type St\n");
-+#ifdef CONFIG_IPSEC_DEBUG
-+ } else {
-+ len+= snprintf(buffer,length,
-+ " sock pid d sleep socket next prev e r z n p sndbf stamp Flags Type St\n");
-+ }
-+#endif /* CONFIG_IPSEC_DEBUG */
-+
-+ while(sk!=NULL) {
-+#ifdef CONFIG_IPSEC_DEBUG
-+ if(!sysctl_ipsec_debug_verbose) {
-+#endif /* CONFIG_IPSEC_DEBUG */
-+ len += ipsec_snprintf(buffer+len, length-len,
-+ "%8p %5d %8p %8p %8p %d %d %d %5d %08lX %8X %2X\n",
-+ sk,
-+ key_pid(sk),
-+ sk->socket,
-+ sk->next,
-+ sk->prev,
-+ sk->err,
-+ sk->num,
-+ sk->protocol,
-+ sk->sndbuf,
-+ sk->socket->flags,
-+ sk->socket->type,
-+ sk->socket->state);
-+#ifdef CONFIG_IPSEC_DEBUG
-+ } else {
-+ len += ipsec_snprintf(buffer+len, length-len,
-+ "%8p %5d %d %8p %8p %8p %8p %d %d %d %d %d %5d %d.%06d %08lX %8X %2X\n",
-+ sk,
-+ key_pid(sk),
-+ sk->dead,
-+ sk->sleep,
-+ sk->socket,
-+ sk->next,
-+ sk->prev,
-+ sk->err,
-+ sk->reuse,
-+ sk->zapped,
-+ sk->num,
-+ sk->protocol,
-+ sk->sndbuf,
-+ (unsigned int)sk->stamp.tv_sec,
-+ (unsigned int)sk->stamp.tv_usec,
-+ sk->socket->flags,
-+ sk->socket->type,
-+ sk->socket->state);
-+ }
-+#endif /* CONFIG_IPSEC_DEBUG */
-+
-+ if (len >= max_content) {
-+ /* we've done all that can fit -- stop loop */
-+ len = max_content; /* truncate crap */
-+ break;
-+ } else {
-+
-+ const off_t pos = begin + len; /* file position of end of what we've generated */
-+
-+ if (pos <= offset) {
-+ /* all is before first interesting character:
-+ * discard, but note where we are.
-+ */
-+ len = 0;
-+ begin = pos;
-+ }
-+ }
-+ sk=sk->next;
-+
-+ }
-+
-+ *start = buffer + (offset - begin); /* Start of wanted data */
-+ return len - (offset - begin);
-+
-+}
-+
-+#ifndef PROC_FS_2325
-+DEBUG_NO_STATIC
-+#endif /* PROC_FS_2325 */
-+int
-+pfkey_supported_get_info(char *buffer, char **start, off_t offset, int length
-+#ifndef PROC_NO_DUMMY
-+, int dummy
-+#endif /* !PROC_NO_DUMMY */
-+)
-+{
-+ const int max_content = length > 0? length-1 : 0;
-+ off_t begin=0;
-+ int len=0;
-+ int satype;
-+ struct supported_list *pfkey_supported_p;
-+
-+ len += ipsec_snprintf(buffer, length,
-+ "satype exttype alg_id ivlen minbits maxbits\n");
-+
-+ for(satype = SADB_SATYPE_UNSPEC; satype <= SADB_SATYPE_MAX; satype++) {
-+ pfkey_supported_p = pfkey_supported_list[satype];
-+ while(pfkey_supported_p) {
-+ len += ipsec_snprintf(buffer+len, length-len,
-+ " %2d %2d %2d %3d %3d %3d\n",
-+ satype,
-+ pfkey_supported_p->supportedp->supported_alg_exttype,
-+ pfkey_supported_p->supportedp->supported_alg_id,
-+ pfkey_supported_p->supportedp->supported_alg_ivlen,
-+ pfkey_supported_p->supportedp->supported_alg_minbits,
-+ pfkey_supported_p->supportedp->supported_alg_maxbits);
-+
-+ if (len >= max_content) {
-+ /* we've done all that can fit -- stop loop */
-+ len = max_content; /* truncate crap */
-+ break;
-+ } else {
-+ const off_t pos = begin + len; /* file position of end of what we've generated */
-+
-+ if (pos <= offset) {
-+ /* all is before first interesting character:
-+ * discard, but note where we are.
-+ */
-+ len = 0;
-+ begin = pos;
-+ }
-+ }
-+
-+ pfkey_supported_p = pfkey_supported_p->next;
-+ }
-+ }
-+
-+ *start = buffer + (offset - begin); /* Start of wanted data */
-+ return len - (offset - begin);
-+
-+}
-+
-+#ifndef PROC_FS_2325
-+DEBUG_NO_STATIC
-+#endif /* PROC_FS_2325 */
-+int
-+pfkey_registered_get_info(char *buffer, char **start, off_t offset, int length
-+#ifndef PROC_NO_DUMMY
-+, int dummy
-+#endif /* !PROC_NO_DUMMY */
-+)
-+{
-+ const int max_content = length > 0? length-1 : 0;
-+ off_t begin=0;
-+ int len=0;
-+ int satype;
-+ struct socket_list *pfkey_sockets;
-+
-+ len += ipsec_snprintf(buffer, length,
-+ "satype socket pid sk\n");
-+
-+ for(satype = SADB_SATYPE_UNSPEC; satype <= SADB_SATYPE_MAX; satype++) {
-+ pfkey_sockets = pfkey_registered_sockets[satype];
-+ while(pfkey_sockets) {
-+#ifdef NET_21
-+ len += ipsec_snprintf(buffer+len, length-len,
-+ " %2d %8p %5d %8p\n",
-+ satype,
-+ pfkey_sockets->socketp,
-+ key_pid(pfkey_sockets->socketp->sk),
-+ pfkey_sockets->socketp->sk);
-+#else /* NET_21 */
-+ len += ipsec_snprintf(buffer+len, length-len,
-+ " %2d %8p N/A %8p\n",
-+ satype,
-+ pfkey_sockets->socketp,
-+#if 0
-+ key_pid((pfkey_sockets->socketp)->data),
-+#endif
-+ (pfkey_sockets->socketp)->data);
-+#endif /* NET_21 */
-+
-+ if (len >= max_content) {
-+ /* we've done all that can fit -- stop loop (could stop two) */
-+ len = max_content; /* truncate crap */
-+ break;
-+ } else {
-+ const off_t pos = begin + len; /* file position of end of what we've generated */
-+
-+ if (pos <= offset) {
-+ /* all is before first interesting character:
-+ * discard, but note where we are.
-+ */
-+ len = 0;
-+ begin = pos;
-+ }
-+ }
-+
-+
-+ pfkey_sockets = pfkey_sockets->next;
-+ }
-+ }
-+ *start = buffer + (offset - begin); /* Start of wanted data */
-+ return len - (offset - begin);
-+}
-+
-+#ifndef PROC_FS_2325
-+struct proc_dir_entry proc_net_pfkey =
-+{
-+ 0,
-+ 6, "pf_key",
-+ S_IFREG | S_IRUGO, 1, 0, 0,
-+ 0, &proc_net_inode_operations,
-+ pfkey_get_info
-+};
-+struct proc_dir_entry proc_net_pfkey_supported =
-+{
-+ 0,
-+ 16, "pf_key_supported",
-+ S_IFREG | S_IRUGO, 1, 0, 0,
-+ 0, &proc_net_inode_operations,
-+ pfkey_supported_get_info
-+};
-+struct proc_dir_entry proc_net_pfkey_registered =
-+{
-+ 0,
-+ 17, "pf_key_registered",
-+ S_IFREG | S_IRUGO, 1, 0, 0,
-+ 0, &proc_net_inode_operations,
-+ pfkey_registered_get_info
-+};
-+#endif /* !PROC_FS_2325 */
-+#endif /* CONFIG_PROC_FS */
-+
-+DEBUG_NO_STATIC int
-+supported_add_all(int satype, struct supported supported[], int size)
-+{
-+ int i;
-+ int error = 0;
-+
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:init_pfkey: "
-+ "sizeof(supported_init_<satype=%d>)[%d]/sizeof(struct supported)[%d]=%d.\n",
-+ satype,
-+ size,
-+ (int)sizeof(struct supported),
-+ (int)(size/sizeof(struct supported)));
-+
-+ for(i = 0; i < size / sizeof(struct supported); i++) {
-+
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:init_pfkey: "
-+ "i=%d inserting satype=%d exttype=%d id=%d ivlen=%d minbits=%d maxbits=%d.\n",
-+ i,
-+ satype,
-+ supported[i].supported_alg_exttype,
-+ supported[i].supported_alg_id,
-+ supported[i].supported_alg_ivlen,
-+ supported[i].supported_alg_minbits,
-+ supported[i].supported_alg_maxbits);
-+
-+ error |= pfkey_list_insert_supported(&(supported[i]),
-+ &(pfkey_supported_list[satype]));
-+ }
-+ return error;
-+}
-+
-+DEBUG_NO_STATIC int
-+supported_remove_all(int satype)
-+{
-+ int error = 0;
-+ struct supported*supportedp;
-+
-+ while(pfkey_supported_list[satype]) {
-+ supportedp = pfkey_supported_list[satype]->supportedp;
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:init_pfkey: "
-+ "removing satype=%d exttype=%d id=%d ivlen=%d minbits=%d maxbits=%d.\n",
-+ satype,
-+ supportedp->supported_alg_exttype,
-+ supportedp->supported_alg_id,
-+ supportedp->supported_alg_ivlen,
-+ supportedp->supported_alg_minbits,
-+ supportedp->supported_alg_maxbits);
-+
-+ error |= pfkey_list_remove_supported(supportedp,
-+ &(pfkey_supported_list[satype]));
-+ }
-+ return error;
-+}
-+
-+int
-+pfkey_init(void)
-+{
-+ int error = 0;
-+ int i;
-+
-+ static struct supported supported_init_ah[] = {
-+#ifdef CONFIG_IPSEC_AUTH_HMAC_MD5
-+ {SADB_EXT_SUPPORTED_AUTH, SADB_AALG_MD5HMAC, 0, 128, 128},
-+#endif /* CONFIG_IPSEC_AUTH_HMAC_MD5 */
-+#ifdef CONFIG_IPSEC_AUTH_HMAC_SHA1
-+ {SADB_EXT_SUPPORTED_AUTH, SADB_AALG_SHA1HMAC, 0, 160, 160}
-+#endif /* CONFIG_IPSEC_AUTH_HMAC_SHA1 */
-+ };
-+ static struct supported supported_init_esp[] = {
-+#ifdef CONFIG_IPSEC_AUTH_HMAC_MD5
-+ {SADB_EXT_SUPPORTED_AUTH, SADB_AALG_MD5HMAC, 0, 128, 128},
-+#endif /* CONFIG_IPSEC_AUTH_HMAC_MD5 */
-+#ifdef CONFIG_IPSEC_AUTH_HMAC_SHA1
-+ {SADB_EXT_SUPPORTED_AUTH, SADB_AALG_SHA1HMAC, 0, 160, 160},
-+#endif /* CONFIG_IPSEC_AUTH_HMAC_SHA1 */
-+#ifdef CONFIG_IPSEC_ENC_3DES
-+ {SADB_EXT_SUPPORTED_ENCRYPT, SADB_EALG_3DESCBC, 64, 168, 168},
-+#endif /* CONFIG_IPSEC_ENC_3DES */
-+ };
-+ static struct supported supported_init_ipip[] = {
-+ {SADB_EXT_SUPPORTED_ENCRYPT, SADB_X_TALG_IPv4_in_IPv4, 0, 32, 32}
-+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
-+ , {SADB_EXT_SUPPORTED_ENCRYPT, SADB_X_TALG_IPv6_in_IPv4, 0, 128, 32}
-+ , {SADB_EXT_SUPPORTED_ENCRYPT, SADB_X_TALG_IPv4_in_IPv6, 0, 32, 128}
-+ , {SADB_EXT_SUPPORTED_ENCRYPT, SADB_X_TALG_IPv6_in_IPv6, 0, 128, 128}
-+#endif /* defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) */
-+ };
-+#ifdef CONFIG_IPSEC_IPCOMP
-+ static struct supported supported_init_ipcomp[] = {
-+ {SADB_EXT_SUPPORTED_ENCRYPT, SADB_X_CALG_DEFLATE, 0, 1, 1}
-+ };
-+#endif /* CONFIG_IPSEC_IPCOMP */
-+
-+#if 0
-+ printk(KERN_INFO
-+ "klips_info:pfkey_init: "
-+ "FreeS/WAN: initialising PF_KEYv2 domain sockets.\n");
-+#endif
-+
-+ for(i = SADB_SATYPE_UNSPEC; i <= SADB_SATYPE_MAX; i++) {
-+ pfkey_registered_sockets[i] = NULL;
-+ pfkey_supported_list[i] = NULL;
-+ }
-+
-+ error |= supported_add_all(SADB_SATYPE_AH, supported_init_ah, sizeof(supported_init_ah));
-+ error |= supported_add_all(SADB_SATYPE_ESP, supported_init_esp, sizeof(supported_init_esp));
-+#ifdef CONFIG_IPSEC_IPCOMP
-+ error |= supported_add_all(SADB_X_SATYPE_COMP, supported_init_ipcomp, sizeof(supported_init_ipcomp));
-+#endif /* CONFIG_IPSEC_IPCOMP */
-+ error |= supported_add_all(SADB_X_SATYPE_IPIP, supported_init_ipip, sizeof(supported_init_ipip));
-+
-+#ifdef NET_21
-+ error |= sock_register(&pfkey_family_ops);
-+#else /* NET_21 */
-+ error |= sock_register(pfkey_proto_ops.family, &pfkey_proto_ops);
-+#endif /* NET_21 */
-+
-+#ifdef CONFIG_PROC_FS
-+# ifndef PROC_FS_2325
-+# ifdef PROC_FS_21
-+ error |= proc_register(proc_net, &proc_net_pfkey);
-+ error |= proc_register(proc_net, &proc_net_pfkey_supported);
-+ error |= proc_register(proc_net, &proc_net_pfkey_registered);
-+# else /* PROC_FS_21 */
-+ error |= proc_register_dynamic(&proc_net, &proc_net_pfkey);
-+ error |= proc_register_dynamic(&proc_net, &proc_net_pfkey_supported);
-+ error |= proc_register_dynamic(&proc_net, &proc_net_pfkey_registered);
-+# endif /* PROC_FS_21 */
-+# else /* !PROC_FS_2325 */
-+ proc_net_create ("pf_key", 0, pfkey_get_info);
-+ proc_net_create ("pf_key_supported", 0, pfkey_supported_get_info);
-+ proc_net_create ("pf_key_registered", 0, pfkey_registered_get_info);
-+# endif /* !PROC_FS_2325 */
-+#endif /* CONFIG_PROC_FS */
-+
-+ return error;
-+}
-+
-+int
-+pfkey_cleanup(void)
-+{
-+ int error = 0;
-+
-+ printk(KERN_INFO "klips_info:pfkey_cleanup: "
-+ "shutting down PF_KEY domain sockets.\n");
-+#ifdef NET_21
-+ error |= sock_unregister(PF_KEY);
-+#else /* NET_21 */
-+ error |= sock_unregister(pfkey_proto_ops.family);
-+#endif /* NET_21 */
-+
-+ error |= supported_remove_all(SADB_SATYPE_AH);
-+ error |= supported_remove_all(SADB_SATYPE_ESP);
-+#ifdef CONFIG_IPSEC_IPCOMP
-+ error |= supported_remove_all(SADB_X_SATYPE_COMP);
-+#endif /* CONFIG_IPSEC_IPCOMP */
-+ error |= supported_remove_all(SADB_X_SATYPE_IPIP);
-+
-+#ifdef CONFIG_PROC_FS
-+# ifndef PROC_FS_2325
-+ if (proc_net_unregister(proc_net_pfkey.low_ino) != 0)
-+ printk("klips_debug:pfkey_cleanup: "
-+ "cannot unregister /proc/net/pf_key\n");
-+ if (proc_net_unregister(proc_net_pfkey_supported.low_ino) != 0)
-+ printk("klips_debug:pfkey_cleanup: "
-+ "cannot unregister /proc/net/pf_key_supported\n");
-+ if (proc_net_unregister(proc_net_pfkey_registered.low_ino) != 0)
-+ printk("klips_debug:pfkey_cleanup: "
-+ "cannot unregister /proc/net/pf_key_registered\n");
-+# else /* !PROC_FS_2325 */
-+ proc_net_remove ("pf_key");
-+ proc_net_remove ("pf_key_supported");
-+ proc_net_remove ("pf_key_registered");
-+# endif /* !PROC_FS_2325 */
-+#endif /* CONFIG_PROC_FS */
-+
-+ /* other module unloading cleanup happens here */
-+ return error;
-+}
-+
-+#ifdef MODULE
-+#if 0
-+int
-+init_module(void)
-+{
-+ pfkey_init();
-+ return 0;
-+}
-+
-+void
-+cleanup_module(void)
-+{
-+ pfkey_cleanup();
-+}
-+#endif /* 0 */
-+#else /* MODULE */
-+void
-+pfkey_proto_init(struct net_proto *pro)
-+{
-+ pfkey_init();
-+}
-+#endif /* MODULE */
-+
-+/*
-+ * $Log: pfkey_v2.c,v $
-+ * Revision 1.81 2004/04/25 21:23:11 ken
-+ * Pull in dhr's changes from FreeS/WAN 2.06
-+ *
-+ * Revision 1.80 2004/04/06 02:49:26 mcr
-+ * pullup of algo code from alg-branch.
-+ *
-+ * Revision 1.79.4.1 2003/12/22 15:25:52 jjo
-+ * . Merged algo-0.8.1-rc11-test1 into alg-branch
-+ *
-+ * Revision 1.79 2003/10/31 02:27:55 mcr
-+ * pulled up port-selector patches and sa_id elimination.
-+ *
-+ * Revision 1.78.4.1 2003/10/29 01:30:41 mcr
-+ * elimited "struct sa_id".
-+ *
-+ * Revision 1.78 2003/04/03 17:38:09 rgb
-+ * Centralised ipsec_kfree_skb and ipsec_dev_{get,put}.
-+ *
-+ * Revision 1.77 2002/10/17 16:49:36 mcr
-+ * sock->ops should reference the unwrapped options so that
-+ * we get hacked in locking on SMP systems.
-+ *
-+ * Revision 1.76 2002/10/12 23:11:53 dhr
-+ *
-+ * [KenB + DHR] more 64-bit cleanup
-+ *
-+ * Revision 1.75 2002/09/20 05:01:57 rgb
-+ * Added memory allocation debugging.
-+ *
-+ * Revision 1.74 2002/09/19 02:42:50 mcr
-+ * do not define the pfkey_ops function for now.
-+ *
-+ * Revision 1.73 2002/09/17 17:29:23 mcr
-+ * #if 0 out some dead code - pfkey_ops is never used as written.
-+ *
-+ * Revision 1.72 2002/07/24 18:44:54 rgb
-+ * Type fiddling to tame ia64 compiler.
-+ *
-+ * Revision 1.71 2002/05/23 07:14:11 rgb
-+ * Cleaned up %p variants to 0p%p for test suite cleanup.
-+ *
-+ * Revision 1.70 2002/04/24 07:55:32 mcr
-+ * #include patches and Makefiles for post-reorg compilation.
-+ *
-+ * Revision 1.69 2002/04/24 07:36:33 mcr
-+ * Moved from ./klips/net/ipsec/pfkey_v2.c,v
-+ *
-+ * Revision 1.68 2002/03/08 01:15:17 mcr
-+ * put some internal structure only debug messages behind
-+ * && sysctl_ipsec_debug_verbose.
-+ *
-+ * Revision 1.67 2002/01/29 17:17:57 mcr
-+ * moved include of ipsec_param.h to after include of linux/kernel.h
-+ * otherwise, it seems that some option that is set in ipsec_param.h
-+ * screws up something subtle in the include path to kernel.h, and
-+ * it complains on the snprintf() prototype.
-+ *
-+ * Revision 1.66 2002/01/29 04:00:54 mcr
-+ * more excise of kversions.h header.
-+ *
-+ * Revision 1.65 2002/01/29 02:13:18 mcr
-+ * introduction of ipsec_kversion.h means that include of
-+ * ipsec_param.h must preceed any decisions about what files to
-+ * include to deal with differences in kernel source.
-+ *
-+ * Revision 1.64 2001/11/26 09:23:51 rgb
-+ * Merge MCR's ipsec_sa, eroute, proc and struct lifetime changes.
-+ *
-+ * Revision 1.61.2.1 2001/09/25 02:28:44 mcr
-+ * cleaned up includes.
-+ *
-+ * Revision 1.63 2001/11/12 19:38:00 rgb
-+ * Continue trying other sockets even if one fails and return only original
-+ * error.
-+ *
-+ * Revision 1.62 2001/10/18 04:45:22 rgb
-+ * 2.4.9 kernel deprecates linux/malloc.h in favour of linux/slab.h,
-+ * lib/freeswan.h version macros moved to lib/kversions.h.
-+ * Other compiler directive cleanups.
-+ *
-+ * Revision 1.61 2001/09/20 15:32:59 rgb
-+ * Min/max cleanup.
-+ *
-+ * Revision 1.60 2001/06/14 19:35:12 rgb
-+ * Update copyright date.
-+ *
-+ * Revision 1.59 2001/06/13 15:35:48 rgb
-+ * Fixed #endif comments.
-+ *
-+ * Revision 1.58 2001/05/04 16:37:24 rgb
-+ * Remove erroneous checking of return codes for proc_net_* in 2.4.
-+ *
-+ * Revision 1.57 2001/05/03 19:43:36 rgb
-+ * Initialise error return variable.
-+ * Check error return codes in startup and shutdown.
-+ * Standardise on SENDERR() macro.
-+ *
-+ * Revision 1.56 2001/04/21 23:05:07 rgb
-+ * Define out skb->used for 2.4 kernels.
-+ *
-+ * Revision 1.55 2001/02/28 05:03:28 rgb
-+ * Clean up and rationalise startup messages.
-+ *
-+ * Revision 1.54 2001/02/27 22:24:55 rgb
-+ * Re-formatting debug output (line-splitting, joining, 1arg/line).
-+ * Check for satoa() return codes.
-+ *
-+ * Revision 1.53 2001/02/27 06:48:18 rgb
-+ * Fixed pfkey socket unregister log message to reflect type and function.
-+ *
-+ * Revision 1.52 2001/02/26 22:34:38 rgb
-+ * Fix error return code that was getting overwritten by the error return
-+ * code of an upmsg.
-+ *
-+ * Revision 1.51 2001/01/30 23:42:47 rgb
-+ * Allow pfkey msgs from pid other than user context required for ACQUIRE
-+ * and subsequent ADD or UDATE.
-+ *
-+ * Revision 1.50 2001/01/23 20:22:59 rgb
-+ * 2.4 fix to remove removed is_clone member.
-+ *
-+ * Revision 1.49 2000/11/06 04:33:47 rgb
-+ * Changed non-exported functions to DEBUG_NO_STATIC.
-+ *
-+ * Revision 1.48 2000/09/29 19:47:41 rgb
-+ * Update copyright.
-+ *
-+ * Revision 1.47 2000/09/22 04:23:04 rgb
-+ * Added more debugging to pfkey_upmsg() call from pfkey_sendmsg() error.
-+ *
-+ * Revision 1.46 2000/09/21 04:20:44 rgb
-+ * Fixed array size off-by-one error. (Thanks Svenning!)
-+ *
-+ * Revision 1.45 2000/09/20 04:01:26 rgb
-+ * Changed static functions to DEBUG_NO_STATIC for revealing function names
-+ * in oopsen.
-+ *
-+ * Revision 1.44 2000/09/19 00:33:17 rgb
-+ * 2.0 fixes.
-+ *
-+ * Revision 1.43 2000/09/16 01:28:13 rgb
-+ * Fixed use of 0 in p format warning.
-+ *
-+ * Revision 1.42 2000/09/16 01:09:41 rgb
-+ * Fixed debug format warning for pointers that was expecting ints.
-+ *
-+ * Revision 1.41 2000/09/13 15:54:00 rgb
-+ * Rewrote pfkey_get_info(), added pfkey_{supported,registered}_get_info().
-+ * Moved supported algos add and remove to functions.
-+ *
-+ * Revision 1.40 2000/09/12 18:49:28 rgb
-+ * Added IPIP tunnel and IPCOMP register support.
-+ *
-+ * Revision 1.39 2000/09/12 03:23:49 rgb
-+ * Converted #if0 debugs to sysctl.
-+ * Removed debug_pfkey initialisations that prevented no_debug loading or
-+ * linking.
-+ *
-+ * Revision 1.38 2000/09/09 06:38:02 rgb
-+ * Return positive errno in pfkey_reply error message.
-+ *
-+ * Revision 1.37 2000/09/08 19:19:09 rgb
-+ * Change references from DEBUG_IPSEC to CONFIG_IPSEC_DEBUG.
-+ * Clean-up of long-unused crud...
-+ * Create pfkey error message on on failure.
-+ * Give pfkey_list_{insert,remove}_{socket,supported}() some error
-+ * checking.
-+ *
-+ * Revision 1.36 2000/09/01 18:49:38 rgb
-+ * Reap experimental NET_21_ bits.
-+ * Turned registered sockets list into an array of one list per satype.
-+ * Remove references to deprecated sklist_{insert,remove}_socket.
-+ * Removed leaking socket debugging code.
-+ * Removed duplicate pfkey_insert_socket in pfkey_create.
-+ * Removed all references to pfkey msg->msg_name, since it is not used for
-+ * pfkey.
-+ * Added a supported algorithms array lists, one per satype and registered
-+ * existing algorithms.
-+ * Fixed pfkey_list_{insert,remove}_{socket,support}() to allow change to
-+ * list.
-+ * Only send pfkey_expire() messages to sockets registered for that satype.
-+ *
-+ * Revision 1.35 2000/08/24 17:03:00 rgb
-+ * Corrected message size error return code for PF_KEYv2.
-+ * Removed downward error prohibition.
-+ *
-+ * Revision 1.34 2000/08/21 16:32:26 rgb
-+ * Re-formatted for cosmetic consistency and readability.
-+ *
-+ * Revision 1.33 2000/08/20 21:38:24 rgb
-+ * Added a pfkey_reply parameter to pfkey_msg_interp(). (Momchil)
-+ * Extended the upward message initiation of pfkey_sendmsg(). (Momchil)
-+ *
-+ * Revision 1.32 2000/07/28 14:58:31 rgb
-+ * Changed kfree_s to kfree, eliminating extra arg to fix 2.4.0-test5.
-+ *
-+ * Revision 1.31 2000/05/16 03:04:00 rgb
-+ * Updates for 2.3.99pre8 from MB.
-+ *
-+ * Revision 1.30 2000/05/10 19:22:21 rgb
-+ * Use sklist private functions for 2.3.xx compatibility.
-+ *
-+ * Revision 1.29 2000/03/22 16:17:03 rgb
-+ * Fixed SOCKOPS_WRAPPED macro for SMP (MB).
-+ *
-+ * Revision 1.28 2000/02/21 19:30:45 rgb
-+ * Removed references to pkt_bridged for 2.3.47 compatibility.
-+ *
-+ * Revision 1.27 2000/02/14 21:07:00 rgb
-+ * Fixed /proc/net/pf-key legend spacing.
-+ *
-+ * Revision 1.26 2000/01/22 03:46:59 rgb
-+ * Fixed pfkey error return mechanism so that we are able to free the
-+ * local copy of the pfkey_msg, plugging a memory leak and silencing
-+ * the bad object free complaints.
-+ *
-+ * Revision 1.25 2000/01/21 06:19:44 rgb
-+ * Moved pfkey_list_remove_socket() calls to before MOD_USE_DEC_COUNT.
-+ * Added debugging to pfkey_upmsg.
-+ *
-+ * Revision 1.24 2000/01/10 16:38:23 rgb
-+ * MB fixups for 2.3.x.
-+ *
-+ * Revision 1.23 1999/12/09 23:22:16 rgb
-+ * Added more instrumentation for debugging 2.0 socket
-+ * selection/reading.
-+ * Removed erroneous 2.0 wait==NULL check bug in select.
-+ *
-+ * Revision 1.22 1999/12/08 20:32:16 rgb
-+ * Tidied up 2.0.xx support, after major pfkey work, eliminating
-+ * msg->msg_name twiddling in the process, since it is not defined
-+ * for PF_KEYv2.
-+ *
-+ * Revision 1.21 1999/12/01 22:17:19 rgb
-+ * Set skb->dev to zero on new skb in case it is a reused skb.
-+ * Added check for skb_put overflow and freeing to avoid upmsg on error.
-+ * Added check for wrong pfkey version and freeing to avoid upmsg on
-+ * error.
-+ * Shut off content dumping in pfkey_destroy.
-+ * Added debugging message for size of buffer allocated for upmsg.
-+ *
-+ * Revision 1.20 1999/11/27 12:11:00 rgb
-+ * Minor clean-up, enabling quiet operation of pfkey if desired.
-+ *
-+ * Revision 1.19 1999/11/25 19:04:21 rgb
-+ * Update proc_fs code for pfkey to use dynamic registration.
-+ *
-+ * Revision 1.18 1999/11/25 09:07:17 rgb
-+ * Implemented SENDERR macro for propagating error codes.
-+ * Fixed error return code bug.
-+ *
-+ * Revision 1.17 1999/11/23 23:07:20 rgb
-+ * Change name of pfkey_msg_parser to pfkey_msg_interp since it no longer
-+ * parses. (PJO)
-+ * Sort out pfkey and freeswan headers, putting them in a library path.
-+ *
-+ * Revision 1.16 1999/11/20 22:00:22 rgb
-+ * Moved socketlist type declarations and prototypes for shared use.
-+ * Renamed reformatted and generically extended for use by other socket
-+ * lists pfkey_{del,add}_open_socket to pfkey_list_{remove,insert}_socket.
-+ *
-+ * Revision 1.15 1999/11/18 04:15:09 rgb
-+ * Make pfkey_data_ready temporarily available for 2.2.x testing.
-+ * Clean up pfkey_destroy_socket() debugging statements.
-+ * Add Peter Onion's code to send messages up to all listening sockets.
-+ * Changed all occurrences of #include "../../../lib/freeswan.h"
-+ * to #include <freeswan.h> which works due to -Ilibfreeswan in the
-+ * klips/net/ipsec/Makefile.
-+ * Replaced all kernel version macros to shorter, readable form.
-+ * Added CONFIG_PROC_FS compiler directives in case it is shut off.
-+ *
-+ * Revision 1.14 1999/11/17 16:01:00 rgb
-+ * Make pfkey_data_ready temporarily available for 2.2.x testing.
-+ * Clean up pfkey_destroy_socket() debugging statements.
-+ * Add Peter Onion's code to send messages up to all listening sockets.
-+ * Changed #include "../../../lib/freeswan.h" to #include <freeswan.h>
-+ * which works due to -Ilibfreeswan in the klips/net/ipsec/Makefile.
-+ *
-+ * Revision 1.13 1999/10/27 19:59:51 rgb
-+ * Removed af_unix comments that are no longer relevant.
-+ * Added debug prink statements.
-+ * Added to the /proc output in pfkey_get_info.
-+ * Made most functions non-static to enable oops tracing.
-+ * Re-enable skb dequeueing and freeing.
-+ * Fix skb_alloc() and skb_put() size bug in pfkey_upmsg().
-+ *
-+ * Revision 1.12 1999/10/26 17:05:42 rgb
-+ * Complete re-ordering based on proto_ops structure order.
-+ * Separated out proto_ops structures for 2.0.x and 2.2.x for clarity.
-+ * Simplification to use built-in socket ops where possible for 2.2.x.
-+ * Add shorter macros for compiler directives to visually clean-up.
-+ * Add lots of sk skb dequeueing debugging statements.
-+ * Added to the /proc output in pfkey_get_info.
-+ *
-+ * Revision 1.11 1999/09/30 02:55:10 rgb
-+ * Bogus skb detection.
-+ * Fix incorrect /proc/net/ipsec-eroute printk message.
-+ *
-+ * Revision 1.10 1999/09/21 15:22:13 rgb
-+ * Temporary fix while I figure out the right way to destroy sockets.
-+ *
-+ * Revision 1.9 1999/07/08 19:19:44 rgb
-+ * Fix pointer format warning.
-+ * Fix missing member error under 2.0.xx kernels.
-+ *
-+ * Revision 1.8 1999/06/13 07:24:04 rgb
-+ * Add more debugging.
-+ *
-+ * Revision 1.7 1999/06/10 05:24:17 rgb
-+ * Clarified compiler directives.
-+ * Renamed variables to reduce confusion.
-+ * Used sklist_*_socket() kernel functions to simplify 2.2.x socket support.
-+ * Added lots of sanity checking.
-+ *
-+ * Revision 1.6 1999/06/03 18:59:50 rgb
-+ * More updates to 2.2.x socket support. Almost works, oops at end of call.
-+ *
-+ * Revision 1.5 1999/05/25 22:44:05 rgb
-+ * Start fixing 2.2 sockets.
-+ *
-+ * Revision 1.4 1999/04/29 15:21:34 rgb
-+ * Move log to the end of the file.
-+ * Eliminate min/max redefinition in #include <net/tcp.h>.
-+ * Correct path for pfkey #includes
-+ * Standardise an error return method.
-+ * Add debugging instrumentation.
-+ * Move message type checking to pfkey_msg_parse().
-+ * Add check for errno incorrectly set.
-+ * Add check for valid PID.
-+ * Add check for reserved illegally set.
-+ * Add check for message out of bounds.
-+ *
-+ * Revision 1.3 1999/04/15 17:58:07 rgb
-+ * Add RCSID labels.
-+ *
-+ * Revision 1.2 1999/04/15 15:37:26 rgb
-+ * Forward check changes from POST1_00 branch.
-+ *
-+ * Revision 1.1.2.2 1999/04/13 20:37:12 rgb
-+ * Header Title correction.
-+ *
-+ * Revision 1.1.2.1 1999/03/26 20:58:55 rgb
-+ * Add pfkeyv2 support to KLIPS.
-+ *
-+ *
-+ * RFC 2367
-+ * PF_KEY_v2 Key Management API
-+ */
---- /dev/null Tue Mar 11 13:02:56 2003
-+++ linux/net/ipsec/pfkey_v2_ext_process.c Mon Feb 9 13:51:03 2004
-@@ -0,0 +1,922 @@
-+/*
-+ * @(#) RFC2367 PF_KEYv2 Key management API message parser
-+ * Copyright (C) 1998-2003 Richard Guy Briggs.
-+ * Copyright (C) 2004 Michael Richardson <mcr@xelerance.com>
-+ *
-+ * 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. See <http://www.fsf.org/copyleft/gpl.txt>.
-+ *
-+ * 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.
-+ *
-+ * RCSID $Id: pfkey_v2_ext_process.c,v 1.15 2004/04/06 02:49:26 mcr Exp $
-+ */
-+
-+/*
-+ * Template from klips/net/ipsec/ipsec/ipsec_netlink.c.
-+ */
-+
-+char pfkey_v2_ext_process_c_version[] = "$Id: pfkey_v2_ext_process.c,v 1.15 2004/04/06 02:49:26 mcr Exp $";
-+
-+#include <linux/config.h>
-+#include <linux/version.h>
-+#include <linux/kernel.h> /* printk() */
-+
-+#include "openswan/ipsec_param.h"
-+
-+#ifdef MALLOC_SLAB
-+# include <linux/slab.h> /* kmalloc() */
-+#else /* MALLOC_SLAB */
-+# include <linux/malloc.h> /* kmalloc() */
-+#endif /* MALLOC_SLAB */
-+#include <linux/errno.h> /* error codes */
-+#include <linux/types.h> /* size_t */
-+#include <linux/interrupt.h> /* mark_bh */
-+
-+#include <linux/netdevice.h> /* struct device, and other headers */
-+#include <linux/etherdevice.h> /* eth_type_trans */
-+#include <linux/ip.h> /* struct iphdr */
-+#include <linux/skbuff.h>
-+
-+#include <openswan.h>
-+
-+#include <crypto/des.h>
-+
-+#ifdef SPINLOCK
-+# ifdef SPINLOCK_23
-+# include <linux/spinlock.h> /* *lock* */
-+# else /* SPINLOCK_23 */
-+# include <asm/spinlock.h> /* *lock* */
-+# endif /* SPINLOCK_23 */
-+#endif /* SPINLOCK */
-+#ifdef NET_21
-+# include <asm/uaccess.h>
-+# include <linux/in6.h>
-+# define ip_chk_addr inet_addr_type
-+# define IS_MYADDR RTN_LOCAL
-+#endif
-+#include <asm/checksum.h>
-+#include <net/ip.h>
-+#ifdef NETLINK_SOCK
-+# include <linux/netlink.h>
-+#else
-+# include <net/netlink.h>
-+#endif
-+
-+#include <linux/random.h> /* get_random_bytes() */
-+
-+#include "openswan/radij.h"
-+#include "openswan/ipsec_encap.h"
-+#include "openswan/ipsec_sa.h"
-+
-+#include "openswan/ipsec_radij.h"
-+#include "openswan/ipsec_xform.h"
-+#include "openswan/ipsec_ah.h"
-+#include "openswan/ipsec_esp.h"
-+#include "openswan/ipsec_tunnel.h"
-+#include "openswan/ipsec_rcv.h"
-+#include "openswan/ipcomp.h"
-+
-+#include <pfkeyv2.h>
-+#include <pfkey.h>
-+
-+#include "openswan/ipsec_proto.h"
-+#include "openswan/ipsec_alg.h"
-+
-+#define SENDERR(_x) do { error = -(_x); goto errlab; } while (0)
-+
-+int
-+pfkey_sa_process(struct sadb_ext *pfkey_ext, struct pfkey_extracted_data* extr)
-+{
-+ struct sadb_sa *pfkey_sa = (struct sadb_sa *)pfkey_ext;
-+ int error = 0;
-+ struct ipsec_sa* ipsp;
-+
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_sa_process: .\n");
-+
-+ if(!extr || !extr->ips) {
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_sa_process: "
-+ "extr or extr->ips is NULL, fatal\n");
-+ SENDERR(EINVAL);
-+ }
-+
-+ switch(pfkey_ext->sadb_ext_type) {
-+ case SADB_EXT_SA:
-+ ipsp = extr->ips;
-+ break;
-+ case SADB_X_EXT_SA2:
-+ if(extr->ips2 == NULL) {
-+ extr->ips2 = ipsec_sa_alloc(&error); /* pass error var by pointer */
-+ }
-+ if(extr->ips2 == NULL) {
-+ SENDERR(-error);
-+ }
-+ ipsp = extr->ips2;
-+ break;
-+ default:
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_sa_process: "
-+ "invalid exttype=%d.\n",
-+ pfkey_ext->sadb_ext_type);
-+ SENDERR(EINVAL);
-+ }
-+
-+ ipsp->ips_said.spi = pfkey_sa->sadb_sa_spi;
-+ ipsp->ips_replaywin = pfkey_sa->sadb_sa_replay;
-+ ipsp->ips_state = pfkey_sa->sadb_sa_state;
-+ ipsp->ips_flags = pfkey_sa->sadb_sa_flags;
-+ ipsp->ips_replaywin_lastseq = ipsp->ips_replaywin_bitmap = 0;
-+ ipsp->ips_ref_rel = pfkey_sa->sadb_x_sa_ref;
-+
-+ switch(ipsp->ips_said.proto) {
-+ case IPPROTO_AH:
-+ ipsp->ips_authalg = pfkey_sa->sadb_sa_auth;
-+ ipsp->ips_encalg = SADB_EALG_NONE;
-+ break;
-+ case IPPROTO_ESP:
-+ ipsp->ips_authalg = pfkey_sa->sadb_sa_auth;
-+ ipsp->ips_encalg = pfkey_sa->sadb_sa_encrypt;
-+#ifdef CONFIG_IPSEC_ALG
-+ ipsec_alg_sa_init(ipsp);
-+#endif /* CONFIG_IPSEC_ALG */
-+ break;
-+ case IPPROTO_IPIP:
-+ ipsp->ips_authalg = AH_NONE;
-+ ipsp->ips_encalg = ESP_NONE;
-+ break;
-+#ifdef CONFIG_IPSEC_IPCOMP
-+ case IPPROTO_COMP:
-+ ipsp->ips_authalg = AH_NONE;
-+ ipsp->ips_encalg = pfkey_sa->sadb_sa_encrypt;
-+ break;
-+#endif /* CONFIG_IPSEC_IPCOMP */
-+ case IPPROTO_INT:
-+ ipsp->ips_authalg = AH_NONE;
-+ ipsp->ips_encalg = ESP_NONE;
-+ break;
-+ case 0:
-+ break;
-+ default:
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_sa_process: "
-+ "unknown proto=%d.\n",
-+ ipsp->ips_said.proto);
-+ SENDERR(EINVAL);
-+ }
-+
-+errlab:
-+ return error;
-+}
-+
-+int
-+pfkey_lifetime_process(struct sadb_ext *pfkey_ext, struct pfkey_extracted_data* extr)
-+{
-+ int error = 0;
-+ struct sadb_lifetime *pfkey_lifetime = (struct sadb_lifetime *)pfkey_ext;
-+
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_lifetime_process: .\n");
-+
-+ if(!extr || !extr->ips) {
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_lifetime_process: "
-+ "extr or extr->ips is NULL, fatal\n");
-+ SENDERR(EINVAL);
-+ }
-+
-+ switch(pfkey_lifetime->sadb_lifetime_exttype) {
-+ case SADB_EXT_LIFETIME_CURRENT:
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_lifetime_process: "
-+ "lifetime_current not supported yet.\n");
-+ SENDERR(EINVAL);
-+ break;
-+ case SADB_EXT_LIFETIME_HARD:
-+ ipsec_lifetime_update_hard(&extr->ips->ips_life.ipl_allocations,
-+ pfkey_lifetime->sadb_lifetime_allocations);
-+
-+ ipsec_lifetime_update_hard(&extr->ips->ips_life.ipl_bytes,
-+ pfkey_lifetime->sadb_lifetime_bytes);
-+
-+ ipsec_lifetime_update_hard(&extr->ips->ips_life.ipl_addtime,
-+ pfkey_lifetime->sadb_lifetime_addtime);
-+
-+ ipsec_lifetime_update_hard(&extr->ips->ips_life.ipl_usetime,
-+ pfkey_lifetime->sadb_lifetime_usetime);
-+
-+ break;
-+
-+ case SADB_EXT_LIFETIME_SOFT:
-+ ipsec_lifetime_update_soft(&extr->ips->ips_life.ipl_allocations,
-+ pfkey_lifetime->sadb_lifetime_allocations);
-+
-+ ipsec_lifetime_update_soft(&extr->ips->ips_life.ipl_bytes,
-+ pfkey_lifetime->sadb_lifetime_bytes);
-+
-+ ipsec_lifetime_update_soft(&extr->ips->ips_life.ipl_addtime,
-+ pfkey_lifetime->sadb_lifetime_addtime);
-+
-+ ipsec_lifetime_update_soft(&extr->ips->ips_life.ipl_usetime,
-+ pfkey_lifetime->sadb_lifetime_usetime);
-+
-+ break;
-+ default:
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_lifetime_process: "
-+ "invalid exttype=%d.\n",
-+ pfkey_ext->sadb_ext_type);
-+ SENDERR(EINVAL);
-+ }
-+
-+errlab:
-+ return error;
-+}
-+
-+int
-+pfkey_address_process(struct sadb_ext *pfkey_ext, struct pfkey_extracted_data* extr)
-+{
-+ int error = 0;
-+ int saddr_len = 0;
-+ char ipaddr_txt[ADDRTOA_BUF];
-+ unsigned char **sap;
-+ unsigned short * portp = 0;
-+ struct sadb_address *pfkey_address = (struct sadb_address *)pfkey_ext;
-+ struct sockaddr* s = (struct sockaddr*)((char*)pfkey_address + sizeof(*pfkey_address));
-+ struct ipsec_sa* ipsp;
-+
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_address_process:\n");
-+
-+ if(!extr || !extr->ips) {
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_address_process: "
-+ "extr or extr->ips is NULL, fatal\n");
-+ SENDERR(EINVAL);
-+ }
-+
-+ switch(s->sa_family) {
-+ case AF_INET:
-+ saddr_len = sizeof(struct sockaddr_in);
-+ addrtoa(((struct sockaddr_in*)s)->sin_addr, 0, ipaddr_txt, sizeof(ipaddr_txt));
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_address_process: "
-+ "found address family=%d, AF_INET, %s.\n",
-+ s->sa_family,
-+ ipaddr_txt);
-+ break;
-+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
-+ case AF_INET6:
-+ saddr_len = sizeof(struct sockaddr_in6);
-+ break;
-+#endif /* defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) */
-+ default:
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_address_process: "
-+ "s->sa_family=%d not supported.\n",
-+ s->sa_family);
-+ SENDERR(EPFNOSUPPORT);
-+ }
-+
-+ switch(pfkey_address->sadb_address_exttype) {
-+ case SADB_EXT_ADDRESS_SRC:
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_address_process: "
-+ "found src address.\n");
-+ sap = (unsigned char **)&(extr->ips->ips_addr_s);
-+ extr->ips->ips_addr_s_size = saddr_len;
-+ break;
-+ case SADB_EXT_ADDRESS_DST:
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_address_process: "
-+ "found dst address.\n");
-+ sap = (unsigned char **)&(extr->ips->ips_addr_d);
-+ extr->ips->ips_addr_d_size = saddr_len;
-+ break;
-+ case SADB_EXT_ADDRESS_PROXY:
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_address_process: "
-+ "found proxy address.\n");
-+ sap = (unsigned char **)&(extr->ips->ips_addr_p);
-+ extr->ips->ips_addr_p_size = saddr_len;
-+ break;
-+ case SADB_X_EXT_ADDRESS_DST2:
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_address_process: "
-+ "found 2nd dst address.\n");
-+ if(extr->ips2 == NULL) {
-+ extr->ips2 = ipsec_sa_alloc(&error); /* pass error var by pointer */
-+ }
-+ if(extr->ips2 == NULL) {
-+ SENDERR(-error);
-+ }
-+ sap = (unsigned char **)&(extr->ips2->ips_addr_d);
-+ extr->ips2->ips_addr_d_size = saddr_len;
-+ break;
-+ case SADB_X_EXT_ADDRESS_SRC_FLOW:
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_address_process: "
-+ "found src flow address.\n");
-+ if(pfkey_alloc_eroute(&(extr->eroute)) == ENOMEM) {
-+ SENDERR(ENOMEM);
-+ }
-+ sap = (unsigned char **)&(extr->eroute->er_eaddr.sen_ip_src);
-+ portp = &(extr->eroute->er_eaddr.sen_sport);
-+ break;
-+ case SADB_X_EXT_ADDRESS_DST_FLOW:
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_address_process: "
-+ "found dst flow address.\n");
-+ if(pfkey_alloc_eroute(&(extr->eroute)) == ENOMEM) {
-+ SENDERR(ENOMEM);
-+ }
-+ sap = (unsigned char **)&(extr->eroute->er_eaddr.sen_ip_dst);
-+ portp = &(extr->eroute->er_eaddr.sen_dport);
-+ break;
-+ case SADB_X_EXT_ADDRESS_SRC_MASK:
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_address_process: "
-+ "found src mask address.\n");
-+ if(pfkey_alloc_eroute(&(extr->eroute)) == ENOMEM) {
-+ SENDERR(ENOMEM);
-+ }
-+ sap = (unsigned char **)&(extr->eroute->er_emask.sen_ip_src);
-+ portp = &(extr->eroute->er_emask.sen_sport);
-+ break;
-+ case SADB_X_EXT_ADDRESS_DST_MASK:
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_address_process: "
-+ "found dst mask address.\n");
-+ if(pfkey_alloc_eroute(&(extr->eroute)) == ENOMEM) {
-+ SENDERR(ENOMEM);
-+ }
-+ sap = (unsigned char **)&(extr->eroute->er_emask.sen_ip_dst);
-+ portp = &(extr->eroute->er_emask.sen_dport);
-+ break;
-+#ifdef NAT_TRAVERSAL
-+ case SADB_X_EXT_NAT_T_OA:
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_address_process: "
-+ "found NAT-OA address.\n");
-+ sap = (unsigned char **)&(extr->ips->ips_natt_oa);
-+ extr->ips->ips_natt_oa_size = saddr_len;
-+ break;
-+#endif
-+ default:
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_address_process: "
-+ "unrecognised ext_type=%d.\n",
-+ pfkey_address->sadb_address_exttype);
-+ SENDERR(EINVAL);
-+ }
-+
-+ switch(pfkey_address->sadb_address_exttype) {
-+ case SADB_EXT_ADDRESS_SRC:
-+ case SADB_EXT_ADDRESS_DST:
-+ case SADB_EXT_ADDRESS_PROXY:
-+ case SADB_X_EXT_ADDRESS_DST2:
-+#ifdef NAT_TRAVERSAL
-+ case SADB_X_EXT_NAT_T_OA:
-+#endif
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_address_process: "
-+ "allocating %d bytes for saddr.\n",
-+ saddr_len);
-+ if(!(*sap = kmalloc(saddr_len, GFP_KERNEL))) {
-+ SENDERR(ENOMEM);
-+ }
-+ memcpy(*sap, s, saddr_len);
-+ break;
-+ default:
-+ if(s->sa_family != AF_INET) {
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_address_process: "
-+ "s->sa_family=%d not supported.\n",
-+ s->sa_family);
-+ SENDERR(EPFNOSUPPORT);
-+ }
-+ (unsigned long)(*sap) = ((struct sockaddr_in*)s)->sin_addr.s_addr;
-+ if (portp != 0)
-+ *portp = ((struct sockaddr_in*)s)->sin_port;
-+#ifdef CONFIG_IPSEC_DEBUG
-+ if(extr->eroute) {
-+ char buf1[64], buf2[64];
-+ if (debug_pfkey) {
-+ subnettoa(extr->eroute->er_eaddr.sen_ip_src,
-+ extr->eroute->er_emask.sen_ip_src, 0, buf1, sizeof(buf1));
-+ subnettoa(extr->eroute->er_eaddr.sen_ip_dst,
-+ extr->eroute->er_emask.sen_ip_dst, 0, buf2, sizeof(buf2));
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_address_parse: "
-+ "extr->eroute set to %s:%d->%s:%d\n",
-+ buf1,
-+ ntohs(extr->eroute->er_eaddr.sen_sport),
-+ buf2,
-+ ntohs(extr->eroute->er_eaddr.sen_dport));
-+ }
-+ }
-+#endif /* CONFIG_IPSEC_DEBUG */
-+ }
-+
-+ ipsp = extr->ips;
-+ switch(pfkey_address->sadb_address_exttype) {
-+ case SADB_X_EXT_ADDRESS_DST2:
-+ ipsp = extr->ips2;
-+ case SADB_EXT_ADDRESS_DST:
-+ if(s->sa_family == AF_INET) {
-+ ipsp->ips_said.dst.u.v4.sin_addr.s_addr = ((struct sockaddr_in*)(ipsp->ips_addr_d))->sin_addr.s_addr;
-+ ipsp->ips_said.dst.u.v4.sin_family = AF_INET;
-+ addrtoa(((struct sockaddr_in*)(ipsp->ips_addr_d))->sin_addr,
-+ 0,
-+ ipaddr_txt,
-+ sizeof(ipaddr_txt));
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_address_process: "
-+ "ips_said.dst set to %s.\n",
-+ ipaddr_txt);
-+ } else {
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_address_process: "
-+ "uh, ips_said.dst doesn't do address family=%d yet, said will be invalid.\n",
-+ s->sa_family);
-+ }
-+ default:
-+ break;
-+ }
-+
-+ /* XXX check if port!=0 */
-+
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_address_process: successful.\n");
-+ errlab:
-+ return error;
-+}
-+
-+int
-+pfkey_key_process(struct sadb_ext *pfkey_ext, struct pfkey_extracted_data* extr)
-+{
-+ int error = 0;
-+ struct sadb_key *pfkey_key = (struct sadb_key *)pfkey_ext;
-+
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_key_process: .\n");
-+
-+ if(!extr || !extr->ips) {
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_key_process: "
-+ "extr or extr->ips is NULL, fatal\n");
-+ SENDERR(EINVAL);
-+ }
-+
-+ switch(pfkey_key->sadb_key_exttype) {
-+ case SADB_EXT_KEY_AUTH:
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_key_process: "
-+ "allocating %d bytes for authkey.\n",
-+ DIVUP(pfkey_key->sadb_key_bits, 8));
-+ if(!(extr->ips->ips_key_a = kmalloc(DIVUP(pfkey_key->sadb_key_bits, 8), GFP_KERNEL))) {
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_key_process: "
-+ "memory allocation error.\n");
-+ SENDERR(ENOMEM);
-+ }
-+ extr->ips->ips_key_bits_a = pfkey_key->sadb_key_bits;
-+ extr->ips->ips_key_a_size = DIVUP(pfkey_key->sadb_key_bits, 8);
-+ memcpy(extr->ips->ips_key_a,
-+ (char*)pfkey_key + sizeof(struct sadb_key),
-+ extr->ips->ips_key_a_size);
-+ break;
-+ case SADB_EXT_KEY_ENCRYPT: /* Key(s) */
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_key_process: "
-+ "allocating %d bytes for enckey.\n",
-+ DIVUP(pfkey_key->sadb_key_bits, 8));
-+ if(!(extr->ips->ips_key_e = kmalloc(DIVUP(pfkey_key->sadb_key_bits, 8), GFP_KERNEL))) {
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_key_process: "
-+ "memory allocation error.\n");
-+ SENDERR(ENOMEM);
-+ }
-+ extr->ips->ips_key_bits_e = pfkey_key->sadb_key_bits;
-+ extr->ips->ips_key_e_size = DIVUP(pfkey_key->sadb_key_bits, 8);
-+ memcpy(extr->ips->ips_key_e,
-+ (char*)pfkey_key + sizeof(struct sadb_key),
-+ extr->ips->ips_key_e_size);
-+ break;
-+ default:
-+ SENDERR(EINVAL);
-+ }
-+
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_key_process: "
-+ "success.\n");
-+errlab:
-+ return error;
-+}
-+
-+int
-+pfkey_ident_process(struct sadb_ext *pfkey_ext, struct pfkey_extracted_data* extr)
-+{
-+ int error = 0;
-+ struct sadb_ident *pfkey_ident = (struct sadb_ident *)pfkey_ext;
-+ int data_len;
-+
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_ident_process: .\n");
-+
-+ if(!extr || !extr->ips) {
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_ident_process: "
-+ "extr or extr->ips is NULL, fatal\n");
-+ SENDERR(EINVAL);
-+ }
-+
-+ switch(pfkey_ident->sadb_ident_exttype) {
-+ case SADB_EXT_IDENTITY_SRC:
-+ data_len = pfkey_ident->sadb_ident_len * IPSEC_PFKEYv2_ALIGN - sizeof(struct sadb_ident);
-+
-+ extr->ips->ips_ident_s.type = pfkey_ident->sadb_ident_type;
-+ extr->ips->ips_ident_s.id = pfkey_ident->sadb_ident_id;
-+ extr->ips->ips_ident_s.len = pfkey_ident->sadb_ident_len;
-+ if(data_len) {
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_ident_process: "
-+ "allocating %d bytes for ident_s.\n",
-+ data_len);
-+ if(!(extr->ips->ips_ident_s.data
-+ = kmalloc(data_len, GFP_KERNEL))) {
-+ SENDERR(ENOMEM);
-+ }
-+ memcpy(extr->ips->ips_ident_s.data,
-+ (char*)pfkey_ident + sizeof(struct sadb_ident),
-+ data_len);
-+ } else {
-+ extr->ips->ips_ident_s.data = NULL;
-+ }
-+ break;
-+ case SADB_EXT_IDENTITY_DST: /* Identity(ies) */
-+ data_len = pfkey_ident->sadb_ident_len * IPSEC_PFKEYv2_ALIGN - sizeof(struct sadb_ident);
-+
-+ extr->ips->ips_ident_d.type = pfkey_ident->sadb_ident_type;
-+ extr->ips->ips_ident_d.id = pfkey_ident->sadb_ident_id;
-+ extr->ips->ips_ident_d.len = pfkey_ident->sadb_ident_len;
-+ if(data_len) {
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_ident_process: "
-+ "allocating %d bytes for ident_d.\n",
-+ data_len);
-+ if(!(extr->ips->ips_ident_d.data
-+ = kmalloc(data_len, GFP_KERNEL))) {
-+ SENDERR(ENOMEM);
-+ }
-+ memcpy(extr->ips->ips_ident_d.data,
-+ (char*)pfkey_ident + sizeof(struct sadb_ident),
-+ data_len);
-+ } else {
-+ extr->ips->ips_ident_d.data = NULL;
-+ }
-+ break;
-+ default:
-+ SENDERR(EINVAL);
-+ }
-+errlab:
-+ return error;
-+}
-+
-+int
-+pfkey_sens_process(struct sadb_ext *pfkey_ext, struct pfkey_extracted_data* extr)
-+{
-+ int error = 0;
-+
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_sens_process: "
-+ "Sorry, I can't process exttype=%d yet.\n",
-+ pfkey_ext->sadb_ext_type);
-+ SENDERR(EINVAL); /* don't process these yet */
-+ errlab:
-+ return error;
-+}
-+
-+int
-+pfkey_prop_process(struct sadb_ext *pfkey_ext, struct pfkey_extracted_data* extr)
-+{
-+ int error = 0;
-+
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_prop_process: "
-+ "Sorry, I can't process exttype=%d yet.\n",
-+ pfkey_ext->sadb_ext_type);
-+ SENDERR(EINVAL); /* don't process these yet */
-+
-+ errlab:
-+ return error;
-+}
-+
-+int
-+pfkey_supported_process(struct sadb_ext *pfkey_ext, struct pfkey_extracted_data* extr)
-+{
-+ int error = 0;
-+
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_supported_process: "
-+ "Sorry, I can't process exttype=%d yet.\n",
-+ pfkey_ext->sadb_ext_type);
-+ SENDERR(EINVAL); /* don't process these yet */
-+
-+errlab:
-+ return error;
-+}
-+
-+int
-+pfkey_spirange_process(struct sadb_ext *pfkey_ext, struct pfkey_extracted_data* extr)
-+{
-+ int error = 0;
-+
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_spirange_process: .\n");
-+/* errlab: */
-+ return error;
-+}
-+
-+int
-+pfkey_x_kmprivate_process(struct sadb_ext *pfkey_ext, struct pfkey_extracted_data* extr)
-+{
-+ int error = 0;
-+
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_x_kmprivate_process: "
-+ "Sorry, I can't process exttype=%d yet.\n",
-+ pfkey_ext->sadb_ext_type);
-+ SENDERR(EINVAL); /* don't process these yet */
-+
-+errlab:
-+ return error;
-+}
-+
-+int
-+pfkey_x_satype_process(struct sadb_ext *pfkey_ext, struct pfkey_extracted_data* extr)
-+{
-+ int error = 0;
-+ struct sadb_x_satype *pfkey_x_satype = (struct sadb_x_satype *)pfkey_ext;
-+
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_x_satype_process: .\n");
-+
-+ if(!extr || !extr->ips) {
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_x_satype_process: "
-+ "extr or extr->ips is NULL, fatal\n");
-+ SENDERR(EINVAL);
-+ }
-+
-+ if(extr->ips2 == NULL) {
-+ extr->ips2 = ipsec_sa_alloc(&error); /* pass error var by pointer */
-+ }
-+ if(extr->ips2 == NULL) {
-+ SENDERR(-error);
-+ }
-+ if(!(extr->ips2->ips_said.proto = satype2proto(pfkey_x_satype->sadb_x_satype_satype))) {
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_x_satype_process: "
-+ "proto lookup from satype=%d failed.\n",
-+ pfkey_x_satype->sadb_x_satype_satype);
-+ SENDERR(EINVAL);
-+ }
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_x_satype_process: "
-+ "protocol==%d decoded from satype==%d(%s).\n",
-+ extr->ips2->ips_said.proto,
-+ pfkey_x_satype->sadb_x_satype_satype,
-+ satype2name(pfkey_x_satype->sadb_x_satype_satype));
-+
-+errlab:
-+ return error;
-+}
-+
-+
-+#ifdef CONFIG_IPSEC_NAT_TRAVERSAL
-+int
-+pfkey_x_nat_t_type_process(struct sadb_ext *pfkey_ext, struct pfkey_extracted_data* extr)
-+{
-+ int error = 0;
-+ struct sadb_x_nat_t_type *pfkey_x_nat_t_type = (struct sadb_x_nat_t_type *)pfkey_ext;
-+
-+ if(!pfkey_x_nat_t_type) {
-+ printk("klips_debug:pfkey_x_nat_t_type_process: "
-+ "null pointer passed in\n");
-+ SENDERR(EINVAL);
-+ }
-+
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_x_nat_t_type_process: %d.\n",
-+ pfkey_x_nat_t_type->sadb_x_nat_t_type_type);
-+
-+ if(!extr || !extr->ips) {
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_nat_t_type_process: "
-+ "extr or extr->ips is NULL, fatal\n");
-+ SENDERR(EINVAL);
-+ }
-+
-+ switch(pfkey_x_nat_t_type->sadb_x_nat_t_type_type) {
-+ case ESPINUDP_WITH_NON_IKE: /* with Non-IKE (older version) */
-+ case ESPINUDP_WITH_NON_ESP: /* with Non-ESP */
-+
-+ extr->ips->ips_natt_type = pfkey_x_nat_t_type->sadb_x_nat_t_type_type;
-+ break;
-+ default:
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_x_nat_t_type_process: "
-+ "unknown type %d.\n",
-+ pfkey_x_nat_t_type->sadb_x_nat_t_type_type);
-+ SENDERR(EINVAL);
-+ break;
-+ }
-+
-+errlab:
-+ return error;
-+}
-+
-+int
-+pfkey_x_nat_t_port_process(struct sadb_ext *pfkey_ext, struct pfkey_extracted_data* extr)
-+{
-+ int error = 0;
-+ struct sadb_x_nat_t_port *pfkey_x_nat_t_port = (struct sadb_x_nat_t_port *)pfkey_ext;
-+
-+ if(!pfkey_x_nat_t_port) {
-+ printk("klips_debug:pfkey_x_nat_t_port_process: "
-+ "null pointer passed in\n");
-+ SENDERR(EINVAL);
-+ }
-+
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_x_nat_t_port_process: %d/%d.\n",
-+ pfkey_x_nat_t_port->sadb_x_nat_t_port_exttype,
-+ pfkey_x_nat_t_port->sadb_x_nat_t_port_port);
-+
-+ if(!extr || !extr->ips) {
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_nat_t_type_process: "
-+ "extr or extr->ips is NULL, fatal\n");
-+ SENDERR(EINVAL);
-+ }
-+
-+ switch(pfkey_x_nat_t_port->sadb_x_nat_t_port_exttype) {
-+ case SADB_X_EXT_NAT_T_SPORT:
-+ extr->ips->ips_natt_sport = pfkey_x_nat_t_port->sadb_x_nat_t_port_port;
-+ break;
-+ case SADB_X_EXT_NAT_T_DPORT:
-+ extr->ips->ips_natt_dport = pfkey_x_nat_t_port->sadb_x_nat_t_port_port;
-+ break;
-+ default:
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_x_nat_t_port_process: "
-+ "unknown exttype %d.\n",
-+ pfkey_x_nat_t_port->sadb_x_nat_t_port_exttype);
-+ SENDERR(EINVAL);
-+ break;
-+ }
-+
-+errlab:
-+ return error;
-+}
-+#endif
-+
-+int
-+pfkey_x_debug_process(struct sadb_ext *pfkey_ext, struct pfkey_extracted_data* extr)
-+{
-+ int error = 0;
-+ struct sadb_x_debug *pfkey_x_debug = (struct sadb_x_debug *)pfkey_ext;
-+
-+ if(!pfkey_x_debug) {
-+ printk("klips_debug:pfkey_x_debug_process: "
-+ "null pointer passed in\n");
-+ SENDERR(EINVAL);
-+ }
-+
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_x_debug_process: .\n");
-+
-+#ifdef CONFIG_IPSEC_DEBUG
-+ if(pfkey_x_debug->sadb_x_debug_netlink >>
-+ (sizeof(pfkey_x_debug->sadb_x_debug_netlink) * 8 - 1)) {
-+ pfkey_x_debug->sadb_x_debug_netlink &=
-+ ~(1 << (sizeof(pfkey_x_debug->sadb_x_debug_netlink) * 8 -1));
-+ debug_tunnel |= pfkey_x_debug->sadb_x_debug_tunnel;
-+ debug_netlink |= pfkey_x_debug->sadb_x_debug_netlink;
-+ debug_xform |= pfkey_x_debug->sadb_x_debug_xform;
-+ debug_eroute |= pfkey_x_debug->sadb_x_debug_eroute;
-+ debug_spi |= pfkey_x_debug->sadb_x_debug_spi;
-+ debug_radij |= pfkey_x_debug->sadb_x_debug_radij;
-+ debug_esp |= pfkey_x_debug->sadb_x_debug_esp;
-+ debug_ah |= pfkey_x_debug->sadb_x_debug_ah;
-+ debug_rcv |= pfkey_x_debug->sadb_x_debug_rcv;
-+ debug_pfkey |= pfkey_x_debug->sadb_x_debug_pfkey;
-+#ifdef CONFIG_IPSEC_IPCOMP
-+ sysctl_ipsec_debug_ipcomp |= pfkey_x_debug->sadb_x_debug_ipcomp;
-+#endif /* CONFIG_IPSEC_IPCOMP */
-+ sysctl_ipsec_debug_verbose |= pfkey_x_debug->sadb_x_debug_verbose;
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_x_debug_process: "
-+ "set\n");
-+ } else {
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_x_debug_process: "
-+ "unset\n");
-+ debug_tunnel &= pfkey_x_debug->sadb_x_debug_tunnel;
-+ debug_netlink &= pfkey_x_debug->sadb_x_debug_netlink;
-+ debug_xform &= pfkey_x_debug->sadb_x_debug_xform;
-+ debug_eroute &= pfkey_x_debug->sadb_x_debug_eroute;
-+ debug_spi &= pfkey_x_debug->sadb_x_debug_spi;
-+ debug_radij &= pfkey_x_debug->sadb_x_debug_radij;
-+ debug_esp &= pfkey_x_debug->sadb_x_debug_esp;
-+ debug_ah &= pfkey_x_debug->sadb_x_debug_ah;
-+ debug_rcv &= pfkey_x_debug->sadb_x_debug_rcv;
-+ debug_pfkey &= pfkey_x_debug->sadb_x_debug_pfkey;
-+#ifdef CONFIG_IPSEC_IPCOMP
-+ sysctl_ipsec_debug_ipcomp &= pfkey_x_debug->sadb_x_debug_ipcomp;
-+#endif /* CONFIG_IPSEC_IPCOMP */
-+ sysctl_ipsec_debug_verbose &= pfkey_x_debug->sadb_x_debug_verbose;
-+ }
-+#else /* CONFIG_IPSEC_DEBUG */
-+ printk("klips_debug:pfkey_x_debug_process: "
-+ "debugging not enabled\n");
-+ SENDERR(EINVAL);
-+#endif /* CONFIG_IPSEC_DEBUG */
-+
-+errlab:
-+ return error;
-+}
-+
-+/*
-+ * $Log: pfkey_v2_ext_process.c,v $
-+ * Revision 1.15 2004/04/06 02:49:26 mcr
-+ * pullup of algo code from alg-branch.
-+ *
-+ * Revision 1.14 2004/02/03 03:13:59 mcr
-+ * no longer #ifdef out NON_ESP mode. That was a mistake.
-+ *
-+ * Revision 1.13 2003/12/15 18:13:12 mcr
-+ * when compiling with NAT traversal, don't assume that the
-+ * kernel has been patched, unless CONFIG_IPSEC_NAT_NON_ESP
-+ * is set.
-+ *
-+ * Revision 1.12.2.1 2003/12/22 15:25:52 jjo
-+ * Merged algo-0.8.1-rc11-test1 into alg-branch
-+ *
-+ * Revision 1.12 2003/12/10 01:14:27 mcr
-+ * NAT-traversal patches to KLIPS.
-+ *
-+ * Revision 1.11 2003/10/31 02:27:55 mcr
-+ * pulled up port-selector patches and sa_id elimination.
-+ *
-+ * Revision 1.10.4.2 2003/10/29 01:30:41 mcr
-+ * elimited "struct sa_id".
-+ *
-+ * Revision 1.10.4.1 2003/09/21 13:59:56 mcr
-+ * pre-liminary X.509 patch - does not yet pass tests.
-+ *
-+ * Revision 1.10 2003/02/06 01:51:41 rgb
-+ * Removed no longer relevant comment
-+ *
-+ * Revision 1.9 2003/01/30 02:32:44 rgb
-+ *
-+ * Transmit error code through to caller from callee for better diagnosis of problems.
-+ *
-+ * Revision 1.8 2002/12/13 22:42:22 mcr
-+ * restored sa_ref code
-+ *
-+ * Revision 1.7 2002/12/13 22:40:48 mcr
-+ * temporarily removed sadb_x_sa_ref reference for 2.xx
-+ *
-+ * Revision 1.6 2002/10/05 05:02:58 dhr
-+ *
-+ * C labels go on statements
-+ *
-+ * Revision 1.5 2002/09/20 15:41:08 rgb
-+ * Switch from pfkey_alloc_ipsec_sa() to ipsec_sa_alloc().
-+ * Added sadb_x_sa_ref to struct sadb_sa.
-+ *
-+ * Revision 1.4 2002/09/20 05:02:02 rgb
-+ * Added memory allocation debugging.
-+ *
-+ * Revision 1.3 2002/07/24 18:44:54 rgb
-+ * Type fiddling to tame ia64 compiler.
-+ *
-+ * Revision 1.2 2002/05/27 18:55:03 rgb
-+ * Remove final vistiges of tdb references via IPSEC_KLIPS1_COMPAT.
-+ *
-+ * Revision 1.1 2002/05/14 02:33:51 rgb
-+ * Moved all the extension processing functions to pfkey_v2_ext_process.c.
-+ *
-+ *
-+ * Local variables:
-+ * c-file-style: "linux"
-+ * End:
-+ *
-+ */
---- /dev/null Tue Mar 11 13:02:56 2003
-+++ linux/net/ipsec/pfkey_v2_parser.c Mon Feb 9 13:51:03 2004
-@@ -0,0 +1,4018 @@
-+/*
-+ * @(#) RFC2367 PF_KEYv2 Key management API message parser
-+ * Copyright (C) 1999, 2000, 2001 Richard Guy Briggs <rgb@freeswan.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. See <http://www.fsf.org/copyleft/gpl.txt>.
-+ *
-+ * 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.
-+ *
-+ * RCSID $Id: pfkey_v2_parser.c,v 1.123 2004/04/06 02:49:26 mcr Exp $
-+ */
-+
-+/*
-+ * Template from klips/net/ipsec/ipsec/ipsec_netlink.c.
-+ */
-+
-+char pfkey_v2_parser_c_version[] = "$Id: pfkey_v2_parser.c,v 1.123 2004/04/06 02:49:26 mcr Exp $";
-+
-+#include <linux/config.h>
-+#include <linux/version.h>
-+#include <linux/kernel.h> /* printk() */
-+
-+#include "openswan/ipsec_param.h"
-+
-+#ifdef MALLOC_SLAB
-+# include <linux/slab.h> /* kmalloc() */
-+#else /* MALLOC_SLAB */
-+# include <linux/malloc.h> /* kmalloc() */
-+#endif /* MALLOC_SLAB */
-+#include <linux/errno.h> /* error codes */
-+#include <linux/types.h> /* size_t */
-+#include <linux/interrupt.h> /* mark_bh */
-+
-+#include <linux/netdevice.h> /* struct device, and other headers */
-+#include <linux/etherdevice.h> /* eth_type_trans */
-+#include <linux/ip.h> /* struct iphdr */
-+#include <linux/skbuff.h>
-+
-+#include <openswan.h>
-+
-+#include <crypto/des.h>
-+
-+#ifdef SPINLOCK
-+# ifdef SPINLOCK_23
-+# include <linux/spinlock.h> /* *lock* */
-+# else /* SPINLOCK_23 */
-+# include <asm/spinlock.h> /* *lock* */
-+# endif /* SPINLOCK_23 */
-+#endif /* SPINLOCK */
-+#ifdef NET_21
-+# include <asm/uaccess.h>
-+# include <linux/in6.h>
-+# define ip_chk_addr inet_addr_type
-+# define IS_MYADDR RTN_LOCAL
-+#endif
-+#include <asm/checksum.h>
-+#include <net/ip.h>
-+#ifdef NETLINK_SOCK
-+# include <linux/netlink.h>
-+#else
-+# include <net/netlink.h>
-+#endif
-+
-+#include <linux/random.h> /* get_random_bytes() */
-+
-+#include "openswan/radij.h"
-+#include "openswan/ipsec_encap.h"
-+#include "openswan/ipsec_sa.h"
-+
-+#include "openswan/ipsec_radij.h"
-+#include "openswan/ipsec_xform.h"
-+#include "openswan/ipsec_ah.h"
-+#include "openswan/ipsec_esp.h"
-+#include "openswan/ipsec_tunnel.h"
-+#include "openswan/ipsec_rcv.h"
-+#include "openswan/ipcomp.h"
-+
-+#include <pfkeyv2.h>
-+#include <pfkey.h>
-+
-+#include "openswan/ipsec_proto.h"
-+#include "openswan/ipsec_alg.h"
-+
-+
-+#define SENDERR(_x) do { error = -(_x); goto errlab; } while (0)
-+
-+struct sklist_t {
-+ struct socket *sk;
-+ struct sklist_t* next;
-+} pfkey_sklist_head, *pfkey_sklist, *pfkey_sklist_prev;
-+
-+__u32 pfkey_msg_seq = 0;
-+
-+
-+#if 0
-+#define DUMP_SAID dump_said(&extr->ips->ips_said, __LINE__)
-+#define DUMP_SAID2 dump_said(&extr.ips->ips_said, __LINE__)
-+static void dump_said(ip_said *s, int line)
-+{
-+ char msa[SATOT_BUF];
-+ size_t msa_len;
-+
-+ msa_len = satot(s, 0, msa, sizeof(msa));
-+
-+ printk("line: %d msa: %s\n", line, msa);
-+}
-+#endif
-+
-+
-+int
-+pfkey_alloc_eroute(struct eroute** eroute)
-+{
-+ int error = 0;
-+ if(*eroute) {
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_alloc_eroute: "
-+ "eroute struct already allocated\n");
-+ SENDERR(EEXIST);
-+ }
-+
-+ if((*eroute = kmalloc(sizeof(**eroute), GFP_ATOMIC) ) == NULL) {
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_alloc_eroute: "
-+ "memory allocation error\n");
-+ SENDERR(ENOMEM);
-+ }
-+
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_alloc_eroute: "
-+ "allocating %lu bytes for an eroute at 0p%p\n",
-+ (unsigned long) sizeof(**eroute), *eroute);
-+
-+ memset((caddr_t)*eroute, 0, sizeof(**eroute));
-+ (*eroute)->er_eaddr.sen_len =
-+ (*eroute)->er_emask.sen_len = sizeof(struct sockaddr_encap);
-+ (*eroute)->er_eaddr.sen_family =
-+ (*eroute)->er_emask.sen_family = AF_ENCAP;
-+ (*eroute)->er_eaddr.sen_type = SENT_IP4;
-+ (*eroute)->er_emask.sen_type = 255;
-+ (*eroute)->er_pid = 0;
-+ (*eroute)->er_count = 0;
-+ (*eroute)->er_lasttime = jiffies/HZ;
-+
-+ errlab:
-+ return(error);
-+}
-+
-+DEBUG_NO_STATIC int
-+pfkey_x_protocol_process(struct sadb_ext *pfkey_ext,
-+ struct pfkey_extracted_data *extr)
-+{
-+ int error = 0;
-+ struct sadb_protocol * p = (struct sadb_protocol *)pfkey_ext;
-+
-+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_x_protocol_process: %p\n", extr);
-+
-+ if (extr == 0) {
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_x_protocol_process:"
-+ "extr is NULL, fatal\n");
-+ SENDERR(EINVAL);
-+ }
-+ if (extr->eroute == 0) {
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_x_protocol_process:"
-+ "extr->eroute is NULL, fatal\n");
-+ SENDERR(EINVAL);
-+ }
-+
-+ extr->eroute->er_eaddr.sen_proto = p->sadb_protocol_proto;
-+ extr->eroute->er_emask.sen_proto = p->sadb_protocol_proto ? ~0:0;
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_x_protocol_process: protocol = %d.\n",
-+ p->sadb_protocol_proto);
-+ errlab:
-+ return error;
-+}
-+
-+DEBUG_NO_STATIC int
-+pfkey_ipsec_sa_init(struct ipsec_sa *ipsp, struct sadb_ext **extensions)
-+{
-+ int i;
-+ int error = 0;
-+ char sa[SATOT_BUF];
-+ size_t sa_len;
-+ char ipaddr_txt[ADDRTOA_BUF];
-+ char ipaddr2_txt[ADDRTOA_BUF];
-+#if defined (CONFIG_IPSEC_AUTH_HMAC_MD5) || defined (CONFIG_IPSEC_AUTH_HMAC_SHA1)
-+ unsigned char kb[AHMD596_BLKLEN];
-+#endif
-+#ifdef CONFIG_IPSEC_ALG
-+ struct ipsec_alg_enc *ixt_e = NULL;
-+ struct ipsec_alg_auth *ixt_a = NULL;
-+#endif /* CONFIG_IPSEC_ALG */
-+
-+ if(ipsp == NULL) {
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_ipsec_sa_init: "
-+ "ipsp is NULL, fatal\n");
-+ SENDERR(EINVAL);
-+ }
-+
-+ sa_len = satot(&ipsp->ips_said, 0, sa, sizeof(sa));
-+
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_ipsec_sa_init: "
-+ "(pfkey defined) called for SA:%s\n",
-+ sa_len ? sa : " (error)");
-+
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_ipsec_sa_init: "
-+ "calling init routine of %s%s%s\n",
-+ IPS_XFORM_NAME(ipsp));
-+
-+ switch(ipsp->ips_said.proto) {
-+
-+#ifdef CONFIG_IPSEC_IPIP
-+ case IPPROTO_IPIP: {
-+ addrtoa(((struct sockaddr_in*)(ipsp->ips_addr_s))->sin_addr,
-+ 0,
-+ ipaddr_txt, sizeof(ipaddr_txt));
-+ addrtoa(((struct sockaddr_in*)(ipsp->ips_addr_d))->sin_addr,
-+ 0,
-+ ipaddr2_txt, sizeof(ipaddr_txt));
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_ipsec_sa_init: "
-+ "(pfkey defined) IPIP ipsec_sa set for %s->%s.\n",
-+ ipaddr_txt,
-+ ipaddr2_txt);
-+ }
-+ break;
-+#endif /* !CONFIG_IPSEC_IPIP */
-+#ifdef CONFIG_IPSEC_AH
-+ case IPPROTO_AH:
-+ switch(ipsp->ips_authalg) {
-+# ifdef CONFIG_IPSEC_AUTH_HMAC_MD5
-+ case AH_MD5: {
-+ unsigned char *akp;
-+ unsigned int aks;
-+ MD5_CTX *ictx;
-+ MD5_CTX *octx;
-+
-+ if(ipsp->ips_key_bits_a != (AHMD596_KLEN * 8)) {
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_ipsec_sa_init: "
-+ "incorrect key size: %d bits -- must be %d bits\n"/*octets (bytes)\n"*/,
-+ ipsp->ips_key_bits_a, AHMD596_KLEN * 8);
-+ SENDERR(EINVAL);
-+ }
-+
-+# if KLIPS_DIVULGE_HMAC_KEY
-+ KLIPS_PRINT(debug_pfkey && sysctl_ipsec_debug_verbose,
-+ "klips_debug:pfkey_ipsec_sa_init: "
-+ "hmac md5-96 key is 0x%08x %08x %08x %08x\n",
-+ ntohl(*(((__u32 *)ipsp->ips_key_a)+0)),
-+ ntohl(*(((__u32 *)ipsp->ips_key_a)+1)),
-+ ntohl(*(((__u32 *)ipsp->ips_key_a)+2)),
-+ ntohl(*(((__u32 *)ipsp->ips_key_a)+3)));
-+# endif /* KLIPS_DIVULGE_HMAC_KEY */
-+
-+ ipsp->ips_auth_bits = AHMD596_ALEN * 8;
-+
-+ /* save the pointer to the key material */
-+ akp = ipsp->ips_key_a;
-+ aks = ipsp->ips_key_a_size;
-+
-+ KLIPS_PRINT(debug_pfkey && sysctl_ipsec_debug_verbose,
-+ "klips_debug:pfkey_ipsec_sa_init: "
-+ "allocating %lu bytes for md5_ctx.\n",
-+ (unsigned long) sizeof(struct md5_ctx));
-+ if((ipsp->ips_key_a = (caddr_t)
-+ kmalloc(sizeof(struct md5_ctx), GFP_ATOMIC)) == NULL) {
-+ ipsp->ips_key_a = akp;
-+ SENDERR(ENOMEM);
-+ }
-+ ipsp->ips_key_a_size = sizeof(struct md5_ctx);
-+
-+ for (i = 0; i < DIVUP(ipsp->ips_key_bits_a, 8); i++) {
-+ kb[i] = akp[i] ^ HMAC_IPAD;
-+ }
-+ for (; i < AHMD596_BLKLEN; i++) {
-+ kb[i] = HMAC_IPAD;
-+ }
-+
-+ ictx = &(((struct md5_ctx*)(ipsp->ips_key_a))->ictx);
-+ MD5Init(ictx);
-+ MD5Update(ictx, kb, AHMD596_BLKLEN);
-+
-+ for (i = 0; i < AHMD596_BLKLEN; i++) {
-+ kb[i] ^= (HMAC_IPAD ^ HMAC_OPAD);
-+ }
-+
-+ octx = &(((struct md5_ctx*)(ipsp->ips_key_a))->octx);
-+ MD5Init(octx);
-+ MD5Update(octx, kb, AHMD596_BLKLEN);
-+
-+# if KLIPS_DIVULGE_HMAC_KEY
-+ KLIPS_PRINT(debug_pfkey && sysctl_ipsec_debug_verbose,
-+ "klips_debug:pfkey_ipsec_sa_init: "
-+ "MD5 ictx=0x%08x %08x %08x %08x octx=0x%08x %08x %08x %08x\n",
-+ ((__u32*)ictx)[0],
-+ ((__u32*)ictx)[1],
-+ ((__u32*)ictx)[2],
-+ ((__u32*)ictx)[3],
-+ ((__u32*)octx)[0],
-+ ((__u32*)octx)[1],
-+ ((__u32*)octx)[2],
-+ ((__u32*)octx)[3] );
-+# endif /* KLIPS_DIVULGE_HMAC_KEY */
-+
-+ /* zero key buffer -- paranoid */
-+ memset(akp, 0, aks);
-+ kfree(akp);
-+ }
-+ break;
-+# endif /* CONFIG_IPSEC_AUTH_HMAC_MD5 */
-+# ifdef CONFIG_IPSEC_AUTH_HMAC_SHA1
-+ case AH_SHA: {
-+ unsigned char *akp;
-+ unsigned int aks;
-+ SHA1_CTX *ictx;
-+ SHA1_CTX *octx;
-+
-+ if(ipsp->ips_key_bits_a != (AHSHA196_KLEN * 8)) {
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_ipsec_sa_init: "
-+ "incorrect key size: %d bits -- must be %d bits\n"/*octets (bytes)\n"*/,
-+ ipsp->ips_key_bits_a, AHSHA196_KLEN * 8);
-+ SENDERR(EINVAL);
-+ }
-+
-+# if KLIPS_DIVULGE_HMAC_KEY
-+ KLIPS_PRINT(debug_pfkey && sysctl_ipsec_debug_verbose,
-+ "klips_debug:pfkey_ipsec_sa_init: "
-+ "hmac sha1-96 key is 0x%08x %08x %08x %08x\n",
-+ ntohl(*(((__u32 *)ipsp->ips_key_a)+0)),
-+ ntohl(*(((__u32 *)ipsp->ips_key_a)+1)),
-+ ntohl(*(((__u32 *)ipsp->ips_key_a)+2)),
-+ ntohl(*(((__u32 *)ipsp->ips_key_a)+3)));
-+# endif /* KLIPS_DIVULGE_HMAC_KEY */
-+
-+ ipsp->ips_auth_bits = AHSHA196_ALEN * 8;
-+
-+ /* save the pointer to the key material */
-+ akp = ipsp->ips_key_a;
-+ aks = ipsp->ips_key_a_size;
-+
-+ KLIPS_PRINT(debug_pfkey && sysctl_ipsec_debug_verbose,
-+ "klips_debug:pfkey_ipsec_sa_init: "
-+ "allocating %lu bytes for sha1_ctx.\n",
-+ (unsigned long) sizeof(struct sha1_ctx));
-+ if((ipsp->ips_key_a = (caddr_t)
-+ kmalloc(sizeof(struct sha1_ctx), GFP_ATOMIC)) == NULL) {
-+ ipsp->ips_key_a = akp;
-+ SENDERR(ENOMEM);
-+ }
-+ ipsp->ips_key_a_size = sizeof(struct sha1_ctx);
-+
-+ for (i = 0; i < DIVUP(ipsp->ips_key_bits_a, 8); i++) {
-+ kb[i] = akp[i] ^ HMAC_IPAD;
-+ }
-+ for (; i < AHMD596_BLKLEN; i++) {
-+ kb[i] = HMAC_IPAD;
-+ }
-+
-+ ictx = &(((struct sha1_ctx*)(ipsp->ips_key_a))->ictx);
-+ SHA1Init(ictx);
-+ SHA1Update(ictx, kb, AHSHA196_BLKLEN);
-+
-+ for (i = 0; i < AHSHA196_BLKLEN; i++) {
-+ kb[i] ^= (HMAC_IPAD ^ HMAC_OPAD);
-+ }
-+
-+ octx = &(((struct sha1_ctx*)(ipsp->ips_key_a))->octx);
-+ SHA1Init(octx);
-+ SHA1Update(octx, kb, AHSHA196_BLKLEN);
-+
-+# if KLIPS_DIVULGE_HMAC_KEY
-+ KLIPS_PRINT(debug_pfkey && sysctl_ipsec_debug_verbose,
-+ "klips_debug:pfkey_ipsec_sa_init: "
-+ "SHA1 ictx=0x%08x %08x %08x %08x octx=0x%08x %08x %08x %08x\n",
-+ ((__u32*)ictx)[0],
-+ ((__u32*)ictx)[1],
-+ ((__u32*)ictx)[2],
-+ ((__u32*)ictx)[3],
-+ ((__u32*)octx)[0],
-+ ((__u32*)octx)[1],
-+ ((__u32*)octx)[2],
-+ ((__u32*)octx)[3] );
-+# endif /* KLIPS_DIVULGE_HMAC_KEY */
-+ /* zero key buffer -- paranoid */
-+ memset(akp, 0, aks);
-+ kfree(akp);
-+ }
-+ break;
-+# endif /* CONFIG_IPSEC_AUTH_HMAC_SHA1 */
-+ default:
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_ipsec_sa_init: "
-+ "authalg=%d support not available in the kernel",
-+ ipsp->ips_authalg);
-+ SENDERR(EINVAL);
-+ }
-+ break;
-+#endif /* CONFIG_IPSEC_AH */
-+#ifdef CONFIG_IPSEC_ESP
-+ case IPPROTO_ESP: {
-+#if defined (CONFIG_IPSEC_AUTH_HMAC_MD5) || defined (CONFIG_IPSEC_AUTH_HMAC_SHA1)
-+ unsigned char *akp;
-+ unsigned int aks;
-+#endif
-+#if defined (CONFIG_IPSEC_ENC_3DES)
-+ unsigned char *ekp;
-+ unsigned int eks;
-+#endif
-+
-+ ipsp->ips_iv_size = 0;
-+#ifdef CONFIG_IPSEC_ALG
-+ if ((ixt_e=ipsp->ips_alg_enc)) {
-+ ipsp->ips_iv_size = ixt_e->ixt_ivlen/8;
-+ } else
-+#endif /* CONFIG_IPSEC_ALG */
-+ switch(ipsp->ips_encalg) {
-+# ifdef CONFIG_IPSEC_ENC_3DES
-+ case ESP_3DES:
-+# endif /* CONFIG_IPSEC_ENC_3DES */
-+# if defined(CONFIG_IPSEC_ENC_3DES)
-+ KLIPS_PRINT(debug_pfkey && sysctl_ipsec_debug_verbose,
-+ "klips_debug:pfkey_ipsec_sa_init: "
-+ "allocating %u bytes for iv.\n",
-+ EMT_ESPDES_IV_SZ);
-+ if((ipsp->ips_iv = (caddr_t)
-+ kmalloc((ipsp->ips_iv_size = EMT_ESPDES_IV_SZ), GFP_ATOMIC)) == NULL) {
-+ SENDERR(ENOMEM);
-+ }
-+ prng_bytes(&ipsec_prng, (char *)ipsp->ips_iv, EMT_ESPDES_IV_SZ);
-+ ipsp->ips_iv_bits = ipsp->ips_iv_size * 8;
-+ ipsp->ips_iv_size = EMT_ESPDES_IV_SZ;
-+ break;
-+# endif /* defined(CONFIG_IPSEC_ENC_3DES) */
-+ case ESP_NONE:
-+ break;
-+ default:
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_ipsec_sa_init: "
-+ "encalg=%d support not available in the kernel",
-+ ipsp->ips_encalg);
-+ SENDERR(EINVAL);
-+ }
-+
-+ /* Create IV */
-+ if (ipsp->ips_iv_size) {
-+ if((ipsp->ips_iv = (caddr_t)
-+ kmalloc(ipsp->ips_iv_size, GFP_ATOMIC)) == NULL) {
-+ SENDERR(ENOMEM);
-+ }
-+ prng_bytes(&ipsec_prng, (char *)ipsp->ips_iv, ipsp->ips_iv_size);
-+ ipsp->ips_iv_bits = ipsp->ips_iv_size * 8;
-+ }
-+
-+#ifdef CONFIG_IPSEC_ALG
-+ if (ixt_e) {
-+ if ((error=ipsec_alg_enc_key_create(ipsp)) < 0)
-+ SENDERR(-error);
-+ } else
-+#endif /* CONFIG_IPSEC_ALG */
-+ switch(ipsp->ips_encalg) {
-+# ifdef CONFIG_IPSEC_ENC_3DES
-+ case ESP_3DES:
-+ if(ipsp->ips_key_bits_e != (EMT_ESP3DES_KEY_SZ * 8)) {
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_ipsec_sa_init: "
-+ "incorrect encryption key size: %d bits -- must be %d bits\n"/*octets (bytes)\n"*/,
-+ ipsp->ips_key_bits_e, EMT_ESP3DES_KEY_SZ * 8);
-+ SENDERR(EINVAL);
-+ }
-+
-+ /* save encryption key pointer */
-+ ekp = ipsp->ips_key_e;
-+ eks = ipsp->ips_key_e_size;
-+
-+ KLIPS_PRINT(debug_pfkey && sysctl_ipsec_debug_verbose,
-+ "klips_debug:pfkey_ipsec_sa_init: "
-+ "allocating %lu bytes for 3des.\n",
-+ (unsigned long) (3 * sizeof(struct des_eks)));
-+ if((ipsp->ips_key_e = (caddr_t)
-+ kmalloc(3 * sizeof(struct des_eks), GFP_ATOMIC)) == NULL) {
-+ ipsp->ips_key_e = ekp;
-+ SENDERR(ENOMEM);
-+ }
-+ ipsp->ips_key_e_size = 3 * sizeof(struct des_eks);
-+
-+ for(i = 0; i < 3; i++) {
-+#if KLIPS_DIVULGE_CYPHER_KEY
-+ KLIPS_PRINT(debug_pfkey && sysctl_ipsec_debug_verbose,
-+ "klips_debug:pfkey_ipsec_sa_init: "
-+ "3des key %d/3 is 0x%08x%08x\n",
-+ i + 1,
-+ ntohl(*((__u32 *)ekp + i * 2)),
-+ ntohl(*((__u32 *)ekp + i * 2 + 1)));
-+# endif
-+#if KLIPS_FIXES_DES_PARITY
-+ /* force parity */
-+ des_set_odd_parity((des_cblock *)(ekp + EMT_ESPDES_KEY_SZ * i));
-+#endif
-+ error = des_set_key((des_cblock *)(ekp + EMT_ESPDES_KEY_SZ * i),
-+ ((struct des_eks *)(ipsp->ips_key_e))[i].ks);
-+ if (error == -1)
-+ printk("klips_debug:pfkey_ipsec_sa_init: "
-+ "parity error in des key %d/3\n",
-+ i + 1);
-+ else if (error == -2)
-+ printk("klips_debug:pfkey_ipsec_sa_init: "
-+ "illegal weak des key %d/3\n", i + 1);
-+ if (error) {
-+ memset(ekp, 0, eks);
-+ kfree(ekp);
-+ SENDERR(EINVAL);
-+ }
-+ }
-+
-+ /* paranoid */
-+ memset(ekp, 0, eks);
-+ kfree(ekp);
-+ break;
-+# endif /* CONFIG_IPSEC_ENC_3DES */
-+ case ESP_NONE:
-+ break;
-+ default:
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_ipsec_sa_init: "
-+ "encalg=%d support not available in the kernel",
-+ ipsp->ips_encalg);
-+ SENDERR(EINVAL);
-+ }
-+
-+#ifdef CONFIG_IPSEC_ALG
-+ if ((ixt_a=ipsp->ips_alg_auth)) {
-+ if ((error=ipsec_alg_auth_key_create(ipsp)) < 0)
-+ SENDERR(-error);
-+ } else
-+#endif /* CONFIG_IPSEC_ALG */
-+
-+ switch(ipsp->ips_authalg) {
-+# ifdef CONFIG_IPSEC_AUTH_HMAC_MD5
-+ case AH_MD5: {
-+ MD5_CTX *ictx;
-+ MD5_CTX *octx;
-+
-+ if(ipsp->ips_key_bits_a != (AHMD596_KLEN * 8)) {
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_ipsec_sa_init: "
-+ "incorrect authorisation key size: %d bits -- must be %d bits\n"/*octets (bytes)\n"*/,
-+ ipsp->ips_key_bits_a,
-+ AHMD596_KLEN * 8);
-+ SENDERR(EINVAL);
-+ }
-+
-+# if KLIPS_DIVULGE_HMAC_KEY
-+ KLIPS_PRINT(debug_pfkey && sysctl_ipsec_debug_verbose,
-+ "klips_debug:pfkey_ipsec_sa_init: "
-+ "hmac md5-96 key is 0x%08x %08x %08x %08x\n",
-+ ntohl(*(((__u32 *)(ipsp->ips_key_a))+0)),
-+ ntohl(*(((__u32 *)(ipsp->ips_key_a))+1)),
-+ ntohl(*(((__u32 *)(ipsp->ips_key_a))+2)),
-+ ntohl(*(((__u32 *)(ipsp->ips_key_a))+3)));
-+# endif /* KLIPS_DIVULGE_HMAC_KEY */
-+ ipsp->ips_auth_bits = AHMD596_ALEN * 8;
-+
-+ /* save the pointer to the key material */
-+ akp = ipsp->ips_key_a;
-+ aks = ipsp->ips_key_a_size;
-+
-+ KLIPS_PRINT(debug_pfkey && sysctl_ipsec_debug_verbose,
-+ "klips_debug:pfkey_ipsec_sa_init: "
-+ "allocating %lu bytes for md5_ctx.\n",
-+ (unsigned long) sizeof(struct md5_ctx));
-+ if((ipsp->ips_key_a = (caddr_t)
-+ kmalloc(sizeof(struct md5_ctx), GFP_ATOMIC)) == NULL) {
-+ ipsp->ips_key_a = akp;
-+ SENDERR(ENOMEM);
-+ }
-+ ipsp->ips_key_a_size = sizeof(struct md5_ctx);
-+
-+ for (i = 0; i < DIVUP(ipsp->ips_key_bits_a, 8); i++) {
-+ kb[i] = akp[i] ^ HMAC_IPAD;
-+ }
-+ for (; i < AHMD596_BLKLEN; i++) {
-+ kb[i] = HMAC_IPAD;
-+ }
-+
-+ ictx = &(((struct md5_ctx*)(ipsp->ips_key_a))->ictx);
-+ MD5Init(ictx);
-+ MD5Update(ictx, kb, AHMD596_BLKLEN);
-+
-+ for (i = 0; i < AHMD596_BLKLEN; i++) {
-+ kb[i] ^= (HMAC_IPAD ^ HMAC_OPAD);
-+ }
-+
-+ octx = &(((struct md5_ctx*)(ipsp->ips_key_a))->octx);
-+ MD5Init(octx);
-+ MD5Update(octx, kb, AHMD596_BLKLEN);
-+
-+# if KLIPS_DIVULGE_HMAC_KEY
-+ KLIPS_PRINT(debug_pfkey && sysctl_ipsec_debug_verbose,
-+ "klips_debug:pfkey_ipsec_sa_init: "
-+ "MD5 ictx=0x%08x %08x %08x %08x octx=0x%08x %08x %08x %08x\n",
-+ ((__u32*)ictx)[0],
-+ ((__u32*)ictx)[1],
-+ ((__u32*)ictx)[2],
-+ ((__u32*)ictx)[3],
-+ ((__u32*)octx)[0],
-+ ((__u32*)octx)[1],
-+ ((__u32*)octx)[2],
-+ ((__u32*)octx)[3] );
-+# endif /* KLIPS_DIVULGE_HMAC_KEY */
-+ /* paranoid */
-+ memset(akp, 0, aks);
-+ kfree(akp);
-+ break;
-+ }
-+# endif /* CONFIG_IPSEC_AUTH_HMAC_MD5 */
-+# ifdef CONFIG_IPSEC_AUTH_HMAC_SHA1
-+ case AH_SHA: {
-+ SHA1_CTX *ictx;
-+ SHA1_CTX *octx;
-+
-+ if(ipsp->ips_key_bits_a != (AHSHA196_KLEN * 8)) {
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_ipsec_sa_init: "
-+ "incorrect authorisation key size: %d bits -- must be %d bits\n"/*octets (bytes)\n"*/,
-+ ipsp->ips_key_bits_a,
-+ AHSHA196_KLEN * 8);
-+ SENDERR(EINVAL);
-+ }
-+
-+# if KLIPS_DIVULGE_HMAC_KEY
-+ KLIPS_PRINT(debug_pfkey && sysctl_ipsec_debug_verbose,
-+ "klips_debug:pfkey_ipsec_sa_init: "
-+ "hmac sha1-96 key is 0x%08x %08x %08x %08x\n",
-+ ntohl(*(((__u32 *)ipsp->ips_key_a)+0)),
-+ ntohl(*(((__u32 *)ipsp->ips_key_a)+1)),
-+ ntohl(*(((__u32 *)ipsp->ips_key_a)+2)),
-+ ntohl(*(((__u32 *)ipsp->ips_key_a)+3)));
-+# endif /* KLIPS_DIVULGE_HMAC_KEY */
-+ ipsp->ips_auth_bits = AHSHA196_ALEN * 8;
-+
-+ /* save the pointer to the key material */
-+ akp = ipsp->ips_key_a;
-+ aks = ipsp->ips_key_a_size;
-+
-+ KLIPS_PRINT(debug_pfkey && sysctl_ipsec_debug_verbose,
-+ "klips_debug:pfkey_ipsec_sa_init: "
-+ "allocating %lu bytes for sha1_ctx.\n",
-+ (unsigned long) sizeof(struct sha1_ctx));
-+ if((ipsp->ips_key_a = (caddr_t)
-+ kmalloc(sizeof(struct sha1_ctx), GFP_ATOMIC)) == NULL) {
-+ ipsp->ips_key_a = akp;
-+ SENDERR(ENOMEM);
-+ }
-+ ipsp->ips_key_a_size = sizeof(struct sha1_ctx);
-+
-+ for (i = 0; i < DIVUP(ipsp->ips_key_bits_a, 8); i++) {
-+ kb[i] = akp[i] ^ HMAC_IPAD;
-+ }
-+ for (; i < AHMD596_BLKLEN; i++) {
-+ kb[i] = HMAC_IPAD;
-+ }
-+
-+ ictx = &(((struct sha1_ctx*)(ipsp->ips_key_a))->ictx);
-+ SHA1Init(ictx);
-+ SHA1Update(ictx, kb, AHSHA196_BLKLEN);
-+
-+ for (i = 0; i < AHSHA196_BLKLEN; i++) {
-+ kb[i] ^= (HMAC_IPAD ^ HMAC_OPAD);
-+ }
-+
-+ octx = &((struct sha1_ctx*)(ipsp->ips_key_a))->octx;
-+ SHA1Init(octx);
-+ SHA1Update(octx, kb, AHSHA196_BLKLEN);
-+
-+# if KLIPS_DIVULGE_HMAC_KEY
-+ KLIPS_PRINT(debug_pfkey && sysctl_ipsec_debug_verbose,
-+ "klips_debug:pfkey_ipsec_sa_init: "
-+ "SHA1 ictx=0x%08x %08x %08x %08x octx=0x%08x %08x %08x %08x\n",
-+ ((__u32*)ictx)[0],
-+ ((__u32*)ictx)[1],
-+ ((__u32*)ictx)[2],
-+ ((__u32*)ictx)[3],
-+ ((__u32*)octx)[0],
-+ ((__u32*)octx)[1],
-+ ((__u32*)octx)[2],
-+ ((__u32*)octx)[3] );
-+# endif /* KLIPS_DIVULGE_HMAC_KEY */
-+ memset(akp, 0, aks);
-+ kfree(akp);
-+ break;
-+ }
-+# endif /* CONFIG_IPSEC_AUTH_HMAC_SHA1 */
-+ case AH_NONE:
-+ break;
-+ default:
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_ipsec_sa_init: "
-+ "authalg=%d support not available in the kernel.\n",
-+ ipsp->ips_authalg);
-+ SENDERR(EINVAL);
-+ }
-+ }
-+ break;
-+#endif /* !CONFIG_IPSEC_ESP */
-+#ifdef CONFIG_IPSEC_IPCOMP
-+ case IPPROTO_COMP:
-+ ipsp->ips_comp_adapt_tries = 0;
-+ ipsp->ips_comp_adapt_skip = 0;
-+ ipsp->ips_comp_ratio_cbytes = 0;
-+ ipsp->ips_comp_ratio_dbytes = 0;
-+ break;
-+#endif /* CONFIG_IPSEC_IPCOMP */
-+ default:
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_ipsec_sa_init: "
-+ "proto=%d unknown.\n",
-+ ipsp->ips_said.proto);
-+ SENDERR(EINVAL);
-+ }
-+
-+ errlab:
-+ return(error);
-+}
-+
-+
-+int
-+pfkey_safe_build(int error, struct sadb_ext *extensions[SADB_MAX+1])
-+{
-+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_safe_build: "
-+ "error=%d\n",
-+ error);
-+ if (!error) {
-+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_safe_build:"
-+ "success.\n");
-+ return 1;
-+ } else {
-+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_safe_build:"
-+ "caught error %d\n",
-+ error);
-+ pfkey_extensions_free(extensions);
-+ return 0;
-+ }
-+}
-+
-+
-+DEBUG_NO_STATIC int
-+pfkey_getspi_parse(struct sock *sk, struct sadb_ext **extensions, struct pfkey_extracted_data* extr)
-+{
-+ int error = 0;
-+ ipsec_spi_t minspi = htonl(256), maxspi = htonl(-1L);
-+ int found_avail = 0;
-+ struct ipsec_sa *ipsq;
-+ char sa[SATOT_BUF];
-+ size_t sa_len;
-+ struct sadb_ext *extensions_reply[SADB_EXT_MAX+1];
-+ struct sadb_msg *pfkey_reply = NULL;
-+ struct socket_list *pfkey_socketsp;
-+ uint8_t satype = ((struct sadb_msg*)extensions[SADB_EXT_RESERVED])->sadb_msg_satype;
-+
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_getspi_parse: .\n");
-+
-+ pfkey_extensions_init(extensions_reply);
-+
-+ if(extr == NULL || extr->ips == NULL) {
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_getspi_parse: "
-+ "error, extr or extr->ipsec_sa pointer NULL\n");
-+ SENDERR(EINVAL);
-+ }
-+
-+ if(extensions[SADB_EXT_SPIRANGE]) {
-+ minspi = ((struct sadb_spirange *)extensions[SADB_EXT_SPIRANGE])->sadb_spirange_min;
-+ maxspi = ((struct sadb_spirange *)extensions[SADB_EXT_SPIRANGE])->sadb_spirange_max;
-+ }
-+
-+ if(maxspi == minspi) {
-+ extr->ips->ips_said.spi = maxspi;
-+ ipsq = ipsec_sa_getbyid(&(extr->ips->ips_said));
-+ if(ipsq != NULL) {
-+ sa_len = satot(&extr->ips->ips_said, 0, sa, sizeof(sa));
-+ ipsec_sa_put(ipsq);
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_getspi_parse: "
-+ "EMT_GETSPI found an old ipsec_sa for SA: %s, delete it first.\n",
-+ sa_len ? sa : " (error)");
-+ SENDERR(EEXIST);
-+ } else {
-+ found_avail = 1;
-+ }
-+ } else {
-+ int i = 0;
-+ __u32 rand_val;
-+ __u32 spi_diff;
-+ while( ( i < (spi_diff = (ntohl(maxspi) - ntohl(minspi)))) && !found_avail ) {
-+ prng_bytes(&ipsec_prng, (char *) &(rand_val),
-+ ( (spi_diff < (2^8)) ? 1 :
-+ ( (spi_diff < (2^16)) ? 2 :
-+ ( (spi_diff < (2^24)) ? 3 :
-+ 4 ) ) ) );
-+ extr->ips->ips_said.spi = htonl(ntohl(minspi) +
-+ (rand_val %
-+ (spi_diff + 1)));
-+ i++;
-+ ipsq = ipsec_sa_getbyid(&(extr->ips->ips_said));
-+ if(ipsq == NULL) {
-+ found_avail = 1;
-+ } else {
-+ ipsec_sa_put(ipsq);
-+ }
-+ }
-+ }
-+
-+ sa_len = satot(&extr->ips->ips_said, 0, sa, sizeof(sa));
-+
-+ if (!found_avail) {
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_getspi_parse: "
-+ "found an old ipsec_sa for SA: %s, delete it first.\n",
-+ sa_len ? sa : " (error)");
-+ SENDERR(EEXIST);
-+ }
-+
-+ if(ip_chk_addr((unsigned long)extr->ips->ips_said.dst.u.v4.sin_addr.s_addr) == IS_MYADDR) {
-+ extr->ips->ips_flags |= EMT_INBOUND;
-+ }
-+
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_getspi_parse: "
-+ "existing ipsec_sa not found (this is good) for SA: %s, %s-bound, allocating.\n",
-+ sa_len ? sa : " (error)",
-+ extr->ips->ips_flags & EMT_INBOUND ? "in" : "out");
-+
-+ /* XXX extr->ips->ips_rcvif = &(enc_softc[em->em_if].enc_if);*/
-+ extr->ips->ips_rcvif = NULL;
-+ extr->ips->ips_life.ipl_addtime.ipl_count = jiffies/HZ;
-+
-+ extr->ips->ips_state = SADB_SASTATE_LARVAL;
-+
-+ if(!extr->ips->ips_life.ipl_allocations.ipl_count) {
-+ extr->ips->ips_life.ipl_allocations.ipl_count += 1;
-+ }
-+
-+ if(!(pfkey_safe_build(error = pfkey_msg_hdr_build(&extensions_reply[0],
-+ SADB_GETSPI,
-+ satype,
-+ 0,
-+ ((struct sadb_msg*)extensions[SADB_EXT_RESERVED])->sadb_msg_seq,
-+ ((struct sadb_msg*)extensions[SADB_EXT_RESERVED])->sadb_msg_pid),
-+ extensions_reply)
-+ && pfkey_safe_build(error = pfkey_sa_ref_build(&extensions_reply[SADB_EXT_SA],
-+ SADB_EXT_SA,
-+ extr->ips->ips_said.spi,
-+ 0,
-+ SADB_SASTATE_LARVAL,
-+ 0,
-+ 0,
-+ 0,
-+ extr->ips->ips_ref),
-+ extensions_reply)
-+ && pfkey_safe_build(error = pfkey_address_build(&extensions_reply[SADB_EXT_ADDRESS_SRC],
-+ SADB_EXT_ADDRESS_SRC,
-+ 0, /*extr->ips->ips_said.proto,*/
-+ 0,
-+ extr->ips->ips_addr_s),
-+ extensions_reply)
-+ && pfkey_safe_build(error = pfkey_address_build(&extensions_reply[SADB_EXT_ADDRESS_DST],
-+ SADB_EXT_ADDRESS_DST,
-+ 0, /*extr->ips->ips_said.proto,*/
-+ 0,
-+ extr->ips->ips_addr_d),
-+ extensions_reply) )) {
-+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_getspi_parse: "
-+ "failed to build the getspi reply message extensions\n");
-+ goto errlab;
-+ }
-+
-+ if((error = pfkey_msg_build(&pfkey_reply, extensions_reply, EXT_BITS_OUT))) {
-+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_getspi_parse: "
-+ "failed to build the getspi reply message\n");
-+ SENDERR(-error);
-+ }
-+ for(pfkey_socketsp = pfkey_open_sockets;
-+ pfkey_socketsp;
-+ pfkey_socketsp = pfkey_socketsp->next) {
-+ if((error = pfkey_upmsg(pfkey_socketsp->socketp, pfkey_reply))) {
-+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_getspi_parse: "
-+ "sending up getspi reply message for satype=%d(%s) to socket=0p%p failed with error=%d.\n",
-+ satype,
-+ satype2name(satype),
-+ pfkey_socketsp->socketp,
-+ error);
-+ SENDERR(-error);
-+ }
-+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_getspi_parse: "
-+ "sending up getspi reply message for satype=%d(%s) to socket=0p%p succeeded.\n",
-+ satype,
-+ satype2name(satype),
-+ pfkey_socketsp->socketp);
-+ }
-+
-+ if((error = ipsec_sa_add(extr->ips))) {
-+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_getspi_parse: "
-+ "failed to add the larval SA=%s with error=%d.\n",
-+ sa_len ? sa : " (error)",
-+ error);
-+ SENDERR(-error);
-+ }
-+ extr->ips = NULL;
-+
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_getspi_parse: "
-+ "successful for SA: %s\n",
-+ sa_len ? sa : " (error)");
-+
-+ errlab:
-+ if (pfkey_reply) {
-+ pfkey_msg_free(&pfkey_reply);
-+ }
-+ pfkey_extensions_free(extensions_reply);
-+ return error;
-+}
-+
-+DEBUG_NO_STATIC int
-+pfkey_update_parse(struct sock *sk, struct sadb_ext **extensions, struct pfkey_extracted_data* extr)
-+{
-+ int error = 0;
-+ struct ipsec_sa* ipsq;
-+ char sa[SATOT_BUF];
-+ size_t sa_len;
-+ struct sadb_ext *extensions_reply[SADB_EXT_MAX+1];
-+ struct sadb_msg *pfkey_reply = NULL;
-+ struct socket_list *pfkey_socketsp;
-+ uint8_t satype = ((struct sadb_msg*)extensions[SADB_EXT_RESERVED])->sadb_msg_satype;
-+#ifdef CONFIG_IPSEC_NAT_TRAVERSAL
-+ struct ipsec_sa *nat_t_ips_saved = NULL;
-+#endif
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_update_parse: .\n");
-+
-+ pfkey_extensions_init(extensions_reply);
-+
-+ if(((struct sadb_sa*)extensions[SADB_EXT_SA])->sadb_sa_state != SADB_SASTATE_MATURE) {
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_update_parse: "
-+ "error, sa_state=%d must be MATURE=%d\n",
-+ ((struct sadb_sa*)extensions[SADB_EXT_SA])->sadb_sa_state,
-+ SADB_SASTATE_MATURE);
-+ SENDERR(EINVAL);
-+ }
-+
-+ if(extr == NULL || extr->ips == NULL) {
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_update_parse: "
-+ "error, extr or extr->ips pointer NULL\n");
-+ SENDERR(EINVAL);
-+ }
-+
-+ sa_len = satot(&extr->ips->ips_said, 0, sa, sizeof(sa));
-+
-+ spin_lock_bh(&tdb_lock);
-+
-+ ipsq = ipsec_sa_getbyid(&(extr->ips->ips_said));
-+ if (ipsq == NULL) {
-+ spin_unlock_bh(&tdb_lock);
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_update_parse: "
-+ "reserved ipsec_sa for SA: %s not found. Call SADB_GETSPI first or call SADB_ADD instead.\n",
-+ sa_len ? sa : " (error)");
-+ SENDERR(ENOENT);
-+ }
-+
-+ if(ip_chk_addr((unsigned long)extr->ips->ips_said.dst.u.v4.sin_addr.s_addr) == IS_MYADDR) {
-+ extr->ips->ips_flags |= EMT_INBOUND;
-+ }
-+
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_update_parse: "
-+ "existing ipsec_sa found (this is good) for SA: %s, %s-bound, updating.\n",
-+ sa_len ? sa : " (error)",
-+ extr->ips->ips_flags & EMT_INBOUND ? "in" : "out");
-+
-+#ifdef CONFIG_IPSEC_NAT_TRAVERSAL
-+ if (extr->ips->ips_natt_sport || extr->ips->ips_natt_dport) {
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_update_parse: only updating NAT-T ports "
-+ "(%u:%u -> %u:%u)\n",
-+ ipsq->ips_natt_sport, ipsq->ips_natt_dport,
-+ extr->ips->ips_natt_sport, extr->ips->ips_natt_dport);
-+
-+ if (extr->ips->ips_natt_sport) {
-+ ipsq->ips_natt_sport = extr->ips->ips_natt_sport;
-+ if (ipsq->ips_addr_s->sa_family == AF_INET) {
-+ ((struct sockaddr_in *)(ipsq->ips_addr_s))->sin_port = htons(extr->ips->ips_natt_sport);
-+ }
-+ }
-+
-+ if (extr->ips->ips_natt_dport) {
-+ ipsq->ips_natt_dport = extr->ips->ips_natt_dport;
-+ if (ipsq->ips_addr_d->sa_family == AF_INET) {
-+ ((struct sockaddr_in *)(ipsq->ips_addr_d))->sin_port = htons(extr->ips->ips_natt_dport);
-+ }
-+ }
-+
-+ nat_t_ips_saved = extr->ips;
-+ extr->ips = ipsq;
-+ }
-+ else {
-+#endif
-+
-+ /* XXX extr->ips->ips_rcvif = &(enc_softc[em->em_if].enc_if);*/
-+ extr->ips->ips_rcvif = NULL;
-+ if ((error = pfkey_ipsec_sa_init(extr->ips, extensions))) {
-+ ipsec_sa_put(ipsq);
-+ spin_unlock_bh(&tdb_lock);
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_update_parse: "
-+ "not successful for SA: %s, deleting.\n",
-+ sa_len ? sa : " (error)");
-+ SENDERR(-error);
-+ }
-+
-+ extr->ips->ips_life.ipl_addtime.ipl_count = ipsq->ips_life.ipl_addtime.ipl_count;
-+ ipsec_sa_put(ipsq);
-+ if((error = ipsec_sa_delchain(ipsq))) {
-+ spin_unlock_bh(&tdb_lock);
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_update_parse: "
-+ "error=%d, trouble deleting intermediate ipsec_sa for SA=%s.\n",
-+ error,
-+ sa_len ? sa : " (error)");
-+ SENDERR(-error);
-+ }
-+#ifdef CONFIG_IPSEC_NAT_TRAVERSAL
-+ }
-+#endif
-+
-+ spin_unlock_bh(&tdb_lock);
-+
-+ if(!(pfkey_safe_build(error = pfkey_msg_hdr_build(&extensions_reply[0],
-+ SADB_UPDATE,
-+ satype,
-+ 0,
-+ ((struct sadb_msg*)extensions[SADB_EXT_RESERVED])->sadb_msg_seq,
-+ ((struct sadb_msg*)extensions[SADB_EXT_RESERVED])->sadb_msg_pid),
-+ extensions_reply)
-+ && pfkey_safe_build(error = pfkey_sa_ref_build(&extensions_reply[SADB_EXT_SA],
-+ SADB_EXT_SA,
-+ extr->ips->ips_said.spi,
-+ extr->ips->ips_replaywin,
-+ extr->ips->ips_state,
-+ extr->ips->ips_authalg,
-+ extr->ips->ips_encalg,
-+ extr->ips->ips_flags,
-+ extr->ips->ips_ref),
-+ extensions_reply)
-+ /* The 3 lifetime extentions should only be sent if non-zero. */
-+ && (extensions[SADB_EXT_LIFETIME_HARD]
-+ ? pfkey_safe_build(error = pfkey_lifetime_build(&extensions_reply[SADB_EXT_LIFETIME_HARD],
-+ SADB_EXT_LIFETIME_HARD,
-+ extr->ips->ips_life.ipl_allocations.ipl_hard,
-+ extr->ips->ips_life.ipl_bytes.ipl_hard,
-+ extr->ips->ips_life.ipl_addtime.ipl_hard,
-+ extr->ips->ips_life.ipl_usetime.ipl_hard,
-+ extr->ips->ips_life.ipl_packets.ipl_hard),
-+ extensions_reply) : 1)
-+ && (extensions[SADB_EXT_LIFETIME_SOFT]
-+ ? pfkey_safe_build(error = pfkey_lifetime_build(&extensions_reply[SADB_EXT_LIFETIME_SOFT],
-+ SADB_EXT_LIFETIME_SOFT,
-+ extr->ips->ips_life.ipl_allocations.ipl_count,
-+ extr->ips->ips_life.ipl_bytes.ipl_count,
-+ extr->ips->ips_life.ipl_addtime.ipl_count,
-+ extr->ips->ips_life.ipl_usetime.ipl_count,
-+ extr->ips->ips_life.ipl_packets.ipl_count),
-+ extensions_reply) : 1)
-+ && (extr->ips->ips_life.ipl_allocations.ipl_count
-+ || extr->ips->ips_life.ipl_bytes.ipl_count
-+ || extr->ips->ips_life.ipl_addtime.ipl_count
-+ || extr->ips->ips_life.ipl_usetime.ipl_count
-+ || extr->ips->ips_life.ipl_packets.ipl_count
-+
-+ ? pfkey_safe_build(error = pfkey_lifetime_build(&extensions_reply[SADB_EXT_LIFETIME_CURRENT],
-+ SADB_EXT_LIFETIME_CURRENT,
-+ extr->ips->ips_life.ipl_allocations.ipl_count,
-+ extr->ips->ips_life.ipl_bytes.ipl_count,
-+ extr->ips->ips_life.ipl_addtime.ipl_count,
-+ extr->ips->ips_life.ipl_usetime.ipl_count,
-+ extr->ips->ips_life.ipl_packets.ipl_count),
-+ extensions_reply) : 1)
-+ && pfkey_safe_build(error = pfkey_address_build(&extensions_reply[SADB_EXT_ADDRESS_SRC],
-+ SADB_EXT_ADDRESS_SRC,
-+ 0, /*extr->ips->ips_said.proto,*/
-+ 0,
-+ extr->ips->ips_addr_s),
-+ extensions_reply)
-+ && pfkey_safe_build(error = pfkey_address_build(&extensions_reply[SADB_EXT_ADDRESS_DST],
-+ SADB_EXT_ADDRESS_DST,
-+ 0, /*extr->ips->ips_said.proto,*/
-+ 0,
-+ extr->ips->ips_addr_d),
-+ extensions_reply)
-+ && (extr->ips->ips_ident_s.data
-+ ? pfkey_safe_build(error = pfkey_ident_build(&extensions_reply[SADB_EXT_IDENTITY_SRC],
-+ SADB_EXT_IDENTITY_SRC,
-+ extr->ips->ips_ident_s.type,
-+ extr->ips->ips_ident_s.id,
-+ extr->ips->ips_ident_s.len,
-+ extr->ips->ips_ident_s.data),
-+ extensions_reply) : 1)
-+ && (extr->ips->ips_ident_d.data
-+ ? pfkey_safe_build(error = pfkey_ident_build(&extensions_reply[SADB_EXT_IDENTITY_DST],
-+ SADB_EXT_IDENTITY_DST,
-+ extr->ips->ips_ident_d.type,
-+ extr->ips->ips_ident_d.id,
-+ extr->ips->ips_ident_d.len,
-+ extr->ips->ips_ident_d.data),
-+ extensions_reply) : 1)
-+#if 0
-+ /* FIXME: This won't work yet because I have not finished
-+ it. */
-+ && (extr->ips->ips_sens_
-+ ? pfkey_safe_build(error = pfkey_sens_build(&extensions_reply[SADB_EXT_SENSITIVITY],
-+ extr->ips->ips_sens_dpd,
-+ extr->ips->ips_sens_sens_level,
-+ extr->ips->ips_sens_sens_len,
-+ extr->ips->ips_sens_sens_bitmap,
-+ extr->ips->ips_sens_integ_level,
-+ extr->ips->ips_sens_integ_len,
-+ extr->ips->ips_sens_integ_bitmap),
-+ extensions_reply) : 1)
-+#endif
-+ )) {
-+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_update_parse: "
-+ "failed to build the update reply message extensions\n");
-+ SENDERR(-error);
-+ }
-+
-+ if((error = pfkey_msg_build(&pfkey_reply, extensions_reply, EXT_BITS_OUT))) {
-+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_update_parse: "
-+ "failed to build the update reply message\n");
-+ SENDERR(-error);
-+ }
-+ for(pfkey_socketsp = pfkey_open_sockets;
-+ pfkey_socketsp;
-+ pfkey_socketsp = pfkey_socketsp->next) {
-+ if((error = pfkey_upmsg(pfkey_socketsp->socketp, pfkey_reply))) {
-+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_update_parse: "
-+ "sending up update reply message for satype=%d(%s) to socket=0p%p failed with error=%d.\n",
-+ satype,
-+ satype2name(satype),
-+ pfkey_socketsp->socketp,
-+ error);
-+ SENDERR(-error);
-+ }
-+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_update_parse: "
-+ "sending up update reply message for satype=%d(%s) to socket=0p%p succeeded.\n",
-+ satype,
-+ satype2name(satype),
-+ pfkey_socketsp->socketp);
-+ }
-+
-+#ifdef CONFIG_IPSEC_NAT_TRAVERSAL
-+ if (nat_t_ips_saved) {
-+ /**
-+ * As we _really_ update existing SA, we keep tdbq and need to delete
-+ * parsed ips (nat_t_ips_saved, was extr->ips).
-+ *
-+ * goto errlab with extr->ips = nat_t_ips_saved will free it.
-+ */
-+
-+ extr->ips = nat_t_ips_saved;
-+
-+ error = 0;
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_update_parse (NAT-T ports): "
-+ "successful for SA: %s\n",
-+ sa_len ? sa : " (error)");
-+
-+ goto errlab;
-+ }
-+#endif
-+
-+ if((error = ipsec_sa_add(extr->ips))) {
-+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_update_parse: "
-+ "failed to update the mature SA=%s with error=%d.\n",
-+ sa_len ? sa : " (error)",
-+ error);
-+ SENDERR(-error);
-+ }
-+ extr->ips = NULL;
-+
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_update_parse: "
-+ "successful for SA: %s\n",
-+ sa_len ? sa : " (error)");
-+
-+ errlab:
-+ if (pfkey_reply) {
-+ pfkey_msg_free(&pfkey_reply);
-+ }
-+ pfkey_extensions_free(extensions_reply);
-+ return error;
-+}
-+
-+DEBUG_NO_STATIC int
-+pfkey_add_parse(struct sock *sk, struct sadb_ext **extensions, struct pfkey_extracted_data* extr)
-+{
-+ int error = 0;
-+ struct ipsec_sa* ipsq;
-+ char sa[SATOT_BUF];
-+ size_t sa_len;
-+ struct sadb_ext *extensions_reply[SADB_EXT_MAX+1];
-+ struct sadb_msg *pfkey_reply = NULL;
-+ struct socket_list *pfkey_socketsp;
-+ uint8_t satype = ((struct sadb_msg*)extensions[SADB_EXT_RESERVED])->sadb_msg_satype;
-+
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_add_parse: .\n");
-+
-+ pfkey_extensions_init(extensions_reply);
-+
-+ if(((struct sadb_sa*)extensions[SADB_EXT_SA])->sadb_sa_state != SADB_SASTATE_MATURE) {
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_add_parse: "
-+ "error, sa_state=%d must be MATURE=%d\n",
-+ ((struct sadb_sa*)extensions[SADB_EXT_SA])->sadb_sa_state,
-+ SADB_SASTATE_MATURE);
-+ SENDERR(EINVAL);
-+ }
-+
-+ if(!extr || !extr->ips) {
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_add_parse: "
-+ "extr or extr->ips pointer NULL\n");
-+ SENDERR(EINVAL);
-+ }
-+
-+ sa_len = satot(&extr->ips->ips_said, 0, sa, sizeof(sa));
-+
-+ ipsq = ipsec_sa_getbyid(&(extr->ips->ips_said));
-+ if(ipsq != NULL) {
-+ ipsec_sa_put(ipsq);
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_add_parse: "
-+ "found an old ipsec_sa for SA%s, delete it first.\n",
-+ sa_len ? sa : " (error)");
-+ SENDERR(EEXIST);
-+ }
-+
-+ if(ip_chk_addr((unsigned long)extr->ips->ips_said.dst.u.v4.sin_addr.s_addr) == IS_MYADDR) {
-+ extr->ips->ips_flags |= EMT_INBOUND;
-+ }
-+
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_add_parse: "
-+ "existing ipsec_sa not found (this is good) for SA%s, %s-bound, allocating.\n",
-+ sa_len ? sa : " (error)",
-+ extr->ips->ips_flags & EMT_INBOUND ? "in" : "out");
-+
-+ /* XXX extr->ips->ips_rcvif = &(enc_softc[em->em_if].enc_if);*/
-+ extr->ips->ips_rcvif = NULL;
-+
-+ if ((error = pfkey_ipsec_sa_init(extr->ips, extensions))) {
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_add_parse: "
-+ "not successful for SA: %s, deleting.\n",
-+ sa_len ? sa : " (error)");
-+ SENDERR(-error);
-+ }
-+
-+ extr->ips->ips_life.ipl_addtime.ipl_count = jiffies / HZ;
-+ if(!extr->ips->ips_life.ipl_allocations.ipl_count) {
-+ extr->ips->ips_life.ipl_allocations.ipl_count += 1;
-+ }
-+
-+ if(!(pfkey_safe_build(error = pfkey_msg_hdr_build(&extensions_reply[0],
-+ SADB_ADD,
-+ satype,
-+ 0,
-+ ((struct sadb_msg*)extensions[SADB_EXT_RESERVED])->sadb_msg_seq,
-+ ((struct sadb_msg*)extensions[SADB_EXT_RESERVED])->sadb_msg_pid),
-+ extensions_reply)
-+ && pfkey_safe_build(error = pfkey_sa_ref_build(&extensions_reply[SADB_EXT_SA],
-+ SADB_EXT_SA,
-+ extr->ips->ips_said.spi,
-+ extr->ips->ips_replaywin,
-+ extr->ips->ips_state,
-+ extr->ips->ips_authalg,
-+ extr->ips->ips_encalg,
-+ extr->ips->ips_flags,
-+ extr->ips->ips_ref),
-+ extensions_reply)
-+ /* The 3 lifetime extentions should only be sent if non-zero. */
-+ && (extensions[SADB_EXT_LIFETIME_HARD]
-+ ? pfkey_safe_build(error = pfkey_lifetime_build(&extensions_reply[SADB_EXT_LIFETIME_HARD],
-+ SADB_EXT_LIFETIME_HARD,
-+ extr->ips->ips_life.ipl_allocations.ipl_hard,
-+ extr->ips->ips_life.ipl_bytes.ipl_hard,
-+ extr->ips->ips_life.ipl_addtime.ipl_hard,
-+ extr->ips->ips_life.ipl_usetime.ipl_hard,
-+ extr->ips->ips_life.ipl_packets.ipl_hard),
-+ extensions_reply) : 1)
-+ && (extensions[SADB_EXT_LIFETIME_SOFT]
-+ ? pfkey_safe_build(error = pfkey_lifetime_build(&extensions_reply[SADB_EXT_LIFETIME_SOFT],
-+ SADB_EXT_LIFETIME_SOFT,
-+ extr->ips->ips_life.ipl_allocations.ipl_soft,
-+ extr->ips->ips_life.ipl_bytes.ipl_soft,
-+ extr->ips->ips_life.ipl_addtime.ipl_soft,
-+ extr->ips->ips_life.ipl_usetime.ipl_soft,
-+ extr->ips->ips_life.ipl_packets.ipl_soft),
-+ extensions_reply) : 1)
-+ && pfkey_safe_build(error = pfkey_address_build(&extensions_reply[SADB_EXT_ADDRESS_SRC],
-+ SADB_EXT_ADDRESS_SRC,
-+ 0, /*extr->ips->ips_said.proto,*/
-+ 0,
-+ extr->ips->ips_addr_s),
-+ extensions_reply)
-+ && pfkey_safe_build(error = pfkey_address_build(&extensions_reply[SADB_EXT_ADDRESS_DST],
-+ SADB_EXT_ADDRESS_DST,
-+ 0, /*extr->ips->ips_said.proto,*/
-+ 0,
-+ extr->ips->ips_addr_d),
-+ extensions_reply)
-+ && (extr->ips->ips_ident_s.data
-+ ? pfkey_safe_build(error = pfkey_ident_build(&extensions_reply[SADB_EXT_IDENTITY_SRC],
-+ SADB_EXT_IDENTITY_SRC,
-+ extr->ips->ips_ident_s.type,
-+ extr->ips->ips_ident_s.id,
-+ extr->ips->ips_ident_s.len,
-+ extr->ips->ips_ident_s.data),
-+ extensions_reply) : 1)
-+ && (extr->ips->ips_ident_d.data
-+ ? pfkey_safe_build(error = pfkey_ident_build(&extensions_reply[SADB_EXT_IDENTITY_DST],
-+ SADB_EXT_IDENTITY_DST,
-+ extr->ips->ips_ident_d.type,
-+ extr->ips->ips_ident_d.id,
-+ extr->ips->ips_ident_d.len,
-+ extr->ips->ips_ident_d.data),
-+ extensions_reply) : 1)
-+#if 0
-+ /* FIXME: This won't work yet because I have not finished
-+ it. */
-+ && (extr->ips->ips_sens_
-+ ? pfkey_safe_build(error = pfkey_sens_build(&extensions_reply[SADB_EXT_SENSITIVITY],
-+ extr->ips->ips_sens_dpd,
-+ extr->ips->ips_sens_sens_level,
-+ extr->ips->ips_sens_sens_len,
-+ extr->ips->ips_sens_sens_bitmap,
-+ extr->ips->ips_sens_integ_level,
-+ extr->ips->ips_sens_integ_len,
-+ extr->ips->ips_sens_integ_bitmap),
-+ extensions_reply) : 1)
-+#endif
-+ )) {
-+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_add_parse: "
-+ "failed to build the add reply message extensions\n");
-+ SENDERR(-error);
-+ }
-+
-+ if((error = pfkey_msg_build(&pfkey_reply, extensions_reply, EXT_BITS_OUT))) {
-+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_add_parse: "
-+ "failed to build the add reply message\n");
-+ SENDERR(-error);
-+ }
-+ for(pfkey_socketsp = pfkey_open_sockets;
-+ pfkey_socketsp;
-+ pfkey_socketsp = pfkey_socketsp->next) {
-+ if((error = pfkey_upmsg(pfkey_socketsp->socketp, pfkey_reply))) {
-+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_add_parse: "
-+ "sending up add reply message for satype=%d(%s) to socket=0p%p failed with error=%d.\n",
-+ satype,
-+ satype2name(satype),
-+ pfkey_socketsp->socketp,
-+ error);
-+ SENDERR(-error);
-+ }
-+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_add_parse: "
-+ "sending up add reply message for satype=%d(%s) to socket=0p%p succeeded.\n",
-+ satype,
-+ satype2name(satype),
-+ pfkey_socketsp->socketp);
-+ }
-+
-+ if((error = ipsec_sa_add(extr->ips))) {
-+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_add_parse: "
-+ "failed to add the mature SA=%s with error=%d.\n",
-+ sa_len ? sa : " (error)",
-+ error);
-+ SENDERR(-error);
-+ }
-+ extr->ips = NULL;
-+
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_add_parse: "
-+ "successful for SA: %s\n",
-+ sa_len ? sa : " (error)");
-+
-+ errlab:
-+ if (pfkey_reply) {
-+ pfkey_msg_free(&pfkey_reply);
-+ }
-+ pfkey_extensions_free(extensions_reply);
-+ return error;
-+}
-+
-+DEBUG_NO_STATIC int
-+pfkey_delete_parse(struct sock *sk, struct sadb_ext **extensions, struct pfkey_extracted_data* extr)
-+{
-+ struct ipsec_sa *ipsp;
-+ char sa[SATOT_BUF];
-+ size_t sa_len;
-+ int error = 0;
-+ struct sadb_ext *extensions_reply[SADB_EXT_MAX+1];
-+ struct sadb_msg *pfkey_reply = NULL;
-+ struct socket_list *pfkey_socketsp;
-+ uint8_t satype = ((struct sadb_msg*)extensions[SADB_EXT_RESERVED])->sadb_msg_satype;
-+
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_delete_parse: .\n");
-+
-+ pfkey_extensions_init(extensions_reply);
-+
-+ if(!extr || !extr->ips) {
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_delete_parse: "
-+ "extr or extr->ips pointer NULL, fatal\n");
-+ SENDERR(EINVAL);
-+ }
-+
-+ sa_len = satot(&extr->ips->ips_said, 0, sa, sizeof(sa));
-+
-+ spin_lock_bh(&tdb_lock);
-+
-+ ipsp = ipsec_sa_getbyid(&(extr->ips->ips_said));
-+ if (ipsp == NULL) {
-+ spin_unlock_bh(&tdb_lock);
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_delete_parse: "
-+ "ipsec_sa not found for SA:%s, could not delete.\n",
-+ sa_len ? sa : " (error)");
-+ SENDERR(ESRCH);
-+ }
-+
-+ ipsec_sa_put(ipsp);
-+ if((error = ipsec_sa_delchain(ipsp))) {
-+ spin_unlock_bh(&tdb_lock);
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_delete_parse: "
-+ "error=%d returned trying to delete ipsec_sa for SA:%s.\n",
-+ error,
-+ sa_len ? sa : " (error)");
-+ SENDERR(-error);
-+ }
-+ spin_unlock_bh(&tdb_lock);
-+
-+ if(!(pfkey_safe_build(error = pfkey_msg_hdr_build(&extensions_reply[0],
-+ SADB_DELETE,
-+ satype,
-+ 0,
-+ ((struct sadb_msg*)extensions[SADB_EXT_RESERVED])->sadb_msg_seq,
-+ ((struct sadb_msg*)extensions[SADB_EXT_RESERVED])->sadb_msg_pid),
-+ extensions_reply)
-+ && pfkey_safe_build(error = pfkey_sa_ref_build(&extensions_reply[SADB_EXT_SA],
-+ SADB_EXT_SA,
-+ extr->ips->ips_said.spi,
-+ 0,
-+ 0,
-+ 0,
-+ 0,
-+ 0,
-+ extr->ips->ips_ref),
-+ extensions_reply)
-+ && pfkey_safe_build(error = pfkey_address_build(&extensions_reply[SADB_EXT_ADDRESS_SRC],
-+ SADB_EXT_ADDRESS_SRC,
-+ 0, /*extr->ips->ips_said.proto,*/
-+ 0,
-+ extr->ips->ips_addr_s),
-+ extensions_reply)
-+ && pfkey_safe_build(error = pfkey_address_build(&extensions_reply[SADB_EXT_ADDRESS_DST],
-+ SADB_EXT_ADDRESS_DST,
-+ 0, /*extr->ips->ips_said.proto,*/
-+ 0,
-+ extr->ips->ips_addr_d),
-+ extensions_reply)
-+ )) {
-+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_delete_parse: "
-+ "failed to build the delete reply message extensions\n");
-+ SENDERR(-error);
-+ }
-+
-+ if((error = pfkey_msg_build(&pfkey_reply, extensions_reply, EXT_BITS_OUT))) {
-+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_delete_parse: "
-+ "failed to build the delete reply message\n");
-+ SENDERR(-error);
-+ }
-+ for(pfkey_socketsp = pfkey_open_sockets;
-+ pfkey_socketsp;
-+ pfkey_socketsp = pfkey_socketsp->next) {
-+ if((error = pfkey_upmsg(pfkey_socketsp->socketp, pfkey_reply))) {
-+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_delete_parse: "
-+ "sending up delete reply message for satype=%d(%s) to socket=0p%p failed with error=%d.\n",
-+ satype,
-+ satype2name(satype),
-+ pfkey_socketsp->socketp,
-+ error);
-+ SENDERR(-error);
-+ }
-+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_delete_parse: "
-+ "sending up delete reply message for satype=%d(%s) to socket=0p%p succeeded.\n",
-+ satype,
-+ satype2name(satype),
-+ pfkey_socketsp->socketp);
-+ }
-+
-+ errlab:
-+ if (pfkey_reply) {
-+ pfkey_msg_free(&pfkey_reply);
-+ }
-+ pfkey_extensions_free(extensions_reply);
-+ return error;
-+}
-+
-+DEBUG_NO_STATIC int
-+pfkey_get_parse(struct sock *sk, struct sadb_ext **extensions, struct pfkey_extracted_data* extr)
-+{
-+ int error = 0;
-+ struct ipsec_sa *ipsp;
-+ char sa[SATOT_BUF];
-+ size_t sa_len;
-+ struct sadb_ext *extensions_reply[SADB_EXT_MAX+1];
-+ struct sadb_msg *pfkey_reply = NULL;
-+
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_get_parse: .\n");
-+
-+ pfkey_extensions_init(extensions_reply);
-+
-+ if(!extr || !extr->ips) {
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_get_parse: "
-+ "extr or extr->ips pointer NULL, fatal\n");
-+ SENDERR(EINVAL);
-+ }
-+
-+ sa_len = satot(&extr->ips->ips_said, 0, sa, sizeof(sa));
-+
-+ spin_lock_bh(&tdb_lock);
-+
-+ ipsp = ipsec_sa_getbyid(&(extr->ips->ips_said));
-+ if (ipsp == NULL) {
-+ spin_unlock_bh(&tdb_lock);
-+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_get_parse: "
-+ "ipsec_sa not found for SA=%s, could not get.\n",
-+ sa_len ? sa : " (error)");
-+ SENDERR(ESRCH);
-+ }
-+
-+ if(!(pfkey_safe_build(error = pfkey_msg_hdr_build(&extensions_reply[0],
-+ SADB_GET,
-+ ((struct sadb_msg*)extensions[SADB_EXT_RESERVED])->sadb_msg_satype,
-+ 0,
-+ ((struct sadb_msg*)extensions[SADB_EXT_RESERVED])->sadb_msg_seq,
-+ ((struct sadb_msg*)extensions[SADB_EXT_RESERVED])->sadb_msg_pid),
-+ extensions_reply)
-+ && pfkey_safe_build(error = pfkey_sa_ref_build(&extensions_reply[SADB_EXT_SA],
-+ SADB_EXT_SA,
-+ extr->ips->ips_said.spi,
-+ extr->ips->ips_replaywin,
-+ extr->ips->ips_state,
-+ extr->ips->ips_authalg,
-+ extr->ips->ips_encalg,
-+ extr->ips->ips_flags,
-+ extr->ips->ips_ref),
-+ extensions_reply)
-+ /* The 3 lifetime extentions should only be sent if non-zero. */
-+ && (ipsp->ips_life.ipl_allocations.ipl_count
-+ || ipsp->ips_life.ipl_bytes.ipl_count
-+ || ipsp->ips_life.ipl_addtime.ipl_count
-+ || ipsp->ips_life.ipl_usetime.ipl_count
-+ || ipsp->ips_life.ipl_packets.ipl_count
-+ ? pfkey_safe_build(error = pfkey_lifetime_build(&extensions_reply[SADB_EXT_LIFETIME_CURRENT],
-+ SADB_EXT_LIFETIME_CURRENT,
-+ ipsp->ips_life.ipl_allocations.ipl_count,
-+ ipsp->ips_life.ipl_bytes.ipl_count,
-+ ipsp->ips_life.ipl_addtime.ipl_count,
-+ ipsp->ips_life.ipl_usetime.ipl_count,
-+ ipsp->ips_life.ipl_packets.ipl_count),
-+ extensions_reply) : 1)
-+ && (ipsp->ips_life.ipl_allocations.ipl_hard
-+ || ipsp->ips_life.ipl_bytes.ipl_hard
-+ || ipsp->ips_life.ipl_addtime.ipl_hard
-+ || ipsp->ips_life.ipl_usetime.ipl_hard
-+ || ipsp->ips_life.ipl_packets.ipl_hard
-+ ? pfkey_safe_build(error = pfkey_lifetime_build(&extensions_reply[SADB_EXT_LIFETIME_HARD],
-+ SADB_EXT_LIFETIME_HARD,
-+ ipsp->ips_life.ipl_allocations.ipl_hard,
-+ ipsp->ips_life.ipl_bytes.ipl_hard,
-+ ipsp->ips_life.ipl_addtime.ipl_hard,
-+ ipsp->ips_life.ipl_usetime.ipl_hard,
-+ ipsp->ips_life.ipl_packets.ipl_hard),
-+ extensions_reply) : 1)
-+ && (ipsp->ips_life.ipl_allocations.ipl_soft
-+ || ipsp->ips_life.ipl_bytes.ipl_soft
-+ || ipsp->ips_life.ipl_addtime.ipl_soft
-+ || ipsp->ips_life.ipl_usetime.ipl_soft
-+ || ipsp->ips_life.ipl_packets.ipl_soft
-+ ? pfkey_safe_build(error = pfkey_lifetime_build(&extensions_reply[SADB_EXT_LIFETIME_SOFT],
-+ SADB_EXT_LIFETIME_SOFT,
-+ ipsp->ips_life.ipl_allocations.ipl_soft,
-+ ipsp->ips_life.ipl_bytes.ipl_soft,
-+ ipsp->ips_life.ipl_addtime.ipl_soft,
-+ ipsp->ips_life.ipl_usetime.ipl_soft,
-+ ipsp->ips_life.ipl_packets.ipl_soft),
-+ extensions_reply) : 1)
-+ && pfkey_safe_build(error = pfkey_address_build(&extensions_reply[SADB_EXT_ADDRESS_SRC],
-+ SADB_EXT_ADDRESS_SRC,
-+ 0, /*extr->ips->ips_said.proto,*/
-+ 0,
-+ extr->ips->ips_addr_s),
-+ extensions_reply)
-+ && pfkey_safe_build(error = pfkey_address_build(&extensions_reply[SADB_EXT_ADDRESS_DST],
-+ SADB_EXT_ADDRESS_DST,
-+ 0, /*extr->ips->ips_said.proto,*/
-+ 0,
-+ extr->ips->ips_addr_d),
-+ extensions_reply)
-+ && (extr->ips->ips_addr_p
-+ ? pfkey_safe_build(error = pfkey_address_build(&extensions_reply[SADB_EXT_ADDRESS_PROXY],
-+ SADB_EXT_ADDRESS_PROXY,
-+ 0, /*extr->ips->ips_said.proto,*/
-+ 0,
-+ extr->ips->ips_addr_p),
-+ extensions_reply) : 1)
-+#if 0
-+ /* FIXME: This won't work yet because the keys are not
-+ stored directly in the ipsec_sa. They are stored as
-+ contexts. */
-+ && (extr->ips->ips_key_a_size
-+ ? pfkey_safe_build(error = pfkey_key_build(&extensions_reply[SADB_EXT_KEY_AUTH],
-+ SADB_EXT_KEY_AUTH,
-+ extr->ips->ips_key_a_size * 8,
-+ extr->ips->ips_key_a),
-+ extensions_reply) : 1)
-+ /* FIXME: This won't work yet because the keys are not
-+ stored directly in the ipsec_sa. They are stored as
-+ key schedules. */
-+ && (extr->ips->ips_key_e_size
-+ ? pfkey_safe_build(error = pfkey_key_build(&extensions_reply[SADB_EXT_KEY_ENCRYPT],
-+ SADB_EXT_KEY_ENCRYPT,
-+ extr->ips->ips_key_e_size * 8,
-+ extr->ips->ips_key_e),
-+ extensions_reply) : 1)
-+#endif
-+ && (extr->ips->ips_ident_s.data
-+ ? pfkey_safe_build(error = pfkey_ident_build(&extensions_reply[SADB_EXT_IDENTITY_SRC],
-+ SADB_EXT_IDENTITY_SRC,
-+ extr->ips->ips_ident_s.type,
-+ extr->ips->ips_ident_s.id,
-+ extr->ips->ips_ident_s.len,
-+ extr->ips->ips_ident_s.data),
-+ extensions_reply) : 1)
-+ && (extr->ips->ips_ident_d.data
-+ ? pfkey_safe_build(error = pfkey_ident_build(&extensions_reply[SADB_EXT_IDENTITY_DST],
-+ SADB_EXT_IDENTITY_DST,
-+ extr->ips->ips_ident_d.type,
-+ extr->ips->ips_ident_d.id,
-+ extr->ips->ips_ident_d.len,
-+ extr->ips->ips_ident_d.data),
-+ extensions_reply) : 1)
-+#if 0
-+ /* FIXME: This won't work yet because I have not finished
-+ it. */
-+ && (extr->ips->ips_sens_
-+ ? pfkey_safe_build(error = pfkey_sens_build(&extensions_reply[SADB_EXT_SENSITIVITY],
-+ extr->ips->ips_sens_dpd,
-+ extr->ips->ips_sens_sens_level,
-+ extr->ips->ips_sens_sens_len,
-+ extr->ips->ips_sens_sens_bitmap,
-+ extr->ips->ips_sens_integ_level,
-+ extr->ips->ips_sens_integ_len,
-+ extr->ips->ips_sens_integ_bitmap),
-+ extensions_reply) : 1)
-+#endif
-+ )) {
-+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_get_parse: "
-+ "failed to build the get reply message extensions\n");
-+ ipsec_sa_put(ipsp);
-+ spin_unlock_bh(&tdb_lock);
-+ SENDERR(-error);
-+ }
-+
-+ ipsec_sa_put(ipsp);
-+ spin_unlock_bh(&tdb_lock);
-+
-+ if((error = pfkey_msg_build(&pfkey_reply, extensions_reply, EXT_BITS_OUT))) {
-+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_get_parse: "
-+ "failed to build the get reply message\n");
-+ SENDERR(-error);
-+ }
-+
-+ if((error = pfkey_upmsg(sk->socket, pfkey_reply))) {
-+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_get_parse: "
-+ "failed to send the get reply message\n");
-+ SENDERR(-error);
-+ }
-+
-+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_get_parse: "
-+ "succeeded in sending get reply message.\n");
-+
-+ errlab:
-+ if (pfkey_reply) {
-+ pfkey_msg_free(&pfkey_reply);
-+ }
-+ pfkey_extensions_free(extensions_reply);
-+ return error;
-+}
-+
-+DEBUG_NO_STATIC int
-+pfkey_acquire_parse(struct sock *sk, struct sadb_ext **extensions, struct pfkey_extracted_data* extr)
-+{
-+ int error = 0;
-+ struct socket_list *pfkey_socketsp;
-+ uint8_t satype = ((struct sadb_msg*)extensions[SADB_EXT_RESERVED])->sadb_msg_satype;
-+
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_acquire_parse: .\n");
-+
-+ /* XXX I don't know if we want an upper bound, since userspace may
-+ want to register itself for an satype > SADB_SATYPE_MAX. */
-+ if((satype == 0) || (satype > SADB_SATYPE_MAX)) {
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_acquire_parse: "
-+ "SATYPE=%d invalid.\n",
-+ satype);
-+ SENDERR(EINVAL);
-+ }
-+
-+ if(!(pfkey_registered_sockets[satype])) {
-+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_acquire_parse: "
-+ "no sockets registered for SAtype=%d(%s).\n",
-+ satype,
-+ satype2name(satype));
-+ SENDERR(EPROTONOSUPPORT);
-+ }
-+
-+ for(pfkey_socketsp = pfkey_registered_sockets[satype];
-+ pfkey_socketsp;
-+ pfkey_socketsp = pfkey_socketsp->next) {
-+ if((error = pfkey_upmsg(pfkey_socketsp->socketp,
-+ ((struct sadb_msg*)extensions[SADB_EXT_RESERVED])))) {
-+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_acquire_parse: "
-+ "sending up acquire reply message for satype=%d(%s) to socket=0p%p failed with error=%d.\n",
-+ satype,
-+ satype2name(satype),
-+ pfkey_socketsp->socketp,
-+ error);
-+ SENDERR(-error);
-+ }
-+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_acquire_parse: "
-+ "sending up acquire reply message for satype=%d(%s) to socket=0p%p succeeded.\n",
-+ satype,
-+ satype2name(satype),
-+ pfkey_socketsp->socketp);
-+ }
-+
-+ errlab:
-+ return error;
-+}
-+
-+DEBUG_NO_STATIC int
-+pfkey_register_parse(struct sock *sk, struct sadb_ext **extensions, struct pfkey_extracted_data* extr)
-+{
-+ int error = 0;
-+ uint8_t satype = ((struct sadb_msg*)extensions[SADB_EXT_RESERVED])->sadb_msg_satype;
-+
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_register_parse: .\n");
-+
-+ /* XXX I don't know if we want an upper bound, since userspace may
-+ want to register itself for an satype > SADB_SATYPE_MAX. */
-+ if((satype == 0) || (satype > SADB_SATYPE_MAX)) {
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_register_parse: "
-+ "SATYPE=%d invalid.\n",
-+ satype);
-+ SENDERR(EINVAL);
-+ }
-+
-+ if(!pfkey_list_insert_socket(sk->socket,
-+ &(pfkey_registered_sockets[satype]))) {
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_register_parse: "
-+ "SATYPE=%02d(%s) successfully registered by KMd (pid=%d).\n",
-+ satype,
-+ satype2name(satype),
-+ key_pid(sk));
-+ };
-+
-+ /* send up register msg with supported SATYPE algos */
-+
-+ error=pfkey_register_reply(satype, (struct sadb_msg*)extensions[SADB_EXT_RESERVED]);
-+ errlab:
-+ return error;
-+}
-+
-+int
-+pfkey_register_reply(int satype, struct sadb_msg *sadb_msg)
-+{
-+ struct sadb_ext *extensions_reply[SADB_EXT_MAX+1];
-+ struct sadb_msg *pfkey_reply = NULL;
-+ struct socket_list *pfkey_socketsp;
-+ struct supported_list *pfkey_supported_listp;
-+ unsigned int alg_num_a = 0, alg_num_e = 0;
-+ struct sadb_alg *alg_a = NULL, *alg_e = NULL, *alg_ap = NULL, *alg_ep = NULL;
-+ int error = 0;
-+
-+ pfkey_extensions_init(extensions_reply);
-+
-+ if((satype == 0) || (satype > SADB_SATYPE_MAX)) {
-+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_register_reply: "
-+ "SAtype=%d unspecified or unknown.\n",
-+ satype);
-+ SENDERR(EINVAL);
-+ }
-+ if(!(pfkey_registered_sockets[satype])) {
-+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_register_reply: "
-+ "no sockets registered for SAtype=%d(%s).\n",
-+ satype,
-+ satype2name(satype));
-+ SENDERR(EPROTONOSUPPORT);
-+ }
-+ /* send up register msg with supported SATYPE algos */
-+ pfkey_supported_listp = pfkey_supported_list[satype];
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_register_reply: "
-+ "pfkey_supported_list[%d]=0p%p\n",
-+ satype,
-+ pfkey_supported_list[satype]);
-+ while(pfkey_supported_listp) {
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_register_reply: "
-+ "checking supported=0p%p\n",
-+ pfkey_supported_listp);
-+ if(pfkey_supported_listp->supportedp->supported_alg_exttype == SADB_EXT_SUPPORTED_AUTH) {
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_register_reply: "
-+ "adding auth alg.\n");
-+ alg_num_a++;
-+ }
-+ if(pfkey_supported_listp->supportedp->supported_alg_exttype == SADB_EXT_SUPPORTED_ENCRYPT) {
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_register_reply: "
-+ "adding encrypt alg.\n");
-+ alg_num_e++;
-+ }
-+ pfkey_supported_listp = pfkey_supported_listp->next;
-+ }
-+
-+ if(alg_num_a) {
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_register_reply: "
-+ "allocating %lu bytes for auth algs.\n",
-+ (unsigned long) (alg_num_a * sizeof(struct sadb_alg)));
-+ if((alg_a = kmalloc(alg_num_a * sizeof(struct sadb_alg), GFP_ATOMIC) ) == NULL) {
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_register_reply: "
-+ "auth alg memory allocation error\n");
-+ SENDERR(ENOMEM);
-+ }
-+ alg_ap = alg_a;
-+ }
-+
-+ if(alg_num_e) {
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_register_reply: "
-+ "allocating %lu bytes for enc algs.\n",
-+ (unsigned long) (alg_num_e * sizeof(struct sadb_alg)));
-+ if((alg_e = kmalloc(alg_num_e * sizeof(struct sadb_alg), GFP_ATOMIC) ) == NULL) {
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_register_reply: "
-+ "enc alg memory allocation error\n");
-+ SENDERR(ENOMEM);
-+ }
-+ alg_ep = alg_e;
-+ }
-+
-+ pfkey_supported_listp = pfkey_supported_list[satype];
-+ while(pfkey_supported_listp) {
-+ if(alg_num_a) {
-+ if(pfkey_supported_listp->supportedp->supported_alg_exttype == SADB_EXT_SUPPORTED_AUTH) {
-+ alg_ap->sadb_alg_id = pfkey_supported_listp->supportedp->supported_alg_id;
-+ alg_ap->sadb_alg_ivlen = pfkey_supported_listp->supportedp->supported_alg_ivlen;
-+ alg_ap->sadb_alg_minbits = pfkey_supported_listp->supportedp->supported_alg_minbits;
-+ alg_ap->sadb_alg_maxbits = pfkey_supported_listp->supportedp->supported_alg_maxbits;
-+ alg_ap->sadb_alg_reserved = 0;
-+ KLIPS_PRINT(debug_pfkey && sysctl_ipsec_debug_verbose,
-+ "klips_debug:pfkey_register_reply: "
-+ "adding auth=0p%p\n",
-+ alg_ap);
-+ alg_ap++;
-+ }
-+ }
-+ if(alg_num_e) {
-+ if(pfkey_supported_listp->supportedp->supported_alg_exttype == SADB_EXT_SUPPORTED_ENCRYPT) {
-+ alg_ep->sadb_alg_id = pfkey_supported_listp->supportedp->supported_alg_id;
-+ alg_ep->sadb_alg_ivlen = pfkey_supported_listp->supportedp->supported_alg_ivlen;
-+ alg_ep->sadb_alg_minbits = pfkey_supported_listp->supportedp->supported_alg_minbits;
-+ alg_ep->sadb_alg_maxbits = pfkey_supported_listp->supportedp->supported_alg_maxbits;
-+ alg_ep->sadb_alg_reserved = 0;
-+ KLIPS_PRINT(debug_pfkey && sysctl_ipsec_debug_verbose,
-+ "klips_debug:pfkey_register_reply: "
-+ "adding encrypt=0p%p\n",
-+ alg_ep);
-+ alg_ep++;
-+ }
-+ }
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_register_reply: "
-+ "found satype=%d(%s) exttype=%d id=%d ivlen=%d minbits=%d maxbits=%d.\n",
-+ satype,
-+ satype2name(satype),
-+ pfkey_supported_listp->supportedp->supported_alg_exttype,
-+ pfkey_supported_listp->supportedp->supported_alg_id,
-+ pfkey_supported_listp->supportedp->supported_alg_ivlen,
-+ pfkey_supported_listp->supportedp->supported_alg_minbits,
-+ pfkey_supported_listp->supportedp->supported_alg_maxbits);
-+ pfkey_supported_listp = pfkey_supported_listp->next;
-+ }
-+ if(!(pfkey_safe_build(error = pfkey_msg_hdr_build(&extensions_reply[0],
-+ SADB_REGISTER,
-+ satype,
-+ 0,
-+ sadb_msg? sadb_msg->sadb_msg_seq : ++pfkey_msg_seq,
-+ sadb_msg? sadb_msg->sadb_msg_pid: current->pid),
-+ extensions_reply) &&
-+ (alg_num_a ? pfkey_safe_build(error = pfkey_supported_build(&extensions_reply[SADB_EXT_SUPPORTED_AUTH],
-+ SADB_EXT_SUPPORTED_AUTH,
-+ alg_num_a,
-+ alg_a),
-+ extensions_reply) : 1) &&
-+ (alg_num_e ? pfkey_safe_build(error = pfkey_supported_build(&extensions_reply[SADB_EXT_SUPPORTED_ENCRYPT],
-+ SADB_EXT_SUPPORTED_ENCRYPT,
-+ alg_num_e,
-+ alg_e),
-+ extensions_reply) : 1))) {
-+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_register_reply: "
-+ "failed to build the register message extensions_reply\n");
-+ SENDERR(-error);
-+ }
-+
-+ if((error = pfkey_msg_build(&pfkey_reply, extensions_reply, EXT_BITS_OUT))) {
-+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_register_reply: "
-+ "failed to build the register message\n");
-+ SENDERR(-error);
-+ }
-+ /* this should go to all registered sockets for that satype only */
-+ for(pfkey_socketsp = pfkey_registered_sockets[satype];
-+ pfkey_socketsp;
-+ pfkey_socketsp = pfkey_socketsp->next) {
-+ if((error = pfkey_upmsg(pfkey_socketsp->socketp, pfkey_reply))) {
-+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_register_reply: "
-+ "sending up acquire message for satype=%d(%s) to socket=0p%p failed with error=%d.\n",
-+ satype,
-+ satype2name(satype),
-+ pfkey_socketsp->socketp,
-+ error);
-+ SENDERR(-error);
-+ }
-+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_register_reply: "
-+ "sending up register message for satype=%d(%s) to socket=0p%p succeeded.\n",
-+ satype,
-+ satype2name(satype),
-+ pfkey_socketsp->socketp);
-+ }
-+
-+ errlab:
-+ if(alg_a) {
-+ kfree(alg_a);
-+ }
-+ if(alg_e) {
-+ kfree(alg_e);
-+ }
-+ if (pfkey_reply) {
-+ pfkey_msg_free(&pfkey_reply);
-+ }
-+ pfkey_extensions_free(extensions_reply);
-+ return error;
-+}
-+
-+DEBUG_NO_STATIC int
-+pfkey_expire_parse(struct sock *sk, struct sadb_ext **extensions, struct pfkey_extracted_data* extr)
-+{
-+ int error = 0;
-+ struct socket_list *pfkey_socketsp;
-+#ifdef CONFIG_IPSEC_DEBUG
-+ uint8_t satype = ((struct sadb_msg*)extensions[SADB_EXT_RESERVED])->sadb_msg_satype;
-+#endif /* CONFIG_IPSEC_DEBUG */
-+
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_expire_parse: .\n");
-+
-+ if(pfkey_open_sockets) {
-+ for(pfkey_socketsp = pfkey_open_sockets;
-+ pfkey_socketsp;
-+ pfkey_socketsp = pfkey_socketsp->next) {
-+ if((error = pfkey_upmsg(pfkey_socketsp->socketp,
-+ ((struct sadb_msg*)extensions[SADB_EXT_RESERVED])))) {
-+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_expire_parse: "
-+ "sending up expire reply message for satype=%d(%s) to socket=0p%p failed with error=%d.\n",
-+ satype,
-+ satype2name(satype),
-+ pfkey_socketsp->socketp,
-+ error);
-+ SENDERR(-error);
-+ }
-+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_expire_parse: "
-+ "sending up expire reply message for satype=%d(%s) to socket=0p%p succeeded.\n",
-+ satype,
-+ satype2name(satype),
-+ pfkey_socketsp->socketp);
-+ }
-+ }
-+
-+ errlab:
-+ return error;
-+}
-+
-+DEBUG_NO_STATIC int
-+pfkey_flush_parse(struct sock *sk, struct sadb_ext **extensions, struct pfkey_extracted_data* extr)
-+{
-+ int error = 0;
-+ struct socket_list *pfkey_socketsp;
-+ uint8_t satype = ((struct sadb_msg*)extensions[SADB_EXT_RESERVED])->sadb_msg_satype;
-+ uint8_t proto = 0;
-+
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_flush_parse: "
-+ "flushing type %d SAs\n",
-+ satype);
-+
-+ if(satype && !(proto = satype2proto(satype))) {
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_flush_parse: "
-+ "satype %d lookup failed.\n",
-+ ((struct sadb_msg*)extensions[SADB_EXT_RESERVED])->sadb_msg_satype);
-+ SENDERR(EINVAL);
-+ }
-+
-+ if ((error = ipsec_sadb_cleanup(proto))) {
-+ SENDERR(-error);
-+ }
-+
-+ if(pfkey_open_sockets) {
-+ for(pfkey_socketsp = pfkey_open_sockets;
-+ pfkey_socketsp;
-+ pfkey_socketsp = pfkey_socketsp->next) {
-+ if((error = pfkey_upmsg(pfkey_socketsp->socketp,
-+ ((struct sadb_msg*)extensions[SADB_EXT_RESERVED])))) {
-+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_flush_parse: "
-+ "sending up flush reply message for satype=%d(%s) (proto=%d) to socket=0p%p failed with error=%d.\n",
-+ satype,
-+ satype2name(satype),
-+ proto,
-+ pfkey_socketsp->socketp,
-+ error);
-+ SENDERR(-error);
-+ }
-+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_flush_parse: "
-+ "sending up flush reply message for satype=%d(%s) to socket=0p%p succeeded.\n",
-+ satype,
-+ satype2name(satype),
-+ pfkey_socketsp->socketp);
-+ }
-+ }
-+
-+ errlab:
-+ return error;
-+}
-+
-+DEBUG_NO_STATIC int
-+pfkey_dump_parse(struct sock *sk, struct sadb_ext **extensions, struct pfkey_extracted_data* extr)
-+{
-+ int error = 0;
-+
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_dump_parse: .\n");
-+
-+ SENDERR(ENOSYS);
-+ errlab:
-+ return error;
-+}
-+
-+DEBUG_NO_STATIC int
-+pfkey_x_promisc_parse(struct sock *sk, struct sadb_ext **extensions, struct pfkey_extracted_data* extr)
-+{
-+ int error = 0;
-+
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_promisc_parse: .\n");
-+
-+ SENDERR(ENOSYS);
-+ errlab:
-+ return error;
-+}
-+
-+DEBUG_NO_STATIC int
-+pfkey_x_pchange_parse(struct sock *sk, struct sadb_ext **extensions, struct pfkey_extracted_data* extr)
-+{
-+ int error = 0;
-+
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_x_pchange_parse: .\n");
-+
-+ SENDERR(ENOSYS);
-+ errlab:
-+ return error;
-+}
-+
-+DEBUG_NO_STATIC int
-+pfkey_x_grpsa_parse(struct sock *sk, struct sadb_ext **extensions, struct pfkey_extracted_data* extr)
-+{
-+ struct ipsec_sa *ips1p, *ips2p, *ipsp;
-+ struct sadb_ext *extensions_reply[SADB_EXT_MAX+1];
-+ struct sadb_msg *pfkey_reply = NULL;
-+ struct socket_list *pfkey_socketsp;
-+ uint8_t satype = ((struct sadb_msg*)extensions[SADB_EXT_RESERVED])->sadb_msg_satype;
-+ char sa1[SATOT_BUF], sa2[SATOT_BUF];
-+ size_t sa_len1, sa_len2 = 0;
-+ int error = 0;
-+
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_x_grpsa_parse: .\n");
-+
-+ pfkey_extensions_init(extensions_reply);
-+
-+ if(extr == NULL || extr->ips == NULL) {
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_x_grpsa_parse: "
-+ "extr or extr->ips is NULL, fatal.\n");
-+ SENDERR(EINVAL);
-+ }
-+
-+ sa_len1 = satot(&extr->ips->ips_said, 0, sa1, sizeof(sa1));
-+ if(extr->ips2 != NULL) {
-+ sa_len2 = satot(&extr->ips2->ips_said, 0, sa2, sizeof(sa2));
-+ }
-+
-+ spin_lock_bh(&tdb_lock);
-+
-+ ips1p = ipsec_sa_getbyid(&(extr->ips->ips_said));
-+ if(ips1p == NULL) {
-+ spin_unlock_bh(&tdb_lock);
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_x_grpsa_parse: "
-+ "reserved ipsec_sa for SA1: %s not found. Call SADB_ADD/UPDATE first.\n",
-+ sa_len1 ? sa1 : " (error)");
-+ SENDERR(ENOENT);
-+ }
-+ if(extr->ips2) { /* GRPSA */
-+ ips2p = ipsec_sa_getbyid(&(extr->ips2->ips_said));
-+ if(ips2p == NULL) {
-+ ipsec_sa_put(ips1p);
-+ spin_unlock_bh(&tdb_lock);
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_x_grpsa_parse: "
-+ "reserved ipsec_sa for SA2: %s not found. Call SADB_ADD/UPDATE first.\n",
-+ sa_len2 ? sa2 : " (error)");
-+ SENDERR(ENOENT);
-+ }
-+
-+ /* Is either one already linked? */
-+ if(ips1p->ips_onext) {
-+ ipsec_sa_put(ips1p);
-+ ipsec_sa_put(ips2p);
-+ spin_unlock_bh(&tdb_lock);
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_x_grpsa_parse: "
-+ "ipsec_sa for SA: %s is already linked.\n",
-+ sa_len1 ? sa1 : " (error)");
-+ SENDERR(EEXIST);
-+ }
-+ if(ips2p->ips_inext) {
-+ ipsec_sa_put(ips1p);
-+ ipsec_sa_put(ips2p);
-+ spin_unlock_bh(&tdb_lock);
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_x_grpsa_parse: "
-+ "ipsec_sa for SA: %s is already linked.\n",
-+ sa_len2 ? sa2 : " (error)");
-+ SENDERR(EEXIST);
-+ }
-+
-+ /* Is extr->ips already linked to extr->ips2? */
-+ ipsp = ips2p;
-+ while(ipsp) {
-+ if(ipsp == ips1p) {
-+ ipsec_sa_put(ips1p);
-+ ipsec_sa_put(ips2p);
-+ spin_unlock_bh(&tdb_lock);
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_x_grpsa_parse: "
-+ "ipsec_sa for SA: %s is already linked to %s.\n",
-+ sa_len1 ? sa1 : " (error)",
-+ sa_len2 ? sa2 : " (error)");
-+ SENDERR(EEXIST);
-+ }
-+ ipsp = ipsp->ips_onext;
-+ }
-+
-+ /* link 'em */
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_x_grpsa_parse: "
-+ "linking ipsec_sa SA: %s with %s.\n",
-+ sa_len1 ? sa1 : " (error)",
-+ sa_len2 ? sa2 : " (error)");
-+ ips1p->ips_onext = ips2p;
-+ ips2p->ips_inext = ips1p;
-+ } else { /* UNGRPSA */
-+ ipsec_sa_put(ips1p);
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_x_grpsa_parse: "
-+ "unlinking ipsec_sa SA: %s.\n",
-+ sa_len1 ? sa1 : " (error)");
-+ while(ips1p->ips_onext) {
-+ ips1p = ips1p->ips_onext;
-+ }
-+ while(ips1p->ips_inext) {
-+ ipsp = ips1p;
-+ ips1p = ips1p->ips_inext;
-+ ipsec_sa_put(ips1p);
-+ ipsp->ips_inext = NULL;
-+ ipsec_sa_put(ipsp);
-+ ips1p->ips_onext = NULL;
-+ }
-+ }
-+
-+ spin_unlock_bh(&tdb_lock);
-+
-+ if(!(pfkey_safe_build(error = pfkey_msg_hdr_build(&extensions_reply[0],
-+ SADB_X_GRPSA,
-+ satype,
-+ 0,
-+ ((struct sadb_msg*)extensions[SADB_EXT_RESERVED])->sadb_msg_seq,
-+ ((struct sadb_msg*)extensions[SADB_EXT_RESERVED])->sadb_msg_pid),
-+ extensions_reply)
-+ && pfkey_safe_build(error = pfkey_sa_ref_build(&extensions_reply[SADB_EXT_SA],
-+ SADB_EXT_SA,
-+ extr->ips->ips_said.spi,
-+ extr->ips->ips_replaywin,
-+ extr->ips->ips_state,
-+ extr->ips->ips_authalg,
-+ extr->ips->ips_encalg,
-+ extr->ips->ips_flags,
-+ extr->ips->ips_ref),
-+ extensions_reply)
-+ && pfkey_safe_build(error = pfkey_address_build(&extensions_reply[SADB_EXT_ADDRESS_DST],
-+ SADB_EXT_ADDRESS_DST,
-+ 0, /*extr->ips->ips_said.proto,*/
-+ 0,
-+ extr->ips->ips_addr_d),
-+ extensions_reply)
-+ && (extr->ips2
-+ ? (pfkey_safe_build(error = pfkey_x_satype_build(&extensions_reply[SADB_X_EXT_SATYPE2],
-+ ((struct sadb_x_satype*)extensions[SADB_X_EXT_SATYPE2])->sadb_x_satype_satype
-+ /* proto2satype(extr->ips2->ips_said.proto) */),
-+ extensions_reply)
-+ && pfkey_safe_build(error = pfkey_sa_ref_build(&extensions_reply[SADB_X_EXT_SA2],
-+ SADB_X_EXT_SA2,
-+ extr->ips2->ips_said.spi,
-+ extr->ips2->ips_replaywin,
-+ extr->ips2->ips_state,
-+ extr->ips2->ips_authalg,
-+ extr->ips2->ips_encalg,
-+ extr->ips2->ips_flags,
-+ extr->ips2->ips_ref),
-+ extensions_reply)
-+ && pfkey_safe_build(error = pfkey_address_build(&extensions_reply[SADB_X_EXT_ADDRESS_DST2],
-+ SADB_X_EXT_ADDRESS_DST2,
-+ 0, /*extr->ips->ips_said.proto,*/
-+ 0,
-+ extr->ips2->ips_addr_d),
-+ extensions_reply) ) : 1 )
-+ )) {
-+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_x_grpsa_parse: "
-+ "failed to build the x_grpsa reply message extensions\n");
-+ SENDERR(-error);
-+ }
-+
-+ if((error = pfkey_msg_build(&pfkey_reply, extensions_reply, EXT_BITS_OUT))) {
-+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_x_grpsa_parse: "
-+ "failed to build the x_grpsa reply message\n");
-+ SENDERR(-error);
-+ }
-+
-+ for(pfkey_socketsp = pfkey_open_sockets;
-+ pfkey_socketsp;
-+ pfkey_socketsp = pfkey_socketsp->next) {
-+ if((error = pfkey_upmsg(pfkey_socketsp->socketp, pfkey_reply))) {
-+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_x_grpsa_parse: "
-+ "sending up x_grpsa reply message for satype=%d(%s) to socket=0p%p failed with error=%d.\n",
-+ satype,
-+ satype2name(satype),
-+ pfkey_socketsp->socketp,
-+ error);
-+ SENDERR(-error);
-+ }
-+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_x_grpsa_parse: "
-+ "sending up x_grpsa reply message for satype=%d(%s) to socket=0p%p succeeded.\n",
-+ satype,
-+ satype2name(satype),
-+ pfkey_socketsp->socketp);
-+ }
-+
-+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_x_grpsa_parse: "
-+ "succeeded in sending x_grpsa reply message.\n");
-+
-+ errlab:
-+ if (pfkey_reply) {
-+ pfkey_msg_free(&pfkey_reply);
-+ }
-+ pfkey_extensions_free(extensions_reply);
-+ return error;
-+}
-+
-+DEBUG_NO_STATIC int
-+pfkey_x_addflow_parse(struct sock *sk, struct sadb_ext **extensions, struct pfkey_extracted_data* extr)
-+{
-+ int error = 0;
-+#ifdef CONFIG_IPSEC_DEBUG
-+ char buf1[64], buf2[64];
-+#endif /* CONFIG_IPSEC_DEBUG */
-+ struct sadb_ext *extensions_reply[SADB_EXT_MAX+1];
-+ struct sadb_msg *pfkey_reply = NULL;
-+ struct socket_list *pfkey_socketsp;
-+ uint8_t satype = ((struct sadb_msg*)extensions[SADB_EXT_RESERVED])->sadb_msg_satype;
-+ ip_address srcflow, dstflow, srcmask, dstmask;
-+
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_x_addflow_parse: .\n");
-+
-+ pfkey_extensions_init(extensions_reply);
-+
-+ memset((caddr_t)&srcflow, 0, sizeof(srcflow));
-+ memset((caddr_t)&dstflow, 0, sizeof(dstflow));
-+ memset((caddr_t)&srcmask, 0, sizeof(srcmask));
-+ memset((caddr_t)&dstmask, 0, sizeof(dstmask));
-+
-+ if(!extr || !(extr->ips) || !(extr->eroute)) {
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_x_addflow_parse: "
-+ "missing extr, ipsec_sa or eroute data.\n");
-+ SENDERR(EINVAL);
-+ }
-+
-+ srcflow.u.v4.sin_family = AF_INET;
-+ dstflow.u.v4.sin_family = AF_INET;
-+ srcmask.u.v4.sin_family = AF_INET;
-+ dstmask.u.v4.sin_family = AF_INET;
-+ srcflow.u.v4.sin_addr = extr->eroute->er_eaddr.sen_ip_src;
-+ dstflow.u.v4.sin_addr = extr->eroute->er_eaddr.sen_ip_dst;
-+ srcmask.u.v4.sin_addr = extr->eroute->er_emask.sen_ip_src;
-+ dstmask.u.v4.sin_addr = extr->eroute->er_emask.sen_ip_dst;
-+
-+#ifdef CONFIG_IPSEC_DEBUG
-+ if (debug_pfkey) {
-+ subnettoa(extr->eroute->er_eaddr.sen_ip_src,
-+ extr->eroute->er_emask.sen_ip_src, 0, buf1, sizeof(buf1));
-+ subnettoa(extr->eroute->er_eaddr.sen_ip_dst,
-+ extr->eroute->er_emask.sen_ip_dst, 0, buf2, sizeof(buf2));
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_x_addflow_parse: "
-+ "calling breakeroute and/or makeroute for %s->%s\n",
-+ buf1, buf2);
-+ }
-+#endif /* CONFIG_IPSEC_DEBUG */
-+ if(extr->ips->ips_flags & SADB_X_SAFLAGS_INFLOW) {
-+/* if(ip_chk_addr((unsigned long)extr->ips->ips_said.dst.u.v4.sin_addr.s_addr) == IS_MYADDR) */
-+ struct ipsec_sa *ipsp, *ipsq;
-+ char sa[SATOT_BUF];
-+ size_t sa_len;
-+
-+ ipsq = ipsec_sa_getbyid(&(extr->ips->ips_said));
-+ if(ipsq == NULL) {
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_x_addflow_parse: "
-+ "ipsec_sa not found, cannot set incoming policy.\n");
-+ SENDERR(ENOENT);
-+ }
-+
-+ ipsp = ipsq;
-+ while(ipsp && ipsp->ips_said.proto != IPPROTO_IPIP) {
-+ ipsp = ipsp->ips_inext;
-+ }
-+
-+ if(ipsp == NULL) {
-+ ipsec_sa_put(ipsq);
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_x_addflow_parse: "
-+ "SA chain does not have an IPIP SA, cannot set incoming policy.\n");
-+ SENDERR(ENOENT);
-+ }
-+
-+ sa_len = satot(&extr->ips->ips_said, 0, sa, sizeof(sa));
-+
-+ ipsp->ips_flags |= SADB_X_SAFLAGS_INFLOW;
-+ ipsp->ips_flow_s = srcflow;
-+ ipsp->ips_flow_d = dstflow;
-+ ipsp->ips_mask_s = srcmask;
-+ ipsp->ips_mask_d = dstmask;
-+
-+ ipsec_sa_put(ipsq);
-+
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_x_addflow_parse: "
-+ "inbound eroute, setting incoming policy information in IPIP ipsec_sa for SA: %s.\n",
-+ sa_len ? sa : " (error)");
-+ } else {
-+ struct sk_buff *first = NULL, *last = NULL;
-+
-+ if(extr->ips->ips_flags & SADB_X_SAFLAGS_REPLACEFLOW) {
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_x_addflow_parse: "
-+ "REPLACEFLOW flag set, calling breakeroute.\n");
-+ if ((error = ipsec_breakroute(&(extr->eroute->er_eaddr),
-+ &(extr->eroute->er_emask),
-+ &first, &last))) {
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_x_addflow_parse: "
-+ "breakeroute returned %d. first=0p%p, last=0p%p\n",
-+ error,
-+ first,
-+ last);
-+ if(first != NULL) {
-+ ipsec_kfree_skb(first);
-+ }
-+ if(last != NULL) {
-+ ipsec_kfree_skb(last);
-+ }
-+ SENDERR(-error);
-+ }
-+ }
-+
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_x_addflow_parse: "
-+ "calling makeroute.\n");
-+
-+ if ((error = ipsec_makeroute(&(extr->eroute->er_eaddr),
-+ &(extr->eroute->er_emask),
-+ extr->ips->ips_said,
-+ ((struct sadb_msg*)extensions[SADB_EXT_RESERVED])->sadb_msg_pid,
-+ NULL,
-+ &(extr->ips->ips_ident_s),
-+ &(extr->ips->ips_ident_d)))) {
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_x_addflow_parse: "
-+ "makeroute returned %d.\n", error);
-+ SENDERR(-error);
-+ }
-+ if(first != NULL) {
-+ KLIPS_PRINT(debug_eroute,
-+ "klips_debug:pfkey_x_addflow_parse: "
-+ "first=0p%p HOLD packet re-injected.\n",
-+ first);
-+ DEV_QUEUE_XMIT(first, first->dev, SOPRI_NORMAL);
-+ }
-+ if(last != NULL) {
-+ KLIPS_PRINT(debug_eroute,
-+ "klips_debug:pfkey_x_addflow_parse: "
-+ "last=0p%p HOLD packet re-injected.\n",
-+ last);
-+ DEV_QUEUE_XMIT(last, last->dev, SOPRI_NORMAL);
-+ }
-+ }
-+
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_x_addflow_parse: "
-+ "makeroute call successful.\n");
-+
-+ if(!(pfkey_safe_build(error = pfkey_msg_hdr_build(&extensions_reply[0],
-+ SADB_X_ADDFLOW,
-+ satype,
-+ 0,
-+ ((struct sadb_msg*)extensions[SADB_EXT_RESERVED])->sadb_msg_seq,
-+ ((struct sadb_msg*)extensions[SADB_EXT_RESERVED])->sadb_msg_pid),
-+ extensions_reply)
-+ && pfkey_safe_build(error = pfkey_sa_ref_build(&extensions_reply[SADB_EXT_SA],
-+ SADB_EXT_SA,
-+ extr->ips->ips_said.spi,
-+ extr->ips->ips_replaywin,
-+ extr->ips->ips_state,
-+ extr->ips->ips_authalg,
-+ extr->ips->ips_encalg,
-+ extr->ips->ips_flags,
-+ extr->ips->ips_ref),
-+ extensions_reply)
-+ && (extensions[SADB_EXT_ADDRESS_SRC]
-+ ? pfkey_safe_build(error = pfkey_address_build(&extensions_reply[SADB_EXT_ADDRESS_SRC],
-+ SADB_EXT_ADDRESS_SRC,
-+ 0, /*extr->ips->ips_said.proto,*/
-+ 0,
-+ extr->ips->ips_addr_s),
-+ extensions_reply) : 1)
-+ && (extensions[SADB_EXT_ADDRESS_DST]
-+ ? pfkey_safe_build(error = pfkey_address_build(&extensions_reply[SADB_EXT_ADDRESS_DST],
-+ SADB_EXT_ADDRESS_DST,
-+ 0, /*extr->ips->ips_said.proto,*/
-+ 0,
-+ extr->ips->ips_addr_d),
-+ extensions_reply) : 1)
-+ && pfkey_safe_build(error = pfkey_address_build(&extensions_reply[SADB_X_EXT_ADDRESS_SRC_FLOW],
-+ SADB_X_EXT_ADDRESS_SRC_FLOW,
-+ 0, /*extr->ips->ips_said.proto,*/
-+ 0,
-+ (struct sockaddr*)&srcflow),
-+ extensions_reply)
-+ && pfkey_safe_build(error = pfkey_address_build(&extensions_reply[SADB_X_EXT_ADDRESS_DST_FLOW],
-+ SADB_X_EXT_ADDRESS_DST_FLOW,
-+ 0, /*extr->ips->ips_said.proto,*/
-+ 0,
-+ (struct sockaddr*)&dstflow),
-+ extensions_reply)
-+ && pfkey_safe_build(error = pfkey_address_build(&extensions_reply[SADB_X_EXT_ADDRESS_SRC_MASK],
-+ SADB_X_EXT_ADDRESS_SRC_MASK,
-+ 0, /*extr->ips->ips_said.proto,*/
-+ 0,
-+ (struct sockaddr*)&srcmask),
-+ extensions_reply)
-+ && pfkey_safe_build(error = pfkey_address_build(&extensions_reply[SADB_X_EXT_ADDRESS_DST_MASK],
-+ SADB_X_EXT_ADDRESS_DST_MASK,
-+ 0, /*extr->ips->ips_said.proto,*/
-+ 0,
-+ (struct sockaddr*)&dstmask),
-+ extensions_reply)
-+ )) {
-+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_x_addflow_parse: "
-+ "failed to build the x_addflow reply message extensions\n");
-+ SENDERR(-error);
-+ }
-+
-+ if((error = pfkey_msg_build(&pfkey_reply, extensions_reply, EXT_BITS_OUT))) {
-+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_x_addflow_parse: "
-+ "failed to build the x_addflow reply message\n");
-+ SENDERR(-error);
-+ }
-+
-+ for(pfkey_socketsp = pfkey_open_sockets;
-+ pfkey_socketsp;
-+ pfkey_socketsp = pfkey_socketsp->next) {
-+ if((error = pfkey_upmsg(pfkey_socketsp->socketp, pfkey_reply))) {
-+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_x_addflow_parse: "
-+ "sending up x_addflow reply message for satype=%d(%s) to socket=0p%p failed with error=%d.\n",
-+ satype,
-+ satype2name(satype),
-+ pfkey_socketsp->socketp,
-+ error);
-+ SENDERR(-error);
-+ }
-+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_x_addflow_parse: "
-+ "sending up x_addflow reply message for satype=%d(%s) (proto=%d) to socket=0p%p succeeded.\n",
-+ satype,
-+ satype2name(satype),
-+ extr->ips->ips_said.proto,
-+ pfkey_socketsp->socketp);
-+ }
-+
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_x_addflow_parse: "
-+ "extr->ips cleaned up and freed.\n");
-+
-+ errlab:
-+ if (pfkey_reply) {
-+ pfkey_msg_free(&pfkey_reply);
-+ }
-+ pfkey_extensions_free(extensions_reply);
-+ return error;
-+}
-+
-+DEBUG_NO_STATIC int
-+pfkey_x_delflow_parse(struct sock *sk, struct sadb_ext **extensions, struct pfkey_extracted_data* extr)
-+{
-+ int error = 0;
-+#ifdef CONFIG_IPSEC_DEBUG
-+ char buf1[64], buf2[64];
-+#endif /* CONFIG_IPSEC_DEBUG */
-+ struct sadb_ext *extensions_reply[SADB_EXT_MAX+1];
-+ struct sadb_msg *pfkey_reply = NULL;
-+ struct socket_list *pfkey_socketsp;
-+ uint8_t satype = ((struct sadb_msg*)extensions[SADB_EXT_RESERVED])->sadb_msg_satype;
-+ ip_address srcflow, dstflow, srcmask, dstmask;
-+
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_x_delflow_parse: .\n");
-+
-+ pfkey_extensions_init(extensions_reply);
-+
-+ memset((caddr_t)&srcflow, 0, sizeof(srcflow));
-+ memset((caddr_t)&dstflow, 0, sizeof(dstflow));
-+ memset((caddr_t)&srcmask, 0, sizeof(srcmask));
-+ memset((caddr_t)&dstmask, 0, sizeof(dstmask));
-+
-+ if(!extr || !(extr->ips)) {
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_x_delflow_parse: "
-+ "extr, or extr->ips is NULL, fatal\n");
-+ SENDERR(EINVAL);
-+ }
-+
-+ if(extr->ips->ips_flags & SADB_X_SAFLAGS_CLEARFLOW) {
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_x_delflow_parse: "
-+ "CLEARFLOW flag set, calling cleareroutes.\n");
-+ if ((error = ipsec_cleareroutes()))
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_x_delflow_parse: "
-+ "cleareroutes returned %d.\n", error);
-+ SENDERR(-error);
-+ } else {
-+ struct sk_buff *first = NULL, *last = NULL;
-+
-+ if(!(extr->eroute)) {
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_x_delflow_parse: "
-+ "extr->eroute is NULL, fatal.\n");
-+ SENDERR(EINVAL);
-+ }
-+
-+ srcflow.u.v4.sin_family = AF_INET;
-+ dstflow.u.v4.sin_family = AF_INET;
-+ srcmask.u.v4.sin_family = AF_INET;
-+ dstmask.u.v4.sin_family = AF_INET;
-+ srcflow.u.v4.sin_addr = extr->eroute->er_eaddr.sen_ip_src;
-+ dstflow.u.v4.sin_addr = extr->eroute->er_eaddr.sen_ip_dst;
-+ srcmask.u.v4.sin_addr = extr->eroute->er_emask.sen_ip_src;
-+ dstmask.u.v4.sin_addr = extr->eroute->er_emask.sen_ip_dst;
-+
-+#ifdef CONFIG_IPSEC_DEBUG
-+ if (debug_pfkey) {
-+ subnettoa(extr->eroute->er_eaddr.sen_ip_src,
-+ extr->eroute->er_emask.sen_ip_src, 0, buf1, sizeof(buf1));
-+ subnettoa(extr->eroute->er_eaddr.sen_ip_dst,
-+ extr->eroute->er_emask.sen_ip_dst, 0, buf2, sizeof(buf2));
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_x_delflow_parse: "
-+ "calling breakeroute for %s->%s\n",
-+ buf1, buf2);
-+ }
-+#endif /* CONFIG_IPSEC_DEBUG */
-+ error = ipsec_breakroute(&(extr->eroute->er_eaddr),
-+ &(extr->eroute->er_emask),
-+ &first, &last);
-+ if(error) {
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_x_delflow_parse: "
-+ "breakeroute returned %d. first=0p%p, last=0p%p\n",
-+ error,
-+ first,
-+ last);
-+ }
-+ if(first != NULL) {
-+ ipsec_kfree_skb(first);
-+ }
-+ if(last != NULL) {
-+ ipsec_kfree_skb(last);
-+ }
-+ if(error) {
-+ SENDERR(-error);
-+ }
-+ }
-+
-+ if(!(pfkey_safe_build(error = pfkey_msg_hdr_build(&extensions_reply[0],
-+ SADB_X_DELFLOW,
-+ satype,
-+ 0,
-+ ((struct sadb_msg*)extensions[SADB_EXT_RESERVED])->sadb_msg_seq,
-+ ((struct sadb_msg*)extensions[SADB_EXT_RESERVED])->sadb_msg_pid),
-+ extensions_reply)
-+ && pfkey_safe_build(error = pfkey_sa_ref_build(&extensions_reply[SADB_EXT_SA],
-+ SADB_EXT_SA,
-+ extr->ips->ips_said.spi,
-+ extr->ips->ips_replaywin,
-+ extr->ips->ips_state,
-+ extr->ips->ips_authalg,
-+ extr->ips->ips_encalg,
-+ extr->ips->ips_flags,
-+ extr->ips->ips_ref),
-+ extensions_reply)
-+ && pfkey_safe_build(error = pfkey_address_build(&extensions_reply[SADB_X_EXT_ADDRESS_SRC_FLOW],
-+ SADB_X_EXT_ADDRESS_SRC_FLOW,
-+ 0, /*extr->ips->ips_said.proto,*/
-+ 0,
-+ (struct sockaddr*)&srcflow),
-+ extensions_reply)
-+ && pfkey_safe_build(error = pfkey_address_build(&extensions_reply[SADB_X_EXT_ADDRESS_DST_FLOW],
-+ SADB_X_EXT_ADDRESS_DST_FLOW,
-+ 0, /*extr->ips->ips_said.proto,*/
-+ 0,
-+ (struct sockaddr*)&dstflow),
-+ extensions_reply)
-+ && pfkey_safe_build(error = pfkey_address_build(&extensions_reply[SADB_X_EXT_ADDRESS_SRC_MASK],
-+ SADB_X_EXT_ADDRESS_SRC_MASK,
-+ 0, /*extr->ips->ips_said.proto,*/
-+ 0,
-+ (struct sockaddr*)&srcmask),
-+ extensions_reply)
-+ && pfkey_safe_build(error = pfkey_address_build(&extensions_reply[SADB_X_EXT_ADDRESS_DST_MASK],
-+ SADB_X_EXT_ADDRESS_DST_MASK,
-+ 0, /*extr->ips->ips_said.proto,*/
-+ 0,
-+ (struct sockaddr*)&dstmask),
-+ extensions_reply)
-+ )) {
-+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_x_delflow_parse: "
-+ "failed to build the x_delflow reply message extensions\n");
-+ SENDERR(-error);
-+ }
-+
-+ if((error = pfkey_msg_build(&pfkey_reply, extensions_reply, EXT_BITS_OUT))) {
-+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_x_delflow_parse: "
-+ "failed to build the x_delflow reply message\n");
-+ SENDERR(-error);
-+ }
-+
-+ for(pfkey_socketsp = pfkey_open_sockets;
-+ pfkey_socketsp;
-+ pfkey_socketsp = pfkey_socketsp->next) {
-+ if((error = pfkey_upmsg(pfkey_socketsp->socketp, pfkey_reply))) {
-+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_x_delflow_parse: "
-+ "sending up x_delflow reply message for satype=%d(%s) to socket=0p%p failed with error=%d.\n",
-+ satype,
-+ satype2name(satype),
-+ pfkey_socketsp->socketp,
-+ error);
-+ SENDERR(-error);
-+ }
-+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_x_delflow_parse: "
-+ "sending up x_delflow reply message for satype=%d(%s) to socket=0p%p succeeded.\n",
-+ satype,
-+ satype2name(satype),
-+ pfkey_socketsp->socketp);
-+ }
-+
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_x_delflow_parse: "
-+ "extr->ips cleaned up and freed.\n");
-+
-+ errlab:
-+ if (pfkey_reply) {
-+ pfkey_msg_free(&pfkey_reply);
-+ }
-+ pfkey_extensions_free(extensions_reply);
-+ return error;
-+}
-+
-+DEBUG_NO_STATIC int
-+pfkey_x_msg_debug_parse(struct sock *sk, struct sadb_ext **extensions, struct pfkey_extracted_data* extr)
-+{
-+ int error = 0;
-+
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_x_msg_debug_parse: .\n");
-+
-+/* errlab:*/
-+ return error;
-+}
-+
-+/* pfkey_expire expects the ipsec_sa table to be locked before being called. */
-+int
-+pfkey_expire(struct ipsec_sa *ipsp, int hard)
-+{
-+ struct sadb_ext *extensions[SADB_EXT_MAX+1];
-+ struct sadb_msg *pfkey_msg = NULL;
-+ struct socket_list *pfkey_socketsp;
-+ int error = 0;
-+ uint8_t satype;
-+
-+ pfkey_extensions_init(extensions);
-+
-+ if(!(satype = proto2satype(ipsp->ips_said.proto))) {
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_expire: "
-+ "satype lookup for protocol %d lookup failed.\n",
-+ ipsp->ips_said.proto);
-+ SENDERR(EINVAL);
-+ }
-+
-+ if(!pfkey_open_sockets) {
-+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_expire: "
-+ "no sockets listening.\n");
-+ SENDERR(EPROTONOSUPPORT);
-+ }
-+
-+ if (!(pfkey_safe_build(error = pfkey_msg_hdr_build(&extensions[0],
-+ SADB_EXPIRE,
-+ satype,
-+ 0,
-+ ++pfkey_msg_seq,
-+ 0),
-+ extensions)
-+ && pfkey_safe_build(error = pfkey_sa_ref_build(&extensions[SADB_EXT_SA],
-+ SADB_EXT_SA,
-+ ipsp->ips_said.spi,
-+ ipsp->ips_replaywin,
-+ ipsp->ips_state,
-+ ipsp->ips_authalg,
-+ ipsp->ips_encalg,
-+ ipsp->ips_flags,
-+ ipsp->ips_ref),
-+ extensions)
-+ && pfkey_safe_build(error = pfkey_lifetime_build(&extensions[SADB_EXT_LIFETIME_CURRENT],
-+ SADB_EXT_LIFETIME_CURRENT,
-+ ipsp->ips_life.ipl_allocations.ipl_count,
-+ ipsp->ips_life.ipl_bytes.ipl_count,
-+ ipsp->ips_life.ipl_addtime.ipl_count,
-+ ipsp->ips_life.ipl_usetime.ipl_count,
-+ ipsp->ips_life.ipl_packets.ipl_count),
-+ extensions)
-+ && (hard ?
-+ pfkey_safe_build(error = pfkey_lifetime_build(&extensions[SADB_EXT_LIFETIME_HARD],
-+ SADB_EXT_LIFETIME_HARD,
-+ ipsp->ips_life.ipl_allocations.ipl_hard,
-+ ipsp->ips_life.ipl_bytes.ipl_hard,
-+ ipsp->ips_life.ipl_addtime.ipl_hard,
-+ ipsp->ips_life.ipl_usetime.ipl_hard,
-+ ipsp->ips_life.ipl_packets.ipl_hard),
-+ extensions)
-+ : pfkey_safe_build(error = pfkey_lifetime_build(&extensions[SADB_EXT_LIFETIME_SOFT],
-+ SADB_EXT_LIFETIME_SOFT,
-+ ipsp->ips_life.ipl_allocations.ipl_soft,
-+ ipsp->ips_life.ipl_bytes.ipl_soft,
-+ ipsp->ips_life.ipl_addtime.ipl_soft,
-+ ipsp->ips_life.ipl_usetime.ipl_soft,
-+ ipsp->ips_life.ipl_packets.ipl_soft),
-+ extensions))
-+ && pfkey_safe_build(error = pfkey_address_build(&extensions[SADB_EXT_ADDRESS_SRC],
-+ SADB_EXT_ADDRESS_SRC,
-+ 0, /* ipsp->ips_said.proto, */
-+ 0,
-+ ipsp->ips_addr_s),
-+ extensions)
-+ && pfkey_safe_build(error = pfkey_address_build(&extensions[SADB_EXT_ADDRESS_DST],
-+ SADB_EXT_ADDRESS_DST,
-+ 0, /* ipsp->ips_said.proto, */
-+ 0,
-+ ipsp->ips_addr_d),
-+ extensions))) {
-+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_expire: "
-+ "failed to build the expire message extensions\n");
-+ spin_unlock(&tdb_lock);
-+ goto errlab;
-+ }
-+
-+ if ((error = pfkey_msg_build(&pfkey_msg, extensions, EXT_BITS_OUT))) {
-+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_expire: "
-+ "failed to build the expire message\n");
-+ SENDERR(-error);
-+ }
-+
-+ for(pfkey_socketsp = pfkey_open_sockets;
-+ pfkey_socketsp;
-+ pfkey_socketsp = pfkey_socketsp->next) {
-+ if((error = pfkey_upmsg(pfkey_socketsp->socketp, pfkey_msg))) {
-+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_expire: "
-+ "sending up expire message for satype=%d(%s) to socket=0p%p failed with error=%d.\n",
-+ satype,
-+ satype2name(satype),
-+ pfkey_socketsp->socketp,
-+ error);
-+ SENDERR(-error);
-+ }
-+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_expire: "
-+ "sending up expire message for satype=%d(%s) (proto=%d) to socket=0p%p succeeded.\n",
-+ satype,
-+ satype2name(satype),
-+ ipsp->ips_said.proto,
-+ pfkey_socketsp->socketp);
-+ }
-+
-+ errlab:
-+ if (pfkey_msg) {
-+ pfkey_msg_free(&pfkey_msg);
-+ }
-+ pfkey_extensions_free(extensions);
-+ return error;
-+}
-+
-+int
-+pfkey_acquire(struct ipsec_sa *ipsp)
-+{
-+ struct sadb_ext *extensions[SADB_EXT_MAX+1];
-+ struct sadb_msg *pfkey_msg = NULL;
-+ struct socket_list *pfkey_socketsp;
-+ int error = 0;
-+ struct sadb_comb comb[] = {
-+ /* auth; encrypt; flags; */
-+ /* auth_minbits; auth_maxbits; encrypt_minbits; encrypt_maxbits; */
-+ /* reserved; soft_allocations; hard_allocations; soft_bytes; hard_bytes; */
-+ /* soft_addtime; hard_addtime; soft_usetime; hard_usetime; */
-+ /* soft_packets; hard_packets; */
-+ { SADB_AALG_MD5HMAC, SADB_EALG_3DESCBC, SADB_SAFLAGS_PFS,
-+ 128, 128, 168, 168,
-+ 0, 0, 0, 0, 0,
-+ 57600, 86400, 57600, 86400,
-+ 0, 0 },
-+ { SADB_AALG_SHA1HMAC, SADB_EALG_3DESCBC, SADB_SAFLAGS_PFS,
-+ 160, 160, 168, 168,
-+ 0, 0, 0, 0, 0,
-+ 57600, 86400, 57600, 86400,
-+ 0, 0 }
-+ };
-+
-+ /* XXX This should not be hard-coded. It should be taken from the spdb */
-+ uint8_t satype = SADB_SATYPE_ESP;
-+
-+ pfkey_extensions_init(extensions);
-+
-+ if((satype == 0) || (satype > SADB_SATYPE_MAX)) {
-+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_acquire: "
-+ "SAtype=%d unspecified or unknown.\n",
-+ satype);
-+ SENDERR(EINVAL);
-+ }
-+
-+ if(!(pfkey_registered_sockets[satype])) {
-+ KLIPS_PRINT(1|debug_pfkey, "klips_debug:pfkey_acquire: "
-+ "no sockets registered for SAtype=%d(%s).\n",
-+ satype,
-+ satype2name(satype));
-+ SENDERR(EPROTONOSUPPORT);
-+ }
-+
-+ if (!(pfkey_safe_build(error = pfkey_msg_hdr_build(&extensions[0],
-+ SADB_ACQUIRE,
-+ satype,
-+ 0,
-+ ++pfkey_msg_seq,
-+ 0),
-+ extensions)
-+ && pfkey_safe_build(error = pfkey_address_build(&extensions[SADB_EXT_ADDRESS_SRC],
-+ SADB_EXT_ADDRESS_SRC,
-+ ipsp->ips_transport_protocol,
-+ 0,
-+ ipsp->ips_addr_s),
-+ extensions)
-+ && pfkey_safe_build(error = pfkey_address_build(&extensions[SADB_EXT_ADDRESS_DST],
-+ SADB_EXT_ADDRESS_DST,
-+ ipsp->ips_transport_protocol,
-+ 0,
-+ ipsp->ips_addr_d),
-+ extensions)
-+#if 0
-+ && (ipsp->ips_addr_p
-+ ? pfkey_safe_build(error = pfkey_address_build(&extensions[SADB_EXT_ADDRESS_PROXY],
-+ SADB_EXT_ADDRESS_PROXY,
-+ ipsp->ips_transport_protocol,
-+ 0,
-+ ipsp->ips_addr_p),
-+ extensions) : 1)
-+#endif
-+ && (ipsp->ips_ident_s.type != SADB_IDENTTYPE_RESERVED
-+ ? pfkey_safe_build(error = pfkey_ident_build(&extensions[SADB_EXT_IDENTITY_SRC],
-+ SADB_EXT_IDENTITY_SRC,
-+ ipsp->ips_ident_s.type,
-+ ipsp->ips_ident_s.id,
-+ ipsp->ips_ident_s.len,
-+ ipsp->ips_ident_s.data),
-+ extensions) : 1)
-+
-+ && (ipsp->ips_ident_d.type != SADB_IDENTTYPE_RESERVED
-+ ? pfkey_safe_build(error = pfkey_ident_build(&extensions[SADB_EXT_IDENTITY_DST],
-+ SADB_EXT_IDENTITY_DST,
-+ ipsp->ips_ident_d.type,
-+ ipsp->ips_ident_d.id,
-+ ipsp->ips_ident_d.len,
-+ ipsp->ips_ident_d.data),
-+ extensions) : 1)
-+#if 0
-+ /* FIXME: This won't work yet because I have not finished
-+ it. */
-+ && (ipsp->ips_sens_
-+ ? pfkey_safe_build(error = pfkey_sens_build(&extensions[SADB_EXT_SENSITIVITY],
-+ ipsp->ips_sens_dpd,
-+ ipsp->ips_sens_sens_level,
-+ ipsp->ips_sens_sens_len,
-+ ipsp->ips_sens_sens_bitmap,
-+ ipsp->ips_sens_integ_level,
-+ ipsp->ips_sens_integ_len,
-+ ipsp->ips_sens_integ_bitmap),
-+ extensions) : 1)
-+#endif
-+ && pfkey_safe_build(error = pfkey_prop_build(&extensions[SADB_EXT_PROPOSAL],
-+ 64, /* replay */
-+ sizeof(comb)/sizeof(struct sadb_comb),
-+ &(comb[0])),
-+ extensions)
-+ )) {
-+ KLIPS_PRINT(1|debug_pfkey, "klips_debug:pfkey_acquire: "
-+ "failed to build the acquire message extensions\n");
-+ SENDERR(-error);
-+ }
-+
-+ if ((error = pfkey_msg_build(&pfkey_msg, extensions, EXT_BITS_OUT))) {
-+ KLIPS_PRINT(1|debug_pfkey, "klips_debug:pfkey_acquire: "
-+ "failed to build the acquire message\n");
-+ SENDERR(-error);
-+ }
-+
-+#if KLIPS_PFKEY_ACQUIRE_LOSSAGE > 0
-+ if(sysctl_ipsec_regress_pfkey_lossage) {
-+ return(0);
-+ }
-+#endif
-+
-+ /* this should go to all registered sockets for that satype only */
-+ for(pfkey_socketsp = pfkey_registered_sockets[satype];
-+ pfkey_socketsp;
-+ pfkey_socketsp = pfkey_socketsp->next) {
-+ if((error = pfkey_upmsg(pfkey_socketsp->socketp, pfkey_msg))) {
-+ KLIPS_PRINT(1|debug_pfkey, "klips_debug:pfkey_acquire: "
-+ "sending up acquire message for satype=%d(%s) to socket=0p%p failed with error=%d.\n",
-+ satype,
-+ satype2name(satype),
-+ pfkey_socketsp->socketp,
-+ error);
-+ SENDERR(-error);
-+ }
-+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_acquire: "
-+ "sending up acquire message for satype=%d(%s) to socket=0p%p succeeded.\n",
-+ satype,
-+ satype2name(satype),
-+ pfkey_socketsp->socketp);
-+ }
-+
-+ errlab:
-+ if (pfkey_msg) {
-+ pfkey_msg_free(&pfkey_msg);
-+ }
-+ pfkey_extensions_free(extensions);
-+ return error;
-+}
-+
-+#ifdef CONFIG_IPSEC_NAT_TRAVERSAL
-+int
-+pfkey_nat_t_new_mapping(struct ipsec_sa *ipsp, struct sockaddr *ipaddr,
-+ __u16 sport)
-+{
-+ struct sadb_ext *extensions[SADB_EXT_MAX+1];
-+ struct sadb_msg *pfkey_msg = NULL;
-+ struct socket_list *pfkey_socketsp;
-+ int error = 0;
-+ uint8_t satype = (ipsp->ips_said.proto==IPPROTO_ESP) ? SADB_SATYPE_ESP : 0;
-+
-+ /* Construct SADB_X_NAT_T_NEW_MAPPING message */
-+
-+ pfkey_extensions_init(extensions);
-+
-+ if((satype == 0) || (satype > SADB_SATYPE_MAX)) {
-+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_nat_t_new_mapping: "
-+ "SAtype=%d unspecified or unknown.\n",
-+ satype);
-+ SENDERR(EINVAL);
-+ }
-+
-+ if(!(pfkey_registered_sockets[satype])) {
-+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_nat_t_new_mapping: "
-+ "no sockets registered for SAtype=%d(%s).\n",
-+ satype,
-+ satype2name(satype));
-+ SENDERR(EPROTONOSUPPORT);
-+ }
-+
-+ if (!(pfkey_safe_build
-+ (error = pfkey_msg_hdr_build(&extensions[0], SADB_X_NAT_T_NEW_MAPPING,
-+ satype, 0, ++pfkey_msg_seq, 0), extensions)
-+ /* SA */
-+ && pfkey_safe_build
-+ (error = pfkey_sa_build(&extensions[SADB_EXT_SA],
-+ SADB_EXT_SA, ipsp->ips_said.spi, 0, 0, 0, 0, 0), extensions)
-+ /* ADDRESS_SRC = old addr */
-+ && pfkey_safe_build
-+ (error = pfkey_address_build(&extensions[SADB_EXT_ADDRESS_SRC],
-+ SADB_EXT_ADDRESS_SRC, ipsp->ips_said.proto, 0, ipsp->ips_addr_s),
-+ extensions)
-+ /* NAT_T_SPORT = old port */
-+ && pfkey_safe_build
-+ (error = pfkey_x_nat_t_port_build(&extensions[SADB_X_EXT_NAT_T_SPORT],
-+ SADB_X_EXT_NAT_T_SPORT, ipsp->ips_natt_sport), extensions)
-+ /* ADDRESS_DST = new addr */
-+ && pfkey_safe_build
-+ (error = pfkey_address_build(&extensions[SADB_EXT_ADDRESS_DST],
-+ SADB_EXT_ADDRESS_DST, ipsp->ips_said.proto, 0, ipaddr), extensions)
-+ /* NAT_T_DPORT = new port */
-+ && pfkey_safe_build
-+ (error = pfkey_x_nat_t_port_build(&extensions[SADB_X_EXT_NAT_T_DPORT],
-+ SADB_X_EXT_NAT_T_DPORT, sport), extensions)
-+ )) {
-+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_nat_t_new_mapping: "
-+ "failed to build the nat_t_new_mapping message extensions\n");
-+ SENDERR(-error);
-+ }
-+
-+ if ((error = pfkey_msg_build(&pfkey_msg, extensions, EXT_BITS_OUT))) {
-+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_nat_t_new_mapping: "
-+ "failed to build the nat_t_new_mapping message\n");
-+ SENDERR(-error);
-+ }
-+
-+ /* this should go to all registered sockets for that satype only */
-+ for(pfkey_socketsp = pfkey_registered_sockets[satype];
-+ pfkey_socketsp;
-+ pfkey_socketsp = pfkey_socketsp->next) {
-+ if((error = pfkey_upmsg(pfkey_socketsp->socketp, pfkey_msg))) {
-+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_nat_t_new_mapping: "
-+ "sending up nat_t_new_mapping message for satype=%d(%s) to socket=%p failed with error=%d.\n",
-+ satype,
-+ satype2name(satype),
-+ pfkey_socketsp->socketp,
-+ error);
-+ SENDERR(-error);
-+ }
-+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_nat_t_new_mapping: "
-+ "sending up nat_t_new_mapping message for satype=%d(%s) to socket=%p succeeded.\n",
-+ satype,
-+ satype2name(satype),
-+ pfkey_socketsp->socketp);
-+ }
-+
-+ errlab:
-+ if (pfkey_msg) {
-+ pfkey_msg_free(&pfkey_msg);
-+ }
-+ pfkey_extensions_free(extensions);
-+ return error;
-+}
-+
-+DEBUG_NO_STATIC int
-+pfkey_x_nat_t_new_mapping_parse(struct sock *sk, struct sadb_ext **extensions, struct pfkey_extracted_data* extr)
-+{
-+ /* SADB_X_NAT_T_NEW_MAPPING not used in kernel */
-+ return -EINVAL;
-+}
-+#endif
-+
-+DEBUG_NO_STATIC int (*ext_processors[SADB_EXT_MAX+1])(struct sadb_ext *pfkey_ext, struct pfkey_extracted_data* extr) =
-+{
-+ NULL, /* pfkey_msg_process, */
-+ pfkey_sa_process,
-+ pfkey_lifetime_process,
-+ pfkey_lifetime_process,
-+ pfkey_lifetime_process,
-+ pfkey_address_process,
-+ pfkey_address_process,
-+ pfkey_address_process,
-+ pfkey_key_process,
-+ pfkey_key_process,
-+ pfkey_ident_process,
-+ pfkey_ident_process,
-+ pfkey_sens_process,
-+ pfkey_prop_process,
-+ pfkey_supported_process,
-+ pfkey_supported_process,
-+ pfkey_spirange_process,
-+ pfkey_x_kmprivate_process,
-+ pfkey_x_satype_process,
-+ pfkey_sa_process,
-+ pfkey_address_process,
-+ pfkey_address_process,
-+ pfkey_address_process,
-+ pfkey_address_process,
-+ pfkey_address_process,
-+ pfkey_x_debug_process,
-+ pfkey_x_protocol_process
-+#ifdef CONFIG_IPSEC_NAT_TRAVERSAL
-+ ,
-+ pfkey_x_nat_t_type_process,
-+ pfkey_x_nat_t_port_process,
-+ pfkey_x_nat_t_port_process,
-+ pfkey_address_process
-+#endif
-+};
-+
-+
-+DEBUG_NO_STATIC int (*msg_parsers[SADB_MAX +1])(struct sock *sk, struct sadb_ext *extensions[], struct pfkey_extracted_data* extr)
-+ =
-+{
-+ NULL, /* RESERVED */
-+ pfkey_getspi_parse,
-+ pfkey_update_parse,
-+ pfkey_add_parse,
-+ pfkey_delete_parse,
-+ pfkey_get_parse,
-+ pfkey_acquire_parse,
-+ pfkey_register_parse,
-+ pfkey_expire_parse,
-+ pfkey_flush_parse,
-+ pfkey_dump_parse,
-+ pfkey_x_promisc_parse,
-+ pfkey_x_pchange_parse,
-+ pfkey_x_grpsa_parse,
-+ pfkey_x_addflow_parse,
-+ pfkey_x_delflow_parse,
-+ pfkey_x_msg_debug_parse
-+#ifdef CONFIG_IPSEC_NAT_TRAVERSAL
-+ , pfkey_x_nat_t_new_mapping_parse
-+#endif
-+};
-+
-+int
-+pfkey_build_reply(struct sadb_msg *pfkey_msg, struct pfkey_extracted_data *extr,
-+ struct sadb_msg **pfkey_reply)
-+{
-+ struct sadb_ext *extensions[SADB_EXT_MAX+1];
-+ int error = 0;
-+ int msg_type = pfkey_msg->sadb_msg_type;
-+ int seq = pfkey_msg->sadb_msg_seq;
-+
-+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_build_reply: "
-+ "building reply with type: %d\n",
-+ msg_type);
-+ pfkey_extensions_init(extensions);
-+ if (!extr || !extr->ips) {
-+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_build_reply: "
-+ "bad ipsec_sa passed\n");
-+ return EINVAL;
-+ }
-+ error = pfkey_safe_build(pfkey_msg_hdr_build(&extensions[0],
-+ msg_type,
-+ proto2satype(extr->ips->ips_said.proto),
-+ 0,
-+ seq,
-+ pfkey_msg->sadb_msg_pid),
-+ extensions) &&
-+ (!(extensions_bitmaps[EXT_BITS_OUT][EXT_BITS_REQ][msg_type] &
-+ 1 << SADB_EXT_SA)
-+ || pfkey_safe_build(pfkey_sa_ref_build(&extensions[SADB_EXT_SA],
-+ SADB_EXT_SA,
-+ extr->ips->ips_said.spi,
-+ extr->ips->ips_replaywin,
-+ extr->ips->ips_state,
-+ extr->ips->ips_authalg,
-+ extr->ips->ips_encalg,
-+ extr->ips->ips_flags,
-+ extr->ips->ips_ref),
-+ extensions)) &&
-+ (!(extensions_bitmaps[EXT_BITS_OUT][EXT_BITS_REQ][msg_type] &
-+ 1 << SADB_EXT_LIFETIME_CURRENT)
-+ || pfkey_safe_build(pfkey_lifetime_build(&extensions
-+ [SADB_EXT_LIFETIME_CURRENT],
-+ SADB_EXT_LIFETIME_CURRENT,
-+ extr->ips->ips_life.ipl_allocations.ipl_count,
-+ extr->ips->ips_life.ipl_bytes.ipl_count,
-+ extr->ips->ips_life.ipl_addtime.ipl_count,
-+ extr->ips->ips_life.ipl_usetime.ipl_count,
-+ extr->ips->ips_life.ipl_packets.ipl_count),
-+ extensions)) &&
-+ (!(extensions_bitmaps[EXT_BITS_OUT][EXT_BITS_REQ][msg_type] &
-+ 1 << SADB_EXT_ADDRESS_SRC)
-+ || pfkey_safe_build(pfkey_address_build(&extensions[SADB_EXT_ADDRESS_SRC],
-+ SADB_EXT_ADDRESS_SRC,
-+ extr->ips->ips_said.proto,
-+ 0,
-+ extr->ips->ips_addr_s),
-+ extensions)) &&
-+ (!(extensions_bitmaps[EXT_BITS_OUT][EXT_BITS_REQ][msg_type] &
-+ 1 << SADB_EXT_ADDRESS_DST)
-+ || pfkey_safe_build(pfkey_address_build(&extensions[SADB_EXT_ADDRESS_DST],
-+ SADB_EXT_ADDRESS_DST,
-+ extr->ips->ips_said.proto,
-+ 0,
-+ extr->ips->ips_addr_d),
-+ extensions));
-+
-+ if (error == 0) {
-+ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_build_reply: "
-+ "building extensions failed\n");
-+ return EINVAL;
-+ }
-+
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_build_reply: "
-+ "built extensions, proceed to build the message\n");
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_build_reply: "
-+ "extensions[1]=0p%p\n",
-+ extensions[1]);
-+ error = pfkey_msg_build(pfkey_reply, extensions, EXT_BITS_OUT);
-+ pfkey_extensions_free(extensions);
-+
-+ return error;
-+}
-+
-+int
-+pfkey_msg_interp(struct sock *sk, struct sadb_msg *pfkey_msg,
-+ struct sadb_msg **pfkey_reply)
-+{
-+ int error = 0;
-+ int i;
-+ struct sadb_ext *extensions[SADB_EXT_MAX+1];
-+ struct pfkey_extracted_data extr = {NULL, NULL, NULL};
-+
-+ pfkey_extensions_init(extensions);
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_msg_interp: "
-+ "parsing message ver=%d, type=%d, errno=%d, satype=%d(%s), len=%d, res=%d, seq=%d, pid=%d.\n",
-+ pfkey_msg->sadb_msg_version,
-+ pfkey_msg->sadb_msg_type,
-+ pfkey_msg->sadb_msg_errno,
-+ pfkey_msg->sadb_msg_satype,
-+ satype2name(pfkey_msg->sadb_msg_satype),
-+ pfkey_msg->sadb_msg_len,
-+ pfkey_msg->sadb_msg_reserved,
-+ pfkey_msg->sadb_msg_seq,
-+ pfkey_msg->sadb_msg_pid);
-+
-+ extr.ips = ipsec_sa_alloc(&error); /* pass in error var by pointer */
-+ if(extr.ips == NULL) {
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_msg_interp: "
-+ "memory allocation error.\n");
-+ SENDERR(-error);
-+ }
-+
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_msg_interp: "
-+ "allocated extr->ips=0p%p.\n",
-+ extr.ips);
-+
-+ if(pfkey_msg->sadb_msg_satype > SADB_SATYPE_MAX) {
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_msg_interp: "
-+ "satype %d > max %d\n",
-+ pfkey_msg->sadb_msg_satype,
-+ SADB_SATYPE_MAX);
-+ SENDERR(EINVAL);
-+ }
-+
-+ switch(pfkey_msg->sadb_msg_type) {
-+ case SADB_GETSPI:
-+ case SADB_UPDATE:
-+ case SADB_ADD:
-+ case SADB_DELETE:
-+ case SADB_X_GRPSA:
-+ case SADB_X_ADDFLOW:
-+
-+ if(!(extr.ips->ips_said.proto = satype2proto(pfkey_msg->sadb_msg_satype))) {
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_msg_interp: "
-+ "satype %d lookup failed.\n",
-+ pfkey_msg->sadb_msg_satype);
-+ SENDERR(EINVAL);
-+ } else {
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_msg_interp: "
-+ "satype %d lookups to proto=%d.\n",
-+ pfkey_msg->sadb_msg_satype,
-+ extr.ips->ips_said.proto);
-+ }
-+ break;
-+ default:
-+ break;
-+ }
-+
-+ /* The NULL below causes the default extension parsers to be used */
-+ /* Parse the extensions */
-+ if((error = pfkey_msg_parse(pfkey_msg, NULL, extensions, EXT_BITS_IN)))
-+ {
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_msg_interp: "
-+ "message parsing failed with error %d.\n",
-+ error);
-+ SENDERR(-error);
-+ }
-+
-+ /* Process the extensions */
-+ for(i=1; i <= SADB_EXT_MAX;i++) {
-+ if(extensions[i] != NULL) {
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_msg_interp: "
-+ "processing ext %d 0p%p with processor 0p%p.\n",
-+ i, extensions[i], ext_processors[i]);
-+ if((error = ext_processors[i](extensions[i], &extr))) {
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_msg_interp: "
-+ "extension processing for type %d failed with error %d.\n",
-+ i,
-+ error);
-+ SENDERR(-error);
-+ }
-+
-+ }
-+
-+ }
-+
-+ /* Parse the message types */
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_msg_interp: "
-+ "parsing message type %d(%s) with msg_parser 0p%p.\n",
-+ pfkey_msg->sadb_msg_type,
-+ pfkey_v2_sadb_type_string(pfkey_msg->sadb_msg_type),
-+ msg_parsers[pfkey_msg->sadb_msg_type]);
-+ if((error = msg_parsers[pfkey_msg->sadb_msg_type](sk, extensions, &extr))) {
-+ KLIPS_PRINT(debug_pfkey,
-+ "klips_debug:pfkey_msg_interp: "
-+ "message parsing failed with error %d.\n",
-+ error);
-+ SENDERR(-error);
-+ }
-+
-+#if 0
-+ error = pfkey_build_reply(pfkey_msg, &extr, pfkey_reply);
-+ if (error) {
-+ *pfkey_reply = NULL;
-+ }
-+#endif
-+ errlab:
-+ if(extr.ips != NULL) {
-+ ipsec_sa_wipe(extr.ips);
-+ }
-+ if(extr.ips2 != NULL) {
-+ ipsec_sa_wipe(extr.ips2);
-+ }
-+ if (extr.eroute != NULL) {
-+ kfree(extr.eroute);
-+ }
-+ return(error);
-+}
-+
-+/*
-+ * $Log: pfkey_v2_parser.c,v $
-+ * Revision 1.123 2004/04/06 02:49:26 mcr
-+ * pullup of algo code from alg-branch.
-+ *
-+ * Revision 1.122.2.2 2004/04/05 04:30:46 mcr
-+ * patches for alg-branch to compile/work with 2.x openswan
-+ *
-+ * Revision 1.122.2.1 2003/12/22 15:25:52 jjo
-+ * . Merged algo-0.8.1-rc11-test1 into alg-branch
-+ *
-+ * Revision 1.122 2003/12/10 01:14:27 mcr
-+ * NAT-traversal patches to KLIPS.
-+ *
-+ * Revision 1.121 2003/10/31 02:27:55 mcr
-+ * pulled up port-selector patches and sa_id elimination.
-+ *
-+ * Revision 1.120.4.2 2003/10/29 01:30:41 mcr
-+ * elimited "struct sa_id".
-+ *
-+ * Revision 1.120.4.1 2003/09/21 13:59:56 mcr
-+ * pre-liminary X.509 patch - does not yet pass tests.
-+ *
-+ * Revision 1.120 2003/04/03 17:38:09 rgb
-+ * Centralised ipsec_kfree_skb and ipsec_dev_{get,put}.
-+ *
-+ * Revision 1.119 2003/02/06 01:52:37 rgb
-+ * Removed no longer relevant comment
-+ *
-+ * Revision 1.118 2003/01/30 02:32:44 rgb
-+ *
-+ * Transmit error code through to caller from callee for better diagnosis of problems.
-+ *
-+ * Revision 1.117 2003/01/16 18:48:13 rgb
-+ *
-+ * Fixed sign bug in error return from an sa allocation call in
-+ * pfkey_msg_interp.
-+ *
-+ * Revision 1.116 2002/10/17 16:38:01 rgb
-+ * Change pfkey_alloc_eroute() to never static since its consumers
-+ * have been moved outside the file.
-+ *
-+ * Revision 1.115 2002/10/12 23:11:53 dhr
-+ *
-+ * [KenB + DHR] more 64-bit cleanup
-+ *
-+ * Revision 1.114 2002/10/05 05:02:58 dhr
-+ *
-+ * C labels go on statements
-+ *
-+ * Revision 1.113 2002/09/30 19:11:22 rgb
-+ * Turn on debugging for upgoing acquire messages to test for reliability.
-+ *
-+ * Revision 1.112 2002/09/20 15:41:16 rgb
-+ * Switch from pfkey_alloc_ipsec_sa() to ipsec_sa_alloc().
-+ * Added sadb_x_sa_ref to struct sadb_sa.
-+ * Added ref parameter to pfkey_sa_build().
-+ *
-+ * Revision 1.111 2002/09/20 05:02:08 rgb
-+ * Added memory allocation debugging.
-+ * Convert to switch to divulge hmac keys for debugging.
-+ * Added text labels to elucidate numeric values presented.
-+ *
-+ * Revision 1.110 2002/08/03 18:03:05 mcr
-+ * loop that checks for SPI's to have been already linked
-+ * fails to actually step to next pointer, but continuously
-+ * resets to head of list. Wrong pointer used.
-+ * test east-icmp-02 revealed this.
-+ *
-+ * Revision 1.109 2002/07/26 08:48:31 rgb
-+ * Added SA ref table code.
-+ *
-+ * Revision 1.108 2002/05/27 18:55:03 rgb
-+ * Remove final vistiges of tdb references via IPSEC_KLIPS1_COMPAT.
-+ *
-+ * Revision 1.107 2002/05/23 07:16:08 rgb
-+ * Added ipsec_sa_put() for releasing an ipsec_sa refcount.
-+ * Pointer clean-up.
-+ * Added refcount code.
-+ *
-+ * Revision 1.106 2002/05/14 02:34:13 rgb
-+ * Converted reference from ipsec_sa_put to ipsec_sa_add to avoid confusion
-+ * with "put" usage in the kernel.
-+ * Change all references to tdb, TDB or Tunnel Descriptor Block to ips,
-+ * ipsec_sa or ipsec_sa.
-+ * Moved all the extension parsing functions to pfkey_v2_ext_process.c.
-+ *
-+ * Revision 1.105 2002/04/24 07:55:32 mcr
-+ * #include patches and Makefiles for post-reorg compilation.
-+ *
-+ * Revision 1.104 2002/04/24 07:36:34 mcr
-+ * Moved from ./klips/net/ipsec/pfkey_v2_parser.c,v
-+ *
-+ * Revision 1.103 2002/04/20 00:12:25 rgb
-+ * Added esp IV CBC attack fix, disabled.
-+ *
-+ * Revision 1.102 2002/03/08 01:15:17 mcr
-+ * put some internal structure only debug messages behind
-+ * && sysctl_ipsec_debug_verbose.
-+ *
-+ * Revision 1.101 2002/01/29 17:17:57 mcr
-+ * moved include of ipsec_param.h to after include of linux/kernel.h
-+ * otherwise, it seems that some option that is set in ipsec_param.h
-+ * screws up something subtle in the include path to kernel.h, and
-+ * it complains on the snprintf() prototype.
-+ *
-+ * Revision 1.100 2002/01/29 04:00:54 mcr
-+ * more excise of kversions.h header.
-+ *
-+ * Revision 1.99 2002/01/29 02:13:19 mcr
-+ * introduction of ipsec_kversion.h means that include of
-+ * ipsec_param.h must preceed any decisions about what files to
-+ * include to deal with differences in kernel source.
-+ *
-+ * Revision 1.98 2002/01/12 02:57:57 mcr
-+ * first regression test causes acquire messages to be lost
-+ * 100% of the time. This is to help testing of pluto.
-+ *
-+ * Revision 1.97 2001/11/26 09:23:52 rgb
-+ * Merge MCR's ipsec_sa, eroute, proc and struct lifetime changes.
-+ *
-+ * Revision 1.93.2.4 2001/10/23 04:20:27 mcr
-+ * parity was forced on wrong structure! prototypes help here.
-+ *
-+ * Revision 1.93.2.3 2001/10/22 21:14:59 mcr
-+ * include des.h, removed phony prototypes and fixed calling
-+ * conventions to match real prototypes.
-+ *
-+ * Revision 1.93.2.2 2001/10/15 05:39:03 mcr
-+ * %08lx is not the right format for u32. Use %08x. 64-bit safe? ha.
-+ *
-+ * Revision 1.93.2.1 2001/09/25 02:30:14 mcr
-+ * struct tdb -> struct ipsec_sa.
-+ * use new lifetime structure. common format routines for debug.
-+ *
-+ * Revision 1.96 2001/11/06 20:47:54 rgb
-+ * Fixed user context call to ipsec_dev_start_xmit() bug. Call
-+ * dev_queue_xmit() instead.
-+ *
-+ * Revision 1.95 2001/11/06 19:47:46 rgb
-+ * Added packet parameter to lifetime and comb structures.
-+ *
-+ * Revision 1.94 2001/10/18 04:45:23 rgb
-+ * 2.4.9 kernel deprecates linux/malloc.h in favour of linux/slab.h,
-+ * lib/freeswan.h version macros moved to lib/kversions.h.
-+ * Other compiler directive cleanups.
-+ *
-+ * Revision 1.93 2001/09/20 15:32:59 rgb
-+ * Min/max cleanup.
-+ *
-+ * Revision 1.92 2001/09/19 16:35:48 rgb
-+ * PF_KEY ident fix for getspi from NetCelo (puttdb duplication).
-+ *
-+ * Revision 1.91 2001/09/15 16:24:06 rgb
-+ * Re-inject first and last HOLD packet when an eroute REPLACE is done.
-+ *
-+ * Revision 1.90 2001/09/14 16:58:38 rgb
-+ * Added support for storing the first and last packets through a HOLD.
-+ *
-+ * Revision 1.89 2001/09/08 21:14:07 rgb
-+ * Added pfkey ident extension support for ISAKMPd. (NetCelo)
-+ * Better state coherency (error management) between pf_key and IKE daemon.
-+ * (NetCelo)
-+ *
-+ * Revision 1.88 2001/08/27 19:42:44 rgb
-+ * Fix memory leak of encrypt and auth structs in pfkey register.
-+ *
-+ * Revision 1.87 2001/07/06 19:50:46 rgb
-+ * Removed unused debugging code.
-+ * Added inbound policy checking code for IPIP SAs.
-+ *
-+ * Revision 1.86 2001/06/20 06:26:04 rgb
-+ * Changed missing SA errors from EEXIST to ENOENT and added debug output
-+ * for already linked SAs.
-+ *
-+ * Revision 1.85 2001/06/15 04:57:02 rgb
-+ * Remove single error return condition check and check for all errors in
-+ * the case of a replace eroute delete operation. This means that
-+ * applications must expect to be deleting something before replacing it
-+ * and if nothing is found, complain.
-+ *
-+ * Revision 1.84 2001/06/14 19:35:12 rgb
-+ * Update copyright date.
-+ *
-+ * Revision 1.83 2001/06/12 00:03:19 rgb
-+ * Silence debug set/unset under normal conditions.
-+ *
-+ * Revision 1.82 2001/05/30 08:14:04 rgb
-+ * Removed vestiges of esp-null transforms.
-+ *
-+ * Revision 1.81 2001/05/27 06:12:12 rgb
-+ * Added structures for pid, packet count and last access time to eroute.
-+ * Added packet count to beginning of /proc/net/ipsec_eroute.
-+ *
-+ * Revision 1.80 2001/05/03 19:43:59 rgb
-+ * Check error return codes for all build function calls.
-+ * Standardise on SENDERR() macro.
-+ *
-+ * Revision 1.79 2001/04/20 21:09:16 rgb
-+ * Cleaned up fixed tdbwipes.
-+ * Free pfkey_reply and clean up extensions_reply for grpsa, addflow and
-+ * delflow (Per Cederqvist) plugging memleaks.
-+ *
-+ * Revision 1.78 2001/04/19 19:02:39 rgb
-+ * Fixed extr.tdb freeing, stealing it for getspi, update and add.
-+ * Refined a couple of spinlocks, fixed the one in update.
-+ *
-+ * Revision 1.77 2001/04/18 20:26:16 rgb
-+ * Wipe/free eroute and both tdbs from extr at end of pfkey_msg_interp()
-+ * instead of inside each message type parser. This fixes two memleaks.
-+ *
-+ * Revision 1.76 2001/04/17 23:51:18 rgb
-+ * Quiet down pfkey_x_debug_process().
-+ *
-+ * Revision 1.75 2001/03/29 01:55:05 rgb
-+ * Fixed pfkey key init memleak.
-+ * Fixed pfkey encryption key debug output.
-+ *
-+ * Revision 1.74 2001/03/27 05:29:14 rgb
-+ * Debug output cleanup/silencing.
-+ *
-+ * Revision 1.73 2001/02/28 05:03:28 rgb
-+ * Clean up and rationalise startup messages.
-+ *
-+ * Revision 1.72 2001/02/27 22:24:56 rgb
-+ * Re-formatting debug output (line-splitting, joining, 1arg/line).
-+ * Check for satoa() return codes.
-+ *
-+ * Revision 1.71 2001/02/27 06:59:30 rgb
-+ * Added satype2name() conversions most places satype is debug printed.
-+ *
-+ * Revision 1.70 2001/02/26 22:37:08 rgb
-+ * Fixed 'unknown proto' INT bug in new code.
-+ * Added satype to protocol debugging instrumentation.
-+ *
-+ * Revision 1.69 2001/02/26 19:57:51 rgb
-+ * Re-formatted debug output (split lines, consistent spacing).
-+ * Fixed as yet undetected FLUSH bug which called ipsec_tdbcleanup()
-+ * with an satype instead of proto.
-+ * Checked for satype consistency and fixed minor bugs.
-+ * Fixed undetected ungrpspi bug that tried to upmsg a second tdb.
-+ * Check for satype sanity in pfkey_expire().
-+ * Added satype sanity check to addflow.
-+ *
-+ * Revision 1.68 2001/02/12 23:14:40 rgb
-+ * Remove double spin lock in pfkey_expire().
-+ *
-+ * Revision 1.67 2001/01/31 19:23:40 rgb
-+ * Fixed double-unlock bug introduced by grpsa upmsg (found by Lars Heete).
-+ *
-+ * Revision 1.66 2001/01/29 22:20:04 rgb
-+ * Fix minor add upmsg lifetime bug.
-+ *
-+ * Revision 1.65 2001/01/24 06:12:33 rgb
-+ * Fixed address extension compile bugs just introduced.
-+ *
-+ * Revision 1.64 2001/01/24 00:31:15 rgb
-+ * Added upmsg for addflow/delflow.
-+ *
-+ * Revision 1.63 2001/01/23 22:02:55 rgb
-+ * Added upmsg to x_grpsa.
-+ * Fixed lifetimes extentions to add/update/get upmsg.
-+ *
-+ * Revision 1.62 2000/11/30 21:47:51 rgb
-+ * Fix error return bug after returning from pfkey_tdb_init().
-+ *
-+ * Revision 1.61 2000/11/17 18:10:29 rgb
-+ * Fixed bugs mostly relating to spirange, to treat all spi variables as
-+ * network byte order since this is the way PF_KEYv2 stored spis.
-+ *
-+ * Revision 1.60 2000/11/06 04:34:53 rgb
-+ * Changed non-exported functions to DEBUG_NO_STATIC.
-+ * Add Svenning's adaptive content compression.
-+ * Ditched spin_lock_irqsave in favour of spin_lock/_bh.
-+ * Fixed double unlock bug (Svenning).
-+ * Fixed pfkey_msg uninitialized bug in pfkey_{expire,acquire}().
-+ * Fixed incorrect extension type (prop) in pfkey)acquire().
-+ *
-+ * Revision 1.59 2000/10/11 15:25:12 rgb
-+ * Fixed IPCOMP disabled compile bug.
-+ *
-+ * Revision 1.58 2000/10/11 14:54:03 rgb
-+ * Fixed pfkey_acquire() satype to SADB_SATYPE_ESP and removed pfkey
-+ * protocol violations of setting pfkey_address_build() protocol parameter
-+ * to non-zero except in the case of pfkey_acquire().
-+ *
-+ * Revision 1.57 2000/10/10 20:10:18 rgb
-+ * Added support for debug_ipcomp and debug_verbose to klipsdebug.
-+ *
-+ * Revision 1.56 2000/10/06 20:24:36 rgb
-+ * Fixes to pfkey_acquire to initialize extensions[] and use correct
-+ * ipproto.
-+ *
-+ * Revision 1.55 2000/10/03 03:20:57 rgb
-+ * Added brackets to get a?b:c scope right for pfkey_register reply.
-+ *
-+ * Revision 1.54 2000/09/29 19:49:30 rgb
-+ * As-yet-unused-bits cleanup.
-+ *
-+ * Revision 1.53 2000/09/28 00:35:45 rgb
-+ * Padded SATYPE printout in pfkey_register for vertical alignment.
-+ *
-+ * Revision 1.52 2000/09/20 16:21:58 rgb
-+ * Cleaned up ident string alloc/free.
-+ *
-+ * Revision 1.51 2000/09/20 04:04:20 rgb
-+ * Changed static functions to DEBUG_NO_STATIC to reveal function names in
-+ * oopsen.
-+ *
-+ * Revision 1.50 2000/09/16 01:10:53 rgb
-+ * Fixed unused var warning with debug off.
-+ *
-+ * Revision 1.49 2000/09/15 11:37:02 rgb
-+ * Merge in heavily modified Svenning Soerensen's <svenning@post5.tele.dk>
-+ * IPCOMP zlib deflate code.
-+ *
-+ * Revision 1.48 2000/09/15 04:57:57 rgb
-+ * Cleaned up existing IPCOMP code before svenning addition.
-+ * Initialize pfkey_reply and extensions_reply in case of early error in
-+ * message parsing functions (thanks Kai!).
-+ *
-+ * Revision 1.47 2000/09/13 08:02:56 rgb
-+ * Added KMd registration notification.
-+ *
-+ * Revision 1.46 2000/09/12 22:35:36 rgb
-+ * Restructured to remove unused extensions from CLEARFLOW messages.
-+ *
-+ * Revision 1.45 2000/09/12 03:24:23 rgb
-+ * Converted #if0 debugs to sysctl.
-+ *
-+ * Revision 1.44 2000/09/09 06:38:39 rgb
-+ * Correct SADB message type for update, add and delete.
-+ *
-+ * Revision 1.43 2000/09/08 19:19:56 rgb
-+ * Change references from DEBUG_IPSEC to CONFIG_IPSEC_DEBUG.
-+ * Removed all references to CONFIG_IPSEC_PFKEYv2.
-+ * Put in sanity checks in most msg type parsers to catch invalid satypes
-+ * and empty socket lists.
-+ * Moved spin-locks in pfkey_get_parse() to simplify.
-+ * Added pfkey_acquire().
-+ * Added upwards messages to update, add, delete, acquire_parse,
-+ * expire_parse and flush.
-+ * Fix pfkey_prop_build() parameter to be only single indirection.
-+ * Changed all replies to use pfkey_reply.
-+ * Check return code on puttdb() and deltdbchain() in getspi, update,
-+ * add, delete.
-+ * Fixed up all pfkey replies to open and registered sockets.
-+ *
-+ * Revision 1.42 2000/09/01 18:50:26 rgb
-+ * Added a supported algorithms array lists, one per satype and registered
-+ * existing algorithms.
-+ * Fixed pfkey_list_{insert,remove}_{socket,support}() to allow change to
-+ * list.
-+ * Only send pfkey_expire() messages to sockets registered for that satype.
-+ * Added reply to pfkey_getspi_parse().
-+ * Added reply to pfkey_get_parse().
-+ * Fixed debug output label bug in pfkey_lifetime_process().
-+ * Cleaned up pfkey_sa_process a little.
-+ * Moved pfkey_safe_build() above message type parsers to make it available
-+ * for creating replies.
-+ * Added comments for future work in pfkey_acquire_parse().
-+ * Fleshed out guts of pfkey_register_parse().
-+ *
-+ * Revision 1.41 2000/08/24 16:58:11 rgb
-+ * Fixed key debugging variables.
-+ * Fixed error return code for a failed search.
-+ * Changed order of pfkey_get operations.
-+ *
-+ * Revision 1.40 2000/08/21 16:32:27 rgb
-+ * Re-formatted for cosmetic consistency and readability.
-+ *
-+ * Revision 1.39 2000/08/20 21:38:57 rgb
-+ * Bugfixes to as-yet-unused pfkey_update_parse() and
-+ * pfkey_register_parse(). (Momchil)
-+ * Added functions pfkey_safe_build(), pfkey_expire() and
-+ * pfkey_build_reply(). (Momchil)
-+ * Added a pfkey_reply parameter to pfkey_msg_interp(). (Momchil)
-+ *
-+ * Revision 1.38 2000/08/18 21:30:41 rgb
-+ * Purged all tdb_spi, tdb_proto and tdb_dst macros. They are unclear.
-+ *
-+ * Revision 1.37 2000/08/18 18:18:02 rgb
-+ * Cosmetic and descriptive changes made to debug test.
-+ * getspi and update fixes from Momchil.
-+ *
-+ * Revision 1.36 2000/08/15 15:41:55 rgb
-+ * Fixed the (as yet unused and untested) pfkey_getspi() routine.
-+ *
-+ * Revision 1.35 2000/08/01 14:51:52 rgb
-+ * Removed _all_ remaining traces of DES.
-+ *
-+ * Revision 1.34 2000/07/28 14:58:32 rgb
-+ * Changed kfree_s to kfree, eliminating extra arg to fix 2.4.0-test5.
-+ *
-+ * Revision 1.33 2000/06/28 05:50:11 rgb
-+ * Actually set iv_bits.
-+ *
-+ * Revision 1.32 2000/05/30 18:36:56 rgb
-+ * Fix AH auth hash setup bug. This breaks interop with previous PF_KEY
-+ * FreeS/WAN, but fixes interop with other implementations.
-+ *
-+ * Revision 1.31 2000/03/16 14:05:48 rgb
-+ * Fixed brace scope preventing non-debug compile.
-+ * Added null parameter check for pfkey_x_debug().
-+ *
-+ * Revision 1.30 2000/01/22 23:21:13 rgb
-+ * Use new function satype2proto().
-+ *
-+ * Revision 1.29 2000/01/22 08:40:21 rgb
-+ * Invert condition to known value to avoid AF_INET6 in 2.0.36.
-+ *
-+ * Revision 1.28 2000/01/22 07:58:57 rgb
-+ * Fixed REPLACEFLOW bug, missing braces around KLIPS_PRINT *and* SENDERR.
-+ *
-+ * Revision 1.27 2000/01/22 03:48:01 rgb
-+ * Added extr pointer component debugging.
-+ *
-+ * Revision 1.26 2000/01/21 09:41:25 rgb
-+ * Changed a (void*) to (char*) cast to do proper pointer math.
-+ * Don't call tdbwipe if tdb2 is NULL.
-+ *
-+ * Revision 1.25 2000/01/21 06:21:01 rgb
-+ * Added address cases for eroute flows.
-+ * Tidied up compiler directive indentation for readability.
-+ * Added ictx,octx vars for simplification.
-+ * Added macros for HMAC padding magic numbers.
-+ * Converted from double tdb arguments to one structure (extr)
-+ * containing pointers to all temporary information structures
-+ * and checking for valid arguments to all ext processors and
-+ * msg type parsers.
-+ * Added spiungrp'ing.
-+ * Added klipsdebug switching capability.
-+ * Removed sa_process() check for zero protocol.
-+ * Added address case for DST2 for grouping.
-+ * Added/changed minor debugging instrumentation.
-+ * Fixed spigrp for single said, ungrouping case.
-+ * Added code to parse addflow and delflow messages.
-+ * Removed redundant statements duplicating tdbwipe() functionality
-+ * and causing double kfrees.
-+ * Permit addflow to have a protocol of 0.
-+ *
-+ * Revision 1.24 1999/12/09 23:23:00 rgb
-+ * Added check to pfkey_sa_process() to do eroutes.
-+ * Converted to DIVUP() macro.
-+ * Converted if() to switch() in pfkey_register_parse().
-+ * Use new pfkey_extensions_init() instead of memset().
-+ *
-+ * Revision 1.23 1999/12/01 22:18:13 rgb
-+ * Preset minspi and maxspi values in case and spirange extension is not
-+ * included and check for the presence of an spirange extension before
-+ * using it. Initialise tdb_sastate to LARVAL.
-+ * Fixed debugging output typo.
-+ * Fixed authentication context initialisation bugs (4 places).
-+ *
-+ * Revision 1.22 1999/11/27 11:53:08 rgb
-+ * Moved pfkey_msg_parse prototype to pfkey.h
-+ * Moved exts_permitted/required prototype to pfkey.h.
-+ * Moved sadb_satype2proto protocol lookup table to lib/pfkey_v2_parse.c.
-+ * Deleted SADB_X_EXT_SA2 code from pfkey_sa_process() since it will never
-+ * be called.
-+ * Moved protocol/algorithm checks to lib/pfkey_v2_parse.c
-+ * Debugging error messages added.
-+ * Enable lifetime_current checking.
-+ * Remove illegal requirement for SA extension to be present in an
-+ * originating GETSPI call.
-+ * Re-instate requirement for UPDATE or ADD message to be MATURE.
-+ * Add argument to pfkey_msg_parse() for direction.
-+ * Fixed IPIP dst address bug and purged redundant, leaky code.
-+ *
-+ * Revision 1.21 1999/11/24 05:24:20 rgb
-+ * hanged 'void*extensions' to 'struct sadb_ext*extensions'.
-+ * Fixed indention.
-+ * Ditched redundant replay check.
-+ * Fixed debug message text from 'parse' to 'process'.
-+ * Added more debug output.
-+ * Forgot to zero extensions array causing bug, fixed.
-+ *
-+ * Revision 1.20 1999/11/23 23:08:13 rgb
-+ * Move all common parsing code to lib/pfkey_v2_parse.c and rename
-+ * remaining bits to *_process. (PJO)
-+ * Add macros for dealing with alignment and rounding up more opaquely.
-+ * Use provided macro ADDRTOA_BUF instead of hardcoded value.
-+ * Sort out pfkey and freeswan headers, putting them in a library path.
-+ * Corrected a couple of bugs in as-yet-inactive code.
-+ *
-+ * Revision 1.19 1999/11/20 22:01:10 rgb
-+ * Add more descriptive error messages for non-zero reserved fields.
-+ * Add more descriptive error message for spirange parsing.
-+ * Start on supported extension parsing.
-+ * Start on register and get message parsing.
-+ *
-+ * Revision 1.18 1999/11/18 04:09:20 rgb
-+ * Replaced all kernel version macros to shorter, readable form.
-+ *
-+ * Revision 1.17 1999/11/17 15:53:41 rgb
-+ * Changed all occurrences of #include "../../../lib/freeswan.h"
-+ * to #include <freeswan.h> which works due to -Ilibfreeswan in the
-+ * klips/net/ipsec/Makefile.
-+ *
-+ * Revision 1.16 1999/10/26 16:57:43 rgb
-+ * Add shorter macros for compiler directives to visually clean-up.
-+ * Give ipv6 code meaningful compiler directive.
-+ * Add comments to other #if 0 debug code.
-+ * Remove unused *_bh_atomic() calls.
-+ * Fix mis-placed spinlock.
-+ *
-+ * Revision 1.15 1999/10/16 18:27:10 rgb
-+ * Clean-up unused cruft.
-+ * Fix-up lifetime_allocations_c and lifetime_addtime_c initialisations.
-+ *
-+ * Revision 1.14 1999/10/08 18:37:34 rgb
-+ * Fix end-of-line spacing to sate whining PHMs.
-+ *
-+ * Revision 1.13 1999/10/03 18:49:12 rgb
-+ * Spinlock fixes for 2.0.xx and 2.3.xx.
-+ *
-+ * Revision 1.12 1999/10/01 15:44:54 rgb
-+ * Move spinlock header include to 2.1> scope.
-+ *
-+ * Revision 1.11 1999/10/01 00:05:45 rgb
-+ * Added tdb structure locking.
-+ * Use 'jiffies' instead of do_get_timeofday().
-+ * Fix lifetime assignments.
-+ *
-+ * Revision 1.10 1999/09/21 15:24:45 rgb
-+ * Rework spirange code to save entropy and prevent endless loops.
-+ *
-+ * Revision 1.9 1999/09/16 12:10:21 rgb
-+ * Minor fixes to random spi selection for correctness and entropy conservation.
-+ *
-+ * Revision 1.8 1999/05/25 22:54:46 rgb
-+ * Fix comparison that should be an assignment in an if.
-+ *
-+ * Revision 1.7 1999/05/09 03:25:37 rgb
-+ * Fix bug introduced by 2.2 quick-and-dirty patch.
-+ *
-+ * Revision 1.6 1999/05/08 21:32:30 rgb
-+ * Fix error return reporting.
-+ *
-+ * Revision 1.5 1999/05/05 22:02:33 rgb
-+ * Add a quick and dirty port to 2.2 kernels by Marc Boucher <marc@mbsi.ca>.
-+ *
-+ * Revision 1.4 1999/04/29 15:22:40 rgb
-+ * Standardise an error return method.
-+ * Add debugging instrumentation.
-+ * Add check for existence of macros min/max.
-+ * Add extensions permitted/required in/out filters.
-+ * Add satype-to-protocol table.
-+ * Add a second tdb pointer to each parser to accomodate GRPSA.
-+ * Move AH & no_algo_set to GETSPI, UPDATE and ADD.
-+ * Add OOO window check.
-+ * Add support for IPPROTO_IPIP and hooks for IPPROTO_COMP.
-+ * Add timestamp to lifetime parse.
-+ * Fix address structure length checking bug.
-+ * Fix address structure allocation bug (forgot to kmalloc!).
-+ * Add checks for extension lengths.
-+ * Add checks for extension reserved illegal values.
-+ * Add check for spirange legal values.
-+ * Add an extension type for parsing a second satype, SA and
-+ * DST_ADDRESS.
-+ * Make changes to tdb_init() template to get pfkey_tdb_init(),
-+ * eliminating any mention of xformsw.
-+ * Implement getspi, update and grpsa (not tested).
-+ * Add stubs for as yet unimplemented message types.
-+ * Add table of message parsers to substitute for msg_parse switch.
-+ *
-+ * Revision 1.3 1999/04/15 17:58:07 rgb
-+ * Add RCSID labels.
-+ *
-+ * Revision 1.2 1999/04/15 15:37:26 rgb
-+ * Forward check changes from POST1_00 branch.
-+ *
-+ * Revision 1.1.2.1 1999/03/26 20:58:56 rgb
-+ * Add pfkeyv2 support to KLIPS.
-+ *
-+ * Local variables:
-+ * c-file-style: "linux"
-+ * End:
-+ *
-+ */
---- /dev/null Tue Mar 11 13:02:56 2003
-+++ linux/net/ipsec/radij.c Mon Feb 9 13:51:03 2004
-@@ -0,0 +1,1225 @@
-+char radij_c_version[] = "RCSID $Id: radij.c,v 1.46 2004/04/06 02:49:26 mcr Exp $";
-+
-+/*
-+ * This file is defived from ${SRC}/sys/net/radix.c of BSD 4.4lite
-+ *
-+ * Variable and procedure names have been modified so that they don't
-+ * conflict with the original BSD code, as a small number of modifications
-+ * have been introduced and we may want to reuse this code in BSD.
-+ *
-+ * The `j' in `radij' is pronounced as a voiceless guttural (like a Greek
-+ * chi or a German ch sound (as `doch', not as in `milch'), or even a
-+ * spanish j as in Juan. It is not as far back in the throat like
-+ * the corresponding Hebrew sound, nor is it a soft breath like the English h.
-+ * It has nothing to do with the Dutch ij sound.
-+ *
-+ * Here is the appropriate copyright notice:
-+ */
-+
-+/*
-+ * Copyright (c) 1988, 1989, 1993
-+ * The Regents of the University of California. All rights reserved.
-+ *
-+ * Redistribution and use in source and binary forms, with or without
-+ * modification, are permitted provided that the following conditions
-+ * are met:
-+ * 1. Redistributions of source code must retain the above copyright
-+ * notice, this list of conditions and the following disclaimer.
-+ * 2. Redistributions in binary form must reproduce the above copyright
-+ * notice, this list of conditions and the following disclaimer in the
-+ * documentation and/or other materials provided with the distribution.
-+ * 3. All advertising materials mentioning features or use of this software
-+ * must display the following acknowledgement:
-+ * This product includes software developed by the University of
-+ * California, Berkeley and its contributors.
-+ * 4. Neither the name of the University nor the names of its contributors
-+ * may be used to endorse or promote products derived from this software
-+ * without specific prior written permission.
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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.
-+ *
-+ * @(#)radix.c 8.2 (Berkeley) 1/4/94
-+ */
-+
-+/*
-+ * Routines to build and maintain radix trees for routing lookups.
-+ */
-+
-+#include <linux/config.h>
-+#include <linux/version.h>
-+#include <linux/kernel.h> /* printk() */
-+
-+#include "openswan/ipsec_param.h"
-+
-+#ifdef MALLOC_SLAB
-+# include <linux/slab.h> /* kmalloc() */
-+#else /* MALLOC_SLAB */
-+# include <linux/malloc.h> /* kmalloc() */
-+#endif /* MALLOC_SLAB */
-+#include <linux/errno.h> /* error codes */
-+#include <linux/types.h> /* size_t */
-+#include <linux/interrupt.h> /* mark_bh */
-+
-+#include <linux/netdevice.h> /* struct device, and other headers */
-+#include <linux/etherdevice.h> /* eth_type_trans */
-+#include <linux/ip.h> /* struct iphdr */
-+#include <linux/skbuff.h>
-+#ifdef NET_21
-+# include <asm/uaccess.h>
-+# include <linux/in6.h>
-+#endif /* NET_21 */
-+#include <asm/checksum.h>
-+#include <net/ip.h>
-+
-+#include <openswan.h>
-+
-+#include "openswan/radij.h"
-+#include "openswan/ipsec_encap.h"
-+#include "openswan/ipsec_radij.h"
-+
-+int maj_keylen;
-+struct radij_mask *rj_mkfreelist;
-+struct radij_node_head *mask_rjhead;
-+static int gotOddMasks;
-+static char *maskedKey;
-+static char *rj_zeroes, *rj_ones;
-+
-+#define rj_masktop (mask_rjhead->rnh_treetop)
-+#ifdef Bcmp
-+# undef Bcmp
-+#endif /* Bcmp */
-+#define Bcmp(a, b, l) (l == 0 ? 0 : memcmp((caddr_t)(b), (caddr_t)(a), (size_t)l))
-+/*
-+ * The data structure for the keys is a radix tree with one way
-+ * branching removed. The index rj_b at an internal node n represents a bit
-+ * position to be tested. The tree is arranged so that all descendants
-+ * of a node n have keys whose bits all agree up to position rj_b - 1.
-+ * (We say the index of n is rj_b.)
-+ *
-+ * There is at least one descendant which has a one bit at position rj_b,
-+ * and at least one with a zero there.
-+ *
-+ * A route is determined by a pair of key and mask. We require that the
-+ * bit-wise logical and of the key and mask to be the key.
-+ * We define the index of a route to associated with the mask to be
-+ * the first bit number in the mask where 0 occurs (with bit number 0
-+ * representing the highest order bit).
-+ *
-+ * We say a mask is normal if every bit is 0, past the index of the mask.
-+ * If a node n has a descendant (k, m) with index(m) == index(n) == rj_b,
-+ * and m is a normal mask, then the route applies to every descendant of n.
-+ * If the index(m) < rj_b, this implies the trailing last few bits of k
-+ * before bit b are all 0, (and hence consequently true of every descendant
-+ * of n), so the route applies to all descendants of the node as well.
-+ *
-+ * The present version of the code makes no use of normal routes,
-+ * but similar logic shows that a non-normal mask m such that
-+ * index(m) <= index(n) could potentially apply to many children of n.
-+ * Thus, for each non-host route, we attach its mask to a list at an internal
-+ * node as high in the tree as we can go.
-+ */
-+
-+struct radij_node *
-+rj_search(v_arg, head)
-+ void *v_arg;
-+ struct radij_node *head;
-+{
-+ register struct radij_node *x;
-+ register caddr_t v;
-+
-+ for (x = head, v = v_arg; x->rj_b >= 0;) {
-+ if (x->rj_bmask & v[x->rj_off])
-+ x = x->rj_r;
-+ else
-+ x = x->rj_l;
-+ }
-+ return (x);
-+};
-+
-+struct radij_node *
-+rj_search_m(v_arg, head, m_arg)
-+ struct radij_node *head;
-+ void *v_arg, *m_arg;
-+{
-+ register struct radij_node *x;
-+ register caddr_t v = v_arg, m = m_arg;
-+
-+ for (x = head; x->rj_b >= 0;) {
-+ if ((x->rj_bmask & m[x->rj_off]) &&
-+ (x->rj_bmask & v[x->rj_off]))
-+ x = x->rj_r;
-+ else
-+ x = x->rj_l;
-+ }
-+ return x;
-+};
-+
-+int
-+rj_refines(m_arg, n_arg)
-+ void *m_arg, *n_arg;
-+{
-+ register caddr_t m = m_arg, n = n_arg;
-+ register caddr_t lim, lim2 = lim = n + *(u_char *)n;
-+ int longer = (*(u_char *)n++) - (int)(*(u_char *)m++);
-+ int masks_are_equal = 1;
-+
-+ if (longer > 0)
-+ lim -= longer;
-+ while (n < lim) {
-+ if (*n & ~(*m))
-+ return 0;
-+ if (*n++ != *m++)
-+ masks_are_equal = 0;
-+
-+ }
-+ while (n < lim2)
-+ if (*n++)
-+ return 0;
-+ if (masks_are_equal && (longer < 0))
-+ for (lim2 = m - longer; m < lim2; )
-+ if (*m++)
-+ return 1;
-+ return (!masks_are_equal);
-+}
-+
-+
-+struct radij_node *
-+rj_match(v_arg, head)
-+ void *v_arg;
-+ struct radij_node_head *head;
-+{
-+ caddr_t v = v_arg;
-+ register struct radij_node *t = head->rnh_treetop, *x;
-+ register caddr_t cp = v, cp2, cp3;
-+ caddr_t cplim, mstart;
-+ struct radij_node *saved_t, *top = t;
-+ int off = t->rj_off, vlen = *(u_char *)cp, matched_off;
-+
-+ /*
-+ * Open code rj_search(v, top) to avoid overhead of extra
-+ * subroutine call.
-+ */
-+ for (; t->rj_b >= 0; ) {
-+ if (t->rj_bmask & cp[t->rj_off])
-+ t = t->rj_r;
-+ else
-+ t = t->rj_l;
-+ }
-+ /*
-+ * See if we match exactly as a host destination
-+ */
-+ KLIPS_PRINT(debug_radij,
-+ "klips_debug:rj_match: "
-+ "* See if we match exactly as a host destination\n");
-+
-+ cp += off; cp2 = t->rj_key + off; cplim = v + vlen;
-+ for (; cp < cplim; cp++, cp2++)
-+ if (*cp != *cp2)
-+ goto on1;
-+ /*
-+ * This extra grot is in case we are explicitly asked
-+ * to look up the default. Ugh!
-+ */
-+ if ((t->rj_flags & RJF_ROOT) && t->rj_dupedkey)
-+ t = t->rj_dupedkey;
-+ return t;
-+on1:
-+ matched_off = cp - v;
-+ saved_t = t;
-+ KLIPS_PRINT(debug_radij,
-+ "klips_debug:rj_match: "
-+ "** try to match a leaf, t=0p%p\n", t);
-+ do {
-+ if (t->rj_mask) {
-+ /*
-+ * Even if we don't match exactly as a hosts;
-+ * we may match if the leaf we wound up at is
-+ * a route to a net.
-+ */
-+ cp3 = matched_off + t->rj_mask;
-+ cp2 = matched_off + t->rj_key;
-+ for (; cp < cplim; cp++)
-+ if ((*cp2++ ^ *cp) & *cp3++)
-+ break;
-+ if (cp == cplim)
-+ return t;
-+ cp = matched_off + v;
-+ }
-+ } while ((t = t->rj_dupedkey));
-+ t = saved_t;
-+ /* start searching up the tree */
-+ KLIPS_PRINT(debug_radij,
-+ "klips_debug:rj_match: "
-+ "*** start searching up the tree, t=0p%p\n",
-+ t);
-+ do {
-+ register struct radij_mask *m;
-+
-+ t = t->rj_p;
-+ KLIPS_PRINT(debug_radij,
-+ "klips_debug:rj_match: "
-+ "**** t=0p%p\n",
-+ t);
-+ if ((m = t->rj_mklist)) {
-+ /*
-+ * After doing measurements here, it may
-+ * turn out to be faster to open code
-+ * rj_search_m here instead of always
-+ * copying and masking.
-+ */
-+ /* off = min(t->rj_off, matched_off); */
-+ off = t->rj_off;
-+ if (matched_off < off)
-+ off = matched_off;
-+ mstart = maskedKey + off;
-+ do {
-+ cp2 = mstart;
-+ cp3 = m->rm_mask + off;
-+ KLIPS_PRINT(debug_radij,
-+ "klips_debug:rj_match: "
-+ "***** cp2=0p%p cp3=0p%p\n",
-+ cp2, cp3);
-+ for (cp = v + off; cp < cplim;)
-+ *cp2++ = *cp++ & *cp3++;
-+ x = rj_search(maskedKey, t);
-+ while (x && x->rj_mask != m->rm_mask)
-+ x = x->rj_dupedkey;
-+ if (x &&
-+ (Bcmp(mstart, x->rj_key + off,
-+ vlen - off) == 0))
-+ return x;
-+ } while ((m = m->rm_mklist));
-+ }
-+ } while (t != top);
-+ KLIPS_PRINT(debug_radij,
-+ "klips_debug:rj_match: "
-+ "***** not found.\n");
-+ return 0;
-+};
-+
-+#ifdef RJ_DEBUG
-+int rj_nodenum;
-+struct radij_node *rj_clist;
-+int rj_saveinfo;
-+DEBUG_NO_STATIC void traverse(struct radij_node *);
-+#ifdef RJ_DEBUG2
-+int rj_debug = 1;
-+#else
-+int rj_debug = 0;
-+#endif /* RJ_DEBUG2 */
-+#endif /* RJ_DEBUG */
-+
-+struct radij_node *
-+rj_newpair(v, b, nodes)
-+ void *v;
-+ int b;
-+ struct radij_node nodes[2];
-+{
-+ register struct radij_node *tt = nodes, *t = tt + 1;
-+ t->rj_b = b; t->rj_bmask = 0x80 >> (b & 7);
-+ t->rj_l = tt; t->rj_off = b >> 3;
-+ tt->rj_b = -1; tt->rj_key = (caddr_t)v; tt->rj_p = t;
-+ tt->rj_flags = t->rj_flags = RJF_ACTIVE;
-+#ifdef RJ_DEBUG
-+ tt->rj_info = rj_nodenum++; t->rj_info = rj_nodenum++;
-+ tt->rj_twin = t; tt->rj_ybro = rj_clist; rj_clist = tt;
-+#endif /* RJ_DEBUG */
-+ return t;
-+}
-+
-+struct radij_node *
-+rj_insert(v_arg, head, dupentry, nodes)
-+ void *v_arg;
-+ struct radij_node_head *head;
-+ int *dupentry;
-+ struct radij_node nodes[2];
-+{
-+ caddr_t v = v_arg;
-+ struct radij_node *top = head->rnh_treetop;
-+ int head_off = top->rj_off, vlen = (int)*((u_char *)v);
-+ register struct radij_node *t = rj_search(v_arg, top);
-+ register caddr_t cp = v + head_off;
-+ register int b;
-+ struct radij_node *tt;
-+ /*
-+ *find first bit at which v and t->rj_key differ
-+ */
-+ {
-+ register caddr_t cp2 = t->rj_key + head_off;
-+ register int cmp_res;
-+ caddr_t cplim = v + vlen;
-+
-+ while (cp < cplim)
-+ if (*cp2++ != *cp++)
-+ goto on1;
-+ *dupentry = 1;
-+ return t;
-+on1:
-+ *dupentry = 0;
-+ cmp_res = (cp[-1] ^ cp2[-1]) & 0xff;
-+ for (b = (cp - v) << 3; cmp_res; b--)
-+ cmp_res >>= 1;
-+ }
-+ {
-+ register struct radij_node *p, *x = top;
-+ cp = v;
-+ do {
-+ p = x;
-+ if (cp[x->rj_off] & x->rj_bmask)
-+ x = x->rj_r;
-+ else x = x->rj_l;
-+ } while (b > (unsigned) x->rj_b); /* x->rj_b < b && x->rj_b >= 0 */
-+#ifdef RJ_DEBUG
-+ if (rj_debug)
-+ printk("klips_debug:rj_insert: Going In:\n"), traverse(p);
-+#endif /* RJ_DEBUG */
-+ t = rj_newpair(v_arg, b, nodes); tt = t->rj_l;
-+ if ((cp[p->rj_off] & p->rj_bmask) == 0)
-+ p->rj_l = t;
-+ else
-+ p->rj_r = t;
-+ x->rj_p = t; t->rj_p = p; /* frees x, p as temp vars below */
-+ if ((cp[t->rj_off] & t->rj_bmask) == 0) {
-+ t->rj_r = x;
-+ } else {
-+ t->rj_r = tt; t->rj_l = x;
-+ }
-+#ifdef RJ_DEBUG
-+ if (rj_debug)
-+ printk("klips_debug:rj_insert: Coming out:\n"), traverse(p);
-+#endif /* RJ_DEBUG */
-+ }
-+ return (tt);
-+}
-+
-+struct radij_node *
-+rj_addmask(n_arg, search, skip)
-+ int search, skip;
-+ void *n_arg;
-+{
-+ caddr_t netmask = (caddr_t)n_arg;
-+ register struct radij_node *x;
-+ register caddr_t cp, cplim;
-+ register int b, mlen, j;
-+ int maskduplicated;
-+
-+ mlen = *(u_char *)netmask;
-+ if (search) {
-+ x = rj_search(netmask, rj_masktop);
-+ mlen = *(u_char *)netmask;
-+ if (Bcmp(netmask, x->rj_key, mlen) == 0)
-+ return (x);
-+ }
-+ R_Malloc(x, struct radij_node *, maj_keylen + 2 * sizeof (*x));
-+ if (x == 0)
-+ return (0);
-+ Bzero(x, maj_keylen + 2 * sizeof (*x));
-+ cp = (caddr_t)(x + 2);
-+ Bcopy(netmask, cp, mlen);
-+ netmask = cp;
-+ x = rj_insert(netmask, mask_rjhead, &maskduplicated, x);
-+ /*
-+ * Calculate index of mask.
-+ */
-+ cplim = netmask + mlen;
-+ for (cp = netmask + skip; cp < cplim; cp++)
-+ if (*(u_char *)cp != 0xff)
-+ break;
-+ b = (cp - netmask) << 3;
-+ if (cp != cplim) {
-+ if (*cp != 0) {
-+ gotOddMasks = 1;
-+ for (j = 0x80; j; b++, j >>= 1)
-+ if ((j & *cp) == 0)
-+ break;
-+ }
-+ }
-+ x->rj_b = -1 - b;
-+ return (x);
-+}
-+
-+#if 0
-+struct radij_node *
-+#endif
-+int
-+rj_addroute(v_arg, n_arg, head, treenodes)
-+ void *v_arg, *n_arg;
-+ struct radij_node_head *head;
-+ struct radij_node treenodes[2];
-+{
-+ caddr_t v = (caddr_t)v_arg, netmask = (caddr_t)n_arg;
-+ register struct radij_node *t, *x=NULL, *tt;
-+ struct radij_node *saved_tt, *top = head->rnh_treetop;
-+ short b = 0, b_leaf;
-+ int mlen, keyduplicated;
-+ caddr_t cplim;
-+ struct radij_mask *m, **mp;
-+
-+ /*
-+ * In dealing with non-contiguous masks, there may be
-+ * many different routes which have the same mask.
-+ * We will find it useful to have a unique pointer to
-+ * the mask to speed avoiding duplicate references at
-+ * nodes and possibly save time in calculating indices.
-+ */
-+ if (netmask) {
-+ x = rj_search(netmask, rj_masktop);
-+ mlen = *(u_char *)netmask;
-+ if (Bcmp(netmask, x->rj_key, mlen) != 0) {
-+ x = rj_addmask(netmask, 0, top->rj_off);
-+ if (x == 0)
-+ return -ENOMEM; /* (0) rgb */
-+ }
-+ netmask = x->rj_key;
-+ b = -1 - x->rj_b;
-+ }
-+ /*
-+ * Deal with duplicated keys: attach node to previous instance
-+ */
-+ saved_tt = tt = rj_insert(v, head, &keyduplicated, treenodes);
-+#ifdef RJ_DEBUG
-+ printk("addkey: duplicated: %d\n", keyduplicated);
-+#endif
-+ if (keyduplicated) {
-+ do {
-+ if (tt->rj_mask == netmask)
-+ return -EEXIST; /* -ENXIO; (0) rgb */
-+ t = tt;
-+ if (netmask == 0 ||
-+ (tt->rj_mask && rj_refines(netmask, tt->rj_mask)))
-+ break;
-+ } while ((tt = tt->rj_dupedkey));
-+ /*
-+ * If the mask is not duplicated, we wouldn't
-+ * find it among possible duplicate key entries
-+ * anyway, so the above test doesn't hurt.
-+ *
-+ * We sort the masks for a duplicated key the same way as
-+ * in a masklist -- most specific to least specific.
-+ * This may require the unfortunate nuisance of relocating
-+ * the head of the list.
-+ */
-+ if (tt && t == saved_tt) {
-+ struct radij_node *xx = x;
-+ /* link in at head of list */
-+ (tt = treenodes)->rj_dupedkey = t;
-+ tt->rj_flags = t->rj_flags;
-+ tt->rj_p = x = t->rj_p;
-+ if (x->rj_l == t) x->rj_l = tt; else x->rj_r = tt;
-+ saved_tt = tt; x = xx;
-+ } else {
-+ (tt = treenodes)->rj_dupedkey = t->rj_dupedkey;
-+ t->rj_dupedkey = tt;
-+ }
-+#ifdef RJ_DEBUG
-+ t=tt+1; tt->rj_info = rj_nodenum++; t->rj_info = rj_nodenum++;
-+ tt->rj_twin = t; tt->rj_ybro = rj_clist; rj_clist = tt;
-+#endif /* RJ_DEBUG */
-+ t = saved_tt;
-+ tt->rj_key = (caddr_t) v;
-+ tt->rj_b = -1;
-+ tt->rj_flags = t->rj_flags & ~RJF_ROOT;
-+ }
-+ /*
-+ * Put mask in tree.
-+ */
-+ if (netmask) {
-+ tt->rj_mask = netmask;
-+ tt->rj_b = x->rj_b;
-+ }
-+ t = saved_tt->rj_p;
-+ b_leaf = -1 - t->rj_b;
-+ if (t->rj_r == saved_tt) x = t->rj_l; else x = t->rj_r;
-+ /* Promote general routes from below */
-+ if (x->rj_b < 0) {
-+ if (x->rj_mask && (x->rj_b >= b_leaf) && x->rj_mklist == 0) {
-+ MKGet(m);
-+ if (m) {
-+ Bzero(m, sizeof *m);
-+ m->rm_b = x->rj_b;
-+ m->rm_mask = x->rj_mask;
-+ x->rj_mklist = t->rj_mklist = m;
-+ }
-+ }
-+ } else if (x->rj_mklist) {
-+ /*
-+ * Skip over masks whose index is > that of new node
-+ */
-+ for (mp = &x->rj_mklist; (m = *mp); mp = &m->rm_mklist)
-+ if (m->rm_b >= b_leaf)
-+ break;
-+ t->rj_mklist = m; *mp = 0;
-+ }
-+ /* Add new route to highest possible ancestor's list */
-+ if ((netmask == 0) || (b > t->rj_b )) {
-+#ifdef RJ_DEBUG
-+ printk("klips:radij.c: netmask = %p or b(%d)>t->rjb(%d)\n", netmask, b, t->rj_b);
-+#endif
-+ return 0; /* tt rgb */ /* can't lift at all */
-+ }
-+ b_leaf = tt->rj_b;
-+ do {
-+ x = t;
-+ t = t->rj_p;
-+ } while (b <= t->rj_b && x != top);
-+ /*
-+ * Search through routes associated with node to
-+ * insert new route according to index.
-+ * For nodes of equal index, place more specific
-+ * masks first.
-+ */
-+ cplim = netmask + mlen;
-+ for (mp = &x->rj_mklist; (m = *mp); mp = &m->rm_mklist) {
-+ if (m->rm_b < b_leaf)
-+ continue;
-+ if (m->rm_b > b_leaf)
-+ break;
-+ if (m->rm_mask == netmask) {
-+ m->rm_refs++;
-+ tt->rj_mklist = m;
-+#ifdef RJ_DEBUG
-+ printk("klips:radij.c: m->rm_mask %p == netmask\n", netmask);
-+#endif
-+ return 0; /* tt rgb */
-+ }
-+ if (rj_refines(netmask, m->rm_mask))
-+ break;
-+ }
-+ MKGet(m);
-+ if (m == 0) {
-+ printk("klips_debug:rj_addroute: "
-+ "Mask for route not entered\n");
-+ return 0; /* (tt) rgb */
-+ }
-+ Bzero(m, sizeof *m);
-+ m->rm_b = b_leaf;
-+ m->rm_mask = netmask;
-+ m->rm_mklist = *mp;
-+ *mp = m;
-+ tt->rj_mklist = m;
-+#ifdef RJ_DEBUG
-+ printk("klips:radij.c: addroute done\n");
-+#endif
-+ return 0; /* tt rgb */
-+}
-+
-+int
-+rj_delete(v_arg, netmask_arg, head, node)
-+ void *v_arg, *netmask_arg;
-+ struct radij_node_head *head;
-+ struct radij_node **node;
-+{
-+ register struct radij_node *t, *p, *x, *tt;
-+ struct radij_mask *m, *saved_m, **mp;
-+ struct radij_node *dupedkey, *saved_tt, *top;
-+ caddr_t v, netmask;
-+ int b, head_off, vlen;
-+
-+ v = v_arg;
-+ netmask = netmask_arg;
-+ x = head->rnh_treetop;
-+ tt = rj_search(v, x);
-+ head_off = x->rj_off;
-+ vlen = *(u_char *)v;
-+ saved_tt = tt;
-+ top = x;
-+ if (tt == 0 ||
-+ Bcmp(v + head_off, tt->rj_key + head_off, vlen - head_off))
-+ return -EFAULT; /* (0) rgb */
-+ /*
-+ * Delete our route from mask lists.
-+ */
-+ if ((dupedkey = tt->rj_dupedkey)) {
-+ if (netmask)
-+ netmask = rj_search(netmask, rj_masktop)->rj_key;
-+ while (tt->rj_mask != netmask)
-+ if ((tt = tt->rj_dupedkey) == 0)
-+ return -ENOENT; /* -ENXIO; (0) rgb */
-+ }
-+ if (tt->rj_mask == 0 || (saved_m = m = tt->rj_mklist) == 0)
-+ goto on1;
-+ if (m->rm_mask != tt->rj_mask) {
-+ printk("klips_debug:rj_delete: "
-+ "inconsistent annotation\n");
-+ goto on1;
-+ }
-+ if (--m->rm_refs >= 0)
-+ goto on1;
-+ b = -1 - tt->rj_b;
-+ t = saved_tt->rj_p;
-+ if (b > t->rj_b)
-+ goto on1; /* Wasn't lifted at all */
-+ do {
-+ x = t;
-+ t = t->rj_p;
-+ } while (b <= t->rj_b && x != top);
-+ for (mp = &x->rj_mklist; (m = *mp); mp = &m->rm_mklist)
-+ if (m == saved_m) {
-+ *mp = m->rm_mklist;
-+ MKFree(m);
-+ break;
-+ }
-+ if (m == 0)
-+ printk("klips_debug:rj_delete: "
-+ "couldn't find our annotation\n");
-+on1:
-+ /*
-+ * Eliminate us from tree
-+ */
-+ if (tt->rj_flags & RJF_ROOT)
-+ return -EFAULT; /* (0) rgb */
-+#ifdef RJ_DEBUG
-+ /* Get us out of the creation list */
-+ for (t = rj_clist; t && t->rj_ybro != tt; t = t->rj_ybro) {}
-+ if (t) t->rj_ybro = tt->rj_ybro;
-+#endif /* RJ_DEBUG */
-+ t = tt->rj_p;
-+ if (dupedkey) {
-+ if (tt == saved_tt) {
-+ x = dupedkey; x->rj_p = t;
-+ if (t->rj_l == tt) t->rj_l = x; else t->rj_r = x;
-+ } else {
-+ for (x = p = saved_tt; p && p->rj_dupedkey != tt;)
-+ p = p->rj_dupedkey;
-+ if (p) p->rj_dupedkey = tt->rj_dupedkey;
-+ else printk("klips_debug:rj_delete: "
-+ "couldn't find node that we started with\n");
-+ }
-+ t = tt + 1;
-+ if (t->rj_flags & RJF_ACTIVE) {
-+#ifndef RJ_DEBUG
-+ *++x = *t; p = t->rj_p;
-+#else
-+ b = t->rj_info; *++x = *t; t->rj_info = b; p = t->rj_p;
-+#endif /* RJ_DEBUG */
-+ if (p->rj_l == t) p->rj_l = x; else p->rj_r = x;
-+ x->rj_l->rj_p = x; x->rj_r->rj_p = x;
-+ }
-+ goto out;
-+ }
-+ if (t->rj_l == tt) x = t->rj_r; else x = t->rj_l;
-+ p = t->rj_p;
-+ if (p->rj_r == t) p->rj_r = x; else p->rj_l = x;
-+ x->rj_p = p;
-+ /*
-+ * Demote routes attached to us.
-+ */
-+ if (t->rj_mklist) {
-+ if (x->rj_b >= 0) {
-+ for (mp = &x->rj_mklist; (m = *mp);)
-+ mp = &m->rm_mklist;
-+ *mp = t->rj_mklist;
-+ } else {
-+ for (m = t->rj_mklist; m;) {
-+ struct radij_mask *mm = m->rm_mklist;
-+ if (m == x->rj_mklist && (--(m->rm_refs) < 0)) {
-+ x->rj_mklist = 0;
-+ MKFree(m);
-+ } else
-+ printk("klips_debug:rj_delete: "
-+ "Orphaned Mask 0p%p at 0p%p\n", m, x);
-+ m = mm;
-+ }
-+ }
-+ }
-+ /*
-+ * We may be holding an active internal node in the tree.
-+ */
-+ x = tt + 1;
-+ if (t != x) {
-+#ifndef RJ_DEBUG
-+ *t = *x;
-+#else
-+ b = t->rj_info; *t = *x; t->rj_info = b;
-+#endif /* RJ_DEBUG */
-+ t->rj_l->rj_p = t; t->rj_r->rj_p = t;
-+ p = x->rj_p;
-+ if (p->rj_l == x) p->rj_l = t; else p->rj_r = t;
-+ }
-+out:
-+ tt->rj_flags &= ~RJF_ACTIVE;
-+ tt[1].rj_flags &= ~RJF_ACTIVE;
-+ *node = tt;
-+ return 0; /* (tt) rgb */
-+}
-+
-+int
-+rj_walktree(h, f, w)
-+ struct radij_node_head *h;
-+ register int (*f)(struct radij_node *,void *);
-+ void *w;
-+{
-+ int error;
-+ struct radij_node *base, *next;
-+ register struct radij_node *rn;
-+
-+ if(!h || !f /* || !w */) {
-+ return -ENODATA;
-+ }
-+
-+ rn = h->rnh_treetop;
-+ /*
-+ * This gets complicated because we may delete the node
-+ * while applying the function f to it, so we need to calculate
-+ * the successor node in advance.
-+ */
-+ /* First time through node, go left */
-+ while (rn->rj_b >= 0)
-+ rn = rn->rj_l;
-+ for (;;) {
-+#ifdef CONFIG_IPSEC_DEBUG
-+ if(debug_radij) {
-+ printk("klips_debug:rj_walktree: "
-+ "for: rn=0p%p rj_b=%d rj_flags=%x",
-+ rn,
-+ rn->rj_b,
-+ rn->rj_flags);
-+ rn->rj_b >= 0 ?
-+ printk(" node off=%x\n",
-+ rn->rj_off) :
-+ printk(" leaf key = %08x->%08x\n",
-+ (u_int)ntohl(((struct sockaddr_encap *)rn->rj_key)->sen_ip_src.s_addr),
-+ (u_int)ntohl(((struct sockaddr_encap *)rn->rj_key)->sen_ip_dst.s_addr))
-+ ;
-+ }
-+#endif /* CONFIG_IPSEC_DEBUG */
-+ base = rn;
-+ /* If at right child go back up, otherwise, go right */
-+ while (rn->rj_p->rj_r == rn && (rn->rj_flags & RJF_ROOT) == 0)
-+ rn = rn->rj_p;
-+ /* Find the next *leaf* since next node might vanish, too */
-+ for (rn = rn->rj_p->rj_r; rn->rj_b >= 0;)
-+ rn = rn->rj_l;
-+ next = rn;
-+#ifdef CONFIG_IPSEC_DEBUG
-+ if(debug_radij) {
-+ printk("klips_debug:rj_walktree: "
-+ "processing leaves, rn=0p%p rj_b=%d rj_flags=%x",
-+ rn,
-+ rn->rj_b,
-+ rn->rj_flags);
-+ rn->rj_b >= 0 ?
-+ printk(" node off=%x\n",
-+ rn->rj_off) :
-+ printk(" leaf key = %08x->%08x\n",
-+ (u_int)ntohl(((struct sockaddr_encap *)rn->rj_key)->sen_ip_src.s_addr),
-+ (u_int)ntohl(((struct sockaddr_encap *)rn->rj_key)->sen_ip_dst.s_addr))
-+ ;
-+ }
-+#endif /* CONFIG_IPSEC_DEBUG */
-+ /* Process leaves */
-+ while ((rn = base)) {
-+ base = rn->rj_dupedkey;
-+#ifdef CONFIG_IPSEC_DEBUG
-+ if(debug_radij) {
-+ printk("klips_debug:rj_walktree: "
-+ "while: base=0p%p rn=0p%p rj_b=%d rj_flags=%x",
-+ base,
-+ rn,
-+ rn->rj_b,
-+ rn->rj_flags);
-+ rn->rj_b >= 0 ?
-+ printk(" node off=%x\n",
-+ rn->rj_off) :
-+ printk(" leaf key = %08x->%08x\n",
-+ (u_int)ntohl(((struct sockaddr_encap *)rn->rj_key)->sen_ip_src.s_addr),
-+ (u_int)ntohl(((struct sockaddr_encap *)rn->rj_key)->sen_ip_dst.s_addr))
-+ ;
-+ }
-+#endif /* CONFIG_IPSEC_DEBUG */
-+ if (!(rn->rj_flags & RJF_ROOT) && (error = (*f)(rn, w)))
-+ return (-error);
-+ }
-+ rn = next;
-+ if (rn->rj_flags & RJF_ROOT)
-+ return (0);
-+ }
-+ /* NOTREACHED */
-+}
-+
-+int
-+rj_inithead(head, off)
-+ void **head;
-+ int off;
-+{
-+ register struct radij_node_head *rnh;
-+ register struct radij_node *t, *tt, *ttt;
-+ if (*head)
-+ return (1);
-+ R_Malloc(rnh, struct radij_node_head *, sizeof (*rnh));
-+ if (rnh == NULL)
-+ return (0);
-+ Bzero(rnh, sizeof (*rnh));
-+ *head = rnh;
-+ t = rj_newpair(rj_zeroes, off, rnh->rnh_nodes);
-+ ttt = rnh->rnh_nodes + 2;
-+ t->rj_r = ttt;
-+ t->rj_p = t;
-+ tt = t->rj_l;
-+ tt->rj_flags = t->rj_flags = RJF_ROOT | RJF_ACTIVE;
-+ tt->rj_b = -1 - off;
-+ *ttt = *tt;
-+ ttt->rj_key = rj_ones;
-+ rnh->rnh_addaddr = rj_addroute;
-+ rnh->rnh_deladdr = rj_delete;
-+ rnh->rnh_matchaddr = rj_match;
-+ rnh->rnh_walktree = rj_walktree;
-+ rnh->rnh_treetop = t;
-+ return (1);
-+}
-+
-+void
-+rj_init()
-+{
-+ char *cp, *cplim;
-+
-+ if (maj_keylen == 0) {
-+ printk("klips_debug:rj_init: "
-+ "radij functions require maj_keylen be set\n");
-+ return;
-+ }
-+ R_Malloc(rj_zeroes, char *, 3 * maj_keylen);
-+ if (rj_zeroes == NULL)
-+ panic("rj_init");
-+ Bzero(rj_zeroes, 3 * maj_keylen);
-+ rj_ones = cp = rj_zeroes + maj_keylen;
-+ maskedKey = cplim = rj_ones + maj_keylen;
-+ while (cp < cplim)
-+ *cp++ = -1;
-+ if (rj_inithead((void **)&mask_rjhead, 0) == 0)
-+ panic("rj_init 2");
-+}
-+
-+void
-+rj_preorder(struct radij_node *rn, int l)
-+{
-+ int i;
-+
-+ if (rn == NULL){
-+ printk("klips_debug:rj_preorder: "
-+ "NULL pointer\n");
-+ return;
-+ }
-+
-+ if (rn->rj_b >= 0){
-+ rj_preorder(rn->rj_l, l+1);
-+ rj_preorder(rn->rj_r, l+1);
-+ printk("klips_debug:");
-+ for (i=0; i<l; i++)
-+ printk("*");
-+ printk(" off = %d\n",
-+ rn->rj_off);
-+ } else {
-+ printk("klips_debug:");
-+ for (i=0; i<l; i++)
-+ printk("@");
-+ printk(" flags = %x",
-+ (u_int)rn->rj_flags);
-+ if (rn->rj_flags & RJF_ACTIVE) {
-+ printk(" @key=0p%p",
-+ rn->rj_key);
-+ printk(" key = %08x->%08x",
-+ (u_int)ntohl(((struct sockaddr_encap *)rn->rj_key)->sen_ip_src.s_addr),
-+ (u_int)ntohl(((struct sockaddr_encap *)rn->rj_key)->sen_ip_dst.s_addr));
-+ printk(" @mask=0p%p",
-+ rn->rj_mask);
-+ if (rn->rj_mask)
-+ printk(" mask = %08x->%08x",
-+ (u_int)ntohl(((struct sockaddr_encap *)rn->rj_mask)->sen_ip_src.s_addr),
-+ (u_int)ntohl(((struct sockaddr_encap *)rn->rj_mask)->sen_ip_dst.s_addr));
-+ if (rn->rj_dupedkey)
-+ printk(" dupedkey = 0p%p",
-+ rn->rj_dupedkey);
-+ }
-+ printk("\n");
-+ }
-+}
-+
-+#ifdef RJ_DEBUG
-+DEBUG_NO_STATIC void traverse(struct radij_node *p)
-+{
-+ rj_preorder(p, 0);
-+}
-+#endif /* RJ_DEBUG */
-+
-+void
-+rj_dumptrees(void)
-+{
-+ rj_preorder(rnh->rnh_treetop, 0);
-+}
-+
-+void
-+rj_free_mkfreelist(void)
-+{
-+ struct radij_mask *mknp, *mknp2;
-+
-+ mknp = rj_mkfreelist;
-+ while(mknp)
-+ {
-+ mknp2 = mknp;
-+ mknp = mknp->rm_mklist;
-+ kfree(mknp2);
-+ }
-+}
-+
-+int
-+radijcleartree(void)
-+{
-+ return rj_walktree(rnh, ipsec_rj_walker_delete, NULL);
-+}
-+
-+int
-+radijcleanup(void)
-+{
-+ int error = 0;
-+
-+ error = radijcleartree();
-+
-+ rj_free_mkfreelist();
-+
-+/* rj_walktree(mask_rjhead, ipsec_rj_walker_delete, NULL); */
-+ if(mask_rjhead) {
-+ kfree(mask_rjhead);
-+ }
-+
-+ if(rj_zeroes) {
-+ kfree(rj_zeroes);
-+ }
-+
-+ if(rnh) {
-+ kfree(rnh);
-+ }
-+
-+ return error;
-+}
-+
-+/*
-+ * $Log: radij.c,v $
-+ * Revision 1.46 2004/04/06 02:49:26 mcr
-+ * pullup of algo code from alg-branch.
-+ *
-+ * Revision 1.45 2003/10/31 02:27:55 mcr
-+ * pulled up port-selector patches and sa_id elimination.
-+ *
-+ * Revision 1.44.30.1 2003/10/29 01:30:41 mcr
-+ * elimited "struct sa_id".
-+ *
-+ * Revision 1.44 2002/07/24 18:44:54 rgb
-+ * Type fiddling to tame ia64 compiler.
-+ *
-+ * Revision 1.43 2002/05/23 07:14:11 rgb
-+ * Cleaned up %p variants to 0p%p for test suite cleanup.
-+ *
-+ * Revision 1.42 2002/04/24 07:55:32 mcr
-+ * #include patches and Makefiles for post-reorg compilation.
-+ *
-+ * Revision 1.41 2002/04/24 07:36:35 mcr
-+ * Moved from ./klips/net/ipsec/radij.c,v
-+ *
-+ * Revision 1.40 2002/01/29 17:17:58 mcr
-+ * moved include of ipsec_param.h to after include of linux/kernel.h
-+ * otherwise, it seems that some option that is set in ipsec_param.h
-+ * screws up something subtle in the include path to kernel.h, and
-+ * it complains on the snprintf() prototype.
-+ *
-+ * Revision 1.39 2002/01/29 04:00:55 mcr
-+ * more excise of kversions.h header.
-+ *
-+ * Revision 1.38 2002/01/29 02:13:19 mcr
-+ * introduction of ipsec_kversion.h means that include of
-+ * ipsec_param.h must preceed any decisions about what files to
-+ * include to deal with differences in kernel source.
-+ *
-+ * Revision 1.37 2001/10/18 04:45:23 rgb
-+ * 2.4.9 kernel deprecates linux/malloc.h in favour of linux/slab.h,
-+ * lib/freeswan.h version macros moved to lib/kversions.h.
-+ * Other compiler directive cleanups.
-+ *
-+ * Revision 1.36 2001/08/22 13:43:51 henry
-+ * eliminate the single use of min() to avoid problems with Linus changing it
-+ *
-+ * Revision 1.35 2001/06/15 04:57:29 rgb
-+ * Clarified error return codes.
-+ * Changed mask add already exists to EEXIST.
-+ * Changed mask delete did not exist to ENOENT.
-+ *
-+ * Revision 1.34 2001/05/03 19:44:26 rgb
-+ * Fix sign of error return codes for rj_addroute().
-+ *
-+ * Revision 1.33 2001/02/27 22:24:56 rgb
-+ * Re-formatting debug output (line-splitting, joining, 1arg/line).
-+ * Check for satoa() return codes.
-+ *
-+ * Revision 1.32 2001/02/27 06:23:15 rgb
-+ * Debug line splitting.
-+ *
-+ * Revision 1.31 2000/11/06 04:35:21 rgb
-+ * Clear table *before* releasing other items in radijcleanup.
-+ *
-+ * Revision 1.30 2000/09/20 04:07:40 rgb
-+ * Changed static functions to DEBUG_NO_STATIC to reveal function names in
-+ * oopsen.
-+ *
-+ * Revision 1.29 2000/09/12 03:25:02 rgb
-+ * Moved radij_c_version printing to ipsec_version_get_info().
-+ *
-+ * Revision 1.28 2000/09/08 19:12:56 rgb
-+ * Change references from DEBUG_IPSEC to CONFIG_IPSEC_DEBUG.
-+ *
-+ * Revision 1.27 2000/07/28 14:58:32 rgb
-+ * Changed kfree_s to kfree, eliminating extra arg to fix 2.4.0-test5.
-+ *
-+ * Revision 1.26 2000/05/10 23:11:37 rgb
-+ * Comment out most of the startup version information.
-+ *
-+ * Revision 1.25 2000/01/21 06:21:47 rgb
-+ * Change return codes to negative on error.
-+ *
-+ * Revision 1.24 1999/11/18 04:09:20 rgb
-+ * Replaced all kernel version macros to shorter, readable form.
-+ *
-+ * Revision 1.23 1999/11/17 15:53:41 rgb
-+ * Changed all occurrences of #include "../../../lib/freeswan.h"
-+ * to #include <freeswan.h> which works due to -Ilibfreeswan in the
-+ * klips/net/ipsec/Makefile.
-+ *
-+ * Revision 1.22 1999/10/15 22:17:28 rgb
-+ * Modify radijcleanup() to call radijcleartree().
-+ *
-+ * Revision 1.21 1999/10/08 18:37:34 rgb
-+ * Fix end-of-line spacing to sate whining PHMs.
-+ *
-+ * Revision 1.20 1999/10/01 15:44:54 rgb
-+ * Move spinlock header include to 2.1> scope.
-+ *
-+ * Revision 1.19 1999/10/01 08:35:52 rgb
-+ * Add spinlock include to shut up compiler for 2.0.38.
-+ *
-+ * Revision 1.18 1999/09/23 18:02:52 rgb
-+ * De-alarm the search failure message so it doesn't sound so grave.
-+ *
-+ * Revision 1.17 1999/05/25 21:26:01 rgb
-+ * Fix rj_walktree() sanity checking bug.
-+ *
-+ * Revision 1.16 1999/05/09 03:25:38 rgb
-+ * Fix bug introduced by 2.2 quick-and-dirty patch.
-+ *
-+ * Revision 1.15 1999/05/05 22:02:33 rgb
-+ * Add a quick and dirty port to 2.2 kernels by Marc Boucher <marc@mbsi.ca>.
-+ *
-+ * Revision 1.14 1999/04/29 15:24:15 rgb
-+ * Add sanity checking for null pointer arguments.
-+ * Standardise an error return method.
-+ *
-+ * Revision 1.13 1999/04/11 00:29:02 henry
-+ * GPL boilerplate
-+ *
-+ * Revision 1.12 1999/04/06 04:54:28 rgb
-+ * Fix/Add RCSID Id: and Log: bits to make PHMDs happy. This includes
-+ * patch shell fixes.
-+ *
-+ * Revision 1.11 1999/02/17 16:52:53 rgb
-+ * Convert DEBUG_IPSEC to KLIPS_PRINT
-+ * Clean out unused cruft.
-+ *
-+ * Revision 1.10 1999/01/22 06:30:05 rgb
-+ * Cruft clean-out.
-+ * 64-bit clean-up.
-+ *
-+ * Revision 1.9 1998/12/01 13:22:04 rgb
-+ * Added support for debug printing of version info.
-+ *
-+ * Revision 1.8 1998/11/30 13:22:55 rgb
-+ * Rationalised all the klips kernel file headers. They are much shorter
-+ * now and won't conflict under RH5.2.
-+ *
-+ * Revision 1.7 1998/10/25 02:43:26 rgb
-+ * Change return type on rj_addroute and rj_delete and add and argument
-+ * to the latter to be able to transmit more infomation about errors.
-+ *
-+ * Revision 1.6 1998/10/19 14:30:06 rgb
-+ * Added inclusion of freeswan.h.
-+ *
-+ * Revision 1.5 1998/10/09 04:33:27 rgb
-+ * Added 'klips_debug' prefix to all klips printk debug statements.
-+ * Fixed output formatting slightly.
-+ *
-+ * Revision 1.4 1998/07/28 00:06:59 rgb
-+ * Add debug detail to tree traversing.
-+ *
-+ * Revision 1.3 1998/07/14 18:07:58 rgb
-+ * Add a routine to clear the eroute tree.
-+ *
-+ * Revision 1.2 1998/06/25 20:03:22 rgb
-+ * Cleanup #endif comments. Debug output for rj_init.
-+ *
-+ * Revision 1.1 1998/06/18 21:30:22 henry
-+ * move sources from klips/src to klips/net/ipsec to keep stupid kernel
-+ * build scripts happier about symlinks
-+ *
-+ * Revision 1.8 1998/05/25 20:34:15 rgb
-+ * Remove temporary ipsec_walk, rj_deltree and rj_delnodes functions.
-+ *
-+ * Rename ipsec_rj_walker (ipsec_walk) to ipsec_rj_walker_procprint and
-+ * add ipsec_rj_walker_delete.
-+ *
-+ * Recover memory for eroute table on unload of module.
-+ *
-+ * Revision 1.7 1998/05/21 12:58:58 rgb
-+ * Moved 'extern' definitions to ipsec_radij.h to support /proc 3k limit fix.
-+ *
-+ * Revision 1.6 1998/04/23 20:57:29 rgb
-+ * Cleaned up compiler warnings for unused debugging functions.
-+ *
-+ * Revision 1.5 1998/04/22 16:51:38 rgb
-+ * Tidy up radij debug code from recent rash of modifications to debug code.
-+ *
-+ * Revision 1.4 1998/04/21 21:28:56 rgb
-+ * Rearrange debug switches to change on the fly debug output from user
-+ * space. Only kernel changes checked in at this time. radij.c was also
-+ * changed to temporarily remove buggy debugging code in rj_delete causing
-+ * an OOPS and hence, netlink device open errors.
-+ *
-+ * Revision 1.3 1998/04/14 17:30:37 rgb
-+ * Fix up compiling errors for radij tree memory reclamation.
-+ *
-+ * Revision 1.2 1998/04/12 22:03:25 rgb
-+ * Updated ESP-3DES-HMAC-MD5-96,
-+ * ESP-DES-HMAC-MD5-96,
-+ * AH-HMAC-MD5-96,
-+ * AH-HMAC-SHA1-96 since Henry started freeswan cvs repository
-+ * from old standards (RFC182[5-9] to new (as of March 1998) drafts.
-+ *
-+ * Fixed eroute references in /proc/net/ipsec*.
-+ *
-+ * Started to patch module unloading memory leaks in ipsec_netlink and
-+ * radij tree unloading.
-+ *
-+ * Revision 1.1 1998/04/09 03:06:15 henry
-+ * sources moved up from linux/net/ipsec
-+ *
-+ * Revision 1.1.1.1 1998/04/08 05:35:03 henry
-+ * RGB's ipsec-0.8pre2.tar.gz ipsec-0.8
-+ *
-+ * Revision 0.4 1997/01/15 01:28:15 ji
-+ * No changes.
-+ *
-+ * Revision 0.3 1996/11/20 14:39:04 ji
-+ * Minor cleanups.
-+ * Rationalized debugging code.
-+ *
-+ * Revision 0.2 1996/11/02 00:18:33 ji
-+ * First limited release.
-+ *
-+ *
-+ */
---- /dev/null Tue Mar 11 13:02:56 2003
-+++ linux/net/ipsec/sysctl_net_ipsec.c Mon Feb 9 13:51:03 2004
-@@ -0,0 +1,196 @@
-+/*
-+ * sysctl interface to net IPSEC subsystem.
-+ * Copyright (C) 1998, 1999, 2000, 2001 Richard Guy Briggs.
-+ *
-+ * 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. See <http://www.fsf.org/copyleft/gpl.txt>.
-+ *
-+ * 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.
-+ *
-+ * RCSID $Id: sysctl_net_ipsec.c,v 1.16 2004/04/06 02:49:26 mcr Exp $
-+ */
-+
-+/* -*- linux-c -*-
-+ *
-+ * Initiated April 3, 1998, Richard Guy Briggs <rgb@conscoop.ottawa.on.ca>
-+ */
-+
-+#include <linux/mm.h>
-+#include <linux/sysctl.h>
-+
-+#include "openswan/ipsec_param.h"
-+
-+#ifdef CONFIG_SYSCTL
-+
-+#define NET_IPSEC 2112 /* Random number */
-+#ifdef CONFIG_IPSEC_DEBUG
-+extern int debug_ah;
-+extern int debug_esp;
-+extern int debug_tunnel;
-+extern int debug_eroute;
-+extern int debug_spi;
-+extern int debug_radij;
-+extern int debug_netlink;
-+extern int debug_xform;
-+extern int debug_rcv;
-+extern int debug_pfkey;
-+extern int sysctl_ipsec_debug_verbose;
-+#ifdef CONFIG_IPSEC_IPCOMP
-+extern int sysctl_ipsec_debug_ipcomp;
-+#endif /* CONFIG_IPSEC_IPCOMP */
-+#endif /* CONFIG_IPSEC_DEBUG */
-+
-+extern int sysctl_ipsec_icmp;
-+extern int sysctl_ipsec_inbound_policy_check;
-+extern int sysctl_ipsec_tos;
-+int sysctl_ipsec_regress_pfkey_lossage;
-+
-+enum {
-+#ifdef CONFIG_IPSEC_DEBUG
-+ NET_IPSEC_DEBUG_AH=1,
-+ NET_IPSEC_DEBUG_ESP=2,
-+ NET_IPSEC_DEBUG_TUNNEL=3,
-+ NET_IPSEC_DEBUG_EROUTE=4,
-+ NET_IPSEC_DEBUG_SPI=5,
-+ NET_IPSEC_DEBUG_RADIJ=6,
-+ NET_IPSEC_DEBUG_NETLINK=7,
-+ NET_IPSEC_DEBUG_XFORM=8,
-+ NET_IPSEC_DEBUG_RCV=9,
-+ NET_IPSEC_DEBUG_PFKEY=10,
-+ NET_IPSEC_DEBUG_VERBOSE=11,
-+ NET_IPSEC_DEBUG_IPCOMP=12,
-+#endif /* CONFIG_IPSEC_DEBUG */
-+ NET_IPSEC_ICMP=13,
-+ NET_IPSEC_INBOUND_POLICY_CHECK=14,
-+ NET_IPSEC_TOS=15,
-+ NET_IPSEC_REGRESS_PFKEY_LOSSAGE=16,
-+};
-+
-+static ctl_table ipsec_table[] = {
-+#ifdef CONFIG_IPSEC_DEBUG
-+ { NET_IPSEC_DEBUG_AH, "debug_ah", &debug_ah,
-+ sizeof(int), 0644, NULL, &proc_dointvec},
-+ { NET_IPSEC_DEBUG_ESP, "debug_esp", &debug_esp,
-+ sizeof(int), 0644, NULL, &proc_dointvec},
-+ { NET_IPSEC_DEBUG_TUNNEL, "debug_tunnel", &debug_tunnel,
-+ sizeof(int), 0644, NULL, &proc_dointvec},
-+ { NET_IPSEC_DEBUG_EROUTE, "debug_eroute", &debug_eroute,
-+ sizeof(int), 0644, NULL, &proc_dointvec},
-+ { NET_IPSEC_DEBUG_SPI, "debug_spi", &debug_spi,
-+ sizeof(int), 0644, NULL, &proc_dointvec},
-+ { NET_IPSEC_DEBUG_RADIJ, "debug_radij", &debug_radij,
-+ sizeof(int), 0644, NULL, &proc_dointvec},
-+ { NET_IPSEC_DEBUG_NETLINK, "debug_netlink", &debug_netlink,
-+ sizeof(int), 0644, NULL, &proc_dointvec},
-+ { NET_IPSEC_DEBUG_XFORM, "debug_xform", &debug_xform,
-+ sizeof(int), 0644, NULL, &proc_dointvec},
-+ { NET_IPSEC_DEBUG_RCV, "debug_rcv", &debug_rcv,
-+ sizeof(int), 0644, NULL, &proc_dointvec},
-+ { NET_IPSEC_DEBUG_PFKEY, "debug_pfkey", &debug_pfkey,
-+ sizeof(int), 0644, NULL, &proc_dointvec},
-+ { NET_IPSEC_DEBUG_VERBOSE, "debug_verbose",&sysctl_ipsec_debug_verbose,
-+ sizeof(int), 0644, NULL, &proc_dointvec},
-+#ifdef CONFIG_IPSEC_IPCOMP
-+ { NET_IPSEC_DEBUG_IPCOMP, "debug_ipcomp", &sysctl_ipsec_debug_ipcomp,
-+ sizeof(int), 0644, NULL, &proc_dointvec},
-+#endif /* CONFIG_IPSEC_IPCOMP */
-+
-+#ifdef CONFIG_IPSEC_REGRESS
-+ { NET_IPSEC_REGRESS_PFKEY_LOSSAGE, "pfkey_lossage",
-+ &sysctl_ipsec_regress_pfkey_lossage,
-+ sizeof(int), 0644, NULL, &proc_dointvec},
-+#endif /* CONFIG_IPSEC_REGRESS */
-+
-+#endif /* CONFIG_IPSEC_DEBUG */
-+ { NET_IPSEC_ICMP, "icmp", &sysctl_ipsec_icmp,
-+ sizeof(int), 0644, NULL, &proc_dointvec},
-+ { NET_IPSEC_INBOUND_POLICY_CHECK, "inbound_policy_check", &sysctl_ipsec_inbound_policy_check,
-+ sizeof(int), 0644, NULL, &proc_dointvec},
-+ { NET_IPSEC_TOS, "tos", &sysctl_ipsec_tos,
-+ sizeof(int), 0644, NULL, &proc_dointvec},
-+ {0}
-+};
-+
-+static ctl_table ipsec_net_table[] = {
-+ { NET_IPSEC, "ipsec", NULL, 0, 0555, ipsec_table },
-+ { 0 }
-+};
-+
-+static ctl_table ipsec_root_table[] = {
-+ { CTL_NET, "net", NULL, 0, 0555, ipsec_net_table },
-+ { 0 }
-+};
-+
-+static struct ctl_table_header *ipsec_table_header;
-+
-+int ipsec_sysctl_register(void)
-+{
-+ ipsec_table_header = register_sysctl_table(ipsec_root_table, 0);
-+ if (!ipsec_table_header) {
-+ return -ENOMEM;
-+ }
-+ return 0;
-+}
-+
-+void ipsec_sysctl_unregister(void)
-+{
-+ unregister_sysctl_table(ipsec_table_header);
-+}
-+
-+#endif /* CONFIG_SYSCTL */
-+
-+/*
-+ * $Log: sysctl_net_ipsec.c,v $
-+ * Revision 1.16 2004/04/06 02:49:26 mcr
-+ * pullup of algo code from alg-branch.
-+ *
-+ * Revision 1.15 2002/04/24 07:55:32 mcr
-+ * #include patches and Makefiles for post-reorg compilation.
-+ *
-+ * Revision 1.14 2002/04/24 07:36:35 mcr
-+ * Moved from ./klips/net/ipsec/sysctl_net_ipsec.c,v
-+ *
-+ * Revision 1.13 2002/01/12 02:58:32 mcr
-+ * first regression test causes acquire messages to be lost
-+ * 100% of the time. This is to help testing of pluto.
-+ *
-+ * Revision 1.12 2001/06/14 19:35:13 rgb
-+ * Update copyright date.
-+ *
-+ * Revision 1.11 2001/02/26 19:58:13 rgb
-+ * Drop sysctl_ipsec_{no_eroute_pass,opportunistic}, replaced by magic SAs.
-+ *
-+ * Revision 1.10 2000/09/16 01:50:15 rgb
-+ * Protect sysctl_ipsec_debug_ipcomp with compiler defines too so that the
-+ * linker won't blame rj_delete() for missing symbols. ;-> Damn statics...
-+ *
-+ * Revision 1.9 2000/09/15 23:17:51 rgb
-+ * Moved stuff around to compile with debug off.
-+ *
-+ * Revision 1.8 2000/09/15 11:37:02 rgb
-+ * Merge in heavily modified Svenning Soerensen's <svenning@post5.tele.dk>
-+ * IPCOMP zlib deflate code.
-+ *
-+ * Revision 1.7 2000/09/15 07:37:15 rgb
-+ * Munged silly log comment that was causing a warning.
-+ *
-+ * Revision 1.6 2000/09/15 04:58:23 rgb
-+ * Added tos runtime switch.
-+ * Removed 'sysctl_ipsec_' prefix from /proc/sys/net/ipsec/ filenames.
-+ *
-+ * Revision 1.5 2000/09/12 03:25:28 rgb
-+ * Filled in and implemented sysctl.
-+ *
-+ * Revision 1.4 1999/04/11 00:29:03 henry
-+ * GPL boilerplate
-+ *
-+ * Revision 1.3 1999/04/06 04:54:29 rgb
-+ * Fix/Add RCSID Id: and Log: bits to make PHMDs happy. This includes
-+ * patch shell fixes.
-+ *
-+ */
---- /dev/null Tue Mar 11 13:02:56 2003
-+++ linux/net/ipsec/version.c Mon Feb 9 13:51:03 2004
-@@ -0,0 +1,44 @@
-+/*
-+ * return IPsec version information
-+ * Copyright (C) 2001 Henry Spencer.
-+ *
-+ * This library is free software; you can redistribute it and/or modify it
-+ * under the terms of the GNU Library General Public License as published by
-+ * the Free Software Foundation; either version 2 of the License, or (at your
-+ * option) any later version. See <http://www.fsf.org/copyleft/lgpl.txt>.
-+ *
-+ * This library 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 Library General Public
-+ * License for more details.
-+ *
-+ * RCSID $Id: version.in.c,v 1.2 2004/04/14 05:09:46 ken Exp $
-+ */
-+
-+#ifdef __KERNEL__
-+#include <linux/netdevice.h>
-+#endif
-+
-+#include "openswan.h"
-+
-+#define V "cvs2002Mar12_01:19:03" /* substituted in by Makefile */
-+static const char openswan_number[] = V;
-+static const char openswan_string[] = "Openswan " V;
-+
-+/*
-+ - ipsec_version_code - return IPsec version number/code, as string
-+ */
-+const char *
-+ipsec_version_code()
-+{
-+ return openswan_number;
-+}
-+
-+/*
-+ - ipsec_version_string - return full version string
-+ */
-+const char *
-+ipsec_version_string()
-+{
-+ return openswan_string;
-+}
-RCSID $Id: af_inet.c.fs2_4.patch,v 1.6 2002/04/24 07:36:36 mcr Exp $
---- ./net/ipv4/af_inet.c.preipsec Wed Apr 26 15:13:17 2000
-+++ ./net/ipv4/af_inet.c Fri Jun 30 15:01:27 2000
-@@ -1019,6 +1019,17 @@
- ip_mr_init();
- #endif
-
-+#if defined(CONFIG_IPSEC)
-+ {
-+ extern /* void */ int ipsec_init(void);
-+ /*
-+ * Initialise AF_INET ESP and AH protocol support including
-+ * e-routing and SA tables
-+ */
-+ ipsec_init();
-+ }
-+#endif /* CONFIG_IPSEC */
-+
- /*
- * Create all the /proc entries.
- */
---- /dev/null Fri May 10 13:59:54 2002
-+++ linux/net/ipsec/Makefile.ver Sun Jul 28 22:10:40 2002
-@@ -0,0 +1 @@
-+IPSECVERSION=cvs2002Mar12_01:19:03
-make[1]: Leaving directory `/data/mtx/oe/tmp/work/openswan-2.2.0-r0/openswan-2.2.0'
diff --git a/recipes/linux/linux-mtx-1-2.4.27/14-au1000-eth-link-beat.diff b/recipes/linux/linux-mtx-1-2.4.27/14-au1000-eth-link-beat.diff
deleted file mode 100644
index f848d2a224..0000000000
--- a/recipes/linux/linux-mtx-1-2.4.27/14-au1000-eth-link-beat.diff
+++ /dev/null
@@ -1,64 +0,0 @@
---- linux/drivers/net/au1000_eth.c.orig 2004-11-23 12:01:00.551663672 +0100
-+++ linux/drivers/net/au1000_eth.c 2004-11-23 12:08:36.795304096 +0100
-@@ -6,7 +6,9 @@
- * Copyright 2002 TimeSys Corp.
- * Author: MontaVista Software, Inc.
- * ppopov@mvista.com or source@mvista.com
-- *
-+ * Bjoern Riemer 2004
-+ * riemer@fokus.fraunhofer.de or riemer@riemer-nt.de
-+ * // fixed the link beat detection with ioctls (SIOCGMIIPHY)
- * ########################################################################
- *
- * This program is free software; you can distribute it and/or modify it
-@@ -1383,6 +1385,10 @@
- aup->phy_ops->phy_status(dev, aup->phy_addr, &link, &speed);
- control = MAC_DISABLE_RX_OWN | MAC_RX_ENABLE | MAC_TX_ENABLE;
- #ifndef CONFIG_CPU_LITTLE_ENDIAN
-+ /*riemer: fix for startup without cable */
-+ if (!link)
-+ dev->flags &= ~IFF_RUNNING;
-+
- control |= MAC_BIG_ENDIAN;
- #endif
- if (link && (dev->if_port == IF_PORT_100BASEFX)) {
-@@ -1841,17 +1847,35 @@
-
- static int au1000_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
- {
-- //u16 *data = (u16 *)&rq->ifr_data;
-+/*
-+// This structure is used in all SIOCxMIIxxx ioctl calls
-+struct mii_ioctl_data {
-+ 0 u16 phy_id;
-+ 1 u16 reg_num;
-+ 2 u16 val_in;
-+ 3 u16 val_out;
-+};*/
-+ u16 *data = (u16 *)&rq->ifr_data;
-+ struct au1000_private *aup = (struct au1000_private *) dev->priv;
-+ //struct mii_ioctl_data *data = (struct mii_ioctl_data *) & rq->ifr_data;
-
- /* fixme */
- switch(cmd) {
- case SIOCDEVPRIVATE: /* Get the address of the PHY in use. */
-- //data[0] = PHY_ADDRESS;
-+ case SIOCGMIIPHY:
-+ if (!netif_running(dev))
-+ return -EINVAL;
-+ data[0] = aup->phy_addr;
- case SIOCDEVPRIVATE+1: /* Read the specified MII register. */
-- //data[3] = mdio_read(ioaddr, data[0], data[1]);
-+ case SIOCGMIIREG:
-+ data[3] = mdio_read(dev, data[0], data[1]);
-+ //data->val_out = mdio_read(dev,data->phy_id,data->reg_num);
- return 0;
- case SIOCDEVPRIVATE+2: /* Write the specified MII register */
-- //mdio_write(ioaddr, data[0], data[1], data[2]);
-+ case SIOCSMIIREG:
-+ if (!capable(CAP_NET_ADMIN))
-+ return -EPERM;
-+ mdio_write(dev, data[0], data[1],data[2]);
- return 0;
- default:
- return -EOPNOTSUPP;
diff --git a/recipes/linux/linux-mtx-1-2.4.27/16-i2c.patch b/recipes/linux/linux-mtx-1-2.4.27/16-i2c.patch
deleted file mode 100644
index cec737bdfe..0000000000
--- a/recipes/linux/linux-mtx-1-2.4.27/16-i2c.patch
+++ /dev/null
@@ -1,7482 +0,0 @@
---- linux-old/Documentation/Configure.help Mon Dec 13 16:57:33 2004
-+++ linux/Documentation/Configure.help Mon Dec 13 19:26:23 2004
-@@ -19347,6 +19347,16 @@
- <file:Documentation/modules.txt>.
- The module will be called i2c-velleman.o.
-
-+Basic I2C on Parallel Port adapter
-+CONFIG_I2C_PPORT
-+ This supports directly connecting I2C devices to the parallel port.
-+ See <file:Documentation/i2c/i2c-pport> for more information.
-+
-+ This driver is also available as a module. If you want to compile
-+ it as a module, say M here and read
-+ <file:Documentation/modules.txt>.
-+ The module will be called i2c-pport.o.
-+
- I2C PCF 8584 interfaces
- CONFIG_I2C_ALGOPCF
- This allows you to use a range of I2C adapters called PCF adapters.
-@@ -19368,6 +19378,15 @@
- <file:Documentation/modules.txt>.
- The module will be called i2c-elektor.o.
-
-+PCF on the EPP Parallel Port
-+CONFIG_I2C_PCFEPP
-+ This supports the PCF8584 connected to the parallel port.
-+
-+ This driver is also available as a module. If you want to compile
-+ it as a module, say M here and read
-+ <file:Documentation/modules.txt>.
-+ The module will be called i2c-pcf-epp.o.
-+
- ITE I2C Algorithm
- CONFIG_ITE_I2C_ALGO
- This supports the use the ITE8172 I2C interface found on some MIPS
-@@ -19405,6 +19424,51 @@
- Supports the SGI interfaces like the ones found on SGI Indy VINO
- or SGI O2 MACE.
-
-+Motorola 8xx I2C algorithm
-+CONFIG_I2C_ALGO8XX
-+ This is the algorithm that allows you to use Motorola 8xx I2C adapters.
-+
-+ This driver is also available as a module. If you want to compile
-+ it as a module, say M here and read
-+ <file:Documentation/modules.txt>.
-+ The module will be called i2c-algo-8xx.o.
-+
-+Motorola 8xx I2C interface
-+CONFIG_I2C_RPXLITE
-+ This supports the Motorola 8xx I2C device.
-+
-+ This driver is also available as a module. If you want to compile
-+ it as a module, say M here and read
-+ <file:Documentation/modules.txt>.
-+ The module will be called i2c-rpx.o.
-+
-+IBM 405 I2C algorithm
-+CONFIG_I2C_IBM_OCP_ALGO
-+ This is the algorithm that allows you to use IBM 405 I2C adapters.
-+
-+ This driver is also available as a module. If you want to compile
-+ it as a module, say M here and read
-+ <file:Documentation/modules.txt>.
-+ The module will be called i2c-algo-ibm_ocp.o.
-+
-+IBM 405 I2C interface
-+CONFIG_I2C_IBM_OCP_ADAP
-+ This supports the IBM 405 I2C device.
-+
-+ This driver is also available as a module. If you want to compile
-+ it as a module, say M here and read
-+ <file:Documentation/modules.txt>.
-+ The module will be called i2c-adap-ibm_ocp.o.
-+
-+StrongARM SA-1110 interface
-+CONFIG_I2C_FRODO
-+ This supports the StrongARM SA-1110 Development Board.
-+
-+ This driver is also available as a module. If you want to compile
-+ it as a module, say M here and read
-+ <file:Documentation/modules.txt>.
-+ The module will be called i2c-frodo.o.
-+
- I2C device interface
- CONFIG_I2C_CHARDEV
- Say Y here to use i2c-* device files, usually found in the /dev
---- linux-old/Documentation/i2c/dev-interface Mon Dec 22 22:44:34 2003
-+++ linux/Documentation/i2c/dev-interface Mon Dec 13 19:26:23 2004
-@@ -89,6 +89,11 @@
- Selects ten bit addresses if select not equals 0, selects normal 7 bit
- addresses if select equals 0. Default 0.
-
-+ioctl(file,I2C_PEC,long select)
-+ Selects SMBus PEC (packet error checking) generation and verification
-+ if select not equals 0, disables if select equals 0. Default 0.
-+ Used only for SMBus transactions.
-+
- ioctl(file,I2C_FUNCS,unsigned long *funcs)
- Gets the adapter functionality and puts it in *funcs.
-
---- linux-old/Documentation/i2c/i2c-pport Thu Jan 1 00:00:00 1970
-+++ linux/Documentation/i2c/i2c-pport Mon Dec 13 19:26:24 2004
-@@ -0,0 +1,67 @@
-+Parallel Port Adapters
-+----------------------
-+If you are installing parallel port adapters it means you are probably messing
-+around with wires and IC's and the like. If you have purchased a card that
-+provides an external i2c/smbus this will require combined algorithm and
-+adapter code in a single module.
-+If you are doing it yourself by using the parallel port there
-+are basically 2 options.
-+
-+1) Using the parallel port and using the i2c-pport adapter module and the
-+i2c-algo-bit algorithm module together to enable you to wire up your parallel
-+port to act as an i2c/smbus. This provides a bus that will enable most
-+sensors to work but doesn't support the entire i2c/smbus capability.
-+
-+2) Using the parallel port to interface to a Philips PCF8584 parallel to i2c
-+adapter chip. You will need to build a bit of a circuit to do this. This
-+configuration needs the i2c-pcf-epp adapter module and the i2c-algo-pcf
-+algorithm module. This support almost all of the i2c/smbus capabilities.
-+
-+
-+i2c-pport Documentation
-+-----------------------
-+This is a primitive parallel port driver for the i2c bus, which exploits
-+features of modern bidirectional parallel ports.
-+
-+Bidirectional ports have particular bits connected in following way:
-+
-+ |
-+ /-----| R
-+ --o| |-----|
-+ read \-----| /------- Out pin
-+ |/
-+ - -|\
-+ write V
-+ |
-+ ---
-+
-+
-+It means when output is set to 1 we can read the port. Therefore
-+we can use 2 pins of parallel port as SDA and SCL for i2c bus. It
-+is not necessary to add any external - additional parts, we can
-+read and write the same port simultaneously.
-+ I only use register base+2 so it is possible to use all
-+8 data bits of parallel port for other applications (I have
-+connected EEPROM and LCD display). I do not use bit Enable Bi-directional
-+ Port. The only disadvantage is we can only support 5V chips.
-+
-+Layout:
-+
-+Cannon 25 pin
-+
-+SDA - connect to pin 14 (Auto Linefeed)
-+SCL - connect to pin 16 (Initialize Printer)
-+GND - connect to pin 18-25
-++5V - use external supply (I use 5V from 3.5" floppy connector)
-+
-+no pullups requied
-+
-+Module parameters:
-+
-+base = 0xXXX
-+XXX - 278 or 378
-+
-+That's all.
-+
-+Daniel Smolik
-+marvin@sitour.cz
---- linux-old/Documentation/i2c/i2c-protocol Mon Dec 22 22:44:34 2003
-+++ linux/Documentation/i2c/i2c-protocol Mon Dec 13 19:26:24 2004
-@@ -65,3 +65,12 @@
- need to emit an Rd instead of a Wr, or vice versa, you set this
- flag. For example:
- S Addr Rd [A] Data [A] Data [A] ... [A] Data [A] P
-+
-+ Flags I2C_M_IGNORE_NAK
-+ Normally message is interrupted immediately if there is [NA] from the
-+ client. Setting this flag treats any [NA] as [A], and all of
-+ message is sent.
-+ These messages may still fail to SCL lo->hi timeout.
-+
-+ Flags I2C_M_NO_RD_ACK
-+ In a read message, master A/NA bit is skipped.
---- linux-old/Documentation/i2c/summary Tue Jan 20 15:10:28 2004
-+++ linux/Documentation/i2c/summary Mon Dec 13 19:26:24 2004
-@@ -59,16 +59,16 @@
- i2c-algo-8xx: An algorithm for CPM's I2C device in Motorola 8xx processors (NOT BUILT BY DEFAULT)
- i2c-algo-bit: A bit-banging algorithm
- i2c-algo-pcf: A PCF 8584 style algorithm
--i2c-algo-ppc405: An algorithm for the I2C device in IBM 405xx processors (NOT BUILT BY DEFAULT)
-+i2c-algo-ibm_ocp: An algorithm for the I2C device in IBM 4xx processors (NOT BUILT BY DEFAULT)
-
- Adapter drivers
- ---------------
-
- i2c-elektor: Elektor ISA card (uses i2c-algo-pcf)
- i2c-elv: ELV parallel port adapter (uses i2c-algo-bit)
--i2c-pcf-epp: PCF8584 on a EPP parallel port (uses i2c-algo-pcf) (BROKEN - missing i2c-pcf-epp.h)
-+i2c-pcf-epp: PCF8584 on a EPP parallel port (uses i2c-algo-pcf) (NOT mkpatched)
- i2c-philips-par: Philips style parallel port adapter (uses i2c-algo-bit)
--i2c-ppc405: IBM 405xx processor I2C device (uses i2c-algo-ppc405) (NOT BUILT BY DEFAULT)
-+i2c-adap-ibm_ocp: IBM 4xx processor I2C device (uses i2c-algo-ibm_ocp) (NOT BUILT BY DEFAULT)
- i2c-pport: Primitive parallel port adapter (uses i2c-algo-bit)
- i2c-rpx: RPX board Motorola 8xx I2C device (uses i2c-algo-8xx) (NOT BUILT BY DEFAULT)
- i2c-velleman: Velleman K8000 parallel port adapter (uses i2c-algo-bit)
---- linux-old/Documentation/i2c/writing-clients Mon Dec 22 22:44:34 2003
-+++ linux/Documentation/i2c/writing-clients Mon Dec 13 19:26:25 2004
-@@ -24,24 +24,24 @@
- routines, a client structure specific information like the actual I2C
- address.
-
-- struct i2c_driver foo_driver
-- {
-- /* name */ "Foo version 2.3 and later driver",
-- /* id */ I2C_DRIVERID_FOO,
-- /* flags */ I2C_DF_NOTIFY,
-- /* attach_adapter */ &foo_attach_adapter,
-- /* detach_client */ &foo_detach_client,
-- /* command */ &foo_command, /* May be NULL */
-- /* inc_use */ &foo_inc_use, /* May be NULL */
-- /* dec_use */ &foo_dec_use /* May be NULL */
-- }
-+static struct i2c_driver foo_driver = {
-+ .owner = THIS_MODULE,
-+ .name = "Foo version 2.3 driver",
-+ .id = I2C_DRIVERID_FOO, /* from i2c-id.h, optional */
-+ .flags = I2C_DF_NOTIFY,
-+ .attach_adapter = &foo_attach_adapter,
-+ .detach_client = &foo_detach_client,
-+ .command = &foo_command /* may be NULL */
-+}
-
- The name can be chosen freely, and may be upto 40 characters long. Please
- use something descriptive here.
-
--The id should be a unique ID. The range 0xf000 to 0xffff is reserved for
--local use, and you can use one of those until you start distributing the
--driver. Before you do that, contact the i2c authors to get your own ID(s).
-+If used, the id should be a unique ID. The range 0xf000 to 0xffff is
-+reserved for local use, and you can use one of those until you start
-+distributing the driver, at which time you should contact the i2c authors
-+to get your own ID(s). Note that most of the time you don't need an ID
-+at all so you can just omit it.
-
- Don't worry about the flags field; just put I2C_DF_NOTIFY into it. This
- means that your driver will be notified when new adapters are found.
-@@ -50,43 +50,8 @@
- All other fields are for call-back functions which will be explained
- below.
-
--
--Module usage count
--==================
--
--If your driver can also be compiled as a module, there are moments at
--which the module can not be removed from memory. For example, when you
--are doing a lengthy transaction, or when you create a /proc directory,
--and some process has entered that directory (this last case is the
--main reason why these call-backs were introduced).
--
--To increase or decrease the module usage count, you can use the
--MOD_{INC,DEC}_USE_COUNT macros. They must be called from the module
--which needs to get its usage count changed; that is why each driver
--module has to implement its own callback.
--
-- void foo_inc_use (struct i2c_client *client)
-- {
-- #ifdef MODULE
-- MOD_INC_USE_COUNT;
-- #endif
-- }
--
-- void foo_dec_use (struct i2c_client *client)
-- {
-- #ifdef MODULE
-- MOD_DEC_USE_COUNT;
-- #endif
-- }
--
--Do not call these call-back functions directly; instead, use one of the
--following functions defined in i2c.h:
-- void i2c_inc_use_client(struct i2c_client *);
-- void i2c_dec_use_client(struct i2c_client *);
--
--You should *not* increase the module count just because a device is
--detected and a client created. This would make it impossible to remove
--an adapter driver!
-+There use to be two additional fields in this structure, inc_use et dec_use,
-+for module usage count, but these fields were obsoleted and removed.
-
-
- Extra client data
---- linux-old/drivers/i2c/i2c-adap-ibm_ocp.c Thu Jan 1 00:00:00 1970
-+++ linux/drivers/i2c/i2c-adap-ibm_ocp.c Mon Dec 13 19:26:26 2004
-@@ -0,0 +1,346 @@
-+/*
-+ -------------------------------------------------------------------------
-+ i2c-adap-ibm_ocp.c i2c-hw access for the IIC peripheral on the IBM PPC 405
-+ -------------------------------------------------------------------------
-+
-+ Ian DaSilva, MontaVista Software, Inc.
-+ idasilva@mvista.com or source@mvista.com
-+
-+ Copyright 2000 MontaVista Software Inc.
-+
-+ Changes made to support the IIC peripheral on the IBM PPC 405
-+
-+
-+ ----------------------------------------------------------------------------
-+ This file was highly leveraged from i2c-elektor.c, which was created
-+ by Simon G. Vogl and Hans Berglund:
-+
-+
-+ Copyright (C) 1995-97 Simon G. Vogl
-+ 1998-99 Hans Berglund
-+
-+ With some changes from Kyösti Mälkki <kmalkki@cc.hut.fi> and even
-+ Frodo Looijaard <frodol@dds.nl>
-+
-+
-+ 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., 675 Mass Ave, Cambridge, MA 02139, USA.
-+ ----------------------------------------------------------------------------
-+
-+ History: 01/20/12 - Armin
-+ akuster@mvista.com
-+ ported up to 2.4.16+
-+
-+ Version 02/03/25 - Armin
-+ converted to ocp format
-+ removed commented out or #if 0 code
-+
-+ TODO: convert to ocp_register
-+ add PM hooks
-+
-+*/
-+
-+
-+#include <linux/kernel.h>
-+#include <linux/ioport.h>
-+#include <linux/module.h>
-+#include <linux/delay.h>
-+#include <linux/slab.h>
-+#include <linux/init.h>
-+#include <linux/i2c.h>
-+#include <linux/i2c-algo-ibm_ocp.h>
-+#include <asm/irq.h>
-+#include <asm/io.h>
-+#include <asm/ocp.h>
-+
-+/*
-+ * This next section is configurable, and it is used to set the number
-+ * of i2c controllers in the system. The default number of instances is 1,
-+ * however, this should be changed to reflect your system's configuration.
-+ */
-+
-+/*
-+ * The STB03xxx, with a PPC405 core, has two i2c controllers.
-+ */
-+//(sizeof(IIC_ADDR)/sizeof(struct iic_regs))
-+extern iic_t *IIC_ADDR[];
-+static struct iic_ibm iic_ibmocp_adaps[IIC_NUMS][5];
-+
-+static struct i2c_algo_iic_data *iic_ibmocp_data[IIC_NUMS];
-+static struct i2c_adapter *iic_ibmocp_ops[IIC_NUMS];
-+
-+static int i2c_debug=0;
-+static wait_queue_head_t iic_wait[IIC_NUMS];
-+static int iic_pending;
-+static spinlock_t irq_driver_lock = SPIN_LOCK_UNLOCKED;
-+
-+
-+/* ----- global defines ----------------------------------------------- */
-+#define DEB(x) if (i2c_debug>=1) x
-+#define DEB2(x) if (i2c_debug>=2) x
-+#define DEB3(x) if (i2c_debug>=3) x
-+#define DEBE(x) x /* error messages */
-+
-+/* ----- local functions ---------------------------------------------- */
-+
-+//
-+// Description: Write a byte to IIC hardware
-+//
-+static void iic_ibmocp_setbyte(void *data, int ctl, int val)
-+{
-+ // writeb resolves to a write to the specified memory location
-+ // plus a call to eieio. eieio ensures that all instructions
-+ // preceding it are completed before any further stores are
-+ // completed.
-+ // Delays at this level (to protect writes) are not needed here.
-+ writeb(val, ctl);
-+}
-+
-+
-+//
-+// Description: Read a byte from IIC hardware
-+//
-+static int iic_ibmocp_getbyte(void *data, int ctl)
-+{
-+ int val;
-+
-+ val = readb(ctl);
-+ return (val);
-+}
-+
-+
-+//
-+// Description: Return our slave address. This is the address
-+// put on the I2C bus when another master on the bus wants to address us
-+// as a slave
-+//
-+static int iic_ibmocp_getown(void *data)
-+{
-+ return(((struct iic_ibm *)(data))->iic_own);
-+}
-+
-+
-+//
-+// Description: Return the clock rate
-+//
-+static int iic_ibmocp_getclock(void *data)
-+{
-+ return(((struct iic_ibm *)(data))->iic_clock);
-+}
-+
-+
-+
-+//
-+// Description: Put this process to sleep. We will wake up when the
-+// IIC controller interrupts.
-+//
-+static void iic_ibmocp_waitforpin(void *data) {
-+
-+ int timeout = 2;
-+ struct iic_ibm *priv_data = data;
-+
-+ //
-+ // If interrupts are enabled (which they are), then put the process to
-+ // sleep. This process will be awakened by two events -- either the
-+ // the IIC peripheral interrupts or the timeout expires.
-+ //
-+ if (priv_data->iic_irq > 0) {
-+ spin_lock_irq(&irq_driver_lock);
-+ if (iic_pending == 0) {
-+ interruptible_sleep_on_timeout(&(iic_wait[priv_data->index]), timeout*HZ );
-+ } else
-+ iic_pending = 0;
-+ spin_unlock_irq(&irq_driver_lock);
-+ } else {
-+ //
-+ // If interrupts are not enabled then delay for a reasonable amount
-+ // of time and return. We expect that by time we return to the calling
-+ // function that the IIC has finished our requested transaction and
-+ // the status bit reflects this.
-+ //
-+ // udelay is probably not the best choice for this since it is
-+ // the equivalent of a busy wait
-+ //
-+ udelay(100);
-+ }
-+ //printk("iic_ibmocp_waitforpin: exitting\n");
-+}
-+
-+
-+//
-+// Description: The registered interrupt handler
-+//
-+static void iic_ibmocp_handler(int this_irq, void *dev_id, struct pt_regs *regs)
-+{
-+ int ret;
-+ struct iic_regs *iic;
-+ struct iic_ibm *priv_data = dev_id;
-+ iic = (struct iic_regs *) priv_data->iic_base;
-+ iic_pending = 1;
-+ DEB2(printk("iic_ibmocp_handler: in interrupt handler\n"));
-+ // Read status register
-+ ret = readb((int) &(iic->sts));
-+ DEB2(printk("iic_ibmocp_handler: status = %x\n", ret));
-+ // Clear status register. See IBM PPC 405 reference manual for details
-+ writeb(0x0a, (int) &(iic->sts));
-+ wake_up_interruptible(&(iic_wait[priv_data->index]));
-+}
-+
-+
-+//
-+// Description: This function is very hardware dependent. First, we lock
-+// the region of memory where out registers exist. Next, we request our
-+// interrupt line and register its associated handler. Our IIC peripheral
-+// uses interrupt number 2, as specified by the 405 reference manual.
-+//
-+static int iic_hw_resrc_init(int instance)
-+{
-+
-+ DEB(printk("iic_hw_resrc_init: Physical Base address: 0x%x\n", (u32) IIC_ADDR[instance] ));
-+ iic_ibmocp_adaps[instance]->iic_base = (u32)ioremap((unsigned long)IIC_ADDR[instance],PAGE_SIZE);
-+
-+ DEB(printk("iic_hw_resrc_init: ioremapped base address: 0x%x\n", iic_ibmocp_adaps[instance]->iic_base));
-+
-+ if (iic_ibmocp_adaps[instance]->iic_irq > 0) {
-+
-+ if (request_irq(iic_ibmocp_adaps[instance]->iic_irq, iic_ibmocp_handler,
-+ 0, "IBM OCP IIC", iic_ibmocp_adaps[instance]) < 0) {
-+ printk(KERN_ERR "iic_hw_resrc_init: Request irq%d failed\n",
-+ iic_ibmocp_adaps[instance]->iic_irq);
-+ iic_ibmocp_adaps[instance]->iic_irq = 0;
-+ } else {
-+ DEB3(printk("iic_hw_resrc_init: Enabled interrupt\n"));
-+ }
-+ }
-+ return 0;
-+}
-+
-+
-+//
-+// Description: Release irq and memory
-+//
-+static void iic_ibmocp_release(void)
-+{
-+ int i;
-+
-+ for(i=0; i<IIC_NUMS; i++) {
-+ struct iic_ibm *priv_data = (struct iic_ibm *)iic_ibmocp_data[i]->data;
-+ if (priv_data->iic_irq > 0) {
-+ disable_irq(priv_data->iic_irq);
-+ free_irq(priv_data->iic_irq, 0);
-+ }
-+ kfree(iic_ibmocp_data[i]);
-+ kfree(iic_ibmocp_ops[i]);
-+ }
-+}
-+
-+
-+//
-+// Description: Called when the module is loaded. This function starts the
-+// cascade of calls up through the heirarchy of i2c modules (i.e. up to the
-+// algorithm layer and into to the core layer)
-+//
-+static int __init iic_ibmocp_init(void)
-+{
-+ int i;
-+
-+ printk(KERN_INFO "iic_ibmocp_init: IBM on-chip iic adapter module\n");
-+
-+ for(i=0; i<IIC_NUMS; i++) {
-+ iic_ibmocp_data[i] = kmalloc(sizeof(struct i2c_algo_iic_data),GFP_KERNEL);
-+ if(iic_ibmocp_data[i] == NULL) {
-+ return -ENOMEM;
-+ }
-+ memset(iic_ibmocp_data[i], 0, sizeof(struct i2c_algo_iic_data));
-+
-+ switch (i) {
-+ case 0:
-+ iic_ibmocp_adaps[i]->iic_irq = IIC_IRQ(0);
-+ break;
-+ case 1:
-+ iic_ibmocp_adaps[i]->iic_irq = IIC_IRQ(1);
-+ break;
-+ }
-+ iic_ibmocp_adaps[i]->iic_clock = IIC_CLOCK;
-+ iic_ibmocp_adaps[i]->iic_own = IIC_OWN;
-+ iic_ibmocp_adaps[i]->index = i;
-+
-+ DEB(printk("irq %x\n", iic_ibmocp_adaps[i]->iic_irq));
-+ DEB(printk("clock %x\n", iic_ibmocp_adaps[i]->iic_clock));
-+ DEB(printk("own %x\n", iic_ibmocp_adaps[i]->iic_own));
-+ DEB(printk("index %x\n", iic_ibmocp_adaps[i]->index));
-+
-+
-+ iic_ibmocp_data[i]->data = (struct iic_regs *)iic_ibmocp_adaps[i];
-+ iic_ibmocp_data[i]->setiic = iic_ibmocp_setbyte;
-+ iic_ibmocp_data[i]->getiic = iic_ibmocp_getbyte;
-+ iic_ibmocp_data[i]->getown = iic_ibmocp_getown;
-+ iic_ibmocp_data[i]->getclock = iic_ibmocp_getclock;
-+ iic_ibmocp_data[i]->waitforpin = iic_ibmocp_waitforpin;
-+ iic_ibmocp_data[i]->udelay = 80;
-+ iic_ibmocp_data[i]->mdelay = 80;
-+ iic_ibmocp_data[i]->timeout = HZ;
-+
-+ iic_ibmocp_ops[i] = kmalloc(sizeof(struct i2c_adapter), GFP_KERNEL);
-+ if(iic_ibmocp_ops[i] == NULL) {
-+ return -ENOMEM;
-+ }
-+ memset(iic_ibmocp_ops[i], 0, sizeof(struct i2c_adapter));
-+ strcpy(iic_ibmocp_ops[i]->name, "IBM OCP IIC adapter");
-+ iic_ibmocp_ops[i]->owner = THIS_MODULE;
-+ iic_ibmocp_ops[i]->id = I2C_HW_OCP;
-+ iic_ibmocp_ops[i]->algo = NULL;
-+ iic_ibmocp_ops[i]->algo_data = iic_ibmocp_data[i];
-+
-+
-+ init_waitqueue_head(&(iic_wait[i]));
-+ if (iic_hw_resrc_init(i) == 0) {
-+ if (i2c_ocp_add_bus(iic_ibmocp_ops[i]) < 0)
-+ return -ENODEV;
-+ } else {
-+ return -ENODEV;
-+ }
-+ DEB(printk(KERN_INFO "iic_ibmocp_init: found device at %#x.\n\n", iic_ibmocp_adaps[i]->iic_base));
-+ }
-+ return 0;
-+}
-+
-+
-+static void __exit iic_ibmocp_exit(void)
-+{
-+ int i;
-+
-+ for(i=0; i<IIC_NUMS; i++) {
-+ i2c_ocp_del_bus(iic_ibmocp_ops[i]);
-+ }
-+ iic_ibmocp_release();
-+}
-+
-+//
-+// If modules is NOT defined when this file is compiled, then the MODULE_*
-+// macros will resolve to nothing
-+//
-+MODULE_AUTHOR("MontaVista Software <www.mvista.com>");
-+MODULE_DESCRIPTION("I2C-Bus adapter routines for PPC 405 IIC bus adapter");
-+MODULE_LICENSE("GPL");
-+
-+MODULE_PARM(base, "i");
-+MODULE_PARM(irq, "i");
-+MODULE_PARM(clock, "i");
-+MODULE_PARM(own, "i");
-+MODULE_PARM(i2c_debug,"i");
-+
-+
-+module_init(iic_ibmocp_init);
-+module_exit(iic_ibmocp_exit);
---- linux-old/drivers/i2c/i2c-algo-8xx.c Thu Jan 1 00:00:00 1970
-+++ linux/drivers/i2c/i2c-algo-8xx.c Mon Dec 13 19:26:27 2004
-@@ -0,0 +1,616 @@
-+/*
-+ * i2c-algo-8xx.c i2x driver algorithms for MPC8XX CPM
-+ * Copyright (c) 1999 Dan Malek (dmalek@jlc.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.
-+
-+ 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., 675 Mass Ave, Cambridge, MA 02139, USA.
-+ *
-+ * moved into proper i2c interface; separated out platform specific
-+ * parts into i2c-rpx.c
-+ * Brad Parker (brad@heeltoe.com)
-+ */
-+
-+// XXX todo
-+// timeout sleep?
-+
-+/* $Id: i2c-algo-8xx.c,v 1.14 2003/07/25 07:56:42 khali Exp $ */
-+
-+#include <linux/kernel.h>
-+#include <linux/module.h>
-+#include <linux/delay.h>
-+#include <linux/slab.h>
-+#include <linux/init.h>
-+#include <linux/errno.h>
-+#include <linux/sched.h>
-+#include <linux/i2c.h>
-+#include <linux/i2c-algo-8xx.h>
-+#include <asm/mpc8xx.h>
-+#include <asm/commproc.h>
-+
-+
-+#define CPM_MAX_READ 513
-+/* #define I2C_CHIP_ERRATA */ /* Try uncomment this if you have an older CPU(earlier than rev D4) */
-+static wait_queue_head_t iic_wait;
-+static ushort r_tbase, r_rbase;
-+
-+int cpm_debug = 0;
-+
-+static void
-+cpm_iic_interrupt(void *dev_id, struct pt_regs *regs)
-+{
-+ volatile i2c8xx_t *i2c = (i2c8xx_t *)dev_id;
-+ if (cpm_debug > 1)
-+ printk("cpm_iic_interrupt(dev_id=%p)\n", dev_id);
-+#if 0
-+ /* Chip errata, clear enable. This is not needed on rev D4 CPUs */
-+ /* This should probably be removed and replaced by I2C_CHIP_ERRATA stuff */
-+ /* Someone with a buggy CPU needs to confirm that */
-+ i2c->i2c_i2mod &= ~1;
-+#endif
-+ /* Clear interrupt.
-+ */
-+ i2c->i2c_i2cer = 0xff;
-+
-+ /* Get 'me going again.
-+ */
-+ wake_up_interruptible(&iic_wait);
-+}
-+
-+static void
-+cpm_iic_init(struct i2c_algo_8xx_data *cpm)
-+{
-+ volatile iic_t *iip = cpm->iip;
-+ volatile i2c8xx_t *i2c = cpm->i2c;
-+ unsigned char brg;
-+ bd_t *bd = (bd_t *)__res;
-+
-+ if (cpm_debug) printk(KERN_DEBUG "cpm_iic_init()\n");
-+
-+ /* Initialize the parameter ram.
-+ * We need to make sure many things are initialized to zero,
-+ * especially in the case of a microcode patch.
-+ */
-+ iip->iic_rstate = 0;
-+ iip->iic_rdp = 0;
-+ iip->iic_rbptr = 0;
-+ iip->iic_rbc = 0;
-+ iip->iic_rxtmp = 0;
-+ iip->iic_tstate = 0;
-+ iip->iic_tdp = 0;
-+ iip->iic_tbptr = 0;
-+ iip->iic_tbc = 0;
-+ iip->iic_txtmp = 0;
-+
-+ /* Set up the IIC parameters in the parameter ram.
-+ */
-+ iip->iic_tbase = r_tbase = cpm->dp_addr;
-+ iip->iic_rbase = r_rbase = cpm->dp_addr + sizeof(cbd_t)*2;
-+
-+ iip->iic_tfcr = SMC_EB;
-+ iip->iic_rfcr = SMC_EB;
-+
-+ /* Set maximum receive size.
-+ */
-+ iip->iic_mrblr = CPM_MAX_READ;
-+
-+ /* Initialize Tx/Rx parameters.
-+ */
-+ if (cpm->reloc == 0) {
-+ volatile cpm8xx_t *cp = cpm->cp;
-+
-+ cp->cp_cpcr =
-+ mk_cr_cmd(CPM_CR_CH_I2C, CPM_CR_INIT_TRX) | CPM_CR_FLG;
-+ while (cp->cp_cpcr & CPM_CR_FLG);
-+ } else {
-+ iip->iic_rbptr = iip->iic_rbase;
-+ iip->iic_tbptr = iip->iic_tbase;
-+ iip->iic_rstate = 0;
-+ iip->iic_tstate = 0;
-+ }
-+
-+ /* Select an arbitrary address. Just make sure it is unique.
-+ */
-+ i2c->i2c_i2add = 0xfe;
-+
-+ /* Make clock run at 60 KHz.
-+ */
-+ brg = (unsigned char) (bd->bi_intfreq/(32*2*60000) -3);
-+ i2c->i2c_i2brg = brg;
-+
-+ i2c->i2c_i2mod = 0x00;
-+ i2c->i2c_i2com = 0x01; /* Master mode */
-+
-+ /* Disable interrupts.
-+ */
-+ i2c->i2c_i2cmr = 0;
-+ i2c->i2c_i2cer = 0xff;
-+
-+ init_waitqueue_head(&iic_wait);
-+
-+ /* Install interrupt handler.
-+ */
-+ if (cpm_debug) {
-+ printk ("%s[%d] Install ISR for IRQ %d\n",
-+ __func__,__LINE__, CPMVEC_I2C);
-+ }
-+ (*cpm->setisr)(CPMVEC_I2C, cpm_iic_interrupt, (void *)i2c);
-+}
-+
-+
-+static int
-+cpm_iic_shutdown(struct i2c_algo_8xx_data *cpm)
-+{
-+ volatile i2c8xx_t *i2c = cpm->i2c;
-+
-+ /* Shut down IIC.
-+ */
-+ i2c->i2c_i2mod &= ~1;
-+ i2c->i2c_i2cmr = 0;
-+ i2c->i2c_i2cer = 0xff;
-+
-+ return(0);
-+}
-+
-+static void
-+cpm_reset_iic_params(volatile iic_t *iip)
-+{
-+ iip->iic_tbase = r_tbase;
-+ iip->iic_rbase = r_rbase;
-+
-+ iip->iic_tfcr = SMC_EB;
-+ iip->iic_rfcr = SMC_EB;
-+
-+ iip->iic_mrblr = CPM_MAX_READ;
-+
-+ iip->iic_rstate = 0;
-+ iip->iic_rdp = 0;
-+ iip->iic_rbptr = iip->iic_rbase;
-+ iip->iic_rbc = 0;
-+ iip->iic_rxtmp = 0;
-+ iip->iic_tstate = 0;
-+ iip->iic_tdp = 0;
-+ iip->iic_tbptr = iip->iic_tbase;
-+ iip->iic_tbc = 0;
-+ iip->iic_txtmp = 0;
-+}
-+
-+#define BD_SC_NAK ((ushort)0x0004) /* NAK - did not respond */
-+#define BD_SC_OV ((ushort)0x0002) /* OV - receive overrun */
-+#define CPM_CR_CLOSE_RXBD ((ushort)0x0007)
-+
-+static void force_close(struct i2c_algo_8xx_data *cpm)
-+{
-+ volatile i2c8xx_t *i2c = cpm->i2c;
-+ if (cpm->reloc == 0) { /* micro code disabled */
-+ volatile cpm8xx_t *cp = cpm->cp;
-+
-+ if (cpm_debug) printk("force_close()\n");
-+ cp->cp_cpcr =
-+ mk_cr_cmd(CPM_CR_CH_I2C, CPM_CR_CLOSE_RXBD) |
-+ CPM_CR_FLG;
-+
-+ while (cp->cp_cpcr & CPM_CR_FLG);
-+ }
-+ i2c->i2c_i2cmr = 0x00; /* Disable all interrupts */
-+ i2c->i2c_i2cer = 0xff;
-+}
-+
-+
-+/* Read from IIC...
-+ * abyte = address byte, with r/w flag already set
-+ */
-+static int
-+cpm_iic_read(struct i2c_algo_8xx_data *cpm, u_char abyte, char *buf, int count)
-+{
-+ volatile iic_t *iip = cpm->iip;
-+ volatile i2c8xx_t *i2c = cpm->i2c;
-+ volatile cpm8xx_t *cp = cpm->cp;
-+ volatile cbd_t *tbdf, *rbdf;
-+ u_char *tb;
-+ unsigned long flags, tmo;
-+
-+ if (count >= CPM_MAX_READ)
-+ return -EINVAL;
-+
-+ /* check for and use a microcode relocation patch */
-+ if (cpm->reloc) {
-+ cpm_reset_iic_params(iip);
-+ }
-+
-+ tbdf = (cbd_t *)&cp->cp_dpmem[iip->iic_tbase];
-+ rbdf = (cbd_t *)&cp->cp_dpmem[iip->iic_rbase];
-+
-+ /* To read, we need an empty buffer of the proper length.
-+ * All that is used is the first byte for address, the remainder
-+ * is just used for timing (and doesn't really have to exist).
-+ */
-+ tb = cpm->temp;
-+ tb = (u_char *)(((uint)tb + 15) & ~15);
-+ tb[0] = abyte; /* Device address byte w/rw flag */
-+
-+ flush_dcache_range((unsigned long) tb, (unsigned long) (tb+1));
-+
-+ if (cpm_debug) printk("cpm_iic_read(abyte=0x%x)\n", abyte);
-+
-+ tbdf->cbd_bufaddr = __pa(tb);
-+ tbdf->cbd_datlen = count + 1;
-+ tbdf->cbd_sc =
-+ BD_SC_READY | BD_SC_LAST |
-+ BD_SC_WRAP | BD_IIC_START;
-+
-+ iip->iic_mrblr = count +1; /* prevent excessive read, +1
-+ is needed otherwise will the
-+ RXB interrupt come too early */
-+
-+ /* flush will invalidate too. */
-+ flush_dcache_range((unsigned long) buf, (unsigned long) (buf+count));
-+
-+ rbdf->cbd_datlen = 0;
-+ rbdf->cbd_bufaddr = __pa(buf);
-+ rbdf->cbd_sc = BD_SC_EMPTY | BD_SC_WRAP| BD_SC_INTRPT;
-+ if(count > 16){
-+ /* Chip bug, set enable here */
-+ local_irq_save(flags);
-+ i2c->i2c_i2cmr = 0x13; /* Enable some interupts */
-+ i2c->i2c_i2cer = 0xff;
-+ i2c->i2c_i2mod |= 1; /* Enable */
-+ i2c->i2c_i2com |= 0x80; /* Begin transmission */
-+
-+ /* Wait for IIC transfer */
-+ tmo = interruptible_sleep_on_timeout(&iic_wait,1*HZ);
-+ local_irq_restore(flags);
-+ } else { /* busy wait for small transfers, its faster */
-+ i2c->i2c_i2cmr = 0x00; /* Disable I2C interupts */
-+ i2c->i2c_i2cer = 0xff;
-+ i2c->i2c_i2mod |= 1; /* Enable */
-+ i2c->i2c_i2com |= 0x80; /* Begin transmission */
-+ tmo = jiffies + 1*HZ;
-+ while(!(i2c->i2c_i2cer & 0x11 || time_after(jiffies, tmo))); /* Busy wait, with a timeout */
-+ }
-+
-+ if (signal_pending(current) || !tmo){
-+ force_close(cpm);
-+ if(cpm_debug)
-+ printk("IIC read: timeout!\n");
-+ return -EIO;
-+ }
-+#ifdef I2C_CHIP_ERRATA
-+ /* Chip errata, clear enable. This is not needed on rev D4 CPUs.
-+ Disabling I2C too early may cause too short stop condition */
-+ udelay(4);
-+ i2c->i2c_i2mod &= ~1;
-+#endif
-+ if (cpm_debug) {
-+ printk("tx sc %04x, rx sc %04x\n",
-+ tbdf->cbd_sc, rbdf->cbd_sc);
-+ }
-+
-+ if (tbdf->cbd_sc & BD_SC_READY) {
-+ printk("IIC read; complete but tbuf ready\n");
-+ force_close(cpm);
-+ printk("tx sc %04x, rx sc %04x\n",
-+ tbdf->cbd_sc, rbdf->cbd_sc);
-+ }
-+
-+ if (tbdf->cbd_sc & BD_SC_NAK) {
-+ if (cpm_debug)
-+ printk("IIC read; no ack\n");
-+ return -EREMOTEIO;
-+ }
-+
-+ if (rbdf->cbd_sc & BD_SC_EMPTY) {
-+ /* force_close(cpm); */
-+ if (cpm_debug){
-+ printk("IIC read; complete but rbuf empty\n");
-+ printk("tx sc %04x, rx sc %04x\n",
-+ tbdf->cbd_sc, rbdf->cbd_sc);
-+ }
-+ return -EREMOTEIO;
-+ }
-+
-+ if (rbdf->cbd_sc & BD_SC_OV) {
-+ if (cpm_debug)
-+ printk("IIC read; Overrun\n");
-+ return -EREMOTEIO;;
-+ }
-+
-+ if (cpm_debug) printk("read %d bytes\n", rbdf->cbd_datlen);
-+
-+ if (rbdf->cbd_datlen < count) {
-+ if (cpm_debug)
-+ printk("IIC read; short, wanted %d got %d\n",
-+ count, rbdf->cbd_datlen);
-+ return 0;
-+ }
-+
-+ return count;
-+}
-+
-+/* Write to IIC...
-+ * addr = address byte, with r/w flag already set
-+ */
-+static int
-+cpm_iic_write(struct i2c_algo_8xx_data *cpm, u_char abyte, char *buf,int count)
-+{
-+ volatile iic_t *iip = cpm->iip;
-+ volatile i2c8xx_t *i2c = cpm->i2c;
-+ volatile cpm8xx_t *cp = cpm->cp;
-+ volatile cbd_t *tbdf;
-+ u_char *tb;
-+ unsigned long flags, tmo;
-+
-+ /* check for and use a microcode relocation patch */
-+ if (cpm->reloc) {
-+ cpm_reset_iic_params(iip);
-+ }
-+ tb = cpm->temp;
-+ tb = (u_char *)(((uint)tb + 15) & ~15);
-+ *tb = abyte; /* Device address byte w/rw flag */
-+
-+ flush_dcache_range((unsigned long) tb, (unsigned long) (tb+1));
-+ flush_dcache_range((unsigned long) buf, (unsigned long) (buf+count));
-+
-+ if (cpm_debug) printk("cpm_iic_write(abyte=0x%x)\n", abyte);
-+
-+ /* set up 2 descriptors */
-+ tbdf = (cbd_t *)&cp->cp_dpmem[iip->iic_tbase];
-+
-+ tbdf[0].cbd_bufaddr = __pa(tb);
-+ tbdf[0].cbd_datlen = 1;
-+ tbdf[0].cbd_sc = BD_SC_READY | BD_IIC_START;
-+
-+ tbdf[1].cbd_bufaddr = __pa(buf);
-+ tbdf[1].cbd_datlen = count;
-+ tbdf[1].cbd_sc = BD_SC_READY | BD_SC_INTRPT | BD_SC_LAST | BD_SC_WRAP;
-+
-+ if(count > 16){
-+ /* Chip bug, set enable here */
-+ local_irq_save(flags);
-+ i2c->i2c_i2cmr = 0x13; /* Enable some interupts */
-+ i2c->i2c_i2cer = 0xff;
-+ i2c->i2c_i2mod |= 1; /* Enable */
-+ i2c->i2c_i2com |= 0x80; /* Begin transmission */
-+
-+ /* Wait for IIC transfer */
-+ tmo = interruptible_sleep_on_timeout(&iic_wait,1*HZ);
-+ local_irq_restore(flags);
-+ } else { /* busy wait for small transfers, its faster */
-+ i2c->i2c_i2cmr = 0x00; /* Disable I2C interupts */
-+ i2c->i2c_i2cer = 0xff;
-+ i2c->i2c_i2mod |= 1; /* Enable */
-+ i2c->i2c_i2com |= 0x80; /* Begin transmission */
-+ tmo = jiffies + 1*HZ;
-+ while(!(i2c->i2c_i2cer & 0x12 || time_after(jiffies, tmo))); /* Busy wait, with a timeout */
-+ }
-+
-+ if (signal_pending(current) || !tmo){
-+ force_close(cpm);
-+ if(cpm_debug && !tmo)
-+ printk("IIC write: timeout!\n");
-+ return -EIO;
-+ }
-+
-+#if I2C_CHIP_ERRATA
-+ /* Chip errata, clear enable. This is not needed on rev D4 CPUs.
-+ Disabling I2C too early may cause too short stop condition */
-+ udelay(4);
-+ i2c->i2c_i2mod &= ~1;
-+#endif
-+ if (cpm_debug) {
-+ printk("tx0 sc %04x, tx1 sc %04x\n",
-+ tbdf[0].cbd_sc, tbdf[1].cbd_sc);
-+ }
-+
-+ if (tbdf->cbd_sc & BD_SC_NAK) {
-+ if (cpm_debug)
-+ printk("IIC write; no ack\n");
-+ return 0;
-+ }
-+
-+ if (tbdf->cbd_sc & BD_SC_READY) {
-+ if (cpm_debug)
-+ printk("IIC write; complete but tbuf ready\n");
-+ return 0;
-+ }
-+
-+ return count;
-+}
-+
-+/* See if an IIC address exists..
-+ * addr = 7 bit address, unshifted
-+ */
-+static int
-+cpm_iic_tryaddress(struct i2c_algo_8xx_data *cpm, int addr)
-+{
-+ volatile iic_t *iip = cpm->iip;
-+ volatile i2c8xx_t *i2c = cpm->i2c;
-+ volatile cpm8xx_t *cp = cpm->cp;
-+ volatile cbd_t *tbdf, *rbdf;
-+ u_char *tb;
-+ unsigned long flags, len, tmo;
-+
-+ if (cpm_debug > 1)
-+ printk("cpm_iic_tryaddress(cpm=%p,addr=%d)\n", cpm, addr);
-+
-+ /* check for and use a microcode relocation patch */
-+ if (cpm->reloc) {
-+ cpm_reset_iic_params(iip);
-+ }
-+
-+ if (cpm_debug && addr == 0) {
-+ printk("iip %p, dp_addr 0x%x\n", cpm->iip, cpm->dp_addr);
-+ printk("iic_tbase %d, r_tbase %d\n", iip->iic_tbase, r_tbase);
-+ }
-+
-+ tbdf = (cbd_t *)&cp->cp_dpmem[iip->iic_tbase];
-+ rbdf = (cbd_t *)&cp->cp_dpmem[iip->iic_rbase];
-+
-+ tb = cpm->temp;
-+ tb = (u_char *)(((uint)tb + 15) & ~15);
-+
-+ /* do a simple read */
-+ tb[0] = (addr << 1) | 1; /* device address (+ read) */
-+ len = 2;
-+
-+ flush_dcache_range((unsigned long) tb, (unsigned long) (tb+2));
-+
-+ tbdf->cbd_bufaddr = __pa(tb);
-+ tbdf->cbd_datlen = len;
-+ tbdf->cbd_sc =
-+ BD_SC_READY | BD_SC_LAST |
-+ BD_SC_WRAP | BD_IIC_START;
-+
-+ rbdf->cbd_datlen = 0;
-+ rbdf->cbd_bufaddr = __pa(tb+2);
-+ rbdf->cbd_sc = BD_SC_EMPTY | BD_SC_WRAP | BD_SC_INTRPT;
-+
-+ local_irq_save(flags);
-+ i2c->i2c_i2cmr = 0x13; /* Enable some interupts */
-+ i2c->i2c_i2cer = 0xff;
-+ i2c->i2c_i2mod |= 1; /* Enable */
-+ i2c->i2c_i2com |= 0x80; /* Begin transmission */
-+
-+ if (cpm_debug > 1) printk("about to sleep\n");
-+
-+ /* wait for IIC transfer */
-+ tmo = interruptible_sleep_on_timeout(&iic_wait,1*HZ);
-+ local_irq_restore(flags);
-+
-+#ifdef I2C_CHIP_ERRATA
-+ /* Chip errata, clear enable. This is not needed on rev D4 CPUs.
-+ Disabling I2C too early may cause too short stop condition */
-+ udelay(4);
-+ i2c->i2c_i2mod &= ~1;
-+#endif
-+
-+ if (signal_pending(current) || !tmo){
-+ force_close(cpm);
-+ if(cpm_debug && !tmo)
-+ printk("IIC tryaddress: timeout!\n");
-+ return -EIO;
-+ }
-+
-+ if (cpm_debug > 1) printk("back from sleep\n");
-+
-+ if (tbdf->cbd_sc & BD_SC_NAK) {
-+ if (cpm_debug > 1) printk("IIC try; no ack\n");
-+ return 0;
-+ }
-+
-+ if (tbdf->cbd_sc & BD_SC_READY) {
-+ printk("IIC try; complete but tbuf ready\n");
-+ }
-+
-+ return 1;
-+}
-+
-+static int cpm_xfer(struct i2c_adapter *adap,
-+ struct i2c_msg msgs[],
-+ int num)
-+{
-+ struct i2c_algo_8xx_data *cpm = adap->algo_data;
-+ struct i2c_msg *pmsg;
-+ int i, ret;
-+ u_char addr;
-+
-+ for (i = 0; i < num; i++) {
-+ pmsg = &msgs[i];
-+
-+ if (cpm_debug)
-+ printk("i2c-algo-8xx.o: "
-+ "#%d addr=0x%x flags=0x%x len=%d\n buf=%lx\n",
-+ i, pmsg->addr, pmsg->flags, pmsg->len, (unsigned long)pmsg->buf);
-+
-+ addr = pmsg->addr << 1;
-+ if (pmsg->flags & I2C_M_RD )
-+ addr |= 1;
-+ if (pmsg->flags & I2C_M_REV_DIR_ADDR )
-+ addr ^= 1;
-+
-+ if (!(pmsg->flags & I2C_M_NOSTART)) {
-+ }
-+ if (pmsg->flags & I2C_M_RD ) {
-+ /* read bytes into buffer*/
-+ ret = cpm_iic_read(cpm, addr, pmsg->buf, pmsg->len);
-+ if (cpm_debug)
-+ printk("i2c-algo-8xx.o: read %d bytes\n", ret);
-+ if (ret < pmsg->len ) {
-+ return (ret<0)? ret : -EREMOTEIO;
-+ }
-+ } else {
-+ /* write bytes from buffer */
-+ ret = cpm_iic_write(cpm, addr, pmsg->buf, pmsg->len);
-+ if (cpm_debug)
-+ printk("i2c-algo-8xx.o: wrote %d\n", ret);
-+ if (ret < pmsg->len ) {
-+ return (ret<0) ? ret : -EREMOTEIO;
-+ }
-+ }
-+ }
-+ return (num);
-+}
-+
-+static u32 cpm_func(struct i2c_adapter *adap)
-+{
-+ return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_10BIT_ADDR |
-+ I2C_FUNC_PROTOCOL_MANGLING;
-+}
-+
-+/* -----exported algorithm data: ------------------------------------- */
-+
-+static struct i2c_algorithm cpm_algo = {
-+ .owner = THIS_MODULE,
-+ .name = "MPC8xx CPM algorithm",
-+ .id = I2C_ALGO_MPC8XX,
-+ .master_xfer = cpm_xfer,
-+ .functionality = cpm_func,
-+};
-+
-+/*
-+ * registering functions to load algorithms at runtime
-+ */
-+int i2c_8xx_add_bus(struct i2c_adapter *adap)
-+{
-+ int i;
-+ struct i2c_algo_8xx_data *cpm = adap->algo_data;
-+
-+ if (cpm_debug)
-+ printk("i2c-algo-8xx.o: hw routines for %s registered.\n",
-+ adap->name);
-+
-+ /* register new adapter to i2c module... */
-+
-+ adap->id |= cpm_algo.id;
-+ adap->algo = &cpm_algo;
-+
-+ i2c_add_adapter(adap);
-+ cpm_iic_init(cpm);
-+}
-+
-+
-+int i2c_8xx_del_bus(struct i2c_adapter *adap)
-+{
-+ struct i2c_algo_8xx_data *cpm = adap->algo_data;
-+
-+ cpm_iic_shutdown(cpm);
-+
-+ return i2c_del_adapter(adap);
-+}
-+
-+EXPORT_SYMBOL(i2c_8xx_add_bus);
-+EXPORT_SYMBOL(i2c_8xx_del_bus);
-+
-+MODULE_AUTHOR("Brad Parker <brad@heeltoe.com>");
-+MODULE_DESCRIPTION("I2C-Bus MPC8XX algorithm");
-+MODULE_LICENSE("GPL");
---- linux-old/include/linux/i2c-algo-8xx.h Thu Jan 1 00:00:00 1970
-+++ linux/include/linux/i2c-algo-8xx.h Mon Dec 13 19:26:27 2004
-@@ -0,0 +1,43 @@
-+/* ------------------------------------------------------------------------- */
-+/* i2c-algo-8xx.h i2c driver algorithms for MPX8XX CPM */
-+/*
-+ 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., 675 Mass Ave, Cambridge, MA 02139, USA. */
-+/* ------------------------------------------------------------------------- */
-+
-+/* $Id: i2c-algo-8xx.h,v 1.7 2003/08/01 20:56:38 khali Exp $ */
-+
-+#ifndef _LINUX_I2C_ALGO_8XX_H
-+#define _LINUX_I2C_ALGO_8XX_H
-+
-+#include "asm/commproc.h"
-+
-+struct i2c_algo_8xx_data {
-+ uint dp_addr;
-+ int reloc;
-+ volatile i2c8xx_t *i2c;
-+ volatile iic_t *iip;
-+ volatile cpm8xx_t *cp;
-+
-+ int (*setisr) (int irq,
-+ void (*func)(void *, void *),
-+ void *data);
-+
-+ u_char temp[513];
-+};
-+
-+int i2c_8xx_add_bus(struct i2c_adapter *);
-+int i2c_8xx_del_bus(struct i2c_adapter *);
-+
-+#endif /* _LINUX_I2C_ALGO_8XX_H */
---- linux-old/drivers/i2c/i2c-algo-bit.c Tue Jan 20 15:10:31 2004
-+++ linux/drivers/i2c/i2c-algo-bit.c Mon Dec 13 19:26:27 2004
-@@ -18,24 +18,22 @@
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
- /* ------------------------------------------------------------------------- */
-
--/* With some changes from Kyösti Mälkki <kmalkki@cc.hut.fi> and even
-- Frodo Looijaard <frodol@dds.nl> */
-+/* With some changes from Frodo Looijaard <frodol@dds.nl>, Kyösti Mälkki
-+ <kmalkki@cc.hut.fi> and Jean Delvare <khali@linux-fr.org> */
-
--/* $Id: i2c-algo-bit.c,v 1.30 2001/07/29 02:44:25 mds Exp $ */
-+/* $Id: i2c-algo-bit.c,v 1.50 2003/12/22 20:03:39 khali Exp $ */
-
- #include <linux/kernel.h>
- #include <linux/module.h>
- #include <linux/delay.h>
- #include <linux/slab.h>
- #include <linux/init.h>
--#include <asm/uaccess.h>
--#include <linux/ioport.h>
- #include <linux/errno.h>
- #include <linux/sched.h>
--
- #include <linux/i2c.h>
- #include <linux/i2c-algo-bit.h>
-
-+
- /* ----- global defines ----------------------------------------------- */
- #define DEB(x) if (i2c_debug>=1) x;
- #define DEB2(x) if (i2c_debug>=2) x;
-@@ -43,27 +41,13 @@
- #define DEBPROTO(x) if (i2c_debug>=9) { x; }
- /* debug the protocol by showing transferred bits */
-
--/* debugging - slow down transfer to have a look at the data .. */
--/* I use this with two leds&resistors, each one connected to sda,scl */
--/* respectively. This makes sure that the algorithm works. Some chips */
--/* might not like this, as they have an internal timeout of some mils */
--/*
--#define SLO_IO jif=jiffies;while(time_before_eq(jiffies, jif+i2c_table[minor].veryslow))\
-- if (need_resched) schedule();
--*/
--
-
- /* ----- global variables --------------------------------------------- */
-
--#ifdef SLO_IO
-- int jif;
--#endif
--
- /* module parameters:
- */
- static int i2c_debug;
- static int bit_test; /* see if the line-setting functions work */
--static int bit_scan; /* have a look at what's hanging 'round */
-
- /* --- setting states on the bus with the right timing: --------------- */
-
-@@ -88,9 +72,6 @@
- {
- setscl(adap,0);
- udelay(adap->udelay);
--#ifdef SLO_IO
-- SLO_IO
--#endif
- }
-
- /*
-@@ -99,33 +80,35 @@
- */
- static inline int sclhi(struct i2c_algo_bit_data *adap)
- {
-- int start=jiffies;
-+ int start;
-
- setscl(adap,1);
-
-- udelay(adap->udelay);
--
- /* Not all adapters have scl sense line... */
-- if (adap->getscl == NULL )
-+ if (adap->getscl == NULL ) {
-+ udelay(adap->udelay);
- return 0;
-+ }
-
-- while (! getscl(adap) ) {
-+ start=jiffies;
-+ while (! getscl(adap) ) {
- /* the hw knows how to read the clock line,
- * so we wait until it actually gets high.
- * This is safer as some chips may hold it low
- * while they are processing data internally.
- */
-- setscl(adap,1);
- if (time_after_eq(jiffies, start+adap->timeout)) {
- return -ETIMEDOUT;
- }
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
- if (current->need_resched)
- schedule();
-+#else
-+ cond_resched();
-+#endif
- }
- DEBSTAT(printk(KERN_DEBUG "needed %ld jiffies\n", jiffies-start));
--#ifdef SLO_IO
-- SLO_IO
--#endif
-+ udelay(adap->udelay);
- return 0;
- }
-
-@@ -144,7 +127,7 @@
- /* scl, sda may not be high */
- DEBPROTO(printk(" Sr "));
- setsda(adap,1);
-- setscl(adap,1);
-+ sclhi(adap);
- udelay(adap->udelay);
-
- sdalo(adap);
-@@ -178,7 +161,6 @@
- struct i2c_algo_bit_data *adap = i2c_adap->algo_data;
-
- /* assert: scl is low */
-- DEB2(printk(KERN_DEBUG " i2c_outb:%2.2X\n",c&0xff));
- for ( i=7 ; i>=0 ; i-- ) {
- sb = c & ( 1 << i );
- setsda(adap,sb);
-@@ -186,6 +168,7 @@
- DEBPROTO(printk(KERN_DEBUG "%d",sb!=0));
- if (sclhi(adap)<0) { /* timed out */
- sdahi(adap); /* we don't want to block the net */
-+ DEB2(printk(KERN_DEBUG " i2c_outb: 0x%02x, timeout at bit #%d\n", c&0xff, i));
- return -ETIMEDOUT;
- };
- /* do arbitration here:
-@@ -196,11 +179,12 @@
- }
- sdahi(adap);
- if (sclhi(adap)<0){ /* timeout */
-+ DEB2(printk(KERN_DEBUG " i2c_outb: 0x%02x, timeout at ack\n", c&0xff));
- return -ETIMEDOUT;
- };
- /* read ack: SDA should be pulled down by slave */
- ack=getsda(adap); /* ack: sda is pulled low ->success. */
-- DEB2(printk(KERN_DEBUG " i2c_outb: getsda() = 0x%2.2x\n", ~ack ));
-+ DEB2(printk(KERN_DEBUG " i2c_outb: 0x%02x , getsda() = %d\n", c & 0xff, ack));
-
- DEBPROTO( printk(KERN_DEBUG "[%2.2x]",c&0xff) );
- DEBPROTO(if (0==ack){ printk(KERN_DEBUG " A ");} else printk(KERN_DEBUG " NA ") );
-@@ -219,11 +203,10 @@
- struct i2c_algo_bit_data *adap = i2c_adap->algo_data;
-
- /* assert: scl is low */
-- DEB2(printk(KERN_DEBUG "i2c_inb.\n"));
--
- sdahi(adap);
- for (i=0;i<8;i++) {
- if (sclhi(adap)<0) { /* timeout */
-+ DEB2(printk(KERN_DEBUG " i2c_inb: timeout at bit #%d\n", 7-i));
- return -ETIMEDOUT;
- };
- indata *= 2;
-@@ -232,6 +215,8 @@
- scllo(adap);
- }
- /* assert: scl is low */
-+ DEB2(printk(KERN_DEBUG "i2c_inb: 0x%02x\n", indata & 0xff));
-+
- DEBPROTO(printk(KERN_DEBUG " 0x%02x", indata & 0xff));
- return (int) (indata & 0xff);
- }
-@@ -242,71 +227,75 @@
- */
- static int test_bus(struct i2c_algo_bit_data *adap, char* name) {
- int scl,sda;
-+
-+ if (adap->getscl==NULL)
-+ printk(KERN_INFO "i2c-algo-bit.o: Testing SDA only, "
-+ "SCL is not readable.\n");
-+
- sda=getsda(adap);
-- if (adap->getscl==NULL) {
-- printk("i2c-algo-bit.o: Warning: Adapter can't read from clock line - skipping test.\n");
-- return 0;
-- }
-- scl=getscl(adap);
-- printk("i2c-algo-bit.o: Adapter: %s scl: %d sda: %d -- testing...\n",
-- name,getscl(adap),getsda(adap));
-+ scl=(adap->getscl==NULL?1:getscl(adap));
-+ printk(KERN_DEBUG "i2c-algo-bit.o: (0) scl=%d, sda=%d\n",scl,sda);
- if (!scl || !sda ) {
-- printk("i2c-algo-bit.o: %s seems to be busy.\n",name);
-+ printk(KERN_WARNING "i2c-algo-bit.o: %s seems to be busy.\n", name);
- goto bailout;
- }
-+
- sdalo(adap);
-- printk("i2c-algo-bit.o:1 scl: %d sda: %d \n",getscl(adap),
-- getsda(adap));
-- if ( 0 != getsda(adap) ) {
-- printk("i2c-algo-bit.o: %s SDA stuck high!\n",name);
-- sdahi(adap);
-+ sda=getsda(adap);
-+ scl=(adap->getscl==NULL?1:getscl(adap));
-+ printk(KERN_DEBUG "i2c-algo-bit.o: (1) scl=%d, sda=%d\n",scl,sda);
-+ if ( 0 != sda ) {
-+ printk(KERN_WARNING "i2c-algo-bit.o: SDA stuck high!\n");
- goto bailout;
- }
-- if ( 0 == getscl(adap) ) {
-- printk("i2c-algo-bit.o: %s SCL unexpected low while pulling SDA low!\n",
-- name);
-+ if ( 0 == scl ) {
-+ printk(KERN_WARNING "i2c-algo-bit.o: SCL unexpected low "
-+ "while pulling SDA low!\n");
- goto bailout;
- }
-+
- sdahi(adap);
-- printk("i2c-algo-bit.o:2 scl: %d sda: %d \n",getscl(adap),
-- getsda(adap));
-- if ( 0 == getsda(adap) ) {
-- printk("i2c-algo-bit.o: %s SDA stuck low!\n",name);
-- sdahi(adap);
-+ sda=getsda(adap);
-+ scl=(adap->getscl==NULL?1:getscl(adap));
-+ printk(KERN_DEBUG "i2c-algo-bit.o: (2) scl=%d, sda=%d\n",scl,sda);
-+ if ( 0 == sda ) {
-+ printk(KERN_WARNING "i2c-algo-bit.o: SDA stuck low!\n");
- goto bailout;
- }
-- if ( 0 == getscl(adap) ) {
-- printk("i2c-algo-bit.o: %s SCL unexpected low while SDA high!\n",
-- name);
-- goto bailout;
-+ if ( 0 == scl ) {
-+ printk(KERN_WARNING "i2c-algo-bit.o: SCL unexpected low "
-+ "while pulling SDA high!\n");
-+ goto bailout;
- }
-+
- scllo(adap);
-- printk("i2c-algo-bit.o:3 scl: %d sda: %d \n",getscl(adap),
-- getsda(adap));
-- if ( 0 != getscl(adap) ) {
-- printk("i2c-algo-bit.o: %s SCL stuck high!\n",name);
-- sclhi(adap);
-+ sda=getsda(adap);
-+ scl=(adap->getscl==NULL?0:getscl(adap));
-+ printk(KERN_DEBUG "i2c-algo-bit.o: (3) scl=%d, sda=%d\n",scl,sda);
-+ if ( 0 != scl ) {
-+ printk(KERN_WARNING "i2c-algo-bit.o: SCL stuck high!\n");
- goto bailout;
- }
-- if ( 0 == getsda(adap) ) {
-- printk("i2c-algo-bit.o: %s SDA unexpected low while pulling SCL low!\n",
-- name);
-+ if ( 0 == sda ) {
-+ printk(KERN_WARNING "i2c-algo-bit.o: SDA unexpected low "
-+ "while pulling SCL low!\n");
- goto bailout;
- }
-+
- sclhi(adap);
-- printk("i2c-algo-bit.o:4 scl: %d sda: %d \n",getscl(adap),
-- getsda(adap));
-- if ( 0 == getscl(adap) ) {
-- printk("i2c-algo-bit.o: %s SCL stuck low!\n",name);
-- sclhi(adap);
-+ sda=getsda(adap);
-+ scl=(adap->getscl==NULL?1:getscl(adap));
-+ printk(KERN_DEBUG "i2c-algo-bit.o: (4) scl=%d, sda=%d\n",scl,sda);
-+ if ( 0 == scl ) {
-+ printk(KERN_WARNING "i2c-algo-bit.o: SCL stuck low!\n");
- goto bailout;
- }
-- if ( 0 == getsda(adap) ) {
-- printk("i2c-algo-bit.o: %s SDA unexpected low while SCL high!\n",
-- name);
-+ if ( 0 == sda ) {
-+ printk(KERN_WARNING "i2c-algo-bit.o: SDA unexpected low "
-+ "while pulling SCL high!\n");
- goto bailout;
- }
-- printk("i2c-algo-bit.o: %s passed test.\n",name);
-+ printk(KERN_INFO "i2c-algo-bit.o: %s passed test.\n",name);
- return 0;
- bailout:
- sdahi(adap);
-@@ -340,16 +329,21 @@
- i2c_start(adap);
- udelay(adap->udelay);
- }
-- DEB2(if (i) printk(KERN_DEBUG "i2c-algo-bit.o: needed %d retries for %d\n",
-- i,addr));
-+ DEB2(if (i)
-+ printk(KERN_DEBUG "i2c-algo-bit.o: Used %d tries to %s client at 0x%02x : %s\n",
-+ i+1, addr & 1 ? "read" : "write", addr>>1,
-+ ret==1 ? "success" : ret==0 ? "no ack" : "failed, timeout?" )
-+ );
- return ret;
- }
-
--static int sendbytes(struct i2c_adapter *i2c_adap,const char *buf, int count)
-+static int sendbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msg)
- {
- struct i2c_algo_bit_data *adap = i2c_adap->algo_data;
- char c;
-- const char *temp = buf;
-+ const char *temp = msg->buf;
-+ int count = msg->len;
-+ unsigned short nak_ok = msg->flags & I2C_M_IGNORE_NAK;
- int retval;
- int wrcount=0;
-
-@@ -358,7 +352,7 @@
- DEB2(printk(KERN_DEBUG "i2c-algo-bit.o: %s sendbytes: writing %2.2X\n",
- i2c_adap->name, c&0xff));
- retval = i2c_outb(i2c_adap,c);
-- if (retval>0) {
-+ if ((retval>0) || (nak_ok && (retval==0))) { /* ok or ignored NAK */
- count--;
- temp++;
- wrcount++;
-@@ -377,12 +371,18 @@
- return wrcount;
- }
-
--static inline int readbytes(struct i2c_adapter *i2c_adap,char *buf,int count)
-+static inline int readbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msg)
- {
-- char *temp = buf;
- int inval;
- int rdcount=0; /* counts bytes read */
- struct i2c_algo_bit_data *adap = i2c_adap->algo_data;
-+ char *temp = msg->buf;
-+ int count = msg->len;
-+ int recv_len = 0;
-+
-+ /* Receive [Count] for I2C_SMBUS_BLOCK_DATA or I2C_SMBUS_BLOCK_PROC_CALL protocol */
-+ if (msg->flags & I2C_M_RECV_LEN)
-+ recv_len = 1;
-
- while (count > 0) {
- inval = i2c_inb(i2c_adap);
-@@ -395,6 +395,20 @@
- break;
- }
-
-+ if (recv_len) {
-+ recv_len = 0;
-+ /* [Count] should be between 1 and 31 (I2C_SMBUS_BLOCK_MAX - 1). */
-+ if (inval > 0 && inval < I2C_SMBUS_BLOCK_MAX) {
-+ count = inval + 1; /* plus one for [Count] itself */
-+ msg->len = count;
-+ if (msg->flags & I2C_M_RECV_PEC)
-+ count++; /* plus one for PEC */
-+ } else {
-+ printk(KERN_ERR "i2c-algo-bit.o: readbytes: bad block count (%d).\n", inval);
-+ break;
-+ }
-+ }
-+
- if ( count > 1 ) { /* send ack */
- sdalo(adap);
- DEBPROTO(printk(" Am "));
-@@ -419,31 +433,34 @@
- * try_address) and transmits the address in the necessary format to handle
- * reads, writes as well as 10bit-addresses.
- * returns:
-- * 0 everything went okay, the chip ack'ed
-+ * 0 everything went okay, the chip ack'ed, or IGNORE_NAK flag was set
- * -x an error occurred (like: -EREMOTEIO if the device did not answer, or
- * -ETIMEDOUT, for example if the lines are stuck...)
- */
--static inline int bit_doAddress(struct i2c_adapter *i2c_adap,
-- struct i2c_msg *msg, int retries)
-+static inline int bit_doAddress(struct i2c_adapter *i2c_adap, struct i2c_msg *msg)
- {
- unsigned short flags = msg->flags;
-+ unsigned short nak_ok = msg->flags & I2C_M_IGNORE_NAK;
- struct i2c_algo_bit_data *adap = i2c_adap->algo_data;
-
- unsigned char addr;
-- int ret;
-+ int ret, retries;
-+
-+ retries = nak_ok ? 0 : i2c_adap->retries;
-+
- if ( (flags & I2C_M_TEN) ) {
- /* a ten bit address */
- addr = 0xf0 | (( msg->addr >> 7) & 0x03);
- DEB2(printk(KERN_DEBUG "addr0: %d\n",addr));
- /* try extended address code...*/
- ret = try_address(i2c_adap, addr, retries);
-- if (ret!=1) {
-+ if ((ret != 1) && !nak_ok) {
- printk(KERN_ERR "died at extended address code.\n");
- return -EREMOTEIO;
- }
- /* the remaining 8 bit address */
- ret = i2c_outb(i2c_adap,msg->addr & 0x7f);
-- if (ret != 1) {
-+ if ((ret != 1) && !nak_ok) {
- /* the chip did not ack / xmission error occurred */
- printk(KERN_ERR "died at 2nd address code.\n");
- return -EREMOTEIO;
-@@ -453,7 +470,7 @@
- /* okay, now switch into reading mode */
- addr |= 0x01;
- ret = try_address(i2c_adap, addr, retries);
-- if (ret!=1) {
-+ if ((ret!=1) && !nak_ok) {
- printk(KERN_ERR "died at extended address code.\n");
- return -EREMOTEIO;
- }
-@@ -465,10 +482,10 @@
- if (flags & I2C_M_REV_DIR_ADDR )
- addr ^= 1;
- ret = try_address(i2c_adap, addr, retries);
-- if (ret!=1) {
-+ if ((ret!=1) && !nak_ok)
- return -EREMOTEIO;
-- }
- }
-+
- return 0;
- }
-
-@@ -479,16 +496,18 @@
- struct i2c_algo_bit_data *adap = i2c_adap->algo_data;
-
- int i,ret;
-+ unsigned short nak_ok;
-
- i2c_start(adap);
- for (i=0;i<num;i++) {
- pmsg = &msgs[i];
-+ nak_ok = pmsg->flags & I2C_M_IGNORE_NAK;
- if (!(pmsg->flags & I2C_M_NOSTART)) {
- if (i) {
- i2c_repstart(adap);
- }
-- ret = bit_doAddress(i2c_adap,pmsg,i2c_adap->retries);
-- if (ret != 0) {
-+ ret = bit_doAddress(i2c_adap, pmsg);
-+ if ((ret != 0) && !nak_ok) {
- DEB2(printk(KERN_DEBUG "i2c-algo-bit.o: NAK from device addr %2.2x msg #%d\n",
- msgs[i].addr,i));
- return (ret<0) ? ret : -EREMOTEIO;
-@@ -496,14 +515,14 @@
- }
- if (pmsg->flags & I2C_M_RD ) {
- /* read bytes into buffer*/
-- ret = readbytes(i2c_adap,pmsg->buf,pmsg->len);
-+ ret = readbytes(i2c_adap, pmsg);
- DEB2(printk(KERN_DEBUG "i2c-algo-bit.o: read %d bytes.\n",ret));
- if (ret < pmsg->len ) {
- return (ret<0)? ret : -EREMOTEIO;
- }
- } else {
- /* write bytes from buffer */
-- ret = sendbytes(i2c_adap,pmsg->buf,pmsg->len);
-+ ret = sendbytes(i2c_adap, pmsg);
- DEB2(printk(KERN_DEBUG "i2c-algo-bit.o: wrote %d bytes.\n",ret));
- if (ret < pmsg->len ) {
- return (ret<0) ? ret : -EREMOTEIO;
-@@ -514,30 +533,25 @@
- return num;
- }
-
--static int algo_control(struct i2c_adapter *adapter,
-- unsigned int cmd, unsigned long arg)
--{
-- return 0;
--}
--
--static u32 bit_func(struct i2c_adapter *adap)
-+static u32 bit_func(struct i2c_adapter *i2c_adap)
- {
- return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_10BIT_ADDR |
-- I2C_FUNC_PROTOCOL_MANGLING;
-+ I2C_FUNC_PROTOCOL_MANGLING |
-+ I2C_FUNC_SMBUS_BLOCK_PROC_CALL |
-+ I2C_FUNC_SMBUS_READ_BLOCK_DATA |
-+ I2C_FUNC_SMBUS_BLOCK_PROC_CALL_PEC |
-+ I2C_FUNC_SMBUS_READ_BLOCK_DATA_PEC;
- }
-
-
- /* -----exported algorithm data: ------------------------------------- */
-
- static struct i2c_algorithm i2c_bit_algo = {
-- "Bit-shift algorithm",
-- I2C_ALGO_BIT,
-- bit_xfer,
-- NULL,
-- NULL, /* slave_xmit */
-- NULL, /* slave_recv */
-- algo_control, /* ioctl */
-- bit_func, /* functionality */
-+ .owner = THIS_MODULE,
-+ .name = "Bit-shift algorithm",
-+ .id = I2C_ALGO_BIT,
-+ .master_xfer = bit_xfer,
-+ .functionality = bit_func,
- };
-
- /*
-@@ -545,7 +559,6 @@
- */
- int i2c_bit_add_bus(struct i2c_adapter *adap)
- {
-- int i;
- struct i2c_algo_bit_data *bit_adap = adap->algo_data;
-
- if (bit_test) {
-@@ -565,78 +578,26 @@
- adap->timeout = 100; /* default values, should */
- adap->retries = 3; /* be replaced by defines */
-
-- /* scan bus */
-- if (bit_scan) {
-- int ack;
-- printk(KERN_INFO " i2c-algo-bit.o: scanning bus %s.\n",
-- adap->name);
-- for (i = 0x00; i < 0xff; i+=2) {
-- i2c_start(bit_adap);
-- ack = i2c_outb(adap,i);
-- i2c_stop(bit_adap);
-- if (ack>0) {
-- printk("(%02x)",i>>1);
-- } else
-- printk(".");
-- }
-- printk("\n");
-- }
--
--#ifdef MODULE
-- MOD_INC_USE_COUNT;
--#endif
- i2c_add_adapter(adap);
--
- return 0;
- }
-
-
- int i2c_bit_del_bus(struct i2c_adapter *adap)
- {
-- int res;
--
-- if ((res = i2c_del_adapter(adap)) < 0)
-- return res;
--
-- DEB2(printk("i2c-algo-bit.o: adapter unregistered: %s\n",adap->name));
--
--#ifdef MODULE
-- MOD_DEC_USE_COUNT;
--#endif
-- return 0;
--}
--
--int __init i2c_algo_bit_init (void)
--{
-- printk(KERN_INFO "i2c-algo-bit.o: i2c bit algorithm module\n");
-- return 0;
-+ return i2c_del_adapter(adap);
- }
-
--
--
- EXPORT_SYMBOL(i2c_bit_add_bus);
- EXPORT_SYMBOL(i2c_bit_del_bus);
-
--#ifdef MODULE
- MODULE_AUTHOR("Simon G. Vogl <simon@tk.uni-linz.ac.at>");
- MODULE_DESCRIPTION("I2C-Bus bit-banging algorithm");
- MODULE_LICENSE("GPL");
-
- MODULE_PARM(bit_test, "i");
--MODULE_PARM(bit_scan, "i");
- MODULE_PARM(i2c_debug,"i");
-
- MODULE_PARM_DESC(bit_test, "Test the lines of the bus to see if it is stuck");
--MODULE_PARM_DESC(bit_scan, "Scan for active chips on the bus");
- MODULE_PARM_DESC(i2c_debug,
- "debug level - 0 off; 1 normal; 2,3 more verbose; 9 bit-protocol");
--
--int init_module(void)
--{
-- return i2c_algo_bit_init();
--}
--
--void cleanup_module(void)
--{
--}
--#endif
---- linux-old/include/linux/i2c-algo-bit.h Sat Feb 5 06:47:38 2000
-+++ linux/include/linux/i2c-algo-bit.h Mon Dec 13 19:26:28 2004
-@@ -21,12 +21,10 @@
- /* With some changes from Kyösti Mälkki <kmalkki@cc.hut.fi> and even
- Frodo Looijaard <frodol@dds.nl> */
-
--/* $Id: i2c-algo-bit.h,v 1.7 1999/12/21 23:45:58 frodo Exp $ */
-+/* $Id: i2c-algo-bit.h,v 1.11 2003/07/25 07:56:42 khali Exp $ */
-
--#ifndef I2C_ALGO_BIT_H
--#define I2C_ALGO_BIT_H 1
--
--#include <linux/i2c.h>
-+#ifndef _LINUX_I2C_ALGO_BIT_H
-+#define _LINUX_I2C_ALGO_BIT_H
-
- /* --- Defines for bit-adapters --------------------------------------- */
- /*
-@@ -42,9 +40,10 @@
- int (*getscl) (void *data);
-
- /* local settings */
-- int udelay;
-- int mdelay;
-- int timeout;
-+ int udelay; /* half-clock-cycle time in microsecs */
-+ /* i.e. clock is (500 / udelay) KHz */
-+ int mdelay; /* in millisecs, unused */
-+ int timeout; /* in jiffies */
- };
-
- #define I2C_BIT_ADAP_MAX 16
-@@ -52,4 +51,4 @@
- int i2c_bit_add_bus(struct i2c_adapter *);
- int i2c_bit_del_bus(struct i2c_adapter *);
-
--#endif /* I2C_ALGO_BIT_H */
-+#endif /* _LINUX_I2C_ALGO_BIT_H */
---- linux-old/drivers/i2c/i2c-algo-ibm_ocp.c Thu Jan 1 00:00:00 1970
-+++ linux/drivers/i2c/i2c-algo-ibm_ocp.c Mon Dec 13 19:26:29 2004
-@@ -0,0 +1,901 @@
-+/*
-+ -------------------------------------------------------------------------
-+ i2c-algo-ibm_ocp.c i2c driver algorithms for IBM PPC 405 adapters
-+ -------------------------------------------------------------------------
-+
-+ Ian DaSilva, MontaVista Software, Inc.
-+ idasilva@mvista.com or source@mvista.com
-+
-+ Copyright 2000 MontaVista Software Inc.
-+
-+ Changes made to support the IIC peripheral on the IBM PPC 405
-+
-+
-+ ---------------------------------------------------------------------------
-+ This file was highly leveraged from i2c-algo-pcf.c, which was created
-+ by Simon G. Vogl and Hans Berglund:
-+
-+
-+ Copyright (C) 1995-1997 Simon G. Vogl
-+ 1998-2000 Hans Berglund
-+
-+ With some changes from Kyösti Mälkki <kmalkki@cc.hut.fi> and
-+ Frodo Looijaard <frodol@dds.nl> ,and also from Martin Bailey
-+ <mbailey@littlefeet-inc.com>
-+
-+
-+ 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., 675 Mass Ave, Cambridge, MA 02139, USA.
-+ ---------------------------------------------------------------------------
-+
-+ History: 01/20/12 - Armin
-+ akuster@mvista.com
-+ ported up to 2.4.16+
-+
-+ Version 02/03/25 - Armin
-+ converted to ocp format
-+ removed commented out or #if 0 code
-+ added Gérard Basler's fix to iic_combined_transaction() such that it
-+ returns the number of successfully completed transfers .
-+*/
-+
-+
-+#include <linux/kernel.h>
-+#include <linux/module.h>
-+#include <linux/delay.h>
-+#include <linux/slab.h>
-+#include <linux/init.h>
-+#include <linux/errno.h>
-+#include <linux/sched.h>
-+#include <linux/i2c.h>
-+#include <linux/i2c-algo-ibm_ocp.h>
-+#include <asm/ocp.h>
-+
-+
-+/* ----- global defines ----------------------------------------------- */
-+#define DEB(x) if (i2c_debug>=1) x
-+#define DEB2(x) if (i2c_debug>=2) x
-+#define DEB3(x) if (i2c_debug>=3) x /* print several statistical values*/
-+#define DEBPROTO(x) if (i2c_debug>=9) x;
-+ /* debug the protocol by showing transferred bits */
-+#define DEF_TIMEOUT 5
-+
-+
-+/* ----- global variables --------------------------------------------- */
-+
-+
-+/* module parameters:
-+ */
-+static int i2c_debug=0;
-+
-+/* --- setting states on the bus with the right timing: --------------- */
-+
-+#define iic_outb(adap, reg, val) adap->setiic(adap->data, (int) &(reg), val)
-+#define iic_inb(adap, reg) adap->getiic(adap->data, (int) &(reg))
-+
-+#define IICO_I2C_SDAHIGH 0x0780
-+#define IICO_I2C_SDALOW 0x0781
-+#define IICO_I2C_SCLHIGH 0x0782
-+#define IICO_I2C_SCLLOW 0x0783
-+#define IICO_I2C_LINEREAD 0x0784
-+
-+#define IIC_SINGLE_XFER 0
-+#define IIC_COMBINED_XFER 1
-+
-+#define IIC_ERR_LOST_ARB -2
-+#define IIC_ERR_INCOMPLETE_XFR -3
-+#define IIC_ERR_NACK -1
-+
-+/* --- other auxiliary functions -------------------------------------- */
-+
-+
-+//
-+// Description: Puts this process to sleep for a period equal to timeout
-+//
-+static inline void iic_sleep(unsigned long timeout)
-+{
-+ schedule_timeout( timeout * HZ);
-+}
-+
-+
-+//
-+// Description: This performs the IBM PPC 405 IIC initialization sequence
-+// as described in the PPC405GP data book.
-+//
-+static int iic_init (struct i2c_algo_iic_data *adap)
-+{
-+ struct iic_regs *iic;
-+ struct iic_ibm *adap_priv_data = adap->data;
-+ unsigned short retval;
-+ iic = (struct iic_regs *) adap_priv_data->iic_base;
-+
-+ /* Clear master low master address */
-+ iic_outb(adap,iic->lmadr, 0);
-+
-+ /* Clear high master address */
-+ iic_outb(adap,iic->hmadr, 0);
-+
-+ /* Clear low slave address */
-+ iic_outb(adap,iic->lsadr, 0);
-+
-+ /* Clear high slave address */
-+ iic_outb(adap,iic->hsadr, 0);
-+
-+ /* Clear status */
-+ iic_outb(adap,iic->sts, 0x0a);
-+
-+ /* Clear extended status */
-+ iic_outb(adap,iic->extsts, 0x8f);
-+
-+ /* Set clock division */
-+ iic_outb(adap,iic->clkdiv, 0x04);
-+
-+ retval = iic_inb(adap, iic->clkdiv);
-+ DEB(printk("iic_init: CLKDIV register = %x\n", retval));
-+
-+ /* Enable interrupts on Requested Master Transfer Complete */
-+ iic_outb(adap,iic->intmsk, 0x01);
-+
-+ /* Clear transfer count */
-+ iic_outb(adap,iic->xfrcnt, 0x0);
-+
-+ /* Clear extended control and status */
-+ iic_outb(adap,iic->xtcntlss, 0xf0);
-+
-+ /* Set mode control (flush master data buf, enable hold SCL, exit */
-+ /* unknown state. */
-+ iic_outb(adap,iic->mdcntl, 0x47);
-+
-+ /* Clear control register */
-+ iic_outb(adap,iic->cntl, 0x0);
-+
-+ DEB2(printk(KERN_DEBUG "iic_init: Initialized IIC on PPC 405\n"));
-+ return 0;
-+}
-+
-+
-+//
-+// Description: After we issue a transaction on the IIC bus, this function
-+// is called. It puts this process to sleep until we get an interrupt from
-+// from the controller telling us that the transaction we requested in complete.
-+//
-+static int wait_for_pin(struct i2c_algo_iic_data *adap, int *status)
-+{
-+
-+ int timeout = DEF_TIMEOUT;
-+ int retval;
-+ struct iic_regs *iic;
-+ struct iic_ibm *adap_priv_data = adap->data;
-+ iic = (struct iic_regs *) adap_priv_data->iic_base;
-+
-+
-+ *status = iic_inb(adap, iic->sts);
-+#ifndef STUB_I2C
-+
-+ while (timeout-- && (*status & 0x01)) {
-+ adap->waitforpin(adap->data);
-+ *status = iic_inb(adap, iic->sts);
-+ }
-+#endif
-+ if (timeout <= 0) {
-+ /* Issue stop signal on the bus, and force an interrupt */
-+ retval = iic_inb(adap, iic->cntl);
-+ iic_outb(adap, iic->cntl, retval | 0x80);
-+ /* Clear status register */
-+ iic_outb(adap, iic->sts, 0x0a);
-+ /* Exit unknown bus state */
-+ retval = iic_inb(adap, iic->mdcntl);
-+ iic_outb(adap, iic->mdcntl, (retval | 0x02));
-+
-+ // Check the status of the controller. Does it still see a
-+ // pending transfer, even though we've tried to stop any
-+ // ongoing transaction?
-+ retval = iic_inb(adap, iic->sts);
-+ retval = retval & 0x01;
-+ if(retval) {
-+ // The iic controller is hosed. It is not responding to any
-+ // of our commands. We have already tried to force it into
-+ // a known state, but it has not worked. Our only choice now
-+ // is a soft reset, which will clear all registers, and force
-+ // us to re-initialize the controller.
-+ /* Soft reset */
-+ iic_outb(adap, iic->xtcntlss, 0x01);
-+ udelay(500);
-+ iic_init(adap);
-+ /* Is the pending transfer bit in the sts reg finally cleared? */
-+ retval = iic_inb(adap, iic->sts);
-+ retval = retval & 0x01;
-+ if(retval) {
-+ printk(KERN_CRIT "The IIC Controller is hosed. A processor reset is required\n");
-+ }
-+ // For some reason, even though the interrupt bit in this
-+ // register was set during iic_init, it didn't take. We
-+ // need to set it again. Don't ask me why....this is just what
-+ // I saw when testing timeouts.
-+ iic_outb(adap, iic->intmsk, 0x01);
-+ }
-+ return(-1);
-+ }
-+ else
-+ return(0);
-+}
-+
-+
-+//------------------------------------
-+// Utility functions
-+//
-+
-+
-+//
-+// Description: Look at the status register to see if there was an error
-+// in the requested transaction. If there is, look at the extended status
-+// register and determine the exact cause.
-+//
-+int analyze_status(struct i2c_algo_iic_data *adap, int *error_code)
-+{
-+ int ret;
-+ struct iic_regs *iic;
-+ struct iic_ibm *adap_priv_data = adap->data;
-+ iic = (struct iic_regs *) adap_priv_data->iic_base;
-+
-+
-+ ret = iic_inb(adap, iic->sts);
-+ if(ret & 0x04) {
-+ // Error occurred
-+ ret = iic_inb(adap, iic->extsts);
-+ if(ret & 0x04) {
-+ // Lost arbitration
-+ *error_code = IIC_ERR_LOST_ARB;
-+ }
-+ if(ret & 0x02) {
-+ // Incomplete transfer
-+ *error_code = IIC_ERR_INCOMPLETE_XFR;
-+ }
-+ if(ret & 0x01) {
-+ // Master transfer aborted by a NACK during the transfer of the
-+ // address byte
-+ *error_code = IIC_ERR_NACK;
-+ }
-+ return -1;
-+ }
-+ return 0;
-+}
-+
-+
-+//
-+// Description: This function is called by the upper layers to do the
-+// grunt work for a master send transaction
-+//
-+static int iic_sendbytes(struct i2c_adapter *i2c_adap,const char *buf,
-+ int count, int xfer_flag)
-+{
-+ struct iic_regs *iic;
-+ struct i2c_algo_iic_data *adap = i2c_adap->algo_data;
-+ struct iic_ibm *adap_priv_data = adap->data;
-+ int wrcount, status, timeout;
-+ int loops, remainder, i, j;
-+ int ret, error_code;
-+ iic = (struct iic_regs *) adap_priv_data->iic_base;
-+
-+
-+ if( count == 0 ) return 0;
-+ wrcount = 0;
-+ loops = count / 4;
-+ remainder = count % 4;
-+
-+ if((loops > 1) && (remainder == 0)) {
-+ for(i=0; i<(loops-1); i++) {
-+ //
-+ // Write four bytes to master data buffer
-+ //
-+ for(j=0; j<4; j++) {
-+ iic_outb(adap, iic->mdbuf,
-+ buf[wrcount++]);
-+ }
-+ //
-+ // Issue command to IICO device to begin transmission
-+ //
-+ iic_outb(adap, iic->cntl, 0x35);
-+ //
-+ // Wait for transmission to complete. When it does,
-+ //loop to the top of the for statement and write the
-+ // next four bytes.
-+ //
-+ timeout = wait_for_pin(adap, &status);
-+ if(timeout < 0) {
-+ //
-+ // Error handling
-+ //
-+ //printk(KERN_ERR "Error: write timeout\n");
-+ return wrcount;
-+ }
-+ ret = analyze_status(adap, &error_code);
-+ if(ret < 0) {
-+ if(error_code == IIC_ERR_INCOMPLETE_XFR) {
-+ // Return the number of bytes transferred
-+ ret = iic_inb(adap, iic->xfrcnt);
-+ ret = ret & 0x07;
-+ return (wrcount-4+ret);
-+ }
-+ else return error_code;
-+ }
-+ }
-+ }
-+ else if((loops >= 1) && (remainder > 0)){
-+ //printk(KERN_DEBUG "iic_sendbytes: (loops >= 1)\n");
-+ for(i=0; i<loops; i++) {
-+ //
-+ // Write four bytes to master data buffer
-+ //
-+ for(j=0; j<4; j++) {
-+ iic_outb(adap, iic->mdbuf,
-+ buf[wrcount++]);
-+ }
-+ //
-+ // Issue command to IICO device to begin transmission
-+ //
-+ iic_outb(adap, iic->cntl, 0x35);
-+ //
-+ // Wait for transmission to complete. When it does,
-+ //loop to the top of the for statement and write the
-+ // next four bytes.
-+ //
-+ timeout = wait_for_pin(adap, &status);
-+ if(timeout < 0) {
-+ //
-+ // Error handling
-+ //
-+ //printk(KERN_ERR "Error: write timeout\n");
-+ return wrcount;
-+ }
-+ ret = analyze_status(adap, &error_code);
-+ if(ret < 0) {
-+ if(error_code == IIC_ERR_INCOMPLETE_XFR) {
-+ // Return the number of bytes transferred
-+ ret = iic_inb(adap, iic->xfrcnt);
-+ ret = ret & 0x07;
-+ return (wrcount-4+ret);
-+ }
-+ else return error_code;
-+ }
-+ }
-+ }
-+
-+ //printk(KERN_DEBUG "iic_sendbytes: expedite write\n");
-+ if(remainder == 0) remainder = 4;
-+ // remainder = remainder - 1;
-+ //
-+ // Write the remaining bytes (less than or equal to 4)
-+ //
-+ for(i=0; i<remainder; i++) {
-+ iic_outb(adap, iic->mdbuf, buf[wrcount++]);
-+ //printk(KERN_DEBUG "iic_sendbytes: data transferred = %x, wrcount = %d\n", buf[wrcount-1], (wrcount-1));
-+ }
-+ //printk(KERN_DEBUG "iic_sendbytes: Issuing write\n");
-+
-+ if(xfer_flag == IIC_COMBINED_XFER) {
-+ iic_outb(adap, iic->cntl, (0x09 | ((remainder-1) << 4)));
-+ }
-+ else {
-+ iic_outb(adap, iic->cntl, (0x01 | ((remainder-1) << 4)));
-+ }
-+ DEB2(printk(KERN_DEBUG "iic_sendbytes: Waiting for interrupt\n"));
-+ timeout = wait_for_pin(adap, &status);
-+ if(timeout < 0) {
-+ //
-+ // Error handling
-+ //
-+ //printk(KERN_ERR "Error: write timeout\n");
-+ return wrcount;
-+ }
-+ ret = analyze_status(adap, &error_code);
-+ if(ret < 0) {
-+ if(error_code == IIC_ERR_INCOMPLETE_XFR) {
-+ // Return the number of bytes transferred
-+ ret = iic_inb(adap, iic->xfrcnt);
-+ ret = ret & 0x07;
-+ return (wrcount-4+ret);
-+ }
-+ else return error_code;
-+ }
-+ DEB2(printk(KERN_DEBUG "iic_sendbytes: Got interrupt\n"));
-+ return wrcount;
-+}
-+
-+
-+//
-+// Description: Called by the upper layers to do the grunt work for
-+// a master read transaction.
-+//
-+static int iic_readbytes(struct i2c_adapter *i2c_adap, char *buf, int count, int xfer_type)
-+{
-+ struct iic_regs *iic;
-+ int rdcount=0, i, status, timeout;
-+ struct i2c_algo_iic_data *adap = i2c_adap->algo_data;
-+ struct iic_ibm *adap_priv_data = adap->data;
-+ int loops, remainder, j;
-+ int ret, error_code;
-+ iic = (struct iic_regs *) adap_priv_data->iic_base;
-+
-+ if(count == 0) return 0;
-+ loops = count / 4;
-+ remainder = count % 4;
-+
-+ //printk(KERN_DEBUG "iic_readbytes: loops = %d, remainder = %d\n", loops, remainder);
-+
-+ if((loops > 1) && (remainder == 0)) {
-+ //printk(KERN_DEBUG "iic_readbytes: (loops > 1) && (remainder == 0)\n");
-+ for(i=0; i<(loops-1); i++) {
-+ //
-+ // Issue command to begin master read (4 bytes maximum)
-+ //
-+ //printk(KERN_DEBUG "--->Issued read command\n");
-+ iic_outb(adap, iic->cntl, 0x37);
-+ //
-+ // Wait for transmission to complete. When it does,
-+ // loop to the top of the for statement and write the
-+ // next four bytes.
-+ //
-+ //printk(KERN_DEBUG "--->Waiting for interrupt\n");
-+ timeout = wait_for_pin(adap, &status);
-+ if(timeout < 0) {
-+ // Error Handler
-+ //printk(KERN_ERR "Error: read timed out\n");
-+ return rdcount;
-+ }
-+ //printk(KERN_DEBUG "--->Got interrupt\n");
-+
-+ ret = analyze_status(adap, &error_code);
-+ if(ret < 0) {
-+ if(error_code == IIC_ERR_INCOMPLETE_XFR)
-+ return rdcount;
-+ else
-+ return error_code;
-+ }
-+
-+ for(j=0; j<4; j++) {
-+ // Wait for data to shuffle to top of data buffer
-+ // This value needs to optimized.
-+ udelay(1);
-+ buf[rdcount] = iic_inb(adap, iic->mdbuf);
-+ rdcount++;
-+ //printk(KERN_DEBUG "--->Read one byte\n");
-+ }
-+ }
-+ }
-+
-+ else if((loops >= 1) && (remainder > 0)){
-+ //printk(KERN_DEBUG "iic_readbytes: (loops >=1) && (remainder > 0)\n");
-+ for(i=0; i<loops; i++) {
-+ //
-+ // Issue command to begin master read (4 bytes maximum)
-+ //
-+ //printk(KERN_DEBUG "--->Issued read command\n");
-+ iic_outb(adap, iic->cntl, 0x37);
-+ //
-+ // Wait for transmission to complete. When it does,
-+ // loop to the top of the for statement and write the
-+ // next four bytes.
-+ //
-+ //printk(KERN_DEBUG "--->Waiting for interrupt\n");
-+ timeout = wait_for_pin(adap, &status);
-+ if(timeout < 0) {
-+ // Error Handler
-+ //printk(KERN_ERR "Error: read timed out\n");
-+ return rdcount;
-+ }
-+ //printk(KERN_DEBUG "--->Got interrupt\n");
-+
-+ ret = analyze_status(adap, &error_code);
-+ if(ret < 0) {
-+ if(error_code == IIC_ERR_INCOMPLETE_XFR)
-+ return rdcount;
-+ else
-+ return error_code;
-+ }
-+
-+ for(j=0; j<4; j++) {
-+ // Wait for data to shuffle to top of data buffer
-+ // This value needs to optimized.
-+ udelay(1);
-+ buf[rdcount] = iic_inb(adap, iic->mdbuf);
-+ rdcount++;
-+ //printk(KERN_DEBUG "--->Read one byte\n");
-+ }
-+ }
-+ }
-+
-+ //printk(KERN_DEBUG "iic_readbytes: expedite read\n");
-+ if(remainder == 0) remainder = 4;
-+ DEB2(printk(KERN_DEBUG "iic_readbytes: writing %x to IICO_CNTL\n", (0x03 | ((remainder-1) << 4))));
-+
-+ if(xfer_type == IIC_COMBINED_XFER) {
-+ iic_outb(adap, iic->cntl, (0x0b | ((remainder-1) << 4)));
-+ }
-+ else {
-+ iic_outb(adap, iic->cntl, (0x03 | ((remainder-1) << 4)));
-+ }
-+ DEB2(printk(KERN_DEBUG "iic_readbytes: Wait for pin\n"));
-+ timeout = wait_for_pin(adap, &status);
-+ DEB2(printk(KERN_DEBUG "iic_readbytes: Got the interrupt\n"));
-+ if(timeout < 0) {
-+ // Error Handler
-+ //printk(KERN_ERR "Error: read timed out\n");
-+ return rdcount;
-+ }
-+
-+ ret = analyze_status(adap, &error_code);
-+ if(ret < 0) {
-+ if(error_code == IIC_ERR_INCOMPLETE_XFR)
-+ return rdcount;
-+ else
-+ return error_code;
-+ }
-+
-+ //printk(KERN_DEBUG "iic_readbyte: Begin reading data buffer\n");
-+ for(i=0; i<remainder; i++) {
-+ buf[rdcount] = iic_inb(adap, iic->mdbuf);
-+ // printk(KERN_DEBUG "iic_readbytes: Character read = %x\n", buf[rdcount]);
-+ rdcount++;
-+ }
-+
-+ return rdcount;
-+}
-+
-+
-+//
-+// Description: This function implements combined transactions. Combined
-+// transactions consist of combinations of reading and writing blocks of data.
-+// Each transfer (i.e. a read or a write) is separated by a repeated start
-+// condition.
-+//
-+static int iic_combined_transaction(struct i2c_adapter *i2c_adap, struct i2c_msg msgs[], int num)
-+{
-+ int i;
-+ struct i2c_msg *pmsg;
-+ int ret;
-+
-+ DEB2(printk(KERN_DEBUG "Beginning combined transaction\n"));
-+ for(i=0; i < num; i++) {
-+ pmsg = &msgs[i];
-+ if(pmsg->flags & I2C_M_RD) {
-+
-+ // Last read or write segment needs to be terminated with a stop
-+ if(i < num-1) {
-+ DEB2(printk(KERN_DEBUG "This one is a read\n"));
-+ }
-+ else {
-+ DEB2(printk(KERN_DEBUG "Doing the last read\n"));
-+ }
-+ ret = iic_readbytes(i2c_adap, pmsg->buf, pmsg->len, (i < num-1) ? IIC_COMBINED_XFER : IIC_SINGLE_XFER);
-+
-+ if (ret != pmsg->len) {
-+ DEB2(printk("i2c-algo-ppc405.o: fail: "
-+ "only read %d bytes.\n",ret));
-+ return i;
-+ }
-+ else {
-+ DEB2(printk("i2c-algo-ppc405.o: read %d bytes.\n",ret));
-+ }
-+ }
-+ else if(!(pmsg->flags & I2C_M_RD)) {
-+
-+ // Last read or write segment needs to be terminated with a stop
-+ if(i < num-1) {
-+ DEB2(printk(KERN_DEBUG "This one is a write\n"));
-+ }
-+ else {
-+ DEB2(printk(KERN_DEBUG "Doing the last write\n"));
-+ }
-+ ret = iic_sendbytes(i2c_adap, pmsg->buf, pmsg->len, (i < num-1) ? IIC_COMBINED_XFER : IIC_SINGLE_XFER);
-+
-+ if (ret != pmsg->len) {
-+ DEB2(printk("i2c-algo-ppc405.o: fail: "
-+ "only wrote %d bytes.\n",ret));
-+ return i;
-+ }
-+ else {
-+ DEB2(printk("i2c-algo-ppc405.o: wrote %d bytes.\n",ret));
-+ }
-+ }
-+ }
-+
-+ return num;
-+}
-+
-+
-+//
-+// Description: Whenever we initiate a transaction, the first byte clocked
-+// onto the bus after the start condition is the address (7 bit) of the
-+// device we want to talk to. This function manipulates the address specified
-+// so that it makes sense to the hardware when written to the IIC peripheral.
-+//
-+// Note: 10 bit addresses are not supported in this driver, although they are
-+// supported by the hardware. This functionality needs to be implemented.
-+//
-+static inline int iic_doAddress(struct i2c_algo_iic_data *adap,
-+ struct i2c_msg *msg, int retries)
-+{
-+ struct iic_regs *iic;
-+ unsigned short flags = msg->flags;
-+ unsigned char addr;
-+ struct iic_ibm *adap_priv_data = adap->data;
-+ iic = (struct iic_regs *) adap_priv_data->iic_base;
-+
-+//
-+// The following segment for 10 bit addresses needs to be ported
-+//
-+/* Ten bit addresses not supported right now
-+ if ( (flags & I2C_M_TEN) ) {
-+ // a ten bit address
-+ addr = 0xf0 | (( msg->addr >> 7) & 0x03);
-+ DEB2(printk(KERN_DEBUG "addr0: %d\n",addr));
-+ // try extended address code...
-+ ret = try_address(adap, addr, retries);
-+ if (ret!=1) {
-+ printk(KERN_ERR "iic_doAddress: died at extended address code.\n");
-+ return -EREMOTEIO;
-+ }
-+ // the remaining 8 bit address
-+ iic_outb(adap,msg->addr & 0x7f);
-+ // Status check comes here
-+ if (ret != 1) {
-+ printk(KERN_ERR "iic_doAddress: died at 2nd address code.\n");
-+ return -EREMOTEIO;
-+ }
-+ if ( flags & I2C_M_RD ) {
-+ i2c_repstart(adap);
-+ // okay, now switch into reading mode
-+ addr |= 0x01;
-+ ret = try_address(adap, addr, retries);
-+ if (ret!=1) {
-+ printk(KERN_ERR "iic_doAddress: died at extended address code.\n");
-+ return -EREMOTEIO;
-+ }
-+ }
-+ } else ----------> // normal 7 bit address
-+
-+Ten bit addresses not supported yet */
-+
-+ addr = ( msg->addr << 1 );
-+ if (flags & I2C_M_RD )
-+ addr |= 1;
-+ if (flags & I2C_M_REV_DIR_ADDR )
-+ addr ^= 1;
-+ //
-+ // Write to the low slave address
-+ //
-+ iic_outb(adap, iic->lmadr, addr);
-+ //
-+ // Write zero to the high slave register since we are
-+ // only using 7 bit addresses
-+ //
-+ iic_outb(adap, iic->hmadr, 0);
-+
-+ return 0;
-+}
-+
-+
-+//
-+// Description: Prepares the controller for a transaction (clearing status
-+// registers, data buffers, etc), and then calls either iic_readbytes or
-+// iic_sendbytes to do the actual transaction.
-+//
-+static int iic_xfer(struct i2c_adapter *i2c_adap,
-+ struct i2c_msg msgs[],
-+ int num)
-+{
-+ struct iic_regs *iic;
-+ struct i2c_algo_iic_data *adap = i2c_adap->algo_data;
-+ struct iic_ibm *adap_priv_data = adap->data;
-+ struct i2c_msg *pmsg;
-+ int i = 0;
-+ int ret;
-+ iic = (struct iic_regs *) adap_priv_data->iic_base;
-+
-+ pmsg = &msgs[i];
-+
-+ //
-+ // Clear status register
-+ //
-+ DEB2(printk(KERN_DEBUG "iic_xfer: iic_xfer: Clearing status register\n"));
-+ iic_outb(adap, iic->sts, 0x0a);
-+
-+ //
-+ // Wait for any pending transfers to complete
-+ //
-+ DEB2(printk(KERN_DEBUG "iic_xfer: Waiting for any pending transfers to complete\n"));
-+ while((ret = iic_inb(adap, iic->sts)) == 0x01) {
-+ ;
-+ }
-+
-+ //
-+ // Flush master data buf
-+ //
-+ DEB2(printk(KERN_DEBUG "iic_xfer: Clearing master data buffer\n"));
-+ ret = iic_inb(adap, iic->mdcntl);
-+ iic_outb(adap, iic->mdcntl, ret | 0x40);
-+
-+ //
-+ // Load slave address
-+ //
-+ DEB2(printk(KERN_DEBUG "iic_xfer: Loading slave address\n"));
-+ ret = iic_doAddress(adap, pmsg, i2c_adap->retries);
-+
-+ //
-+ // Check to see if the bus is busy
-+ //
-+ ret = iic_inb(adap, iic->extsts);
-+ // Mask off the irrelevent bits
-+ ret = ret & 0x70;
-+ // When the bus is free, the BCS bits in the EXTSTS register are 0b100
-+ if(ret != 0x40) return IIC_ERR_LOST_ARB;
-+
-+ //
-+ // Combined transaction (read and write)
-+ //
-+ if(num > 1) {
-+ DEB2(printk(KERN_DEBUG "iic_xfer: Call combined transaction\n"));
-+ ret = iic_combined_transaction(i2c_adap, msgs, num);
-+ }
-+ //
-+ // Read only
-+ //
-+ else if((num == 1) && (pmsg->flags & I2C_M_RD)) {
-+ //
-+ // Tell device to begin reading data from the master data
-+ //
-+ DEB2(printk(KERN_DEBUG "iic_xfer: Call adapter's read\n"));
-+ ret = iic_readbytes(i2c_adap, pmsg->buf, pmsg->len, IIC_SINGLE_XFER);
-+ }
-+ //
-+ // Write only
-+ //
-+ else if((num == 1 ) && (!(pmsg->flags & I2C_M_RD))) {
-+ //
-+ // Write data to master data buffers and tell our device
-+ // to begin transmitting
-+ //
-+ DEB2(printk(KERN_DEBUG "iic_xfer: Call adapter's write\n"));
-+ ret = iic_sendbytes(i2c_adap, pmsg->buf, pmsg->len, IIC_SINGLE_XFER);
-+ }
-+
-+ return ret;
-+}
-+
-+
-+//
-+// Description: Implements device specific ioctls. Higher level ioctls can
-+// be found in i2c-core.c and are typical of any i2c controller (specifying
-+// slave address, timeouts, etc). These ioctls take advantage of any hardware
-+// features built into the controller for which this algorithm-adapter set
-+// was written. These ioctls allow you to take control of the data and clock
-+// lines on the IBM PPC 405 IIC controller and set the either high or low,
-+// similar to a GPIO pin.
-+//
-+static int algo_control(struct i2c_adapter *adapter,
-+ unsigned int cmd, unsigned long arg)
-+{
-+ struct iic_regs *iic;
-+ struct i2c_algo_iic_data *adap = adapter->algo_data;
-+ struct iic_ibm *adap_priv_data = adap->data;
-+ int ret=0;
-+ int lines;
-+ iic = (struct iic_regs *) adap_priv_data->iic_base;
-+
-+ lines = iic_inb(adap, iic->directcntl);
-+
-+ if (cmd == IICO_I2C_SDAHIGH) {
-+ lines = lines & 0x01;
-+ if( lines ) lines = 0x04;
-+ else lines = 0;
-+ iic_outb(adap, iic->directcntl,(0x08|lines));
-+ }
-+ else if (cmd == IICO_I2C_SDALOW) {
-+ lines = lines & 0x01;
-+ if( lines ) lines = 0x04;
-+ else lines = 0;
-+ iic_outb(adap, iic->directcntl,(0x00|lines));
-+ }
-+ else if (cmd == IICO_I2C_SCLHIGH) {
-+ lines = lines & 0x02;
-+ if( lines ) lines = 0x08;
-+ else lines = 0;
-+ iic_outb(adap, iic->directcntl,(0x04|lines));
-+ }
-+ else if (cmd == IICO_I2C_SCLLOW) {
-+ lines = lines & 0x02;
-+ if( lines ) lines = 0x08;
-+ else lines = 0;
-+ iic_outb(adap, iic->directcntl,(0x00|lines));
-+ }
-+ else if (cmd == IICO_I2C_LINEREAD) {
-+ ret = lines;
-+ }
-+ return ret;
-+}
-+
-+
-+static u32 iic_func(struct i2c_adapter *adap)
-+{
-+ return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_10BIT_ADDR |
-+ I2C_FUNC_PROTOCOL_MANGLING;
-+}
-+
-+
-+/* -----exported algorithm data: ------------------------------------- */
-+
-+static struct i2c_algorithm iic_algo = {
-+ .owner = THIS_MODULE,
-+ .name = "IBM on-chip IIC algorithm",
-+ .id = I2C_ALGO_OCP,
-+ .master_xfer = iic_xfer,
-+ .algo_control = algo_control,
-+ .functionality = iic_func,
-+};
-+
-+/*
-+ * registering functions to load algorithms at runtime
-+ */
-+
-+
-+//
-+// Description: Register bus structure
-+//
-+int i2c_ocp_add_bus(struct i2c_adapter *adap)
-+{
-+ struct i2c_algo_iic_data *iic_adap = adap->algo_data;
-+
-+ DEB2(printk(KERN_DEBUG "i2c-algo-iic.o: hw routines for %s registered.\n",
-+ adap->name));
-+
-+ /* register new adapter to i2c module... */
-+
-+ adap->id |= iic_algo.id;
-+ adap->algo = &iic_algo;
-+
-+ adap->timeout = 100; /* default values, should */
-+ adap->retries = 3; /* be replaced by defines */
-+
-+ iic_init(iic_adap);
-+ i2c_add_adapter(adap);
-+ return 0;
-+}
-+
-+
-+//
-+// Done
-+//
-+int i2c_ocp_del_bus(struct i2c_adapter *adap)
-+{
-+ return i2c_del_adapter(adap);
-+}
-+
-+
-+EXPORT_SYMBOL(i2c_ocp_add_bus);
-+EXPORT_SYMBOL(i2c_ocp_del_bus);
-+
-+//
-+// The MODULE_* macros resolve to nothing if MODULES is not defined
-+// when this file is compiled.
-+//
-+MODULE_AUTHOR("MontaVista Software <www.mvista.com>");
-+MODULE_DESCRIPTION("PPC 405 iic algorithm");
-+MODULE_LICENSE("GPL");
-+
-+MODULE_PARM(i2c_debug,"i");
-+
-+MODULE_PARM_DESC(i2c_debug,
-+ "debug level - 0 off; 1 normal; 2,3 more verbose; 9 iic-protocol");
-+
---- linux-old/include/linux/i2c-algo-ibm_ocp.h Thu Jan 1 00:00:00 1970
-+++ linux/include/linux/i2c-algo-ibm_ocp.h Mon Dec 13 19:26:29 2004
-@@ -0,0 +1,52 @@
-+/* ------------------------------------------------------------------------- */
-+/* i2c-algo-ibm_ocp.h i2c driver algorithms for IBM PPC 405 IIC adapters */
-+/* ------------------------------------------------------------------------- */
-+/* Copyright (C) 1995-97 Simon G. Vogl
-+ 1998-99 Hans Berglund
-+
-+ 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., 675 Mass Ave, Cambridge, MA 02139, USA. */
-+/* ------------------------------------------------------------------------- */
-+
-+/* With some changes from Kyösti Mälkki <kmalkki@cc.hut.fi> and even
-+ Frodo Looijaard <frodol@dds.nl> */
-+
-+/* Modifications by MontaVista Software, August 2000
-+ Changes made to support the IIC peripheral on the IBM PPC 405 */
-+
-+#ifndef _LINUX_I2C_ALGO_IBM_OCP_H
-+#define _LINUX_I2C_ALGO_IBM_OCP_H
-+
-+struct i2c_algo_iic_data {
-+ struct iic_regs *data; /* private data for lolevel routines */
-+ void (*setiic) (void *data, int ctl, int val);
-+ int (*getiic) (void *data, int ctl);
-+ int (*getown) (void *data);
-+ int (*getclock) (void *data);
-+ void (*waitforpin) (void *data);
-+
-+ /* local settings */
-+ int udelay;
-+ int mdelay;
-+ int timeout;
-+};
-+
-+
-+#define I2C_IIC_ADAP_MAX 16
-+
-+
-+int i2c_ocp_add_bus(struct i2c_adapter *);
-+int i2c_ocp_del_bus(struct i2c_adapter *);
-+
-+#endif /* _LINUX_I2C_ALGO_IBM_OCP_H */
---- linux-old/drivers/i2c/i2c-algo-pcf.c Tue Jan 20 15:10:31 2004
-+++ linux/drivers/i2c/i2c-algo-pcf.c Mon Dec 13 19:26:29 2004
-@@ -32,14 +32,11 @@
- #include <linux/delay.h>
- #include <linux/slab.h>
- #include <linux/init.h>
--#include <asm/uaccess.h>
--#include <linux/ioport.h>
- #include <linux/errno.h>
- #include <linux/sched.h>
--
- #include <linux/i2c.h>
- #include <linux/i2c-algo-pcf.h>
--#include "i2c-pcf8584.h"
-+
-
- /* ----- global defines ----------------------------------------------- */
- #define DEB(x) if (i2c_debug>=1) x
-@@ -52,7 +49,6 @@
- /* module parameters:
- */
- static int i2c_debug=0;
--static int pcf_scan=0; /* have a look at what's hanging 'round */
-
- /* --- setting states on the bus with the right timing: --------------- */
-
-@@ -149,8 +145,7 @@
- set_pcf(adap, 1, I2C_PCF_PIN);
- /* check to see S1 now used as R/W ctrl -
- PCF8584 does that when ESO is zero */
-- /* PCF also resets PIN bit */
-- if ((temp = get_pcf(adap, 1)) != (0)) {
-+ if (((temp = get_pcf(adap, 1)) & 0x7f) != (0)) {
- DEB2(printk(KERN_ERR "i2c-algo-pcf.o: PCF detection failed -- can't select S0 (0x%02x).\n", temp));
- return -ENXIO; /* definetly not PCF8584 */
- }
-@@ -166,7 +161,7 @@
- /* S1=0xA0, next byte in S2 */
- set_pcf(adap, 1, I2C_PCF_PIN | I2C_PCF_ES1);
- /* check to see S2 now selected */
-- if ((temp = get_pcf(adap, 1)) != I2C_PCF_ES1) {
-+ if (((temp = get_pcf(adap, 1)) & 0x7f) != I2C_PCF_ES1) {
- DEB2(printk(KERN_ERR "i2c-algo-pcf.o: PCF detection failed -- can't select S2 (0x%02x).\n", temp));
- return -ENXIO;
- }
-@@ -427,12 +422,6 @@
- return (i);
- }
-
--static int algo_control(struct i2c_adapter *adapter,
-- unsigned int cmd, unsigned long arg)
--{
-- return 0;
--}
--
- static u32 pcf_func(struct i2c_adapter *adap)
- {
- return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_10BIT_ADDR |
-@@ -442,14 +431,11 @@
- /* -----exported algorithm data: ------------------------------------- */
-
- static struct i2c_algorithm pcf_algo = {
-- "PCF8584 algorithm",
-- I2C_ALGO_PCF,
-- pcf_xfer,
-- NULL,
-- NULL, /* slave_xmit */
-- NULL, /* slave_recv */
-- algo_control, /* ioctl */
-- pcf_func, /* functionality */
-+ .owner = THIS_MODULE,
-+ .name = "PCF8584 algorithm",
-+ .id = I2C_ALGO_PCF,
-+ .master_xfer = pcf_xfer,
-+ .functionality = pcf_func,
- };
-
- /*
-@@ -457,7 +443,7 @@
- */
- int i2c_pcf_add_bus(struct i2c_adapter *adap)
- {
-- int i, status;
-+ int i;
- struct i2c_algo_pcf_data *pcf_adap = adap->algo_data;
-
- DEB2(printk(KERN_DEBUG "i2c-algo-pcf.o: hw routines for %s registered.\n",
-@@ -475,81 +461,23 @@
- return i;
- }
-
--#ifdef MODULE
-- MOD_INC_USE_COUNT;
--#endif
--
- i2c_add_adapter(adap);
--
-- /* scan bus */
-- if (pcf_scan) {
-- printk(KERN_INFO " i2c-algo-pcf.o: scanning bus %s.\n",
-- adap->name);
-- for (i = 0x00; i < 0xff; i+=2) {
-- if (wait_for_bb(pcf_adap)) {
-- printk(KERN_INFO " i2c-algo-pcf.o: scanning bus %s - TIMEOUTed.\n",
-- adap->name);
-- break;
-- }
-- i2c_outb(pcf_adap, i);
-- i2c_start(pcf_adap);
-- if ((wait_for_pin(pcf_adap, &status) >= 0) &&
-- ((status & I2C_PCF_LRB) == 0)) {
-- printk("(%02x)",i>>1);
-- } else {
-- printk(".");
-- }
-- i2c_stop(pcf_adap);
-- udelay(pcf_adap->udelay);
-- }
-- printk("\n");
-- }
- return 0;
- }
-
-
- int i2c_pcf_del_bus(struct i2c_adapter *adap)
- {
-- int res;
-- if ((res = i2c_del_adapter(adap)) < 0)
-- return res;
-- DEB2(printk("i2c-algo-pcf.o: adapter unregistered: %s\n",adap->name));
--
--#ifdef MODULE
-- MOD_DEC_USE_COUNT;
--#endif
-- return 0;
--}
--
--int __init i2c_algo_pcf_init (void)
--{
-- printk("i2c-algo-pcf.o: i2c pcf8584 algorithm module\n");
-- return 0;
-+ return i2c_del_adapter(adap);
- }
-
--
- EXPORT_SYMBOL(i2c_pcf_add_bus);
- EXPORT_SYMBOL(i2c_pcf_del_bus);
-
--#ifdef MODULE
- MODULE_AUTHOR("Hans Berglund <hb@spacetec.no>");
- MODULE_DESCRIPTION("I2C-Bus PCF8584 algorithm");
- MODULE_LICENSE("GPL");
-
--MODULE_PARM(pcf_scan, "i");
- MODULE_PARM(i2c_debug,"i");
--
--MODULE_PARM_DESC(pcf_scan, "Scan for active chips on the bus");
- MODULE_PARM_DESC(i2c_debug,
- "debug level - 0 off; 1 normal; 2,3 more verbose; 9 pcf-protocol");
--
--
--int init_module(void)
--{
-- return i2c_algo_pcf_init();
--}
--
--void cleanup_module(void)
--{
--}
--#endif
---- linux-old/include/linux/i2c-algo-pcf.h Thu Mar 23 02:26:01 2000
-+++ linux/include/linux/i2c-algo-pcf.h Mon Dec 13 19:26:30 2004
-@@ -22,13 +22,12 @@
- /* With some changes from Kyösti Mälkki <kmalkki@cc.hut.fi> and even
- Frodo Looijaard <frodol@dds.nl> */
-
--/* $Id: i2c-algo-pcf.h,v 1.7 2000/02/27 23:02:45 frodo Exp $ */
-+/* $Id: i2c-algo-pcf.h,v 1.9 2003/07/25 07:56:42 khali Exp $ */
-
--#ifndef I2C_ALGO_PCF_H
--#define I2C_ALGO_PCF_H 1
-+#ifndef _LINUX_I2C_ALGO_PCF_H
-+#define _LINUX_I2C_ALGO_PCF_H
-
--/* --- Defines for pcf-adapters --------------------------------------- */
--#include <linux/i2c.h>
-+#include <linux/i2c-pcf8584.h>
-
- struct i2c_algo_pcf_data {
- void *data; /* private data for lolevel routines */
-@@ -49,4 +48,4 @@
- int i2c_pcf_add_bus(struct i2c_adapter *);
- int i2c_pcf_del_bus(struct i2c_adapter *);
-
--#endif /* I2C_ALGO_PCF_H */
-+#endif /* _LINUX_I2C_ALGO_PCF_H */
---- linux-old/drivers/i2c/i2c-core.c Wed Jul 7 00:38:02 2004
-+++ linux/drivers/i2c/i2c-core.c Mon Dec 13 19:26:31 2004
-@@ -18,56 +18,33 @@
- /* ------------------------------------------------------------------------- */
-
- /* With some changes from Kyösti Mälkki <kmalkki@cc.hut.fi>.
-- All SMBus-related things are written by Frodo Looijaard <frodol@dds.nl> */
-+ All SMBus-related things are written by Frodo Looijaard <frodol@dds.nl>
-+ SMBus 2.0 support by Mark Studebaker <mdsxyz123@yahoo.com> */
-
--/* $Id: i2c-core.c,v 1.64 2001/08/13 01:35:56 mds Exp $ */
-+/* i2c-core.c,v 1.91.2.2 2003/01/21 10:00:19 kmalkki Exp */
-
- #include <linux/module.h>
- #include <linux/kernel.h>
- #include <linux/errno.h>
- #include <linux/slab.h>
- #include <linux/proc_fs.h>
--#include <linux/config.h>
--
--#include <linux/i2c.h>
--
--/* ----- compatibility stuff ----------------------------------------------- */
--
- #include <linux/init.h>
--
-+#include <linux/i2c.h>
- #include <asm/uaccess.h>
-
- /* ----- global defines ---------------------------------------------------- */
-
--/* exclusive access to the bus */
--#define I2C_LOCK(adap) down(&adap->lock)
--#define I2C_UNLOCK(adap) up(&adap->lock)
--
--#define ADAP_LOCK() down(&adap_lock)
--#define ADAP_UNLOCK() up(&adap_lock)
--
--#define DRV_LOCK() down(&driver_lock)
--#define DRV_UNLOCK() up(&driver_lock)
--
- #define DEB(x) if (i2c_debug>=1) x;
- #define DEB2(x) if (i2c_debug>=2) x;
-
- /* ----- global variables -------------------------------------------------- */
-
--/**** lock for writing to global variables: the adapter & driver list */
--struct semaphore adap_lock;
--struct semaphore driver_lock;
--
--/**** adapter list */
-+DECLARE_MUTEX(core_lists);
- static struct i2c_adapter *adapters[I2C_ADAP_MAX];
--static int adap_count;
--
--/**** drivers list */
- static struct i2c_driver *drivers[I2C_DRIVER_MAX];
--static int driver_count;
-
- /**** debug level */
--static int i2c_debug=1;
-+static int i2c_debug;
-
- /* ---------------------------------------------------
- * /proc entry declarations
-@@ -75,10 +52,6 @@
- */
-
- #ifdef CONFIG_PROC_FS
--
--static int i2cproc_init(void);
--static int i2cproc_cleanup(void);
--
- static ssize_t i2cproc_bus_read(struct file * file, char * buf,size_t count,
- loff_t *ppos);
- static int read_bus_i2c(char *buf, char **start, off_t offset, int len,
-@@ -87,15 +60,11 @@
- /* To implement the dynamic /proc/bus/i2c-? files, we need our own
- implementation of the read hook */
- static struct file_operations i2cproc_operations = {
-- read: i2cproc_bus_read,
-+ .read = i2cproc_bus_read,
- };
-
--static int i2cproc_initialized = 0;
--
--#else /* undef CONFIG_PROC_FS */
--
--#define i2cproc_init() 0
--#define i2cproc_cleanup() 0
-+static int i2cproc_register(struct i2c_adapter *adap, int bus);
-+static void i2cproc_remove(int bus);
-
- #endif /* CONFIG_PROC_FS */
-
-@@ -112,9 +81,9 @@
- */
- int i2c_add_adapter(struct i2c_adapter *adap)
- {
-- int i,j,res;
-+ int i,j,res = 0;
-
-- ADAP_LOCK();
-+ down(&core_lists);
- for (i = 0; i < I2C_ADAP_MAX; i++)
- if (NULL == adapters[i])
- break;
-@@ -125,68 +94,39 @@
- res = -ENOMEM;
- goto ERROR0;
- }
-+
-+#ifdef CONFIG_PROC_FS
-+ res = i2cproc_register(adap, i);
-+ if (res<0)
-+ goto ERROR0;
-+#endif /* def CONFIG_PROC_FS */
-
- adapters[i] = adap;
-- adap_count++;
-- ADAP_UNLOCK();
-
- /* init data types */
-- init_MUTEX(&adap->lock);
--
--#ifdef CONFIG_PROC_FS
--
-- if (i2cproc_initialized) {
-- char name[8];
-- struct proc_dir_entry *proc_entry;
--
-- sprintf(name,"i2c-%d", i);
--
-- proc_entry = create_proc_entry(name,0,proc_bus);
-- if (! proc_entry) {
-- printk("i2c-core.o: Could not create /proc/bus/%s\n",
-- name);
-- res = -ENOENT;
-- goto ERROR1;
-- }
--
-- proc_entry->proc_fops = &i2cproc_operations;
-- proc_entry->owner = THIS_MODULE;
-- adap->inode = proc_entry->low_ino;
-- }
--
--#endif /* def CONFIG_PROC_FS */
-+ init_MUTEX(&adap->bus);
-+ init_MUTEX(&adap->list);
-
- /* inform drivers of new adapters */
-- DRV_LOCK();
- for (j=0;j<I2C_DRIVER_MAX;j++)
- if (drivers[j]!=NULL &&
- (drivers[j]->flags&(I2C_DF_NOTIFY|I2C_DF_DUMMY)))
- /* We ignore the return code; if it fails, too bad */
- drivers[j]->attach_adapter(adap);
-- DRV_UNLOCK();
-
- DEB(printk(KERN_DEBUG "i2c-core.o: adapter %s registered as adapter %d.\n",
- adap->name,i));
--
-- return 0;
--
--
--ERROR1:
-- ADAP_LOCK();
-- adapters[i] = NULL;
-- adap_count--;
- ERROR0:
-- ADAP_UNLOCK();
-+ up(&core_lists);
- return res;
- }
-
-
- int i2c_del_adapter(struct i2c_adapter *adap)
- {
-- int i,j,res;
--
-- ADAP_LOCK();
-+ int i,j,res = 0;
-
-+ down(&core_lists);
- for (i = 0; i < I2C_ADAP_MAX; i++)
- if (adap == adapters[i])
- break;
-@@ -202,20 +142,17 @@
- * *detach* it! Of course, each dummy driver should know about
- * this or hell will break loose...
- */
-- DRV_LOCK();
- for (j = 0; j < I2C_DRIVER_MAX; j++)
- if (drivers[j] && (drivers[j]->flags & I2C_DF_DUMMY))
- if ((res = drivers[j]->attach_adapter(adap))) {
- printk(KERN_WARNING "i2c-core.o: can't detach adapter %s "
- "while detaching driver %s: driver not "
- "detached!",adap->name,drivers[j]->name);
-- goto ERROR1;
-+ goto ERROR0;
- }
-- DRV_UNLOCK();
--
-
- /* detach any active clients. This must be done first, because
-- * it can fail; in which case we give upp. */
-+ * it can fail; in which case we give up. */
- for (j=0;j<I2C_CLIENT_MAX;j++) {
- struct i2c_client *client = adap->clients[j];
- if (client!=NULL)
-@@ -231,26 +168,15 @@
- goto ERROR0;
- }
- }
-+
- #ifdef CONFIG_PROC_FS
-- if (i2cproc_initialized) {
-- char name[8];
-- sprintf(name,"i2c-%d", i);
-- remove_proc_entry(name,proc_bus);
-- }
-+ i2cproc_remove(i);
- #endif /* def CONFIG_PROC_FS */
-
- adapters[i] = NULL;
-- adap_count--;
--
-- ADAP_UNLOCK();
- DEB(printk(KERN_DEBUG "i2c-core.o: adapter unregistered: %s\n",adap->name));
-- return 0;
--
- ERROR0:
-- ADAP_UNLOCK();
-- return res;
--ERROR1:
-- DRV_UNLOCK();
-+ up(&core_lists);
- return res;
- }
-
-@@ -264,7 +190,8 @@
- int i2c_add_driver(struct i2c_driver *driver)
- {
- int i;
-- DRV_LOCK();
-+
-+ down(&core_lists);
- for (i = 0; i < I2C_DRIVER_MAX; i++)
- if (NULL == drivers[i])
- break;
-@@ -273,19 +200,12 @@
- " i2c-core.o: register_driver(%s) "
- "- enlarge I2C_DRIVER_MAX.\n",
- driver->name);
-- DRV_UNLOCK();
-+ up(&core_lists);
- return -ENOMEM;
- }
--
- drivers[i] = driver;
-- driver_count++;
--
-- DRV_UNLOCK(); /* driver was successfully added */
--
- DEB(printk(KERN_DEBUG "i2c-core.o: driver %s registered.\n",driver->name));
-
-- ADAP_LOCK();
--
- /* now look for instances of driver on our adapters
- */
- if (driver->flags& (I2C_DF_NOTIFY|I2C_DF_DUMMY)) {
-@@ -294,15 +214,15 @@
- /* Ignore errors */
- driver->attach_adapter(adapters[i]);
- }
-- ADAP_UNLOCK();
-+ up(&core_lists);
- return 0;
- }
-
- int i2c_del_driver(struct i2c_driver *driver)
- {
-- int i,j,k,res;
-+ int i,j,k,res = 0;
-
-- DRV_LOCK();
-+ down(&core_lists);
- for (i = 0; i < I2C_DRIVER_MAX; i++)
- if (driver == drivers[i])
- break;
-@@ -310,7 +230,7 @@
- printk(KERN_WARNING " i2c-core.o: unregister_driver: "
- "[%s] not found\n",
- driver->name);
-- DRV_UNLOCK();
-+ up(&core_lists);
- return -ENODEV;
- }
- /* Have a look at each adapter, if clients of this driver are still
-@@ -322,7 +242,6 @@
- * invalid operation might (will!) result, when using stale client
- * pointers.
- */
-- ADAP_LOCK(); /* should be moved inside the if statement... */
- for (k=0;k<I2C_ADAP_MAX;k++) {
- struct i2c_adapter *adap = adapters[k];
- if (adap == NULL) /* skip empty entries. */
-@@ -341,8 +260,7 @@
- "not be detached properly; driver "
- "not unloaded!",driver->name,
- adap->name);
-- ADAP_UNLOCK();
-- return res;
-+ goto ERROR0;
- }
- } else {
- for (j=0;j<I2C_CLIENT_MAX;j++) {
-@@ -359,37 +277,47 @@
- "unregistering driver "
- "`%s', the client at "
- "address %02x of "
-- "adapter `%s' could not"
-- "be detached; driver"
-+ "adapter `%s' could not "
-+ "be detached; driver "
- "not unloaded!",
- driver->name,
- client->addr,
- adap->name);
-- ADAP_UNLOCK();
-- return res;
-+ goto ERROR0;
- }
- }
- }
- }
- }
-- ADAP_UNLOCK();
- drivers[i] = NULL;
-- driver_count--;
-- DRV_UNLOCK();
--
- DEB(printk(KERN_DEBUG "i2c-core.o: driver unregistered: %s\n",driver->name));
-- return 0;
-+
-+ERROR0:
-+ up(&core_lists);
-+ return res;
- }
-
--int i2c_check_addr (struct i2c_adapter *adapter, int addr)
-+static int __i2c_check_addr (struct i2c_adapter *adapter, int addr)
- {
- int i;
- for (i = 0; i < I2C_CLIENT_MAX ; i++)
- if (adapter->clients[i] && (adapter->clients[i]->addr == addr))
- return -EBUSY;
-+
- return 0;
- }
-
-+int i2c_check_addr (struct i2c_adapter *adapter, int addr)
-+{
-+ int rval;
-+
-+ down(&adapter->list);
-+ rval = __i2c_check_addr(adapter, addr);
-+ up(&adapter->list);
-+
-+ return rval;
-+}
-+
- int i2c_attach_client(struct i2c_client *client)
- {
- struct i2c_adapter *adapter = client->adapter;
-@@ -398,6 +326,7 @@
- if (i2c_check_addr(client->adapter,client->addr))
- return -EBUSY;
-
-+ down(&adapter->list);
- for (i = 0; i < I2C_CLIENT_MAX; i++)
- if (NULL == adapter->clients[i])
- break;
-@@ -405,11 +334,11 @@
- printk(KERN_WARNING
- " i2c-core.o: attach_client(%s) - enlarge I2C_CLIENT_MAX.\n",
- client->name);
-+ up(&adapter->list);
- return -ENOMEM;
- }
--
- adapter->clients[i] = client;
-- adapter->client_count++;
-+ up(&adapter->list);
-
- if (adapter->client_register)
- if (adapter->client_register(client))
-@@ -431,16 +360,6 @@
- struct i2c_adapter *adapter = client->adapter;
- int i,res;
-
-- for (i = 0; i < I2C_CLIENT_MAX; i++)
-- if (client == adapter->clients[i])
-- break;
-- if (I2C_CLIENT_MAX == i) {
-- printk(KERN_WARNING " i2c-core.o: unregister_client "
-- "[%s] not found\n",
-- client->name);
-- return -ENODEV;
-- }
--
- if( (client->flags & I2C_CLIENT_ALLOW_USE) &&
- (client->usage_count>0))
- return -EBUSY;
-@@ -452,33 +371,41 @@
- return res;
- }
-
-+ down(&adapter->list);
-+ for (i = 0; i < I2C_CLIENT_MAX; i++)
-+ if (client == adapter->clients[i])
-+ break;
-+ if (I2C_CLIENT_MAX == i) {
-+ printk(KERN_WARNING " i2c-core.o: unregister_client "
-+ "[%s] not found\n",
-+ client->name);
-+ up(&adapter->list);
-+ return -ENODEV;
-+ }
- adapter->clients[i] = NULL;
-- adapter->client_count--;
-+ up(&adapter->list);
-
- DEB(printk(KERN_DEBUG "i2c-core.o: client [%s] unregistered.\n",client->name));
- return 0;
- }
-
--void i2c_inc_use_client(struct i2c_client *client)
-+static void i2c_inc_use_client(struct i2c_client *client)
- {
--
-- if (client->driver->inc_use != NULL)
-- client->driver->inc_use(client);
--
-- if (client->adapter->inc_use != NULL)
-- client->adapter->inc_use(client->adapter);
-+ if(client->driver->owner)
-+ __MOD_INC_USE_COUNT(client->driver->owner);
-+ if(client->adapter->owner)
-+ __MOD_INC_USE_COUNT(client->adapter->owner);
- }
-
--void i2c_dec_use_client(struct i2c_client *client)
-+static void i2c_dec_use_client(struct i2c_client *client)
- {
--
-- if (client->driver->dec_use != NULL)
-- client->driver->dec_use(client);
--
-- if (client->adapter->dec_use != NULL)
-- client->adapter->dec_use(client->adapter);
-+ if(client->driver->owner)
-+ __MOD_DEC_USE_COUNT(client->driver->owner);
-+ if(client->adapter->owner)
-+ __MOD_DEC_USE_COUNT(client->adapter->owner);
- }
-
-+#if 0 /* just forget about this for now --km */
- struct i2c_client *i2c_get_client(int driver_id, int adapter_id,
- struct i2c_client *prev)
- {
-@@ -545,18 +472,17 @@
-
- return 0;
- }
-+#endif
-
- int i2c_use_client(struct i2c_client *client)
- {
-- if(client->flags & I2C_CLIENT_ALLOW_USE) {
-- if (client->flags & I2C_CLIENT_ALLOW_MULTIPLE_USE)
-+ if (client->flags & I2C_CLIENT_ALLOW_USE) {
-+ if (client->flags & I2C_CLIENT_ALLOW_MULTIPLE_USE)
-+ client->usage_count++;
-+ else if (client->usage_count > 0)
-+ return -EBUSY;
-+ else
- client->usage_count++;
-- else {
-- if(client->usage_count > 0)
-- return -EBUSY;
-- else
-- client->usage_count++;
-- }
- }
-
- i2c_inc_use_client(client);
-@@ -589,12 +515,13 @@
- #ifdef CONFIG_PROC_FS
-
- /* This function generates the output for /proc/bus/i2c */
--int read_bus_i2c(char *buf, char **start, off_t offset, int len, int *eof,
-+static int read_bus_i2c(char *buf, char **start, off_t offset, int len, int *eof,
- void *private)
- {
- int i;
- int nr = 0;
- /* Note that it is safe to write a `little' beyond len. Yes, really. */
-+ down(&core_lists);
- for (i = 0; (i < I2C_ADAP_MAX) && (nr < len); i++)
- if (adapters[i]) {
- nr += sprintf(buf+nr, "i2c-%d\t", i);
-@@ -611,6 +538,7 @@
- adapters[i]->name,
- adapters[i]->algo->name);
- }
-+ up(&core_lists);
- return nr;
- }
-
-@@ -621,98 +549,125 @@
- struct inode * inode = file->f_dentry->d_inode;
- char *kbuf;
- struct i2c_client *client;
-+ struct i2c_adapter *adap;
- int i,j,k,order_nr,len=0;
- size_t len_total;
- int order[I2C_CLIENT_MAX];
-+#define OUTPUT_LENGTH_PER_LINE 70
-
-- if (count > 4000)
-- return -EINVAL;
- len_total = file->f_pos + count;
-- /* Too bad if this gets longer (unlikely) */
-- if (len_total > 4000)
-- len_total = 4000;
-- for (i = 0; i < I2C_ADAP_MAX; i++)
-- if (adapters[i]->inode == inode->i_ino) {
-- /* We need a bit of slack in the kernel buffer; this makes the
-- sprintf safe. */
-- if (! (kbuf = kmalloc(count + 80,GFP_KERNEL)))
-- return -ENOMEM;
-- /* Order will hold the indexes of the clients
-- sorted by address */
-- order_nr=0;
-- for (j = 0; j < I2C_CLIENT_MAX; j++) {
-- if ((client = adapters[i]->clients[j]) &&
-- (client->driver->id != I2C_DRIVERID_I2CDEV)) {
-- for(k = order_nr;
-- (k > 0) &&
-- adapters[i]->clients[order[k-1]]->
-- addr > client->addr;
-- k--)
-- order[k] = order[k-1];
-- order[k] = j;
-- order_nr++;
-- }
-- }
--
--
-- for (j = 0; (j < order_nr) && (len < len_total); j++) {
-- client = adapters[i]->clients[order[j]];
-- len += sprintf(kbuf+len,"%02x\t%-32s\t%-32s\n",
-- client->addr,
-- client->name,
-- client->driver->name);
-- }
-- len = len - file->f_pos;
-- if (len > count)
-- len = count;
-- if (len < 0)
-- len = 0;
-- if (copy_to_user (buf,kbuf+file->f_pos, len)) {
-- kfree(kbuf);
-- return -EFAULT;
-- }
-- file->f_pos += len;
-- kfree(kbuf);
-- return len;
-- }
-- return -ENOENT;
-+ if (len_total > (I2C_CLIENT_MAX * OUTPUT_LENGTH_PER_LINE) )
-+ /* adjust to maximum file size */
-+ len_total = (I2C_CLIENT_MAX * OUTPUT_LENGTH_PER_LINE);
-+
-+ down(&core_lists);
-+ /* adap = file->private_data; ?? --km */
-+ for (i = 0; i < I2C_ADAP_MAX; i++) {
-+ adap = adapters[i];
-+ if (adap && (adap->inode == inode->i_ino))
-+ break;
-+ }
-+ if ( I2C_ADAP_MAX == i ) {
-+ up(&core_lists);
-+ return -ENOENT;
-+ }
-+
-+ /* We need a bit of slack in the kernel buffer; this makes the
-+ sprintf safe. */
-+ if (! (kbuf = kmalloc(len_total +
-+ OUTPUT_LENGTH_PER_LINE,
-+ GFP_KERNEL)))
-+ return -ENOMEM;
-+
-+ /* Order will hold the indexes of the clients
-+ sorted by address */
-+ order_nr=0;
-+ down(&adap->list);
-+ for (j = 0; j < I2C_CLIENT_MAX; j++) {
-+ if ((client = adap->clients[j]) &&
-+ (client->driver->id != I2C_DRIVERID_I2CDEV)) {
-+ for(k = order_nr;
-+ (k > 0) &&
-+ adap->clients[order[k-1]]->
-+ addr > client->addr;
-+ k--)
-+ order[k] = order[k-1];
-+ order[k] = j;
-+ order_nr++;
-+ }
-+ }
-+
-+
-+ for (j = 0; (j < order_nr) && (len < len_total); j++) {
-+ client = adap->clients[order[j]];
-+ len += sprintf(kbuf+len,"%02x\t%-32s\t%-32s\n",
-+ client->addr,
-+ client->name,
-+ client->driver->name);
-+ }
-+ up(&adap->list);
-+ up(&core_lists);
-+
-+ len = len - file->f_pos;
-+ if (len > count)
-+ len = count;
-+ if (len < 0)
-+ len = 0;
-+ if (copy_to_user (buf,kbuf+file->f_pos, len)) {
-+ kfree(kbuf);
-+ return -EFAULT;
-+ }
-+ file->f_pos += len;
-+ kfree(kbuf);
-+ return len;
-+}
-+
-+static int i2cproc_register(struct i2c_adapter *adap, int bus)
-+{
-+ char name[8];
-+ struct proc_dir_entry *proc_entry;
-+
-+ sprintf(name,"i2c-%d", bus);
-+ proc_entry = create_proc_entry(name,0,proc_bus);
-+ if (! proc_entry) {
-+ printk(KERN_ERR "i2c-core.o: Could not create /proc/bus/%s\n",
-+ name);
-+ return -ENOENT;
-+ }
-+
-+ proc_entry->proc_fops = &i2cproc_operations;
-+ proc_entry->owner = adap->owner;
-+ adap->inode = proc_entry->low_ino;
-+ return 0;
- }
-
--int i2cproc_init(void)
-+static void i2cproc_remove(int bus)
- {
-+ char name[8];
-+ sprintf(name,"i2c-%d", bus);
-+ remove_proc_entry(name, proc_bus);
-+}
-
-+static int __init i2cproc_init(void)
-+{
- struct proc_dir_entry *proc_bus_i2c;
-
-- i2cproc_initialized = 0;
--
-- if (! proc_bus) {
-- printk("i2c-core.o: /proc/bus/ does not exist");
-- i2cproc_cleanup();
-- return -ENOENT;
-- }
- proc_bus_i2c = create_proc_entry("i2c",0,proc_bus);
- if (!proc_bus_i2c) {
- printk(KERN_ERR "i2c-core.o: Could not create /proc/bus/i2c");
-- i2cproc_cleanup();
- return -ENOENT;
- }
-+
- proc_bus_i2c->read_proc = &read_bus_i2c;
- proc_bus_i2c->owner = THIS_MODULE;
-- i2cproc_initialized += 2;
- return 0;
- }
-
--int i2cproc_cleanup(void)
-+static void __exit i2cproc_cleanup(void)
- {
--
-- if (i2cproc_initialized >= 1) {
-- remove_proc_entry("i2c",proc_bus);
-- i2cproc_initialized -= 2;
-- }
-- return 0;
-+ remove_proc_entry("i2c",proc_bus);
- }
-
--
- #endif /* def CONFIG_PROC_FS */
-
- /* ----------------------------------------------------
-@@ -728,9 +683,9 @@
- DEB2(printk(KERN_DEBUG "i2c-core.o: master_xfer: %s with %d msgs.\n",
- adap->name,num));
-
-- I2C_LOCK(adap);
-+ down(&adap->bus);
- ret = adap->algo->master_xfer(adap,msgs,num);
-- I2C_UNLOCK(adap);
-+ up(&adap->bus);
-
- return ret;
- } else {
-@@ -755,9 +710,9 @@
- DEB2(printk(KERN_DEBUG "i2c-core.o: master_send: writing %d bytes on %s.\n",
- count,client->adapter->name));
-
-- I2C_LOCK(adap);
-+ down(&adap->bus);
- ret = adap->algo->master_xfer(adap,&msg,1);
-- I2C_UNLOCK(adap);
-+ up(&adap->bus);
-
- /* if everything went ok (i.e. 1 msg transmitted), return #bytes
- * transmitted, else error code.
-@@ -785,9 +740,9 @@
- DEB2(printk(KERN_DEBUG "i2c-core.o: master_recv: reading %d bytes on %s.\n",
- count,client->adapter->name));
-
-- I2C_LOCK(adap);
-+ down(&adap->bus);
- ret = adap->algo->master_xfer(adap,&msg,1);
-- I2C_UNLOCK(adap);
-+ up(&adap->bus);
-
- DEB2(printk(KERN_DEBUG "i2c-core.o: master_recv: return:%d (count:%d, addr:0x%02x)\n",
- ret, count, client->addr));
-@@ -965,6 +920,123 @@
-
- /* The SMBus parts */
-
-+#define POLY (0x1070U << 3)
-+static u8
-+crc8(u16 data)
-+{
-+ int i;
-+
-+ for(i = 0; i < 8; i++) {
-+ if (data & 0x8000)
-+ data = data ^ POLY;
-+ data = data << 1;
-+ }
-+ return (u8)(data >> 8);
-+}
-+
-+/* CRC over count bytes in the first array plus the bytes in the rest
-+ array if it is non-null. rest[0] is the (length of rest) - 1
-+ and is included. */
-+u8 i2c_smbus_partial_pec(u8 crc, int count, u8 *first, u8 *rest)
-+{
-+ int i;
-+
-+ for(i = 0; i < count; i++)
-+ crc = crc8((crc ^ first[i]) << 8);
-+ if(rest != NULL)
-+ for(i = 0; i <= rest[0]; i++)
-+ crc = crc8((crc ^ rest[i]) << 8);
-+ return crc;
-+}
-+
-+u8 i2c_smbus_pec(int count, u8 *first, u8 *rest)
-+{
-+ return i2c_smbus_partial_pec(0, count, first, rest);
-+}
-+
-+/* Returns new "size" (transaction type)
-+ Note that we convert byte to byte_data and byte_data to word_data
-+ rather than invent new xxx_PEC transactions. */
-+int i2c_smbus_add_pec(u16 addr, u8 command, int size,
-+ union i2c_smbus_data *data)
-+{
-+ u8 buf[3];
-+
-+ buf[0] = addr << 1;
-+ buf[1] = command;
-+ switch(size) {
-+ case I2C_SMBUS_BYTE:
-+ data->byte = i2c_smbus_pec(2, buf, NULL);
-+ size = I2C_SMBUS_BYTE_DATA;
-+ break;
-+ case I2C_SMBUS_BYTE_DATA:
-+ buf[2] = data->byte;
-+ data->word = buf[2] ||
-+ (i2c_smbus_pec(3, buf, NULL) << 8);
-+ size = I2C_SMBUS_WORD_DATA;
-+ break;
-+ case I2C_SMBUS_WORD_DATA:
-+ /* unsupported */
-+ break;
-+ case I2C_SMBUS_BLOCK_DATA:
-+ data->block[data->block[0] + 1] =
-+ i2c_smbus_pec(2, buf, data->block);
-+ size = I2C_SMBUS_BLOCK_DATA_PEC;
-+ break;
-+ }
-+ return size;
-+}
-+
-+int i2c_smbus_check_pec(u16 addr, u8 command, int size, u8 partial,
-+ union i2c_smbus_data *data)
-+{
-+ u8 buf[3], rpec, cpec;
-+
-+ buf[1] = command;
-+ switch(size) {
-+ case I2C_SMBUS_BYTE_DATA:
-+ buf[0] = (addr << 1) | 1;
-+ cpec = i2c_smbus_pec(2, buf, NULL);
-+ rpec = data->byte;
-+ break;
-+ case I2C_SMBUS_WORD_DATA:
-+ buf[0] = (addr << 1) | 1;
-+ buf[2] = data->word & 0xff;
-+ cpec = i2c_smbus_pec(3, buf, NULL);
-+ rpec = data->word >> 8;
-+ break;
-+ case I2C_SMBUS_WORD_DATA_PEC:
-+ /* unsupported */
-+ cpec = rpec = 0;
-+ break;
-+ case I2C_SMBUS_PROC_CALL_PEC:
-+ /* unsupported */
-+ cpec = rpec = 0;
-+ break;
-+ case I2C_SMBUS_BLOCK_DATA_PEC:
-+ buf[0] = (addr << 1);
-+ buf[2] = (addr << 1) | 1;
-+ cpec = i2c_smbus_pec(3, buf, data->block);
-+ rpec = data->block[data->block[0] + 1];
-+ break;
-+ case I2C_SMBUS_BLOCK_PROC_CALL_PEC:
-+ buf[0] = (addr << 1) | 1;
-+ rpec = i2c_smbus_partial_pec(partial, 1,
-+ buf, data->block);
-+ cpec = data->block[data->block[0] + 1];
-+ break;
-+ default:
-+ cpec = rpec = 0;
-+ break;
-+ }
-+ if(rpec != cpec) {
-+ DEB(printk(KERN_DEBUG "i2c-core.o: Bad PEC 0x%02x vs. 0x%02x\n",
-+ rpec, cpec));
-+ return -1;
-+ }
-+ return 0;
-+}
-+
- extern s32 i2c_smbus_write_quick(struct i2c_client * client, u8 value)
- {
- return i2c_smbus_xfer(client->adapter,client->addr,client->flags,
-@@ -983,8 +1055,9 @@
-
- extern s32 i2c_smbus_write_byte(struct i2c_client * client, u8 value)
- {
-+ union i2c_smbus_data data; /* only for PEC */
- return i2c_smbus_xfer(client->adapter,client->addr,client->flags,
-- I2C_SMBUS_WRITE,value, I2C_SMBUS_BYTE,NULL);
-+ I2C_SMBUS_WRITE,value, I2C_SMBUS_BYTE,&data);
- }
-
- extern s32 i2c_smbus_read_byte_data(struct i2c_client * client, u8 command)
-@@ -1072,6 +1145,43 @@
- I2C_SMBUS_BLOCK_DATA,&data);
- }
-
-+/* Returns the number of read bytes */
-+extern s32 i2c_smbus_block_process_call(struct i2c_client * client,
-+ u8 command, u8 length, u8 *values)
-+{
-+ union i2c_smbus_data data;
-+ int i;
-+ if (length > I2C_SMBUS_BLOCK_MAX - 1)
-+ return -1;
-+ data.block[0] = length;
-+ for (i = 1; i <= length; i++)
-+ data.block[i] = values[i-1];
-+ if(i2c_smbus_xfer(client->adapter,client->addr,client->flags,
-+ I2C_SMBUS_WRITE, command,
-+ I2C_SMBUS_BLOCK_PROC_CALL, &data))
-+ return -1;
-+ for (i = 1; i <= data.block[0]; i++)
-+ values[i-1] = data.block[i];
-+ return data.block[0];
-+}
-+
-+/* Returns the number of read bytes */
-+extern s32 i2c_smbus_read_i2c_block_data(struct i2c_client * client,
-+ u8 command, u8 *values)
-+{
-+ union i2c_smbus_data data;
-+ int i;
-+ if (i2c_smbus_xfer(client->adapter,client->addr,client->flags,
-+ I2C_SMBUS_READ,command,
-+ I2C_SMBUS_I2C_BLOCK_DATA,&data))
-+ return -1;
-+ else {
-+ for (i = 1; i <= data.block[0]; i++)
-+ values[i-1] = data.block[i];
-+ return data.block[0];
-+ }
-+}
-+
- extern s32 i2c_smbus_write_i2c_block_data(struct i2c_client * client,
- u8 command, u8 length, u8 *values)
- {
-@@ -1098,13 +1208,13 @@
- need to use only one message; when reading, we need two. We initialize
- most things with sane defaults, to keep the code below somewhat
- simpler. */
-- unsigned char msgbuf0[34];
-- unsigned char msgbuf1[34];
-+ unsigned char msgbuf0[I2C_SMBUS_BLOCK_MAX+2];
-+ unsigned char msgbuf1[I2C_SMBUS_BLOCK_MAX+2];
- int num = read_write == I2C_SMBUS_READ?2:1;
- struct i2c_msg msg[2] = { { addr, flags, 1, msgbuf0 },
- { addr, flags | I2C_M_RD, 0, msgbuf1 }
- };
-- int i;
-+ int i, len;
-
- msgbuf0[0] = command;
- switch(size) {
-@@ -1140,16 +1250,30 @@
- break;
- case I2C_SMBUS_PROC_CALL:
- num = 2; /* Special case */
-+ read_write = I2C_SMBUS_READ;
- msg[0].len = 3;
- msg[1].len = 2;
- msgbuf0[1] = data->word & 0xff;
- msgbuf0[2] = (data->word >> 8) & 0xff;
- break;
- case I2C_SMBUS_BLOCK_DATA:
-+ case I2C_SMBUS_BLOCK_DATA_PEC:
- if (read_write == I2C_SMBUS_READ) {
-- printk(KERN_ERR "i2c-core.o: Block read not supported "
-- "under I2C emulation!\n");
-- return -1;
-+ /* I2C_FUNC_SMBUS_EMUL doesn't include I2C_FUNC_SMBUS_READ_BLOCK_DATA */
-+ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_READ_BLOCK_DATA)) {
-+ printk(KERN_ERR "i2c-core.o: Block read not supported "
-+ "under I2C emulation!\n");
-+ return -1;
-+ }
-+ /* set send message */
-+ msg[0].len = 1;
-+ /* set recv message */
-+ msg[1].flags |= I2C_M_RECV_LEN;
-+ msg[1].len = I2C_SMBUS_BLOCK_MAX + 1;
-+ if (size == I2C_SMBUS_BLOCK_DATA_PEC) {
-+ msg[1].len++;
-+ msg[1].flags |= I2C_M_RECV_PEC;
-+ }
- } else {
- msg[0].len = data->block[0] + 2;
- if (msg[0].len > I2C_SMBUS_BLOCK_MAX + 2) {
-@@ -1158,10 +1282,57 @@
- data->block[0]);
- return -1;
- }
-+ if(size == I2C_SMBUS_BLOCK_DATA_PEC)
-+ (msg[0].len)++;
- for (i = 1; i <= msg[0].len; i++)
- msgbuf0[i] = data->block[i-1];
- }
- break;
-+ case I2C_SMBUS_BLOCK_PROC_CALL:
-+ case I2C_SMBUS_BLOCK_PROC_CALL_PEC:
-+ /* I2C_FUNC_SMBUS_EMUL doesn't include I2C_FUNC_SMBUS_BLOCK_PROC_CALL */
-+ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BLOCK_PROC_CALL)) {
-+ printk(KERN_ERR "i2c-core.o: adapter doesn't support block process call!\n");
-+ return -1;
-+ }
-+
-+ /* Another special case */
-+ num = 2;
-+ read_write = I2C_SMBUS_READ;
-+
-+ /* set send message */
-+ msg[0].len = data->block[0] + 2;
-+ if (msg[0].len > I2C_SMBUS_BLOCK_MAX + 2) {
-+ printk(KERN_ERR "i2c-core.o: smbus_access called with "
-+ "invalid block write size (%d)\n", data->block[0]);
-+ return -1;
-+ }
-+ for (i = 1; i <= msg[0].len; i++)
-+ msgbuf0[i] = data->block[i-1];
-+
-+ /* set recv message */
-+ msg[1].flags |= I2C_M_RECV_LEN;
-+ msg[1].len = I2C_SMBUS_BLOCK_MAX + 1;
-+ if (size == I2C_SMBUS_BLOCK_PROC_CALL_PEC) {
-+ msg[1].len++;
-+ msg[1].flags |= I2C_M_RECV_PEC;
-+ }
-+ break;
-+ case I2C_SMBUS_I2C_BLOCK_DATA:
-+ if (read_write == I2C_SMBUS_READ) {
-+ msg[1].len = I2C_SMBUS_I2C_BLOCK_MAX;
-+ } else {
-+ msg[0].len = data->block[0] + 1;
-+ if (msg[0].len > I2C_SMBUS_I2C_BLOCK_MAX + 1) {
-+ printk("i2c-core.o: i2c_smbus_xfer_emulated called with "
-+ "invalid block write size (%d)\n",
-+ data->block[0]);
-+ return -1;
-+ }
-+ for (i = 1; i <= data->block[0]; i++)
-+ msgbuf0[i] = data->block[i];
-+ }
-+ break;
- default:
- printk(KERN_ERR "i2c-core.o: smbus_access called with invalid size (%d)\n",
- size);
-@@ -1183,25 +1354,72 @@
- case I2C_SMBUS_PROC_CALL:
- data->word = msgbuf1[0] | (msgbuf1[1] << 8);
- break;
-+ case I2C_SMBUS_I2C_BLOCK_DATA:
-+ /* fixed at 32 for now */
-+ data->block[0] = I2C_SMBUS_I2C_BLOCK_MAX;
-+ for (i = 0; i < I2C_SMBUS_I2C_BLOCK_MAX; i++)
-+ data->block[i+1] = msgbuf1[i];
-+ break;
-+ case I2C_SMBUS_BLOCK_DATA:
-+ case I2C_SMBUS_BLOCK_PROC_CALL:
-+ case I2C_SMBUS_BLOCK_DATA_PEC:
-+ case I2C_SMBUS_BLOCK_PROC_CALL_PEC:
-+ len = msgbuf1[0] + 1;
-+ if(size == I2C_SMBUS_BLOCK_DATA_PEC ||
-+ size == I2C_SMBUS_BLOCK_PROC_CALL_PEC)
-+ len++;
-+ for (i = 0; i < len; i++)
-+ data->block[i] = msgbuf1[i];
-+ break;
- }
- return 0;
- }
-
-
--s32 i2c_smbus_xfer(struct i2c_adapter * adapter, u16 addr, unsigned short flags,
-+s32 i2c_smbus_xfer(struct i2c_adapter * adap, u16 addr, unsigned short flags,
- char read_write, u8 command, int size,
- union i2c_smbus_data * data)
- {
- s32 res;
-- flags = flags & I2C_M_TEN;
-- if (adapter->algo->smbus_xfer) {
-- I2C_LOCK(adapter);
-- res = adapter->algo->smbus_xfer(adapter,addr,flags,read_write,
-+ int swpec = 0;
-+ u8 partial = 0;
-+
-+ flags &= I2C_M_TEN | I2C_CLIENT_PEC;
-+ if((flags & I2C_CLIENT_PEC) &&
-+ !(i2c_check_functionality(adap, I2C_FUNC_SMBUS_HWPEC_CALC))) {
-+ swpec = 1;
-+ if(read_write == I2C_SMBUS_READ &&
-+ size == I2C_SMBUS_BLOCK_DATA)
-+ size = I2C_SMBUS_BLOCK_DATA_PEC;
-+ else if(size == I2C_SMBUS_PROC_CALL)
-+ size = I2C_SMBUS_PROC_CALL_PEC;
-+ else if(size == I2C_SMBUS_BLOCK_PROC_CALL) {
-+ i2c_smbus_add_pec(addr, command,
-+ I2C_SMBUS_BLOCK_DATA, data);
-+ partial = data->block[data->block[0] + 1];
-+ size = I2C_SMBUS_BLOCK_PROC_CALL_PEC;
-+ } else if(read_write == I2C_SMBUS_WRITE &&
-+ size != I2C_SMBUS_QUICK &&
-+ size != I2C_SMBUS_I2C_BLOCK_DATA)
-+ size = i2c_smbus_add_pec(addr, command, size, data);
-+ }
-+
-+ if (adap->algo->smbus_xfer) {
-+ down(&adap->bus);
-+ res = adap->algo->smbus_xfer(adap,addr,flags,read_write,
- command,size,data);
-- I2C_UNLOCK(adapter);
-+ up(&adap->bus);
- } else
-- res = i2c_smbus_xfer_emulated(adapter,addr,flags,read_write,
-+ res = i2c_smbus_xfer_emulated(adap,addr,flags,read_write,
- command,size,data);
-+
-+ if(res >= 0 && swpec &&
-+ size != I2C_SMBUS_QUICK && size != I2C_SMBUS_I2C_BLOCK_DATA &&
-+ (read_write == I2C_SMBUS_READ || size == I2C_SMBUS_PROC_CALL_PEC ||
-+ size == I2C_SMBUS_BLOCK_PROC_CALL_PEC)) {
-+ if(i2c_smbus_check_pec(addr, command, size, partial, data))
-+ return -1;
-+ }
- return res;
- }
-
-@@ -1228,143 +1446,37 @@
- printk(KERN_INFO "i2c-core.o: i2c core module version %s (%s)\n", I2C_VERSION, I2C_DATE);
- memset(adapters,0,sizeof(adapters));
- memset(drivers,0,sizeof(drivers));
-- adap_count=0;
-- driver_count=0;
-
-- init_MUTEX(&adap_lock);
-- init_MUTEX(&driver_lock);
--
-- i2cproc_init();
--
-+#ifdef CONFIG_PROC_FS
-+ return i2cproc_init();
-+#else
- return 0;
--}
--
--#ifndef MODULE
--#ifdef CONFIG_I2C_CHARDEV
-- extern int i2c_dev_init(void);
--#endif
--#ifdef CONFIG_I2C_ALGOBIT
-- extern int i2c_algo_bit_init(void);
--#endif
--#ifdef CONFIG_I2C_PHILIPSPAR
-- extern int i2c_bitlp_init(void);
--#endif
--#ifdef CONFIG_I2C_ELV
-- extern int i2c_bitelv_init(void);
--#endif
--#ifdef CONFIG_I2C_VELLEMAN
-- extern int i2c_bitvelle_init(void);
--#endif
--#ifdef CONFIG_I2C_BITVIA
-- extern int i2c_bitvia_init(void);
--#endif
--
--#ifdef CONFIG_I2C_ALGOPCF
-- extern int i2c_algo_pcf_init(void);
--#endif
--#ifdef CONFIG_I2C_ELEKTOR
-- extern int i2c_pcfisa_init(void);
--#endif
--
--#ifdef CONFIG_I2C_ALGO8XX
-- extern int i2c_algo_8xx_init(void);
--#endif
--#ifdef CONFIG_I2C_RPXLITE
-- extern int i2c_rpx_init(void);
--#endif
--
--#ifdef CONFIG_I2C_ALGO_SIBYTE
-- extern int i2c_algo_sibyte_init(void);
-- extern int i2c_sibyte_init(void);
--#endif
--#ifdef CONFIG_I2C_MAX1617
-- extern int i2c_max1617_init(void);
--#endif
--#ifdef CONFIG_I2C_ALGO_AU1550
-- extern int i2c_pb1550_init(void);
- #endif
-+}
-
--#ifdef CONFIG_I2C_PROC
-- extern int sensors_init(void);
-+static void __exit i2c_exit(void)
-+{
-+#ifdef CONFIG_PROC_FS
-+ i2cproc_cleanup();
- #endif
-+}
-
--/* This is needed for automatic patch generation: sensors code starts here */
--/* This is needed for automatic patch generation: sensors code ends here */
--
-+/* leave this in for now simply to make patching easier so we don't have
-+ to remove the call in drivers/char/mem.c */
- int __init i2c_init_all(void)
- {
-- /* --------------------- global ----- */
-- i2c_init();
--
--#ifdef CONFIG_I2C_CHARDEV
-- i2c_dev_init();
--#endif
-- /* --------------------- bit -------- */
--#ifdef CONFIG_I2C_ALGOBIT
-- i2c_algo_bit_init();
--#endif
--#ifdef CONFIG_I2C_PHILIPSPAR
-- i2c_bitlp_init();
--#endif
--#ifdef CONFIG_I2C_ELV
-- i2c_bitelv_init();
--#endif
--#ifdef CONFIG_I2C_VELLEMAN
-- i2c_bitvelle_init();
--#endif
--
-- /* --------------------- pcf -------- */
--#ifdef CONFIG_I2C_ALGOPCF
-- i2c_algo_pcf_init();
--#endif
--#ifdef CONFIG_I2C_ELEKTOR
-- i2c_pcfisa_init();
--#endif
--
-- /* --------------------- 8xx -------- */
--#ifdef CONFIG_I2C_ALGO8XX
-- i2c_algo_8xx_init();
--#endif
--#ifdef CONFIG_I2C_RPXLITE
-- i2c_rpx_init();
--#endif
--
-- /* --------------------- SiByte -------- */
--#ifdef CONFIG_I2C_ALGO_SIBYTE
-- i2c_algo_sibyte_init();
-- i2c_sibyte_init();
--#endif
--#ifdef CONFIG_I2C_MAX1617
-- i2c_max1617_init();
--#endif
--
--#ifdef CONFIG_I2C_ALGO_AU1550
-- i2c_pb1550_init();
--#endif
--
-- /* -------------- proc interface ---- */
--#ifdef CONFIG_I2C_PROC
-- sensors_init();
--#endif
--/* This is needed for automatic patch generation: sensors code starts here */
--/* This is needed for automatic patch generation: sensors code ends here */
--
- return 0;
- }
-
--#endif
--
--
--
- EXPORT_SYMBOL(i2c_add_adapter);
- EXPORT_SYMBOL(i2c_del_adapter);
- EXPORT_SYMBOL(i2c_add_driver);
- EXPORT_SYMBOL(i2c_del_driver);
- EXPORT_SYMBOL(i2c_attach_client);
- EXPORT_SYMBOL(i2c_detach_client);
--EXPORT_SYMBOL(i2c_inc_use_client);
--EXPORT_SYMBOL(i2c_dec_use_client);
-+#if 0
- EXPORT_SYMBOL(i2c_get_client);
-+#endif
- EXPORT_SYMBOL(i2c_use_client);
- EXPORT_SYMBOL(i2c_release_client);
- EXPORT_SYMBOL(i2c_check_addr);
-@@ -1388,11 +1500,12 @@
- EXPORT_SYMBOL(i2c_smbus_process_call);
- EXPORT_SYMBOL(i2c_smbus_read_block_data);
- EXPORT_SYMBOL(i2c_smbus_write_block_data);
-+EXPORT_SYMBOL(i2c_smbus_read_i2c_block_data);
-+EXPORT_SYMBOL(i2c_smbus_write_i2c_block_data);
-
- EXPORT_SYMBOL(i2c_get_functionality);
- EXPORT_SYMBOL(i2c_check_functionality);
-
--#ifdef MODULE
- MODULE_AUTHOR("Simon G. Vogl <simon@tk.uni-linz.ac.at>");
- MODULE_DESCRIPTION("I2C-Bus main module");
- MODULE_LICENSE("GPL");
-@@ -1400,13 +1513,5 @@
- MODULE_PARM(i2c_debug, "i");
- MODULE_PARM_DESC(i2c_debug,"debug level");
-
--int init_module(void)
--{
-- return i2c_init();
--}
--
--void cleanup_module(void)
--{
-- i2cproc_cleanup();
--}
--#endif
-+module_init(i2c_init);
-+module_exit(i2c_exit);
---- linux-old/drivers/i2c/i2c-dev.c Tue Jan 20 15:10:31 2004
-+++ linux/drivers/i2c/i2c-dev.c Mon Dec 13 19:26:32 2004
-@@ -28,9 +28,8 @@
- /* The devfs code is contributed by Philipp Matthias Hahn
- <pmhahn@titan.lahn.de> */
-
--/* $Id: i2c-dev.c,v 1.40 2001/08/25 01:28:01 mds Exp $ */
-+/* $Id: i2c-dev.c,v 1.57 2003/12/22 20:03:39 khali Exp $ */
-
--#include <linux/config.h>
- #include <linux/kernel.h>
- #include <linux/module.h>
- #include <linux/fs.h>
-@@ -39,21 +38,14 @@
- #ifdef CONFIG_DEVFS_FS
- #include <linux/devfs_fs_kernel.h>
- #endif
--
--
--/* If you want debugging uncomment: */
--/* #define DEBUG */
--
- #include <linux/init.h>
--#include <asm/uaccess.h>
--
- #include <linux/i2c.h>
- #include <linux/i2c-dev.h>
-+#include <asm/uaccess.h>
-+
-+/* If you want debugging uncomment: */
-+/* #define DEBUG */
-
--#ifdef MODULE
--extern int init_module(void);
--extern int cleanup_module(void);
--#endif /* def MODULE */
-
- /* struct file_operations changed too often in the 2.1 series for nice code */
-
-@@ -73,22 +65,14 @@
- static int i2cdev_command(struct i2c_client *client, unsigned int cmd,
- void *arg);
-
--#ifdef MODULE
--static
--#else
--extern
--#endif
-- int __init i2c_dev_init(void);
--static int i2cdev_cleanup(void);
--
- static struct file_operations i2cdev_fops = {
-- owner: THIS_MODULE,
-- llseek: no_llseek,
-- read: i2cdev_read,
-- write: i2cdev_write,
-- ioctl: i2cdev_ioctl,
-- open: i2cdev_open,
-- release: i2cdev_release,
-+ .owner = THIS_MODULE,
-+ .llseek = no_llseek,
-+ .read = i2cdev_read,
-+ .write = i2cdev_write,
-+ .ioctl = i2cdev_ioctl,
-+ .open = i2cdev_open,
-+ .release = i2cdev_release,
- };
-
- #define I2CDEV_ADAPS_MAX I2C_ADAP_MAX
-@@ -99,28 +83,22 @@
- #endif
-
- static struct i2c_driver i2cdev_driver = {
-- name: "i2c-dev dummy driver",
-- id: I2C_DRIVERID_I2CDEV,
-- flags: I2C_DF_DUMMY,
-- attach_adapter: i2cdev_attach_adapter,
-- detach_client: i2cdev_detach_client,
-- command: i2cdev_command,
--/* inc_use: NULL,
-- dec_use: NULL, */
-+ .owner = THIS_MODULE, /* not really used */
-+ .name = "i2c-dev dummy driver",
-+ .id = I2C_DRIVERID_I2CDEV,
-+ .flags = I2C_DF_DUMMY,
-+ .attach_adapter = i2cdev_attach_adapter,
-+ .detach_client = i2cdev_detach_client,
-+ .command = i2cdev_command,
- };
-
- static struct i2c_client i2cdev_client_template = {
-- name: "I2C /dev entry",
-- id: 1,
-- flags: 0,
-- addr: -1,
--/* adapter: NULL, */
-- driver: &i2cdev_driver,
--/* data: NULL */
-+ .name = "I2C /dev entry",
-+ .id = 1,
-+ .addr = -1,
-+ .driver = &i2cdev_driver,
- };
-
--static int i2cdev_initialized;
--
- static ssize_t i2cdev_read (struct file *file, char *buf, size_t count,
- loff_t *offset)
- {
-@@ -142,7 +120,7 @@
- return -ENOMEM;
-
- #ifdef DEBUG
-- printk(KERN_DEBUG "i2c-dev.o: i2c-%d reading %d bytes.\n",MINOR(inode->i_rdev),
-+ printk(KERN_DEBUG "i2c-dev.o: i2c-%d reading %d bytes.\n",minor(inode->i_rdev),
- count);
- #endif
-
-@@ -177,7 +155,7 @@
- }
-
- #ifdef DEBUG
-- printk(KERN_DEBUG "i2c-dev.o: i2c-%d writing %d bytes.\n",MINOR(inode->i_rdev),
-+ printk(KERN_DEBUG "i2c-dev.o: i2c-%d writing %d bytes.\n",minor(inode->i_rdev),
- count);
- #endif
- ret = i2c_master_send(client,tmp,count);
-@@ -199,7 +177,7 @@
-
- #ifdef DEBUG
- printk(KERN_DEBUG "i2c-dev.o: i2c-%d ioctl, cmd: 0x%x, arg: %lx.\n",
-- MINOR(inode->i_rdev),cmd, arg);
-+ minor(inode->i_rdev),cmd, arg);
- #endif /* DEBUG */
-
- switch ( cmd ) {
-@@ -218,6 +196,12 @@
- else
- client->flags &= ~I2C_M_TEN;
- return 0;
-+ case I2C_PEC:
-+ if (arg)
-+ client->flags |= I2C_CLIENT_PEC;
-+ else
-+ client->flags &= ~I2C_CLIENT_PEC;
-+ return 0;
- case I2C_FUNCS:
- funcs = i2c_get_functionality(client->adapter);
- return (copy_to_user((unsigned long *)arg,&funcs,
-@@ -318,7 +302,8 @@
- (data_arg.size != I2C_SMBUS_WORD_DATA) &&
- (data_arg.size != I2C_SMBUS_PROC_CALL) &&
- (data_arg.size != I2C_SMBUS_BLOCK_DATA) &&
-- (data_arg.size != I2C_SMBUS_I2C_BLOCK_DATA)) {
-+ (data_arg.size != I2C_SMBUS_I2C_BLOCK_DATA) &&
-+ (data_arg.size != I2C_SMBUS_BLOCK_PROC_CALL)) {
- #ifdef DEBUG
- printk(KERN_DEBUG "i2c-dev.o: size out of range (%x) in ioctl I2C_SMBUS.\n",
- data_arg.size);
-@@ -361,10 +346,11 @@
- else if ((data_arg.size == I2C_SMBUS_WORD_DATA) ||
- (data_arg.size == I2C_SMBUS_PROC_CALL))
- datasize = sizeof(data_arg.data->word);
-- else /* size == I2C_SMBUS_BLOCK_DATA */
-+ else /* size == smbus block, i2c block, or block proc. call */
- datasize = sizeof(data_arg.data->block);
-
- if ((data_arg.size == I2C_SMBUS_PROC_CALL) ||
-+ (data_arg.size == I2C_SMBUS_BLOCK_PROC_CALL) ||
- (data_arg.read_write == I2C_SMBUS_WRITE)) {
- if (copy_from_user(&temp, data_arg.data, datasize))
- return -EFAULT;
-@@ -373,6 +359,7 @@
- data_arg.read_write,
- data_arg.command,data_arg.size,&temp);
- if (! res && ((data_arg.size == I2C_SMBUS_PROC_CALL) ||
-+ (data_arg.size == I2C_SMBUS_BLOCK_PROC_CALL) ||
- (data_arg.read_write == I2C_SMBUS_READ))) {
- if (copy_to_user(data_arg.data, &temp, datasize))
- return -EFAULT;
-@@ -387,7 +374,7 @@
-
- int i2cdev_open (struct inode *inode, struct file *file)
- {
-- unsigned int minor = MINOR(inode->i_rdev);
-+ unsigned int minor = minor(inode->i_rdev);
- struct i2c_client *client;
-
- if ((minor >= I2CDEV_ADAPS_MAX) || ! (i2cdev_adaps[minor])) {
-@@ -403,11 +390,13 @@
- if(! (client = kmalloc(sizeof(struct i2c_client),GFP_KERNEL)))
- return -ENOMEM;
- memcpy(client,&i2cdev_client_template,sizeof(struct i2c_client));
-+
-+ /* registered with adapter, passed as client to user */
- client->adapter = i2cdev_adaps[minor];
- file->private_data = client;
-
-- if (i2cdev_adaps[minor]->inc_use)
-- i2cdev_adaps[minor]->inc_use(i2cdev_adaps[minor]);
-+ if(client->adapter->owner)
-+ __MOD_INC_USE_COUNT(client->adapter->owner);
-
- #ifdef DEBUG
- printk(KERN_DEBUG "i2c-dev.o: opened i2c-%d\n",minor);
-@@ -417,16 +406,19 @@
-
- static int i2cdev_release (struct inode *inode, struct file *file)
- {
-- unsigned int minor = MINOR(inode->i_rdev);
-- kfree(file->private_data);
-- file->private_data=NULL;
-+ struct i2c_client *client;
-+#ifdef DEBUG
-+ unsigned int minor = minor(inode->i_rdev);
-+#endif
-+
-+ client = file->private_data;
-+ file->private_data = NULL;
-+ if(client->adapter->owner)
-+ __MOD_DEC_USE_COUNT(client->adapter->owner);
-+ kfree(client);
- #ifdef DEBUG
- printk(KERN_DEBUG "i2c-dev.o: Closed: i2c-%d\n", minor);
- #endif
-- lock_kernel();
-- if (i2cdev_adaps[minor]->dec_use)
-- i2cdev_adaps[minor]->dec_use(i2cdev_adaps[minor]);
-- unlock_kernel();
- return 0;
- }
-
-@@ -451,7 +443,7 @@
- devfs_i2c[i] = devfs_register (devfs_handle, name,
- DEVFS_FL_DEFAULT, I2C_MAJOR, i,
- S_IFCHR | S_IRUSR | S_IWUSR,
-- &i2cdev_fops, NULL);
-+ &i2cdev_fops, adap);
- #endif
- printk(KERN_DEBUG "i2c-dev.o: Registered '%s' as minor %d\n",adap->name,i);
- } else {
-@@ -479,13 +471,12 @@
- return -1;
- }
-
--int __init i2c_dev_init(void)
-+static int __init i2c_dev_init(void)
- {
- int res;
-
- printk(KERN_INFO "i2c-dev.o: i2c /dev entries driver module version %s (%s)\n", I2C_VERSION, I2C_DATE);
-
-- i2cdev_initialized = 0;
- #ifdef CONFIG_DEVFS_FS
- if (devfs_register_chrdev(I2C_MAJOR, "i2c", &i2cdev_fops)) {
- #else
-@@ -498,63 +489,31 @@
- #ifdef CONFIG_DEVFS_FS
- devfs_handle = devfs_mk_dir(NULL, "i2c", NULL);
- #endif
-- i2cdev_initialized ++;
--
- if ((res = i2c_add_driver(&i2cdev_driver))) {
- printk(KERN_ERR "i2c-dev.o: Driver registration failed, module not inserted.\n");
-- i2cdev_cleanup();
-+#ifdef CONFIG_DEVFS_FS
-+ devfs_unregister(devfs_handle);
-+#endif
-+ unregister_chrdev(I2C_MAJOR,"i2c");
- return res;
- }
-- i2cdev_initialized ++;
- return 0;
- }
-
--int i2cdev_cleanup(void)
-+static void __exit i2c_dev_exit(void)
- {
-- int res;
--
-- if (i2cdev_initialized >= 2) {
-- if ((res = i2c_del_driver(&i2cdev_driver))) {
-- printk("i2c-dev.o: Driver deregistration failed, "
-- "module not removed.\n");
-- return res;
-- }
-- i2cdev_initialized --;
-- }
--
-- if (i2cdev_initialized >= 1) {
-+ i2c_del_driver(&i2cdev_driver);
- #ifdef CONFIG_DEVFS_FS
-- devfs_unregister(devfs_handle);
-- if ((res = devfs_unregister_chrdev(I2C_MAJOR, "i2c"))) {
--#else
-- if ((res = unregister_chrdev(I2C_MAJOR,"i2c"))) {
-+ devfs_unregister(devfs_handle);
- #endif
-- printk("i2c-dev.o: unable to release major %d for i2c bus\n",
-- I2C_MAJOR);
-- return res;
-- }
-- i2cdev_initialized --;
-- }
-- return 0;
-+ unregister_chrdev(I2C_MAJOR,"i2c");
- }
-
- EXPORT_NO_SYMBOLS;
-
--#ifdef MODULE
--
- MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl> and Simon G. Vogl <simon@tk.uni-linz.ac.at>");
- MODULE_DESCRIPTION("I2C /dev entries driver");
- MODULE_LICENSE("GPL");
-
--int init_module(void)
--{
-- return i2c_dev_init();
--}
--
--int cleanup_module(void)
--{
-- return i2cdev_cleanup();
--}
--
--#endif /* def MODULE */
--
-+module_init(i2c_dev_init);
-+module_exit(i2c_dev_exit);
---- linux-old/include/linux/i2c-dev.h Sat Jul 5 03:23:47 2003
-+++ linux/include/linux/i2c-dev.h Mon Dec 13 19:26:32 2004
-@@ -19,14 +19,16 @@
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
--/* $Id: i2c-dev.h,v 1.9 2001/08/15 03:04:58 mds Exp $ */
--
--#ifndef I2C_DEV_H
--#define I2C_DEV_H
-+/* $Id: i2c-dev.h,v 1.14 2003/07/25 07:56:42 khali Exp $ */
-
-+#ifndef _LINUX_I2C_DEV_H
-+#define _LINUX_I2C_DEV_H
-
- #include <linux/types.h>
--#include <linux/i2c.h>
-+
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,18)
-+#define minor(d) MINOR(d)
-+#endif
-
- /* Some IOCTL commands are defined in <linux/i2c.h> */
- /* Note: 10-bit addresses are NOT supported! */
-@@ -45,137 +47,4 @@
- __u32 nmsgs; /* number of i2c_msgs */
- };
-
--#ifndef __KERNEL__
--
--#include <sys/ioctl.h>
--
--static inline __s32 i2c_smbus_access(int file, char read_write, __u8 command,
-- int size, union i2c_smbus_data *data)
--{
-- struct i2c_smbus_ioctl_data args;
--
-- args.read_write = read_write;
-- args.command = command;
-- args.size = size;
-- args.data = data;
-- return ioctl(file,I2C_SMBUS,&args);
--}
--
--
--static inline __s32 i2c_smbus_write_quick(int file, __u8 value)
--{
-- return i2c_smbus_access(file,value,0,I2C_SMBUS_QUICK,NULL);
--}
--
--static inline __s32 i2c_smbus_read_byte(int file)
--{
-- union i2c_smbus_data data;
-- if (i2c_smbus_access(file,I2C_SMBUS_READ,0,I2C_SMBUS_BYTE,&data))
-- return -1;
-- else
-- return 0x0FF & data.byte;
--}
--
--static inline __s32 i2c_smbus_write_byte(int file, __u8 value)
--{
-- return i2c_smbus_access(file,I2C_SMBUS_WRITE,value,
-- I2C_SMBUS_BYTE,NULL);
--}
--
--static inline __s32 i2c_smbus_read_byte_data(int file, __u8 command)
--{
-- union i2c_smbus_data data;
-- if (i2c_smbus_access(file,I2C_SMBUS_READ,command,
-- I2C_SMBUS_BYTE_DATA,&data))
-- return -1;
-- else
-- return 0x0FF & data.byte;
--}
--
--static inline __s32 i2c_smbus_write_byte_data(int file, __u8 command,
-- __u8 value)
--{
-- union i2c_smbus_data data;
-- data.byte = value;
-- return i2c_smbus_access(file,I2C_SMBUS_WRITE,command,
-- I2C_SMBUS_BYTE_DATA, &data);
--}
--
--static inline __s32 i2c_smbus_read_word_data(int file, __u8 command)
--{
-- union i2c_smbus_data data;
-- if (i2c_smbus_access(file,I2C_SMBUS_READ,command,
-- I2C_SMBUS_WORD_DATA,&data))
-- return -1;
-- else
-- return 0x0FFFF & data.word;
--}
--
--static inline __s32 i2c_smbus_write_word_data(int file, __u8 command,
-- __u16 value)
--{
-- union i2c_smbus_data data;
-- data.word = value;
-- return i2c_smbus_access(file,I2C_SMBUS_WRITE,command,
-- I2C_SMBUS_WORD_DATA, &data);
--}
--
--static inline __s32 i2c_smbus_process_call(int file, __u8 command, __u16 value)
--{
-- union i2c_smbus_data data;
-- data.word = value;
-- if (i2c_smbus_access(file,I2C_SMBUS_WRITE,command,
-- I2C_SMBUS_PROC_CALL,&data))
-- return -1;
-- else
-- return 0x0FFFF & data.word;
--}
--
--
--/* Returns the number of read bytes */
--static inline __s32 i2c_smbus_read_block_data(int file, __u8 command,
-- __u8 *values)
--{
-- union i2c_smbus_data data;
-- int i;
-- if (i2c_smbus_access(file,I2C_SMBUS_READ,command,
-- I2C_SMBUS_BLOCK_DATA,&data))
-- return -1;
-- else {
-- for (i = 1; i <= data.block[0]; i++)
-- values[i-1] = data.block[i];
-- return data.block[0];
-- }
--}
--
--static inline __s32 i2c_smbus_write_block_data(int file, __u8 command,
-- __u8 length, __u8 *values)
--{
-- union i2c_smbus_data data;
-- int i;
-- if (length > 32)
-- length = 32;
-- for (i = 1; i <= length; i++)
-- data.block[i] = values[i-1];
-- data.block[0] = length;
-- return i2c_smbus_access(file,I2C_SMBUS_WRITE,command,
-- I2C_SMBUS_BLOCK_DATA, &data);
--}
--
--static inline __s32 i2c_smbus_write_i2c_block_data(int file, __u8 command,
-- __u8 length, __u8 *values)
--{
-- union i2c_smbus_data data;
-- int i;
-- if (length > 32)
-- length = 32;
-- for (i = 1; i <= length; i++)
-- data.block[i] = values[i-1];
-- data.block[0] = length;
-- return i2c_smbus_access(file,I2C_SMBUS_WRITE,command,
-- I2C_SMBUS_I2C_BLOCK_DATA, &data);
--}
--
--#endif /* ndef __KERNEL__ */
--
--#endif
-+#endif /* _LINUX_I2C_DEV_H */
---- linux-old/drivers/i2c/i2c-elektor.c Tue Jan 20 15:10:31 2004
-+++ linux/drivers/i2c/i2c-elektor.c Mon Dec 13 19:26:33 2004
-@@ -31,23 +31,22 @@
- #include <linux/delay.h>
- #include <linux/slab.h>
- #include <linux/init.h>
-+#include <linux/interrupt.h>
- #include <linux/pci.h>
--#include <asm/irq.h>
--#include <asm/io.h>
--
-+#include <linux/wait.h>
- #include <linux/i2c.h>
- #include <linux/i2c-algo-pcf.h>
--#include <linux/i2c-elektor.h>
--#include "i2c-pcf8584.h"
-+#include <asm/io.h>
-+#include <asm/irq.h>
-
- #define DEFAULT_BASE 0x330
-
--static int base = 0;
--static int irq = 0;
-+static int base;
-+static int irq;
- static int clock = 0x1c;
- static int own = 0x55;
--static int mmapped = 0;
--static int i2c_debug = 0;
-+static int mmapped;
-+static int i2c_debug;
-
- /* vdovikin: removed static struct i2c_pcf_isa gpi; code -
- this module in real supports only one device, due to missing arguments
-@@ -56,6 +55,7 @@
-
- static wait_queue_head_t pcf_wait;
- static int pcf_pending;
-+static spinlock_t irq_driver_lock = SPIN_LOCK_UNLOCKED;
-
- /* ----- global defines ----------------------------------------------- */
- #define DEB(x) if (i2c_debug>=1) x
-@@ -63,13 +63,24 @@
- #define DEB3(x) if (i2c_debug>=3) x
- #define DEBE(x) x /* error messages */
-
-+
-+/* compatibility */
-+#ifndef isa_readb
-+#define isa_readb readb
-+#endif
-+
-+#ifndef isa_writeb
-+#define isa_writeb writeb
-+#endif
-+
- /* ----- local functions ---------------------------------------------- */
-
- static void pcf_isa_setbyte(void *data, int ctl, int val)
- {
- int address = ctl ? (base + 1) : base;
-
-- if (ctl && irq) {
-+ /* enable irq if any specified for serial operation */
-+ if (ctl && irq && (val & I2C_PCF_ESO)) {
- val |= I2C_PCF_ENI;
- }
-
-@@ -81,10 +92,10 @@
- break;
- case 2: /* double mapped I/O needed for UP2000 board,
- I don't know why this... */
-- writeb(val, address);
-+ isa_writeb(val, address);
- /* fall */
- case 1: /* memory mapped I/O */
-- writeb(val, address);
-+ isa_writeb(val, address);
- break;
- }
- }
-@@ -92,7 +103,7 @@
- static int pcf_isa_getbyte(void *data, int ctl)
- {
- int address = ctl ? (base + 1) : base;
-- int val = mmapped ? readb(address) : inb(address);
-+ int val = mmapped ? isa_readb(address) : inb(address);
-
- DEB3(printk(KERN_DEBUG "i2c-elektor.o: Read 0x%X 0x%02X\n", address, val));
-
-@@ -115,12 +126,12 @@
- int timeout = 2;
-
- if (irq > 0) {
-- cli();
-+ spin_lock_irq(&irq_driver_lock);
- if (pcf_pending == 0) {
- interruptible_sleep_on_timeout(&pcf_wait, timeout*HZ );
- } else
- pcf_pending = 0;
-- sti();
-+ spin_unlock_irq(&irq_driver_lock);
- } else {
- udelay(100);
- }
-@@ -136,13 +147,11 @@
- static int pcf_isa_init(void)
- {
- if (!mmapped) {
-- if (check_region(base, 2) < 0 ) {
-+ if (!request_region(base, 2, "i2c (isa bus adapter)")) {
- printk(KERN_ERR
- "i2c-elektor.o: requested I/O region (0x%X:2) "
- "is in use.\n", base);
- return -ENODEV;
-- } else {
-- request_region(base, 2, "i2c (isa bus adapter)");
- }
- }
- if (irq > 0) {
-@@ -156,70 +165,29 @@
- }
-
-
--static void __exit pcf_isa_exit(void)
--{
-- if (irq > 0) {
-- disable_irq(irq);
-- free_irq(irq, 0);
-- }
-- if (!mmapped) {
-- release_region(base , 2);
-- }
--}
--
--
--static int pcf_isa_reg(struct i2c_client *client)
--{
-- return 0;
--}
--
--
--static int pcf_isa_unreg(struct i2c_client *client)
--{
-- return 0;
--}
--
--static void pcf_isa_inc_use(struct i2c_adapter *adap)
--{
--#ifdef MODULE
-- MOD_INC_USE_COUNT;
--#endif
--}
--
--static void pcf_isa_dec_use(struct i2c_adapter *adap)
--{
--#ifdef MODULE
-- MOD_DEC_USE_COUNT;
--#endif
--}
--
--
- /* ------------------------------------------------------------------------
- * Encapsulate the above functions in the correct operations structure.
- * This is only done when more than one hardware adapter is supported.
- */
- static struct i2c_algo_pcf_data pcf_isa_data = {
-- NULL,
-- pcf_isa_setbyte,
-- pcf_isa_getbyte,
-- pcf_isa_getown,
-- pcf_isa_getclock,
-- pcf_isa_waitforpin,
-- 10, 10, 100, /* waits, timeout */
-+ .setpcf = pcf_isa_setbyte,
-+ .getpcf = pcf_isa_getbyte,
-+ .getown = pcf_isa_getown,
-+ .getclock = pcf_isa_getclock,
-+ .waitforpin = pcf_isa_waitforpin,
-+ .udelay = 10,
-+ .mdelay = 10,
-+ .timeout = HZ,
- };
-
- static struct i2c_adapter pcf_isa_ops = {
-- "PCF8584 ISA adapter",
-- I2C_HW_P_ELEK,
-- NULL,
-- &pcf_isa_data,
-- pcf_isa_inc_use,
-- pcf_isa_dec_use,
-- pcf_isa_reg,
-- pcf_isa_unreg,
-+ .owner = THIS_MODULE,
-+ .name = "PCF8584 ISA adapter",
-+ .id = I2C_HW_P_ELEK,
-+ .algo_data = &pcf_isa_data,
- };
-
--int __init i2c_pcfisa_init(void)
-+static int __init i2c_pcfisa_init(void)
- {
- #ifdef __alpha__
- /* check to see we have memory mapped PCF8584 connected to the
-@@ -277,22 +245,41 @@
- }
-
- init_waitqueue_head(&pcf_wait);
-- if (pcf_isa_init() == 0) {
-- if (i2c_pcf_add_bus(&pcf_isa_ops) < 0)
-- return -ENODEV;
-- } else {
-+ if (pcf_isa_init())
- return -ENODEV;
-- }
-+ if (i2c_pcf_add_bus(&pcf_isa_ops) < 0)
-+ goto fail;
-
- printk(KERN_DEBUG "i2c-elektor.o: found device at %#x.\n", base);
-
- return 0;
-+
-+ fail:
-+ if (irq > 0) {
-+ disable_irq(irq);
-+ free_irq(irq, 0);
-+ }
-+
-+ if (!mmapped)
-+ release_region(base , 2);
-+ return -ENODEV;
- }
-
-+static void __exit i2c_pcfisa_exit(void)
-+{
-+ i2c_pcf_del_bus(&pcf_isa_ops);
-+
-+ if (irq > 0) {
-+ disable_irq(irq);
-+ free_irq(irq, 0);
-+ }
-+
-+ if (!mmapped)
-+ release_region(base , 2);
-+}
-
- EXPORT_NO_SYMBOLS;
-
--#ifdef MODULE
- MODULE_AUTHOR("Hans Berglund <hb@spacetec.no>");
- MODULE_DESCRIPTION("I2C-Bus adapter routines for PCF8584 ISA bus adapter");
- MODULE_LICENSE("GPL");
-@@ -304,15 +291,5 @@
- MODULE_PARM(mmapped, "i");
- MODULE_PARM(i2c_debug, "i");
-
--int init_module(void)
--{
-- return i2c_pcfisa_init();
--}
--
--void cleanup_module(void)
--{
-- i2c_pcf_del_bus(&pcf_isa_ops);
-- pcf_isa_exit();
--}
--
--#endif
-+module_init(i2c_pcfisa_init);
-+module_exit(i2c_pcfisa_exit);
---- linux-old/include/linux/i2c-elektor.h Tue Nov 6 00:55:29 2001
-+++ linux/include/linux/i2c-elektor.h Mon Dec 13 19:26:33 2004
-@@ -1,47 +0,0 @@
--/* ------------------------------------------------------------------------- */
--/* i2c-elektor.c i2c-hw access for PCF8584 style isa bus adaptes */
--/* ------------------------------------------------------------------------- */
--/* Copyright (C) 1995-97 Simon G. Vogl
-- 1998-99 Hans Berglund
--
-- 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., 675 Mass Ave, Cambridge, MA 02139, USA. */
--/* ------------------------------------------------------------------------- */
--
--/* With some changes from Kyösti Mälkki <kmalkki@cc.hut.fi> and even
-- Frodo Looijaard <frodol@dds.nl> */
--
--/* $Id: i2c-elektor.h,v 1.5 2001/06/05 01:46:33 mds Exp $ */
--
--#ifndef I2C_PCF_ELEKTOR_H
--#define I2C_PCF_ELEKTOR_H 1
--
--/*
-- * This struct contains the hw-dependent functions of PCF8584 adapters to
-- * manipulate the registers, and to init any hw-specific features.
-- * vdovikin: removed: this module in real supports only one device,
-- * due to missing arguments in some functions, called from the algo-pcf module.
-- * Sometimes it's need to be rewriten -
-- * but for now just remove this for simpler reading */
--
--/*
--struct i2c_pcf_isa {
-- int pi_base;
-- int pi_irq;
-- int pi_clock;
-- int pi_own;
--};
--*/
--
--#endif /* PCF_ELEKTOR_H */
---- linux-old/drivers/i2c/i2c-elv.c Tue Jan 20 15:10:31 2004
-+++ linux/drivers/i2c/i2c-elv.c Mon Dec 13 19:26:33 2004
-@@ -21,21 +21,18 @@
- /* With some changes from Kyösti Mälkki <kmalkki@cc.hut.fi> and even
- Frodo Looijaard <frodol@dds.nl> */
-
--/* $Id: i2c-elv.c,v 1.17 2001/07/29 02:44:25 mds Exp $ */
-+/* $Id: i2c-elv.c,v 1.29 2003/12/22 20:03:11 khali Exp $ */
-
- #include <linux/kernel.h>
- #include <linux/module.h>
- #include <linux/delay.h>
- #include <linux/slab.h>
- #include <linux/init.h>
--
--#include <asm/uaccess.h>
--
- #include <linux/ioport.h>
--#include <asm/io.h>
- #include <linux/errno.h>
- #include <linux/i2c.h>
- #include <linux/i2c-algo-bit.h>
-+#include <asm/io.h>
-
- #define DEFAULT_BASE 0x378
- static int base=0;
-@@ -89,58 +86,31 @@
-
- static int bit_elv_init(void)
- {
-- if (check_region(base,(base == 0x3bc)? 3 : 8) < 0 ) {
-- return -ENODEV;
-- } else {
-- /* test for ELV adap. */
-- if (inb(base+1) & 0x80) { /* BUSY should be high */
-- DEBINIT(printk(KERN_DEBUG "i2c-elv.o: Busy was low.\n"));
-- return -ENODEV;
-- } else {
-- outb(0x0c,base+2); /* SLCT auf low */
-- udelay(400);
-- if ( !(inb(base+1) && 0x10) ) {
-- outb(0x04,base+2);
-- DEBINIT(printk(KERN_DEBUG "i2c-elv.o: Select was high.\n"));
-- return -ENODEV;
-- }
-- }
-- request_region(base,(base == 0x3bc)? 3 : 8,
-- "i2c (ELV adapter)");
-- PortData = 0;
-- bit_elv_setsda((void*)base,1);
-- bit_elv_setscl((void*)base,1);
-+ if (!request_region(base, (base == 0x3bc) ? 3 : 8,
-+ "i2c (ELV adapter)"))
-+ return -ENODEV;
-+
-+ if (inb(base+1) & 0x80) { /* BUSY should be high */
-+ DEBINIT(printk(KERN_DEBUG "i2c-elv.o: Busy was low.\n"));
-+ goto fail;
-+ }
-+
-+ outb(0x0c,base+2); /* SLCT auf low */
-+ udelay(400);
-+ if (!(inb(base+1) && 0x10)) {
-+ outb(0x04,base+2);
-+ DEBINIT(printk(KERN_DEBUG "i2c-elv.o: Select was high.\n"));
-+ goto fail;
- }
-- return 0;
--}
--
--static void __exit bit_elv_exit(void)
--{
-- release_region( base , (base == 0x3bc)? 3 : 8 );
--}
--
--static int bit_elv_reg(struct i2c_client *client)
--{
-- return 0;
--}
-
--static int bit_elv_unreg(struct i2c_client *client)
--{
-+ PortData = 0;
-+ bit_elv_setsda((void*)base,1);
-+ bit_elv_setscl((void*)base,1);
- return 0;
--}
-
--static void bit_elv_inc_use(struct i2c_adapter *adap)
--{
--#ifdef MODULE
-- MOD_INC_USE_COUNT;
--#endif
--}
--
--static void bit_elv_dec_use(struct i2c_adapter *adap)
--{
--#ifdef MODULE
-- MOD_DEC_USE_COUNT;
--#endif
-+fail:
-+ release_region(base , (base == 0x3bc) ? 3 : 8);
-+ return -ENODEV;
- }
-
- /* ------------------------------------------------------------------------
-@@ -148,26 +118,23 @@
- * This is only done when more than one hardware adapter is supported.
- */
- static struct i2c_algo_bit_data bit_elv_data = {
-- NULL,
-- bit_elv_setsda,
-- bit_elv_setscl,
-- bit_elv_getsda,
-- bit_elv_getscl,
-- 80, 80, 100, /* waits, timeout */
-+ .setsda = bit_elv_setsda,
-+ .setscl = bit_elv_setscl,
-+ .getsda = bit_elv_getsda,
-+ .getscl = bit_elv_getscl,
-+ .udelay = 80,
-+ .mdelay = 80,
-+ .timeout = HZ
- };
-
- static struct i2c_adapter bit_elv_ops = {
-- "ELV Parallel port adaptor",
-- I2C_HW_B_ELV,
-- NULL,
-- &bit_elv_data,
-- bit_elv_inc_use,
-- bit_elv_dec_use,
-- bit_elv_reg,
-- bit_elv_unreg,
-+ .owner = THIS_MODULE,
-+ .name = "ELV Parallel port adaptor",
-+ .id = I2C_HW_B_ELV,
-+ .algo_data = &bit_elv_data,
- };
-
--int __init i2c_bitelv_init(void)
-+static int __init i2c_bitelv_init(void)
- {
- printk(KERN_INFO "i2c-elv.o: i2c ELV parallel port adapter module version %s (%s)\n", I2C_VERSION, I2C_DATE);
- if (base==0) {
-@@ -193,25 +160,19 @@
- return 0;
- }
-
-+static void __exit i2c_bitelv_exit(void)
-+{
-+ i2c_bit_del_bus(&bit_elv_ops);
-+ release_region(base, (base == 0x3bc) ? 3 : 8);
-+}
-
- EXPORT_NO_SYMBOLS;
-
--#ifdef MODULE
- MODULE_AUTHOR("Simon G. Vogl <simon@tk.uni-linz.ac.at>");
- MODULE_DESCRIPTION("I2C-Bus adapter routines for ELV parallel port adapter");
- MODULE_LICENSE("GPL");
-
- MODULE_PARM(base, "i");
-
--int init_module(void)
--{
-- return i2c_bitelv_init();
--}
--
--void cleanup_module(void)
--{
-- i2c_bit_del_bus(&bit_elv_ops);
-- bit_elv_exit();
--}
--
--#endif
-+module_init(i2c_bitelv_init);
-+module_exit(i2c_bitelv_exit);
---- linux-old/drivers/i2c/i2c-frodo.c Thu Jan 1 00:00:00 1970
-+++ linux/drivers/i2c/i2c-frodo.c Mon Dec 13 19:26:33 2004
-@@ -0,0 +1,83 @@
-+
-+/*
-+ * linux/drivers/i2c/i2c-frodo.c
-+ *
-+ * Author: Abraham van der Merwe <abraham@2d3d.co.za>
-+ *
-+ * An I2C adapter driver for the 2d3D, Inc. StrongARM SA-1110
-+ * Development board (Frodo).
-+ *
-+ * This source code 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/kernel.h>
-+#include <linux/init.h>
-+#include <linux/delay.h>
-+#include <linux/i2c.h>
-+#include <linux/i2c-algo-bit.h>
-+#include <asm/hardware.h>
-+
-+
-+static void frodo_setsda (void *data,int state)
-+{
-+ if (state)
-+ FRODO_CPLD_I2C |= FRODO_I2C_SDA_OUT;
-+ else
-+ FRODO_CPLD_I2C &= ~FRODO_I2C_SDA_OUT;
-+}
-+
-+static void frodo_setscl (void *data,int state)
-+{
-+ if (state)
-+ FRODO_CPLD_I2C |= FRODO_I2C_SCL_OUT;
-+ else
-+ FRODO_CPLD_I2C &= ~FRODO_I2C_SCL_OUT;
-+}
-+
-+static int frodo_getsda (void *data)
-+{
-+ return ((FRODO_CPLD_I2C & FRODO_I2C_SDA_IN) != 0);
-+}
-+
-+static int frodo_getscl (void *data)
-+{
-+ return ((FRODO_CPLD_I2C & FRODO_I2C_SCL_IN) != 0);
-+}
-+
-+static struct i2c_algo_bit_data bit_frodo_data = {
-+ .setsda = frodo_setsda,
-+ .setscl = frodo_setscl,
-+ .getsda = frodo_getsda,
-+ .getscl = frodo_getscl,
-+ .udelay = 80,
-+ .mdelay = 80,
-+ .timeout = HZ
-+};
-+
-+static struct i2c_adapter frodo_ops = {
-+ .owner = THIS_MODULE,
-+ .name = "Frodo adapter driver",
-+ .id = I2C_HW_B_FRODO,
-+ .algo_data = &bit_frodo_data,
-+};
-+
-+static int __init i2c_frodo_init (void)
-+{
-+ return i2c_bit_add_bus(&frodo_ops);
-+}
-+
-+static void __exit i2c_frodo_exit (void)
-+{
-+ i2c_bit_del_bus(&frodo_ops);
-+}
-+
-+MODULE_AUTHOR ("Abraham van der Merwe <abraham@2d3d.co.za>");
-+MODULE_DESCRIPTION ("I2C-Bus adapter routines for Frodo");
-+MODULE_LICENSE ("GPL");
-+
-+module_init (i2c_frodo_init);
-+module_exit (i2c_frodo_exit);
-+
---- linux-old/include/linux/i2c-id.h Wed Jul 7 00:38:02 2004
-+++ linux/include/linux/i2c-id.h Mon Dec 13 19:26:33 2004
-@@ -20,10 +20,11 @@
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
- /* ------------------------------------------------------------------------- */
-
--/* $Id: i2c-id.h,v 1.35 2001/08/12 17:22:20 mds Exp $ */
-+/* $Id: i2c-id.h,v 1.92 2004/07/27 18:15:06 mmh Exp $ */
-+
-+#ifndef LINUX_I2C_ID_H
-+#define LINUX_I2C_ID_H
-
--#ifndef I2C_ID_H
--#define I2C_ID_H
- /*
- * This file is part of the i2c-bus package and contains the identifier
- * values for drivers, adapters and other folk populating these serial
-@@ -90,10 +91,25 @@
- #define I2C_DRIVERID_DRP3510 43 /* ADR decoder (Astra Radio) */
- #define I2C_DRIVERID_SP5055 44 /* Satellite tuner */
- #define I2C_DRIVERID_STV0030 45 /* Multipurpose switch */
-+#define I2C_DRIVERID_SAA7108 46 /* video decoder, image scaler */
-+#define I2C_DRIVERID_DS1307 47 /* DS1307 real time clock */
- #define I2C_DRIVERID_ADV7175 48 /* ADV 7175/7176 video encoder */
--#define I2C_DRIVERID_MAX1617 56 /* temp sensor */
--#define I2C_DRIVERID_SAA7191 57 /* video decoder */
--#define I2C_DRIVERID_INDYCAM 58 /* SGI IndyCam */
-+#define I2C_DRIVERID_ZR36067 49 /* Zoran 36067 video encoder */
-+#define I2C_DRIVERID_ZR36120 50 /* Zoran 36120 video encoder */
-+#define I2C_DRIVERID_24LC32A 51 /* Microchip 24LC32A 32k EEPROM */
-+#define I2C_DRIVERID_STM41T00 52 /* real time clock */
-+#define I2C_DRIVERID_UDA1342 53 /* UDA1342 audio codec */
-+#define I2C_DRIVERID_ADV7170 54 /* video encoder */
-+#define I2C_DRIVERID_RADEON 55 /* I2C bus on Radeon boards */
-+#define I2C_DRIVERID_MAX1617 56 /* temp sensor */
-+#define I2C_DRIVERID_SAA7191 57 /* video encoder */
-+#define I2C_DRIVERID_INDYCAM 58 /* SGI IndyCam */
-+#define I2C_DRIVERID_BT832 59 /* CMOS camera video processor */
-+#define I2C_DRIVERID_TDA9887 60 /* TDA988x IF-PLL demodulator */
-+#define I2C_DRIVERID_OVCAMCHIP 61 /* OmniVision CMOS image sens. */
-+#define I2C_DRIVERID_TDA7313 62 /* TDA7313 audio processor */
-+#define I2C_DRIVERID_MAX6900 63 /* MAX6900 real-time clock */
-+
-
- #define I2C_DRIVERID_EXP0 0xF0 /* experimental use id's */
- #define I2C_DRIVERID_EXP1 0xF1
-@@ -102,6 +118,8 @@
-
- #define I2C_DRIVERID_I2CDEV 900
- #define I2C_DRIVERID_I2CPROC 901
-+#define I2C_DRIVERID_ARP 902 /* SMBus ARP Client */
-+#define I2C_DRIVERID_ALERT 903 /* SMBus Alert Responder Client */
-
- /* IDs -- Use DRIVERIDs 1000-1999 for sensors.
- These were originally in sensors.h in the lm_sensors package */
-@@ -131,6 +149,28 @@
- #define I2C_DRIVERID_ADM1024 1025
- #define I2C_DRIVERID_IT87 1026
- #define I2C_DRIVERID_CH700X 1027 /* single driver for CH7003-7009 digital pc to tv encoders */
-+#define I2C_DRIVERID_FSCPOS 1028
-+#define I2C_DRIVERID_FSCSCY 1029
-+#define I2C_DRIVERID_PCF8591 1030
-+#define I2C_DRIVERID_SMSC47M1 1031
-+#define I2C_DRIVERID_VT1211 1032
-+#define I2C_DRIVERID_LM92 1033
-+#define I2C_DRIVERID_VT8231 1034
-+#define I2C_DRIVERID_SMARTBATT 1035
-+#define I2C_DRIVERID_BMCSENSORS 1036
-+#define I2C_DRIVERID_FS451 1037
-+#define I2C_DRIVERID_W83627HF 1038
-+#define I2C_DRIVERID_LM85 1039
-+#define I2C_DRIVERID_LM83 1040
-+#define I2C_DRIVERID_SAA1064 1041
-+#define I2C_DRIVERID_LM90 1042
-+#define I2C_DRIVERID_ASB100 1043
-+#define I2C_DRIVERID_MAX6650 1044
-+#define I2C_DRIVERID_XEONTEMP 1045
-+#define I2C_DRIVERID_FSCHER 1046
-+#define I2C_DRIVERID_W83L785TS 1047
-+#define I2C_DRIVERID_ADM1026 1048
-+#define I2C_DRIVERID_LM93 1049
-
- /*
- * ---- Adapter types ----------------------------------------------------
-@@ -147,16 +187,21 @@
- #define I2C_ALGO_ISA 0x050000 /* lm_sensors ISA pseudo-adapter */
- #define I2C_ALGO_SAA7146 0x060000 /* SAA 7146 video decoder bus */
- #define I2C_ALGO_ACB 0x070000 /* ACCESS.bus algorithm */
--
-+#define I2C_ALGO_IIC 0x080000 /* ITE IIC bus */
-+#define I2C_ALGO_SAA7134 0x090000
-+#define I2C_ALGO_MPC824X 0x0a0000 /* Motorola 8240 / 8245 */
-+#define I2C_ALGO_IPMI 0x0b0000 /* IPMI dummy adapter */
-+#define I2C_ALGO_IPMB 0x0c0000 /* IPMB adapter */
-+#define I2C_ALGO_MPC107 0x0d0000
- #define I2C_ALGO_EC 0x100000 /* ACPI embedded controller */
-
- #define I2C_ALGO_MPC8XX 0x110000 /* MPC8xx PowerPC I2C algorithm */
--
--#define I2C_ALGO_SIBYTE 0x120000 /* Broadcom SiByte SOCs */
--
--#define I2C_ALGO_SGI 0x130000 /* SGI algorithm */
--
--#define I2C_ALGO_AU1550 0x140000 /* Alchemy Au1550 PSC */
-+#define I2C_ALGO_OCP 0x120000 /* IBM or otherwise On-chip I2C algorithm */
-+#define I2C_ALGO_BITHS 0x130000 /* enhanced bit style adapters */
-+#define I2C_ALGO_OCP_IOP3XX 0x140000 /* XSCALE IOP3XX On-chip I2C alg */
-+#define I2C_ALGO_SIBYTE 0x150000 /* Broadcom SiByte SOCs */
-+#define I2C_ALGO_SGI 0x160000 /* SGI algorithm */
-+#define I2C_ALGO_USB 0x170000 /* USB algorithm */
-
- #define I2C_ALGO_EXP 0x800000 /* experimental */
-
-@@ -184,21 +229,46 @@
- #define I2C_HW_B_I810 0x0a /* Intel I810 */
- #define I2C_HW_B_VOO 0x0b /* 3dfx Voodoo 3 / Banshee */
- #define I2C_HW_B_PPORT 0x0c /* Primitive parallel port adapter */
-+#define I2C_HW_B_SAVG 0x0d /* Savage 4 */
-+#define I2C_HW_B_SCX200 0x0e /* Nat'l Semi SCx200 I2C */
- #define I2C_HW_B_RIVA 0x10 /* Riva based graphics cards */
- #define I2C_HW_B_IOC 0x11 /* IOC bit-wiggling */
- #define I2C_HW_B_TSUNA 0x12 /* DEC Tsunami chipset */
-+#define I2C_HW_B_FRODO 0x13 /* 2d3D, Inc. SA-1110 Development Board */
-+#define I2C_HW_B_OMAHA 0x14 /* Omaha I2C interface (ARM) */
-+#define I2C_HW_B_GUIDE 0x15 /* Guide bit-basher */
-+#define I2C_HW_B_IXP2000 0x16 /* GPIO on IXP2000 systems */
-+#define I2C_HW_B_IXP425 0x17 /* GPIO on IXP425 systems */
-+#define I2C_HW_B_S3VIA 0x18 /* S3Via ProSavage adapter */
-+#define I2C_HW_B_ZR36067 0x19 /* Zoran-36057/36067 based boards */
-+#define I2C_HW_B_PCILYNX 0x1a /* TI PCILynx I2C adapter */
-
- /* --- PCF 8584 based algorithms */
- #define I2C_HW_P_LP 0x00 /* Parallel port interface */
- #define I2C_HW_P_ISA 0x01 /* generic ISA Bus inteface card */
- #define I2C_HW_P_ELEK 0x02 /* Elektor ISA Bus inteface card */
-
-+/* --- USB based adapters */
-+#define I2C_HW_USB_USBVISION 0x00
-+
- /* --- ACPI Embedded controller algorithms */
- #define I2C_HW_ACPI_EC 0x00
-
-+/* --- MPC824x PowerPC adapters */
-+#define I2C_HW_MPC824X 0x00 /* Motorola 8240 / 8245 */
-+
- /* --- MPC8xx PowerPC adapters */
- #define I2C_HW_MPC8XX_EPON 0x00 /* Eponymous MPC8xx I2C adapter */
-
-+/* --- ITE based algorithms */
-+#define I2C_HW_I_IIC 0x00 /* controller on the ITE */
-+
-+/* --- PowerPC on-chip adapters */
-+#define I2C_HW_OCP 0x00 /* IBM on-chip I2C adapter */
-+
-+/* --- XSCALE on-chip adapters */
-+#define I2C_HW_IOP321 0x00
-+
- /* --- Broadcom SiByte adapters */
- #define I2C_HW_SIBYTE 0x00
-
-@@ -206,9 +276,6 @@
- #define I2C_HW_SGI_VINO 0x00
- #define I2C_HW_SGI_MACE 0x01
-
--/* --- Au1550 PSC adapters */
--#define I2C_HW_AU1550_PSC 0x00
--
- /* --- SMBus only adapters */
- #define I2C_HW_SMBUS_PIIX4 0x00
- #define I2C_HW_SMBUS_ALI15X3 0x01
-@@ -218,9 +285,27 @@
- #define I2C_HW_SMBUS_AMD756 0x05
- #define I2C_HW_SMBUS_SIS5595 0x06
- #define I2C_HW_SMBUS_ALI1535 0x07
-+#define I2C_HW_SMBUS_SIS630 0x08
-+#define I2C_HW_SMBUS_SIS645 0x09
-+#define I2C_HW_SMBUS_AMD8111 0x0a
-+#define I2C_HW_SMBUS_SCX200 0x0b
-+#define I2C_HW_SMBUS_NFORCE2 0x0c
- #define I2C_HW_SMBUS_W9968CF 0x0d
-+#define I2C_HW_SMBUS_OV511 0x0e /* OV511(+) USB 1.1 webcam ICs */
-+#define I2C_HW_SMBUS_OV518 0x0f /* OV518(+) USB 1.1 webcam ICs */
-+#define I2C_HW_SMBUS_OV519 0x10 /* OV519 USB 1.1 webcam IC */
-+#define I2C_HW_SMBUS_OVFX2 0x11 /* Cypress/OmniVision FX2 webcam */
-
- /* --- ISA pseudo-adapter */
- #define I2C_HW_ISA 0x00
-
--#endif /* I2C_ID_H */
-+/* --- IPMI pseudo-adapter */
-+#define I2C_HW_IPMI 0x00
-+
-+/* --- IPMB adapter */
-+#define I2C_HW_IPMB 0x00
-+
-+/* --- MCP107 adapter */
-+#define I2C_HW_MPC107 0x00
-+
-+#endif /* LINUX_I2C_ID_H */
---- linux-old/drivers/i2c/i2c-pcf-epp.c Thu Jan 1 00:00:00 1970
-+++ linux/drivers/i2c/i2c-pcf-epp.c Mon Dec 13 19:26:34 2004
-@@ -0,0 +1,281 @@
-+/* ------------------------------------------------------------------------- */
-+/* i2c-pcf-epp.c i2c-hw access for PCF8584 style EPP parallel port adapters */
-+/* ------------------------------------------------------------------------- */
-+/* Copyright (C) 1998-99 Hans Berglund
-+
-+ 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., 675 Mass Ave, Cambridge, MA 02139, USA. */
-+/* ------------------------------------------------------------------------- */
-+
-+/* With some changes from Ryosuke Tajima <rosk@jsk.t.u-tokyo.ac.jp> */
-+
-+#include <linux/kernel.h>
-+#include <linux/ioport.h>
-+#include <linux/module.h>
-+#include <linux/delay.h>
-+#include <linux/slab.h>
-+#include <linux/init.h>
-+#include <linux/parport.h>
-+#include <linux/i2c.h>
-+#include <linux/i2c-algo-pcf.h>
-+#include <asm/irq.h>
-+#include <asm/io.h>
-+
-+
-+struct i2c_pcf_epp {
-+ int pe_base;
-+ int pe_irq;
-+ int pe_clock;
-+ int pe_own;
-+} ;
-+
-+#define DEFAULT_BASE 0x378
-+#define DEFAULT_IRQ 7
-+#define DEFAULT_CLOCK 0x1c
-+#define DEFAULT_OWN 0x55
-+
-+static int base = 0;
-+static int irq = 0;
-+static int clock = 0;
-+static int own = 0;
-+static int i2c_debug=0;
-+static struct i2c_pcf_epp gpe;
-+static wait_queue_head_t pcf_wait;
-+static int pcf_pending;
-+static spinlock_t irq_driver_lock = SPIN_LOCK_UNLOCKED;
-+
-+/* ----- global defines ----------------------------------------------- */
-+#define DEB(x) if (i2c_debug>=1) x
-+#define DEB2(x) if (i2c_debug>=2) x
-+#define DEB3(x) if (i2c_debug>=3) x
-+#define DEBE(x) x /* error messages */
-+
-+/* --- Convenience defines for the EPP/SPP port: */
-+#define BASE ((struct i2c_pcf_epp *)(data))->pe_base
-+// #define DATA BASE /* SPP data port */
-+#define STAT (BASE+1) /* SPP status port */
-+#define CTRL (BASE+2) /* SPP control port */
-+#define EADD (BASE+3) /* EPP address port */
-+#define EDAT (BASE+4) /* EPP data port */
-+
-+/* ----- local functions ---------------------------------------------- */
-+
-+static void pcf_epp_setbyte(void *data, int ctl, int val)
-+{
-+ if (ctl) {
-+ if (gpe.pe_irq > 0) {
-+ DEB3(printk(KERN_DEBUG "i2c-pcf-epp.o: Write control 0x%x\n",
-+ val|I2C_PCF_ENI));
-+ // set A0 pin HIGH
-+ outb(inb(CTRL) | PARPORT_CONTROL_INIT, CTRL);
-+ // DEB3(printk(KERN_DEBUG "i2c-pcf-epp.o: CTRL port = 0x%x\n", inb(CTRL)));
-+ // DEB3(printk(KERN_DEBUG "i2c-pcf-epp.o: STAT port = 0x%x\n", inb(STAT)));
-+
-+ // EPP write data cycle
-+ outb(val | I2C_PCF_ENI, EDAT);
-+ } else {
-+ DEB3(printk(KERN_DEBUG "i2c-pcf-epp.o: Write control 0x%x\n", val));
-+ // set A0 pin HIGH
-+ outb(inb(CTRL) | PARPORT_CONTROL_INIT, CTRL);
-+ outb(val, CTRL);
-+ }
-+ } else {
-+ DEB3(printk(KERN_DEBUG "i2c-pcf-epp.o: Write data 0x%x\n", val));
-+ // set A0 pin LO
-+ outb(inb(CTRL) & ~PARPORT_CONTROL_INIT, CTRL);
-+ // DEB3(printk(KERN_DEBUG "i2c-pcf-epp.o: CTRL port = 0x%x\n", inb(CTRL)));
-+ // DEB3(printk(KERN_DEBUG "i2c-pcf-epp.o: STAT port = 0x%x\n", inb(STAT)));
-+ outb(val, EDAT);
-+ }
-+}
-+
-+static int pcf_epp_getbyte(void *data, int ctl)
-+{
-+ int val;
-+
-+ if (ctl) {
-+ // set A0 pin HIGH
-+ outb(inb(CTRL) | PARPORT_CONTROL_INIT, CTRL);
-+ val = inb(EDAT);
-+ DEB3(printk(KERN_DEBUG "i2c-pcf-epp.o: Read control 0x%x\n", val));
-+ } else {
-+ // set A0 pin LOW
-+ outb(inb(CTRL) & ~PARPORT_CONTROL_INIT, CTRL);
-+ val = inb(EDAT);
-+ DEB3(printk(KERN_DEBUG "i2c-pcf-epp.o: Read data 0x%x\n", val));
-+ }
-+ return (val);
-+}
-+
-+static int pcf_epp_getown(void *data)
-+{
-+ return (gpe.pe_own);
-+}
-+
-+
-+static int pcf_epp_getclock(void *data)
-+{
-+ return (gpe.pe_clock);
-+}
-+
-+#if 0
-+static void pcf_epp_sleep(unsigned long timeout)
-+{
-+ schedule_timeout( timeout * HZ);
-+}
-+#endif
-+
-+static void pcf_epp_waitforpin(void) {
-+ int timeout = 10;
-+
-+ if (gpe.pe_irq > 0) {
-+ spin_lock_irq(&irq_driver_lock);
-+ if (pcf_pending == 0) {
-+ interruptible_sleep_on_timeout(&pcf_wait, timeout*HZ);
-+ //udelay(100);
-+ } else {
-+ pcf_pending = 0;
-+ }
-+ spin_unlock_irq(&irq_driver_lock);
-+ } else {
-+ udelay(100);
-+ }
-+}
-+
-+static void pcf_epp_handler(int this_irq, void *dev_id, struct pt_regs *regs) {
-+ pcf_pending = 1;
-+ wake_up_interruptible(&pcf_wait);
-+ DEB3(printk(KERN_DEBUG "i2c-pcf-epp.o: in interrupt handler.\n"));
-+}
-+
-+
-+static int pcf_epp_init(void *data)
-+{
-+ if (check_region(gpe.pe_base, 5) < 0 ) {
-+
-+ printk(KERN_WARNING "Could not request port region with base 0x%x\n", gpe.pe_base);
-+ return -ENODEV;
-+ } else {
-+ request_region(gpe.pe_base, 5, "i2c (EPP parallel port adapter)");
-+ }
-+
-+ DEB3(printk(KERN_DEBUG "i2c-pcf-epp.o: init status port = 0x%x\n", inb(0x379)));
-+
-+ if (gpe.pe_irq > 0) {
-+ if (request_irq(gpe.pe_irq, pcf_epp_handler, 0, "PCF8584", 0) < 0) {
-+ printk(KERN_NOTICE "i2c-pcf-epp.o: Request irq%d failed\n", gpe.pe_irq);
-+ gpe.pe_irq = 0;
-+ } else
-+ disable_irq(gpe.pe_irq);
-+ enable_irq(gpe.pe_irq);
-+ }
-+ // EPP mode initialize
-+ // enable interrupt from nINTR pin
-+ outb(inb(CTRL)|0x14, CTRL);
-+ // clear ERROR bit of STAT
-+ outb(inb(STAT)|0x01, STAT);
-+ outb(inb(STAT)&~0x01,STAT);
-+
-+ return 0;
-+}
-+
-+/* ------------------------------------------------------------------------
-+ * Encapsulate the above functions in the correct operations structure.
-+ * This is only done when more than one hardware adapter is supported.
-+ */
-+static struct i2c_algo_pcf_data pcf_epp_data = {
-+ .setpcf = pcf_epp_setbyte,
-+ .getpcf = pcf_epp_getbyte,
-+ .getown = pcf_epp_getown,
-+ .getclock = pcf_epp_getclock,
-+ .waitforpin = pcf_epp_waitforpin,
-+ .udelay = 80,
-+ .mdelay = 80,
-+ .timeout = HZ,
-+};
-+
-+static struct i2c_adapter pcf_epp_ops = {
-+ .owner = THIS_MODULE,
-+ .name = "PCF8584 EPP adapter",
-+ .id = I2C_HW_P_LP,
-+ .algo_data = &pcf_epp_data,
-+};
-+
-+static int __init i2c_pcfepp_init(void)
-+{
-+ struct i2c_pcf_epp *pepp = &gpe;
-+
-+ printk(KERN_DEBUG "i2c-pcf-epp.o: i2c pcf8584-epp adapter module version %s (%s)\n", I2C_VERSION, I2C_DATE);
-+ if (base == 0)
-+ pepp->pe_base = DEFAULT_BASE;
-+ else
-+ pepp->pe_base = base;
-+
-+ if (irq == 0)
-+ pepp->pe_irq = DEFAULT_IRQ;
-+ else if (irq<0) {
-+ // switch off irq
-+ pepp->pe_irq=0;
-+ } else {
-+ pepp->pe_irq = irq;
-+ }
-+ if (clock == 0)
-+ pepp->pe_clock = DEFAULT_CLOCK;
-+ else
-+ pepp->pe_clock = clock;
-+
-+ if (own == 0)
-+ pepp->pe_own = DEFAULT_OWN;
-+ else
-+ pepp->pe_own = own;
-+
-+ pcf_epp_data.data = (void *)pepp;
-+ init_waitqueue_head(&pcf_wait);
-+ if (pcf_epp_init(pepp) == 0) {
-+ int ret;
-+ if ( (ret = i2c_pcf_add_bus(&pcf_epp_ops)) < 0) {
-+ printk(KERN_WARNING "i2c_pcf_add_bus caused an error: %d\n",ret);
-+ release_region(pepp->pe_base , 5);
-+ return ret;
-+ }
-+ } else {
-+
-+ return -ENODEV;
-+ }
-+ printk(KERN_DEBUG "i2c-pcf-epp.o: found device at %#x.\n", pepp->pe_base);
-+ return 0;
-+}
-+
-+static void __exit pcf_epp_exit(void)
-+{
-+ i2c_pcf_del_bus(&pcf_epp_ops);
-+ if (gpe.pe_irq > 0) {
-+ disable_irq(gpe.pe_irq);
-+ free_irq(gpe.pe_irq, 0);
-+ }
-+ release_region(gpe.pe_base , 5);
-+}
-+
-+MODULE_AUTHOR("Hans Berglund <hb@spacetec.no> \n modified by Ryosuke Tajima <rosk@jsk.t.u-tokyo.ac.jp>");
-+MODULE_DESCRIPTION("I2C-Bus adapter routines for PCF8584 EPP parallel port adapter");
-+MODULE_LICENSE("GPL");
-+
-+MODULE_PARM(base, "i");
-+MODULE_PARM(irq, "i");
-+MODULE_PARM(clock, "i");
-+MODULE_PARM(own, "i");
-+MODULE_PARM(i2c_debug, "i");
-+
-+module_init(i2c_pcfepp_init);
-+module_exit(pcf_epp_exit);
---- linux-old/include/linux/i2c-pcf8584.h Thu Jan 1 00:00:00 1970
-+++ linux/include/linux/i2c-pcf8584.h Mon Dec 13 19:26:34 2004
-@@ -0,0 +1,78 @@
-+/* -------------------------------------------------------------------- */
-+/* i2c-pcf8584.h: PCF 8584 global defines */
-+/* -------------------------------------------------------------------- */
-+/* Copyright (C) 1996 Simon G. Vogl
-+ 1999 Hans Berglund
-+
-+ 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., 675 Mass Ave, Cambridge, MA 02139, USA. */
-+/* -------------------------------------------------------------------- */
-+
-+/* With some changes from Frodo Looijaard <frodol@dds.nl> */
-+
-+/* $Id: i2c-pcf8584.h,v 1.6 2003/07/25 07:56:42 khali Exp $ */
-+
-+#ifndef _LINUX_I2C_PCF8584_H
-+#define _LINUX_I2C_PCF8584_H
-+
-+/* ----- Control register bits ---------------------------------------- */
-+#define I2C_PCF_PIN 0x80
-+#define I2C_PCF_ESO 0x40
-+#define I2C_PCF_ES1 0x20
-+#define I2C_PCF_ES2 0x10
-+#define I2C_PCF_ENI 0x08
-+#define I2C_PCF_STA 0x04
-+#define I2C_PCF_STO 0x02
-+#define I2C_PCF_ACK 0x01
-+
-+#define I2C_PCF_START (I2C_PCF_PIN | I2C_PCF_ESO | I2C_PCF_STA | I2C_PCF_ACK)
-+#define I2C_PCF_STOP (I2C_PCF_PIN | I2C_PCF_ESO | I2C_PCF_STO | I2C_PCF_ACK)
-+#define I2C_PCF_REPSTART ( I2C_PCF_ESO | I2C_PCF_STA | I2C_PCF_ACK)
-+#define I2C_PCF_IDLE (I2C_PCF_PIN | I2C_PCF_ESO | I2C_PCF_ACK)
-+
-+/* ----- Status register bits ----------------------------------------- */
-+/*#define I2C_PCF_PIN 0x80 as above*/
-+
-+#define I2C_PCF_INI 0x40 /* 1 if not initialized */
-+#define I2C_PCF_STS 0x20
-+#define I2C_PCF_BER 0x10
-+#define I2C_PCF_AD0 0x08
-+#define I2C_PCF_LRB 0x08
-+#define I2C_PCF_AAS 0x04
-+#define I2C_PCF_LAB 0x02
-+#define I2C_PCF_BB 0x01
-+
-+/* ----- Chip clock frequencies --------------------------------------- */
-+#define I2C_PCF_CLK3 0x00
-+#define I2C_PCF_CLK443 0x10
-+#define I2C_PCF_CLK6 0x14
-+#define I2C_PCF_CLK 0x18
-+#define I2C_PCF_CLK12 0x1c
-+
-+/* ----- transmission frequencies ------------------------------------- */
-+#define I2C_PCF_TRNS90 0x00 /* 90 kHz */
-+#define I2C_PCF_TRNS45 0x01 /* 45 kHz */
-+#define I2C_PCF_TRNS11 0x02 /* 11 kHz */
-+#define I2C_PCF_TRNS15 0x03 /* 1.5 kHz */
-+
-+
-+/* ----- Access to internal registers according to ES1,ES2 ------------ */
-+/* they are mapped to the data port ( a0 = 0 ) */
-+/* available when ESO == 0 : */
-+
-+#define I2C_PCF_OWNADR 0
-+#define I2C_PCF_INTREG I2C_PCF_ES2
-+#define I2C_PCF_CLKREG I2C_PCF_ES1
-+
-+#endif /* _LINUX_I2C_PCF8584_H */
---- linux-old/drivers/i2c/i2c-philips-par.c Fri Feb 20 01:22:16 2004
-+++ linux/drivers/i2c/i2c-philips-par.c Mon Dec 13 19:26:34 2004
-@@ -21,7 +21,7 @@
- /* With some changes from Kyösti Mälkki <kmalkki@cc.hut.fi> and even
- Frodo Looijaard <frodol@dds.nl> */
-
--/* $Id: i2c-philips-par.c,v 1.18 2000/07/06 19:21:49 frodo Exp $ */
-+/* $Id: i2c-philips-par.c,v 1.33 2004/01/23 20:22:53 khali Exp $ */
-
- #include <linux/kernel.h>
- #include <linux/ioport.h>
-@@ -29,14 +29,10 @@
- #include <linux/init.h>
- #include <linux/stddef.h>
- #include <linux/parport.h>
--
-+#include <linux/slab.h>
- #include <linux/i2c.h>
- #include <linux/i2c-algo-bit.h>
-
--#ifndef __exit
--#define __exit __init
--#endif
--
- static int type;
-
- struct i2c_par
-@@ -130,59 +126,34 @@
- PARPORT_STATUS_BUSY) ? 0 : 1;
- }
-
--static int bit_lp_reg(struct i2c_client *client)
--{
-- return 0;
--}
--
--static int bit_lp_unreg(struct i2c_client *client)
--{
-- return 0;
--}
--
--static void bit_lp_inc_use(struct i2c_adapter *adap)
--{
-- MOD_INC_USE_COUNT;
--}
--
--static void bit_lp_dec_use(struct i2c_adapter *adap)
--{
-- MOD_DEC_USE_COUNT;
--}
--
- /* ------------------------------------------------------------------------
- * Encapsulate the above functions in the correct operations structure.
- * This is only done when more than one hardware adapter is supported.
- */
-
- static struct i2c_algo_bit_data bit_lp_data = {
-- NULL,
-- bit_lp_setsda,
-- bit_lp_setscl,
-- bit_lp_getsda,
-- bit_lp_getscl,
-- 80, 80, 100, /* waits, timeout */
-+ .setsda = bit_lp_setsda,
-+ .setscl = bit_lp_setscl,
-+ .getsda = bit_lp_getsda,
-+ .getscl = bit_lp_getscl,
-+ .udelay = 80,
-+ .mdelay = 80,
-+ .timeout = HZ
- };
-
- static struct i2c_algo_bit_data bit_lp_data2 = {
-- NULL,
-- bit_lp_setsda2,
-- bit_lp_setscl2,
-- bit_lp_getsda2,
-- NULL,
-- 80, 80, 100, /* waits, timeout */
-+ .setsda = bit_lp_setsda2,
-+ .setscl = bit_lp_setscl2,
-+ .getsda = bit_lp_getsda2,
-+ .udelay = 80,
-+ .mdelay = 80,
-+ .timeout = HZ
- };
-
- static struct i2c_adapter bit_lp_ops = {
-- "Philips Parallel port adapter",
-- I2C_HW_B_LP,
-- NULL,
-- NULL,
-- bit_lp_inc_use,
-- bit_lp_dec_use,
-- bit_lp_reg,
--
-- bit_lp_unreg,
-+ .owner = THIS_MODULE,
-+ .name = "Philips Parallel port adapter",
-+ .id = I2C_HW_B_LP,
- };
-
- static void i2c_parport_attach (struct parport *port)
-@@ -202,6 +173,7 @@
- NULL);
- if (!adapter->pdev) {
- printk(KERN_ERR "i2c-philips-par: Unable to register with parport.\n");
-+ kfree(adapter);
- return;
- }
-
-@@ -210,8 +182,12 @@
- adapter->bit_lp_data = type ? bit_lp_data2 : bit_lp_data;
- adapter->bit_lp_data.data = port;
-
-+ if (parport_claim_or_block(adapter->pdev) < 0 ) {
-+ printk(KERN_ERR "i2c-philips-par: Could not claim parallel port.\n");
-+ kfree(adapter);
-+ return;
-+ }
- /* reset hardware to sane state */
-- parport_claim_or_block(adapter->pdev);
- adapter->bit_lp_data.setsda(port, 1);
- adapter->bit_lp_data.setscl(port, 1);
- parport_release(adapter->pdev);
-@@ -257,7 +233,7 @@
- NULL
- };
-
--int __init i2c_bitlp_init(void)
-+static int __init i2c_bitlp_init(void)
- {
- printk(KERN_INFO "i2c-philips-par.o: i2c Philips parallel port adapter module version %s (%s)\n", I2C_VERSION, I2C_DATE);
-
-@@ -266,7 +242,7 @@
- return 0;
- }
-
--void __exit i2c_bitlp_exit(void)
-+static void __exit i2c_bitlp_exit(void)
- {
- parport_unregister_driver(&i2c_driver);
- }
-@@ -279,14 +255,5 @@
-
- MODULE_PARM(type, "i");
-
--#ifdef MODULE
--int init_module(void)
--{
-- return i2c_bitlp_init();
--}
--
--void cleanup_module(void)
--{
-- i2c_bitlp_exit();
--}
--#endif
-+module_init(i2c_bitlp_init);
-+module_exit(i2c_bitlp_exit);
---- linux-old/drivers/i2c/i2c-pport.c Thu Jan 1 00:00:00 1970
-+++ linux/drivers/i2c/i2c-pport.c Mon Dec 13 19:26:34 2004
-@@ -0,0 +1,169 @@
-+/* ------------------------------------------------------------------------- */
-+/* i2c-pport.c i2c-hw access for primitive i2c par. port adapter */
-+/* ------------------------------------------------------------------------- */
-+/* Copyright (C) 2001 Daniel Smolik
-+
-+ 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., 675 Mass Ave, Cambridge, MA 02139, USA. */
-+/* ------------------------------------------------------------------------- */
-+
-+/*
-+ See doc/i2c-pport for instructions on wiring to the
-+ parallel port connector.
-+
-+ Cut & paste :-) based on Velleman K8000 driver by Simon G. Vogl
-+
-+ Note that SDA is hardware inverted.
-+*/
-+
-+
-+#include <linux/kernel.h>
-+#include <linux/module.h>
-+#include <linux/delay.h>
-+#include <linux/slab.h>
-+#include <linux/init.h>
-+#include <linux/ioport.h>
-+#include <linux/errno.h>
-+#include <linux/i2c.h>
-+#include <linux/i2c-algo-bit.h>
-+#include <asm/io.h>
-+
-+
-+#define DEFAULT_BASE 0x378
-+static int base = DEFAULT_BASE;
-+static unsigned char PortData = 0;
-+
-+/* ----- global defines ----------------------------------------------- */
-+#define DEB(x) /* should be reasonable open, close &c. */
-+#define DEB2(x) /* low level debugging - very slow */
-+#define DEBE(x) x /* error messages */
-+#define DEBINIT(x) x /* detection status messages */
-+
-+/* --- Convenience defines for the parallel port: */
-+#define BASE (unsigned int)(data)
-+#define DATA BASE /* Centronics data port */
-+#define STAT (BASE+1) /* Centronics status port */
-+#define CTRL (BASE+2) /* Centronics control port */
-+
-+/* we will use SDA - Auto Linefeed(14) POUT (ctrl bit 1) */
-+/* we will use SCL - Initialize printer(16) BUSY (ctrl bit 2) */
-+
-+#define SET_SCL | 0x04
-+#define CLR_SCL & 0xFB
-+
-+#define SET_SDA & 0xFD
-+#define CLR_SDA | 0x02
-+
-+
-+/* ----- local functions ---------------------------------------------- */
-+
-+
-+static void bit_pport_setscl(void *data, int state)
-+{
-+ if (state) {
-+ PortData = PortData SET_SCL;
-+ } else {
-+ PortData = PortData CLR_SCL;
-+ }
-+ outb(PortData, CTRL);
-+}
-+
-+static void bit_pport_setsda(void *data, int state)
-+{
-+ if (state) {
-+ PortData = PortData SET_SDA;
-+ } else {
-+ PortData = PortData CLR_SDA;
-+ }
-+ outb(PortData, CTRL);
-+}
-+
-+static int bit_pport_getscl(void *data)
-+{
-+ return ( 4 == ( (inb_p(CTRL)) & 0x04 ) );
-+}
-+
-+static int bit_pport_getsda(void *data)
-+{
-+ return ( 0 == ( (inb_p(CTRL)) & 0x02 ) );
-+}
-+
-+static int bit_pport_init(void)
-+{
-+ if (!request_region((base+2),1, "i2c (PPORT adapter)")) {
-+ return -ENODEV;
-+ }
-+
-+ PortData = inb(base+2);
-+ bit_pport_setsda((void*)base, 1);
-+ bit_pport_setscl((void*)base, 1);
-+
-+ return 0;
-+}
-+
-+
-+/* ------------------------------------------------------------------------
-+ * Encapsulate the above functions in the correct operations structure.
-+ * This is only done when more than one hardware adapter is supported.
-+ */
-+static struct i2c_algo_bit_data bit_pport_data = {
-+ .setsda = bit_pport_setsda,
-+ .setscl = bit_pport_setscl,
-+ .getsda = bit_pport_getsda,
-+ .getscl = bit_pport_getscl,
-+ .udelay = 40,
-+ .mdelay = 80,
-+ .timeout = HZ
-+};
-+
-+static struct i2c_adapter bit_pport_ops = {
-+ .owner = THIS_MODULE,
-+ .name = "Primitive Parallel port adaptor",
-+ .id = I2C_HW_B_PPORT,
-+ .algo_data = &bit_pport_data,
-+};
-+
-+static int __init i2c_bitpport_init(void)
-+{
-+ printk("i2c-pport.o: i2c Primitive parallel port adapter module version %s (%s)\n", I2C_VERSION, I2C_DATE);
-+
-+ bit_pport_data.data = (void*)base;
-+ if (bit_pport_init() < 0)
-+ return -ENODEV;
-+
-+ if (i2c_bit_add_bus(&bit_pport_ops) < 0) {
-+ release_region(base+2, 1);
-+ return -ENODEV;
-+ }
-+
-+ printk("i2c-pport.o: found device at %#x.\n",base);
-+ return 0;
-+}
-+
-+static void __exit i2c_bitpport_exit(void)
-+{
-+ i2c_bit_del_bus(&bit_pport_ops);
-+ release_region((base+2),1);
-+}
-+
-+EXPORT_NO_SYMBOLS;
-+
-+MODULE_AUTHOR("Daniel Smolik <marvin@sitour.cz>");
-+MODULE_DESCRIPTION("I2C-Bus adapter routines for Primitive parallel port adapter");
-+MODULE_LICENSE("GPL");
-+
-+MODULE_PARM(base, "i");
-+
-+module_init(i2c_bitpport_init);
-+module_exit(i2c_bitpport_exit);
---- linux-old/drivers/i2c/i2c-proc.c Tue Jan 20 15:10:31 2004
-+++ linux/drivers/i2c/i2c-proc.c Mon Dec 13 19:26:35 2004
-@@ -23,29 +23,26 @@
- This driver puts entries in /proc/sys/dev/sensors for each I2C device
- */
-
-+#include <linux/config.h>
- #include <linux/module.h>
- #include <linux/kernel.h>
- #include <linux/slab.h>
- #include <linux/ctype.h>
- #include <linux/sysctl.h>
- #include <linux/proc_fs.h>
-+#include <linux/init.h>
- #include <linux/ioport.h>
--#include <asm/uaccess.h>
--
- #include <linux/i2c.h>
- #include <linux/i2c-proc.h>
-+#include <asm/uaccess.h>
-
--#include <linux/init.h>
--
--#ifndef THIS_MODULE
--#define THIS_MODULE NULL
-+#ifndef CONFIG_SYSCTL
-+#error Your kernel lacks sysctl support (CONFIG_SYSCTL)!
- #endif
-
--static int i2c_create_name(char **name, const char *prefix,
-- struct i2c_adapter *adapter, int addr);
- static int i2c_parse_reals(int *nrels, void *buffer, int bufsize,
- long *results, int magnitude);
--static int i2c_write_reals(int nrels, void *buffer, int *bufsize,
-+static int i2c_write_reals(int nrels, void *buffer, size_t *bufsize,
- long *results, int magnitude);
- static int i2c_proc_chips(ctl_table * ctl, int write,
- struct file *filp, void *buffer,
-@@ -55,22 +52,10 @@
- void *newval, size_t newlen,
- void **context);
-
--int __init sensors_init(void);
--
- #define SENSORS_ENTRY_MAX 20
- static struct ctl_table_header *i2c_entries[SENSORS_ENTRY_MAX];
-
- static struct i2c_client *i2c_clients[SENSORS_ENTRY_MAX];
--static unsigned short i2c_inodes[SENSORS_ENTRY_MAX];
--
--static ctl_table sysctl_table[] = {
-- {CTL_DEV, "dev", NULL, 0, 0555},
-- {0},
-- {DEV_SENSORS, "sensors", NULL, 0, 0555},
-- {0},
-- {0, NULL, NULL, 0, 0555},
-- {0}
--};
-
- static ctl_table i2c_proc_dev_sensors[] = {
- {SENSORS_CHIPS, "chips", NULL, 0, 0644, NULL, &i2c_proc_chips,
-@@ -91,31 +76,45 @@
-
-
- static struct ctl_table_header *i2c_proc_header;
--static int i2c_initialized;
-
- /* This returns a nice name for a new directory; for example lm78-isa-0310
- (for a LM78 chip on the ISA bus at port 0x310), or lm75-i2c-3-4e (for
- a LM75 chip on the third i2c bus at address 0x4e).
- name is allocated first. */
--int i2c_create_name(char **name, const char *prefix,
-- struct i2c_adapter *adapter, int addr)
-+static char *generate_name(struct i2c_client *client, const char *prefix)
- {
-- char name_buffer[50];
-- int id;
-- if (i2c_is_isa_adapter(adapter))
-+ struct i2c_adapter *adapter = client->adapter;
-+ int addr = client->addr;
-+ char name_buffer[50], *name;
-+
-+ if (i2c_is_isa_adapter(adapter)) {
- sprintf(name_buffer, "%s-isa-%04x", prefix, addr);
-- else {
-- if ((id = i2c_adapter_id(adapter)) < 0)
-- return -ENOENT;
-+ } else if (adapter->algo->smbus_xfer || adapter->algo->master_xfer) {
-+ int id = i2c_adapter_id(adapter);
-+ if (id < 0)
-+ return ERR_PTR(-ENOENT);
- sprintf(name_buffer, "%s-i2c-%d-%02x", prefix, id, addr);
-+ } else { /* dummy adapter, generate prefix */
-+ int end, i;
-+
-+ sprintf(name_buffer, "%s-", prefix);
-+ end = strlen(name_buffer);
-+
-+ for (i = 0; i < 32; i++) {
-+ if (adapter->algo->name[i] == ' ')
-+ break;
-+ name_buffer[end++] = tolower(adapter->algo->name[i]);
-+ }
-+
-+ name_buffer[end] = 0;
-+ sprintf(name_buffer + end, "-%04x", addr);
- }
-- *name = kmalloc(strlen(name_buffer) + 1, GFP_KERNEL);
-- if (!*name) {
-- printk (KERN_WARNING "i2c_create_name: not enough memory\n");
-- return -ENOMEM;
-- }
-- strcpy(*name, name_buffer);
-- return 0;
-+
-+ name = kmalloc(strlen(name_buffer) + 1, GFP_KERNEL);
-+ if (!name)
-+ return ERR_PTR(-ENOMEM);
-+ strcpy(name, name_buffer);
-+ return name;
- }
-
- /* This rather complex function must be called when you want to add an entry
-@@ -124,139 +123,91 @@
- ctl_template should be a template of the newly created directory. It is
- copied in memory. The extra2 field of each file is set to point to client.
- If any driver wants subdirectories within the newly created directory,
-- this function must be updated!
-- controlling_mod is the controlling module. It should usually be
-- THIS_MODULE when calling. Note that this symbol is not defined in
-- kernels before 2.3.13; define it to NULL in that case. We will not use it
-- for anything older than 2.3.27 anyway. */
-+ this function must be updated! */
- int i2c_register_entry(struct i2c_client *client, const char *prefix,
-- ctl_table * ctl_template,
-- struct module *controlling_mod)
-+ struct ctl_table *ctl_template)
- {
-- int i, res, len, id;
-- ctl_table *new_table;
-- char *name;
-- struct ctl_table_header *new_header;
--
-- if ((res = i2c_create_name(&name, prefix, client->adapter,
-- client->addr))) return res;
-+ struct { struct ctl_table root[2], dev[2], sensors[2]; } *tbl;
-+ struct ctl_table_header *hdr;
-+ struct ctl_table *tmp, *leaf;
-+ const char *name;
-+ int id, len = 0;
-
-- for (id = 0; id < SENSORS_ENTRY_MAX; id++)
-- if (!i2c_entries[id]) {
-- break;
-- }
-- if (id == SENSORS_ENTRY_MAX) {
-- kfree(name);
-- return -ENOMEM;
-- }
-- id += 256;
-+ name = generate_name(client, prefix);
-+ if (IS_ERR(name))
-+ return PTR_ERR(name);
-
-- len = 0;
-- while (ctl_template[len].procname)
-- len++;
-- len += 7;
-- if (!(new_table = kmalloc(sizeof(ctl_table) * len, GFP_KERNEL))) {
-- kfree(name);
-- return -ENOMEM;
-- }
--
-- memcpy(new_table, sysctl_table, 6 * sizeof(ctl_table));
-- new_table[0].child = &new_table[2];
-- new_table[2].child = &new_table[4];
-- new_table[4].child = &new_table[6];
-- new_table[4].procname = name;
-- new_table[4].ctl_name = id;
-- memcpy(new_table + 6, ctl_template, (len - 6) * sizeof(ctl_table));
-- for (i = 6; i < len; i++)
-- new_table[i].extra2 = client;
--
-- if (!(new_header = register_sysctl_table(new_table, 0))) {
-- kfree(new_table);
-- kfree(name);
-- return -ENOMEM;
-+ for (id = 0; id < SENSORS_ENTRY_MAX; id++) {
-+ if (!i2c_entries[id])
-+ goto free_slot;
- }
-
-- i2c_entries[id - 256] = new_header;
-+ goto out_free_name;
-
-- i2c_clients[id - 256] = client;
--#ifdef DEBUG
-- if (!new_header || !new_header->ctl_table ||
-- !new_header->ctl_table->child ||
-- !new_header->ctl_table->child->child ||
-- !new_header->ctl_table->child->child->de) {
-- printk
-- ("i2c-proc.o: NULL pointer when trying to install fill_inode fix!\n");
-- return id;
-- }
--#endif /* DEBUG */
-- i2c_inodes[id - 256] =
-- new_header->ctl_table->child->child->de->low_ino;
-- new_header->ctl_table->child->child->de->owner = controlling_mod;
--
-- return id;
-+ free_slot:
-+ while (ctl_template[len].ctl_name)
-+ len++;
-+ tbl = kmalloc(sizeof(*tbl) + sizeof(ctl_table) * (len + 1),
-+ GFP_KERNEL);
-+ if (!tbl)
-+ goto out_free_name;
-+ memset(tbl, 0, sizeof(*tbl));
-+
-+ /* The client sysctls */
-+ leaf = (struct ctl_table *) (tbl + 1);
-+ memcpy(leaf, ctl_template, sizeof(ctl_table) * (len+1));
-+ for (tmp = leaf; tmp->ctl_name; tmp++)
-+ tmp->extra2 = client;
-+
-+ tbl->sensors->ctl_name = id+256;
-+ tbl->sensors->procname = name;
-+ tbl->sensors->mode = 0555;
-+ tbl->sensors->child = leaf;
-+
-+ tbl->dev->ctl_name = DEV_SENSORS;
-+ tbl->dev->procname = "sensors";
-+ tbl->dev->mode = 0555;
-+ tbl->dev->child = tbl->sensors;
-+
-+ tbl->root->ctl_name = CTL_DEV;
-+ tbl->root->procname = "dev";
-+ tbl->root->mode = 0555;
-+ tbl->root->child = tbl->dev;
-+
-+ hdr = register_sysctl_table(tbl->root, 0);
-+ if (!hdr)
-+ goto out_free_tbl;
-+
-+ i2c_entries[id] = hdr;
-+ i2c_clients[id] = client;
-+
-+ return (id + 256); /* XXX(hch) why?? */
-+
-+ out_free_tbl:
-+ kfree(tbl);
-+ out_free_name:
-+ kfree(name);
-+ return -ENOMEM;
- }
-
- void i2c_deregister_entry(int id)
- {
-- ctl_table *table;
-- char *temp;
- id -= 256;
-- if (i2c_entries[id]) {
-- table = i2c_entries[id]->ctl_table;
-- unregister_sysctl_table(i2c_entries[id]);
-- /* 2-step kfree needed to keep gcc happy about const points */
-- (const char *) temp = table[4].procname;
-- kfree(temp);
-- kfree(table);
-- i2c_entries[id] = NULL;
-- i2c_clients[id] = NULL;
-- }
--}
-
--/* Monitor access for /proc/sys/dev/sensors; make unloading i2c-proc.o
-- impossible if some process still uses it or some file in it */
--void i2c_fill_inode(struct inode *inode, int fill)
--{
-- if (fill)
-- MOD_INC_USE_COUNT;
-- else
-- MOD_DEC_USE_COUNT;
--}
--
--/* Monitor access for /proc/sys/dev/sensors/ directories; make unloading
-- the corresponding module impossible if some process still uses it or
-- some file in it */
--void i2c_dir_fill_inode(struct inode *inode, int fill)
--{
-- int i;
-- struct i2c_client *client;
-+ if (i2c_entries[id]) {
-+ struct ctl_table_header *hdr = i2c_entries[id];
-+ struct ctl_table *tbl = hdr->ctl_table;
-
--#ifdef DEBUG
-- if (!inode) {
-- printk("i2c-proc.o: Warning: inode NULL in fill_inode()\n");
-- return;
-+ unregister_sysctl_table(hdr);
-+ kfree(tbl->child->child->procname);
-+ kfree(tbl); /* actually the whole anonymous struct */
- }
--#endif /* def DEBUG */
-
-- for (i = 0; i < SENSORS_ENTRY_MAX; i++)
-- if (i2c_clients[i]
-- && (i2c_inodes[i] == inode->i_ino)) break;
--#ifdef DEBUG
-- if (i == SENSORS_ENTRY_MAX) {
-- printk
-- ("i2c-proc.o: Warning: inode (%ld) not found in fill_inode()\n",
-- inode->i_ino);
-- return;
-- }
--#endif /* def DEBUG */
-- client = i2c_clients[i];
-- if (fill)
-- client->driver->inc_use(client);
-- else
-- client->driver->dec_use(client);
-+ i2c_entries[id] = NULL;
-+ i2c_clients[id] = NULL;
- }
-
--int i2c_proc_chips(ctl_table * ctl, int write, struct file *filp,
-+static int i2c_proc_chips(ctl_table * ctl, int write, struct file *filp,
- void *buffer, size_t * lenp)
- {
- char BUF[SENSORS_PREFIX_MAX + 30];
-@@ -294,7 +245,7 @@
- return 0;
- }
-
--int i2c_sysctl_chips(ctl_table * table, int *name, int nlen,
-+static int i2c_sysctl_chips(ctl_table * table, int *name, int nlen,
- void *oldval, size_t * oldlenp, void *newval,
- size_t newlen, void **context)
- {
-@@ -456,7 +407,7 @@
- WARNING! This is tricky code. I have tested it, but there may still be
- hidden bugs in it, even leading to crashes and things!
- */
--int i2c_parse_reals(int *nrels, void *buffer, int bufsize,
-+static int i2c_parse_reals(int *nrels, void *buffer, int bufsize,
- long *results, int magnitude)
- {
- int maxels, min, mag;
-@@ -557,7 +508,7 @@
- return 0;
- }
-
--int i2c_write_reals(int nrels, void *buffer, int *bufsize,
-+static int i2c_write_reals(int nrels, void *buffer, size_t *bufsize,
- long *results, int magnitude)
- {
- #define BUFLEN 20
-@@ -646,6 +597,7 @@
- I2C_FUNC_SMBUS_QUICK)) return -1;
-
- for (addr = 0x00; addr <= (is_isa ? 0xffff : 0x7f); addr++) {
-+ /* XXX: WTF is going on here??? */
- if ((is_isa && check_region(addr, 1)) ||
- (!is_isa && i2c_check_addr(adapter, addr)))
- continue;
-@@ -846,46 +798,33 @@
- return 0;
- }
-
--int __init sensors_init(void)
-+static int __init i2c_proc_init(void)
- {
- printk(KERN_INFO "i2c-proc.o version %s (%s)\n", I2C_VERSION, I2C_DATE);
-- i2c_initialized = 0;
- if (!
- (i2c_proc_header =
-- register_sysctl_table(i2c_proc, 0))) return -ENOMEM;
-+ register_sysctl_table(i2c_proc, 0))) {
-+ printk(KERN_ERR "i2c-proc.o: error: sysctl interface not supported by kernel!\n");
-+ return -EPERM;
-+ }
- i2c_proc_header->ctl_table->child->de->owner = THIS_MODULE;
-- i2c_initialized++;
- return 0;
- }
-
-+static void __exit i2c_proc_exit(void)
-+{
-+ unregister_sysctl_table(i2c_proc_header);
-+}
-+
-+EXPORT_SYMBOL(i2c_register_entry);
- EXPORT_SYMBOL(i2c_deregister_entry);
--EXPORT_SYMBOL(i2c_detect);
- EXPORT_SYMBOL(i2c_proc_real);
--EXPORT_SYMBOL(i2c_register_entry);
- EXPORT_SYMBOL(i2c_sysctl_real);
--
--#ifdef MODULE
-+EXPORT_SYMBOL(i2c_detect);
-
- MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl>");
- MODULE_DESCRIPTION("i2c-proc driver");
- MODULE_LICENSE("GPL");
-
--int i2c_cleanup(void)
--{
-- if (i2c_initialized >= 1) {
-- unregister_sysctl_table(i2c_proc_header);
-- i2c_initialized--;
-- }
-- return 0;
--}
--
--int init_module(void)
--{
-- return sensors_init();
--}
--
--int cleanup_module(void)
--{
-- return i2c_cleanup();
--}
--#endif /* MODULE */
-+module_init(i2c_proc_init);
-+module_exit(i2c_proc_exit);
---- linux-old/include/linux/i2c-proc.h Tue Nov 6 00:55:29 2001
-+++ linux/include/linux/i2c-proc.h Mon Dec 13 19:26:36 2004
-@@ -1,6 +1,7 @@
- /*
-- sensors.h - Part of lm_sensors, Linux kernel modules for hardware
-- monitoring
-+ i2c-proc.h - Part of the i2c package
-+ was originally sensors.h - Part of lm_sensors, Linux kernel modules
-+ for hardware monitoring
- Copyright (c) 1998, 1999 Frodo Looijaard <frodol@dds.nl>
-
- This program is free software; you can redistribute it and/or modify
-@@ -18,14 +19,9 @@
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
--#ifndef SENSORS_SENSORS_H
--#define SENSORS_SENSORS_H
-+#ifndef _LINUX_I2C_PROC_H
-+#define _LINUX_I2C_PROC_H
-
--#ifdef __KERNEL__
--
--/* Next two must be included before sysctl.h can be included, in 2.0 kernels */
--#include <linux/types.h>
--#include <linux/fs.h>
- #include <linux/sysctl.h>
-
- /* The type of callback functions used in sensors_{proc,sysctl}_real */
-@@ -73,8 +69,7 @@
- these functions must be updated! */
- extern int i2c_register_entry(struct i2c_client *client,
- const char *prefix,
-- ctl_table * ctl_template,
-- struct module *controlling_mod);
-+ ctl_table * ctl_template);
-
- extern void i2c_deregister_entry(int id);
-
-@@ -347,6 +342,31 @@
- {NULL}}; \
- SENSORS_INSMOD
-
-+#define SENSORS_INSMOD_8(chip1,chip2,chip3,chip4,chip5,chip6,chip7,chip8) \
-+ enum chips { any_chip, chip1, chip2, chip3, chip4, chip5, chip6, chip7, chip8 }; \
-+ SENSORS_MODULE_PARM(force, \
-+ "List of adapter,address pairs to boldly assume " \
-+ "to be present"); \
-+ SENSORS_MODULE_PARM_FORCE(chip1); \
-+ SENSORS_MODULE_PARM_FORCE(chip2); \
-+ SENSORS_MODULE_PARM_FORCE(chip3); \
-+ SENSORS_MODULE_PARM_FORCE(chip4); \
-+ SENSORS_MODULE_PARM_FORCE(chip5); \
-+ SENSORS_MODULE_PARM_FORCE(chip6); \
-+ SENSORS_MODULE_PARM_FORCE(chip7); \
-+ SENSORS_MODULE_PARM_FORCE(chip8); \
-+ static struct i2c_force_data forces[] = {{force,any_chip}, \
-+ {force_ ## chip1,chip1}, \
-+ {force_ ## chip2,chip2}, \
-+ {force_ ## chip3,chip3}, \
-+ {force_ ## chip4,chip4}, \
-+ {force_ ## chip5,chip5}, \
-+ {force_ ## chip6,chip6}, \
-+ {force_ ## chip7,chip7}, \
-+ {force_ ## chip8,chip8}, \
-+ {NULL}}; \
-+ SENSORS_INSMOD
-+
- typedef int i2c_found_addr_proc(struct i2c_adapter *adapter,
- int addr, unsigned short flags,
- int kind);
-@@ -362,7 +382,7 @@
-
- /* This macro is used to scale user-input to sensible values in almost all
- chip drivers. */
--extern inline int SENSORS_LIMIT(long value, long low, long high)
-+static inline int SENSORS_LIMIT(long value, long low, long high)
- {
- if (value < low)
- return low;
-@@ -372,8 +392,6 @@
- return value;
- }
-
--#endif /* def __KERNEL__ */
--
-
- /* The maximum length of the prefix */
- #define SENSORS_PREFIX_MAX 20
-@@ -392,5 +410,5 @@
- char name[SENSORS_PREFIX_MAX + 13];
- };
-
--#endif /* def SENSORS_SENSORS_H */
-+#endif /* def _LINUX_I2C_PROC_H */
-
---- linux-old/drivers/i2c/i2c-rpx.c Thu Jan 1 00:00:00 1970
-+++ linux/drivers/i2c/i2c-rpx.c Mon Dec 13 19:26:36 2004
-@@ -0,0 +1,101 @@
-+/*
-+ * Embedded Planet RPX Lite MPC8xx CPM I2C interface.
-+ * Copyright (c) 1999 Dan Malek (dmalek@jlc.net).
-+ *
-+ * moved into proper i2c interface;
-+ * Brad Parker (brad@heeltoe.com)
-+ *
-+ * RPX lite specific parts of the i2c interface
-+ * Update: There actually isn't anything RPXLite-specific about this module.
-+ * This should work for most any 8xx board. The console messages have been
-+ * changed to eliminate RPXLite references.
-+ */
-+
-+#include <linux/kernel.h>
-+#include <linux/module.h>
-+#include <linux/init.h>
-+#include <linux/stddef.h>
-+#include <linux/i2c.h>
-+#include <linux/i2c-algo-8xx.h>
-+#include <asm/mpc8xx.h>
-+#include <asm/commproc.h>
-+
-+
-+static void
-+rpx_iic_init(struct i2c_algo_8xx_data *data)
-+{
-+ volatile cpm8xx_t *cp;
-+ volatile immap_t *immap;
-+
-+ cp = cpmp; /* Get pointer to Communication Processor */
-+ immap = (immap_t *)IMAP_ADDR; /* and to internal registers */
-+
-+ data->iip = (iic_t *)&cp->cp_dparam[PROFF_IIC];
-+
-+ /* Check for and use a microcode relocation patch.
-+ */
-+ if ((data->reloc = data->iip->iic_rpbase))
-+ data->iip = (iic_t *)&cp->cp_dpmem[data->iip->iic_rpbase];
-+
-+ data->i2c = (i2c8xx_t *)&(immap->im_i2c);
-+ data->cp = cp;
-+
-+ /* Initialize Port B IIC pins.
-+ */
-+ cp->cp_pbpar |= 0x00000030;
-+ cp->cp_pbdir |= 0x00000030;
-+ cp->cp_pbodr |= 0x00000030;
-+
-+ /* Allocate space for two transmit and two receive buffer
-+ * descriptors in the DP ram.
-+ */
-+ data->dp_addr = m8xx_cpm_dpalloc(sizeof(cbd_t) * 4);
-+
-+ /* ptr to i2c area */
-+ data->i2c = (i2c8xx_t *)&(((immap_t *)IMAP_ADDR)->im_i2c);
-+}
-+
-+static int rpx_install_isr(int irq, void (*func)(void *, void *), void *data)
-+{
-+ /* install interrupt handler */
-+ cpm_install_handler(irq, (void (*)(void *, struct pt_regs *)) func, data);
-+
-+ return 0;
-+}
-+
-+static struct i2c_algo_8xx_data rpx_data = {
-+ .setisr = rpx_install_isr
-+};
-+
-+static struct i2c_adapter rpx_ops = {
-+ .owner = THIS_MODULE,
-+ .name = "m8xx",
-+ .id = I2C_HW_MPC8XX_EPON,
-+ .algo_data = &rpx_data,
-+};
-+
-+static int __init i2c_rpx_init(void)
-+{
-+ printk("i2c-rpx.o: i2c MPC8xx module version %s (%s)\n", I2C_VERSION, I2C_DATE);
-+
-+ /* reset hardware to sane state */
-+ rpx_iic_init(&rpx_data);
-+
-+ if (i2c_8xx_add_bus(&rpx_ops) < 0) {
-+ printk("i2c-rpx: Unable to register with I2C\n");
-+ return -ENODEV;
-+ }
-+
-+ return 0;
-+}
-+
-+static void __exit i2c_rpx_exit(void)
-+{
-+ i2c_8xx_del_bus(&rpx_ops);
-+}
-+
-+MODULE_AUTHOR("Dan Malek <dmalek@jlc.net>");
-+MODULE_DESCRIPTION("I2C-Bus adapter routines for MPC8xx boards");
-+
-+module_init(i2c_rpx_init);
-+module_exit(i2c_rpx_exit);
---- linux-old/drivers/i2c/i2c-velleman.c Tue Jan 20 15:10:31 2004
-+++ linux/drivers/i2c/i2c-velleman.c Mon Dec 13 19:26:36 2004
-@@ -18,18 +18,18 @@
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
- /* ------------------------------------------------------------------------- */
-
--/* $Id: i2c-velleman.c,v 1.19 2000/01/24 02:06:33 mds Exp $ */
-+/* $Id: i2c-velleman.c,v 1.33 2003/12/24 17:49:44 khali Exp $ */
-
- #include <linux/kernel.h>
- #include <linux/ioport.h>
- #include <linux/module.h>
- #include <linux/init.h>
--#include <linux/string.h> /* for 2.0 kernels to get NULL */
--#include <asm/errno.h> /* for 2.0 kernels to get ENODEV */
--#include <asm/io.h>
--
-+#include <linux/errno.h>
-+#include <linux/delay.h>
- #include <linux/i2c.h>
- #include <linux/i2c-algo-bit.h>
-+#include <asm/io.h>
-+#include <asm/param.h> /* for HZ */
-
- /* ----- global defines ----------------------------------------------- */
- #define DEB(x) /* should be reasonable open, close &c. */
-@@ -90,75 +90,38 @@
-
- static int bit_velle_init(void)
- {
-- if (check_region(base,(base == 0x3bc)? 3 : 8) < 0 ) {
-- DEBE(printk("i2c-velleman.o: Port %#x already in use.\n",
-- base));
-+ if (!request_region(base, (base == 0x3bc) ? 3 : 8,
-+ "i2c (Vellemann adapter)"))
- return -ENODEV;
-- } else {
-- request_region(base, (base == 0x3bc)? 3 : 8,
-- "i2c (Vellemann adapter)");
-- bit_velle_setsda((void*)base,1);
-- bit_velle_setscl((void*)base,1);
-- }
-- return 0;
--}
-
--static void __exit bit_velle_exit(void)
--{
-- release_region( base , (base == 0x3bc)? 3 : 8 );
--}
--
--
--static int bit_velle_reg(struct i2c_client *client)
--{
-- return 0;
--}
--
--static int bit_velle_unreg(struct i2c_client *client)
--{
-+ bit_velle_setsda((void*)base,1);
-+ bit_velle_setscl((void*)base,1);
- return 0;
- }
-
--static void bit_velle_inc_use(struct i2c_adapter *adap)
--{
--#ifdef MODULE
-- MOD_INC_USE_COUNT;
--#endif
--}
--
--static void bit_velle_dec_use(struct i2c_adapter *adap)
--{
--#ifdef MODULE
-- MOD_DEC_USE_COUNT;
--#endif
--}
--
- /* ------------------------------------------------------------------------
- * Encapsulate the above functions in the correct operations structure.
- * This is only done when more than one hardware adapter is supported.
- */
-
- static struct i2c_algo_bit_data bit_velle_data = {
-- NULL,
-- bit_velle_setsda,
-- bit_velle_setscl,
-- bit_velle_getsda,
-- bit_velle_getscl,
-- 10, 10, 100, /* waits, timeout */
-+ .setsda = bit_velle_setsda,
-+ .setscl = bit_velle_setscl,
-+ .getsda = bit_velle_getsda,
-+ .getscl = bit_velle_getscl,
-+ .udelay = 10,
-+ .mdelay = 10,
-+ .timeout = HZ
- };
-
- static struct i2c_adapter bit_velle_ops = {
-- "Velleman K8000",
-- I2C_HW_B_VELLE,
-- NULL,
-- &bit_velle_data,
-- bit_velle_inc_use,
-- bit_velle_dec_use,
-- bit_velle_reg,
-- bit_velle_unreg,
-+ .owner = THIS_MODULE,
-+ .name = "Velleman K8000",
-+ .id = I2C_HW_B_VELLE,
-+ .algo_data = &bit_velle_data,
- };
-
--int __init i2c_bitvelle_init(void)
-+static int __init i2c_bitvelle_init(void)
- {
- printk(KERN_INFO "i2c-velleman.o: i2c Velleman K8000 adapter module version %s (%s)\n", I2C_VERSION, I2C_DATE);
- if (base==0) {
-@@ -184,24 +147,19 @@
- return 0;
- }
-
-+static void __exit i2c_bitvelle_exit(void)
-+{
-+ i2c_bit_del_bus(&bit_velle_ops);
-+ release_region(base, (base == 0x3bc) ? 3 : 8);
-+}
-+
- EXPORT_NO_SYMBOLS;
-
--#ifdef MODULE
- MODULE_AUTHOR("Simon G. Vogl <simon@tk.uni-linz.ac.at>");
- MODULE_DESCRIPTION("I2C-Bus adapter routines for Velleman K8000 adapter");
- MODULE_LICENSE("GPL");
-
- MODULE_PARM(base, "i");
-
--int init_module(void)
--{
-- return i2c_bitvelle_init();
--}
--
--void cleanup_module(void)
--{
-- i2c_bit_del_bus(&bit_velle_ops);
-- bit_velle_exit();
--}
--
--#endif
-+module_init(i2c_bitvelle_init);
-+module_exit(i2c_bitvelle_exit);
---- linux-old/include/linux/i2c.h Tue Jan 20 15:10:34 2004
-+++ linux/include/linux/i2c.h Mon Dec 13 19:26:37 2004
-@@ -23,36 +23,33 @@
- /* With some changes from Kyösti Mälkki <kmalkki@cc.hut.fi> and
- Frodo Looijaard <frodol@dds.nl> */
-
--/* $Id: i2c.h,v 1.46 2001/08/31 00:04:07 phil Exp $ */
-+/* $Id: i2c.h,v 1.80 2004/10/07 23:47:17 phil Exp $ */
-
--#ifndef I2C_H
--#define I2C_H
-+#ifndef _LINUX_I2C_H
-+#define _LINUX_I2C_H
-
--#define I2C_DATE "20010830"
--#define I2C_VERSION "2.6.1"
-+#define I2C_DATE "20041007"
-+#define I2C_VERSION "2.8.8"
-
--#include <linux/i2c-id.h> /* id values of adapters et. al. */
-+#include <linux/module.h>
- #include <linux/types.h>
--
--
--struct i2c_msg;
--
--
--#ifdef __KERNEL__
--
--/* --- Includes and compatibility declarations ------------------------ */
--
-+#include <linux/errno.h>
-+#include <linux/sched.h>
- #include <asm/semaphore.h>
--#include <linux/config.h>
-+#include <linux/i2c-id.h>
-+
-+#include <linux/version.h>
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,10)
-+#define MODULE_LICENSE(x)
-+#endif
-
- /* --- General options ------------------------------------------------ */
-
--#define I2C_ALGO_MAX 4 /* control memory consumption */
--#define I2C_ADAP_MAX 16
-+#define I2C_ADAP_MAX 16 /* control memory consumption */
- #define I2C_DRIVER_MAX 16
- #define I2C_CLIENT_MAX 32
--#define I2C_DUMMY_MAX 4
-
-+struct i2c_msg;
- struct i2c_algorithm;
- struct i2c_adapter;
- struct i2c_client;
-@@ -60,7 +57,6 @@
- struct i2c_client_address_data;
- union i2c_smbus_data;
-
--
- /*
- * The master routines are the ones normally used to transmit data to devices
- * on a bus (or read from them). Apart from two basic transfer functions to
-@@ -113,6 +109,8 @@
- extern s32 i2c_smbus_write_block_data(struct i2c_client * client,
- u8 command, u8 length,
- u8 *values);
-+extern s32 i2c_smbus_read_i2c_block_data(struct i2c_client * client,
-+ u8 command, u8 *values);
- extern s32 i2c_smbus_write_i2c_block_data(struct i2c_client * client,
- u8 command, u8 length,
- u8 *values);
-@@ -125,6 +123,7 @@
- */
-
- struct i2c_driver {
-+ struct module *owner;
- char name[32];
- int id;
- unsigned int flags; /* div., see below */
-@@ -148,18 +147,6 @@
- * with the device.
- */
- int (*command)(struct i2c_client *client,unsigned int cmd, void *arg);
--
-- /* These two are mainly used for bookkeeping & dynamic unloading of
-- * kernel modules. inc_use tells the driver that a client is being
-- * used by another module & that it should increase its ref. counter.
-- * dec_use is the inverse operation.
-- * NB: Make sure you have no circular dependencies, or else you get a
-- * deadlock when trying to unload the modules.
-- * You should use the i2c_{inc,dec}_use_client functions instead of
-- * calling this function directly.
-- */
-- void (*inc_use)(struct i2c_client *client);
-- void (*dec_use)(struct i2c_client *client);
- };
-
- /*
-@@ -192,6 +179,7 @@
- * to name two of the most common.
- */
- struct i2c_algorithm {
-+ struct module *owner; /* future use --km */
- char name[32]; /* textual description */
- unsigned int id;
-
-@@ -221,16 +209,13 @@
- * with the access algorithms necessary to access it.
- */
- struct i2c_adapter {
-+ struct module *owner;
- char name[32]; /* some useful name to identify the adapter */
- unsigned int id;/* == is algo->id | hwdep.struct->id, */
- /* for registered values see below */
- struct i2c_algorithm *algo;/* the algorithm to access the bus */
- void *algo_data;
-
-- /* --- These may be NULL, but should increase the module use count */
-- void (*inc_use)(struct i2c_adapter *);
-- void (*dec_use)(struct i2c_adapter *);
--
- /* --- administration stuff. */
- int (*client_register)(struct i2c_client *);
- int (*client_unregister)(struct i2c_client *);
-@@ -241,11 +226,11 @@
- /* and can be set via the i2c_ioctl call */
-
- /* data fields that are valid for all devices */
-- struct semaphore lock;
-+ struct semaphore bus;
-+ struct semaphore list;
- unsigned int flags;/* flags specifying div. data */
-
- struct i2c_client *clients[I2C_CLIENT_MAX];
-- int client_count;
-
- int timeout;
- int retries;
-@@ -264,6 +249,9 @@
- #define I2C_CLIENT_ALLOW_USE 0x01 /* Client allows access */
- #define I2C_CLIENT_ALLOW_MULTIPLE_USE 0x02 /* Allow multiple access-locks */
- /* on an i2c_client */
-+#define I2C_CLIENT_PEC 0x04 /* Use Packet Error Checking */
-+#define I2C_CLIENT_TEN 0x10 /* we have a ten bit chip address */
-+ /* Must equal I2C_M_TEN below */
-
- /* i2c_client_address_data is the struct for holding default client
- * addresses for a driver and for the parameters supplied on the
-@@ -302,12 +290,6 @@
- extern int i2c_attach_client(struct i2c_client *);
- extern int i2c_detach_client(struct i2c_client *);
-
--/* Only call these if you grab a resource that makes unloading the
-- client and the adapter it is on completely impossible. Like when a
-- /proc directory is entered. */
--extern void i2c_inc_use_client(struct i2c_client *);
--extern void i2c_dec_use_client(struct i2c_client *);
--
- /* New function: This is to get an i2c_client-struct for controlling the
- client either by using i2c_control-function or having the
- client-module export functions that can be used with the i2c_client
-@@ -341,6 +323,15 @@
- struct i2c_client_address_data *address_data,
- i2c_client_found_addr_proc *found_proc);
-
-+static inline int i2c_client_command(struct i2c_client *client,
-+ unsigned int cmd, void *arg)
-+{
-+ if (client->driver && client->driver->command)
-+ return client->driver->command(client, cmd, arg);
-+ else
-+ return -EINVAL;
-+}
-+
- /* An ioctl like call to set div. parameters of the adapter.
- */
- extern int i2c_control(struct i2c_client *,unsigned int, unsigned long);
-@@ -358,8 +349,6 @@
- /* Return 1 if adapter supports everything we need, 0 if not. */
- extern int i2c_check_functionality (struct i2c_adapter *adap, u32 func);
-
--#endif /* __KERNEL__ */
--
- /*
- * I2C Message - used for pure i2c transaction, also from /dev interface
- */
-@@ -370,15 +359,28 @@
- #define I2C_M_RD 0x01
- #define I2C_M_NOSTART 0x4000
- #define I2C_M_REV_DIR_ADDR 0x2000
-+#define I2C_M_IGNORE_NAK 0x1000
-+#define I2C_M_NO_RD_ACK 0x0800
-+#define I2C_M_RECV_LEN 0x0400 /* length will be first received byte */
-+#define I2C_M_RECV_PEC 0x0200 /* receive one more than the returned
-+ length byte for the PEC */
- __u16 len; /* msg length */
- __u8 *buf; /* pointer to msg data */
-+ int err;
-+ short done;
- };
-
- /* To determine what functionality is present */
-
- #define I2C_FUNC_I2C 0x00000001
- #define I2C_FUNC_10BIT_ADDR 0x00000002
--#define I2C_FUNC_PROTOCOL_MANGLING 0x00000004 /* I2C_M_{REV_DIR_ADDR,NOSTART} */
-+#define I2C_FUNC_PROTOCOL_MANGLING 0x00000004 /* I2C_M_{REV_DIR_ADDR,NOSTART,..} */
-+#define I2C_FUNC_SMBUS_HWPEC_CALC 0x00000008 /* SMBus 2.0 */
-+#define I2C_FUNC_SMBUS_READ_WORD_DATA_PEC 0x00000800 /* SMBus 2.0 */
-+#define I2C_FUNC_SMBUS_WRITE_WORD_DATA_PEC 0x00001000 /* SMBus 2.0 */
-+#define I2C_FUNC_SMBUS_PROC_CALL_PEC 0x00002000 /* SMBus 2.0 */
-+#define I2C_FUNC_SMBUS_BLOCK_PROC_CALL_PEC 0x00004000 /* SMBus 2.0 */
-+#define I2C_FUNC_SMBUS_BLOCK_PROC_CALL 0x00008000 /* SMBus 2.0 */
- #define I2C_FUNC_SMBUS_QUICK 0x00010000
- #define I2C_FUNC_SMBUS_READ_BYTE 0x00020000
- #define I2C_FUNC_SMBUS_WRITE_BYTE 0x00040000
-@@ -389,8 +391,12 @@
- #define I2C_FUNC_SMBUS_PROC_CALL 0x00800000
- #define I2C_FUNC_SMBUS_READ_BLOCK_DATA 0x01000000
- #define I2C_FUNC_SMBUS_WRITE_BLOCK_DATA 0x02000000
--#define I2C_FUNC_SMBUS_READ_I2C_BLOCK 0x04000000 /* New I2C-like block */
--#define I2C_FUNC_SMBUS_WRITE_I2C_BLOCK 0x08000000 /* transfer */
-+#define I2C_FUNC_SMBUS_READ_I2C_BLOCK 0x04000000 /* I2C-like block xfer */
-+#define I2C_FUNC_SMBUS_WRITE_I2C_BLOCK 0x08000000 /* w/ 1-byte reg. addr. */
-+#define I2C_FUNC_SMBUS_READ_I2C_BLOCK_2 0x10000000 /* I2C-like block xfer */
-+#define I2C_FUNC_SMBUS_WRITE_I2C_BLOCK_2 0x20000000 /* w/ 2-byte reg. addr. */
-+#define I2C_FUNC_SMBUS_READ_BLOCK_DATA_PEC 0x40000000 /* SMBus 2.0 */
-+#define I2C_FUNC_SMBUS_WRITE_BLOCK_DATA_PEC 0x80000000 /* SMBus 2.0 */
-
- #define I2C_FUNC_SMBUS_BYTE I2C_FUNC_SMBUS_READ_BYTE | \
- I2C_FUNC_SMBUS_WRITE_BYTE
-@@ -402,13 +408,28 @@
- I2C_FUNC_SMBUS_WRITE_BLOCK_DATA
- #define I2C_FUNC_SMBUS_I2C_BLOCK I2C_FUNC_SMBUS_READ_I2C_BLOCK | \
- I2C_FUNC_SMBUS_WRITE_I2C_BLOCK
-+#define I2C_FUNC_SMBUS_I2C_BLOCK_2 I2C_FUNC_SMBUS_READ_I2C_BLOCK_2 | \
-+ I2C_FUNC_SMBUS_WRITE_I2C_BLOCK_2
-+#define I2C_FUNC_SMBUS_BLOCK_DATA_PEC I2C_FUNC_SMBUS_READ_BLOCK_DATA_PEC | \
-+ I2C_FUNC_SMBUS_WRITE_BLOCK_DATA_PEC
-+#define I2C_FUNC_SMBUS_WORD_DATA_PEC I2C_FUNC_SMBUS_READ_WORD_DATA_PEC | \
-+ I2C_FUNC_SMBUS_WRITE_WORD_DATA_PEC
-+
-+#define I2C_FUNC_SMBUS_READ_BYTE_PEC I2C_FUNC_SMBUS_READ_BYTE_DATA
-+#define I2C_FUNC_SMBUS_WRITE_BYTE_PEC I2C_FUNC_SMBUS_WRITE_BYTE_DATA
-+#define I2C_FUNC_SMBUS_READ_BYTE_DATA_PEC I2C_FUNC_SMBUS_READ_WORD_DATA
-+#define I2C_FUNC_SMBUS_WRITE_BYTE_DATA_PEC I2C_FUNC_SMBUS_WRITE_WORD_DATA
-+#define I2C_FUNC_SMBUS_BYTE_PEC I2C_FUNC_SMBUS_BYTE_DATA
-+#define I2C_FUNC_SMBUS_BYTE_DATA_PEC I2C_FUNC_SMBUS_WORD_DATA
-
- #define I2C_FUNC_SMBUS_EMUL I2C_FUNC_SMBUS_QUICK | \
- I2C_FUNC_SMBUS_BYTE | \
- I2C_FUNC_SMBUS_BYTE_DATA | \
- I2C_FUNC_SMBUS_WORD_DATA | \
- I2C_FUNC_SMBUS_PROC_CALL | \
-- I2C_FUNC_SMBUS_WRITE_BLOCK_DATA
-+ I2C_FUNC_SMBUS_WRITE_BLOCK_DATA | \
-+ I2C_FUNC_SMBUS_WRITE_BLOCK_DATA_PEC | \
-+ I2C_FUNC_SMBUS_I2C_BLOCK
-
- /*
- * Data for SMBus Messages
-@@ -418,8 +439,9 @@
- union i2c_smbus_data {
- __u8 byte;
- __u16 word;
-- __u8 block[I2C_SMBUS_BLOCK_MAX + 2]; /* block[0] is used for length */
-+ __u8 block[I2C_SMBUS_BLOCK_MAX + 3]; /* block[0] is used for length */
- /* one more for read length in block process call */
-+ /* and one more for PEC */
- };
-
- /* smbus_access read or write markers */
-@@ -435,6 +457,11 @@
- #define I2C_SMBUS_PROC_CALL 4
- #define I2C_SMBUS_BLOCK_DATA 5
- #define I2C_SMBUS_I2C_BLOCK_DATA 6
-+#define I2C_SMBUS_BLOCK_PROC_CALL 7 /* SMBus 2.0 */
-+#define I2C_SMBUS_BLOCK_DATA_PEC 8 /* SMBus 2.0 */
-+#define I2C_SMBUS_PROC_CALL_PEC 9 /* SMBus 2.0 */
-+#define I2C_SMBUS_BLOCK_PROC_CALL_PEC 10 /* SMBus 2.0 */
-+#define I2C_SMBUS_WORD_DATA_PEC 11 /* SMBus 2.0 */
-
-
- /* ----- commands for the ioctl like i2c_command call:
-@@ -460,6 +487,7 @@
-
- #define I2C_FUNCS 0x0705 /* Get the adapter functionality */
- #define I2C_RDWR 0x0707 /* Combined R/W transfer (one stop only)*/
-+#define I2C_PEC 0x0708 /* != 0 for SMBus PEC */
- #if 0
- #define I2C_ACK_TEST 0x0710 /* See if a slave is at a specific address */
- #endif
-@@ -475,16 +503,6 @@
-
- #define I2C_MAJOR 89 /* Device major number */
-
--#ifdef __KERNEL__
--
--# ifndef NULL
--# define NULL ( (void *) 0 )
--# endif
--
--# ifndef ENODEV
--# include <asm/errno.h>
--# endif
--
- /* These defines are used for probing i2c client addresses */
- /* Default fill of many variables */
- #define I2C_CLIENT_DEFAULTS {I2C_CLIENT_END, I2C_CLIENT_END, I2C_CLIENT_END, \
-@@ -546,5 +564,11 @@
- #define i2c_is_isa_adapter(adapptr) \
- ((adapptr)->algo->id == I2C_ALGO_ISA)
-
--#endif /* def __KERNEL__ */
--#endif /* I2C_H */
-+/* Tiny delay function used by the i2c bus drivers */
-+static inline void i2c_delay(signed long timeout)
-+{
-+ set_current_state(TASK_INTERRUPTIBLE);
-+ schedule_timeout(timeout);
-+}
-+
-+#endif /* _LINUX_I2C_H */
diff --git a/recipes/linux/linux-mtx-1-2.4.27/17-lmsensors.2.8.8.patch b/recipes/linux/linux-mtx-1-2.4.27/17-lmsensors.2.8.8.patch
deleted file mode 100644
index 78d95c47ad..0000000000
--- a/recipes/linux/linux-mtx-1-2.4.27/17-lmsensors.2.8.8.patch
+++ /dev/null
@@ -1,40940 +0,0 @@
---- linux-old/drivers/i2c/i2c-ali1535.c Thu Jan 1 00:00:00 1970
-+++ linux/drivers/i2c/i2c-ali1535.c Mon Dec 13 20:18:40 2004
-@@ -0,0 +1,601 @@
-+/*
-+ i2c-ali1535.c - Part of lm_sensors, Linux kernel modules for hardware
-+ monitoring
-+ Copyright (c) 2000 Frodo Looijaard <frodol@dds.nl>,
-+ Philip Edelbrock <phil@netroedge.com>,
-+ Mark D. Studebaker <mdsxyz123@yahoo.com>,
-+ Dan Eaton <dan.eaton@rocketlogix.com> and
-+ Stephen Rousset<stephen.rousset@rocketlogix.com>
-+
-+ 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., 675 Mass Ave, Cambridge, MA 02139, USA.
-+*/
-+
-+/*
-+ This is the driver for the SMB Host controller on
-+ Acer Labs Inc. (ALI) M1535 South Bridge.
-+
-+ The M1535 is a South bridge for portable systems.
-+ It is very similar to the M15x3 South bridges also produced
-+ by Acer Labs Inc. Some of the registers within the part
-+ have moved and some have been redefined slightly. Additionally,
-+ the sequencing of the SMBus transactions has been modified
-+ to be more consistent with the sequencing recommended by
-+ the manufacturer and observed through testing. These
-+ changes are reflected in this driver and can be identified
-+ by comparing this driver to the i2c-ali15x3 driver.
-+ For an overview of these chips see http://www.acerlabs.com
-+
-+ The SMB controller is part of the 7101 device, which is an
-+ ACPI-compliant Power Management Unit (PMU).
-+
-+ The whole 7101 device has to be enabled for the SMB to work.
-+ You can't just enable the SMB alone.
-+ The SMB and the ACPI have separate I/O spaces.
-+ We make sure that the SMB is enabled. We leave the ACPI alone.
-+
-+ This driver controls the SMB Host only.
-+
-+ This driver does not use interrupts.
-+*/
-+
-+
-+/* Note: we assume there can only be one ALI1535, with one SMBus interface */
-+
-+#include <linux/module.h>
-+#include <linux/pci.h>
-+#include <linux/kernel.h>
-+#include <linux/stddef.h>
-+#include <linux/sched.h>
-+#include <linux/ioport.h>
-+#include <linux/i2c.h>
-+#include <linux/init.h>
-+#include <asm/io.h>
-+#include <asm/semaphore.h>
-+#define LM_DATE "20041007"
-+#define LM_VERSION "2.8.8"
-+
-+
-+/* ALI1535 SMBus address offsets */
-+#define SMBHSTSTS (0 + ali1535_smba)
-+#define SMBHSTTYP (1 + ali1535_smba)
-+#define SMBHSTPORT (2 + ali1535_smba)
-+#define SMBHSTCMD (7 + ali1535_smba)
-+#define SMBHSTADD (3 + ali1535_smba)
-+#define SMBHSTDAT0 (4 + ali1535_smba)
-+#define SMBHSTDAT1 (5 + ali1535_smba)
-+#define SMBBLKDAT (6 + ali1535_smba)
-+
-+/* PCI Address Constants */
-+#define SMBCOM 0x004
-+#define SMBREV 0x008
-+#define SMBCFG 0x0D1
-+#define SMBBA 0x0E2
-+#define SMBHSTCFG 0x0F0
-+#define SMBCLK 0x0F2
-+
-+/* Other settings */
-+#define MAX_TIMEOUT 500 /* times 1/100 sec */
-+#define ALI1535_SMB_IOSIZE 32
-+
-+/*
-+*/
-+#define ALI1535_SMB_DEFAULTBASE 0x8040
-+
-+/* ALI1535 address lock bits */
-+#define ALI1535_LOCK 0x06 < dwe >
-+
-+/* ALI1535 command constants */
-+#define ALI1535_QUICK 0x00
-+#define ALI1535_BYTE 0x10
-+#define ALI1535_BYTE_DATA 0x20
-+#define ALI1535_WORD_DATA 0x30
-+#define ALI1535_BLOCK_DATA 0x40
-+#define ALI1535_I2C_READ 0x60
-+
-+#define ALI1535_DEV10B_EN 0x80 /* Enable 10-bit addressing in */
-+ /* I2C read */
-+#define ALI1535_T_OUT 0x08 /* Time-out Command (write) */
-+#define ALI1535_A_HIGH_BIT9 0x08 /* Bit 9 of 10-bit address in */
-+ /* Alert-Response-Address */
-+ /* (read) */
-+#define ALI1535_KILL 0x04 /* Kill Command (write) */
-+#define ALI1535_A_HIGH_BIT8 0x04 /* Bit 8 of 10-bit address in */
-+ /* Alert-Response-Address */
-+ /* (read) */
-+
-+#define ALI1535_D_HI_MASK 0x03 /* Mask for isolating bits 9-8 */
-+ /* of 10-bit address in I2C */
-+ /* Read Command */
-+
-+/* ALI1535 status register bits */
-+#define ALI1535_STS_IDLE 0x04
-+#define ALI1535_STS_BUSY 0x08 /* host busy */
-+#define ALI1535_STS_DONE 0x10 /* transaction complete */
-+#define ALI1535_STS_DEV 0x20 /* device error */
-+#define ALI1535_STS_BUSERR 0x40 /* bus error */
-+#define ALI1535_STS_FAIL 0x80 /* failed bus transaction */
-+#define ALI1535_STS_ERR 0xE0 /* all the bad error bits */
-+
-+#define ALI1535_BLOCK_CLR 0x04 /* reset block data index */
-+
-+/* ALI1535 device address register bits */
-+#define ALI1535_RD_ADDR 0x01 /* Read/Write Bit in Device */
-+ /* Address field */
-+ /* -> Write = 0 */
-+ /* -> Read = 1 */
-+#define ALI1535_SMBIO_EN 0x04 /* SMB I/O Space enable */
-+
-+static int ali1535_transaction(void);
-+
-+static unsigned short ali1535_smba = 0;
-+DECLARE_MUTEX(i2c_ali1535_sem);
-+
-+
-+/* Detect whether a ALI1535 can be found, and initialize it, where necessary.
-+ Note the differences between kernels with the old PCI BIOS interface and
-+ newer kernels with the real PCI interface. In compat.h some things are
-+ defined to make the transition easier. */
-+int ali1535_setup(struct pci_dev *ALI1535_dev)
-+{
-+ int error_return = 0;
-+ unsigned char temp;
-+
-+/* Check the following things:
-+ - SMB I/O address is initialized
-+ - Device is enabled
-+ - We can use the addresses
-+*/
-+
-+/* Determine the address of the SMBus area */
-+ pci_read_config_word(ALI1535_dev, SMBBA, &ali1535_smba);
-+ ali1535_smba &= (0xffff & ~(ALI1535_SMB_IOSIZE - 1));
-+ if (ali1535_smba == 0) {
-+ printk
-+ ("i2c-ali1535.o: ALI1535_smb region uninitialized - upgrade BIOS?\n");
-+ error_return = -ENODEV;
-+ }
-+
-+ if (error_return == -ENODEV)
-+ goto END;
-+
-+ if (check_region(ali1535_smba, ALI1535_SMB_IOSIZE)) {
-+ printk
-+ ("i2c-ali1535.o: ALI1535_smb region 0x%x already in use!\n",
-+ ali1535_smba);
-+ error_return = -ENODEV;
-+ }
-+
-+ if (error_return == -ENODEV)
-+ goto END;
-+
-+ /* check if whole device is enabled */
-+ pci_read_config_byte(ALI1535_dev, SMBCFG, &temp);
-+ if ((temp & ALI1535_SMBIO_EN) == 0) {
-+ printk
-+ ("i2c-ali1535.o: SMB device not enabled - upgrade BIOS?\n");
-+ error_return = -ENODEV;
-+ goto END;
-+ }
-+
-+/* Is SMB Host controller enabled? */
-+ pci_read_config_byte(ALI1535_dev, SMBHSTCFG, &temp);
-+ if ((temp & 1) == 0) {
-+ printk
-+ ("i2c-ali1535.o: SMBus controller not enabled - upgrade BIOS?\n");
-+ error_return = -ENODEV;
-+ goto END;
-+ }
-+
-+/* set SMB clock to 74KHz as recommended in data sheet */
-+ pci_write_config_byte(ALI1535_dev, SMBCLK, 0x20);
-+
-+ /* Everything is happy, let's grab the memory and set things up. */
-+ request_region(ali1535_smba, ALI1535_SMB_IOSIZE, "ali1535-smb");
-+
-+#ifdef DEBUG
-+/*
-+ The interrupt routing for SMB is set up in register 0x77 in the
-+ 1533 ISA Bridge device, NOT in the 7101 device.
-+ Don't bother with finding the 1533 device and reading the register.
-+ if ((....... & 0x0F) == 1)
-+ printk("i2c-ali1535.o: ALI1535 using Interrupt 9 for SMBus.\n");
-+*/
-+ pci_read_config_byte(ALI1535_dev, SMBREV, &temp);
-+ printk("i2c-ali1535.o: SMBREV = 0x%X\n", temp);
-+ printk("i2c-ali1535.o: ALI1535_smba = 0x%X\n", ali1535_smba);
-+#endif /* DEBUG */
-+
-+ END:
-+ return error_return;
-+}
-+
-+
-+/* Another internally used function */
-+int ali1535_transaction(void)
-+{
-+ int temp;
-+ int result = 0;
-+ int timeout = 0;
-+
-+#ifdef DEBUG
-+ printk
-+ ("i2c-ali1535.o: Transaction (pre): STS=%02x, TYP=%02x, CMD=%02x, ADD=%02x, DAT0=%02x, "
-+ "DAT1=%02x\n", inb_p(SMBHSTSTS), inb_p(SMBHSTTYP),
-+ inb_p(SMBHSTCMD), inb_p(SMBHSTADD), inb_p(SMBHSTDAT0),
-+ inb_p(SMBHSTDAT1));
-+#endif
-+
-+ /* get status */
-+ temp = inb_p(SMBHSTSTS);
-+
-+ /* Make sure the SMBus host is ready to start transmitting */
-+ /* Check the busy bit first */
-+ if (temp & ALI1535_STS_BUSY) {
-+/*
-+ If the host controller is still busy, it may have timed out in the previous transaction,
-+ resulting in a "SMBus Timeout" printk.
-+ I've tried the following to reset a stuck busy bit.
-+ 1. Reset the controller with an KILL command.
-+ (this doesn't seem to clear the controller if an external device is hung)
-+ 2. Reset the controller and the other SMBus devices with a T_OUT command.
-+ (this clears the host busy bit if an external device is hung,
-+ but it comes back upon a new access to a device)
-+ 3. Disable and reenable the controller in SMBHSTCFG
-+ Worst case, nothing seems to work except power reset.
-+*/
-+/* Abort - reset the host controller */
-+/*
-+#ifdef DEBUG
-+ printk("i2c-ali1535.o: Resetting host controller to clear busy condition\n",temp);
-+#endif
-+ outb_p(ALI1535_KILL, SMBHSTTYP);
-+ temp = inb_p(SMBHSTSTS);
-+ if (temp & ALI1535_STS_BUSY) {
-+*/
-+
-+/*
-+ Try resetting entire SMB bus, including other devices -
-+ This may not work either - it clears the BUSY bit but
-+ then the BUSY bit may come back on when you try and use the chip again.
-+ If that's the case you are stuck.
-+*/
-+ printk
-+ ("i2c-ali1535.o: Resetting entire SMB Bus to clear busy condition (%02x)\n",
-+ temp);
-+ outb_p(ALI1535_T_OUT, SMBHSTTYP);
-+ temp = inb_p(SMBHSTSTS);
-+ }
-+/*
-+ }
-+*/
-+
-+ /* now check the error bits and the busy bit */
-+ if (temp & (ALI1535_STS_ERR | ALI1535_STS_BUSY)) {
-+ /* do a clear-on-write */
-+ outb_p(0xFF, SMBHSTSTS);
-+ if ((temp = inb_p(SMBHSTSTS)) &
-+ (ALI1535_STS_ERR | ALI1535_STS_BUSY)) {
-+ /* this is probably going to be correctable only by a power reset
-+ as one of the bits now appears to be stuck */
-+ /* This may be a bus or device with electrical problems. */
-+ printk
-+ ("i2c-ali1535.o: SMBus reset failed! (0x%02x) - controller or device on bus is probably hung\n",
-+ temp);
-+ return -1;
-+ }
-+ } else {
-+ /* check and clear done bit */
-+ if (temp & ALI1535_STS_DONE) {
-+ outb_p(temp, SMBHSTSTS);
-+ }
-+ }
-+
-+ /* start the transaction by writing anything to the start register */
-+ outb_p(0xFF, SMBHSTPORT);
-+
-+ /* We will always wait for a fraction of a second! */
-+ timeout = 0;
-+ do {
-+ i2c_delay(1);
-+ temp = inb_p(SMBHSTSTS);
-+ } while (((temp & ALI1535_STS_BUSY) && !(temp & ALI1535_STS_IDLE))
-+ && (timeout++ < MAX_TIMEOUT));
-+
-+ /* If the SMBus is still busy, we give up */
-+ if (timeout >= MAX_TIMEOUT) {
-+ result = -1;
-+ printk("i2c-ali1535.o: SMBus Timeout!\n");
-+ }
-+
-+ if (temp & ALI1535_STS_FAIL) {
-+ result = -1;
-+#ifdef DEBUG
-+ printk("i2c-ali1535.o: Error: Failed bus transaction\n");
-+#endif
-+ }
-+
-+/*
-+ Unfortunately the ALI SMB controller maps "no response" and "bus collision"
-+ into a single bit. No reponse is the usual case so don't do a printk.
-+ This means that bus collisions go unreported.
-+*/
-+ if (temp & ALI1535_STS_BUSERR) {
-+ result = -1;
-+#ifdef DEBUG
-+ printk
-+ ("i2c-ali1535.o: Error: no response or bus collision ADD=%02x\n",
-+ inb_p(SMBHSTADD));
-+#endif
-+ }
-+
-+/* haven't ever seen this */
-+ if (temp & ALI1535_STS_DEV) {
-+ result = -1;
-+ printk("i2c-ali1535.o: Error: device error\n");
-+ }
-+
-+/*
-+ check to see if the "command complete" indication is set
-+ */
-+ if (!(temp & ALI1535_STS_DONE)) {
-+ result = -1;
-+ printk("i2c-ali1535.o: Error: command never completed\n");
-+ }
-+#ifdef DEBUG
-+ printk
-+ ("i2c-ali1535.o: Transaction (post): STS=%02x, TYP=%02x, CMD=%02x, ADD=%02x, "
-+ "DAT0=%02x, DAT1=%02x\n", inb_p(SMBHSTSTS), inb_p(SMBHSTTYP),
-+ inb_p(SMBHSTCMD), inb_p(SMBHSTADD), inb_p(SMBHSTDAT0),
-+ inb_p(SMBHSTDAT1));
-+#endif
-+
-+/*
-+ take consequent actions for error conditions
-+ */
-+ if (!(temp & ALI1535_STS_DONE)) {
-+ /* issue "kill" to reset host controller */
-+ outb_p(ALI1535_KILL,SMBHSTTYP);
-+ outb_p(0xFF,SMBHSTSTS);
-+ }
-+ else if (temp & ALI1535_STS_ERR) {
-+ /* issue "timeout" to reset all devices on bus */
-+ outb_p(ALI1535_T_OUT,SMBHSTTYP);
-+ outb_p(0xFF,SMBHSTSTS);
-+ }
-+
-+ return result;
-+}
-+
-+/* Return -1 on error. */
-+s32 ali1535_access(struct i2c_adapter * adap, u16 addr,
-+ unsigned short flags, char read_write, u8 command,
-+ int size, union i2c_smbus_data * data)
-+{
-+ int i, len;
-+ int temp;
-+ int timeout;
-+ s32 result = 0;
-+
-+ down(&i2c_ali1535_sem);
-+/* make sure SMBus is idle */
-+ temp = inb_p(SMBHSTSTS);
-+ for (timeout = 0;
-+ (timeout < MAX_TIMEOUT) && !(temp & ALI1535_STS_IDLE);
-+ timeout++) {
-+ i2c_delay(1);
-+ temp = inb_p(SMBHSTSTS);
-+ }
-+ if (timeout >= MAX_TIMEOUT) {
-+ printk("i2c-ali1535.o: Idle wait Timeout! STS=0x%02x\n",
-+ temp);
-+ }
-+
-+/* clear status register (clear-on-write) */
-+ outb_p(0xFF, SMBHSTSTS);
-+
-+ switch (size) {
-+ case I2C_SMBUS_QUICK:
-+ outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),
-+ SMBHSTADD);
-+ size = ALI1535_QUICK;
-+ outb_p(size, SMBHSTTYP); /* output command */
-+ break;
-+ case I2C_SMBUS_BYTE:
-+ outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),
-+ SMBHSTADD);
-+ size = ALI1535_BYTE;
-+ outb_p(size, SMBHSTTYP); /* output command */
-+ if (read_write == I2C_SMBUS_WRITE)
-+ outb_p(command, SMBHSTCMD);
-+ break;
-+ case I2C_SMBUS_BYTE_DATA:
-+ outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),
-+ SMBHSTADD);
-+ size = ALI1535_BYTE_DATA;
-+ outb_p(size, SMBHSTTYP); /* output command */
-+ outb_p(command, SMBHSTCMD);
-+ if (read_write == I2C_SMBUS_WRITE)
-+ outb_p(data->byte, SMBHSTDAT0);
-+ break;
-+ case I2C_SMBUS_WORD_DATA:
-+ outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),
-+ SMBHSTADD);
-+ size = ALI1535_WORD_DATA;
-+ outb_p(size, SMBHSTTYP); /* output command */
-+ outb_p(command, SMBHSTCMD);
-+ if (read_write == I2C_SMBUS_WRITE) {
-+ outb_p(data->word & 0xff, SMBHSTDAT0);
-+ outb_p((data->word & 0xff00) >> 8, SMBHSTDAT1);
-+ }
-+ break;
-+ case I2C_SMBUS_BLOCK_DATA:
-+ outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),
-+ SMBHSTADD);
-+ size = ALI1535_BLOCK_DATA;
-+ outb_p(size, SMBHSTTYP); /* output command */
-+ outb_p(command, SMBHSTCMD);
-+ if (read_write == I2C_SMBUS_WRITE) {
-+ len = data->block[0];
-+ if (len < 0) {
-+ len = 0;
-+ data->block[0] = len;
-+ }
-+ if (len > 32) {
-+ len = 32;
-+ data->block[0] = len;
-+ }
-+ outb_p(len, SMBHSTDAT0);
-+ outb_p(inb_p(SMBHSTTYP) | ALI1535_BLOCK_CLR, SMBHSTTYP); /* Reset SMBBLKDAT */
-+ for (i = 1; i <= len; i++)
-+ outb_p(data->block[i], SMBBLKDAT);
-+ }
-+ break;
-+ default:
-+ printk
-+ (KERN_WARNING "i2c-ali1535.o: Unsupported transaction %d\n", size);
-+ result = -1;
-+ goto EXIT;
-+ }
-+
-+ if (ali1535_transaction()) /* Error in transaction */
-+ {
-+ result = -1;
-+ goto EXIT;
-+ }
-+
-+ if ((read_write == I2C_SMBUS_WRITE) || (size == ALI1535_QUICK))
-+ {
-+ result = 0;
-+ goto EXIT;
-+ }
-+
-+ switch (size) {
-+ case ALI1535_BYTE: /* Result put in SMBHSTDAT0 */
-+ data->byte = inb_p(SMBHSTDAT0);
-+ break;
-+ case ALI1535_BYTE_DATA:
-+ data->byte = inb_p(SMBHSTDAT0);
-+ break;
-+ case ALI1535_WORD_DATA:
-+ data->word = inb_p(SMBHSTDAT0) + (inb_p(SMBHSTDAT1) << 8);
-+ break;
-+ case ALI1535_BLOCK_DATA:
-+ len = inb_p(SMBHSTDAT0);
-+ if (len > 32)
-+ len = 32;
-+ data->block[0] = len;
-+ outb_p(inb_p(SMBHSTTYP) | ALI1535_BLOCK_CLR, SMBHSTTYP); /* Reset SMBBLKDAT */
-+ for (i = 1; i <= data->block[0]; i++) {
-+ data->block[i] = inb_p(SMBBLKDAT);
-+#ifdef DEBUG
-+ printk
-+ ("i2c-ali1535.o: Blk: len=%d, i=%d, data=%02x\n",
-+ len, i, data->block[i]);
-+#endif /* DEBUG */
-+ }
-+ break;
-+ }
-+EXIT:
-+ up(&i2c_ali1535_sem);
-+ return result;
-+}
-+
-+
-+u32 ali1535_func(struct i2c_adapter *adapter)
-+{
-+ return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
-+ I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
-+ I2C_FUNC_SMBUS_BLOCK_DATA;
-+}
-+
-+static struct i2c_algorithm smbus_algorithm = {
-+ .name = "Non-i2c SMBus adapter",
-+ .id = I2C_ALGO_SMBUS,
-+ .smbus_xfer = ali1535_access,
-+ .functionality = ali1535_func,
-+};
-+
-+static struct i2c_adapter ali1535_adapter = {
-+ .owner = THIS_MODULE,
-+ .name = "unset",
-+ .id = I2C_ALGO_SMBUS | I2C_HW_SMBUS_ALI1535,
-+ .algo = &smbus_algorithm,
-+};
-+
-+
-+static struct pci_device_id ali1535_ids[] __devinitdata = {
-+ {
-+ .vendor = PCI_VENDOR_ID_AL,
-+ .device = PCI_DEVICE_ID_AL_M7101,
-+ .subvendor = PCI_ANY_ID,
-+ .subdevice = PCI_ANY_ID,
-+ },
-+ { 0, }
-+};
-+
-+static int __devinit ali1535_probe(struct pci_dev *dev, const struct pci_device_id *id)
-+{
-+ if (ali1535_setup(dev)) {
-+ printk
-+ ("i2c-ali1535.o: ALI1535 not detected, module not inserted.\n");
-+ return -ENODEV;
-+ }
-+
-+ sprintf(ali1535_adapter.name, "SMBus ALI1535 adapter at %04x",
-+ ali1535_smba);
-+ return i2c_add_adapter(&ali1535_adapter);
-+}
-+
-+static void __devexit ali1535_remove(struct pci_dev *dev)
-+{
-+ i2c_del_adapter(&ali1535_adapter);
-+ release_region(ali1535_smba, ALI1535_SMB_IOSIZE);
-+}
-+
-+
-+static struct pci_driver ali1535_driver = {
-+ .name = "ali1535 smbus",
-+ .id_table = ali1535_ids,
-+ .probe = ali1535_probe,
-+ .remove = __devexit_p(ali1535_remove),
-+};
-+
-+static int __init i2c_ali1535_init(void)
-+{
-+ printk("i2c-ali1535.o version %s (%s)\n", LM_VERSION, LM_DATE);
-+ return pci_module_init(&ali1535_driver);
-+}
-+
-+
-+static void __exit i2c_ali1535_exit(void)
-+{
-+ pci_unregister_driver(&ali1535_driver);
-+}
-+
-+#ifdef RLX
-+EXPORT_SYMBOL(ali1535_smba);
-+EXPORT_SYMBOL(ali1535_access);
-+EXPORT_SYMBOL(i2c_ali1535_sem);
-+#endif
-+
-+MODULE_AUTHOR
-+ ("Frodo Looijaard <frodol@dds.nl>, Philip Edelbrock <phil@netroedge.com>, "
-+ "Mark D. Studebaker <mdsxyz123@yahoo.com> and Dan Eaton <dan.eaton@rocketlogix.com>");
-+MODULE_DESCRIPTION("ALI1535 SMBus driver");
-+MODULE_LICENSE("GPL");
-+
-+module_init(i2c_ali1535_init);
-+module_exit(i2c_ali1535_exit);
-+
---- linux-old/drivers/i2c/i2c-ali15x3.c Thu Jan 1 00:00:00 1970
-+++ linux/drivers/i2c/i2c-ali15x3.c Mon Dec 13 20:18:40 2004
-@@ -0,0 +1,533 @@
-+/*
-+ ali15x3.c - Part of lm_sensors, Linux kernel modules for hardware
-+ monitoring
-+ Copyright (c) 1999 Frodo Looijaard <frodol@dds.nl> and
-+ Philip Edelbrock <phil@netroedge.com> and
-+ Mark D. Studebaker <mdsxyz123@yahoo.com>
-+
-+ 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., 675 Mass Ave, Cambridge, MA 02139, USA.
-+*/
-+
-+/*
-+ This is the driver for the SMB Host controller on
-+ Acer Labs Inc. (ALI) M1541 and M1543C South Bridges.
-+
-+ The M1543C is a South bridge for desktop systems.
-+ The M1533 is a South bridge for portable systems.
-+ They are part of the following ALI chipsets:
-+ "Aladdin Pro 2": Includes the M1621 Slot 1 North bridge
-+ with AGP and 100MHz CPU Front Side bus
-+ "Aladdin V": Includes the M1541 Socket 7 North bridge
-+ with AGP and 100MHz CPU Front Side bus
-+ "Aladdin IV": Includes the M1541 Socket 7 North bridge
-+ with host bus up to 83.3 MHz.
-+ For an overview of these chips see http://www.acerlabs.com
-+
-+ The M1533/M1543C devices appear as FOUR separate devices
-+ on the PCI bus. An output of lspci will show something similar
-+ to the following:
-+
-+ 00:02.0 USB Controller: Acer Laboratories Inc. M5237
-+ 00:03.0 Bridge: Acer Laboratories Inc. M7101
-+ 00:07.0 ISA bridge: Acer Laboratories Inc. M1533
-+ 00:0f.0 IDE interface: Acer Laboratories Inc. M5229
-+
-+ The SMB controller is part of the 7101 device, which is an
-+ ACPI-compliant Power Management Unit (PMU).
-+
-+ The whole 7101 device has to be enabled for the SMB to work.
-+ You can't just enable the SMB alone.
-+ The SMB and the ACPI have separate I/O spaces.
-+ We make sure that the SMB is enabled. We leave the ACPI alone.
-+
-+ This driver controls the SMB Host only.
-+ The SMB Slave controller on the M15X3 is not enabled.
-+
-+ This driver does not use interrupts.
-+*/
-+
-+/* Note: we assume there can only be one ALI15X3, with one SMBus interface */
-+
-+/* #define DEBUG 1 */
-+
-+#include <linux/module.h>
-+#include <linux/pci.h>
-+#include <linux/kernel.h>
-+#include <linux/stddef.h>
-+#include <linux/sched.h>
-+#include <linux/ioport.h>
-+#include <linux/i2c.h>
-+#include <linux/init.h>
-+#include <asm/io.h>
-+#define LM_DATE "20041007"
-+#define LM_VERSION "2.8.8"
-+#include <linux/sensors_compat.h>
-+
-+/* ALI15X3 SMBus address offsets */
-+#define SMBHSTSTS (0 + ali15x3_smba)
-+#define SMBHSTCNT (1 + ali15x3_smba)
-+#define SMBHSTSTART (2 + ali15x3_smba)
-+#define SMBHSTCMD (7 + ali15x3_smba)
-+#define SMBHSTADD (3 + ali15x3_smba)
-+#define SMBHSTDAT0 (4 + ali15x3_smba)
-+#define SMBHSTDAT1 (5 + ali15x3_smba)
-+#define SMBBLKDAT (6 + ali15x3_smba)
-+
-+/* PCI Address Constants */
-+#define SMBCOM 0x004
-+#define SMBBA 0x014
-+#define SMBATPC 0x05B /* used to unlock xxxBA registers */
-+#define SMBHSTCFG 0x0E0
-+#define SMBSLVC 0x0E1
-+#define SMBCLK 0x0E2
-+#define SMBREV 0x008
-+
-+/* Other settings */
-+#define MAX_TIMEOUT 200 /* times 1/100 sec */
-+#define ALI15X3_SMB_IOSIZE 32
-+
-+/* this is what the Award 1004 BIOS sets them to on a ASUS P5A MB.
-+ We don't use these here. If the bases aren't set to some value we
-+ tell user to upgrade BIOS and we fail.
-+*/
-+#define ALI15X3_SMB_DEFAULTBASE 0xE800
-+
-+/* ALI15X3 address lock bits */
-+#define ALI15X3_LOCK 0x06
-+
-+/* ALI15X3 command constants */
-+#define ALI15X3_ABORT 0x02
-+#define ALI15X3_T_OUT 0x04
-+#define ALI15X3_QUICK 0x00
-+#define ALI15X3_BYTE 0x10
-+#define ALI15X3_BYTE_DATA 0x20
-+#define ALI15X3_WORD_DATA 0x30
-+#define ALI15X3_BLOCK_DATA 0x40
-+#define ALI15X3_BLOCK_CLR 0x80
-+
-+/* ALI15X3 status register bits */
-+#define ALI15X3_STS_IDLE 0x04
-+#define ALI15X3_STS_BUSY 0x08
-+#define ALI15X3_STS_DONE 0x10
-+#define ALI15X3_STS_DEV 0x20 /* device error */
-+#define ALI15X3_STS_COLL 0x40 /* collision or no response */
-+#define ALI15X3_STS_TERM 0x80 /* terminated by abort */
-+#define ALI15X3_STS_ERR 0xE0 /* all the bad error bits */
-+
-+
-+/* If force_addr is set to anything different from 0, we forcibly enable
-+ the device at the given address. */
-+static int force_addr = 0;
-+MODULE_PARM(force_addr, "i");
-+MODULE_PARM_DESC(force_addr,
-+ "Initialize the base address of the i2c controller");
-+
-+static unsigned short ali15x3_smba = 0;
-+
-+static int ali15x3_setup(struct pci_dev *ALI15X3_dev)
-+{
-+ u16 a;
-+ unsigned char temp;
-+
-+ /* Check the following things:
-+ - SMB I/O address is initialized
-+ - Device is enabled
-+ - We can use the addresses
-+ */
-+
-+ /* Unlock the register.
-+ The data sheet says that the address registers are read-only
-+ if the lock bits are 1, but in fact the address registers
-+ are zero unless you clear the lock bits.
-+ */
-+ pci_read_config_byte(ALI15X3_dev, SMBATPC, &temp);
-+ if (temp & ALI15X3_LOCK) {
-+ temp &= ~ALI15X3_LOCK;
-+ pci_write_config_byte(ALI15X3_dev, SMBATPC, temp);
-+ }
-+
-+ /* Determine the address of the SMBus area */
-+ pci_read_config_word(ALI15X3_dev, SMBBA, &ali15x3_smba);
-+ ali15x3_smba &= (0xffff & ~(ALI15X3_SMB_IOSIZE - 1));
-+ if (ali15x3_smba == 0 && force_addr == 0) {
-+ dev_err(ALI15X3_dev, "ALI15X3_smb region uninitialized "
-+ "- upgrade BIOS or use force_addr=0xaddr\n");
-+ return -ENODEV;
-+ }
-+
-+ if(force_addr)
-+ ali15x3_smba = force_addr & ~(ALI15X3_SMB_IOSIZE - 1);
-+
-+ if (!request_region(ali15x3_smba, ALI15X3_SMB_IOSIZE, "ali15x3-smb")) {
-+ dev_err(ALI15X3_dev,
-+ "ALI15X3_smb region 0x%x already in use!\n",
-+ ali15x3_smba);
-+ return -ENODEV;
-+ }
-+
-+ if(force_addr) {
-+ dev_info(ALI15X3_dev, "forcing ISA address 0x%04X\n",
-+ ali15x3_smba);
-+ if (PCIBIOS_SUCCESSFUL !=
-+ pci_write_config_word(ALI15X3_dev, SMBBA, ali15x3_smba))
-+ return -ENODEV;
-+ if (PCIBIOS_SUCCESSFUL !=
-+ pci_read_config_word(ALI15X3_dev, SMBBA, &a))
-+ return -ENODEV;
-+ if ((a & ~(ALI15X3_SMB_IOSIZE - 1)) != ali15x3_smba) {
-+ /* make sure it works */
-+ dev_err(ALI15X3_dev,
-+ "force address failed - not supported?\n");
-+ return -ENODEV;
-+ }
-+ }
-+ /* check if whole device is enabled */
-+ pci_read_config_byte(ALI15X3_dev, SMBCOM, &temp);
-+ if ((temp & 1) == 0) {
-+ dev_info(ALI15X3_dev, "enabling SMBus device\n");
-+ pci_write_config_byte(ALI15X3_dev, SMBCOM, temp | 0x01);
-+ }
-+
-+ /* Is SMB Host controller enabled? */
-+ pci_read_config_byte(ALI15X3_dev, SMBHSTCFG, &temp);
-+ if ((temp & 1) == 0) {
-+ dev_info(ALI15X3_dev, "enabling SMBus controller\n");
-+ pci_write_config_byte(ALI15X3_dev, SMBHSTCFG, temp | 0x01);
-+ }
-+
-+ /* set SMB clock to 74KHz as recommended in data sheet */
-+ pci_write_config_byte(ALI15X3_dev, SMBCLK, 0x20);
-+
-+ /*
-+ The interrupt routing for SMB is set up in register 0x77 in the
-+ 1533 ISA Bridge device, NOT in the 7101 device.
-+ Don't bother with finding the 1533 device and reading the register.
-+ if ((....... & 0x0F) == 1)
-+ dev_dbg(ALI15X3_dev, "ALI15X3 using Interrupt 9 for SMBus.\n");
-+ */
-+ pci_read_config_byte(ALI15X3_dev, SMBREV, &temp);
-+ dev_dbg(ALI15X3_dev, "SMBREV = 0x%X\n", temp);
-+ dev_dbg(ALI15X3_dev, "iALI15X3_smba = 0x%X\n", ali15x3_smba);
-+
-+ return 0;
-+}
-+
-+/* Another internally used function */
-+static int ali15x3_transaction(struct i2c_adapter *adap)
-+{
-+ int temp;
-+ int result = 0;
-+ int timeout = 0;
-+
-+ dev_dbg(adap, "Transaction (pre): STS=%02x, CNT=%02x, CMD=%02x, "
-+ "ADD=%02x, DAT0=%02x, DAT1=%02x\n", inb_p(SMBHSTSTS),
-+ inb_p(SMBHSTCNT), inb_p(SMBHSTCMD), inb_p(SMBHSTADD),
-+ inb_p(SMBHSTDAT0), inb_p(SMBHSTDAT1));
-+
-+ /* get status */
-+ temp = inb_p(SMBHSTSTS);
-+
-+ /* Make sure the SMBus host is ready to start transmitting */
-+ /* Check the busy bit first */
-+ if (temp & ALI15X3_STS_BUSY) {
-+ /*
-+ If the host controller is still busy, it may have timed out in the
-+ previous transaction, resulting in a "SMBus Timeout" Dev.
-+ I've tried the following to reset a stuck busy bit.
-+ 1. Reset the controller with an ABORT command.
-+ (this doesn't seem to clear the controller if an external
-+ device is hung)
-+ 2. Reset the controller and the other SMBus devices with a
-+ T_OUT command. (this clears the host busy bit if an
-+ external device is hung, but it comes back upon a new access
-+ to a device)
-+ 3. Disable and reenable the controller in SMBHSTCFG
-+ Worst case, nothing seems to work except power reset.
-+ */
-+ /* Abort - reset the host controller */
-+ /*
-+ Try resetting entire SMB bus, including other devices -
-+ This may not work either - it clears the BUSY bit but
-+ then the BUSY bit may come back on when you try and use the chip again.
-+ If that's the case you are stuck.
-+ */
-+ dev_info(adap, "Resetting entire SMB Bus to "
-+ "clear busy condition (%02x)\n", temp);
-+ outb_p(ALI15X3_T_OUT, SMBHSTCNT);
-+ temp = inb_p(SMBHSTSTS);
-+ }
-+
-+ /* now check the error bits and the busy bit */
-+ if (temp & (ALI15X3_STS_ERR | ALI15X3_STS_BUSY)) {
-+ /* do a clear-on-write */
-+ outb_p(0xFF, SMBHSTSTS);
-+ if ((temp = inb_p(SMBHSTSTS)) &
-+ (ALI15X3_STS_ERR | ALI15X3_STS_BUSY)) {
-+ /* this is probably going to be correctable only by a power reset
-+ as one of the bits now appears to be stuck */
-+ /* This may be a bus or device with electrical problems. */
-+ dev_err(adap, "SMBus reset failed! (0x%02x) - "
-+ "controller or device on bus is probably hung\n",
-+ temp);
-+ return -1;
-+ }
-+ } else {
-+ /* check and clear done bit */
-+ if (temp & ALI15X3_STS_DONE) {
-+ outb_p(temp, SMBHSTSTS);
-+ }
-+ }
-+
-+ /* start the transaction by writing anything to the start register */
-+ outb_p(0xFF, SMBHSTSTART);
-+
-+ /* We will always wait for a fraction of a second! */
-+ timeout = 0;
-+ do {
-+ i2c_delay(1);
-+ temp = inb_p(SMBHSTSTS);
-+ } while ((!(temp & (ALI15X3_STS_ERR | ALI15X3_STS_DONE)))
-+ && (timeout++ < MAX_TIMEOUT));
-+
-+ /* If the SMBus is still busy, we give up */
-+ if (timeout >= MAX_TIMEOUT) {
-+ result = -1;
-+ dev_err(adap, "SMBus Timeout!\n");
-+ }
-+
-+ if (temp & ALI15X3_STS_TERM) {
-+ result = -1;
-+ dev_dbg(adap, "Error: Failed bus transaction\n");
-+ }
-+
-+ /*
-+ Unfortunately the ALI SMB controller maps "no response" and "bus
-+ collision" into a single bit. No reponse is the usual case so don't
-+ do a printk.
-+ This means that bus collisions go unreported.
-+ */
-+ if (temp & ALI15X3_STS_COLL) {
-+ result = -1;
-+ dev_dbg(adap,
-+ "Error: no response or bus collision ADD=%02x\n",
-+ inb_p(SMBHSTADD));
-+ }
-+
-+ /* haven't ever seen this */
-+ if (temp & ALI15X3_STS_DEV) {
-+ result = -1;
-+ dev_err(adap, "Error: device error\n");
-+ }
-+ dev_dbg(adap, "Transaction (post): STS=%02x, CNT=%02x, CMD=%02x, "
-+ "ADD=%02x, DAT0=%02x, DAT1=%02x\n", inb_p(SMBHSTSTS),
-+ inb_p(SMBHSTCNT), inb_p(SMBHSTCMD), inb_p(SMBHSTADD),
-+ inb_p(SMBHSTDAT0), inb_p(SMBHSTDAT1));
-+ return result;
-+}
-+
-+/* Return -1 on error. */
-+static s32 ali15x3_access(struct i2c_adapter * adap, u16 addr,
-+ unsigned short flags, char read_write, u8 command,
-+ int size, union i2c_smbus_data * data)
-+{
-+ int i, len;
-+ int temp;
-+ int timeout;
-+
-+ /* clear all the bits (clear-on-write) */
-+ outb_p(0xFF, SMBHSTSTS);
-+ /* make sure SMBus is idle */
-+ temp = inb_p(SMBHSTSTS);
-+ for (timeout = 0;
-+ (timeout < MAX_TIMEOUT) && !(temp & ALI15X3_STS_IDLE);
-+ timeout++) {
-+ i2c_delay(1);
-+ temp = inb_p(SMBHSTSTS);
-+ }
-+ if (timeout >= MAX_TIMEOUT) {
-+ dev_err(adap, "Idle wait Timeout! STS=0x%02x\n", temp);
-+ }
-+
-+ switch (size) {
-+ case I2C_SMBUS_QUICK:
-+ outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),
-+ SMBHSTADD);
-+ size = ALI15X3_QUICK;
-+ break;
-+ case I2C_SMBUS_BYTE:
-+ outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),
-+ SMBHSTADD);
-+ if (read_write == I2C_SMBUS_WRITE)
-+ outb_p(command, SMBHSTCMD);
-+ size = ALI15X3_BYTE;
-+ break;
-+ case I2C_SMBUS_BYTE_DATA:
-+ outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),
-+ SMBHSTADD);
-+ outb_p(command, SMBHSTCMD);
-+ if (read_write == I2C_SMBUS_WRITE)
-+ outb_p(data->byte, SMBHSTDAT0);
-+ size = ALI15X3_BYTE_DATA;
-+ break;
-+ case I2C_SMBUS_WORD_DATA:
-+ outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),
-+ SMBHSTADD);
-+ outb_p(command, SMBHSTCMD);
-+ if (read_write == I2C_SMBUS_WRITE) {
-+ outb_p(data->word & 0xff, SMBHSTDAT0);
-+ outb_p((data->word & 0xff00) >> 8, SMBHSTDAT1);
-+ }
-+ size = ALI15X3_WORD_DATA;
-+ break;
-+ case I2C_SMBUS_BLOCK_DATA:
-+ outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),
-+ SMBHSTADD);
-+ outb_p(command, SMBHSTCMD);
-+ if (read_write == I2C_SMBUS_WRITE) {
-+ len = data->block[0];
-+ if (len < 0) {
-+ len = 0;
-+ data->block[0] = len;
-+ }
-+ if (len > 32) {
-+ len = 32;
-+ data->block[0] = len;
-+ }
-+ outb_p(len, SMBHSTDAT0);
-+ /* Reset SMBBLKDAT */
-+ outb_p(inb_p(SMBHSTCNT) | ALI15X3_BLOCK_CLR, SMBHSTCNT);
-+ for (i = 1; i <= len; i++)
-+ outb_p(data->block[i], SMBBLKDAT);
-+ }
-+ size = ALI15X3_BLOCK_DATA;
-+ break;
-+ default:
-+ printk
-+ (KERN_WARNING "i2c-ali15x3.o: Unsupported transaction %d\n", size);
-+ return -1;
-+ }
-+
-+ outb_p(size, SMBHSTCNT); /* output command */
-+
-+ if (ali15x3_transaction(adap)) /* Error in transaction */
-+ return -1;
-+
-+ if ((read_write == I2C_SMBUS_WRITE) || (size == ALI15X3_QUICK))
-+ return 0;
-+
-+
-+ switch (size) {
-+ case ALI15X3_BYTE: /* Result put in SMBHSTDAT0 */
-+ data->byte = inb_p(SMBHSTDAT0);
-+ break;
-+ case ALI15X3_BYTE_DATA:
-+ data->byte = inb_p(SMBHSTDAT0);
-+ break;
-+ case ALI15X3_WORD_DATA:
-+ data->word = inb_p(SMBHSTDAT0) + (inb_p(SMBHSTDAT1) << 8);
-+ break;
-+ case ALI15X3_BLOCK_DATA:
-+ len = inb_p(SMBHSTDAT0);
-+ if (len > 32)
-+ len = 32;
-+ data->block[0] = len;
-+ /* Reset SMBBLKDAT */
-+ outb_p(inb_p(SMBHSTCNT) | ALI15X3_BLOCK_CLR, SMBHSTCNT);
-+ for (i = 1; i <= data->block[0]; i++) {
-+ data->block[i] = inb_p(SMBBLKDAT);
-+ dev_dbg(adap, "Blk: len=%d, i=%d, data=%02x\n",
-+ len, i, data->block[i]);
-+ }
-+ break;
-+ }
-+ return 0;
-+}
-+
-+static u32 ali15x3_func(struct i2c_adapter *adapter)
-+{
-+ return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
-+ I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
-+ I2C_FUNC_SMBUS_BLOCK_DATA;
-+}
-+
-+static struct i2c_algorithm smbus_algorithm = {
-+ .name = "Non-I2C SMBus adapter",
-+ .id = I2C_ALGO_SMBUS,
-+ .smbus_xfer = ali15x3_access,
-+ .functionality = ali15x3_func,
-+};
-+
-+static struct i2c_adapter ali15x3_adapter = {
-+ .owner = THIS_MODULE,
-+ .id = I2C_ALGO_SMBUS | I2C_HW_SMBUS_ALI15X3,
-+ .algo = &smbus_algorithm,
-+ .name = "unset",
-+};
-+
-+static struct pci_device_id ali15x3_ids[] __devinitdata = {
-+ {
-+ .vendor = PCI_VENDOR_ID_AL,
-+ .device = PCI_DEVICE_ID_AL_M7101,
-+ .subvendor = PCI_ANY_ID,
-+ .subdevice = PCI_ANY_ID,
-+ },
-+ { 0, }
-+};
-+
-+static int __devinit ali15x3_probe(struct pci_dev *dev, const struct pci_device_id *id)
-+{
-+ if (ali15x3_setup(dev)) {
-+ dev_err(dev,
-+ "ALI15X3 not detected, module not inserted.\n");
-+ return -ENODEV;
-+ }
-+
-+ snprintf(ali15x3_adapter.name, 32,
-+ "SMBus ALI15X3 adapter at %04x", ali15x3_smba);
-+ return i2c_add_adapter(&ali15x3_adapter);
-+}
-+
-+static void __devexit ali15x3_remove(struct pci_dev *dev)
-+{
-+ i2c_del_adapter(&ali15x3_adapter);
-+ release_region(ali15x3_smba, ALI15X3_SMB_IOSIZE);
-+}
-+
-+static struct pci_driver ali15x3_driver = {
-+ .name = "ali15x3 smbus",
-+ .id_table = ali15x3_ids,
-+ .probe = ali15x3_probe,
-+ .remove = __devexit_p(ali15x3_remove),
-+};
-+
-+static int __init i2c_ali15x3_init(void)
-+{
-+ printk("i2c-ali15x3.o version %s (%s)\n", LM_VERSION, LM_DATE);
-+ return pci_module_init(&ali15x3_driver);
-+}
-+
-+static void __exit i2c_ali15x3_exit(void)
-+{
-+ pci_unregister_driver(&ali15x3_driver);
-+}
-+
-+MODULE_AUTHOR ("Frodo Looijaard <frodol@dds.nl>, "
-+ "Philip Edelbrock <phil@netroedge.com>, "
-+ "and Mark D. Studebaker <mdsxyz123@yahoo.com>");
-+MODULE_DESCRIPTION("ALI15X3 SMBus driver");
-+MODULE_LICENSE("GPL");
-+
-+module_init(i2c_ali15x3_init);
-+module_exit(i2c_ali15x3_exit);
---- linux-old/drivers/i2c/i2c-amd756.c Thu Jan 1 00:00:00 1970
-+++ linux/drivers/i2c/i2c-amd756.c Mon Dec 13 20:18:41 2004
-@@ -0,0 +1,425 @@
-+/*
-+ amd756.c - Part of lm_sensors, Linux kernel modules for hardware
-+ monitoring
-+
-+ Copyright (c) 1999-2002 Merlin Hughes <merlin@merlin.org>
-+
-+ Shamelessly ripped from i2c-piix4.c:
-+
-+ Copyright (c) 1998, 1999 Frodo Looijaard <frodol@dds.nl> and
-+ Philip Edelbrock <phil@netroedge.com>
-+
-+ 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., 675 Mass Ave, Cambridge, MA 02139, USA.
-+*/
-+
-+/*
-+ 2002-04-08: Added nForce support. (Csaba Halasz)
-+ 2002-10-03: Fixed nForce PnP I/O port. (Michael Steil)
-+ 2002-12-28: Rewritten into something that resembles a Linux driver (hch)
-+ 2003-11-29: Added back AMD8111 removed by the previous rewrite.
-+ (Philip Pokorny)
-+ 2004-02-15: Don't register driver to avoid driver conflicts.
-+ (Daniel Rune Jensen)
-+*/
-+
-+/*
-+ Supports AMD756, AMD766, AMD768, AMD8111 and nVidia nForce
-+ Note: we assume there can only be one device, with one SMBus interface.
-+*/
-+
-+#include <linux/module.h>
-+#include <linux/pci.h>
-+#include <linux/kernel.h>
-+#include <linux/stddef.h>
-+#include <linux/sched.h>
-+#include <linux/ioport.h>
-+#include <linux/i2c.h>
-+#include <linux/init.h>
-+#include <asm/io.h>
-+#define LM_DATE "20041007"
-+#define LM_VERSION "2.8.8"
-+
-+#define DRV_NAME "i2c-amd756"
-+
-+/* AMD756 SMBus address offsets */
-+#define SMB_ADDR_OFFSET 0xE0
-+#define SMB_IOSIZE 16
-+#define SMB_GLOBAL_STATUS (0x0 + amd756_ioport)
-+#define SMB_GLOBAL_ENABLE (0x2 + amd756_ioport)
-+#define SMB_HOST_ADDRESS (0x4 + amd756_ioport)
-+#define SMB_HOST_DATA (0x6 + amd756_ioport)
-+#define SMB_HOST_COMMAND (0x8 + amd756_ioport)
-+#define SMB_HOST_BLOCK_DATA (0x9 + amd756_ioport)
-+#define SMB_HAS_DATA (0xA + amd756_ioport)
-+#define SMB_HAS_DEVICE_ADDRESS (0xC + amd756_ioport)
-+#define SMB_HAS_HOST_ADDRESS (0xE + amd756_ioport)
-+#define SMB_SNOOP_ADDRESS (0xF + amd756_ioport)
-+
-+/* PCI Address Constants */
-+
-+/* address of I/O space */
-+#define SMBBA 0x058 /* mh */
-+#define SMBBANFORCE 0x014
-+
-+/* general configuration */
-+#define SMBGCFG 0x041 /* mh */
-+
-+/* silicon revision code */
-+#define SMBREV 0x008
-+
-+/* Other settings */
-+#define MAX_TIMEOUT 500
-+
-+/* AMD756 constants */
-+#define AMD756_QUICK 0x00
-+#define AMD756_BYTE 0x01
-+#define AMD756_BYTE_DATA 0x02
-+#define AMD756_WORD_DATA 0x03
-+#define AMD756_PROCESS_CALL 0x04
-+#define AMD756_BLOCK_DATA 0x05
-+
-+
-+static unsigned short amd756_ioport = 0;
-+
-+/*
-+ SMBUS event = I/O 28-29 bit 11
-+ see E0 for the status bits and enabled in E2
-+
-+*/
-+
-+#define GS_ABRT_STS (1 << 0)
-+#define GS_COL_STS (1 << 1)
-+#define GS_PRERR_STS (1 << 2)
-+#define GS_HST_STS (1 << 3)
-+#define GS_HCYC_STS (1 << 4)
-+#define GS_TO_STS (1 << 5)
-+#define GS_SMB_STS (1 << 11)
-+
-+#define GS_CLEAR_STS (GS_ABRT_STS | GS_COL_STS | GS_PRERR_STS | \
-+ GS_HCYC_STS | GS_TO_STS )
-+
-+#define GE_CYC_TYPE_MASK (7)
-+#define GE_HOST_STC (1 << 3)
-+#define GE_ABORT (1 << 5)
-+
-+
-+static int amd756_transaction(void)
-+{
-+ int temp;
-+ int result = 0;
-+ int timeout = 0;
-+
-+ pr_debug(DRV_NAME
-+ ": Transaction (pre): GS=%04x, GE=%04x, ADD=%04x, DAT=%04x\n",
-+ inw_p(SMB_GLOBAL_STATUS), inw_p(SMB_GLOBAL_ENABLE),
-+ inw_p(SMB_HOST_ADDRESS), inb_p(SMB_HOST_DATA));
-+
-+ /* Make sure the SMBus host is ready to start transmitting */
-+ if ((temp = inw_p(SMB_GLOBAL_STATUS)) & (GS_HST_STS | GS_SMB_STS)) {
-+ pr_debug(DRV_NAME ": SMBus busy (%04x). Waiting... \n", temp);
-+ do {
-+ i2c_delay(1);
-+ temp = inw_p(SMB_GLOBAL_STATUS);
-+ } while ((temp & (GS_HST_STS | GS_SMB_STS)) &&
-+ (timeout++ < MAX_TIMEOUT));
-+ /* If the SMBus is still busy, we give up */
-+ if (timeout >= MAX_TIMEOUT) {
-+ pr_debug(DRV_NAME ": Busy wait timeout (%04x)\n", temp);
-+ goto abort;
-+ }
-+ timeout = 0;
-+ }
-+
-+ /* start the transaction by setting the start bit */
-+ outw_p(inw(SMB_GLOBAL_ENABLE) | GE_HOST_STC, SMB_GLOBAL_ENABLE);
-+
-+ /* We will always wait for a fraction of a second! */
-+ do {
-+ i2c_delay(1);
-+ temp = inw_p(SMB_GLOBAL_STATUS);
-+ } while ((temp & GS_HST_STS) && (timeout++ < MAX_TIMEOUT));
-+
-+ /* If the SMBus is still busy, we give up */
-+ if (timeout >= MAX_TIMEOUT) {
-+ pr_debug(DRV_NAME ": Completion timeout!\n");
-+ goto abort;
-+ }
-+
-+ if (temp & GS_PRERR_STS) {
-+ result = -1;
-+ pr_debug(DRV_NAME ": SMBus Protocol error (no response)!\n");
-+ }
-+
-+ if (temp & GS_COL_STS) {
-+ result = -1;
-+ printk(KERN_WARNING DRV_NAME ": SMBus collision!\n");
-+ }
-+
-+ if (temp & GS_TO_STS) {
-+ result = -1;
-+ pr_debug(DRV_NAME ": SMBus protocol timeout!\n");
-+ }
-+
-+ if (temp & GS_HCYC_STS)
-+ pr_debug(DRV_NAME ": SMBus protocol success!\n");
-+
-+ outw_p(GS_CLEAR_STS, SMB_GLOBAL_STATUS);
-+
-+#ifdef DEBUG
-+ if (((temp = inw_p(SMB_GLOBAL_STATUS)) & GS_CLEAR_STS) != 0x00) {
-+ pr_debug(DRV_NAME
-+ ": Failed reset at end of transaction (%04x)\n", temp);
-+ }
-+
-+ pr_debug(DRV_NAME
-+ ": Transaction (post): GS=%04x, GE=%04x, ADD=%04x, DAT=%04x\n",
-+ inw_p(SMB_GLOBAL_STATUS), inw_p(SMB_GLOBAL_ENABLE),
-+ inw_p(SMB_HOST_ADDRESS), inb_p(SMB_HOST_DATA));
-+#endif
-+
-+ return result;
-+
-+ abort:
-+ printk(KERN_WARNING DRV_NAME ": Sending abort.\n");
-+ outw_p(inw(SMB_GLOBAL_ENABLE) | GE_ABORT, SMB_GLOBAL_ENABLE);
-+ i2c_delay(100);
-+ outw_p(GS_CLEAR_STS, SMB_GLOBAL_STATUS);
-+ return -1;
-+}
-+
-+/* Return -1 on error. */
-+
-+static s32 amd756_access(struct i2c_adapter * adap, u16 addr,
-+ unsigned short flags, char read_write,
-+ u8 command, int size, union i2c_smbus_data * data)
-+{
-+ int i, len;
-+
-+ /** TODO: Should I supporte the 10-bit transfers? */
-+ switch (size) {
-+ /* TODO: proc call is supported, I'm just not sure what to do here... */
-+ case I2C_SMBUS_QUICK:
-+ outw_p(((addr & 0x7f) << 1) | (read_write & 0x01),
-+ SMB_HOST_ADDRESS);
-+ size = AMD756_QUICK;
-+ break;
-+ case I2C_SMBUS_BYTE:
-+ outw_p(((addr & 0x7f) << 1) | (read_write & 0x01),
-+ SMB_HOST_ADDRESS);
-+ if (read_write == I2C_SMBUS_WRITE)
-+ outb_p(command, SMB_HOST_DATA);
-+ size = AMD756_BYTE;
-+ break;
-+ case I2C_SMBUS_BYTE_DATA:
-+ outw_p(((addr & 0x7f) << 1) | (read_write & 0x01),
-+ SMB_HOST_ADDRESS);
-+ outb_p(command, SMB_HOST_COMMAND);
-+ if (read_write == I2C_SMBUS_WRITE)
-+ outw_p(data->byte, SMB_HOST_DATA);
-+ size = AMD756_BYTE_DATA;
-+ break;
-+ case I2C_SMBUS_WORD_DATA:
-+ outw_p(((addr & 0x7f) << 1) | (read_write & 0x01),
-+ SMB_HOST_ADDRESS);
-+ outb_p(command, SMB_HOST_COMMAND);
-+ if (read_write == I2C_SMBUS_WRITE)
-+ outw_p(data->word, SMB_HOST_DATA); /* TODO: endian???? */
-+ size = AMD756_WORD_DATA;
-+ break;
-+ case I2C_SMBUS_BLOCK_DATA:
-+ outw_p(((addr & 0x7f) << 1) | (read_write & 0x01),
-+ SMB_HOST_ADDRESS);
-+ outb_p(command, SMB_HOST_COMMAND);
-+ if (read_write == I2C_SMBUS_WRITE) {
-+ len = data->block[0];
-+ if (len < 0)
-+ len = 0;
-+ if (len > 32)
-+ len = 32;
-+ outw_p(len, SMB_HOST_DATA);
-+ /* i = inw_p(SMBHSTCNT); Reset SMBBLKDAT */
-+ for (i = 1; i <= len; i++)
-+ outb_p(data->block[i],
-+ SMB_HOST_BLOCK_DATA);
-+ }
-+ size = AMD756_BLOCK_DATA;
-+ break;
-+ default:
-+ printk
-+ (KERN_WARNING "i2c-amd756.o: Unsupported transaction %d\n", size);
-+ return -1;
-+ }
-+
-+ /* How about enabling interrupts... */
-+ outw_p(size & GE_CYC_TYPE_MASK, SMB_GLOBAL_ENABLE);
-+
-+ if (amd756_transaction()) /* Error in transaction */
-+ return -1;
-+
-+ if ((read_write == I2C_SMBUS_WRITE) || (size == AMD756_QUICK))
-+ return 0;
-+
-+
-+ switch (size) {
-+ case AMD756_BYTE:
-+ data->byte = inw_p(SMB_HOST_DATA);
-+ break;
-+ case AMD756_BYTE_DATA:
-+ data->byte = inw_p(SMB_HOST_DATA);
-+ break;
-+ case AMD756_WORD_DATA:
-+ data->word = inw_p(SMB_HOST_DATA); /* TODO: endian???? */
-+ break;
-+ case AMD756_BLOCK_DATA:
-+ data->block[0] = inw_p(SMB_HOST_DATA) & 0x3f;
-+ if(data->block[0] > 32)
-+ data->block[0] = 32;
-+ /* i = inw_p(SMBHSTCNT); Reset SMBBLKDAT */
-+ for (i = 1; i <= data->block[0]; i++)
-+ data->block[i] = inb_p(SMB_HOST_BLOCK_DATA);
-+ break;
-+ }
-+
-+ return 0;
-+}
-+
-+static u32 amd756_func(struct i2c_adapter *adapter)
-+{
-+ return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
-+ I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
-+ I2C_FUNC_SMBUS_BLOCK_DATA | I2C_FUNC_SMBUS_PROC_CALL;
-+}
-+
-+static struct i2c_algorithm smbus_algorithm = {
-+ .name = "Non-I2C SMBus adapter",
-+ .id = I2C_ALGO_SMBUS,
-+ .smbus_xfer = amd756_access,
-+ .functionality = amd756_func,
-+};
-+
-+static struct i2c_adapter amd756_adapter = {
-+ .owner = THIS_MODULE,
-+ .name = "unset",
-+ .id = I2C_ALGO_SMBUS | I2C_HW_SMBUS_AMD756,
-+ .algo = &smbus_algorithm,
-+};
-+
-+enum chiptype { AMD756, AMD766, AMD768, NFORCE, AMD8111 };
-+
-+static struct pci_device_id amd756_ids[] __devinitdata = {
-+ {PCI_VENDOR_ID_AMD, 0x740B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AMD756 },
-+ {PCI_VENDOR_ID_AMD, 0x7413, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AMD766 },
-+ {PCI_VENDOR_ID_AMD, 0x7443, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AMD768 },
-+ {PCI_VENDOR_ID_AMD, 0x746B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AMD8111 },
-+ {PCI_VENDOR_ID_NVIDIA, 0x01B4, PCI_ANY_ID, PCI_ANY_ID, 0, 0, NFORCE },
-+ { 0, }
-+};
-+
-+static int __devinit amd756_probe(struct pci_dev *pdev,
-+ const struct pci_device_id *id)
-+{
-+ int nforce = (id->driver_data == NFORCE);
-+ int error;
-+ u8 temp;
-+
-+ if (amd756_ioport) {
-+ printk(KERN_ERR DRV_NAME ": Only one device supported. "
-+ "(you have a strange motherboard, btw..)\n");
-+ return -ENODEV;
-+ }
-+
-+ if (nforce) {
-+ if (PCI_FUNC(pdev->devfn) != 1)
-+ return -ENODEV;
-+
-+ pci_read_config_word(pdev, SMBBANFORCE, &amd756_ioport);
-+ amd756_ioport &= 0xfffc;
-+ } else { /* amd */
-+ if (PCI_FUNC(pdev->devfn) != 3)
-+ return -ENODEV;
-+
-+ pci_read_config_byte(pdev, SMBGCFG, &temp);
-+ if ((temp & 128) == 0) {
-+ printk(KERN_ERR DRV_NAME
-+ ": Error: SMBus controller I/O not enabled!\n");
-+ return -ENODEV;
-+ }
-+
-+ /* Determine the address of the SMBus areas */
-+ /* Technically it is a dword but... */
-+ pci_read_config_word(pdev, SMBBA, &amd756_ioport);
-+ amd756_ioport &= 0xff00;
-+ amd756_ioport += SMB_ADDR_OFFSET;
-+ }
-+
-+ if (!request_region(amd756_ioport, SMB_IOSIZE, "amd756-smbus")) {
-+ printk(KERN_ERR DRV_NAME
-+ ": SMB region 0x%x already in use!\n", amd756_ioport);
-+ return -ENODEV;
-+ }
-+
-+#ifdef DEBUG
-+ pci_read_config_byte(pdev, SMBREV, &temp);
-+ printk(KERN_DEBUG DRV_NAME ": SMBREV = 0x%X\n", temp);
-+ printk(KERN_DEBUG DRV_NAME ": AMD756_smba = 0x%X\n", amd756_ioport);
-+#endif
-+
-+ sprintf(amd756_adapter.name,
-+ "SMBus AMD756 adapter at %04x", amd756_ioport);
-+
-+ error = i2c_add_adapter(&amd756_adapter);
-+ if (error) {
-+ printk(KERN_ERR DRV_NAME
-+ ": Adapter registration failed, module not inserted.\n");
-+ goto out_err;
-+ }
-+
-+ return 0;
-+
-+ out_err:
-+ release_region(amd756_ioport, SMB_IOSIZE);
-+ return error;
-+}
-+
-+
-+static int __init i2c_amd756_init(void)
-+{
-+ struct pci_dev *dev;
-+ const struct pci_device_id *id;
-+
-+ printk(KERN_INFO "i2c-amd756.o version %s (%s)\n", LM_VERSION, LM_DATE);
-+
-+ pci_for_each_dev(dev) {
-+ id = pci_match_device(amd756_ids, dev);
-+ if (id && amd756_probe(dev, id) >= 0)
-+ return 0;
-+ }
-+
-+ return -ENODEV;
-+}
-+
-+
-+static void __exit i2c_amd756_exit(void)
-+{
-+ i2c_del_adapter(&amd756_adapter);
-+ release_region(amd756_ioport, SMB_IOSIZE);
-+}
-+
-+MODULE_AUTHOR("Merlin Hughes <merlin@merlin.org>");
-+MODULE_DESCRIPTION("AMD756/766/768/8111 and nVidia nForce SMBus driver");
-+MODULE_LICENSE("GPL");
-+
-+module_init(i2c_amd756_init)
-+module_exit(i2c_amd756_exit)
---- linux-old/drivers/i2c/i2c-amd8111.c Thu Jan 1 00:00:00 1970
-+++ linux/drivers/i2c/i2c-amd8111.c Mon Dec 13 20:18:41 2004
-@@ -0,0 +1,421 @@
-+/*
-+ * SMBus 2.0 driver for AMD-8111 IO-Hub.
-+ *
-+ * Copyright (c) 2002 Vojtech Pavlik
-+ *
-+ * 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 version 2.
-+ */
-+
-+#include <linux/module.h>
-+#include <linux/pci.h>
-+#include <linux/kernel.h>
-+#include <linux/stddef.h>
-+#include <linux/sched.h>
-+#include <linux/ioport.h>
-+#include <linux/init.h>
-+#include <linux/i2c.h>
-+#include <linux/delay.h>
-+#include <linux/slab.h>
-+#include <asm/io.h>
-+#define LM_DATE "20041007"
-+#define LM_VERSION "2.8.8"
-+
-+#ifndef I2C_HW_SMBUS_AMD8111
-+#error Your i2c is too old - i2c-2.7.0 or greater required!
-+#endif
-+
-+/* kernel 2.4.9 needs this */
-+#ifndef min_t
-+#define min_t(type,x,y) min(type,x,y)
-+#endif
-+
-+MODULE_LICENSE("GPL");
-+MODULE_AUTHOR ("Vojtech Pavlik <vojtech@suse.cz>");
-+MODULE_DESCRIPTION("AMD8111 SMBus 2.0 driver");
-+
-+struct amd_smbus {
-+ struct pci_dev *dev;
-+ struct i2c_adapter adapter;
-+ int base;
-+ int size;
-+};
-+
-+/*
-+ * AMD PCI control registers definitions.
-+ */
-+
-+#define AMD_PCI_MISC 0x48
-+
-+#define AMD_PCI_MISC_SCI 0x04 /* deliver SCI */
-+#define AMD_PCI_MISC_INT 0x02 /* deliver PCI IRQ */
-+#define AMD_PCI_MISC_SPEEDUP 0x01 /* 16x clock speedup */
-+
-+/*
-+ * ACPI 2.0 chapter 13 PCI interface definitions.
-+ */
-+
-+#define AMD_EC_DATA 0x00 /* data register */
-+#define AMD_EC_SC 0x04 /* status of controller */
-+#define AMD_EC_CMD 0x04 /* command register */
-+#define AMD_EC_ICR 0x08 /* interrupt control register */
-+
-+#define AMD_EC_SC_SMI 0x04 /* smi event pending */
-+#define AMD_EC_SC_SCI 0x02 /* sci event pending */
-+#define AMD_EC_SC_BURST 0x01 /* burst mode enabled */
-+#define AMD_EC_SC_CMD 0x08 /* byte in data reg is command */
-+#define AMD_EC_SC_IBF 0x02 /* data ready for embedded controller */
-+#define AMD_EC_SC_OBF 0x01 /* data ready for host */
-+
-+#define AMD_EC_CMD_RD 0x80 /* read EC */
-+#define AMD_EC_CMD_WR 0x81 /* write EC */
-+#define AMD_EC_CMD_BE 0x82 /* enable burst mode */
-+#define AMD_EC_CMD_BD 0x83 /* disable burst mode */
-+#define AMD_EC_CMD_QR 0x84 /* query EC */
-+
-+/*
-+ * ACPI 2.0 chapter 13 access of registers of the EC
-+ */
-+
-+unsigned int amd_ec_wait_write(struct amd_smbus *smbus)
-+{
-+ int timeout = 500;
-+
-+ while (timeout-- && (inb(smbus->base + AMD_EC_SC) & AMD_EC_SC_IBF))
-+ udelay(1);
-+
-+ if (!timeout) {
-+ printk(KERN_WARNING "i2c-amd8111.c: Timeout while waiting for IBF to clear\n");
-+ return -1;
-+ }
-+
-+ return 0;
-+}
-+
-+unsigned int amd_ec_wait_read(struct amd_smbus *smbus)
-+{
-+ int timeout = 500;
-+
-+ while (timeout-- && (~inb(smbus->base + AMD_EC_SC) & AMD_EC_SC_OBF))
-+ udelay(1);
-+
-+ if (!timeout) {
-+ printk(KERN_WARNING "i2c-amd8111.c: Timeout while waiting for OBF to set\n");
-+ return -1;
-+ }
-+
-+ return 0;
-+}
-+
-+unsigned int amd_ec_read(struct amd_smbus *smbus, unsigned char address, unsigned char *data)
-+{
-+ if (amd_ec_wait_write(smbus))
-+ return -1;
-+ outb(AMD_EC_CMD_RD, smbus->base + AMD_EC_CMD);
-+
-+ if (amd_ec_wait_write(smbus))
-+ return -1;
-+ outb(address, smbus->base + AMD_EC_DATA);
-+
-+ if (amd_ec_wait_read(smbus))
-+ return -1;
-+ *data = inb(smbus->base + AMD_EC_DATA);
-+
-+ return 0;
-+}
-+
-+unsigned int amd_ec_write(struct amd_smbus *smbus, unsigned char address, unsigned char data)
-+{
-+ if (amd_ec_wait_write(smbus))
-+ return -1;
-+ outb(AMD_EC_CMD_WR, smbus->base + AMD_EC_CMD);
-+
-+ if (amd_ec_wait_write(smbus))
-+ return -1;
-+ outb(address, smbus->base + AMD_EC_DATA);
-+
-+ if (amd_ec_wait_write(smbus))
-+ return -1;
-+ outb(data, smbus->base + AMD_EC_DATA);
-+
-+ return 0;
-+}
-+
-+/*
-+ * ACPI 2.0 chapter 13 SMBus 2.0 EC register model
-+ */
-+
-+#define AMD_SMB_PRTCL 0x00 /* protocol, PEC */
-+#define AMD_SMB_STS 0x01 /* status */
-+#define AMD_SMB_ADDR 0x02 /* address */
-+#define AMD_SMB_CMD 0x03 /* command */
-+#define AMD_SMB_DATA 0x04 /* 32 data registers */
-+#define AMD_SMB_BCNT 0x24 /* number of data bytes */
-+#define AMD_SMB_ALRM_A 0x25 /* alarm address */
-+#define AMD_SMB_ALRM_D 0x26 /* 2 bytes alarm data */
-+
-+#define AMD_SMB_STS_DONE 0x80
-+#define AMD_SMB_STS_ALRM 0x40
-+#define AMD_SMB_STS_RES 0x20
-+#define AMD_SMB_STS_STATUS 0x1f
-+
-+#define AMD_SMB_STATUS_OK 0x00
-+#define AMD_SMB_STATUS_FAIL 0x07
-+#define AMD_SMB_STATUS_DNAK 0x10
-+#define AMD_SMB_STATUS_DERR 0x11
-+#define AMD_SMB_STATUS_CMD_DENY 0x12
-+#define AMD_SMB_STATUS_UNKNOWN 0x13
-+#define AMD_SMB_STATUS_ACC_DENY 0x17
-+#define AMD_SMB_STATUS_TIMEOUT 0x18
-+#define AMD_SMB_STATUS_NOTSUP 0x19
-+#define AMD_SMB_STATUS_BUSY 0x1A
-+#define AMD_SMB_STATUS_PEC 0x1F
-+
-+#define AMD_SMB_PRTCL_WRITE 0x00
-+#define AMD_SMB_PRTCL_READ 0x01
-+#define AMD_SMB_PRTCL_QUICK 0x02
-+#define AMD_SMB_PRTCL_BYTE 0x04
-+#define AMD_SMB_PRTCL_BYTE_DATA 0x06
-+#define AMD_SMB_PRTCL_WORD_DATA 0x08
-+#define AMD_SMB_PRTCL_BLOCK_DATA 0x0a
-+#define AMD_SMB_PRTCL_PROC_CALL 0x0c
-+#define AMD_SMB_PRTCL_BLOCK_PROC_CALL 0x0d
-+#define AMD_SMB_PRTCL_I2C_BLOCK_DATA 0x4a
-+#define AMD_SMB_PRTCL_PEC 0x80
-+
-+
-+s32 amd8111_access(struct i2c_adapter * adap, u16 addr, unsigned short flags,
-+ char read_write, u8 command, int size, union i2c_smbus_data * data)
-+{
-+ struct amd_smbus *smbus = adap->algo_data;
-+ unsigned char protocol, len, pec, temp[2];
-+ int i;
-+
-+ protocol = (read_write == I2C_SMBUS_READ) ? AMD_SMB_PRTCL_READ : AMD_SMB_PRTCL_WRITE;
-+ pec = (flags & I2C_CLIENT_PEC) ? AMD_SMB_PRTCL_PEC : 0;
-+
-+ switch (size) {
-+
-+ case I2C_SMBUS_QUICK:
-+ protocol |= AMD_SMB_PRTCL_QUICK;
-+ read_write = I2C_SMBUS_WRITE;
-+ break;
-+
-+ case I2C_SMBUS_BYTE:
-+ if (read_write == I2C_SMBUS_WRITE)
-+ amd_ec_write(smbus, AMD_SMB_CMD, command);
-+ protocol |= AMD_SMB_PRTCL_BYTE;
-+ break;
-+
-+ case I2C_SMBUS_BYTE_DATA:
-+ amd_ec_write(smbus, AMD_SMB_CMD, command);
-+ if (read_write == I2C_SMBUS_WRITE)
-+ amd_ec_write(smbus, AMD_SMB_DATA, data->byte);
-+ protocol |= AMD_SMB_PRTCL_BYTE_DATA;
-+ break;
-+
-+ case I2C_SMBUS_WORD_DATA:
-+ amd_ec_write(smbus, AMD_SMB_CMD, command);
-+ if (read_write == I2C_SMBUS_WRITE) {
-+ amd_ec_write(smbus, AMD_SMB_DATA, data->word);
-+ amd_ec_write(smbus, AMD_SMB_DATA + 1, data->word >> 8);
-+ }
-+ protocol |= AMD_SMB_PRTCL_WORD_DATA | pec;
-+ break;
-+
-+ case I2C_SMBUS_BLOCK_DATA:
-+ amd_ec_write(smbus, AMD_SMB_CMD, command);
-+ if (read_write == I2C_SMBUS_WRITE) {
-+ len = min_t(u8, data->block[0], 32);
-+ amd_ec_write(smbus, AMD_SMB_BCNT, len);
-+ for (i = 0; i < len; i++)
-+ amd_ec_write(smbus, AMD_SMB_DATA + i, data->block[i + 1]);
-+ }
-+ protocol |= AMD_SMB_PRTCL_BLOCK_DATA | pec;
-+ break;
-+
-+ case I2C_SMBUS_I2C_BLOCK_DATA:
-+ len = min_t(u8, data->block[0], 32);
-+ amd_ec_write(smbus, AMD_SMB_CMD, command);
-+ amd_ec_write(smbus, AMD_SMB_BCNT, len);
-+ if (read_write == I2C_SMBUS_WRITE)
-+ for (i = 0; i < len; i++)
-+ amd_ec_write(smbus, AMD_SMB_DATA + i, data->block[i + 1]);
-+ protocol |= AMD_SMB_PRTCL_I2C_BLOCK_DATA;
-+ break;
-+
-+ case I2C_SMBUS_PROC_CALL:
-+ amd_ec_write(smbus, AMD_SMB_CMD, command);
-+ amd_ec_write(smbus, AMD_SMB_DATA, data->word);
-+ amd_ec_write(smbus, AMD_SMB_DATA + 1, data->word >> 8);
-+ protocol = AMD_SMB_PRTCL_PROC_CALL | pec;
-+ read_write = I2C_SMBUS_READ;
-+ break;
-+
-+ case I2C_SMBUS_BLOCK_PROC_CALL:
-+ protocol |= pec;
-+ len = min_t(u8, data->block[0], 31);
-+ amd_ec_write(smbus, AMD_SMB_CMD, command);
-+ amd_ec_write(smbus, AMD_SMB_BCNT, len);
-+ for (i = 0; i < len; i++)
-+ amd_ec_write(smbus, AMD_SMB_DATA + i, data->block[i + 1]);
-+ protocol = AMD_SMB_PRTCL_BLOCK_PROC_CALL | pec;
-+ read_write = I2C_SMBUS_READ;
-+ break;
-+
-+ case I2C_SMBUS_WORD_DATA_PEC:
-+ case I2C_SMBUS_BLOCK_DATA_PEC:
-+ case I2C_SMBUS_PROC_CALL_PEC:
-+ case I2C_SMBUS_BLOCK_PROC_CALL_PEC:
-+ printk(KERN_WARNING "i2c-amd8111.c: Unexpected software PEC transaction %d\n.", size);
-+ return -1;
-+
-+ default:
-+ printk(KERN_WARNING "i2c-amd8111.c: Unsupported transaction %d\n", size);
-+ return -1;
-+ }
-+
-+ amd_ec_write(smbus, AMD_SMB_ADDR, addr << 1);
-+ amd_ec_write(smbus, AMD_SMB_PRTCL, protocol);
-+
-+ amd_ec_read(smbus, AMD_SMB_STS, temp + 0);
-+
-+ if (~temp[0] & AMD_SMB_STS_DONE) {
-+ udelay(500);
-+ amd_ec_read(smbus, AMD_SMB_STS, temp + 0);
-+ }
-+
-+ if (~temp[0] & AMD_SMB_STS_DONE) {
-+ i2c_delay(HZ/100);
-+ amd_ec_read(smbus, AMD_SMB_STS, temp + 0);
-+ }
-+
-+ if ((~temp[0] & AMD_SMB_STS_DONE) || (temp[0] & AMD_SMB_STS_STATUS))
-+ return -1;
-+
-+ if (read_write == I2C_SMBUS_WRITE)
-+ return 0;
-+
-+ switch (size) {
-+
-+ case I2C_SMBUS_BYTE:
-+ case I2C_SMBUS_BYTE_DATA:
-+ amd_ec_read(smbus, AMD_SMB_DATA, &data->byte);
-+ break;
-+
-+ case I2C_SMBUS_WORD_DATA:
-+ case I2C_SMBUS_PROC_CALL:
-+ amd_ec_read(smbus, AMD_SMB_DATA, temp + 0);
-+ amd_ec_read(smbus, AMD_SMB_DATA + 1, temp + 1);
-+ data->word = (temp[1] << 8) | temp[0];
-+ break;
-+
-+ case I2C_SMBUS_BLOCK_DATA:
-+ case I2C_SMBUS_BLOCK_PROC_CALL:
-+ amd_ec_read(smbus, AMD_SMB_BCNT, &len);
-+ len = min_t(u8, len, 32);
-+ case I2C_SMBUS_I2C_BLOCK_DATA:
-+ for (i = 0; i < len; i++)
-+ amd_ec_read(smbus, AMD_SMB_DATA + i, data->block + i + 1);
-+ data->block[0] = len;
-+ break;
-+ }
-+
-+ return 0;
-+}
-+
-+
-+u32 amd8111_func(struct i2c_adapter *adapter)
-+{
-+ return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE | I2C_FUNC_SMBUS_BYTE_DATA |
-+ I2C_FUNC_SMBUS_WORD_DATA | I2C_FUNC_SMBUS_BLOCK_DATA |
-+ I2C_FUNC_SMBUS_PROC_CALL | I2C_FUNC_SMBUS_BLOCK_PROC_CALL |
-+ I2C_FUNC_SMBUS_I2C_BLOCK | I2C_FUNC_SMBUS_HWPEC_CALC;
-+}
-+
-+static struct i2c_algorithm smbus_algorithm = {
-+ .name = "Non-I2C SMBus 2.0 adapter",
-+ .id = I2C_ALGO_SMBUS,
-+ .smbus_xfer = amd8111_access,
-+ .functionality = amd8111_func,
-+};
-+
-+
-+static struct pci_device_id amd8111_ids[] __devinitdata = {
-+ { 0x1022, 0x746a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
-+ { 0, }
-+};
-+
-+static int __devinit amd8111_probe(struct pci_dev *dev, const struct pci_device_id *id)
-+{
-+ struct amd_smbus *smbus;
-+ int error;
-+
-+ if (~pci_resource_flags(dev, 0) & IORESOURCE_IO)
-+ return -1;
-+
-+ if (!(smbus = (void*)kmalloc(sizeof(struct amd_smbus), GFP_KERNEL)))
-+ return -1;
-+ memset(smbus, 0, sizeof(struct amd_smbus));
-+
-+ pci_set_drvdata(dev, smbus);
-+ smbus->dev = dev;
-+ smbus->base = pci_resource_start(dev, 0);
-+ smbus->size = pci_resource_len(dev, 0);
-+
-+ if (!request_region(smbus->base, smbus->size, "amd8111 SMBus 2.0")) {
-+ kfree(smbus);
-+ return -1;
-+ }
-+
-+ smbus->adapter.owner = THIS_MODULE;
-+ sprintf(smbus->adapter.name, "SMBus2 AMD8111 adapter at %04x", smbus->base);
-+ smbus->adapter.id = I2C_ALGO_SMBUS | I2C_HW_SMBUS_AMD8111;
-+ smbus->adapter.algo = &smbus_algorithm;
-+ smbus->adapter.algo_data = smbus;
-+
-+ error = i2c_add_adapter(&smbus->adapter);
-+ if (error) {
-+ printk(KERN_WARNING "i2c-amd8111.c: Failed to register adapter.\n");
-+ release_region(smbus->base, smbus->size);
-+ kfree(smbus);
-+ return -1;
-+ }
-+
-+ pci_write_config_dword(smbus->dev, AMD_PCI_MISC, 0);
-+
-+ printk(KERN_INFO "i2c-amd8111.c: AMD8111 SMBus 2.0 adapter at %#x\n", smbus->base);
-+ return 0;
-+}
-+
-+
-+static void __devexit amd8111_remove(struct pci_dev *dev)
-+{
-+ struct amd_smbus *smbus = (void*) pci_get_drvdata(dev);
-+ i2c_del_adapter(&smbus->adapter);
-+ release_region(smbus->base, smbus->size);
-+ kfree(smbus);
-+}
-+
-+static struct pci_driver amd8111_driver = {
-+ .name = "amd8111 smbus 2.0",
-+ .id_table = amd8111_ids,
-+ .probe = amd8111_probe,
-+ .remove = __devexit_p(amd8111_remove),
-+};
-+
-+static int __init i2c_amd8111_init(void)
-+{
-+ printk(KERN_INFO "i2c-amd8111.o version %s (%s)\n", LM_VERSION, LM_DATE);
-+ return pci_module_init(&amd8111_driver);
-+}
-+
-+
-+static void __exit i2c_amd8111_exit(void)
-+{
-+ pci_unregister_driver(&amd8111_driver);
-+}
-+
-+module_init(i2c_amd8111_init);
-+module_exit(i2c_amd8111_exit);
---- linux-old/drivers/i2c/i2c-hydra.c Thu Jan 1 00:00:00 1970
-+++ linux/drivers/i2c/i2c-hydra.c Mon Dec 13 20:18:41 2004
-@@ -0,0 +1,175 @@
-+/*
-+ i2c-hydra.c - Part of lm_sensors, Linux kernel modules
-+ for hardware monitoring
-+
-+ i2c Support for the Apple `Hydra' Mac I/O
-+
-+ Copyright (c) 1999 Geert Uytterhoeven <geert@linux-m68k.org>
-+
-+ Based on i2c Support for Via Technologies 82C586B South Bridge
-+ Copyright (c) 1998, 1999 Kyösti Mälkki <kmalkki@cc.hut.fi>
-+
-+ 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., 675 Mass Ave, Cambridge, MA 02139, USA.
-+*/
-+
-+#include <linux/kernel.h>
-+#include <linux/module.h>
-+#include <linux/pci.h>
-+#include <linux/types.h>
-+#include <linux/i2c.h>
-+#include <linux/i2c-algo-bit.h>
-+#include <linux/init.h>
-+#include <asm/io.h>
-+#include <asm/system.h>
-+#include <asm/param.h> /* for HZ */
-+
-+MODULE_LICENSE("GPL");
-+
-+
-+#define HYDRA_CACHE_PD 0x00000030
-+
-+#define HYDRA_CPD_PD0 0x00000001 /* CachePD lines */
-+#define HYDRA_CPD_PD1 0x00000002
-+#define HYDRA_CPD_PD2 0x00000004
-+#define HYDRA_CPD_PD3 0x00000008
-+
-+#define HYDRA_SCLK HYDRA_CPD_PD0
-+#define HYDRA_SDAT HYDRA_CPD_PD1
-+#define HYDRA_SCLK_OE 0x00000010
-+#define HYDRA_SDAT_OE 0x00000020
-+
-+static unsigned long hydra_base;
-+
-+static inline void pdregw(u32 val)
-+{
-+ writel(val, hydra_base + HYDRA_CACHE_PD);
-+}
-+
-+static inline u32 pdregr(void)
-+{
-+ u32 val = readl(hydra_base + HYDRA_CACHE_PD);
-+ return val;
-+}
-+
-+static void bit_hydra_setscl(void *data, int state)
-+{
-+ u32 val = pdregr();
-+ if (state)
-+ val &= ~HYDRA_SCLK_OE;
-+ else {
-+ val &= ~HYDRA_SCLK;
-+ val |= HYDRA_SCLK_OE;
-+ }
-+ pdregw(val);
-+ pdregr(); /* flush posted write */
-+}
-+
-+static void bit_hydra_setsda(void *data, int state)
-+{
-+ u32 val = pdregr();
-+ if (state)
-+ val &= ~HYDRA_SDAT_OE;
-+ else {
-+ val &= ~HYDRA_SDAT;
-+ val |= HYDRA_SDAT_OE;
-+ }
-+ pdregw(val);
-+ pdregr(); /* flush posted write */
-+}
-+
-+static int bit_hydra_getscl(void *data)
-+{
-+ return (pdregr() & HYDRA_SCLK) != 0;
-+}
-+
-+static int bit_hydra_getsda(void *data)
-+{
-+ return (pdregr() & HYDRA_SDAT) != 0;
-+}
-+
-+/* ------------------------------------------------------------------------ */
-+
-+static struct i2c_algo_bit_data bit_hydra_data = {
-+ .setsda = bit_hydra_setsda,
-+ .setscl = bit_hydra_setscl,
-+ .getsda = bit_hydra_getsda,
-+ .getscl = bit_hydra_getscl,
-+ .udelay = 5,
-+ .mdelay = 5,
-+ .timeout = HZ
-+};
-+
-+static struct i2c_adapter bit_hydra_ops = {
-+ .owner = THIS_MODULE,
-+ .name = "Hydra i2c",
-+ .id = I2C_HW_B_HYDRA,
-+ .algo_data = &bit_hydra_data,
-+};
-+
-+static struct pci_device_id hydra_ids[] __devinitdata = {
-+ {
-+ .vendor = PCI_VENDOR_ID_APPLE,
-+ .device = PCI_DEVICE_ID_APPLE_HYDRA,
-+ .subvendor = PCI_ANY_ID,
-+ .subdevice = PCI_ANY_ID,
-+ },
-+ { 0, }
-+};
-+
-+static int __devinit hydra_probe(struct pci_dev *dev, const struct pci_device_id *id)
-+{
-+ unsigned int base_addr;
-+
-+ base_addr = dev->resource[0].start;
-+ hydra_base = (unsigned long) ioremap(base_addr, 0x100);
-+
-+ pdregw(0); /* clear SCLK_OE and SDAT_OE */
-+ return i2c_bit_add_bus(&bit_hydra_ops);
-+}
-+
-+static void __devexit hydra_remove(struct pci_dev *dev)
-+{
-+ pdregw(0); /* clear SCLK_OE and SDAT_OE */
-+ i2c_bit_del_bus(&bit_hydra_ops);
-+ iounmap((void *) hydra_base);
-+}
-+
-+
-+static struct pci_driver hydra_driver = {
-+ .name = "hydra smbus",
-+ .id_table = hydra_ids,
-+ .probe = hydra_probe,
-+ .remove = __devexit_p(hydra_remove),
-+};
-+
-+static int __init i2c_hydra_init(void)
-+{
-+ return pci_module_init(&hydra_driver);
-+}
-+
-+
-+static void __exit i2c_hydra_exit(void)
-+{
-+ pci_unregister_driver(&hydra_driver);
-+}
-+
-+
-+
-+MODULE_AUTHOR("Geert Uytterhoeven <geert@linux-m68k.org>");
-+MODULE_DESCRIPTION("i2c for Apple Hydra Mac I/O");
-+
-+module_init(i2c_hydra_init);
-+module_exit(i2c_hydra_exit);
-+
---- linux-old/drivers/i2c/i2c-i801.c Thu Jan 1 00:00:00 1970
-+++ linux/drivers/i2c/i2c-i801.c Mon Dec 13 20:18:41 2004
-@@ -0,0 +1,656 @@
-+/*
-+ i801.c - Part of lm_sensors, Linux kernel modules for hardware
-+ monitoring
-+ Copyright (c) 1998 - 2002 Frodo Looijaard <frodol@dds.nl>,
-+ Philip Edelbrock <phil@netroedge.com>, and Mark D. Studebaker
-+ <mdsxyz123@yahoo.com>
-+
-+ 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., 675 Mass Ave, Cambridge, MA 02139, USA.
-+*/
-+
-+/*
-+ SUPPORTED DEVICES PCI ID
-+ 82801AA 2413
-+ 82801AB 2423
-+ 82801BA 2443
-+ 82801CA/CAM 2483
-+ 82801DB 24C3 (HW PEC supported, 32 byte buffer not supported)
-+ 82801EB 24D3 (HW PEC supported, 32 byte buffer not supported)
-+ 6300ESB 25A4 ("")
-+ ICH6 266A
-+ This driver supports several versions of Intel's I/O Controller Hubs (ICH).
-+ For SMBus support, they are similar to the PIIX4 and are part
-+ of Intel's '810' and other chipsets.
-+ See the doc/busses/i2c-i801 file for details.
-+ I2C Block Read and Process Call are not supported.
-+*/
-+
-+/* Note: we assume there can only be one I801, with one SMBus interface */
-+
-+/* #define DEBUG 1 */
-+
-+#include <linux/module.h>
-+#include <linux/pci.h>
-+#include <linux/kernel.h>
-+#include <linux/stddef.h>
-+#include <linux/sched.h>
-+#include <linux/ioport.h>
-+#include <linux/init.h>
-+#include <linux/i2c.h>
-+#include <asm/io.h>
-+#define LM_DATE "20041007"
-+#define LM_VERSION "2.8.8"
-+#include <linux/sensors_compat.h>
-+
-+/* 82801DB is undefined before kernel 2.4.19 */
-+#ifndef PCI_DEVICE_ID_INTEL_82801DB_3
-+#define PCI_DEVICE_ID_INTEL_82801DB_3 0x24c3
-+#endif
-+
-+#ifdef I2C_FUNC_SMBUS_BLOCK_DATA_PEC
-+#define HAVE_PEC
-+#endif
-+
-+/* I801 SMBus address offsets */
-+#define SMBHSTSTS (0 + i801_smba)
-+#define SMBHSTCNT (2 + i801_smba)
-+#define SMBHSTCMD (3 + i801_smba)
-+#define SMBHSTADD (4 + i801_smba)
-+#define SMBHSTDAT0 (5 + i801_smba)
-+#define SMBHSTDAT1 (6 + i801_smba)
-+#define SMBBLKDAT (7 + i801_smba)
-+#define SMBPEC (8 + i801_smba) /* ICH4 only */
-+#define SMBAUXSTS (12 + i801_smba) /* ICH4 only */
-+#define SMBAUXCTL (13 + i801_smba) /* ICH4 only */
-+
-+/* PCI Address Constants */
-+#define SMBBA 0x020
-+#define SMBHSTCFG 0x040
-+#define SMBREV 0x008
-+
-+/* Host configuration bits for SMBHSTCFG */
-+#define SMBHSTCFG_HST_EN 1
-+#define SMBHSTCFG_SMB_SMI_EN 2
-+#define SMBHSTCFG_I2C_EN 4
-+
-+/* Other settings */
-+#define MAX_TIMEOUT 100
-+#define ENABLE_INT9 0 /* set to 0x01 to enable - untested */
-+
-+/* I801 command constants */
-+#define I801_QUICK 0x00
-+#define I801_BYTE 0x04
-+#define I801_BYTE_DATA 0x08
-+#define I801_WORD_DATA 0x0C
-+#define I801_PROC_CALL 0x10 /* later chips only, unimplemented */
-+#define I801_BLOCK_DATA 0x14
-+#define I801_I2C_BLOCK_DATA 0x18 /* unimplemented */
-+#define I801_BLOCK_LAST 0x34
-+#define I801_I2C_BLOCK_LAST 0x38 /* unimplemented */
-+#define I801_START 0x40
-+#define I801_PEC_EN 0x80 /* ICH4 only */
-+
-+/* insmod parameters */
-+
-+/* If force_addr is set to anything different from 0, we forcibly enable
-+ the I801 at the given address. VERY DANGEROUS! */
-+static int force_addr = 0;
-+MODULE_PARM(force_addr, "i");
-+MODULE_PARM_DESC(force_addr,
-+ "Forcibly enable the I801 at the given address. "
-+ "EXTREMELY DANGEROUS!");
-+
-+static int i801_transaction(void);
-+static int i801_block_transaction(union i2c_smbus_data *data,
-+ char read_write, int command);
-+
-+static unsigned short i801_smba;
-+static struct pci_dev *I801_dev;
-+static int isich4;
-+
-+static int i801_setup(struct pci_dev *dev)
-+{
-+ int error_return = 0;
-+ unsigned char temp;
-+
-+ /* Note: we keep on searching until we have found 'function 3' */
-+ if(PCI_FUNC(dev->devfn) != 3)
-+ return -ENODEV;
-+
-+ I801_dev = dev;
-+ if (dev->device == PCI_DEVICE_ID_INTEL_82801DB_3 ||
-+ dev->device == 0x24d3 ||
-+ dev->device == 0x25a4)
-+ isich4 = 1;
-+ else
-+ isich4 = 0;
-+
-+ /* Determine the address of the SMBus areas */
-+ if (force_addr) {
-+ i801_smba = force_addr & 0xfff0;
-+ } else {
-+ pci_read_config_word(I801_dev, SMBBA, &i801_smba);
-+ i801_smba &= 0xfff0;
-+ if(i801_smba == 0) {
-+ dev_err(dev, "SMB base address uninitialized"
-+ "- upgrade BIOS or use force_addr=0xaddr\n");
-+ return -ENODEV;
-+ }
-+ }
-+
-+ if (!request_region(i801_smba, (isich4 ? 16 : 8), "i801-smbus")) {
-+ dev_err(dev, "I801_smb region 0x%x already in use!\n",
-+ i801_smba);
-+ error_return = -EBUSY;
-+ goto END;
-+ }
-+
-+ pci_read_config_byte(I801_dev, SMBHSTCFG, &temp);
-+ temp &= ~SMBHSTCFG_I2C_EN; /* SMBus timing */
-+ pci_write_config_byte(I801_dev, SMBHSTCFG, temp);
-+
-+ /* If force_addr is set, we program the new address here. Just to make
-+ sure, we disable the device first. */
-+ if (force_addr) {
-+ pci_write_config_byte(I801_dev, SMBHSTCFG, temp & 0xfe);
-+ pci_write_config_word(I801_dev, SMBBA, i801_smba);
-+ pci_write_config_byte(I801_dev, SMBHSTCFG, temp | 0x01);
-+ dev_warn(dev, "WARNING: I801 SMBus interface set to "
-+ "new address %04x!\n", i801_smba);
-+ } else if ((temp & 1) == 0) {
-+ pci_write_config_byte(I801_dev, SMBHSTCFG, temp | 1);
-+ dev_warn(dev, "enabling SMBus device\n");
-+ }
-+
-+ if (temp & 0x02)
-+ dev_dbg(dev, "I801 using Interrupt SMI# for SMBus.\n");
-+ else
-+ dev_dbg(dev, "I801 using PCI Interrupt for SMBus.\n");
-+
-+ pci_read_config_byte(I801_dev, SMBREV, &temp);
-+ dev_dbg(dev, "SMBREV = 0x%X\n", temp);
-+ dev_dbg(dev, "I801_smba = 0x%X\n", i801_smba);
-+
-+END:
-+ return error_return;
-+}
-+
-+
-+static int i801_transaction(void)
-+{
-+ int temp;
-+ int result = 0;
-+ int timeout = 0;
-+
-+ dev_dbg(I801_dev, "Transaction (pre): CNT=%02x, CMD=%02x,"
-+ "ADD=%02x, DAT0=%02x, DAT1=%02x\n", inb_p(SMBHSTCNT),
-+ inb_p(SMBHSTCMD), inb_p(SMBHSTADD), inb_p(SMBHSTDAT0),
-+ inb_p(SMBHSTDAT1));
-+
-+ /* Make sure the SMBus host is ready to start transmitting */
-+ /* 0x1f = Failed, Bus_Err, Dev_Err, Intr, Host_Busy */
-+ if ((temp = (0x1f & inb_p(SMBHSTSTS))) != 0x00) {
-+ dev_dbg(I801_dev, "SMBus busy (%02x). Resetting... \n",
-+ temp);
-+ outb_p(temp, SMBHSTSTS);
-+ if ((temp = (0x1f & inb_p(SMBHSTSTS))) != 0x00) {
-+ dev_dbg(I801_dev, "Failed! (%02x)\n", temp);
-+ return -1;
-+ } else {
-+ dev_dbg(I801_dev, "Successfull!\n");
-+ }
-+ }
-+
-+ outb_p(inb(SMBHSTCNT) | I801_START, SMBHSTCNT);
-+
-+ /* We will always wait for a fraction of a second! */
-+ do {
-+ i2c_delay(1);
-+ temp = inb_p(SMBHSTSTS);
-+ } while ((temp & 0x01) && (timeout++ < MAX_TIMEOUT));
-+
-+ /* If the SMBus is still busy, we give up */
-+ if (timeout >= MAX_TIMEOUT) {
-+ dev_dbg(I801_dev, "SMBus Timeout!\n");
-+ result = -1;
-+ }
-+
-+ if (temp & 0x10) {
-+ result = -1;
-+ dev_dbg(I801_dev, "Error: Failed bus transaction\n");
-+ }
-+
-+ if (temp & 0x08) {
-+ result = -1;
-+ dev_err(I801_dev, "Bus collision! SMBus may be locked "
-+ "until next hard reset. (sorry!)\n");
-+ /* Clock stops and slave is stuck in mid-transmission */
-+ }
-+
-+ if (temp & 0x04) {
-+ result = -1;
-+ dev_dbg(I801_dev, "Error: no response!\n");
-+ }
-+
-+ if ((inb_p(SMBHSTSTS) & 0x1f) != 0x00)
-+ outb_p(inb(SMBHSTSTS), SMBHSTSTS);
-+
-+ if ((temp = (0x1f & inb_p(SMBHSTSTS))) != 0x00) {
-+ dev_dbg(I801_dev, "Failed reset at end of transaction"
-+ "(%02x)\n", temp);
-+ }
-+ dev_dbg(I801_dev, "Transaction (post): CNT=%02x, CMD=%02x, "
-+ "ADD=%02x, DAT0=%02x, DAT1=%02x\n", inb_p(SMBHSTCNT),
-+ inb_p(SMBHSTCMD), inb_p(SMBHSTADD), inb_p(SMBHSTDAT0),
-+ inb_p(SMBHSTDAT1));
-+ return result;
-+}
-+
-+/* All-inclusive block transaction function */
-+static int i801_block_transaction(union i2c_smbus_data *data, char read_write,
-+ int command)
-+{
-+ int i, len;
-+ int smbcmd;
-+ int temp;
-+ int result = 0;
-+ int timeout;
-+ unsigned char hostc, errmask;
-+
-+ if (command == I2C_SMBUS_I2C_BLOCK_DATA) {
-+ if (read_write == I2C_SMBUS_WRITE) {
-+ /* set I2C_EN bit in configuration register */
-+ pci_read_config_byte(I801_dev, SMBHSTCFG, &hostc);
-+ pci_write_config_byte(I801_dev, SMBHSTCFG,
-+ hostc | SMBHSTCFG_I2C_EN);
-+ } else {
-+ dev_err(I801_dev,
-+ "I2C_SMBUS_I2C_BLOCK_READ not DB!\n");
-+ return -1;
-+ }
-+ }
-+
-+ if (read_write == I2C_SMBUS_WRITE) {
-+ len = data->block[0];
-+ if (len < 1)
-+ len = 1;
-+ if (len > 32)
-+ len = 32;
-+ outb_p(len, SMBHSTDAT0);
-+ outb_p(data->block[1], SMBBLKDAT);
-+ } else {
-+ len = 32; /* max for reads */
-+ }
-+
-+ if(isich4 && command != I2C_SMBUS_I2C_BLOCK_DATA) {
-+ /* set 32 byte buffer */
-+ }
-+
-+ for (i = 1; i <= len; i++) {
-+ if (i == len && read_write == I2C_SMBUS_READ)
-+ smbcmd = I801_BLOCK_LAST;
-+ else
-+ smbcmd = I801_BLOCK_DATA;
-+ outb_p(smbcmd | ENABLE_INT9, SMBHSTCNT);
-+
-+ dev_dbg(I801_dev, "Block (pre %d): CNT=%02x, CMD=%02x, "
-+ "ADD=%02x, DAT0=%02x, BLKDAT=%02x\n", i,
-+ inb_p(SMBHSTCNT), inb_p(SMBHSTCMD), inb_p(SMBHSTADD),
-+ inb_p(SMBHSTDAT0), inb_p(SMBBLKDAT));
-+
-+ /* Make sure the SMBus host is ready to start transmitting */
-+ temp = inb_p(SMBHSTSTS);
-+ if (i == 1) {
-+ /* Erronenous conditions before transaction:
-+ * Byte_Done, Failed, Bus_Err, Dev_Err, Intr, Host_Busy */
-+ errmask=0x9f;
-+ } else {
-+ /* Erronenous conditions during transaction:
-+ * Failed, Bus_Err, Dev_Err, Intr */
-+ errmask=0x1e;
-+ }
-+ if (temp & errmask) {
-+ dev_dbg(I801_dev, "SMBus busy (%02x). "
-+ "Resetting... \n", temp);
-+ outb_p(temp, SMBHSTSTS);
-+ if (((temp = inb_p(SMBHSTSTS)) & errmask) != 0x00) {
-+ dev_err(I801_dev,
-+ "Reset failed! (%02x)\n", temp);
-+ result = -1;
-+ goto END;
-+ }
-+ if (i != 1) {
-+ /* if die in middle of block transaction, fail */
-+ result = -1;
-+ goto END;
-+ }
-+ }
-+
-+ if (i == 1)
-+ outb_p(inb(SMBHSTCNT) | I801_START, SMBHSTCNT);
-+
-+ /* We will always wait for a fraction of a second! */
-+ timeout = 0;
-+ do {
-+ temp = inb_p(SMBHSTSTS);
-+ i2c_delay(1);
-+ }
-+ while ((!(temp & 0x80))
-+ && (timeout++ < MAX_TIMEOUT));
-+
-+ /* If the SMBus is still busy, we give up */
-+ if (timeout >= MAX_TIMEOUT) {
-+ result = -1;
-+ dev_dbg(I801_dev, "SMBus Timeout!\n");
-+ }
-+
-+ if (temp & 0x10) {
-+ result = -1;
-+ dev_dbg(I801_dev,
-+ "Error: Failed bus transaction\n");
-+ } else if (temp & 0x08) {
-+ result = -1;
-+ dev_err(I801_dev, "Bus collision!\n");
-+ } else if (temp & 0x04) {
-+ result = -1;
-+ dev_dbg(I801_dev, "Error: no response!\n");
-+ }
-+
-+ if (i == 1 && read_write == I2C_SMBUS_READ) {
-+ len = inb_p(SMBHSTDAT0);
-+ if (len < 1)
-+ len = 1;
-+ if (len > 32)
-+ len = 32;
-+ data->block[0] = len;
-+ }
-+
-+ /* Retrieve/store value in SMBBLKDAT */
-+ if (read_write == I2C_SMBUS_READ)
-+ data->block[i] = inb_p(SMBBLKDAT);
-+ if (read_write == I2C_SMBUS_WRITE && i+1 <= len)
-+ outb_p(data->block[i+1], SMBBLKDAT);
-+ if ((temp & 0x9e) != 0x00)
-+ outb_p(temp, SMBHSTSTS); /* signals SMBBLKDAT ready */
-+
-+ if ((temp = (0x1e & inb_p(SMBHSTSTS))) != 0x00) {
-+ dev_dbg(I801_dev,
-+ "Bad status (%02x) at end of transaction\n",
-+ temp);
-+ }
-+ dev_dbg(I801_dev, "Block (post %d): CNT=%02x, CMD=%02x, "
-+ "ADD=%02x, DAT0=%02x, BLKDAT=%02x\n", i,
-+ inb_p(SMBHSTCNT), inb_p(SMBHSTCMD), inb_p(SMBHSTADD),
-+ inb_p(SMBHSTDAT0), inb_p(SMBBLKDAT));
-+
-+ if (result < 0)
-+ goto END;
-+ }
-+
-+#ifdef HAVE_PEC
-+ if(isich4 && command == I2C_SMBUS_BLOCK_DATA_PEC) {
-+ /* wait for INTR bit as advised by Intel */
-+ timeout = 0;
-+ do {
-+ temp = inb_p(SMBHSTSTS);
-+ i2c_delay(1);
-+ } while ((!(temp & 0x02))
-+ && (timeout++ < MAX_TIMEOUT));
-+
-+ if (timeout >= MAX_TIMEOUT) {
-+ dev_dbg(I801_dev, "PEC Timeout!\n");
-+ }
-+ outb_p(temp, SMBHSTSTS);
-+ }
-+#endif
-+ result = 0;
-+END:
-+ if (command == I2C_SMBUS_I2C_BLOCK_DATA) {
-+ /* restore saved configuration register value */
-+ pci_write_config_byte(I801_dev, SMBHSTCFG, hostc);
-+ }
-+ return result;
-+}
-+
-+/* Return -1 on error. */
-+static s32 i801_access(struct i2c_adapter * adap, u16 addr,
-+ unsigned short flags, char read_write, u8 command,
-+ int size, union i2c_smbus_data * data)
-+{
-+ int hwpec = 0;
-+ int block = 0;
-+ int ret, xact = 0;
-+
-+#ifdef HAVE_PEC
-+ if(isich4)
-+ hwpec = (flags & I2C_CLIENT_PEC) != 0;
-+#endif
-+
-+ switch (size) {
-+ case I2C_SMBUS_QUICK:
-+ outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),
-+ SMBHSTADD);
-+ xact = I801_QUICK;
-+ break;
-+ case I2C_SMBUS_BYTE:
-+ outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),
-+ SMBHSTADD);
-+ if (read_write == I2C_SMBUS_WRITE)
-+ outb_p(command, SMBHSTCMD);
-+ xact = I801_BYTE;
-+ break;
-+ case I2C_SMBUS_BYTE_DATA:
-+ outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),
-+ SMBHSTADD);
-+ outb_p(command, SMBHSTCMD);
-+ if (read_write == I2C_SMBUS_WRITE)
-+ outb_p(data->byte, SMBHSTDAT0);
-+ xact = I801_BYTE_DATA;
-+ break;
-+ case I2C_SMBUS_WORD_DATA:
-+ outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),
-+ SMBHSTADD);
-+ outb_p(command, SMBHSTCMD);
-+ if (read_write == I2C_SMBUS_WRITE) {
-+ outb_p(data->word & 0xff, SMBHSTDAT0);
-+ outb_p((data->word & 0xff00) >> 8, SMBHSTDAT1);
-+ }
-+ xact = I801_WORD_DATA;
-+ break;
-+ case I2C_SMBUS_BLOCK_DATA:
-+ case I2C_SMBUS_I2C_BLOCK_DATA:
-+#ifdef HAVE_PEC
-+ case I2C_SMBUS_BLOCK_DATA_PEC:
-+ if(hwpec && size == I2C_SMBUS_BLOCK_DATA)
-+ size = I2C_SMBUS_BLOCK_DATA_PEC;
-+#endif
-+ outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),
-+ SMBHSTADD);
-+ outb_p(command, SMBHSTCMD);
-+ block = 1;
-+ break;
-+ case I2C_SMBUS_PROC_CALL:
-+ default:
-+ dev_err(I801_dev, "Unsupported transaction %d\n", size);
-+ return -1;
-+ }
-+
-+#ifdef HAVE_PEC
-+ if(isich4 && hwpec) {
-+ if(size != I2C_SMBUS_QUICK &&
-+ size != I2C_SMBUS_I2C_BLOCK_DATA)
-+ outb_p(1, SMBAUXCTL); /* enable HW PEC */
-+ }
-+#endif
-+ if(block)
-+ ret = i801_block_transaction(data, read_write, size);
-+ else {
-+ outb_p(xact | ENABLE_INT9, SMBHSTCNT);
-+ ret = i801_transaction();
-+ }
-+
-+#ifdef HAVE_PEC
-+ if(isich4 && hwpec) {
-+ if(size != I2C_SMBUS_QUICK &&
-+ size != I2C_SMBUS_I2C_BLOCK_DATA)
-+ outb_p(0, SMBAUXCTL);
-+ }
-+#endif
-+
-+ if(block)
-+ return ret;
-+ if(ret)
-+ return -1;
-+ if ((read_write == I2C_SMBUS_WRITE) || (xact == I801_QUICK))
-+ return 0;
-+
-+ switch (xact & 0x7f) {
-+ case I801_BYTE: /* Result put in SMBHSTDAT0 */
-+ case I801_BYTE_DATA:
-+ data->byte = inb_p(SMBHSTDAT0);
-+ break;
-+ case I801_WORD_DATA:
-+ data->word = inb_p(SMBHSTDAT0) + (inb_p(SMBHSTDAT1) << 8);
-+ break;
-+ }
-+ return 0;
-+}
-+
-+
-+static u32 i801_func(struct i2c_adapter *adapter)
-+{
-+ return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
-+ I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
-+ I2C_FUNC_SMBUS_BLOCK_DATA | I2C_FUNC_SMBUS_WRITE_I2C_BLOCK
-+#ifdef HAVE_PEC
-+ | (isich4 ? I2C_FUNC_SMBUS_BLOCK_DATA_PEC |
-+ I2C_FUNC_SMBUS_HWPEC_CALC
-+ : 0)
-+#endif
-+ ;
-+}
-+
-+static struct i2c_algorithm smbus_algorithm = {
-+ .name = "Non-I2C SMBus adapter",
-+ .id = I2C_ALGO_SMBUS,
-+ .smbus_xfer = i801_access,
-+ .functionality = i801_func,
-+};
-+
-+static struct i2c_adapter i801_adapter = {
-+ .owner = THIS_MODULE,
-+ .id = I2C_ALGO_SMBUS | I2C_HW_SMBUS_I801,
-+ .algo = &smbus_algorithm,
-+ .name = "unset",
-+};
-+
-+static struct pci_device_id i801_ids[] __devinitdata = {
-+ {
-+ .vendor = PCI_VENDOR_ID_INTEL,
-+ .device = PCI_DEVICE_ID_INTEL_82801AA_3,
-+ .subvendor = PCI_ANY_ID,
-+ .subdevice = PCI_ANY_ID,
-+ },
-+ {
-+ .vendor = PCI_VENDOR_ID_INTEL,
-+ .device = PCI_DEVICE_ID_INTEL_82801AB_3,
-+ .subvendor = PCI_ANY_ID,
-+ .subdevice = PCI_ANY_ID,
-+ },
-+ {
-+ .vendor = PCI_VENDOR_ID_INTEL,
-+ .device = PCI_DEVICE_ID_INTEL_82801BA_2,
-+ .subvendor = PCI_ANY_ID,
-+ .subdevice = PCI_ANY_ID,
-+ },
-+ {
-+ .vendor = PCI_VENDOR_ID_INTEL,
-+ .device = PCI_DEVICE_ID_INTEL_82801CA_3,
-+ .subvendor = PCI_ANY_ID,
-+ .subdevice = PCI_ANY_ID,
-+ },
-+ {
-+ .vendor = PCI_VENDOR_ID_INTEL,
-+ .device = PCI_DEVICE_ID_INTEL_82801DB_3,
-+ .subvendor = PCI_ANY_ID,
-+ .subdevice = PCI_ANY_ID,
-+ },
-+ {
-+ .vendor = PCI_VENDOR_ID_INTEL,
-+ .device = 0x24d3, /* 82801EB ICH5 */
-+ .subvendor = PCI_ANY_ID,
-+ .subdevice = PCI_ANY_ID,
-+ },
-+ {
-+ .vendor = PCI_VENDOR_ID_INTEL,
-+ .device = 0x25a4, /* PCI_DEVICE_ID_INTEL_ESB_4 */
-+ .subvendor = PCI_ANY_ID,
-+ .subdevice = PCI_ANY_ID,
-+ },
-+ {
-+ .vendor = PCI_VENDOR_ID_INTEL,
-+ .device = 0x266a, /* PCI_DEVICE_ID_INTEL_ICH6_16 */
-+ .subvendor = PCI_ANY_ID,
-+ .subdevice = PCI_ANY_ID,
-+ },
-+ { 0, }
-+};
-+
-+static int __devinit i801_probe(struct pci_dev *dev, const struct pci_device_id *id)
-+{
-+
-+ if (i801_setup(dev)) {
-+ dev_warn(dev,
-+ "I801 not detected, module not inserted.\n");
-+ return -ENODEV;
-+ }
-+
-+ snprintf(i801_adapter.name, 32,
-+ "SMBus I801 adapter at %04x", i801_smba);
-+ return i2c_add_adapter(&i801_adapter);
-+}
-+
-+static void __devexit i801_remove(struct pci_dev *dev)
-+{
-+ i2c_del_adapter(&i801_adapter);
-+ release_region(i801_smba, (isich4 ? 16 : 8));
-+}
-+
-+static struct pci_driver i801_driver = {
-+ .name = "i801 smbus",
-+ .id_table = i801_ids,
-+ .probe = i801_probe,
-+ .remove = __devexit_p(i801_remove),
-+};
-+
-+static int __init i2c_i801_init(void)
-+{
-+ printk(KERN_INFO "i2c-i801 version %s (%s)\n", LM_VERSION, LM_DATE);
-+ return pci_module_init(&i801_driver);
-+}
-+
-+static void __exit i2c_i801_exit(void)
-+{
-+ pci_unregister_driver(&i801_driver);
-+}
-+
-+MODULE_AUTHOR ("Frodo Looijaard <frodol@dds.nl>, "
-+ "Philip Edelbrock <phil@netroedge.com>, "
-+ "and Mark D. Studebaker <mdsxyz123@yahoo.com>");
-+MODULE_DESCRIPTION("I801 SMBus driver");
-+MODULE_LICENSE("GPL");
-+
-+module_init(i2c_i801_init);
-+module_exit(i2c_i801_exit);
---- linux-old/drivers/i2c/i2c-i810.c Thu Jan 1 00:00:00 1970
-+++ linux/drivers/i2c/i2c-i810.c Mon Dec 13 20:18:41 2004
-@@ -0,0 +1,310 @@
-+/*
-+ i2c-i810.c - Part of lm_sensors, Linux kernel modules for hardware
-+ monitoring
-+ Copyright (c) 1998, 1999, 2000 Frodo Looijaard <frodol@dds.nl>,
-+ Philip Edelbrock <phil@netroedge.com>,
-+ Ralph Metzler <rjkm@thp.uni-koeln.de>, and
-+ Mark D. Studebaker <mdsxyz123@yahoo.com>
-+
-+ Based on code written by Ralph Metzler <rjkm@thp.uni-koeln.de> and
-+ Simon Vogl
-+
-+ 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., 675 Mass Ave, Cambridge, MA 02139, USA.
-+*/
-+/*
-+ This interfaces to the I810/I815 to provide access to
-+ the DDC Bus and the I2C Bus.
-+
-+ SUPPORTED DEVICES PCI ID
-+ i810AA 7121
-+ i810AB 7123
-+ i810E 7125
-+ i815 1132
-+*/
-+
-+
-+#include <linux/module.h>
-+#include <linux/pci.h>
-+#include <linux/i2c.h>
-+#include <linux/i2c-algo-bit.h>
-+#include <linux/init.h>
-+#include <asm/io.h>
-+#include <asm/param.h> /* for HZ */
-+#define LM_DATE "20041007"
-+#define LM_VERSION "2.8.8"
-+
-+MODULE_LICENSE("GPL");
-+
-+#ifndef PCI_DEVICE_ID_INTEL_82815_2
-+#define PCI_DEVICE_ID_INTEL_82815_2 0x1132
-+#endif
-+
-+/* GPIO register locations */
-+#define I810_IOCONTROL_OFFSET 0x5000
-+#define I810_HVSYNC 0x00 /* not used */
-+#define I810_GPIOA 0x10
-+#define I810_GPIOB 0x14
-+
-+/* bit locations in the registers */
-+#define SCL_DIR_MASK 0x0001
-+#define SCL_DIR 0x0002
-+#define SCL_VAL_MASK 0x0004
-+#define SCL_VAL_OUT 0x0008
-+#define SCL_VAL_IN 0x0010
-+#define SDA_DIR_MASK 0x0100
-+#define SDA_DIR 0x0200
-+#define SDA_VAL_MASK 0x0400
-+#define SDA_VAL_OUT 0x0800
-+#define SDA_VAL_IN 0x1000
-+
-+/* initialization states */
-+#define INIT1 0x1
-+#define INIT2 0x2
-+#define INIT3 0x4
-+
-+/* delays */
-+#define CYCLE_DELAY 10
-+#define TIMEOUT (HZ / 2)
-+
-+
-+static void config_i810(struct pci_dev *dev);
-+
-+
-+static unsigned long ioaddr;
-+
-+/* The i810 GPIO registers have individual masks for each bit
-+ so we never have to read before writing. Nice. */
-+
-+static void bit_i810i2c_setscl(void *data, int val)
-+{
-+ writel((val ? SCL_VAL_OUT : 0) | SCL_DIR | SCL_DIR_MASK | SCL_VAL_MASK,
-+ ioaddr + I810_GPIOB);
-+ readl(ioaddr + I810_GPIOB); /* flush posted write */
-+}
-+
-+static void bit_i810i2c_setsda(void *data, int val)
-+{
-+ writel((val ? SDA_VAL_OUT : 0) | SDA_DIR | SDA_DIR_MASK | SDA_VAL_MASK,
-+ ioaddr + I810_GPIOB);
-+ readl(ioaddr + I810_GPIOB); /* flush posted write */
-+}
-+
-+/* The GPIO pins are open drain, so the pins could always remain outputs.
-+ However, some chip versions don't latch the inputs unless they
-+ are set as inputs.
-+ We rely on the i2c-algo-bit routines to set the pins high before
-+ reading the input from other chips. Following guidance in the 815
-+ prog. ref. guide, we do a "dummy write" of 0 to the register before
-+ reading which forces the input value to be latched. We presume this
-+ applies to the 810 as well; shouldn't hurt anyway. This is necessary to get
-+ i2c_algo_bit bit_test=1 to pass. */
-+
-+static int bit_i810i2c_getscl(void *data)
-+{
-+ writel(SCL_DIR_MASK, ioaddr + I810_GPIOB);
-+ writel(0, ioaddr + I810_GPIOB);
-+ return (0 != (readl(ioaddr + I810_GPIOB) & SCL_VAL_IN));
-+}
-+
-+static int bit_i810i2c_getsda(void *data)
-+{
-+ writel(SDA_DIR_MASK, ioaddr + I810_GPIOB);
-+ writel(0, ioaddr + I810_GPIOB);
-+ return (0 != (readl(ioaddr + I810_GPIOB) & SDA_VAL_IN));
-+}
-+
-+static void bit_i810ddc_setscl(void *data, int val)
-+{
-+ writel((val ? SCL_VAL_OUT : 0) | SCL_DIR | SCL_DIR_MASK | SCL_VAL_MASK,
-+ ioaddr + I810_GPIOA);
-+ readl(ioaddr + I810_GPIOA); /* flush posted write */
-+}
-+
-+static void bit_i810ddc_setsda(void *data, int val)
-+{
-+ writel((val ? SDA_VAL_OUT : 0) | SDA_DIR | SDA_DIR_MASK | SDA_VAL_MASK,
-+ ioaddr + I810_GPIOA);
-+ readl(ioaddr + I810_GPIOA); /* flush posted write */
-+}
-+
-+static int bit_i810ddc_getscl(void *data)
-+{
-+ writel(SCL_DIR_MASK, ioaddr + I810_GPIOA);
-+ writel(0, ioaddr + I810_GPIOA);
-+ return (0 != (readl(ioaddr + I810_GPIOA) & SCL_VAL_IN));
-+}
-+
-+static int bit_i810ddc_getsda(void *data)
-+{
-+ writel(SDA_DIR_MASK, ioaddr + I810_GPIOA);
-+ writel(0, ioaddr + I810_GPIOA);
-+ return (0 != (readl(ioaddr + I810_GPIOA) & SDA_VAL_IN));
-+}
-+
-+
-+/* Configures the chip */
-+void config_i810(struct pci_dev *dev)
-+{
-+ unsigned long cadr;
-+
-+ /* map I810 memory */
-+ cadr = dev->resource[1].start;
-+ cadr += I810_IOCONTROL_OFFSET;
-+ cadr &= PCI_BASE_ADDRESS_MEM_MASK;
-+ ioaddr = (unsigned long)ioremap_nocache(cadr, 0x1000);
-+ if(ioaddr) {
-+ bit_i810i2c_setscl(NULL, 1);
-+ bit_i810i2c_setsda(NULL, 1);
-+ bit_i810ddc_setscl(NULL, 1);
-+ bit_i810ddc_setsda(NULL, 1);
-+ }
-+}
-+
-+
-+static struct i2c_algo_bit_data i810_i2c_bit_data = {
-+ .setsda = bit_i810i2c_setsda,
-+ .setscl = bit_i810i2c_setscl,
-+ .getsda = bit_i810i2c_getsda,
-+ .getscl = bit_i810i2c_getscl,
-+ .udelay = CYCLE_DELAY,
-+ .mdelay = CYCLE_DELAY,
-+ .timeout = TIMEOUT,
-+};
-+
-+static struct i2c_adapter i810_i2c_adapter = {
-+ .owner = THIS_MODULE,
-+ .name = "I810/I815 I2C Adapter",
-+ .id = I2C_HW_B_I810,
-+ .algo_data = &i810_i2c_bit_data,
-+};
-+
-+static struct i2c_algo_bit_data i810_ddc_bit_data = {
-+ .setsda = bit_i810ddc_setsda,
-+ .setscl = bit_i810ddc_setscl,
-+ .getsda = bit_i810ddc_getsda,
-+ .getscl = bit_i810ddc_getscl,
-+ .udelay = CYCLE_DELAY,
-+ .mdelay = CYCLE_DELAY,
-+ .timeout = TIMEOUT,
-+};
-+
-+static struct i2c_adapter i810_ddc_adapter = {
-+ .owner = THIS_MODULE,
-+ .name = "I810/I815 DDC Adapter",
-+ .id = I2C_HW_B_I810,
-+ .algo_data = &i810_ddc_bit_data,
-+};
-+
-+
-+static struct pci_device_id i810_ids[] __devinitdata = {
-+ {
-+ .vendor = PCI_VENDOR_ID_INTEL,
-+ .device = PCI_DEVICE_ID_INTEL_82810_IG1,
-+ .subvendor = PCI_ANY_ID,
-+ .subdevice = PCI_ANY_ID,
-+ },
-+ {
-+ .vendor = PCI_VENDOR_ID_INTEL,
-+ .device = PCI_DEVICE_ID_INTEL_82810_IG3,
-+ .subvendor = PCI_ANY_ID,
-+ .subdevice = PCI_ANY_ID,
-+ },
-+ {
-+ .vendor = PCI_VENDOR_ID_INTEL,
-+ .device = 0x7125,
-+ .subvendor = PCI_ANY_ID,
-+ .subdevice = PCI_ANY_ID,
-+ },
-+ {
-+ .vendor = PCI_VENDOR_ID_INTEL,
-+ .device = PCI_DEVICE_ID_INTEL_82815_2,
-+ .subvendor = PCI_ANY_ID,
-+ .subdevice = PCI_ANY_ID,
-+ },
-+ {
-+ .vendor = PCI_VENDOR_ID_INTEL,
-+ .device = 0x2562,
-+ .subvendor = PCI_ANY_ID,
-+ .subdevice = PCI_ANY_ID,
-+ },
-+ { 0, }
-+};
-+
-+static int __devinit i810_probe(struct pci_dev *dev, const struct pci_device_id *id)
-+{
-+ int retval;
-+
-+ config_i810(dev);
-+ printk("i2c-i810.o: i810/i815 found.\n");
-+
-+ retval = i2c_bit_add_bus(&i810_i2c_adapter);
-+ if(retval)
-+ return retval;
-+ retval = i2c_bit_add_bus(&i810_ddc_adapter);
-+ if(retval)
-+ i2c_bit_del_bus(&i810_i2c_adapter);
-+ return retval;
-+}
-+
-+static void __devexit i810_remove(struct pci_dev *dev)
-+{
-+ i2c_bit_del_bus(&i810_ddc_adapter);
-+ i2c_bit_del_bus(&i810_i2c_adapter);
-+}
-+
-+
-+/* Don't register driver to avoid driver conflicts */
-+/*
-+static struct pci_driver i810_driver = {
-+ .name = "i810 smbus",
-+ .id_table = i810_ids,
-+ .probe = i810_probe,
-+ .remove = __devexit_p(i810_remove),
-+};
-+*/
-+
-+static int __init i2c_i810_init(void)
-+{
-+ struct pci_dev *dev;
-+ const struct pci_device_id *id;
-+
-+ printk("i2c-i810.o version %s (%s)\n", LM_VERSION, LM_DATE);
-+/*
-+ return pci_module_init(&i810_driver);
-+*/
-+ pci_for_each_dev(dev) {
-+ id = pci_match_device(i810_ids, dev);
-+ if(id)
-+ if(i810_probe(dev, id) >= 0)
-+ return 0;
-+ }
-+ return -ENODEV;
-+}
-+
-+static void __exit i2c_i810_exit(void)
-+{
-+/*
-+ pci_unregister_driver(&i810_driver);
-+*/
-+ i810_remove(NULL);
-+ iounmap((void *)ioaddr);
-+}
-+
-+MODULE_AUTHOR
-+ ("Frodo Looijaard <frodol@dds.nl>, Philip Edelbrock <phil@netroedge.com>, Ralph Metzler <rjkm@thp.uni-koeln.de>, and Mark D. Studebaker <mdsxyz123@yahoo.com>");
-+MODULE_DESCRIPTION("I810/I815 I2C/DDC driver");
-+
-+module_init(i2c_i810_init);
-+module_exit(i2c_i810_exit);
---- linux-old/drivers/i2c/i2c-isa.c Thu Jan 1 00:00:00 1970
-+++ linux/drivers/i2c/i2c-isa.c Mon Dec 13 20:18:41 2004
-@@ -0,0 +1,74 @@
-+/*
-+ i2c-isa.c - Part of lm_sensors, Linux kernel modules for hardware
-+ monitoring
-+ Copyright (c) 1998, 1999 Frodo Looijaard <frodol@dds.nl>
-+
-+ 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., 675 Mass Ave, Cambridge, MA 02139, USA.
-+*/
-+
-+/* This implements an i2c algorithm/adapter for ISA bus. Not that this is
-+ on first sight very useful; almost no functionality is preserved.
-+ Except that it makes writing drivers for chips which can be on both
-+ the SMBus and the ISA bus very much easier. See lm78.c for an example
-+ of this. */
-+
-+#include <linux/init.h>
-+#include <linux/module.h>
-+#include <linux/kernel.h>
-+#include <linux/errno.h>
-+#include <linux/i2c.h>
-+#define LM_DATE "20041007"
-+#define LM_VERSION "2.8.8"
-+
-+static u32 isa_func(struct i2c_adapter *adapter);
-+
-+/* This is the actual algorithm we define */
-+static struct i2c_algorithm isa_algorithm = {
-+ .name = "ISA bus algorithm",
-+ .id = I2C_ALGO_ISA,
-+ .functionality = isa_func,
-+};
-+
-+/* There can only be one... */
-+static struct i2c_adapter isa_adapter = {
-+ .owner = THIS_MODULE,
-+ .name = "ISA main adapter",
-+ .id = I2C_ALGO_ISA | I2C_HW_ISA,
-+ .algo = &isa_algorithm,
-+};
-+
-+/* We can't do a thing... */
-+static u32 isa_func(struct i2c_adapter *adapter)
-+{
-+ return 0;
-+}
-+
-+static int __init i2c_isa_init(void)
-+{
-+ printk("i2c-isa.o version %s (%s)\n", LM_VERSION, LM_DATE);
-+ return i2c_add_adapter(&isa_adapter);
-+}
-+
-+static void __exit i2c_isa_exit(void)
-+{
-+ i2c_del_adapter(&isa_adapter);
-+}
-+
-+MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl>");
-+MODULE_DESCRIPTION("ISA bus access through i2c");
-+MODULE_LICENSE("GPL");
-+
-+module_init(i2c_isa_init);
-+module_exit(i2c_isa_exit);
---- linux-old/drivers/i2c/i2c-nforce2.c Thu Jan 1 00:00:00 1970
-+++ linux/drivers/i2c/i2c-nforce2.c Mon Dec 13 20:18:41 2004
-@@ -0,0 +1,409 @@
-+/*
-+ SMBus driver for nVidia nForce2 MCP
-+
-+ Copyright (c) 2003 Hans-Frieder Vogt <hfvogt@arcor.de>,
-+ Based on
-+ SMBus 2.0 driver for AMD-8111 IO-Hub
-+ Copyright (c) 2002 Vojtech Pavlik
-+
-+ 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., 675 Mass Ave, Cambridge, MA 02139, USA.
-+*/
-+
-+/*
-+ SUPPORTED DEVICES PCI ID
-+ nForce2 MCP 0064
-+
-+ This driver supports the 2 SMBuses that are included in the MCP2 of the
-+ nForce2 chipset.
-+*/
-+
-+/* Note: we assume there can only be one nForce2, with two SMBus interfaces */
-+
-+#include <linux/module.h>
-+#include <linux/pci.h>
-+#include <linux/kernel.h>
-+#include <linux/stddef.h>
-+#include <linux/sched.h>
-+#include <linux/ioport.h>
-+#include <linux/init.h>
-+#include <linux/i2c.h>
-+#include <linux/delay.h>
-+#include <linux/slab.h>
-+#include <asm/io.h>
-+#define LM_DATE "20041007"
-+#define LM_VERSION "2.8.8"
-+
-+/* kernel 2.4.9 needs this */
-+#ifndef min_t
-+#define min_t(type,x,y) min(type,x,y)
-+#endif
-+
-+MODULE_LICENSE("GPL");
-+MODULE_AUTHOR ("Hans-Frieder Vogt <hfvogt@arcor.de>");
-+MODULE_DESCRIPTION("nForce2 SMBus driver");
-+
-+#ifndef PCI_DEVICE_ID_NVIDIA_NFORCE2_SMBUS
-+#define PCI_DEVICE_ID_NVIDIA_NFORCE2_SMBUS 0x0064
-+#endif
-+
-+
-+struct nforce2_smbus {
-+ struct pci_dev *dev;
-+ struct i2c_adapter adapter;
-+ int base;
-+ int size;
-+};
-+
-+
-+/*
-+ * nVidia nForce2 SMBus control register definitions
-+ */
-+#define NFORCE_PCI_SMB1 0x50
-+#define NFORCE_PCI_SMB2 0x54
-+
-+
-+/*
-+ * ACPI 2.0 chapter 13 SMBus 2.0 EC register model
-+ */
-+#define NVIDIA_SMB_PRTCL (smbus->base + 0x00) /* protocol, PEC */
-+#define NVIDIA_SMB_STS (smbus->base + 0x01) /* status */
-+#define NVIDIA_SMB_ADDR (smbus->base + 0x02) /* address */
-+#define NVIDIA_SMB_CMD (smbus->base + 0x03) /* command */
-+#define NVIDIA_SMB_DATA (smbus->base + 0x04) /* 32 data registers */
-+#define NVIDIA_SMB_BCNT (smbus->base + 0x24) /* number of data bytes */
-+#define NVIDIA_SMB_ALRM_A (smbus->base + 0x25) /* alarm address */
-+#define NVIDIA_SMB_ALRM_D (smbus->base + 0x26) /* 2 bytes alarm data */
-+
-+#define NVIDIA_SMB_STS_DONE 0x80
-+#define NVIDIA_SMB_STS_ALRM 0x40
-+#define NVIDIA_SMB_STS_RES 0x20
-+#define NVIDIA_SMB_STS_STATUS 0x1f
-+
-+#define NVIDIA_SMB_PRTCL_WRITE 0x00
-+#define NVIDIA_SMB_PRTCL_READ 0x01
-+#define NVIDIA_SMB_PRTCL_QUICK 0x02
-+#define NVIDIA_SMB_PRTCL_BYTE 0x04
-+#define NVIDIA_SMB_PRTCL_BYTE_DATA 0x06
-+#define NVIDIA_SMB_PRTCL_WORD_DATA 0x08
-+#define NVIDIA_SMB_PRTCL_BLOCK_DATA 0x0a
-+#define NVIDIA_SMB_PRTCL_PROC_CALL 0x0c
-+#define NVIDIA_SMB_PRTCL_BLOCK_PROC_CALL 0x0d
-+#define NVIDIA_SMB_PRTCL_I2C_BLOCK_DATA 0x4a
-+#define NVIDIA_SMB_PRTCL_PEC 0x80
-+
-+
-+/* Other settings */
-+#define MAX_TIMEOUT 256
-+
-+
-+
-+static s32 nforce2_access(struct i2c_adapter *adap, u16 addr,
-+ unsigned short flags, char read_write,
-+ u8 command, int size, union i2c_smbus_data *data);
-+/*
-+static int nforce2_block_transaction(union i2c_smbus_data *data,
-+ char read_write, int i2c_enable);
-+ */
-+static u32 nforce2_func(struct i2c_adapter *adapter);
-+
-+
-+static struct i2c_algorithm smbus_algorithm = {
-+ .name = "Non-I2C SMBus adapter",
-+ .id = I2C_ALGO_SMBUS,
-+ .smbus_xfer = nforce2_access,
-+ .functionality = nforce2_func,
-+};
-+
-+/* Return -1 on error. See smbus.h for more information */
-+s32 nforce2_access(struct i2c_adapter * adap, u16 addr, unsigned short flags,
-+ char read_write, u8 command, int size,
-+ union i2c_smbus_data * data)
-+{
-+ struct nforce2_smbus *smbus = adap->algo_data;
-+ unsigned char protocol, pec, temp;
-+ unsigned char len = 0; /* to keep the compiler quiet */
-+ int timeout = 0;
-+ int i;
-+
-+ protocol = (read_write == I2C_SMBUS_READ) ? NVIDIA_SMB_PRTCL_READ : NVIDIA_SMB_PRTCL_WRITE;
-+ pec = (flags & I2C_CLIENT_PEC) ? NVIDIA_SMB_PRTCL_PEC : 0;
-+
-+ switch (size) {
-+
-+ case I2C_SMBUS_QUICK:
-+ protocol |= NVIDIA_SMB_PRTCL_QUICK;
-+ read_write = I2C_SMBUS_WRITE;
-+ break;
-+
-+ case I2C_SMBUS_BYTE:
-+ if (read_write == I2C_SMBUS_WRITE)
-+ outb_p(command, NVIDIA_SMB_CMD);
-+ protocol |= NVIDIA_SMB_PRTCL_BYTE;
-+ break;
-+
-+ case I2C_SMBUS_BYTE_DATA:
-+ outb_p(command, NVIDIA_SMB_CMD);
-+ if (read_write == I2C_SMBUS_WRITE)
-+ outb_p(data->byte, NVIDIA_SMB_DATA);
-+ protocol |= NVIDIA_SMB_PRTCL_BYTE_DATA;
-+ break;
-+
-+ case I2C_SMBUS_WORD_DATA:
-+ outb_p(command, NVIDIA_SMB_CMD);
-+ if (read_write == I2C_SMBUS_WRITE) {
-+ outb_p(data->word, NVIDIA_SMB_DATA);
-+ outb_p(data->word >> 8, NVIDIA_SMB_DATA+1);
-+ }
-+ protocol |= NVIDIA_SMB_PRTCL_WORD_DATA | pec;
-+ break;
-+
-+ case I2C_SMBUS_BLOCK_DATA:
-+ outb_p(command, NVIDIA_SMB_CMD);
-+ if (read_write == I2C_SMBUS_WRITE) {
-+ len = min_t(u8, data->block[0], 32);
-+ outb_p(len, NVIDIA_SMB_BCNT);
-+ for (i = 0; i < len; i++)
-+ outb_p(data->block[i + 1], NVIDIA_SMB_DATA+i);
-+ }
-+ protocol |= NVIDIA_SMB_PRTCL_BLOCK_DATA | pec;
-+ break;
-+
-+ case I2C_SMBUS_I2C_BLOCK_DATA:
-+ len = min_t(u8, data->block[0], 32);
-+ outb_p(command, NVIDIA_SMB_CMD);
-+ outb_p(len, NVIDIA_SMB_BCNT);
-+ if (read_write == I2C_SMBUS_WRITE)
-+ for (i = 0; i < len; i++)
-+ outb_p(data->block[i + 1], NVIDIA_SMB_DATA+i);
-+ protocol |= NVIDIA_SMB_PRTCL_I2C_BLOCK_DATA;
-+ break;
-+
-+ case I2C_SMBUS_PROC_CALL:
-+ printk(KERN_WARNING "i2c-nforce2.o: I2C_SMBUS_PROC_CALL not supported!\n");
-+ return -1;
-+ /*
-+ outb_p(command, NVIDIA_SMB_CMD);
-+ outb_p(data->word, NVIDIA_SMB_DATA);
-+ outb_p(data->word >> 8, NVIDIA_SMB_DATA + 1);
-+ protocol = NVIDIA_SMB_PRTCL_PROC_CALL | pec;
-+ read_write = I2C_SMBUS_READ;
-+ break;
-+ */
-+
-+ case I2C_SMBUS_BLOCK_PROC_CALL:
-+ printk(KERN_WARNING "i2c-nforce2.o: I2C_SMBUS_BLOCK_PROC_CALL not supported!\n");
-+ return -1;
-+ /*
-+ protocol |= pec;
-+ len = min_t(u8, data->block[0], 31);
-+ outb_p(command, NVIDIA_SMB_CMD);
-+ outb_p(len, NVIDIA_SMB_BCNT);
-+ for (i = 0; i < len; i++)
-+ outb_p(data->block[i + 1], NVIDIA_SMB_DATA + i);
-+ protocol = NVIDIA_SMB_PRTCL_BLOCK_PROC_CALL | pec;
-+ read_write = I2C_SMBUS_READ;
-+ break;
-+ */
-+
-+ case I2C_SMBUS_WORD_DATA_PEC:
-+ case I2C_SMBUS_BLOCK_DATA_PEC:
-+ case I2C_SMBUS_PROC_CALL_PEC:
-+ case I2C_SMBUS_BLOCK_PROC_CALL_PEC:
-+ printk(KERN_WARNING "i2c-nforce2.c: Unexpected software PEC transaction %d\n.", size);
-+ return -1;
-+
-+ default:
-+ printk(KERN_WARNING "i2c-nforce2.c: Unsupported transaction %d\n", size);
-+ return -1;
-+ }
-+
-+ outb_p((addr & 0x7f) << 1, NVIDIA_SMB_ADDR);
-+ outb_p(protocol, NVIDIA_SMB_PRTCL);
-+
-+ temp = inb_p(NVIDIA_SMB_STS);
-+
-+#if 0
-+ do {
-+ i2c_delay(1);
-+ temp = inb_p(NVIDIA_SMB_STS);
-+ } while (((temp & NVIDIA_SMB_STS_DONE) == 0) && (timeout++ < MAX_TIMEOUT));
-+#endif
-+ if (~temp & NVIDIA_SMB_STS_DONE) {
-+ udelay(500);
-+ temp = inb_p(NVIDIA_SMB_STS);
-+ }
-+ if (~temp & NVIDIA_SMB_STS_DONE) {
-+ i2c_delay(HZ/100);
-+ temp = inb_p(NVIDIA_SMB_STS);
-+ }
-+
-+ if ((timeout >= MAX_TIMEOUT) || (~temp & NVIDIA_SMB_STS_DONE) || (temp & NVIDIA_SMB_STS_STATUS))
-+ return -1;
-+
-+ if (read_write == I2C_SMBUS_WRITE)
-+ return 0;
-+
-+ switch (size) {
-+
-+ case I2C_SMBUS_BYTE:
-+ case I2C_SMBUS_BYTE_DATA:
-+ data->byte = inb_p(NVIDIA_SMB_DATA);
-+ break;
-+
-+ case I2C_SMBUS_WORD_DATA:
-+ /* case I2C_SMBUS_PROC_CALL: not supported */
-+ data->word = inb_p(NVIDIA_SMB_DATA) | (inb_p(NVIDIA_SMB_DATA+1) << 8);
-+ break;
-+
-+ case I2C_SMBUS_BLOCK_DATA:
-+ /* case I2C_SMBUS_BLOCK_PROC_CALL: not supported */
-+ len = inb_p(NVIDIA_SMB_BCNT);
-+ len = min_t(u8, len, 32);
-+ case I2C_SMBUS_I2C_BLOCK_DATA:
-+ for (i = 0; i < len; i++)
-+ data->block[i+1] = inb_p(NVIDIA_SMB_DATA + i);
-+ data->block[0] = len;
-+ break;
-+ }
-+
-+ return 0;
-+}
-+
-+
-+u32 nforce2_func(struct i2c_adapter *adapter)
-+{
-+ /* other functionality might be possible, but is not tested */
-+ return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
-+ I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA /* |
-+ I2C_FUNC_SMBUS_BLOCK_DATA */;
-+}
-+
-+
-+static struct pci_device_id nforce2_ids[] = {
-+ { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE2_SMBUS,
-+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
-+ { 0 }
-+};
-+
-+
-+static int __devinit nforce2_probe_smb (struct pci_dev *dev, int reg, struct nforce2_smbus *smbus, char *name)
-+{
-+ u16 iobase;
-+ int error;
-+
-+ if (pci_read_config_word(dev, reg, &iobase) != PCIBIOS_SUCCESSFUL) {
-+ printk (KERN_ERR "i2c-nforce2.o: Error reading PCI config for %s\n", name);
-+ return -1;
-+ }
-+ smbus->dev = dev;
-+ smbus->base = iobase & 0xfffc;
-+ smbus->size = 8;
-+
-+ if (!request_region(smbus->base, smbus->size, "nForce2 SMBus")) {
-+ printk (KERN_ERR "i2c-nforce2.o: Error requesting region %02x .. %02X for %s\n", smbus->base, smbus->base+smbus->size-1, name);
-+ return -1;
-+ }
-+
-+ /* TODO: find a better way to find out whether this file is compiled
-+ * with i2c 2.7.0 of earlier
-+ */
-+#ifdef I2C_HW_SMBUS_AMD8111
-+ smbus->adapter.owner = THIS_MODULE;
-+#endif
-+ sprintf(smbus->adapter.name, "SMBus nForce2 adapter at %04x", smbus->base);
-+ smbus->adapter.id = I2C_ALGO_SMBUS | I2C_HW_SMBUS_NFORCE2;
-+ smbus->adapter.algo = &smbus_algorithm;
-+ smbus->adapter.algo_data = smbus;
-+
-+ error = i2c_add_adapter(&smbus->adapter);
-+ if (error) {
-+ printk(KERN_WARNING "i2c-nforce2.o: Failed to register adapter.\n");
-+ release_region(smbus->base, smbus->size);
-+ return -1;
-+ }
-+ printk(KERN_INFO "i2c-nforce2.o: nForce2 SMBus adapter at %#x\n", smbus->base);
-+ return 0;
-+}
-+
-+
-+static int __devinit nforce2_probe(struct pci_dev *dev, const struct pci_device_id *id)
-+{
-+ struct nforce2_smbus *smbuses;
-+ int res1, res2;
-+
-+ /* we support 2 SMBus adapters */
-+ if (!(smbuses = (void *)kmalloc(2*sizeof(struct nforce2_smbus),
-+ GFP_KERNEL)))
-+ return -ENOMEM;
-+ memset (smbuses, 0, 2*sizeof(struct nforce2_smbus));
-+ pci_set_drvdata(dev, smbuses);
-+
-+ /* SMBus adapter 1 */
-+ res1 = nforce2_probe_smb (dev, NFORCE_PCI_SMB1, &smbuses[0], "SMB1");
-+ if (res1 < 0) {
-+ printk (KERN_ERR "i2c-nforce2.o: Error probing SMB1.\n");
-+ smbuses[0].base = 0; /* to have a check value */
-+ }
-+ res2 = nforce2_probe_smb (dev, NFORCE_PCI_SMB2, &smbuses[1], "SMB2");
-+ if (res2 < 0) {
-+ printk (KERN_ERR "i2c-nforce2.o: Error probing SMB2.\n");
-+ smbuses[1].base = 0; /* to have a check value */
-+ }
-+ if ((res1 < 0) && (res2 < 0)) {
-+ /* we did not find even one of the SMBuses, so we give up */
-+ kfree(smbuses);
-+ return -ENODEV;
-+ }
-+
-+ return 0;
-+}
-+
-+
-+static void __devexit nforce2_remove(struct pci_dev *dev)
-+{
-+ struct nforce2_smbus *smbuses = (void*) pci_get_drvdata(dev);
-+
-+ if (smbuses[0].base) {
-+ i2c_del_adapter(&smbuses[0].adapter);
-+ release_region(smbuses[0].base, smbuses[0].size);
-+ }
-+ if (smbuses[1].base) {
-+ i2c_del_adapter(&smbuses[1].adapter);
-+ release_region(smbuses[1].base, smbuses[1].size);
-+ }
-+ kfree(smbuses);
-+}
-+
-+static struct pci_driver nforce2_driver = {
-+ .name = "nForce2 SMBus",
-+ .id_table = nforce2_ids,
-+ .probe = nforce2_probe,
-+ .remove = __devexit_p(nforce2_remove),
-+};
-+
-+int __init nforce2_init(void)
-+{
-+ printk(KERN_INFO "i2c-nforce2.o version %s (%s)\n", LM_VERSION, LM_DATE);
-+ return pci_module_init(&nforce2_driver);
-+}
-+
-+void __exit nforce2_exit(void)
-+{
-+ pci_unregister_driver(&nforce2_driver);
-+}
-+
-+module_init(nforce2_init);
-+module_exit(nforce2_exit);
-+
---- linux-old/drivers/i2c/i2c-piix4.c Thu Jan 1 00:00:00 1970
-+++ linux/drivers/i2c/i2c-piix4.c Mon Dec 13 20:18:42 2004
-@@ -0,0 +1,549 @@
-+/*
-+ piix4.c - Part of lm_sensors, Linux kernel modules for hardware
-+ monitoring
-+ Copyright (c) 1998 - 2002 Frodo Looijaard <frodol@dds.nl> and
-+ Philip Edelbrock <phil@netroedge.com>
-+
-+ 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., 675 Mass Ave, Cambridge, MA 02139, USA.
-+*/
-+
-+/*
-+ Supports:
-+ Intel PIIX4, 440MX
-+ Serverworks OSB4, CSB5, CSB6
-+ SMSC Victory66
-+
-+ Note: we assume there can only be one device, with one SMBus interface.
-+*/
-+
-+#include <linux/version.h>
-+#include <linux/module.h>
-+#include <linux/config.h>
-+#include <linux/pci.h>
-+#include <linux/kernel.h>
-+#include <linux/stddef.h>
-+#include <linux/sched.h>
-+#include <linux/ioport.h>
-+#include <linux/i2c.h>
-+#include <linux/init.h>
-+#include <linux/apm_bios.h>
-+#include <asm/io.h>
-+#define LM_DATE "20041007"
-+#define LM_VERSION "2.8.8"
-+
-+
-+struct sd {
-+ const unsigned short mfr;
-+ const unsigned short dev;
-+ const unsigned char fn;
-+ const char *name;
-+};
-+
-+/* PIIX4 SMBus address offsets */
-+#define SMBHSTSTS (0 + piix4_smba)
-+#define SMBHSLVSTS (1 + piix4_smba)
-+#define SMBHSTCNT (2 + piix4_smba)
-+#define SMBHSTCMD (3 + piix4_smba)
-+#define SMBHSTADD (4 + piix4_smba)
-+#define SMBHSTDAT0 (5 + piix4_smba)
-+#define SMBHSTDAT1 (6 + piix4_smba)
-+#define SMBBLKDAT (7 + piix4_smba)
-+#define SMBSLVCNT (8 + piix4_smba)
-+#define SMBSHDWCMD (9 + piix4_smba)
-+#define SMBSLVEVT (0xA + piix4_smba)
-+#define SMBSLVDAT (0xC + piix4_smba)
-+
-+/* count for request_region */
-+#define SMBIOSIZE 8
-+
-+/* PCI Address Constants */
-+#define SMBBA 0x090
-+#define SMBHSTCFG 0x0D2
-+#define SMBSLVC 0x0D3
-+#define SMBSHDW1 0x0D4
-+#define SMBSHDW2 0x0D5
-+#define SMBREV 0x0D6
-+
-+/* Other settings */
-+#define MAX_TIMEOUT 500
-+#define ENABLE_INT9 0
-+
-+/* PIIX4 constants */
-+#define PIIX4_QUICK 0x00
-+#define PIIX4_BYTE 0x04
-+#define PIIX4_BYTE_DATA 0x08
-+#define PIIX4_WORD_DATA 0x0C
-+#define PIIX4_BLOCK_DATA 0x14
-+
-+/* insmod parameters */
-+
-+/* If force is set to anything different from 0, we forcibly enable the
-+ PIIX4. DANGEROUS! */
-+static int force = 0;
-+MODULE_PARM(force, "i");
-+MODULE_PARM_DESC(force, "Forcibly enable the PIIX4. DANGEROUS!");
-+
-+/* If force_addr is set to anything different from 0, we forcibly enable
-+ the PIIX4 at the given address. VERY DANGEROUS! */
-+static int force_addr = 0;
-+MODULE_PARM(force_addr, "i");
-+MODULE_PARM_DESC(force_addr,
-+ "Forcibly enable the PIIX4 at the given address. "
-+ "EXTREMELY DANGEROUS!");
-+
-+static int fix_hstcfg = 0;
-+MODULE_PARM(fix_hstcfg, "i");
-+MODULE_PARM_DESC(fix_hstcfg,
-+ "Fix config register. Needed on some boards (Force CPCI735).");
-+
-+static int piix4_transaction(void);
-+
-+static unsigned short piix4_smba = 0;
-+
-+#ifdef CONFIG_X86
-+/*
-+ * Get DMI information.
-+ */
-+
-+static int __devinit ibm_dmi_probe(void)
-+{
-+ extern int is_unsafe_smbus;
-+ return is_unsafe_smbus;
-+}
-+#endif
-+
-+/* Detect whether a PIIX4 can be found, and initialize it, where necessary.
-+ Note the differences between kernels with the old PCI BIOS interface and
-+ newer kernels with the real PCI interface. In compat.h some things are
-+ defined to make the transition easier. */
-+static int __devinit piix4_setup(struct pci_dev *PIIX4_dev,
-+ const struct pci_device_id *id)
-+{
-+ unsigned char temp;
-+
-+ /* match up the function */
-+ if (PCI_FUNC(PIIX4_dev->devfn) != id->driver_data)
-+ return -ENODEV;
-+
-+ printk(KERN_INFO "Found %s device\n", PIIX4_dev->name);
-+
-+#ifdef CONFIG_X86
-+ if(ibm_dmi_probe() && PIIX4_dev->vendor == PCI_VENDOR_ID_INTEL) {
-+ printk(KERN_ERR "i2c-piix4.o: IBM Laptop detected; this module "
-+ "may corrupt your serial eeprom! Refusing to load "
-+ "module!\n");
-+ return -EPERM;
-+ }
-+#endif
-+
-+ /* Determine the address of the SMBus areas */
-+ if (force_addr) {
-+ piix4_smba = force_addr & 0xfff0;
-+ force = 0;
-+ } else {
-+ pci_read_config_word(PIIX4_dev, SMBBA, &piix4_smba);
-+ piix4_smba &= 0xfff0;
-+ if(piix4_smba == 0) {
-+ printk(KERN_ERR "i2c-piix4.o: SMB base address "
-+ "uninitialized - upgrade BIOS or use "
-+ "force_addr=0xaddr\n");
-+ return -ENODEV;
-+ }
-+ }
-+
-+ if (!request_region(piix4_smba, SMBIOSIZE, "piix4-smbus")) {
-+ printk(KERN_ERR "i2c-piix4.o: SMB region 0x%x already in "
-+ "use!\n", piix4_smba);
-+ return -ENODEV;
-+ }
-+
-+ pci_read_config_byte(PIIX4_dev, SMBHSTCFG, &temp);
-+
-+ /* Some BIOS will set up the chipset incorrectly and leave a register
-+ in an undefined state (causing I2C to act very strangely). */
-+ if (temp & 0x02) {
-+ if (fix_hstcfg) {
-+ printk(KERN_INFO "i2c-piix4.o: Working around buggy "
-+ "BIOS (I2C)\n");
-+ temp &= 0xfd;
-+ pci_write_config_byte(PIIX4_dev, SMBHSTCFG, temp);
-+ } else {
-+ printk(KERN_INFO "i2c-piix4.o: Unusual config register "
-+ "value\n");
-+ printk(KERN_INFO "i2c-piix4.o: Try using fix_hstcfg=1 "
-+ "if you experience problems\n");
-+ }
-+ }
-+
-+ /* If force_addr is set, we program the new address here. Just to make
-+ sure, we disable the PIIX4 first. */
-+ if (force_addr) {
-+ pci_write_config_byte(PIIX4_dev, SMBHSTCFG, temp & 0xfe);
-+ pci_write_config_word(PIIX4_dev, SMBBA, piix4_smba);
-+ pci_write_config_byte(PIIX4_dev, SMBHSTCFG, temp | 0x01);
-+ printk(KERN_INFO "i2c-piix4.o: WARNING: SMBus interface set to "
-+ "new address %04x!\n", piix4_smba);
-+ } else if ((temp & 1) == 0) {
-+ if (force) {
-+ /* This should never need to be done, but has been
-+ * noted that many Dell machines have the SMBus
-+ * interface on the PIIX4 disabled!? NOTE: This assumes
-+ * I/O space and other allocations WERE done by the
-+ * Bios! Don't complain if your hardware does weird
-+ * things after enabling this. :') Check for Bios
-+ * updates before resorting to this.
-+ */
-+ pci_write_config_byte(PIIX4_dev, SMBHSTCFG,
-+ temp | 1);
-+ printk(KERN_NOTICE "i2c-piix4.o: WARNING: SMBus "
-+ "interface has been FORCEFULLY ENABLED!\n");
-+ } else {
-+ printk(KERN_ERR "i2c-piix4.o: Host SMBus controller "
-+ "not enabled!\n");
-+ release_region(piix4_smba, SMBIOSIZE);
-+ piix4_smba = 0;
-+ return -ENODEV;
-+ }
-+ }
-+
-+#ifdef DEBUG
-+ if ((temp & 0x0E) == 8)
-+ printk(KERN_DEBUG "i2c-piix4.o: Using Interrupt 9 for "
-+ "SMBus.\n");
-+ else if ((temp & 0x0E) == 0)
-+ printk(KERN_DEBUG "i2c-piix4.o: Using Interrupt SMI# "
-+ "for SMBus.\n");
-+ else
-+ printk(KERN_ERR "i2c-piix4.o: Illegal Interrupt configuration "
-+ "(or code out of date)!\n");
-+
-+ pci_read_config_byte(PIIX4_dev, SMBREV, &temp);
-+ printk(KERN_DEBUG "i2c-piix4.o: SMBREV = 0x%X\n", temp);
-+ printk(KERN_DEBUG "i2c-piix4.o: SMBA = 0x%X\n", piix4_smba);
-+#endif /* DEBUG */
-+
-+ return 0;
-+}
-+
-+
-+/* Another internally used function */
-+int piix4_transaction(void)
-+{
-+ int temp;
-+ int result = 0;
-+ int timeout = 0;
-+
-+#ifdef DEBUG
-+ printk
-+ (KERN_DEBUG "i2c-piix4.o: Transaction (pre): CNT=%02x, CMD=%02x, ADD=%02x, DAT0=%02x, "
-+ "DAT1=%02x\n", inb_p(SMBHSTCNT), inb_p(SMBHSTCMD),
-+ inb_p(SMBHSTADD), inb_p(SMBHSTDAT0), inb_p(SMBHSTDAT1));
-+#endif
-+
-+ /* Make sure the SMBus host is ready to start transmitting */
-+ if ((temp = inb_p(SMBHSTSTS)) != 0x00) {
-+#ifdef DEBUG
-+ printk(KERN_DEBUG "i2c-piix4.o: SMBus busy (%02x). Resetting... \n",
-+ temp);
-+#endif
-+ outb_p(temp, SMBHSTSTS);
-+ if ((temp = inb_p(SMBHSTSTS)) != 0x00) {
-+#ifdef DEBUG
-+ printk(KERN_ERR "i2c-piix4.o: Failed! (%02x)\n", temp);
-+#endif
-+ return -1;
-+ } else {
-+#ifdef DEBUG
-+ printk(KERN_DEBUG "i2c-piix4.o: Successfull!\n");
-+#endif
-+ }
-+ }
-+
-+ /* start the transaction by setting bit 6 */
-+ outb_p(inb(SMBHSTCNT) | 0x040, SMBHSTCNT);
-+
-+ /* We will always wait for a fraction of a second! (See PIIX4 docs errata) */
-+ do {
-+ i2c_delay(1);
-+ temp = inb_p(SMBHSTSTS);
-+ } while ((temp & 0x01) && (timeout++ < MAX_TIMEOUT));
-+
-+#ifdef DEBUG
-+ /* If the SMBus is still busy, we give up */
-+ if (timeout >= MAX_TIMEOUT) {
-+ printk(KERN_ERR "i2c-piix4.o: SMBus Timeout!\n");
-+ result = -1;
-+ }
-+#endif
-+
-+ if (temp & 0x10) {
-+ result = -1;
-+#ifdef DEBUG
-+ printk(KERN_ERR "i2c-piix4.o: Error: Failed bus transaction\n");
-+#endif
-+ }
-+
-+ if (temp & 0x08) {
-+ result = -1;
-+ printk
-+ (KERN_ERR "i2c-piix4.o: Bus collision! SMBus may be locked until next hard\n"
-+ "reset. (sorry!)\n");
-+ /* Clock stops and slave is stuck in mid-transmission */
-+ }
-+
-+ if (temp & 0x04) {
-+ result = -1;
-+#ifdef DEBUG
-+ printk(KERN_ERR "i2c-piix4.o: Error: no response!\n");
-+#endif
-+ }
-+
-+ if (inb_p(SMBHSTSTS) != 0x00)
-+ outb_p(inb(SMBHSTSTS), SMBHSTSTS);
-+
-+#ifdef DEBUG
-+ if ((temp = inb_p(SMBHSTSTS)) != 0x00) {
-+ printk
-+ (KERN_ERR "i2c-piix4.o: Failed reset at end of transaction (%02x)\n",
-+ temp);
-+ }
-+ printk
-+ (KERN_DEBUG "i2c-piix4.o: Transaction (post): CNT=%02x, CMD=%02x, ADD=%02x, "
-+ "DAT0=%02x, DAT1=%02x\n", inb_p(SMBHSTCNT), inb_p(SMBHSTCMD),
-+ inb_p(SMBHSTADD), inb_p(SMBHSTDAT0), inb_p(SMBHSTDAT1));
-+#endif
-+ return result;
-+}
-+
-+/* Return -1 on error. */
-+s32 piix4_access(struct i2c_adapter * adap, u16 addr,
-+ unsigned short flags, char read_write,
-+ u8 command, int size, union i2c_smbus_data * data)
-+{
-+ int i, len;
-+
-+ switch (size) {
-+ case I2C_SMBUS_QUICK:
-+ outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),
-+ SMBHSTADD);
-+ size = PIIX4_QUICK;
-+ break;
-+ case I2C_SMBUS_BYTE:
-+ outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),
-+ SMBHSTADD);
-+ if (read_write == I2C_SMBUS_WRITE)
-+ outb_p(command, SMBHSTCMD);
-+ size = PIIX4_BYTE;
-+ break;
-+ case I2C_SMBUS_BYTE_DATA:
-+ outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),
-+ SMBHSTADD);
-+ outb_p(command, SMBHSTCMD);
-+ if (read_write == I2C_SMBUS_WRITE)
-+ outb_p(data->byte, SMBHSTDAT0);
-+ size = PIIX4_BYTE_DATA;
-+ break;
-+ case I2C_SMBUS_WORD_DATA:
-+ outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),
-+ SMBHSTADD);
-+ outb_p(command, SMBHSTCMD);
-+ if (read_write == I2C_SMBUS_WRITE) {
-+ outb_p(data->word & 0xff, SMBHSTDAT0);
-+ outb_p((data->word & 0xff00) >> 8, SMBHSTDAT1);
-+ }
-+ size = PIIX4_WORD_DATA;
-+ break;
-+ case I2C_SMBUS_BLOCK_DATA:
-+ outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),
-+ SMBHSTADD);
-+ outb_p(command, SMBHSTCMD);
-+ if (read_write == I2C_SMBUS_WRITE) {
-+ len = data->block[0];
-+ if (len < 0)
-+ len = 0;
-+ if (len > 32)
-+ len = 32;
-+ outb_p(len, SMBHSTDAT0);
-+ i = inb_p(SMBHSTCNT); /* Reset SMBBLKDAT */
-+ for (i = 1; i <= len; i++)
-+ outb_p(data->block[i], SMBBLKDAT);
-+ }
-+ size = PIIX4_BLOCK_DATA;
-+ break;
-+ default:
-+ printk
-+ (KERN_WARNING "i2c-piix4.o: Unsupported transaction %d\n", size);
-+ return -1;
-+ }
-+
-+ outb_p((size & 0x1C) + (ENABLE_INT9 & 1), SMBHSTCNT);
-+
-+ if (piix4_transaction()) /* Error in transaction */
-+ return -1;
-+
-+ if ((read_write == I2C_SMBUS_WRITE) || (size == PIIX4_QUICK))
-+ return 0;
-+
-+
-+ switch (size) {
-+ case PIIX4_BYTE: /* Where is the result put? I assume here it is in
-+ SMBHSTDAT0 but it might just as well be in the
-+ SMBHSTCMD. No clue in the docs */
-+
-+ data->byte = inb_p(SMBHSTDAT0);
-+ break;
-+ case PIIX4_BYTE_DATA:
-+ data->byte = inb_p(SMBHSTDAT0);
-+ break;
-+ case PIIX4_WORD_DATA:
-+ data->word = inb_p(SMBHSTDAT0) + (inb_p(SMBHSTDAT1) << 8);
-+ break;
-+ case PIIX4_BLOCK_DATA:
-+ data->block[0] = inb_p(SMBHSTDAT0);
-+ i = inb_p(SMBHSTCNT); /* Reset SMBBLKDAT */
-+ for (i = 1; i <= data->block[0]; i++)
-+ data->block[i] = inb_p(SMBBLKDAT);
-+ break;
-+ }
-+ return 0;
-+}
-+
-+
-+u32 piix4_func(struct i2c_adapter *adapter)
-+{
-+ return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
-+ I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
-+ I2C_FUNC_SMBUS_BLOCK_DATA;
-+}
-+
-+static struct i2c_algorithm smbus_algorithm = {
-+ .name = "Non-I2C SMBus adapter",
-+ .id = I2C_ALGO_SMBUS,
-+ .smbus_xfer = piix4_access,
-+ .functionality = piix4_func,
-+};
-+
-+static struct i2c_adapter piix4_adapter = {
-+ .owner = THIS_MODULE,
-+ .name = "unset",
-+ .id = I2C_ALGO_SMBUS | I2C_HW_SMBUS_PIIX4,
-+ .algo = &smbus_algorithm,
-+};
-+
-+#ifndef PCI_DEVICE_ID_SERVERWORKS_CSB6
-+#define PCI_DEVICE_ID_SERVERWORKS_CSB6 0x0203
-+#endif
-+
-+static struct pci_device_id piix4_ids[] __devinitdata = {
-+ {
-+ .vendor = PCI_VENDOR_ID_INTEL,
-+ .device = PCI_DEVICE_ID_INTEL_82371AB_3,
-+ .subvendor = PCI_ANY_ID,
-+ .subdevice = PCI_ANY_ID,
-+ .driver_data = 3
-+ },
-+ {
-+ .vendor = PCI_VENDOR_ID_SERVERWORKS,
-+ .device = PCI_DEVICE_ID_SERVERWORKS_OSB4,
-+ .subvendor = PCI_ANY_ID,
-+ .subdevice = PCI_ANY_ID,
-+ .driver_data = 0,
-+ },
-+ {
-+ .vendor = PCI_VENDOR_ID_SERVERWORKS,
-+ .device = PCI_DEVICE_ID_SERVERWORKS_CSB5,
-+ .subvendor = PCI_ANY_ID,
-+ .subdevice = PCI_ANY_ID,
-+ .driver_data = 0,
-+ },
-+ {
-+ .vendor = PCI_VENDOR_ID_SERVERWORKS,
-+ .device = PCI_DEVICE_ID_SERVERWORKS_CSB6,
-+ .subvendor = PCI_ANY_ID,
-+ .subdevice = PCI_ANY_ID,
-+ .driver_data = 0,
-+ },
-+ {
-+ .vendor = PCI_VENDOR_ID_INTEL,
-+ .device = PCI_DEVICE_ID_INTEL_82443MX_3,
-+ .subvendor = PCI_ANY_ID,
-+ .subdevice = PCI_ANY_ID,
-+ .driver_data = 3,
-+ },
-+ {
-+ .vendor = PCI_VENDOR_ID_EFAR,
-+ .device = PCI_DEVICE_ID_EFAR_SLC90E66_3,
-+ .subvendor = PCI_ANY_ID,
-+ .subdevice = PCI_ANY_ID,
-+ .driver_data = 0,
-+ },
-+ { 0, }
-+};
-+
-+static int __devinit piix4_probe(struct pci_dev *dev,
-+ const struct pci_device_id *id)
-+{
-+ int retval;
-+
-+ retval = piix4_setup(dev, id);
-+ if (retval)
-+ return retval;
-+
-+ sprintf(piix4_adapter.name, "SMBus PIIX4 adapter at %04x",
-+ piix4_smba);
-+
-+ if ((retval = i2c_add_adapter(&piix4_adapter))) {
-+ printk(KERN_ERR "i2c-piix4.o: Couldn't register adapter!\n");
-+ release_region(piix4_smba, SMBIOSIZE);
-+ piix4_smba = 0;
-+ }
-+
-+ return retval;
-+}
-+
-+static void __devexit piix4_remove(struct pci_dev *dev)
-+{
-+ if (piix4_smba) {
-+ i2c_del_adapter(&piix4_adapter);
-+ release_region(piix4_smba, SMBIOSIZE);
-+ piix4_smba = 0;
-+ }
-+}
-+
-+static struct pci_driver piix4_driver = {
-+ .name = "piix4 smbus",
-+ .id_table = piix4_ids,
-+ .probe = piix4_probe,
-+ .remove = __devexit_p(piix4_remove),
-+};
-+
-+static int __init i2c_piix4_init(void)
-+{
-+ printk("i2c-piix4.o version %s (%s)\n", LM_VERSION, LM_DATE);
-+ return pci_module_init(&piix4_driver);
-+}
-+
-+static void __exit i2c_piix4_exit(void)
-+{
-+ pci_unregister_driver(&piix4_driver);
-+}
-+
-+MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl> and "
-+ "Philip Edelbrock <phil@netroedge.com>");
-+MODULE_DESCRIPTION("PIIX4 SMBus driver");
-+MODULE_LICENSE("GPL");
-+
-+module_init(i2c_piix4_init);
-+module_exit(i2c_piix4_exit);
---- linux-old/drivers/i2c/i2c-savage4.c Thu Jan 1 00:00:00 1970
-+++ linux/drivers/i2c/i2c-savage4.c Mon Dec 13 20:18:42 2004
-@@ -0,0 +1,229 @@
-+/*
-+ i2c-savage4.c - Part of lm_sensors, Linux kernel modules for hardware
-+ monitoring
-+ Copyright (C) 1998-2003 The LM Sensors Team
-+ Alexander Wold <awold@bigfoot.com>
-+ Mark D. Studebaker <mdsxyz123@yahoo.com>
-+
-+ Based on i2c-voodoo3.c.
-+
-+ 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., 675 Mass Ave, Cambridge, MA 02139, USA.
-+*/
-+
-+/* This interfaces to the I2C bus of the Savage4 to gain access to
-+ the BT869 and possibly other I2C devices. The DDC bus is not
-+ yet supported because its register is not memory-mapped.
-+ However we leave the DDC code here, commented out, to make
-+ it easier to add later.
-+*/
-+
-+#include <linux/module.h>
-+#include <linux/pci.h>
-+#include <linux/i2c.h>
-+#include <linux/i2c-algo-bit.h>
-+#include <linux/init.h>
-+#include <asm/io.h>
-+#include <asm/param.h> /* for HZ */
-+#define LM_DATE "20041007"
-+#define LM_VERSION "2.8.8"
-+
-+/* 3DFX defines */
-+/* #define PCI_VENDOR_ID_S3 0x5333 */
-+#define PCI_CHIP_SAVAGE3D 0x8A20
-+#define PCI_CHIP_SAVAGE3D_MV 0x8A21
-+#define PCI_CHIP_SAVAGE4 0x8A22
-+#define PCI_CHIP_SAVAGE2000 0x9102
-+#define PCI_CHIP_PROSAVAGE_PM 0x8A25
-+#define PCI_CHIP_PROSAVAGE_KM 0x8A26
-+#define PCI_CHIP_SAVAGE_MX_MV 0x8c10
-+#define PCI_CHIP_SAVAGE_MX 0x8c11
-+#define PCI_CHIP_SAVAGE_IX_MV 0x8c12
-+#define PCI_CHIP_SAVAGE_IX 0x8c13
-+
-+#define REG 0xff20 /* Serial Port 1 Register */
-+
-+/* bit locations in the register */
-+//#define DDC_ENAB 0x00040000
-+//#define DDC_SCL_OUT 0x00080000
-+//#define DDC_SDA_OUT 0x00100000
-+//#define DDC_SCL_IN 0x00200000
-+//#define DDC_SDA_IN 0x00400000
-+#define I2C_ENAB 0x00000020
-+#define I2C_SCL_OUT 0x00000001
-+#define I2C_SDA_OUT 0x00000002
-+#define I2C_SCL_IN 0x00000008
-+#define I2C_SDA_IN 0x00000010
-+
-+/* initialization states */
-+#define INIT2 0x20
-+/* #define INIT3 0x4 */
-+
-+/* delays */
-+#define CYCLE_DELAY 10
-+#define TIMEOUT (HZ / 2)
-+
-+
-+static void config_s4(struct pci_dev *dev);
-+
-+static unsigned long ioaddr;
-+
-+/* The sav GPIO registers don't have individual masks for each bit
-+ so we always have to read before writing. */
-+
-+static void bit_savi2c_setscl(void *data, int val)
-+{
-+ unsigned int r;
-+ r = readl(ioaddr + REG);
-+ if(val)
-+ r |= I2C_SCL_OUT;
-+ else
-+ r &= ~I2C_SCL_OUT;
-+ writel(r, ioaddr + REG);
-+ readl(ioaddr + REG); /* flush posted write */
-+}
-+
-+static void bit_savi2c_setsda(void *data, int val)
-+{
-+ unsigned int r;
-+ r = readl(ioaddr + REG);
-+ if(val)
-+ r |= I2C_SDA_OUT;
-+ else
-+ r &= ~I2C_SDA_OUT;
-+ writel(r, ioaddr + REG);
-+ readl(ioaddr + REG); /* flush posted write */
-+}
-+
-+/* The GPIO pins are open drain, so the pins always remain outputs.
-+ We rely on the i2c-algo-bit routines to set the pins high before
-+ reading the input from other chips. */
-+
-+static int bit_savi2c_getscl(void *data)
-+{
-+ return (0 != (readl(ioaddr + REG) & I2C_SCL_IN));
-+}
-+
-+static int bit_savi2c_getsda(void *data)
-+{
-+ return (0 != (readl(ioaddr + REG) & I2C_SDA_IN));
-+}
-+
-+/* Configures the chip */
-+
-+void config_s4(struct pci_dev *dev)
-+{
-+ unsigned int cadr;
-+
-+ /* map memory */
-+ cadr = dev->resource[0].start;
-+ cadr &= PCI_BASE_ADDRESS_MEM_MASK;
-+ ioaddr = (unsigned long)ioremap_nocache(cadr, 0x0080000);
-+ if(ioaddr) {
-+// writel(0x8160, ioaddr + REG2);
-+ writel(0x00000020, ioaddr + REG);
-+ printk("i2c-savage4: Using Savage4 at 0x%lx\n", ioaddr);
-+ }
-+}
-+
-+
-+static struct i2c_algo_bit_data sav_i2c_bit_data = {
-+ .setsda = bit_savi2c_setsda,
-+ .setscl = bit_savi2c_setscl,
-+ .getsda = bit_savi2c_getsda,
-+ .getscl = bit_savi2c_getscl,
-+ .udelay = CYCLE_DELAY,
-+ .mdelay = CYCLE_DELAY,
-+ .timeout = TIMEOUT
-+};
-+
-+static struct i2c_adapter savage4_i2c_adapter = {
-+ .owner = THIS_MODULE,
-+ .name = "I2C Savage4 adapter",
-+ .id = I2C_HW_B_SAVG,
-+ .algo_data = &sav_i2c_bit_data,
-+};
-+
-+static struct pci_device_id savage4_ids[] __devinitdata = {
-+ {
-+ .vendor = PCI_VENDOR_ID_S3,
-+ .device = PCI_CHIP_SAVAGE4,
-+ .subvendor = PCI_ANY_ID,
-+ .subdevice = PCI_ANY_ID,
-+ },
-+ {
-+ .vendor = PCI_VENDOR_ID_S3,
-+ .device = PCI_CHIP_SAVAGE2000,
-+ .subvendor = PCI_ANY_ID,
-+ .subdevice = PCI_ANY_ID,
-+ },
-+ { 0, }
-+};
-+
-+static int __devinit savage4_probe(struct pci_dev *dev, const struct pci_device_id *id)
-+{
-+ config_s4(dev);
-+ return i2c_bit_add_bus(&savage4_i2c_adapter);
-+}
-+
-+static void __devexit savage4_remove(struct pci_dev *dev)
-+{
-+ i2c_bit_del_bus(&savage4_i2c_adapter);
-+}
-+
-+
-+/* Don't register driver to avoid driver conflicts */
-+/*
-+static struct pci_driver savage4_driver = {
-+ .name = "savage4 smbus",
-+ .id_table = savage4_ids,
-+ .probe = savage4_probe,
-+ .remove = __devexit_p(savage4_remove),
-+};
-+*/
-+
-+static int __init i2c_savage4_init(void)
-+{
-+ struct pci_dev *dev;
-+ const struct pci_device_id *id;
-+
-+ printk("i2c-savage4.o version %s (%s)\n", LM_VERSION, LM_DATE);
-+/*
-+ return pci_module_init(&savage4_driver);
-+*/
-+ pci_for_each_dev(dev) {
-+ id = pci_match_device(savage4_ids, dev);
-+ if(id)
-+ if(savage4_probe(dev, id) >= 0)
-+ return 0;
-+ }
-+ return -ENODEV;
-+}
-+
-+static void __exit i2c_savage4_exit(void)
-+{
-+/*
-+ pci_unregister_driver(&savage4_driver);
-+*/
-+ savage4_remove(NULL);
-+ iounmap((void *)ioaddr);
-+}
-+
-+MODULE_AUTHOR("Alexander Wold <awold@bigfoot.com> "
-+ "and Mark D. Studebaker <mdsxyz123@yahoo.com>");
-+MODULE_DESCRIPTION("Savage4 I2C/SMBus driver");
-+MODULE_LICENSE("GPL");
-+
-+module_init(i2c_savage4_init);
-+module_exit(i2c_savage4_exit);
---- linux-old/drivers/i2c/i2c-sis5595.c Thu Jan 1 00:00:00 1970
-+++ linux/drivers/i2c/i2c-sis5595.c Mon Dec 13 20:18:42 2004
-@@ -0,0 +1,481 @@
-+/*
-+ sis5595.c - Part of lm_sensors, Linux kernel modules for hardware
-+ monitoring
-+ Copyright (c) 1998, 1999 Frodo Looijaard <frodol@dds.nl> and
-+ Philip Edelbrock <phil@netroedge.com>
-+
-+ 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., 675 Mass Ave, Cambridge, MA 02139, USA.
-+*/
-+
-+/* Note: we assume there can only be one SIS5595 with one SMBus interface */
-+
-+/*
-+ Note: all have mfr. ID 0x1039.
-+ SUPPORTED PCI ID
-+ 5595 0008
-+
-+ Note: these chips contain a 0008 device which is incompatible with the
-+ 5595. We recognize these by the presence of the listed
-+ "blacklist" PCI ID and refuse to load.
-+
-+ NOT SUPPORTED PCI ID BLACKLIST PCI ID
-+ 540 0008 0540
-+ 550 0008 0550
-+ 5513 0008 5511
-+ 5581 0008 5597
-+ 5582 0008 5597
-+ 5597 0008 5597
-+ 5598 0008 5597/5598
-+ 630 0008 0630
-+ 645 0008 0645
-+ 646 0008 0646
-+ 648 0008 0648
-+ 650 0008 0650
-+ 651 0008 0651
-+ 730 0008 0730
-+ 735 0008 0735
-+ 745 0008 0745
-+ 746 0008 0746
-+*/
-+
-+/* TO DO:
-+ * Add Block Transfers (ugly, but supported by the adapter)
-+ * Add adapter resets
-+ */
-+
-+#include <linux/module.h>
-+#include <linux/pci.h>
-+#include <linux/kernel.h>
-+#include <linux/stddef.h>
-+#include <linux/sched.h>
-+#include <linux/ioport.h>
-+#include <linux/i2c.h>
-+#include <linux/init.h>
-+#include <asm/io.h>
-+#define LM_DATE "20041007"
-+#define LM_VERSION "2.8.8"
-+
-+MODULE_LICENSE("GPL");
-+
-+static int blacklist[] = {
-+ PCI_DEVICE_ID_SI_540,
-+ PCI_DEVICE_ID_SI_550,
-+ PCI_DEVICE_ID_SI_630,
-+ PCI_DEVICE_ID_SI_730,
-+ PCI_DEVICE_ID_SI_5511, /* 5513 chip has the 0008 device but
-+ that ID shows up in other chips so we
-+ use the 5511 ID for recognition */
-+ PCI_DEVICE_ID_SI_5597,
-+ PCI_DEVICE_ID_SI_5598,
-+ 0x645,
-+ 0x646,
-+ 0x648,
-+ 0x650,
-+ 0x651,
-+ 0x735,
-+ 0x745,
-+ 0x746,
-+ 0 };
-+
-+/* Length of ISA address segment */
-+#define SIS5595_EXTENT 8
-+/* SIS5595 SMBus registers */
-+#define SMB_STS_LO 0x00
-+#define SMB_STS_HI 0x01
-+#define SMB_CTL_LO 0x02
-+#define SMB_CTL_HI 0x03
-+#define SMB_ADDR 0x04
-+#define SMB_CMD 0x05
-+#define SMB_PCNT 0x06
-+#define SMB_CNT 0x07
-+#define SMB_BYTE 0x08
-+#define SMB_DEV 0x10
-+#define SMB_DB0 0x11
-+#define SMB_DB1 0x12
-+#define SMB_HAA 0x13
-+
-+/* PCI Address Constants */
-+#define SMB_INDEX 0x38
-+#define SMB_DAT 0x39
-+#define SIS5595_ENABLE_REG 0x40
-+#define ACPI_BASE 0x90
-+
-+/* Other settings */
-+#define MAX_TIMEOUT 500
-+
-+/* SIS5595 constants */
-+#define SIS5595_QUICK 0x00
-+#define SIS5595_BYTE 0x02
-+#define SIS5595_BYTE_DATA 0x04
-+#define SIS5595_WORD_DATA 0x06
-+#define SIS5595_PROC_CALL 0x08
-+#define SIS5595_BLOCK_DATA 0x0A
-+
-+/* insmod parameters */
-+
-+/* If force_addr is set to anything different from 0, we forcibly enable
-+ the device at the given address. */
-+static int force_addr = 0;
-+MODULE_PARM(force_addr, "i");
-+MODULE_PARM_DESC(force_addr,
-+ "Initialize the base address of the i2c controller");
-+
-+static int sis5595_transaction(void);
-+
-+static unsigned short sis5595_base = 0;
-+
-+static u8 sis5595_read(u8 reg)
-+{
-+ outb(reg, sis5595_base + SMB_INDEX);
-+ return inb(sis5595_base + SMB_DAT);
-+}
-+
-+static void sis5595_write(u8 reg, u8 data)
-+{
-+ outb(reg, sis5595_base + SMB_INDEX);
-+ outb(data, sis5595_base + SMB_DAT);
-+}
-+
-+
-+/* Detect whether a SIS5595 can be found, and initialize it, where necessary.
-+ Note the differences between kernels with the old PCI BIOS interface and
-+ newer kernels with the real PCI interface. In compat.h some things are
-+ defined to make the transition easier. */
-+int sis5595_setup(struct pci_dev *SIS5595_dev)
-+{
-+ u16 a;
-+ u8 val;
-+ int *i;
-+
-+ /* Look for imposters */
-+ for(i = blacklist; *i != 0; i++) {
-+ if (pci_find_device(PCI_VENDOR_ID_SI, *i, NULL)) {
-+ printk("i2c-sis5595.o: Error: Looked for SIS5595 but found unsupported device %.4X\n", *i);
-+ return -ENODEV;
-+ }
-+ }
-+
-+/* Determine the address of the SMBus areas */
-+ pci_read_config_word(SIS5595_dev, ACPI_BASE, &sis5595_base);
-+ if(sis5595_base == 0 && force_addr == 0) {
-+ printk("i2c-sis5595.o: ACPI base address uninitialized - upgrade BIOS or use force_addr=0xaddr\n");
-+ return -ENODEV;
-+ }
-+
-+ if(force_addr)
-+ sis5595_base = force_addr & ~(SIS5595_EXTENT - 1);
-+#ifdef DEBUG
-+ printk("ACPI Base address: %04x\n", sis5595_base);
-+#endif
-+ /* NB: We grab just the two SMBus registers here, but this may still
-+ * interfere with ACPI :-( */
-+ if (check_region(sis5595_base + SMB_INDEX, 2)) {
-+ printk
-+ ("i2c-sis5595.o: SMBus registers 0x%04x-0x%04x already in use!\n",
-+ sis5595_base + SMB_INDEX,
-+ sis5595_base + SMB_INDEX + 1);
-+ return -ENODEV;
-+ }
-+
-+ if(force_addr) {
-+ printk("i2c-sis5595.o: forcing ISA address 0x%04X\n", sis5595_base);
-+ if (PCIBIOS_SUCCESSFUL !=
-+ pci_write_config_word(SIS5595_dev, ACPI_BASE, sis5595_base))
-+ return -ENODEV;
-+ if (PCIBIOS_SUCCESSFUL !=
-+ pci_read_config_word(SIS5595_dev, ACPI_BASE, &a))
-+ return -ENODEV;
-+ if ((a & ~(SIS5595_EXTENT - 1)) != sis5595_base) {
-+ /* doesn't work for some chips! */
-+ printk("i2c-sis5595.o: force address failed - not supported?\n");
-+ return -ENODEV;
-+ }
-+ }
-+
-+ if (PCIBIOS_SUCCESSFUL !=
-+ pci_read_config_byte(SIS5595_dev, SIS5595_ENABLE_REG, &val))
-+ return -ENODEV;
-+ if((val & 0x80) == 0) {
-+ printk("sis5595.o: enabling ACPI\n");
-+ if (PCIBIOS_SUCCESSFUL !=
-+ pci_write_config_byte(SIS5595_dev, SIS5595_ENABLE_REG,
-+ val | 0x80))
-+ return -ENODEV;
-+ if (PCIBIOS_SUCCESSFUL !=
-+ pci_read_config_byte(SIS5595_dev, SIS5595_ENABLE_REG, &val))
-+ return -ENODEV;
-+ if((val & 0x80) == 0) { /* doesn't work for some chips? */
-+ printk("sis5595.o: ACPI enable failed - not supported?\n");
-+ return -ENODEV;
-+ }
-+ }
-+
-+ /* Everything is happy, let's grab the memory and set things up. */
-+ request_region(sis5595_base + SMB_INDEX, 2, "sis5595-smbus");
-+ return(0);
-+}
-+
-+
-+/* Another internally used function */
-+int sis5595_transaction(void)
-+{
-+ int temp;
-+ int result = 0;
-+ int timeout = 0;
-+
-+ /* Make sure the SMBus host is ready to start transmitting */
-+ if (
-+ (temp =
-+ sis5595_read(SMB_STS_LO) + (sis5595_read(SMB_STS_HI) << 8)) !=
-+ 0x00) {
-+#ifdef DEBUG
-+ printk("i2c-sis5595.o: SMBus busy (%04x). Resetting... \n",
-+ temp);
-+#endif
-+ sis5595_write(SMB_STS_LO, temp & 0xff);
-+ sis5595_write(SMB_STS_HI, temp >> 8);
-+ if (
-+ (temp =
-+ sis5595_read(SMB_STS_LO) +
-+ (sis5595_read(SMB_STS_HI) << 8)) != 0x00) {
-+#ifdef DEBUG
-+ printk("i2c-sis5595.o: Failed! (%02x)\n", temp);
-+#endif
-+ return -1;
-+ } else {
-+#ifdef DEBUG
-+ printk("i2c-sis5595.o: Successfull!\n");
-+#endif
-+ }
-+ }
-+
-+ /* start the transaction by setting bit 4 */
-+ sis5595_write(SMB_CTL_LO, sis5595_read(SMB_CTL_LO) | 0x10);
-+
-+ /* We will always wait for a fraction of a second! */
-+ do {
-+ i2c_delay(1);
-+ temp = sis5595_read(SMB_STS_LO);
-+ } while (!(temp & 0x40) && (timeout++ < MAX_TIMEOUT));
-+
-+ /* If the SMBus is still busy, we give up */
-+ if (timeout >= MAX_TIMEOUT) {
-+#ifdef DEBUG
-+ printk("i2c-sis5595.o: SMBus Timeout!\n");
-+#endif
-+ result = -1;
-+ }
-+
-+ if (temp & 0x10) {
-+ result = -1;
-+#ifdef DEBUG
-+ printk("i2c-sis5595.o: Error: Failed bus transaction\n");
-+#endif
-+ }
-+
-+ if (temp & 0x20) {
-+ result = -1;
-+ printk
-+ ("i2c-sis5595.o: Bus collision! SMBus may be locked until next hard\n"
-+ "reset (or not...)\n");
-+ /* Clock stops and slave is stuck in mid-transmission */
-+ }
-+
-+ if (
-+ (temp =
-+ sis5595_read(SMB_STS_LO) + (sis5595_read(SMB_STS_HI) << 8)) !=
-+ 0x00) {
-+ sis5595_write(SMB_STS_LO, temp & 0xff);
-+ sis5595_write(SMB_STS_HI, temp >> 8);
-+ }
-+
-+ if (
-+ (temp =
-+ sis5595_read(SMB_STS_LO) + (sis5595_read(SMB_STS_HI) << 8)) !=
-+ 0x00) {
-+
-+#ifdef DEBUG
-+ printk
-+ ("i2c-sis5595.o: Failed reset at end of transaction (%02x)\n",
-+ temp);
-+#endif
-+ }
-+ return result;
-+}
-+
-+/* Return -1 on error. */
-+s32 sis5595_access(struct i2c_adapter * adap, u16 addr,
-+ unsigned short flags, char read_write,
-+ u8 command, int size, union i2c_smbus_data * data)
-+{
-+ switch (size) {
-+ case I2C_SMBUS_QUICK:
-+ sis5595_write(SMB_ADDR,
-+ ((addr & 0x7f) << 1) | (read_write & 0x01));
-+ size = SIS5595_QUICK;
-+ break;
-+ case I2C_SMBUS_BYTE:
-+ sis5595_write(SMB_ADDR,
-+ ((addr & 0x7f) << 1) | (read_write & 0x01));
-+ if (read_write == I2C_SMBUS_WRITE)
-+ sis5595_write(SMB_CMD, command);
-+ size = SIS5595_BYTE;
-+ break;
-+ case I2C_SMBUS_BYTE_DATA:
-+ sis5595_write(SMB_ADDR,
-+ ((addr & 0x7f) << 1) | (read_write & 0x01));
-+ sis5595_write(SMB_CMD, command);
-+ if (read_write == I2C_SMBUS_WRITE)
-+ sis5595_write(SMB_BYTE, data->byte);
-+ size = SIS5595_BYTE_DATA;
-+ break;
-+ case I2C_SMBUS_PROC_CALL:
-+ case I2C_SMBUS_WORD_DATA:
-+ sis5595_write(SMB_ADDR,
-+ ((addr & 0x7f) << 1) | (read_write & 0x01));
-+ sis5595_write(SMB_CMD, command);
-+ if (read_write == I2C_SMBUS_WRITE) {
-+ sis5595_write(SMB_BYTE, data->word & 0xff);
-+ sis5595_write(SMB_BYTE + 1,
-+ (data->word & 0xff00) >> 8);
-+ }
-+ size =
-+ (size ==
-+ I2C_SMBUS_PROC_CALL) ? SIS5595_PROC_CALL :
-+ SIS5595_WORD_DATA;
-+ break;
-+/*
-+ case I2C_SMBUS_BLOCK_DATA:
-+ printk("sis5595.o: Block data not yet implemented!\n");
-+ return -1;
-+ break;
-+*/
-+ default:
-+ printk
-+ (KERN_WARNING "sis5595.o: Unsupported transaction %d\n", size);
-+ return -1;
-+ }
-+
-+ sis5595_write(SMB_CTL_LO, ((size & 0x0E)));
-+
-+ if (sis5595_transaction()) /* Error in transaction */
-+ return -1;
-+
-+ if ((size != SIS5595_PROC_CALL) &&
-+ ((read_write == I2C_SMBUS_WRITE) || (size == SIS5595_QUICK)))
-+ return 0;
-+
-+
-+ switch (size) {
-+ case SIS5595_BYTE: /* Where is the result put? I assume here it is in
-+ SMB_DATA but it might just as well be in the
-+ SMB_CMD. No clue in the docs */
-+ case SIS5595_BYTE_DATA:
-+ data->byte = sis5595_read(SMB_BYTE);
-+ break;
-+ case SIS5595_WORD_DATA:
-+ case SIS5595_PROC_CALL:
-+ data->word =
-+ sis5595_read(SMB_BYTE) +
-+ (sis5595_read(SMB_BYTE + 1) << 8);
-+ break;
-+ }
-+ return 0;
-+}
-+
-+
-+u32 sis5595_func(struct i2c_adapter *adapter)
-+{
-+ return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
-+ I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
-+ I2C_FUNC_SMBUS_PROC_CALL;
-+}
-+
-+
-+static struct i2c_algorithm smbus_algorithm = {
-+ .name = "Non-I2C SMBus adapter",
-+ .id = I2C_ALGO_SMBUS,
-+ .smbus_xfer = sis5595_access,
-+ .functionality = sis5595_func,
-+};
-+
-+static struct i2c_adapter sis5595_adapter = {
-+ .owner = THIS_MODULE,
-+ .name = "unset",
-+ .id = I2C_ALGO_SMBUS | I2C_HW_SMBUS_SIS5595,
-+ .algo = &smbus_algorithm,
-+};
-+
-+
-+static struct pci_device_id sis5595_ids[] __devinitdata = {
-+ {
-+ .vendor = PCI_VENDOR_ID_SI,
-+ .device = PCI_DEVICE_ID_SI_503,
-+ .subvendor = PCI_ANY_ID,
-+ .subdevice = PCI_ANY_ID,
-+ },
-+ { 0, }
-+};
-+
-+static int __devinit sis5595_probe(struct pci_dev *dev, const struct pci_device_id *id)
-+{
-+
-+ if (sis5595_setup(dev)) {
-+ printk
-+ ("i2c-sis5595.o: SIS5595 not detected, module not inserted.\n");
-+
-+ return -ENODEV;
-+ }
-+
-+ sprintf(sis5595_adapter.name, "SMBus SIS5595 adapter at %04x",
-+ sis5595_base + SMB_INDEX);
-+ i2c_add_adapter(&sis5595_adapter);
-+
-+ return 0;
-+}
-+
-+static void __devexit sis5595_remove(struct pci_dev *dev)
-+{
-+ i2c_del_adapter(&sis5595_adapter);
-+ release_region(sis5595_base + SMB_INDEX, 2);
-+}
-+
-+
-+static struct pci_driver sis5595_driver = {
-+ .name = "sis5595 smbus",
-+ .id_table = sis5595_ids,
-+ .probe = sis5595_probe,
-+ .remove = __devexit_p(sis5595_remove),
-+};
-+
-+static int __init i2c_sis5595_init(void)
-+{
-+ printk("i2c-sis5595.o version %s (%s)\n", LM_VERSION, LM_DATE);
-+ return pci_module_init(&sis5595_driver);
-+}
-+
-+
-+static void __exit i2c_sis5595_exit(void)
-+{
-+ pci_unregister_driver(&sis5595_driver);
-+}
-+
-+
-+
-+MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl>");
-+MODULE_DESCRIPTION("SIS5595 SMBus driver");
-+
-+module_init(i2c_sis5595_init);
-+module_exit(i2c_sis5595_exit);
---- linux-old/drivers/i2c/i2c-sis630.c Thu Jan 1 00:00:00 1970
-+++ linux/drivers/i2c/i2c-sis630.c Mon Dec 13 20:18:42 2004
-@@ -0,0 +1,527 @@
-+/*
-+ i2c-sis630.c - Part of lm_sensors, Linux kernel modules for hardware
-+ monitoring
-+
-+ Copyright (c) 2002,2003 Alexander Malysh <amalysh@web.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., 675 Mass Ave, Cambridge, MA 02139, USA.
-+*/
-+
-+/*
-+ Changes:
-+ 24.08.2002
-+ Fixed the typo in sis630_access (Thanks to Mark M. Hoffman)
-+ Changed sis630_transaction.(Thanks to Mark M. Hoffman)
-+ 18.09.2002
-+ Added SIS730 as supported.
-+ 21.09.2002
-+ Added high_clock module option.If this option is set
-+ used Host Master Clock 56KHz (default 14KHz).For now we save old Host
-+ Master Clock and after transaction completed restore (otherwise
-+ it's confuse BIOS and hung Machine).
-+ 24.09.2002
-+ Fixed typo in sis630_access
-+ Fixed logical error by restoring of Host Master Clock
-+ 31.07.2003
-+ Added block data read/write support.
-+*/
-+
-+/*
-+ Status: beta
-+
-+ Supports:
-+ SIS 630
-+ SIS 730
-+
-+ Note: we assume there can only be one device, with one SMBus interface.
-+*/
-+
-+#include <linux/module.h>
-+#include <linux/kernel.h>
-+#include <linux/pci.h>
-+#include <linux/stddef.h>
-+#include <linux/sched.h>
-+#include <linux/ioport.h>
-+#include <linux/i2c.h>
-+#include <linux/init.h>
-+#include <asm/io.h>
-+#define LM_DATE "20041007"
-+#define LM_VERSION "2.8.8"
-+
-+
-+#ifdef DEBUG
-+#define DBG(x...) printk(KERN_DEBUG "i2c-sis630.o: " x)
-+#else
-+#define DBG(x...)
-+#endif
-+
-+/* SIS630 SMBus registers */
-+#define SMB_STS 0x80 /* status */
-+#define SMB_EN 0x81 /* status enable */
-+#define SMB_CNT 0x82
-+#define SMBHOST_CNT 0x83
-+#define SMB_ADDR 0x84
-+#define SMB_CMD 0x85
-+#define SMB_PCOUNT 0x86 /* processed count */
-+#define SMB_COUNT 0x87
-+#define SMB_BYTE 0x88 /* ~0x8F data byte field */
-+#define SMBDEV_ADDR 0x90
-+#define SMB_DB0 0x91
-+#define SMB_DB1 0x92
-+#define SMB_SAA 0x93
-+
-+/* register count for request_region */
-+#define SIS630_SMB_IOREGION 20
-+
-+/* PCI address constants */
-+/* acpi base address register */
-+#define SIS630_ACPI_BASE_REG 0x74
-+/* bios control register */
-+#define SIS630_BIOS_CTL_REG 0x40
-+
-+/* Other settings */
-+#define MAX_TIMEOUT 500
-+
-+/* SIS630 constants */
-+#define SIS630_QUICK 0x00
-+#define SIS630_BYTE 0x01
-+#define SIS630_BYTE_DATA 0x02
-+#define SIS630_WORD_DATA 0x03
-+#define SIS630_PCALL 0x04
-+#define SIS630_BLOCK_DATA 0x05
-+
-+/* insmod parameters */
-+static int high_clock = 0;
-+static int force = 0;
-+MODULE_PARM(high_clock, "i");
-+MODULE_PARM_DESC(high_clock, "Set Host Master Clock to 56KHz (default 14KHz).");
-+MODULE_PARM(force, "i");
-+MODULE_PARM_DESC(force, "Forcibly enable the SIS630. DANGEROUS!");
-+
-+/* acpi base address */
-+static unsigned short acpi_base = 0;
-+
-+/* supported chips */
-+static int supported[] = {
-+ PCI_DEVICE_ID_SI_630,
-+ PCI_DEVICE_ID_SI_730,
-+ 0 /* terminates the list */
-+};
-+
-+static inline u8 sis630_read(u8 reg) {
-+ return inb(acpi_base + reg);
-+}
-+
-+static inline void sis630_write(u8 reg, u8 data) {
-+ outb(data, acpi_base + reg);
-+}
-+
-+static int sis630_transaction_start(int size, u8 *oldclock) {
-+ int temp;
-+
-+ /*
-+ Make sure the SMBus host is ready to start transmitting.
-+ */
-+ if ((temp = sis630_read(SMB_CNT) & 0x03) != 0x00) {
-+ DBG("SMBus busy (%02x).Resetting...\n",temp);
-+ /* kill smbus transaction */
-+ sis630_write(SMBHOST_CNT, 0x20);
-+
-+ if ((temp = sis630_read(SMB_CNT) & 0x03) != 0x00) {
-+ DBG("Failed! (%02x)\n", temp);
-+ return -1;
-+ } else {
-+ DBG("Successfull!\n");
-+ }
-+ }
-+
-+ /* save old clock, so we can prevent machine for hung */
-+ *oldclock = sis630_read(SMB_CNT);
-+
-+ DBG("saved clock 0x%02x\n", *oldclock);
-+
-+ /* disable timeout interrupt , set Host Master Clock to 56KHz if requested */
-+ if (high_clock > 0)
-+ sis630_write(SMB_CNT, 0x20);
-+ else
-+ sis630_write(SMB_CNT, (*oldclock & ~0x40));
-+
-+ /* clear all sticky bits */
-+ temp = sis630_read(SMB_STS);
-+ sis630_write(SMB_STS, temp & 0x1e);
-+
-+ /* start the transaction by setting bit 4 and size */
-+ sis630_write(SMBHOST_CNT,0x10 | (size & 0x07));
-+
-+ return 0;
-+}
-+
-+static int sis630_transaction_wait(int size) {
-+ int temp, result = 0, timeout = 0;
-+
-+ /* We will always wait for a fraction of a second! */
-+ do {
-+ i2c_delay(1);
-+ temp = sis630_read(SMB_STS);
-+ /* check if block transmitted */
-+ if (size == SIS630_BLOCK_DATA && (temp & 0x10))
-+ break;
-+ } while (!(temp & 0x0e) && (timeout++ < MAX_TIMEOUT));
-+
-+ /* If the SMBus is still busy, we give up */
-+ if (timeout >= MAX_TIMEOUT) {
-+ DBG("SMBus Timeout!\n");
-+ result = -1;
-+ }
-+
-+ if (temp & 0x02) {
-+ result = -1;
-+ DBG("Error: Failed bus transaction\n");
-+ }
-+
-+ if (temp & 0x04) {
-+ result = -1;
-+ printk(KERN_ERR "i2c-sis630.o: Bus collision!\n");
-+ /*
-+ TBD: Datasheet say:
-+ the software should clear this bit and restart SMBUS operation.
-+ Should we do it or user start request again?
-+ */
-+ }
-+
-+ return result;
-+}
-+
-+static void sis630_transaction_end(u8 oldclock) {
-+ int temp = 0;
-+
-+ /* clear all status "sticky" bits */
-+ sis630_write(SMB_STS, temp);
-+
-+ DBG("SMB_CNT before clock restore 0x%02x\n", sis630_read(SMB_CNT));
-+
-+ /*
-+ * restore old Host Master Clock if high_clock is set
-+ * and oldclock was not 56KHz
-+ */
-+ if (high_clock > 0 && !(oldclock & 0x20))
-+ sis630_write(SMB_CNT,(sis630_read(SMB_CNT) & ~0x20));
-+
-+ DBG("SMB_CNT after clock restore 0x%02x\n", sis630_read(SMB_CNT));
-+}
-+
-+static int sis630_transaction(int size) {
-+ int result = 0;
-+ u8 oldclock = 0;
-+
-+ if (!(result = sis630_transaction_start(size, &oldclock))) {
-+ result = sis630_transaction_wait(size);
-+ sis630_transaction_end(oldclock);
-+ }
-+
-+ return result;
-+}
-+
-+static int sis630_block_data(union i2c_smbus_data * data, int read_write) {
-+ int i, len = 0, rc = 0;
-+ u8 oldclock = 0;
-+
-+ if (read_write == I2C_SMBUS_WRITE) {
-+ len = data->block[0];
-+ if (len < 0)
-+ len = 0;
-+ else if (len > 32)
-+ len = 32;
-+ sis630_write(SMB_COUNT, len);
-+ for (i=1; i <= len; i++) {
-+ DBG("set data 0x%02x\n", data->block[i]);
-+ /* set data */
-+ sis630_write(SMB_BYTE+(i-1)%8, data->block[i]);
-+ if (i==8 || (len<8 && i==len)) {
-+ DBG("start trans len=%d i=%d\n",len ,i);
-+ /* first transaction */
-+ if (sis630_transaction_start(SIS630_BLOCK_DATA, &oldclock))
-+ return -1;
-+ }
-+ else if ((i-1)%8 == 7 || i==len) {
-+ DBG("trans_wait len=%d i=%d\n",len,i);
-+ if (i>8) {
-+ DBG("clear smbary_sts len=%d i=%d\n",len,i);
-+ /*
-+ If this is not first transaction,
-+ we must clear sticky bit.
-+ clear SMBARY_STS
-+ */
-+ sis630_write(SMB_STS,0x10);
-+ }
-+ if (sis630_transaction_wait(SIS630_BLOCK_DATA)) {
-+ DBG("trans_wait failed\n");
-+ rc = -1;
-+ break;
-+ }
-+
-+ }
-+ }
-+ }
-+ else { /* read request */
-+ data->block[0] = len = 0;
-+ if (sis630_transaction_start(SIS630_BLOCK_DATA, &oldclock)) {
-+ return -1;
-+ }
-+ do {
-+ if (sis630_transaction_wait(SIS630_BLOCK_DATA)) {
-+ DBG("trans_wait failed\n");
-+ rc = -1;
-+ break;
-+ }
-+ /* if this first transaction then read byte count */
-+ if (len == 0)
-+ data->block[0] = sis630_read(SMB_COUNT);
-+
-+ /* just to be sure */
-+ if (data->block[0] > 32)
-+ data->block[0] = 32;
-+
-+ DBG("block data read len=0x%x\n", data->block[0]);
-+
-+ for (i=0; i < 8 && len < data->block[0]; i++,len++) {
-+ DBG("read i=%d len=%d\n", i, len);
-+ data->block[len+1] = sis630_read(SMB_BYTE+i);
-+ }
-+
-+ DBG("clear smbary_sts len=%d i=%d\n",len,i);
-+
-+ /* clear SMBARY_STS */
-+ sis630_write(SMB_STS,0x10);
-+ } while(len < data->block[0]);
-+ }
-+
-+ sis630_transaction_end(oldclock);
-+
-+ return rc;
-+}
-+
-+/* Return -1 on error. */
-+static s32 sis630_access(struct i2c_adapter * adap, u16 addr,
-+ unsigned short flags, char read_write,
-+ u8 command, int size, union i2c_smbus_data * data)
-+{
-+
-+ switch (size) {
-+ case I2C_SMBUS_QUICK:
-+ sis630_write(SMB_ADDR, ((addr & 0x7f) << 1) | (read_write & 0x01));
-+ size = SIS630_QUICK;
-+ break;
-+ case I2C_SMBUS_BYTE:
-+ sis630_write(SMB_ADDR, ((addr & 0x7f) << 1) | (read_write & 0x01));
-+ if (read_write == I2C_SMBUS_WRITE)
-+ sis630_write(SMB_CMD, command);
-+ size = SIS630_BYTE;
-+ break;
-+ case I2C_SMBUS_BYTE_DATA:
-+ sis630_write(SMB_ADDR, ((addr & 0x7f) << 1) | (read_write & 0x01));
-+ sis630_write(SMB_CMD, command);
-+ if (read_write == I2C_SMBUS_WRITE)
-+ sis630_write(SMB_BYTE, data->byte);
-+ size = SIS630_BYTE_DATA;
-+ break;
-+ case I2C_SMBUS_PROC_CALL:
-+ case I2C_SMBUS_WORD_DATA:
-+ sis630_write(SMB_ADDR,((addr & 0x7f) << 1) | (read_write & 0x01));
-+ sis630_write(SMB_CMD, command);
-+ if (read_write == I2C_SMBUS_WRITE) {
-+ sis630_write(SMB_BYTE, data->word & 0xff);
-+ sis630_write(SMB_BYTE + 1,(data->word & 0xff00) >> 8);
-+ }
-+ size = (size == I2C_SMBUS_PROC_CALL ? SIS630_PCALL : SIS630_WORD_DATA);
-+ break;
-+ case I2C_SMBUS_BLOCK_DATA:
-+ sis630_write(SMB_ADDR,((addr & 0x7f) << 1) | (read_write & 0x01));
-+ sis630_write(SMB_CMD, command);
-+ size = SIS630_BLOCK_DATA;
-+ return sis630_block_data(data, read_write);
-+ default:
-+ printk("Unsupported I2C size\n");
-+ return -1;
-+ break;
-+ }
-+
-+
-+ if (sis630_transaction(size))
-+ return -1;
-+
-+ if ((size != SIS630_PCALL) &&
-+ ((read_write == I2C_SMBUS_WRITE) || (size == SIS630_QUICK))) {
-+ return 0;
-+ }
-+
-+ switch(size) {
-+ case SIS630_BYTE:
-+ case SIS630_BYTE_DATA:
-+ data->byte = sis630_read(SMB_BYTE);
-+ break;
-+ case SIS630_PCALL:
-+ case SIS630_WORD_DATA:
-+ data->word = sis630_read(SMB_BYTE) + (sis630_read(SMB_BYTE + 1) << 8);
-+ break;
-+ default:
-+ return -1;
-+ break;
-+ }
-+
-+ return 0;
-+}
-+
-+
-+static u32 sis630_func(struct i2c_adapter *adapter) {
-+ return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE | I2C_FUNC_SMBUS_BYTE_DATA |
-+ I2C_FUNC_SMBUS_WORD_DATA | I2C_FUNC_SMBUS_PROC_CALL |
-+ I2C_FUNC_SMBUS_BLOCK_DATA;
-+}
-+
-+static int __devinit sis630_setup(struct pci_dev *sis630_dev) {
-+ unsigned char b;
-+ struct pci_dev *dummy = NULL;
-+ int i;
-+
-+ /* check for supported SiS devices */
-+ for (i=0; supported[i] > 0; i++) {
-+ if ((dummy = pci_find_device(PCI_VENDOR_ID_SI, supported[i], dummy)))
-+ break; /* found */
-+ }
-+
-+ if (!dummy && force > 0) {
-+ printk(KERN_ERR "i2c-sis630.o: WARNING: Can't detect SIS630 compatible device, but "
-+ "loading because of force option enabled\n");
-+ }
-+ else if (!dummy) {
-+ return -ENODEV;
-+ }
-+
-+ /*
-+ Enable ACPI first , so we can accsess reg 74-75
-+ in acpi io space and read acpi base addr
-+ */
-+ if (PCIBIOS_SUCCESSFUL !=
-+ pci_read_config_byte(sis630_dev, SIS630_BIOS_CTL_REG,&b)) {
-+ printk(KERN_ERR "i2c-sis630.o: Error: Can't read bios ctl reg\n");
-+ return -ENODEV;
-+ }
-+
-+ /* if ACPI already enabled , do nothing */
-+ if (!(b & 0x80) &&
-+ PCIBIOS_SUCCESSFUL !=
-+ pci_write_config_byte(sis630_dev,SIS630_BIOS_CTL_REG,b|0x80)) {
-+ printk(KERN_ERR "i2c-sis630.o: Error: Can't enable ACPI\n");
-+ return -ENODEV;
-+ }
-+ /* Determine the ACPI base address */
-+ if (PCIBIOS_SUCCESSFUL !=
-+ pci_read_config_word(sis630_dev,SIS630_ACPI_BASE_REG,&acpi_base)) {
-+ printk(KERN_ERR "i2c-sis630.o: Error: Can't determine ACPI base address\n");
-+ return -ENODEV;
-+ }
-+
-+ DBG("ACPI base at 0x%04x\n", acpi_base);
-+
-+ /* Everything is happy, let's grab the memory and set things up. */
-+ if (!request_region(acpi_base + SMB_STS, SIS630_SMB_IOREGION, "sis630-smbus")){
-+ printk(KERN_ERR "i2c-sis630.o: SMBus registers 0x%04x-0x%04x "
-+ "already in use!\n",acpi_base + SMB_STS, acpi_base + SMB_SAA);
-+ acpi_base = 0; /* reset acpi_base */
-+ return -ENODEV;
-+ }
-+
-+ return 0;
-+}
-+
-+
-+static struct i2c_algorithm smbus_algorithm = {
-+ .name = "Non-I2C SMBus adapter",
-+ .id = I2C_ALGO_SMBUS,
-+ .smbus_xfer = sis630_access,
-+ .functionality = sis630_func,
-+};
-+
-+static struct i2c_adapter sis630_adapter = {
-+ .owner = THIS_MODULE,
-+ .name = "unset",
-+ .id = I2C_ALGO_SMBUS | I2C_HW_SMBUS_SIS630,
-+ .algo = &smbus_algorithm,
-+};
-+
-+
-+static struct pci_device_id sis630_ids[] __devinitdata = {
-+ {
-+ .vendor = PCI_VENDOR_ID_SI,
-+ .device = PCI_DEVICE_ID_SI_503,
-+ .subvendor = PCI_ANY_ID,
-+ .subdevice = PCI_ANY_ID,
-+ },
-+ { 0, }
-+};
-+
-+static int __devinit sis630_probe(struct pci_dev *dev, const struct pci_device_id *id)
-+{
-+ if (sis630_setup(dev)) {
-+ printk(KERN_ERR "i2c-sis630.o: SIS630 comp. bus not detected, module not inserted.\n");
-+ return -ENODEV;
-+ }
-+
-+ sprintf(sis630_adapter.name, "SMBus SIS630 adapter at %04x",
-+ acpi_base + SMB_STS);
-+
-+ return i2c_add_adapter(&sis630_adapter);
-+}
-+
-+static void __devexit sis630_remove(struct pci_dev *dev)
-+{
-+ if (acpi_base) {
-+ i2c_del_adapter(&sis630_adapter);
-+ release_region(acpi_base + SMB_STS, SIS630_SMB_IOREGION);
-+ acpi_base = 0;
-+ }
-+}
-+
-+
-+static struct pci_driver sis630_driver = {
-+ .name = "sis630 smbus",
-+ .id_table = sis630_ids,
-+ .probe = sis630_probe,
-+ .remove = __devexit_p(sis630_remove),
-+};
-+
-+static int __init i2c_sis630_init(void)
-+{
-+ printk("i2c-sis630.o version %s (%s)\n", LM_VERSION, LM_DATE);
-+ return pci_module_init(&sis630_driver);
-+}
-+
-+
-+static void __exit i2c_sis630_exit(void)
-+{
-+ pci_unregister_driver(&sis630_driver);
-+}
-+
-+
-+
-+
-+MODULE_LICENSE("GPL");
-+
-+MODULE_AUTHOR("Alexander Malysh <amalysh@web.de>");
-+MODULE_DESCRIPTION("SIS630 SMBus driver");
-+
-+module_init(i2c_sis630_init);
-+module_exit(i2c_sis630_exit);
---- linux-old/drivers/i2c/i2c-sis645.c Thu Jan 1 00:00:00 1970
-+++ linux/drivers/i2c/i2c-sis645.c Mon Dec 13 20:18:42 2004
-@@ -0,0 +1,590 @@
-+/*
-+ sis645.c - Part of lm_sensors, Linux kernel modules for hardware
-+ monitoring
-+
-+ Copyright (c) 2003 Mark M. Hoffman <mhoffman@lightlink.com>
-+
-+ 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., 675 Mass Ave, Cambridge, MA 02139, USA.
-+*/
-+
-+/*
-+ This module must be considered BETA unless and until
-+ the chipset manufacturer releases a datasheet.
-+
-+ The register definitions are based on the SiS630.
-+ The method for *finding* the registers is based on trial and error.
-+
-+ A history of changes to this file is available by anonymous CVS:
-+ http://www2.lm-sensors.nu/~lm78/download.html
-+*/
-+
-+/* 25th March 2004
-+ Support for Sis655 chipsets added by Ken Healy
-+*/
-+
-+/*
-+ Note: we assume there can only be one SiS645 with one SMBus interface
-+*/
-+
-+/* #define DEBUG 1 */
-+
-+#include <linux/module.h>
-+#include <linux/pci.h>
-+#include <linux/kernel.h>
-+#include <linux/stddef.h>
-+#include <linux/sched.h>
-+#include <linux/ioport.h>
-+#include <linux/i2c.h>
-+#include <linux/init.h>
-+#include <linux/mm.h>
-+#include <asm/io.h>
-+#define LM_DATE "20041007"
-+#define LM_VERSION "2.8.8"
-+#include <linux/sensors_compat.h>
-+
-+#define DRV_NAME "i2c-sis645"
-+
-+/* SiS645DX north bridge (defined in 2.4.21) */
-+#ifndef PCI_DEVICE_ID_SI_646
-+#define PCI_DEVICE_ID_SI_646 0x0646
-+#endif
-+
-+/* SiS648 north bridge (defined in 2.4.21) */
-+#ifndef PCI_DEVICE_ID_SI_648
-+#define PCI_DEVICE_ID_SI_648 0x0648
-+#endif
-+
-+/* SiS650 north bridge (defined in 2.4.19) */
-+#ifndef PCI_DEVICE_ID_SI_650
-+#define PCI_DEVICE_ID_SI_650 0x0650
-+#endif
-+
-+/* SiS651 north bridge (defined in 2.4.21)*/
-+#ifndef PCI_DEVICE_ID_SI_651
-+#define PCI_DEVICE_ID_SI_651 0x0651
-+#endif
-+
-+/* SiS655 north bridge (defined in 2.4.22)*/
-+#ifndef PCI_DEVICE_ID_SI_655
-+#define PCI_DEVICE_ID_SI_655 0x0655
-+#endif
-+
-+/* SiS746 north bridge (defined in 2.4.21) */
-+#ifndef PCI_DEVICE_ID_SI_746
-+#define PCI_DEVICE_ID_SI_746 0x0746
-+#endif
-+
-+/* SiS85C503/5513 (LPC Bridge) */
-+#ifndef PCI_DEVICE_ID_SI_LPC
-+#define PCI_DEVICE_ID_SI_LPC 0x0018
-+#endif
-+
-+/* SiS961 south bridge */
-+#ifndef PCI_DEVICE_ID_SI_961
-+#define PCI_DEVICE_ID_SI_961 0x0961
-+#endif
-+
-+/* SiS962 south bridge */
-+#ifndef PCI_DEVICE_ID_SI_962
-+#define PCI_DEVICE_ID_SI_962 0x0962
-+#endif
-+
-+/* SiS963 south bridge */
-+#ifndef PCI_DEVICE_ID_SI_963
-+#define PCI_DEVICE_ID_SI_963 0x0963
-+#endif
-+
-+/* SMBus ID */
-+#ifndef PCI_DEVICE_ID_SI_SMBUS
-+#define PCI_DEVICE_ID_SI_SMBUS 0x16
-+#endif
-+
-+/* base address register in PCI config space */
-+#define SIS645_BAR 0x04
-+
-+/* SiS645 SMBus registers */
-+#define SMB_STS 0x00
-+#define SMB_EN 0x01
-+#define SMB_CNT 0x02
-+#define SMB_HOST_CNT 0x03
-+#define SMB_ADDR 0x04
-+#define SMB_CMD 0x05
-+#define SMB_PCOUNT 0x06
-+#define SMB_COUNT 0x07
-+#define SMB_BYTE 0x08
-+#define SMB_DEV_ADDR 0x10
-+#define SMB_DB0 0x11
-+#define SMB_DB1 0x12
-+#define SMB_SAA 0x13
-+
-+/* register count for request_region */
-+#define SMB_IOSIZE 0x20
-+
-+/* Other settings */
-+#define MAX_TIMEOUT 500
-+
-+/* SiS645 SMBus constants */
-+#define SIS645_QUICK 0x00
-+#define SIS645_BYTE 0x01
-+#define SIS645_BYTE_DATA 0x02
-+#define SIS645_WORD_DATA 0x03
-+#define SIS645_PROC_CALL 0x04
-+#define SIS645_BLOCK_DATA 0x05
-+
-+static struct i2c_adapter sis645_adapter;
-+static u16 sis645_smbus_base = 0;
-+
-+static inline u8 sis645_read(u8 reg)
-+{
-+ return inb(sis645_smbus_base + reg) ;
-+}
-+
-+static inline void sis645_write(u8 reg, u8 data)
-+{
-+ outb(data, sis645_smbus_base + reg) ;
-+}
-+
-+#ifdef CONFIG_HOTPLUG
-+
-+/* Turns on SMBus device if it is not; return 0 iff successful
-+ */
-+static int __devinit sis645_enable_smbus(struct pci_dev *dev)
-+{
-+ u8 val = 0;
-+
-+ pci_read_config_byte(dev, 0x77, &val);
-+
-+#ifdef DEBUG
-+ printk(KERN_DEBUG DRV_NAME ": Config byte was 0x%02x.\n", val);
-+#endif
-+
-+ pci_write_config_byte(dev, 0x77, val & ~0x10);
-+
-+ pci_read_config_byte(dev, 0x77, &val);
-+
-+ if (val & 0x10) {
-+#ifdef DEBUG
-+ printk(KERN_DEBUG DRV_NAME ": Config byte stuck!\n");
-+#endif
-+ return -1;
-+ }
-+
-+ return 0;
-+}
-+
-+/* Builds the basic pci_dev for SiS645 SMBus
-+ */
-+static int __devinit sis645_build_dev(struct pci_dev **smbus_dev,
-+ struct pci_dev *bridge_dev)
-+{
-+ struct pci_dev temp_dev;
-+ u16 vid = 0, did = 0;
-+ int ret;
-+
-+ /* fill in the device structure for search */
-+ memset(&temp_dev, 0, sizeof(temp_dev));
-+ temp_dev.bus = bridge_dev->bus;
-+ temp_dev.sysdata = bridge_dev->bus->sysdata;
-+ temp_dev.hdr_type = PCI_HEADER_TYPE_NORMAL;
-+
-+ /* the SMBus device is function 1 on the same unit as the ISA bridge */
-+ temp_dev.devfn = bridge_dev->devfn + 1;
-+
-+ /* query to make sure */
-+ ret = pci_read_config_word(&temp_dev, PCI_VENDOR_ID, &vid);
-+ if (ret || PCI_VENDOR_ID_SI != vid) {
-+ printk(KERN_ERR DRV_NAME ": Couldn't find SMBus device!\n");
-+ return ret;
-+ }
-+ temp_dev.vendor = vid;
-+
-+ ret = pci_read_config_word(&temp_dev, PCI_DEVICE_ID, &did);
-+ if (ret || PCI_DEVICE_ID_SI_SMBUS != did) {
-+ printk(KERN_ERR DRV_NAME ": Couldn't find SMBus device!\n");
-+ return ret;
-+ }
-+ temp_dev.device = did;
-+
-+ /* ok, we've got it... request some memory and finish it off */
-+ *smbus_dev = kmalloc(sizeof(**smbus_dev), GFP_ATOMIC);
-+ if (NULL == *smbus_dev) {
-+ printk(KERN_ERR DRV_NAME ": Out of memory!\n");
-+ return -ENOMEM;
-+ }
-+
-+ **smbus_dev = temp_dev;
-+
-+ ret = pci_setup_device(*smbus_dev);
-+ if (ret) {
-+ printk(KERN_ERR DRV_NAME ": pci_setup_device failed (0x%08x)\n",ret);
-+ }
-+ return ret;
-+}
-+
-+/* See if a SMBus can be found, and enable it if possible.
-+ */
-+static int __devinit sis645_hotplug_smbus(void)
-+{
-+ int ret;
-+ struct pci_dev *smbus_dev, *bridge_dev ;
-+
-+ if ((bridge_dev = pci_find_device(PCI_VENDOR_ID_SI,
-+ PCI_DEVICE_ID_SI_961, NULL)))
-+ printk(KERN_INFO DRV_NAME ": Found SiS961 south bridge.\n");
-+
-+ else if ((bridge_dev = pci_find_device(PCI_VENDOR_ID_SI,
-+ PCI_DEVICE_ID_SI_962, NULL)))
-+ printk(KERN_INFO DRV_NAME ": Found SiS962 [MuTIOL Media IO].\n");
-+
-+ else if ((bridge_dev = pci_find_device(PCI_VENDOR_ID_SI,
-+ PCI_DEVICE_ID_SI_963, NULL)))
-+ printk(KERN_INFO DRV_NAME ": Found SiS963 [MuTIOL Media IO].\n");
-+
-+ else if ((bridge_dev = pci_find_device(PCI_VENDOR_ID_SI,
-+ PCI_DEVICE_ID_SI_503, NULL)) ||
-+ (bridge_dev = pci_find_device(PCI_VENDOR_ID_SI,
-+ PCI_DEVICE_ID_SI_LPC, NULL))) {
-+
-+ printk(KERN_INFO DRV_NAME ": Found SiS south bridge in compatability mode(?)\n");
-+
-+ /* look for known compatible north bridges */
-+ if ((NULL == pci_find_device(PCI_VENDOR_ID_SI,
-+ PCI_DEVICE_ID_SI_645, NULL))
-+ && (NULL == pci_find_device(PCI_VENDOR_ID_SI,
-+ PCI_DEVICE_ID_SI_646, NULL))
-+ && (NULL == pci_find_device(PCI_VENDOR_ID_SI,
-+ PCI_DEVICE_ID_SI_648, NULL))
-+ && (NULL == pci_find_device(PCI_VENDOR_ID_SI,
-+ PCI_DEVICE_ID_SI_650, NULL))
-+ && (NULL == pci_find_device(PCI_VENDOR_ID_SI,
-+ PCI_DEVICE_ID_SI_651, NULL))
-+ && (NULL == pci_find_device(PCI_VENDOR_ID_SI,
-+ PCI_DEVICE_ID_SI_655, NULL))
-+ && (NULL == pci_find_device(PCI_VENDOR_ID_SI,
-+ PCI_DEVICE_ID_SI_735, NULL))
-+ && (NULL == pci_find_device(PCI_VENDOR_ID_SI,
-+ PCI_DEVICE_ID_SI_745, NULL))
-+ && (NULL == pci_find_device(PCI_VENDOR_ID_SI,
-+ PCI_DEVICE_ID_SI_746, NULL))) {
-+ printk(KERN_ERR DRV_NAME ": Can't find suitable host bridge!\n");
-+ return -ENODEV;
-+ }
-+ } else {
-+ printk(KERN_ERR DRV_NAME ": Can't find suitable south bridge!\n");
-+ return -ENODEV;
-+ }
-+
-+ /* if we get this far, we think the smbus device is present */
-+
-+ if ((ret = sis645_enable_smbus(bridge_dev)))
-+ return ret;
-+
-+ if ((ret = sis645_build_dev(&smbus_dev, bridge_dev)))
-+ return ret;
-+
-+ if ((ret = pci_enable_device(smbus_dev))) {
-+ printk(KERN_ERR DRV_NAME ": Can't pci_enable SMBus device!"
-+ " (0x%08x)\n", ret);
-+ return ret;
-+ }
-+
-+ pci_insert_device(smbus_dev, smbus_dev->bus);
-+
-+ return 0;
-+}
-+#endif /* CONFIG_HOTPLUG */
-+
-+/* Execute a SMBus transaction.
-+ int size is from SIS645_QUICK to SIS645_BLOCK_DATA
-+ */
-+static int sis645_transaction(int size)
-+{
-+ int temp;
-+ int result = 0;
-+ int timeout = 0;
-+
-+ /* Make sure the SMBus host is ready to start transmitting */
-+ if (((temp = sis645_read(SMB_CNT)) & 0x03) != 0x00) {
-+#ifdef DEBUG
-+ printk(KERN_DEBUG DRV_NAME ": SMBus busy (0x%02x). Resetting...\n",
-+ temp);
-+#endif
-+
-+ /* kill the transaction */
-+ sis645_write(SMB_HOST_CNT, 0x20);
-+
-+ /* check it again */
-+ if (((temp = sis645_read(SMB_CNT)) & 0x03) != 0x00) {
-+#ifdef DEBUG
-+ printk(KERN_DEBUG DRV_NAME ": Failed! (0x%02x)\n", temp);
-+#endif
-+ return -1;
-+ } else {
-+#ifdef DEBUG
-+ printk(KERN_DEBUG DRV_NAME ": Successful!\n");
-+#endif
-+ }
-+ }
-+
-+ /* Turn off timeout interrupts, set fast host clock */
-+ sis645_write(SMB_CNT, 0x20);
-+
-+ /* clear all (sticky) status flags */
-+ temp = sis645_read(SMB_STS);
-+ sis645_write(SMB_STS, temp & 0x1e);
-+
-+ /* start the transaction by setting bit 4 and size bits */
-+ sis645_write(SMB_HOST_CNT, 0x10 | (size & 0x07));
-+
-+ /* We will always wait for a fraction of a second! */
-+ do {
-+ i2c_delay(1);
-+ temp = sis645_read(SMB_STS);
-+ } while (!(temp & 0x0e) && (timeout++ < MAX_TIMEOUT));
-+
-+ /* If the SMBus is still busy, we give up */
-+ if (timeout >= MAX_TIMEOUT) {
-+ printk(KERN_DEBUG DRV_NAME ": SMBus Timeout! (0x%02x)\n",temp);
-+ result = -1;
-+ }
-+
-+ /* device error - probably missing ACK */
-+ if (temp & 0x02) {
-+#ifdef DEBUG
-+ printk(KERN_DEBUG DRV_NAME ": Failed bus transaction!\n");
-+#endif
-+ result = -1;
-+ }
-+
-+ /* bus collision */
-+ if (temp & 0x04) {
-+#ifdef DEBUG
-+ printk(KERN_DEBUG DRV_NAME ": Bus collision!\n");
-+#endif
-+ result = -1;
-+ }
-+
-+ /* Finish up by resetting the bus */
-+ sis645_write(SMB_STS, temp);
-+ if ((temp = sis645_read(SMB_STS))) {
-+#ifdef DEBUG
-+ printk(KERN_DEBUG DRV_NAME ": Failed reset at end of transaction!"
-+ " (0x%02x)\n", temp);
-+#endif
-+ }
-+
-+ return result;
-+}
-+
-+/* Return -1 on error. */
-+static s32 sis645_access(struct i2c_adapter * adap, u16 addr,
-+ unsigned short flags, char read_write,
-+ u8 command, int size, union i2c_smbus_data * data)
-+{
-+
-+ switch (size) {
-+ case I2C_SMBUS_QUICK:
-+ sis645_write(SMB_ADDR, ((addr & 0x7f) << 1) | (read_write & 0x01));
-+ size = SIS645_QUICK;
-+ break;
-+
-+ case I2C_SMBUS_BYTE:
-+ sis645_write(SMB_ADDR, ((addr & 0x7f) << 1) | (read_write & 0x01));
-+ if (read_write == I2C_SMBUS_WRITE)
-+ sis645_write(SMB_CMD, command);
-+ size = SIS645_BYTE;
-+ break;
-+
-+ case I2C_SMBUS_BYTE_DATA:
-+ sis645_write(SMB_ADDR, ((addr & 0x7f) << 1) | (read_write & 0x01));
-+ sis645_write(SMB_CMD, command);
-+ if (read_write == I2C_SMBUS_WRITE)
-+ sis645_write(SMB_BYTE, data->byte);
-+ size = SIS645_BYTE_DATA;
-+ break;
-+
-+ case I2C_SMBUS_PROC_CALL:
-+ case I2C_SMBUS_WORD_DATA:
-+ sis645_write(SMB_ADDR, ((addr & 0x7f) << 1) | (read_write & 0x01));
-+ sis645_write(SMB_CMD, command);
-+ if (read_write == I2C_SMBUS_WRITE) {
-+ sis645_write(SMB_BYTE, data->word & 0xff);
-+ sis645_write(SMB_BYTE + 1, (data->word & 0xff00) >> 8);
-+ }
-+ size = (size == I2C_SMBUS_PROC_CALL ? SIS645_PROC_CALL : SIS645_WORD_DATA);
-+ break;
-+
-+ case I2C_SMBUS_BLOCK_DATA:
-+ /* TO DO: */
-+ printk(KERN_INFO DRV_NAME ": SMBus block not implemented!\n");
-+ return -1;
-+ break;
-+
-+ default:
-+ printk(KERN_INFO DRV_NAME ": Unsupported I2C size\n");
-+ return -1;
-+ break;
-+ }
-+
-+ if (sis645_transaction(size))
-+ return -1;
-+
-+ if ((size != SIS645_PROC_CALL) &&
-+ ((read_write == I2C_SMBUS_WRITE) || (size == SIS645_QUICK)))
-+ return 0;
-+
-+ switch (size) {
-+ case SIS645_BYTE:
-+ case SIS645_BYTE_DATA:
-+ data->byte = sis645_read(SMB_BYTE);
-+ break;
-+
-+ case SIS645_WORD_DATA:
-+ case SIS645_PROC_CALL:
-+ data->word = sis645_read(SMB_BYTE) +
-+ (sis645_read(SMB_BYTE + 1) << 8);
-+ break;
-+ }
-+ return 0;
-+}
-+
-+static u32 sis645_func(struct i2c_adapter *adapter)
-+{
-+ return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
-+ I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
-+ I2C_FUNC_SMBUS_PROC_CALL;
-+}
-+
-+static struct i2c_algorithm smbus_algorithm = {
-+ .name = "Non-I2C SMBus adapter",
-+ .id = I2C_ALGO_SMBUS,
-+ .smbus_xfer = sis645_access,
-+ .functionality = sis645_func,
-+};
-+
-+static struct i2c_adapter sis645_adapter = {
-+ .owner = THIS_MODULE,
-+ .name = "unset",
-+ .id = I2C_ALGO_SMBUS | I2C_HW_SMBUS_SIS645,
-+ .algo = &smbus_algorithm,
-+};
-+
-+static struct pci_device_id sis645_ids[] __devinitdata = {
-+ {
-+ .vendor = PCI_VENDOR_ID_SI,
-+ .device = PCI_DEVICE_ID_SI_SMBUS,
-+ .subvendor = PCI_ANY_ID,
-+ .subdevice = PCI_ANY_ID,
-+ },
-+ { 0, }
-+};
-+
-+static int __devinit sis645_probe(struct pci_dev *dev,
-+ const struct pci_device_id *id)
-+{
-+ u16 ww = 0;
-+ int retval;
-+
-+ if (sis645_smbus_base) {
-+ dev_err(dev, "Only one device supported.\n");
-+ return -EBUSY;
-+ }
-+
-+ pci_read_config_word(dev, PCI_CLASS_DEVICE, &ww);
-+ if (PCI_CLASS_SERIAL_SMBUS != ww) {
-+ dev_err(dev, "Unsupported device class 0x%04x!\n", ww);
-+ return -ENODEV;
-+ }
-+
-+ sis645_smbus_base = pci_resource_start(dev, SIS645_BAR);
-+ if (!sis645_smbus_base) {
-+ dev_err(dev, "SiS645 SMBus base address "
-+ "not initialized!\n");
-+ return -EINVAL;
-+ }
-+ dev_info(dev, "SiS645 SMBus base address: 0x%04x\n",
-+ sis645_smbus_base);
-+
-+ /* Everything is happy, let's grab the memory and set things up. */
-+ if (!request_region(sis645_smbus_base, SMB_IOSIZE, "sis645-smbus")) {
-+ dev_err(dev, "SMBus registers 0x%04x-0x%04x "
-+ "already in use!\n", sis645_smbus_base,
-+ sis645_smbus_base + SMB_IOSIZE - 1);
-+
-+ sis645_smbus_base = 0;
-+ return -EINVAL;
-+ }
-+
-+ sprintf(sis645_adapter.name, "SiS645 SMBus adapter at 0x%04x",
-+ sis645_smbus_base);
-+
-+ if ((retval = i2c_add_adapter(&sis645_adapter))) {
-+ dev_err(dev, "Couldn't register adapter!\n");
-+ release_region(sis645_smbus_base, SMB_IOSIZE);
-+ sis645_smbus_base = 0;
-+ }
-+
-+ return retval;
-+}
-+
-+static void __devexit sis645_remove(struct pci_dev *dev)
-+{
-+ if (sis645_smbus_base) {
-+ i2c_del_adapter(&sis645_adapter);
-+ release_region(sis645_smbus_base, SMB_IOSIZE);
-+ sis645_smbus_base = 0;
-+ }
-+}
-+
-+static struct pci_driver sis645_driver = {
-+ .name = "sis645 smbus",
-+ .id_table = sis645_ids,
-+ .probe = sis645_probe,
-+ .remove = __devexit_p(sis645_remove),
-+};
-+
-+static int __init i2c_sis645_init(void)
-+{
-+ printk(KERN_INFO DRV_NAME ".o version %s (%s)\n", LM_VERSION, LM_DATE);
-+
-+ /* if the required device id is not present, try to HOTPLUG it first */
-+ if (!pci_find_device(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_SMBUS, NULL)) {
-+
-+ printk(KERN_INFO DRV_NAME ": "
-+ "Attempting to enable SiS645 SMBus device\n");
-+
-+#ifdef CONFIG_HOTPLUG
-+ sis645_hotplug_smbus();
-+#else
-+ printk(KERN_INFO DRV_NAME ": "
-+ "Requires kernel with CONFIG_HOTPLUG, sorry!\n");
-+#endif
-+ }
-+
-+ return pci_module_init(&sis645_driver);
-+}
-+
-+static void __exit i2c_sis645_exit(void)
-+{
-+ pci_unregister_driver(&sis645_driver);
-+}
-+
-+MODULE_AUTHOR("Mark M. Hoffman <mhoffman@lightlink.com>");
-+MODULE_DESCRIPTION("SiS645 SMBus driver");
-+MODULE_LICENSE("GPL");
-+
-+/* Register initialization functions using helper macros */
-+module_init(i2c_sis645_init);
-+module_exit(i2c_sis645_exit);
---- linux-old/drivers/i2c/i2c-tsunami.c Thu Jan 1 00:00:00 1970
-+++ linux/drivers/i2c/i2c-tsunami.c Mon Dec 13 20:18:42 2004
-@@ -0,0 +1,155 @@
-+/*
-+ i2c-tsunami.c - Part of lm_sensors, Linux kernel modules for hardware
-+ monitoring
-+ Copyright (c) 2001 Oleg Vdovikin <vdovikin@jscc.ru>
-+
-+ Based on code written by Ralph Metzler <rjkm@thp.uni-koeln.de> and
-+ Simon Vogl
-+
-+ 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., 675 Mass Ave, Cambridge, MA 02139, USA.
-+*/
-+
-+/* This interfaces to the I2C bus of the Tsunami/Typhoon 21272 chipsets
-+ to gain access to the on-board I2C devices.
-+
-+ For more information refer to Compaq's
-+ "Tsunami/Typhoon 21272 Chipset Hardware Reference Manual"
-+ Order Number: DS-0025-TE
-+*/
-+
-+#include <linux/module.h>
-+#include <linux/i2c.h>
-+#include <linux/i2c-algo-bit.h>
-+#include <linux/init.h>
-+#include <asm/io.h>
-+#include <asm/hwrpb.h>
-+#include <asm/core_tsunami.h>
-+#define LM_DATE "20041007"
-+#define LM_VERSION "2.8.8"
-+
-+MODULE_LICENSE("GPL");
-+
-+/* Memory Presence Detect Register (MPD-RW) bits
-+ with except of reserved RAZ bits */
-+
-+#define MPD_DR 0x8 /* Data receive - RO */
-+#define MPD_CKR 0x4 /* Clock receive - RO */
-+#define MPD_DS 0x2 /* Data send - Must be a 1 to receive - WO */
-+#define MPD_CKS 0x1 /* Clock send - WO */
-+
-+static inline void writempd(unsigned long value)
-+{
-+ TSUNAMI_cchip->mpd.csr = value;
-+ mb();
-+}
-+
-+static inline unsigned long readmpd(void)
-+{
-+ return TSUNAMI_cchip->mpd.csr;
-+}
-+
-+static void bit_tsunami_setscl(void *data, int val)
-+{
-+ /* read currently setted bits to modify them */
-+ unsigned long bits = readmpd() >> 2; /* assume output == input */
-+
-+ if (val)
-+ bits |= MPD_CKS;
-+ else
-+ bits &= ~MPD_CKS;
-+
-+ writempd(bits);
-+}
-+
-+static void bit_tsunami_setsda(void *data, int val)
-+{
-+ /* read currently setted bits to modify them */
-+ unsigned long bits = readmpd() >> 2; /* assume output == input */
-+
-+ if (val)
-+ bits |= MPD_DS;
-+ else
-+ bits &= ~MPD_DS;
-+
-+ writempd(bits);
-+}
-+
-+/* The MPD pins are open drain, so the pins always remain outputs.
-+ We rely on the i2c-algo-bit routines to set the pins high before
-+ reading the input from other chips. */
-+
-+static int bit_tsunami_getscl(void *data)
-+{
-+ return (0 != (readmpd() & MPD_CKR));
-+}
-+
-+static int bit_tsunami_getsda(void *data)
-+{
-+ return (0 != (readmpd() & MPD_DR));
-+}
-+
-+static struct i2c_algo_bit_data tsunami_i2c_bit_data = {
-+ .setsda = bit_tsunami_setsda,
-+ .setscl = bit_tsunami_setscl,
-+ .getsda = bit_tsunami_getsda,
-+ .getscl = bit_tsunami_getscl,
-+ .udelay = 10,
-+ .mdelay = 10,
-+ .timeout = HZ/2
-+};
-+
-+static struct i2c_adapter tsunami_i2c_adapter = {
-+ .owner = THIS_MODULE,
-+ .name = "I2C Tsunami/Typhoon adapter",
-+ .id = I2C_HW_B_TSUNA,
-+ .algo_data = &tsunami_i2c_bit_data,
-+};
-+
-+
-+#if 0
-+static struct pci_driver tsunami_driver = {
-+ .name = "tsunami smbus",
-+ .id_table = tsunami_ids,
-+ .probe = tsunami_probe,
-+ .remove = __devexit_p(tsunami_remove),
-+};
-+#endif
-+
-+static int __init i2c_tsunami_init(void)
-+{
-+ printk("i2c-tsunami.o version %s (%s)\n", LM_VERSION, LM_DATE);
-+
-+ if (hwrpb->sys_type != ST_DEC_TSUNAMI) {
-+ printk("i2c-tsunami.o: not Tsunami based system (%ld), module not inserted.\n", hwrpb->sys_type);
-+ return -ENXIO;
-+ } else {
-+ printk("i2c-tsunami.o: using Cchip MPD at 0x%lx.\n", (long) &TSUNAMI_cchip->mpd);
-+ }
-+ return i2c_bit_add_bus(&tsunami_i2c_adapter);
-+}
-+
-+
-+static void __exit i2c_tsunami_exit(void)
-+{
-+ i2c_bit_del_bus(&tsunami_i2c_adapter);
-+}
-+
-+
-+
-+MODULE_AUTHOR("Oleg I. Vdovikin <vdovikin@jscc.ru>");
-+MODULE_DESCRIPTION("Tsunami I2C/SMBus driver");
-+
-+module_init(i2c_tsunami_init);
-+module_exit(i2c_tsunami_exit);
---- linux-old/drivers/i2c/i2c-via.c Thu Jan 1 00:00:00 1970
-+++ linux/drivers/i2c/i2c-via.c Mon Dec 13 20:18:42 2004
-@@ -0,0 +1,207 @@
-+/*
-+ i2c-via.c - Part of lm_sensors, Linux kernel modules
-+ for hardware monitoring
-+
-+ i2c Support for Via Technologies 82C586B South Bridge
-+
-+ Copyright (c) 1998, 1999 Kyösti Mälkki <kmalkki@cc.hut.fi>
-+
-+ 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., 675 Mass Ave, Cambridge, MA 02139, USA.
-+*/
-+
-+#include <linux/kernel.h>
-+#include <linux/ioport.h>
-+#include <linux/module.h>
-+#include <linux/pci.h>
-+#include <linux/types.h>
-+#include <linux/i2c.h>
-+#include <linux/i2c-algo-bit.h>
-+#include <linux/init.h>
-+#include <asm/io.h>
-+#include <asm/param.h> /* for HZ */
-+#define LM_DATE "20041007"
-+#define LM_VERSION "2.8.8"
-+
-+/* Power management registers */
-+
-+#define PM_CFG_REVID 0x08 /* silicon revision code */
-+#define PM_CFG_IOBASE0 0x20
-+#define PM_CFG_IOBASE1 0x48
-+
-+#define I2C_DIR (pm_io_base+0x40)
-+#define I2C_OUT (pm_io_base+0x42)
-+#define I2C_IN (pm_io_base+0x44)
-+#define I2C_SCL 0x02 /* clock bit in DIR/OUT/IN register */
-+#define I2C_SDA 0x04
-+
-+/* io-region reservation */
-+#define IOSPACE 0x06
-+#define IOTEXT "via-i2c"
-+
-+static u16 pm_io_base = 0;
-+
-+/*
-+ It does not appear from the datasheet that the GPIO pins are
-+ open drain. So a we set a low value by setting the direction to
-+ output and a high value by setting the direction to input and
-+ relying on the required I2C pullup. The data value is initialized
-+ to 0 in via_init() and never changed.
-+*/
-+
-+static void bit_via_setscl(void *data, int state)
-+{
-+ outb(state ? inb(I2C_DIR) & ~I2C_SCL : inb(I2C_DIR) | I2C_SCL,
-+ I2C_DIR);
-+}
-+
-+static void bit_via_setsda(void *data, int state)
-+{
-+ outb(state ? inb(I2C_DIR) & ~I2C_SDA : inb(I2C_DIR) | I2C_SDA,
-+ I2C_DIR);
-+}
-+
-+static int bit_via_getscl(void *data)
-+{
-+ return (0 != (inb(I2C_IN) & I2C_SCL));
-+}
-+
-+static int bit_via_getsda(void *data)
-+{
-+ return (0 != (inb(I2C_IN) & I2C_SDA));
-+}
-+
-+
-+static struct i2c_algo_bit_data bit_data = {
-+ .setsda = bit_via_setsda,
-+ .setscl = bit_via_setscl,
-+ .getsda = bit_via_getsda,
-+ .getscl = bit_via_getscl,
-+ .udelay = 5,
-+ .mdelay = 5,
-+ .timeout = HZ
-+};
-+
-+static struct i2c_adapter vt586b_adapter = {
-+ .owner = THIS_MODULE,
-+ .name = "VIA i2c",
-+ .id = I2C_HW_B_VIA,
-+ .algo_data = &bit_data,
-+};
-+
-+
-+static struct pci_device_id vt586b_ids[] __devinitdata = {
-+ { PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_3, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
-+ { 0, }
-+};
-+
-+static int __devinit vt586b_probe(struct pci_dev *dev, const struct pci_device_id *id)
-+{
-+ u16 base;
-+ u8 rev;
-+ int res;
-+
-+ if (pm_io_base) {
-+ printk(KERN_ERR "i2c-via.o: Will only support one host\n");
-+ return -EBUSY;
-+ }
-+
-+ pci_read_config_byte(dev, PM_CFG_REVID, &rev);
-+
-+ switch (rev) {
-+ case 0x00:
-+ base = PM_CFG_IOBASE0;
-+ break;
-+ case 0x01:
-+ case 0x10:
-+ base = PM_CFG_IOBASE1;
-+ break;
-+
-+ default:
-+ base = PM_CFG_IOBASE1;
-+ /* later revision */
-+ }
-+
-+ pci_read_config_word(dev, base, &pm_io_base);
-+ pm_io_base &= (0xff << 8);
-+
-+ if (! request_region(I2C_DIR, IOSPACE, IOTEXT)) {
-+ printk("i2c-via.o: IO 0x%x-0x%x already in use\n",
-+ I2C_DIR, I2C_DIR + IOSPACE);
-+ return -EBUSY;
-+ }
-+ outb(inb(I2C_DIR) & ~(I2C_SDA | I2C_SCL), I2C_DIR);
-+ outb(inb(I2C_OUT) & ~(I2C_SDA | I2C_SCL), I2C_OUT);
-+
-+ res = i2c_bit_add_bus(&vt586b_adapter);
-+ if ( res < 0 ) {
-+ release_region(I2C_DIR, IOSPACE);
-+ pm_io_base = 0;
-+ return res;
-+ }
-+ return 0;
-+}
-+
-+static void __devexit vt586b_remove(struct pci_dev *dev)
-+{
-+ i2c_bit_del_bus(&vt586b_adapter);
-+ release_region(I2C_DIR, IOSPACE);
-+ pm_io_base = 0;
-+}
-+
-+
-+/* Don't register driver to avoid driver conflicts */
-+/*
-+static struct pci_driver vt586b_driver = {
-+ .name = "vt586b smbus",
-+ .id_table = vt586b_ids,
-+ .probe = vt586b_probe,
-+ .remove = __devexit_p(vt586b_remove),
-+};
-+*/
-+
-+static int __init i2c_vt586b_init(void)
-+{
-+ struct pci_dev *dev;
-+ const struct pci_device_id *id;
-+
-+ printk("i2c-via.o version %s (%s)\n", LM_VERSION, LM_DATE);
-+/*
-+ return pci_module_init(&vt586b_driver);
-+*/
-+ pci_for_each_dev(dev) {
-+ id = pci_match_device(vt586b_ids, dev);
-+ if(id)
-+ if(vt586b_probe(dev, id) >= 0)
-+ return 0;
-+ }
-+ return -ENODEV;
-+}
-+
-+
-+static void __exit i2c_vt586b_exit(void)
-+{
-+/*
-+ pci_unregister_driver(&vt586b_driver);
-+*/
-+ vt586b_remove(NULL);
-+}
-+
-+
-+MODULE_AUTHOR("Kyösti Mälkki <kmalkki@cc.hut.fi>");
-+MODULE_DESCRIPTION("i2c for Via vt82c586b southbridge");
-+MODULE_LICENSE("GPL");
-+
-+module_init(i2c_vt586b_init);
-+module_exit(i2c_vt586b_exit);
---- linux-old/drivers/i2c/i2c-viapro.c Thu Jan 1 00:00:00 1970
-+++ linux/drivers/i2c/i2c-viapro.c Mon Dec 13 20:18:43 2004
-@@ -0,0 +1,514 @@
-+/*
-+ i2c-viapro.c - Part of lm_sensors, Linux kernel modules for hardware
-+ monitoring
-+ Copyright (c) 1998 - 2002 Frodo Looijaard <frodol@dds.nl>,
-+ Philip Edelbrock <phil@netroedge.com>, Kyösti Mälkki <kmalkki@cc.hut.fi>,
-+ Mark D. Studebaker <mdsxyz123@yahoo.com>
-+
-+ 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., 675 Mass Ave, Cambridge, MA 02139, USA.
-+*/
-+
-+/*
-+ Supports Via devices:
-+ 82C596A/B (0x3050)
-+ 82C596B (0x3051)
-+ 82C686A/B
-+ 8231
-+ 8233
-+ 8233A (0x3147 and 0x3177)
-+ 8235
-+ 8237
-+ Note: we assume there can only be one device, with one SMBus interface.
-+*/
-+
-+#include <linux/module.h>
-+#include <linux/pci.h>
-+#include <linux/kernel.h>
-+#include <linux/stddef.h>
-+#include <linux/sched.h>
-+#include <linux/ioport.h>
-+#include <linux/i2c.h>
-+#include <linux/init.h>
-+#include <asm/io.h>
-+#define LM_DATE "20041007"
-+#define LM_VERSION "2.8.8"
-+#include <linux/sensors_compat.h>
-+
-+#define SMBBA1 0x90
-+#define SMBBA2 0x80
-+#define SMBBA3 0xD0
-+
-+/* SMBus address offsets */
-+static unsigned short vt596_smba;
-+#define SMBHSTSTS (vt596_smba + 0)
-+#define SMBHSLVSTS (vt596_smba + 1)
-+#define SMBHSTCNT (vt596_smba + 2)
-+#define SMBHSTCMD (vt596_smba + 3)
-+#define SMBHSTADD (vt596_smba + 4)
-+#define SMBHSTDAT0 (vt596_smba + 5)
-+#define SMBHSTDAT1 (vt596_smba + 6)
-+#define SMBBLKDAT (vt596_smba + 7)
-+#define SMBSLVCNT (vt596_smba + 8)
-+#define SMBSHDWCMD (vt596_smba + 9)
-+#define SMBSLVEVT (vt596_smba + 0xA)
-+#define SMBSLVDAT (vt596_smba + 0xC)
-+
-+/* PCI Address Constants */
-+
-+/* SMBus data in configuration space can be found in two places,
-+ We try to select the better one*/
-+
-+static unsigned short smb_cf_hstcfg = 0xD2;
-+
-+#define SMBHSTCFG (smb_cf_hstcfg)
-+#define SMBSLVC (smb_cf_hstcfg + 1)
-+#define SMBSHDW1 (smb_cf_hstcfg + 2)
-+#define SMBSHDW2 (smb_cf_hstcfg + 3)
-+#define SMBREV (smb_cf_hstcfg + 4)
-+
-+/* Other settings */
-+#define MAX_TIMEOUT 500
-+#define ENABLE_INT9 0
-+
-+/* VT82C596 constants */
-+#define VT596_QUICK 0x00
-+#define VT596_BYTE 0x04
-+#define VT596_BYTE_DATA 0x08
-+#define VT596_WORD_DATA 0x0C
-+#define VT596_BLOCK_DATA 0x14
-+
-+
-+/* If force is set to anything different from 0, we forcibly enable the
-+ VT596. DANGEROUS! */
-+static int force;
-+MODULE_PARM(force, "i");
-+MODULE_PARM_DESC(force, "Forcibly enable the SMBus. DANGEROUS!");
-+
-+/* If force_addr is set to anything different from 0, we forcibly enable
-+ the VT596 at the given address. VERY DANGEROUS! */
-+static int force_addr;
-+MODULE_PARM(force_addr, "i");
-+MODULE_PARM_DESC(force_addr,
-+ "Forcibly enable the SMBus at the given address. "
-+ "EXTREMELY DANGEROUS!");
-+
-+
-+static struct i2c_adapter vt596_adapter;
-+
-+/* Another internally used function */
-+static int vt596_transaction(void)
-+{
-+ int temp;
-+ int result = 0;
-+ int timeout = 0;
-+
-+ dev_dbg(&vt596_adapter, "Transaction (pre): CNT=%02x, CMD=%02x, "
-+ "ADD=%02x, DAT0=%02x, DAT1=%02x\n", inb_p(SMBHSTCNT),
-+ inb_p(SMBHSTCMD), inb_p(SMBHSTADD), inb_p(SMBHSTDAT0),
-+ inb_p(SMBHSTDAT1));
-+
-+ /* Make sure the SMBus host is ready to start transmitting */
-+ if ((temp = inb_p(SMBHSTSTS)) != 0x00) {
-+ dev_dbg(&vt596_adapter, "SMBus busy (0x%02x). "
-+ "Resetting...\n", temp);
-+
-+ outb_p(temp, SMBHSTSTS);
-+ if ((temp = inb_p(SMBHSTSTS)) != 0x00) {
-+ dev_dbg(&vt596_adapter, "Failed! (0x%02x)\n", temp);
-+
-+ return -1;
-+ } else {
-+ dev_dbg(&vt596_adapter, "Successfull!\n");
-+ }
-+ }
-+
-+ /* start the transaction by setting bit 6 */
-+ outb_p(inb(SMBHSTCNT) | 0x040, SMBHSTCNT);
-+
-+ /* We will always wait for a fraction of a second!
-+ I don't know if VIA needs this, Intel did */
-+ do {
-+ i2c_delay(1);
-+ temp = inb_p(SMBHSTSTS);
-+ } while ((temp & 0x01) && (timeout++ < MAX_TIMEOUT));
-+
-+ /* If the SMBus is still busy, we give up */
-+ if (timeout >= MAX_TIMEOUT) {
-+ result = -1;
-+ dev_dbg(&vt596_adapter, "SMBus Timeout!\n");
-+ }
-+
-+ if (temp & 0x10) {
-+ result = -1;
-+ dev_dbg(&vt596_adapter, "Error: Failed bus transaction\n");
-+ }
-+
-+ if (temp & 0x08) {
-+ result = -1;
-+ dev_info(&vt596_adapter, "Bus collision! SMBus may be "
-+ "locked until next hard\nreset. (sorry!)\n");
-+ /* Clock stops and slave is stuck in mid-transmission */
-+ }
-+
-+ if (temp & 0x04) {
-+ result = -1;
-+ dev_dbg(&vt596_adapter, "Error: no response!\n");
-+ }
-+
-+ if (inb_p(SMBHSTSTS) != 0x00)
-+ outb_p(inb(SMBHSTSTS), SMBHSTSTS);
-+
-+ if ((temp = inb_p(SMBHSTSTS)) != 0x00) {
-+ dev_dbg(&vt596_adapter, "Failed reset at end of "
-+ "transaction (%02x)\n", temp);
-+ }
-+ dev_dbg(&vt596_adapter, "Transaction (post): CNT=%02x, CMD=%02x, "
-+ "ADD=%02x, DAT0=%02x, DAT1=%02x\n", inb_p(SMBHSTCNT),
-+ inb_p(SMBHSTCMD), inb_p(SMBHSTADD), inb_p(SMBHSTDAT0),
-+ inb_p(SMBHSTDAT1));
-+
-+ return result;
-+}
-+
-+/* Return -1 on error. */
-+static s32 vt596_access(struct i2c_adapter *adap, u16 addr,
-+ unsigned short flags, char read_write, u8 command,
-+ int size, union i2c_smbus_data *data)
-+{
-+ int i, len;
-+
-+ switch (size) {
-+ case I2C_SMBUS_QUICK:
-+ outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),
-+ SMBHSTADD);
-+ size = VT596_QUICK;
-+ break;
-+ case I2C_SMBUS_BYTE:
-+ outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),
-+ SMBHSTADD);
-+ if (read_write == I2C_SMBUS_WRITE)
-+ outb_p(command, SMBHSTCMD);
-+ size = VT596_BYTE;
-+ break;
-+ case I2C_SMBUS_BYTE_DATA:
-+ outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),
-+ SMBHSTADD);
-+ outb_p(command, SMBHSTCMD);
-+ if (read_write == I2C_SMBUS_WRITE)
-+ outb_p(data->byte, SMBHSTDAT0);
-+ size = VT596_BYTE_DATA;
-+ break;
-+ case I2C_SMBUS_WORD_DATA:
-+ outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),
-+ SMBHSTADD);
-+ outb_p(command, SMBHSTCMD);
-+ if (read_write == I2C_SMBUS_WRITE) {
-+ outb_p(data->word & 0xff, SMBHSTDAT0);
-+ outb_p((data->word & 0xff00) >> 8, SMBHSTDAT1);
-+ }
-+ size = VT596_WORD_DATA;
-+ break;
-+ case I2C_SMBUS_BLOCK_DATA:
-+ outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),
-+ SMBHSTADD);
-+ outb_p(command, SMBHSTCMD);
-+ if (read_write == I2C_SMBUS_WRITE) {
-+ len = data->block[0];
-+ if (len < 0)
-+ len = 0;
-+ if (len > 32)
-+ len = 32;
-+ outb_p(len, SMBHSTDAT0);
-+ i = inb_p(SMBHSTCNT); /* Reset SMBBLKDAT */
-+ for (i = 1; i <= len; i++)
-+ outb_p(data->block[i], SMBBLKDAT);
-+ }
-+ size = VT596_BLOCK_DATA;
-+ break;
-+ default:
-+ dev_warn(&vt596_adapter, "Unsupported transaction %d\n", size);
-+ return -1;
-+ }
-+
-+ outb_p((size & 0x1C) + (ENABLE_INT9 & 1), SMBHSTCNT);
-+
-+ if (vt596_transaction()) /* Error in transaction */
-+ return -1;
-+
-+ if ((read_write == I2C_SMBUS_WRITE) || (size == VT596_QUICK))
-+ return 0;
-+
-+ switch (size) {
-+ case VT596_BYTE:
-+ /* Where is the result put? I assume here it is in
-+ * SMBHSTDAT0 but it might just as well be in the
-+ * SMBHSTCMD. No clue in the docs
-+ */
-+ data->byte = inb_p(SMBHSTDAT0);
-+ break;
-+ case VT596_BYTE_DATA:
-+ data->byte = inb_p(SMBHSTDAT0);
-+ break;
-+ case VT596_WORD_DATA:
-+ data->word = inb_p(SMBHSTDAT0) + (inb_p(SMBHSTDAT1) << 8);
-+ break;
-+ case VT596_BLOCK_DATA:
-+ data->block[0] = inb_p(SMBHSTDAT0);
-+ if (data->block[0] > 32)
-+ data->block[0] = 32;
-+ i = inb_p(SMBHSTCNT); /* Reset SMBBLKDAT */
-+ for (i = 1; i <= data->block[0]; i++)
-+ data->block[i] = inb_p(SMBBLKDAT);
-+ break;
-+ }
-+ return 0;
-+}
-+
-+static u32 vt596_func(struct i2c_adapter *adapter)
-+{
-+ return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
-+ I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
-+ I2C_FUNC_SMBUS_BLOCK_DATA;
-+}
-+
-+static struct i2c_algorithm smbus_algorithm = {
-+ .name = "Non-I2C SMBus adapter",
-+ .id = I2C_ALGO_SMBUS,
-+ .smbus_xfer = vt596_access,
-+ .functionality = vt596_func,
-+};
-+
-+static struct i2c_adapter vt596_adapter = {
-+ .owner = THIS_MODULE,
-+ .id = I2C_ALGO_SMBUS | I2C_HW_SMBUS_VIA2,
-+ .algo = &smbus_algorithm,
-+ .name = "unset",
-+};
-+
-+static int __devinit vt596_probe(struct pci_dev *pdev,
-+ const struct pci_device_id *id)
-+{
-+ unsigned char temp;
-+ int error = -ENODEV;
-+
-+ /* Determine the address of the SMBus areas */
-+ if (force_addr) {
-+ vt596_smba = force_addr & 0xfff0;
-+ force = 0;
-+ goto found;
-+ }
-+
-+ if ((pci_read_config_word(pdev, id->driver_data, &vt596_smba)) ||
-+ !(vt596_smba & 0x1)) {
-+ /* try 2nd address and config reg. for 596 */
-+ if (id->device == PCI_DEVICE_ID_VIA_82C596_3 &&
-+ !pci_read_config_word(pdev, SMBBA2, &vt596_smba) &&
-+ (vt596_smba & 0x1)) {
-+ smb_cf_hstcfg = 0x84;
-+ } else {
-+ /* no matches at all */
-+ dev_err(pdev, "Cannot configure "
-+ "SMBus I/O Base address\n");
-+ return -ENODEV;
-+ }
-+ }
-+
-+ vt596_smba &= 0xfff0;
-+ if (vt596_smba == 0) {
-+ dev_err(pdev, "SMBus base address "
-+ "uninitialized - upgrade BIOS or use "
-+ "force_addr=0xaddr\n");
-+ return -ENODEV;
-+ }
-+
-+ found:
-+ if (!request_region(vt596_smba, 8, "viapro-smbus")) {
-+ dev_err(pdev, "SMBus region 0x%x already in use!\n",
-+ vt596_smba);
-+ return -ENODEV;
-+ }
-+
-+ pci_read_config_byte(pdev, SMBHSTCFG, &temp);
-+ /* If force_addr is set, we program the new address here. Just to make
-+ sure, we disable the VT596 first. */
-+ if (force_addr) {
-+ pci_write_config_byte(pdev, SMBHSTCFG, temp & 0xfe);
-+ pci_write_config_word(pdev, id->driver_data, vt596_smba);
-+ pci_write_config_byte(pdev, SMBHSTCFG, temp | 0x01);
-+ dev_warn(pdev, "WARNING: SMBus interface set to new "
-+ "address 0x%04x!\n", vt596_smba);
-+ } else if ((temp & 1) == 0) {
-+ if (force) {
-+ /* NOTE: This assumes I/O space and other allocations
-+ * WERE done by the Bios! Don't complain if your
-+ * hardware does weird things after enabling this.
-+ * :') Check for Bios updates before resorting to
-+ * this.
-+ */
-+ pci_write_config_byte(pdev, SMBHSTCFG, temp | 1);
-+ dev_info(pdev, "Enabling SMBus device\n");
-+ } else {
-+ dev_err(pdev, "SMBUS: Error: Host SMBus "
-+ "controller not enabled! - upgrade BIOS or "
-+ "use force=1\n");
-+ goto release_region;
-+ }
-+ }
-+
-+ if ((temp & 0x0E) == 8)
-+ dev_dbg(pdev, "using Interrupt 9 for SMBus.\n");
-+ else if ((temp & 0x0E) == 0)
-+ dev_dbg(pdev, "using Interrupt SMI# for SMBus.\n");
-+ else
-+ dev_dbg(pdev, "Illegal Interrupt configuration "
-+ "(or code out of date)!\n");
-+
-+ pci_read_config_byte(pdev, SMBREV, &temp);
-+ dev_dbg(pdev, "SMBREV = 0x%X\n", temp);
-+ dev_dbg(pdev, "VT596_smba = 0x%X\n", vt596_smba);
-+
-+ snprintf(vt596_adapter.name, 32,
-+ "SMBus Via Pro adapter at %04x", vt596_smba);
-+
-+ return i2c_add_adapter(&vt596_adapter);
-+
-+ release_region:
-+ release_region(vt596_smba, 8);
-+ return error;
-+}
-+
-+static void __devexit vt596_remove(struct pci_dev *pdev)
-+{
-+ i2c_del_adapter(&vt596_adapter);
-+ release_region(vt596_smba, 8);
-+}
-+
-+/* 8233A is undefined before kernel 2.4.19 */
-+#ifndef PCI_DEVICE_ID_VIA_8233A
-+#define PCI_DEVICE_ID_VIA_8233A 0x3147
-+#endif
-+/* 8235 is undefined before kernel 2.4.20 */
-+#ifndef PCI_DEVICE_ID_VIA_8235
-+#define PCI_DEVICE_ID_VIA_8235 0x3177
-+#endif
-+/* 8237 is undefined before kernel 2.4.21 */
-+#ifndef PCI_DEVICE_ID_VIA_8237
-+#define PCI_DEVICE_ID_VIA_8237 0x3227
-+#endif
-+static struct pci_device_id vt596_ids[] __devinitdata = {
-+ {
-+ .vendor = PCI_VENDOR_ID_VIA,
-+ .device = PCI_DEVICE_ID_VIA_82C596_3,
-+ .subvendor = PCI_ANY_ID,
-+ .subdevice = PCI_ANY_ID,
-+ .driver_data = SMBBA1,
-+ },
-+ {
-+ .vendor = PCI_VENDOR_ID_VIA,
-+ .device = PCI_DEVICE_ID_VIA_82C596B_3,
-+ .subvendor = PCI_ANY_ID,
-+ .subdevice = PCI_ANY_ID,
-+ .driver_data = SMBBA1,
-+ },
-+ {
-+ .vendor = PCI_VENDOR_ID_VIA,
-+ .device = PCI_DEVICE_ID_VIA_82C686_4,
-+ .subvendor = PCI_ANY_ID,
-+ .subdevice = PCI_ANY_ID,
-+ .driver_data = SMBBA1,
-+ },
-+ {
-+ .vendor = PCI_VENDOR_ID_VIA,
-+ .device = PCI_DEVICE_ID_VIA_8233_0,
-+ .subvendor = PCI_ANY_ID,
-+ .subdevice = PCI_ANY_ID,
-+ .driver_data = SMBBA3
-+ },
-+ {
-+ .vendor = PCI_VENDOR_ID_VIA,
-+ .device = PCI_DEVICE_ID_VIA_8233A,
-+ .subvendor = PCI_ANY_ID,
-+ .subdevice = PCI_ANY_ID,
-+ .driver_data = SMBBA3,
-+ },
-+ {
-+ .vendor = PCI_VENDOR_ID_VIA,
-+ .device = PCI_DEVICE_ID_VIA_8235,
-+ .subvendor = PCI_ANY_ID,
-+ .subdevice = PCI_ANY_ID,
-+ .driver_data = SMBBA3
-+ },
-+ {
-+ .vendor = PCI_VENDOR_ID_VIA,
-+ .device = PCI_DEVICE_ID_VIA_8237,
-+ .subvendor = PCI_ANY_ID,
-+ .subdevice = PCI_ANY_ID,
-+ .driver_data = SMBBA3
-+ },
-+ {
-+ .vendor = PCI_VENDOR_ID_VIA,
-+ .device = PCI_DEVICE_ID_VIA_8231_4,
-+ .subvendor = PCI_ANY_ID,
-+ .subdevice = PCI_ANY_ID,
-+ .driver_data = SMBBA1,
-+ },
-+ { 0, }
-+};
-+
-+/* Don't register driver to avoid driver conflicts */
-+/*
-+static struct pci_driver vt596_driver = {
-+ .name = "vt596 smbus",
-+ .id_table = vt596_ids,
-+ .probe = vt596_probe,
-+ .remove = __devexit_p(vt596_remove),
-+};
-+*/
-+
-+static int __init i2c_vt596_init(void)
-+{
-+ struct pci_dev *dev;
-+ const struct pci_device_id *id;
-+
-+ printk("i2c-viapro.o version %s (%s)\n", LM_VERSION, LM_DATE);
-+/*
-+ return pci_module_init(&vt596_driver);
-+*/
-+ pci_for_each_dev(dev) {
-+ id = pci_match_device(vt596_ids, dev);
-+ if(id)
-+ if(vt596_probe(dev, id) >= 0)
-+ return 0;
-+ }
-+ return -ENODEV;
-+}
-+
-+
-+static void __exit i2c_vt596_exit(void)
-+{
-+/*
-+ pci_unregister_driver(&vt596_driver);
-+*/
-+ vt596_remove(NULL);
-+}
-+
-+MODULE_AUTHOR(
-+ "Frodo Looijaard <frodol@dds.nl> and "
-+ "Philip Edelbrock <phil@netroedge.com>");
-+MODULE_DESCRIPTION("vt82c596 SMBus driver");
-+MODULE_LICENSE("GPL");
-+
-+module_init(i2c_vt596_init);
-+module_exit(i2c_vt596_exit);
---- linux-old/drivers/i2c/i2c-voodoo3.c Thu Jan 1 00:00:00 1970
-+++ linux/drivers/i2c/i2c-voodoo3.c Mon Dec 13 20:18:43 2004
-@@ -0,0 +1,281 @@
-+/*
-+ voodoo3.c - Part of lm_sensors, Linux kernel modules for hardware
-+ monitoring
-+ Copyright (c) 1998, 1999 Frodo Looijaard <frodol@dds.nl>,
-+ Philip Edelbrock <phil@netroedge.com>,
-+ Ralph Metzler <rjkm@thp.uni-koeln.de>, and
-+ Mark D. Studebaker <mdsxyz123@yahoo.com>
-+
-+ Based on code written by Ralph Metzler <rjkm@thp.uni-koeln.de> and
-+ Simon Vogl
-+
-+ 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., 675 Mass Ave, Cambridge, MA 02139, USA.
-+*/
-+
-+/* This interfaces to the I2C bus of the Voodoo3 to gain access to
-+ the BT869 and possibly other I2C devices. */
-+
-+#include <linux/module.h>
-+#include <linux/pci.h>
-+#include <linux/i2c.h>
-+#include <linux/i2c-algo-bit.h>
-+#include <linux/init.h>
-+#include <asm/io.h>
-+#include <asm/param.h> /* for HZ */
-+#define LM_DATE "20041007"
-+#define LM_VERSION "2.8.8"
-+
-+MODULE_LICENSE("GPL");
-+
-+/* the only registers we use */
-+#define REG 0x78
-+#define REG2 0x70
-+
-+/* bit locations in the register */
-+#define DDC_ENAB 0x00040000
-+#define DDC_SCL_OUT 0x00080000
-+#define DDC_SDA_OUT 0x00100000
-+#define DDC_SCL_IN 0x00200000
-+#define DDC_SDA_IN 0x00400000
-+#define I2C_ENAB 0x00800000
-+#define I2C_SCL_OUT 0x01000000
-+#define I2C_SDA_OUT 0x02000000
-+#define I2C_SCL_IN 0x04000000
-+#define I2C_SDA_IN 0x08000000
-+
-+/* initialization states */
-+#define INIT2 0x2
-+#define INIT3 0x4
-+
-+/* delays */
-+#define CYCLE_DELAY 10
-+#define TIMEOUT (HZ / 2)
-+
-+
-+static void config_v3(struct pci_dev *dev);
-+
-+static unsigned long ioaddr;
-+
-+/* The voo GPIO registers don't have individual masks for each bit
-+ so we always have to read before writing. */
-+
-+static void bit_vooi2c_setscl(void *data, int val)
-+{
-+ unsigned int r;
-+ r = readl(ioaddr + REG);
-+ if(val)
-+ r |= I2C_SCL_OUT;
-+ else
-+ r &= ~I2C_SCL_OUT;
-+ writel(r, ioaddr + REG);
-+ readl(ioaddr + REG); /* flush posted write */
-+}
-+
-+static void bit_vooi2c_setsda(void *data, int val)
-+{
-+ unsigned int r;
-+ r = readl(ioaddr + REG);
-+ if(val)
-+ r |= I2C_SDA_OUT;
-+ else
-+ r &= ~I2C_SDA_OUT;
-+ writel(r, ioaddr + REG);
-+ readl(ioaddr + REG); /* flush posted write */
-+}
-+
-+/* The GPIO pins are open drain, so the pins always remain outputs.
-+ We rely on the i2c-algo-bit routines to set the pins high before
-+ reading the input from other chips. */
-+
-+static int bit_vooi2c_getscl(void *data)
-+{
-+ return (0 != (readl(ioaddr + REG) & I2C_SCL_IN));
-+}
-+
-+static int bit_vooi2c_getsda(void *data)
-+{
-+ return (0 != (readl(ioaddr + REG) & I2C_SDA_IN));
-+}
-+
-+static void bit_vooddc_setscl(void *data, int val)
-+{
-+ unsigned int r;
-+ r = readl(ioaddr + REG);
-+ if(val)
-+ r |= DDC_SCL_OUT;
-+ else
-+ r &= ~DDC_SCL_OUT;
-+ writel(r, ioaddr + REG);
-+ readl(ioaddr + REG); /* flush posted write */
-+}
-+
-+static void bit_vooddc_setsda(void *data, int val)
-+{
-+ unsigned int r;
-+ r = readl(ioaddr + REG);
-+ if(val)
-+ r |= DDC_SDA_OUT;
-+ else
-+ r &= ~DDC_SDA_OUT;
-+ writel(r, ioaddr + REG);
-+ readl(ioaddr + REG); /* flush posted write */
-+}
-+
-+static int bit_vooddc_getscl(void *data)
-+{
-+ return (0 != (readl(ioaddr + REG) & DDC_SCL_IN));
-+}
-+
-+static int bit_vooddc_getsda(void *data)
-+{
-+ return (0 != (readl(ioaddr + REG) & DDC_SDA_IN));
-+}
-+
-+
-+/* Configures the chip */
-+
-+void config_v3(struct pci_dev *dev)
-+{
-+ unsigned int cadr;
-+
-+ /* map Voodoo3 memory */
-+ cadr = dev->resource[0].start;
-+ cadr &= PCI_BASE_ADDRESS_MEM_MASK;
-+ ioaddr = (unsigned long)ioremap_nocache(cadr, 0x1000);
-+ if(ioaddr) {
-+ writel(0x8160, ioaddr + REG2);
-+ writel(0xcffc0020, ioaddr + REG);
-+ printk("i2c-voodoo3: Using Banshee/Voodoo3 at 0x%lx\n", ioaddr);
-+ }
-+}
-+
-+static struct i2c_algo_bit_data voo_i2c_bit_data = {
-+ .setsda = bit_vooi2c_setsda,
-+ .setscl = bit_vooi2c_setscl,
-+ .getsda = bit_vooi2c_getsda,
-+ .getscl = bit_vooi2c_getscl,
-+ .udelay = CYCLE_DELAY,
-+ .mdelay = CYCLE_DELAY,
-+ .timeout = TIMEOUT
-+};
-+
-+static struct i2c_adapter voodoo3_i2c_adapter = {
-+ .owner = THIS_MODULE,
-+ .name = "I2C Voodoo3/Banshee adapter",
-+ .id = I2C_HW_B_VOO,
-+ .algo_data = &voo_i2c_bit_data,
-+};
-+
-+static struct i2c_algo_bit_data voo_ddc_bit_data = {
-+ .setsda = bit_vooddc_setsda,
-+ .setscl = bit_vooddc_setscl,
-+ .getsda = bit_vooddc_getsda,
-+ .getscl = bit_vooddc_getscl,
-+ .udelay = CYCLE_DELAY,
-+ .mdelay = CYCLE_DELAY,
-+ .timeout = TIMEOUT
-+};
-+
-+static struct i2c_adapter voodoo3_ddc_adapter = {
-+ .owner = THIS_MODULE,
-+ .name = "DDC Voodoo3/Banshee adapter",
-+ .id = I2C_HW_B_VOO,
-+ .algo_data = &voo_ddc_bit_data,
-+};
-+
-+
-+static struct pci_device_id voodoo3_ids[] __devinitdata = {
-+ {
-+ .vendor = PCI_VENDOR_ID_3DFX,
-+ .device = PCI_DEVICE_ID_3DFX_VOODOO3,
-+ .subvendor = PCI_ANY_ID,
-+ .subdevice = PCI_ANY_ID,
-+ },
-+ {
-+ .vendor = PCI_VENDOR_ID_3DFX,
-+ .device = PCI_DEVICE_ID_3DFX_BANSHEE,
-+ .subvendor = PCI_ANY_ID,
-+ .subdevice = PCI_ANY_ID,
-+ },
-+ { 0, }
-+};
-+
-+static int __devinit voodoo3_probe(struct pci_dev *dev, const struct pci_device_id *id)
-+{
-+ int retval;
-+
-+ printk("voodoo3: in probe\n");
-+ config_v3(dev);
-+ retval = i2c_bit_add_bus(&voodoo3_i2c_adapter);
-+ if(retval)
-+ return retval;
-+ retval = i2c_bit_add_bus(&voodoo3_ddc_adapter);
-+ if(retval)
-+ i2c_bit_del_bus(&voodoo3_i2c_adapter);
-+ return retval;
-+}
-+
-+static void __devexit voodoo3_remove(struct pci_dev *dev)
-+{
-+ i2c_bit_del_bus(&voodoo3_i2c_adapter);
-+ i2c_bit_del_bus(&voodoo3_ddc_adapter);
-+}
-+
-+
-+/* Don't register driver to avoid driver conflicts */
-+/*
-+static struct pci_driver voodoo3_driver = {
-+ .name = "voodoo3 smbus",
-+ .id_table = voodoo3_ids,
-+ .probe = voodoo3_probe,
-+ .remove = __devexit_p(voodoo3_remove),
-+};
-+*/
-+
-+static int __init i2c_voodoo3_init(void)
-+{
-+ struct pci_dev *dev;
-+ const struct pci_device_id *id;
-+
-+ printk("i2c-voodoo3.o version %s (%s)\n", LM_VERSION, LM_DATE);
-+/*
-+ return pci_module_init(&voodoo3_driver);
-+*/
-+ pci_for_each_dev(dev) {
-+ id = pci_match_device(voodoo3_ids, dev);
-+ if(id)
-+ if(voodoo3_probe(dev, id) >= 0)
-+ return 0;
-+ }
-+ return -ENODEV;
-+}
-+
-+
-+static void __exit i2c_voodoo3_exit(void)
-+{
-+/*
-+ pci_unregister_driver(&voodoo3_driver);
-+*/
-+ voodoo3_remove(NULL);
-+ iounmap((void *)ioaddr);
-+}
-+
-+
-+MODULE_AUTHOR
-+ ("Frodo Looijaard <frodol@dds.nl>, Philip Edelbrock <phil@netroedge.com>, Ralph Metzler <rjkm@thp.uni-koeln.de>, and Mark D. Studebaker <mdsxyz123@yahoo.com>");
-+MODULE_DESCRIPTION("Voodoo3 I2C/SMBus driver");
-+
-+module_init(i2c_voodoo3_init);
-+module_exit(i2c_voodoo3_exit);
---- linux-old/drivers/sensors/adm1021.c Thu Jan 1 00:00:00 1970
-+++ linux/drivers/sensors/adm1021.c Mon Dec 13 20:18:43 2004
-@@ -0,0 +1,594 @@
-+/*
-+ adm1021.c - Part of lm_sensors, Linux kernel modules for hardware
-+ monitoring
-+ Copyright (c) 1998, 1999 Frodo Looijaard <frodol@dds.nl> and
-+ Philip Edelbrock <phil@netroedge.com>
-+
-+ 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., 675 Mass Ave, Cambridge, MA 02139, USA.
-+*/
-+
-+#include <linux/module.h>
-+#include <linux/slab.h>
-+#include <linux/i2c.h>
-+#include <linux/i2c-proc.h>
-+#include <linux/init.h>
-+#define LM_DATE "20041007"
-+#define LM_VERSION "2.8.8"
-+
-+/* Addresses to scan */
-+static unsigned short normal_i2c[] = { SENSORS_I2C_END };
-+static unsigned short normal_i2c_range[] = { 0x18, 0x1a, 0x29, 0x2b,
-+ 0x4c, 0x4e, SENSORS_I2C_END
-+};
-+static unsigned int normal_isa[] = { SENSORS_ISA_END };
-+static unsigned int normal_isa_range[] = { SENSORS_ISA_END };
-+
-+/* Insmod parameters */
-+SENSORS_INSMOD_8(adm1021, adm1023, max1617, max1617a, thmc10, lm84, gl523sm, mc1066);
-+
-+/* adm1021 constants specified below */
-+
-+/* The adm1021 registers */
-+/* Read-only */
-+#define ADM1021_REG_TEMP 0x00
-+#define ADM1021_REG_REMOTE_TEMP 0x01
-+#define ADM1021_REG_STATUS 0x02
-+#define ADM1021_REG_MAN_ID 0x0FE /* 0x41 = Analog Devices, 0x49 = TI,
-+ 0x4D = Maxim, 0x23 = Genesys , 0x54 = Onsemi*/
-+#define ADM1021_REG_DEV_ID 0x0FF /* ADM1021 = 0x0X, ADM1021A/ADM1023 = 0x3X */
-+#define ADM1021_REG_DIE_CODE 0x0FF /* MAX1617A */
-+/* These use different addresses for reading/writing */
-+#define ADM1021_REG_CONFIG_R 0x03
-+#define ADM1021_REG_CONFIG_W 0x09
-+#define ADM1021_REG_CONV_RATE_R 0x04
-+#define ADM1021_REG_CONV_RATE_W 0x0A
-+/* These are for the ADM1023's additional precision on the remote temp sensor */
-+#define ADM1021_REG_REM_TEMP_PREC 0x010
-+#define ADM1021_REG_REM_OFFSET 0x011
-+#define ADM1021_REG_REM_OFFSET_PREC 0x012
-+#define ADM1021_REG_REM_TOS_PREC 0x013
-+#define ADM1021_REG_REM_THYST_PREC 0x014
-+/* limits */
-+#define ADM1021_REG_TOS_R 0x05
-+#define ADM1021_REG_TOS_W 0x0B
-+#define ADM1021_REG_REMOTE_TOS_R 0x07
-+#define ADM1021_REG_REMOTE_TOS_W 0x0D
-+#define ADM1021_REG_THYST_R 0x06
-+#define ADM1021_REG_THYST_W 0x0C
-+#define ADM1021_REG_REMOTE_THYST_R 0x08
-+#define ADM1021_REG_REMOTE_THYST_W 0x0E
-+/* write-only */
-+#define ADM1021_REG_ONESHOT 0x0F
-+
-+#define ADM1021_ALARM_TEMP (ADM1021_ALARM_TEMP_HIGH | ADM1021_ALARM_TEMP_LOW)
-+#define ADM1021_ALARM_RTEMP (ADM1021_ALARM_RTEMP_HIGH | ADM1021_ALARM_RTEMP_LOW\
-+ | ADM1021_ALARM_RTEMP_NA)
-+#define ADM1021_ALARM_ALL (ADM1021_ALARM_TEMP | ADM1021_ALARM_RTEMP)
-+
-+/* Conversions. Rounding and limit checking is only done on the TO_REG
-+ variants. Note that you should be a bit careful with which arguments
-+ these macros are called: arguments may be evaluated more than once.
-+ Fixing this is just not worth it. */
-+/* Conversions note: 1021 uses normal integer signed-byte format*/
-+#define TEMP_FROM_REG(val) (val > 127 ? val-256 : val)
-+#define TEMP_TO_REG(val) (SENSORS_LIMIT((val < 0 ? val+256 : val),0,255))
-+
-+/* Each client has this additional data */
-+struct adm1021_data {
-+ struct i2c_client client;
-+ int sysctl_id;
-+ enum chips type;
-+
-+ struct semaphore update_lock;
-+ char valid; /* !=0 if following fields are valid */
-+ unsigned long last_updated; /* In jiffies */
-+
-+ u8 temp, temp_os, temp_hyst; /* Register values */
-+ u8 remote_temp, remote_temp_os, remote_temp_hyst, alarms, die_code;
-+ u8 fail;
-+ /* Special values for ADM1023 only */
-+ u8 remote_temp_prec, remote_temp_os_prec, remote_temp_hyst_prec,
-+ remote_temp_offset, remote_temp_offset_prec;
-+};
-+
-+static int adm1021_attach_adapter(struct i2c_adapter *adapter);
-+static int adm1021_detect(struct i2c_adapter *adapter, int address,
-+ unsigned short flags, int kind);
-+static void adm1021_init_client(struct i2c_client *client);
-+static int adm1021_detach_client(struct i2c_client *client);
-+static int adm1021_read_value(struct i2c_client *client, u8 reg);
-+static int adm1021_rd_good(u8 *val, struct i2c_client *client, u8 reg, u8 mask);
-+static int adm1021_write_value(struct i2c_client *client, u8 reg,
-+ u16 value);
-+static void adm1021_temp(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void adm1021_remote_temp(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag,
-+ long *results);
-+static void adm1021_alarms(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void adm1021_die_code(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void adm1021_update_client(struct i2c_client *client);
-+
-+/* (amalysh) read only mode, otherwise any limit's writing confuse BIOS */
-+static int read_only = 0;
-+
-+
-+/* This is the driver that will be inserted */
-+static struct i2c_driver adm1021_driver = {
-+ .owner = THIS_MODULE,
-+ .name = "ADM1021, MAX1617 sensor driver",
-+ .id = I2C_DRIVERID_ADM1021,
-+ .flags = I2C_DF_NOTIFY,
-+ .attach_adapter = adm1021_attach_adapter,
-+ .detach_client = adm1021_detach_client,
-+};
-+
-+/* -- SENSORS SYSCTL START -- */
-+
-+#define ADM1021_SYSCTL_TEMP 1200
-+#define ADM1021_SYSCTL_REMOTE_TEMP 1201
-+#define ADM1021_SYSCTL_DIE_CODE 1202
-+#define ADM1021_SYSCTL_ALARMS 1203
-+
-+#define ADM1021_ALARM_TEMP_HIGH 0x40
-+#define ADM1021_ALARM_TEMP_LOW 0x20
-+#define ADM1021_ALARM_RTEMP_HIGH 0x10
-+#define ADM1021_ALARM_RTEMP_LOW 0x08
-+#define ADM1021_ALARM_RTEMP_NA 0x04
-+
-+/* -- SENSORS SYSCTL END -- */
-+
-+/* These files are created for each detected adm1021. This is just a template;
-+ though at first sight, you might think we could use a statically
-+ allocated list, we need some way to get back to the parent - which
-+ is done through one of the 'extra' fields which are initialized
-+ when a new copy is allocated. */
-+static ctl_table adm1021_dir_table_template[] = {
-+ {ADM1021_SYSCTL_TEMP, "temp1", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &adm1021_temp},
-+ {ADM1021_SYSCTL_REMOTE_TEMP, "temp2", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &adm1021_remote_temp},
-+ {ADM1021_SYSCTL_DIE_CODE, "die_code", NULL, 0, 0444, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &adm1021_die_code},
-+ {ADM1021_SYSCTL_ALARMS, "alarms", NULL, 0, 0444, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &adm1021_alarms},
-+ {0}
-+};
-+
-+static ctl_table adm1021_max_dir_table_template[] = {
-+ {ADM1021_SYSCTL_TEMP, "temp1", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &adm1021_temp},
-+ {ADM1021_SYSCTL_REMOTE_TEMP, "temp2", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &adm1021_remote_temp},
-+ {ADM1021_SYSCTL_ALARMS, "alarms", NULL, 0, 0444, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &adm1021_alarms},
-+ {0}
-+};
-+
-+static int adm1021_id = 0;
-+
-+static int adm1021_attach_adapter(struct i2c_adapter *adapter)
-+{
-+ return i2c_detect(adapter, &addr_data, adm1021_detect);
-+}
-+
-+static int adm1021_detect(struct i2c_adapter *adapter, int address,
-+ unsigned short flags, int kind)
-+{
-+ int i;
-+ struct i2c_client *new_client;
-+ struct adm1021_data *data;
-+ int err = 0;
-+ const char *type_name = "";
-+ const char *client_name = "";
-+
-+ /* Make sure we aren't probing the ISA bus!! This is just a safety check
-+ at this moment; i2c_detect really won't call us. */
-+#ifdef DEBUG
-+ if (i2c_is_isa_adapter(adapter)) {
-+ printk
-+ ("adm1021.o: adm1021_detect called for an ISA bus adapter?!?\n");
-+ return 0;
-+ }
-+#endif
-+
-+ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
-+ goto error0;
-+
-+ /* OK. For now, we presume we have a valid client. We now create the
-+ client structure, even though we cannot fill it completely yet.
-+ But it allows us to access adm1021_{read,write}_value. */
-+
-+ if (!(data = kmalloc(sizeof(struct adm1021_data), GFP_KERNEL))) {
-+ err = -ENOMEM;
-+ goto error0;
-+ }
-+
-+ new_client = &data->client;
-+ new_client->addr = address;
-+ new_client->data = data;
-+ new_client->adapter = adapter;
-+ new_client->driver = &adm1021_driver;
-+ new_client->flags = 0;
-+
-+ /* Now, we do the remaining detection. */
-+
-+ if (kind < 0) {
-+ if ((adm1021_read_value(new_client, ADM1021_REG_STATUS) & 0x03) != 0x00
-+ || (adm1021_read_value(new_client, ADM1021_REG_CONFIG_R) & 0x3F) != 0x00
-+ || (adm1021_read_value(new_client, ADM1021_REG_CONV_RATE_R) & 0xF8) != 0x00) {
-+ err = -ENODEV;
-+ goto error1;
-+ }
-+ }
-+
-+ /* Determine the chip type. */
-+
-+ if (kind <= 0) {
-+ i = adm1021_read_value(new_client, ADM1021_REG_MAN_ID);
-+ if (i == 0x41)
-+ if ((adm1021_read_value (new_client, ADM1021_REG_DEV_ID) & 0xF0) == 0x30)
-+ kind = adm1023;
-+ else
-+ kind = adm1021;
-+ else if (i == 0x49)
-+ kind = thmc10;
-+ else if (i == 0x23)
-+ kind = gl523sm;
-+ else if ((i == 0x4d) &&
-+ (adm1021_read_value
-+ (new_client, ADM1021_REG_DEV_ID) == 0x01))
-+ kind = max1617a;
-+ else if (i == 0x54)
-+ kind = mc1066;
-+ /* LM84 Mfr ID in a different place, and it has more unused bits */
-+ else if (adm1021_read_value(new_client, ADM1021_REG_CONV_RATE_R) == 0x00
-+ && (kind == 0 /* skip extra detection */
-+ || ((adm1021_read_value(new_client, ADM1021_REG_CONFIG_R) & 0x7F) == 0x00
-+ && (adm1021_read_value(new_client, ADM1021_REG_STATUS) & 0xAB) == 0x00)))
-+ kind = lm84;
-+ else
-+ kind = max1617;
-+ }
-+
-+ if (kind == max1617) {
-+ type_name = "max1617";
-+ client_name = "MAX1617 chip";
-+ } else if (kind == max1617a) {
-+ type_name = "max1617a";
-+ client_name = "MAX1617A chip";
-+ } else if (kind == adm1021) {
-+ type_name = "adm1021";
-+ client_name = "ADM1021 chip";
-+ } else if (kind == adm1023) {
-+ type_name = "adm1023";
-+ client_name = "ADM1023 chip";
-+ } else if (kind == thmc10) {
-+ type_name = "thmc10";
-+ client_name = "THMC10 chip";
-+ } else if (kind == lm84) {
-+ type_name = "lm84";
-+ client_name = "LM84 chip";
-+ } else if (kind == gl523sm) {
-+ type_name = "gl523sm";
-+ client_name = "GL523SM chip";
-+ } else if (kind == mc1066) {
-+ type_name = "mc1066";
-+ client_name = "MC1066 chip";
-+ }
-+
-+ /* Fill in the remaining client fields and put it into the global list */
-+ strcpy(new_client->name, client_name);
-+ data->type = kind;
-+
-+ new_client->id = adm1021_id++;
-+ data->valid = 0;
-+ init_MUTEX(&data->update_lock);
-+
-+ /* Tell the I2C layer a new client has arrived */
-+ if ((err = i2c_attach_client(new_client)))
-+ goto error3;
-+
-+ /* Register a new directory entry with module sensors */
-+ if ((i = i2c_register_entry(new_client, type_name,
-+ data->type == adm1021 ? adm1021_dir_table_template :
-+ adm1021_max_dir_table_template)) < 0) {
-+ err = i;
-+ goto error4;
-+ }
-+ data->sysctl_id = i;
-+
-+ /* Initialize the ADM1021 chip */
-+ if (kind != lm84)
-+ adm1021_init_client(new_client);
-+ return 0;
-+
-+ error4:
-+ i2c_detach_client(new_client);
-+ error3:
-+ error1:
-+ kfree(data);
-+ error0:
-+ return err;
-+}
-+
-+static void adm1021_init_client(struct i2c_client *client)
-+{
-+ /* Enable ADC and disable suspend mode */
-+ adm1021_write_value(client, ADM1021_REG_CONFIG_W,
-+ adm1021_read_value(client, ADM1021_REG_CONFIG_R) & 0xBF);
-+ /* Set Conversion rate to 1/sec (this can be tinkered with) */
-+ adm1021_write_value(client, ADM1021_REG_CONV_RATE_W, 0x04);
-+}
-+
-+static int adm1021_detach_client(struct i2c_client *client)
-+{
-+ int err;
-+
-+ i2c_deregister_entry(((struct adm1021_data *) (client->data))->
-+ sysctl_id);
-+
-+ if ((err = i2c_detach_client(client))) {
-+ printk
-+ ("adm1021.o: Client deregistration failed, client not detached.\n");
-+ return err;
-+ }
-+
-+ kfree(client->data);
-+
-+ return 0;
-+}
-+
-+
-+/* All registers are byte-sized */
-+static int adm1021_read_value(struct i2c_client *client, u8 reg)
-+{
-+ return i2c_smbus_read_byte_data(client, reg);
-+}
-+
-+/* only update value if read succeeded; set fail bit if failed */
-+static int adm1021_rd_good(u8 *val, struct i2c_client *client, u8 reg, u8 mask)
-+{
-+ int i;
-+ struct adm1021_data *data = client->data;
-+
-+ i = i2c_smbus_read_byte_data(client, reg);
-+ if (i < 0) {
-+ data->fail |= mask;
-+ return i;
-+ }
-+ *val = i;
-+ return 0;
-+}
-+
-+static int adm1021_write_value(struct i2c_client *client, u8 reg, u16 value)
-+{
-+ if (read_only > 0)
-+ return 0;
-+
-+ return i2c_smbus_write_byte_data(client, reg, value);
-+}
-+
-+static void adm1021_update_client(struct i2c_client *client)
-+{
-+ struct adm1021_data *data = client->data;
-+
-+ down(&data->update_lock);
-+
-+ if ((jiffies - data->last_updated > HZ + HZ / 2) ||
-+ (jiffies < data->last_updated) || !data->valid) {
-+
-+#ifdef DEBUG
-+ printk("Starting adm1021 update\n");
-+#endif
-+
-+ data->fail = 0;
-+ adm1021_rd_good(&(data->temp), client, ADM1021_REG_TEMP,
-+ ADM1021_ALARM_TEMP);
-+ adm1021_rd_good(&(data->temp_os), client, ADM1021_REG_TOS_R,
-+ ADM1021_ALARM_TEMP);
-+ adm1021_rd_good(&(data->temp_hyst), client,
-+ ADM1021_REG_THYST_R, ADM1021_ALARM_TEMP);
-+ adm1021_rd_good(&(data->remote_temp), client,
-+ ADM1021_REG_REMOTE_TEMP, ADM1021_ALARM_RTEMP);
-+ adm1021_rd_good(&(data->remote_temp_os), client,
-+ ADM1021_REG_REMOTE_TOS_R, ADM1021_ALARM_RTEMP);
-+ adm1021_rd_good(&(data->remote_temp_hyst), client,
-+ ADM1021_REG_REMOTE_THYST_R,
-+ ADM1021_ALARM_RTEMP);
-+ data->alarms = ADM1021_ALARM_ALL;
-+ if (!adm1021_rd_good(&(data->alarms), client,
-+ ADM1021_REG_STATUS, 0))
-+ data->alarms &= ADM1021_ALARM_ALL;
-+ if (data->type == adm1021)
-+ adm1021_rd_good(&(data->die_code), client,
-+ ADM1021_REG_DIE_CODE, 0);
-+ if (data->type == adm1023) {
-+ adm1021_rd_good(&(data->remote_temp_prec), client,
-+ ADM1021_REG_REM_TEMP_PREC,
-+ ADM1021_ALARM_TEMP);
-+ adm1021_rd_good(&(data->remote_temp_os_prec), client,
-+ ADM1021_REG_REM_TOS_PREC,
-+ ADM1021_ALARM_RTEMP);
-+ adm1021_rd_good(&(data->remote_temp_hyst_prec), client,
-+ ADM1021_REG_REM_THYST_PREC,
-+ ADM1021_ALARM_RTEMP);
-+ adm1021_rd_good(&(data->remote_temp_offset), client,
-+ ADM1021_REG_REM_OFFSET,
-+ ADM1021_ALARM_RTEMP);
-+ adm1021_rd_good(&(data->remote_temp_offset_prec),
-+ client, ADM1021_REG_REM_OFFSET_PREC,
-+ ADM1021_ALARM_RTEMP);
-+ }
-+ data->last_updated = jiffies;
-+ data->valid = 1;
-+ }
-+
-+ up(&data->update_lock);
-+}
-+
-+
-+void adm1021_temp(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct adm1021_data *data = client->data;
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 0;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ adm1021_update_client(client);
-+ results[0] = TEMP_FROM_REG(data->temp_os);
-+ results[1] = TEMP_FROM_REG(data->temp_hyst);
-+ results[2] = TEMP_FROM_REG(data->temp);
-+ *nrels_mag = 3;
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ if (*nrels_mag >= 1) {
-+ data->temp_os = TEMP_TO_REG(results[0]);
-+ adm1021_write_value(client, ADM1021_REG_TOS_W,
-+ data->temp_os);
-+ }
-+ if (*nrels_mag >= 2) {
-+ data->temp_hyst = TEMP_TO_REG(results[1]);
-+ adm1021_write_value(client, ADM1021_REG_THYST_W,
-+ data->temp_hyst);
-+ }
-+ }
-+}
-+
-+void adm1021_remote_temp(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results)
-+{
-+ struct adm1021_data *data = client->data;
-+ int prec = 0;
-+
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ if (data->type == adm1023) { *nrels_mag = 3; }
-+ else { *nrels_mag = 0; }
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ adm1021_update_client(client);
-+ results[0] = TEMP_FROM_REG(data->remote_temp_os);
-+ results[1] = TEMP_FROM_REG(data->remote_temp_hyst);
-+ results[2] = TEMP_FROM_REG(data->remote_temp);
-+ if (data->type == adm1023) {
-+ results[0]=results[0]*1000 +
-+ ((data->remote_temp_os_prec >> 5) * 125);
-+ results[1]=results[1]*1000 +
-+ ((data->remote_temp_hyst_prec >> 5) * 125);
-+ results[2]=(TEMP_FROM_REG(data->remote_temp_offset)*1000) +
-+ ((data->remote_temp_offset_prec >> 5) * 125);
-+ results[3]=TEMP_FROM_REG(data->remote_temp)*1000 +
-+ ((data->remote_temp_prec >> 5) * 125);
-+ *nrels_mag = 4;
-+ } else {
-+ *nrels_mag = 3;
-+ }
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ if (*nrels_mag >= 1) {
-+ if (data->type == adm1023) {
-+ prec=((results[0]-((results[0]/1000)*1000))/125)<<5;
-+ adm1021_write_value(client,
-+ ADM1021_REG_REM_TOS_PREC,
-+ prec);
-+ results[0]=results[0]/1000;
-+ data->remote_temp_os_prec=prec;
-+ }
-+ data->remote_temp_os = TEMP_TO_REG(results[0]);
-+ adm1021_write_value(client,
-+ ADM1021_REG_REMOTE_TOS_W,
-+ data->remote_temp_os);
-+ }
-+ if (*nrels_mag >= 2) {
-+ if (data->type == adm1023) {
-+ prec=((results[1]-((results[1]/1000)*1000))/125)<<5;
-+ adm1021_write_value(client,
-+ ADM1021_REG_REM_THYST_PREC,
-+ prec);
-+ results[1]=results[1]/1000;
-+ data->remote_temp_hyst_prec=prec;
-+ }
-+ data->remote_temp_hyst = TEMP_TO_REG(results[1]);
-+ adm1021_write_value(client,
-+ ADM1021_REG_REMOTE_THYST_W,
-+ data->remote_temp_hyst);
-+ }
-+ if (*nrels_mag >= 3) {
-+ if (data->type == adm1023) {
-+ prec=((results[2]-((results[2]/1000)*1000))/125)<<5;
-+ adm1021_write_value(client,
-+ ADM1021_REG_REM_OFFSET_PREC,
-+ prec);
-+ results[2]=results[2]/1000;
-+ data->remote_temp_offset_prec=prec;
-+ data->remote_temp_offset=results[2];
-+ adm1021_write_value(client,
-+ ADM1021_REG_REM_OFFSET,
-+ data->remote_temp_offset);
-+ }
-+ }
-+ }
-+}
-+
-+void adm1021_die_code(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results)
-+{
-+ struct adm1021_data *data = client->data;
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 0;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ adm1021_update_client(client);
-+ results[0] = data->die_code;
-+ *nrels_mag = 1;
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ /* Can't write to it */
-+ }
-+}
-+
-+void adm1021_alarms(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct adm1021_data *data = client->data;
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 0;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ adm1021_update_client(client);
-+ results[0] = data->alarms | data->fail;
-+ *nrels_mag = 1;
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ /* Can't write to it */
-+ }
-+}
-+
-+static int __init sm_adm1021_init(void)
-+{
-+ printk(KERN_INFO "adm1021.o version %s (%s)\n", LM_VERSION, LM_DATE);
-+ return i2c_add_driver(&adm1021_driver);
-+}
-+
-+static void __exit sm_adm1021_exit(void)
-+{
-+ i2c_del_driver(&adm1021_driver);
-+}
-+
-+MODULE_AUTHOR
-+ ("Frodo Looijaard <frodol@dds.nl> and Philip Edelbrock <phil@netroedge.com>");
-+MODULE_DESCRIPTION("adm1021 driver");
-+MODULE_LICENSE("GPL");
-+
-+MODULE_PARM(read_only, "i");
-+MODULE_PARM_DESC(read_only, "Don't set any values, read only mode");
-+
-+module_init(sm_adm1021_init)
-+module_exit(sm_adm1021_exit)
---- linux-old/drivers/sensors/adm1024.c Thu Jan 1 00:00:00 1970
-+++ linux/drivers/sensors/adm1024.c Mon Dec 13 20:18:43 2004
-@@ -0,0 +1,782 @@
-+/*
-+ adm1024.c - Part of lm_sensors, Linux kernel modules for hardware
-+ monitoring
-+ Add by Ken Bowley <ken@opnix.com> from the adm1025.c written by
-+ Gordon Wu <gwu@esoft.com> and from adm9240.c written by
-+ Copyright (c) 1999 Frodo Looijaard <frodol@dds.nl>
-+ and Philip Edelbrock <phil@netroedge.com>
-+
-+ 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., 675 Mass Ave, Cambridge, MA 02139, USA.
-+*/
-+
-+/* Supports the Analog Devices ADM1024. See doc/chips/adm1024 for details */
-+
-+#include <linux/module.h>
-+#include <linux/slab.h>
-+#include <linux/i2c.h>
-+#include <linux/i2c-proc.h>
-+#include <linux/init.h>
-+#define LM_DATE "20041007"
-+#define LM_VERSION "2.8.8"
-+
-+/* Addresses to scan */
-+static unsigned short normal_i2c[] = { SENSORS_I2C_END };
-+static unsigned short normal_i2c_range[] = { 0x2c, 0x2e, SENSORS_I2C_END };
-+static unsigned int normal_isa[] = { SENSORS_ISA_END };
-+static unsigned int normal_isa_range[] = { SENSORS_ISA_END };
-+
-+/* Insmod parameters */
-+SENSORS_INSMOD_1(adm1024);
-+
-+/* Many ADM1024 constants specified below */
-+
-+#define ADM1024_REG_IN_MAX(nr) (0x2b + (nr) * 2)
-+#define ADM1024_REG_IN_MIN(nr) (0x2c + (nr) * 2)
-+#define ADM1024_REG_IN(nr) (0x20 + (nr))
-+
-+/* The ADM1024 registers */
-+#define ADM1024_REG_INT_TEMP_TRIP_SET 0x13
-+#define ADM1024_REG_EXT_TEMP_TRIP_SET 0x14
-+#define ADM1024_REG_TEST 0x15
-+#define ADM1024_REG_CHANNEL_MODE 0x16
-+#define ADM1024_REG_INT_TEMP_TRIP 0x17 /* read only */
-+#define ADM1024_REG_EXT_TEMP_TRIP 0x18 /* read only */
-+#define ADM1024_REG_ANALOG_OUT 0x19
-+#define ADM1024_REG_AIN1_LOW_LIMIT 0x1A
-+#define ADM1024_REG_AIN2_LOW_LIMIT 0x1B
-+/* These are all read-only */
-+#define ADM1024_REG_2_5V 0x20 /* 2.5V Measured Value/EXT Temp 2 */
-+#define ADM1024_REG_VCCP1 0x21
-+#define ADM1024_REG_3_3V 0x22 /* VCC Measured Value */
-+#define ADM1024_REG_5V 0x23
-+#define ADM1024_REG_12V 0x24
-+#define ADM1024_REG_VCCP2 0x25
-+#define ADM1024_REG_EXT_TEMP1 0x26
-+#define ADM1024_REG_TEMP 0x27
-+#define ADM1024_REG_FAN1 0x28 /* FAN1/AIN1 Value */
-+#define ADM1024_REG_FAN2 0x29 /* FAN2/AIN2 Value */
-+#define ADM1024_REG_COMPANY_ID 0x3E /* 0x41 for ADM1024 */
-+#define ADM1024_REG_DIE_REV 0x3F
-+/* These are read/write */
-+#define ADM1024_REG_2_5V_HIGH 0x2B /* 2.5V/Ext Temp2 High Limit */
-+#define ADM1024_REG_2_5V_LOW 0x2C /* 2.5V/Ext Temp2 Low Limit */
-+#define ADM1024_REG_VCCP1_HIGH 0x2D
-+#define ADM1024_REG_VCCP1_LOW 0x2E
-+#define ADM1024_REG_3_3V_HIGH 0x2F /* VCC High Limit */
-+#define ADM1024_REG_3_3V_LOW 0x30 /* VCC Low Limit */
-+#define ADM1024_REG_5V_HIGH 0x31
-+#define ADM1024_REG_5V_LOW 0x32
-+#define ADM1024_REG_12V_HIGH 0x33
-+#define ADM1024_REG_12V_LOW 0x34
-+#define ADM1024_REG_VCCP2_HIGH 0x35
-+#define ADM1024_REG_VCCP2_LOW 0x36
-+#define ADM1024_REG_EXT_TEMP1_HIGH 0x37
-+#define ADM1024_REG_EXT_TEMP1_LOW 0x38
-+#define ADM1024_REG_TOS 0x39
-+#define ADM1024_REG_THYST 0x3A
-+#define ADM1024_REG_FAN1_MIN 0x3B
-+#define ADM1024_REG_FAN2_MIN 0x3C
-+
-+#define ADM1024_REG_CONFIG 0x40
-+#define ADM1024_REG_INT1_STAT 0x41
-+#define ADM1024_REG_INT2_STAT 0x42
-+#define ADM1024_REG_INT1_MASK 0x43
-+#define ADM1024_REG_INT2_MASK 0x44
-+
-+#define ADM1024_REG_CHASSIS_CLEAR 0x46
-+#define ADM1024_REG_VID_FAN_DIV 0x47
-+#define ADM1024_REG_I2C_ADDR 0x48
-+#define ADM1024_REG_VID4 0x49
-+#define ADM1024_REG_CONFIG2 0x4A
-+#define ADM1024_REG_TEMP_CONFIG 0x4B
-+#define ADM1024_REG_EXTMODE1 0x4C /* Interupt Status Register Mirror No. 1 */
-+#define ADM1024_REG_EXTMODE2 0x4D /* Interupt Status Register Mirror No. 2 */
-+
-+/* Conversions. Rounding and limit checking is only done on the TO_REG
-+ variants. Note that you should be a bit careful with which arguments
-+ these macros are called: arguments may be evaluated more than once.
-+ Fixing this is just not worth it. */
-+#define IN_TO_REG(val,nr) (SENSORS_LIMIT(((val) & 0xff),0,255))
-+#define IN_FROM_REG(val,nr) (val)
-+
-+static inline u8 FAN_TO_REG(long rpm, int div)
-+{
-+ if (rpm == 0)
-+ return 255;
-+ rpm = SENSORS_LIMIT(rpm, 1, 1000000);
-+ return SENSORS_LIMIT((1350000 + rpm * div / 2) / (rpm * div), 1,
-+ 254);
-+}
-+
-+#define FAN_FROM_REG(val,div) ((val)==0?-1:\
-+ (val)==255?0:1350000/((div)*(val)))
-+
-+#define TEMP_FROM_REG(temp) \
-+ ((temp)<256?((((temp)&0x1fe) >> 1) * 10) + ((temp) & 1) * 5: \
-+ ((((temp)&0x1fe) >> 1) -255) * 10 - ((temp) & 1) * 5) \
-+
-+#define EXT_TEMP_FROM_REG(temp) (((temp)>0x80?(temp)-0x100:(temp))*10)
-+
-+
-+#define TEMP_LIMIT_FROM_REG(val) (((val)>0x80?(val)-0x100:(val))*10)
-+
-+#define TEMP_LIMIT_TO_REG(val) SENSORS_LIMIT(((val)<0?(((val)-5)/10):\
-+ ((val)+5)/10), \
-+ 0,255)
-+
-+#define ALARMS_FROM_REG(val) (val)
-+
-+#define DIV_FROM_REG(val) (1 << (val))
-+#define DIV_TO_REG(val) ((val)==1?0:((val)==8?3:((val)==4?2:1)))
-+
-+#define VID_FROM_REG(val) ((val)==0x1f?0:(val)>=0x10?510-(val)*10:\
-+ 205-(val)*5)
-+
-+/* For each registered ADM1024, we need to keep some data in memory. That
-+ data is pointed to by adm1024_list[NR]->data. The structure itself is
-+ dynamically allocated, at the same time when a new adm1024 client is
-+ allocated. */
-+struct adm1024_data {
-+ struct i2c_client client;
-+ int sysctl_id;
-+ enum chips type;
-+
-+ struct semaphore update_lock;
-+ char valid; /* !=0 if following fields are valid */
-+ unsigned long last_updated; /* In jiffies */
-+
-+ u8 in[6]; /* Register value */
-+ u8 in_max[6]; /* Register value */
-+ u8 in_min[6]; /* Register value */
-+ u8 fan[2]; /* Register value */
-+ u8 fan_min[2]; /* Register value */
-+ u8 fan_div[2]; /* Register encoding, shifted right */
-+ int temp; /* Temp, shifted right */
-+ u8 temp_os_max; /* Register value */
-+ u8 temp_os_hyst; /* Register value */
-+ int temp1; /* Ext Temp 1 */
-+ u8 temp1_os_max;
-+ u8 temp1_os_hyst;
-+ int temp2; /* Ext Temp 2 */
-+ u8 temp2_os_max;
-+ u8 temp2_os_hyst;
-+ u16 alarms; /* Register encoding, combined */
-+ u8 analog_out; /* Register value */
-+ u8 vid; /* Register value combined */
-+};
-+
-+
-+
-+static int adm1024_attach_adapter(struct i2c_adapter *adapter);
-+static int adm1024_detect(struct i2c_adapter *adapter, int address,
-+ unsigned short flags, int kind);
-+static int adm1024_detach_client(struct i2c_client *client);
-+
-+static int adm1024_read_value(struct i2c_client *client, u8 register);
-+static int adm1024_write_value(struct i2c_client *client, u8 register,
-+ u8 value);
-+static void adm1024_update_client(struct i2c_client *client);
-+static void adm1024_init_client(struct i2c_client *client);
-+
-+
-+static void adm1024_in(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void adm1024_fan(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void adm1024_temp(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void adm1024_temp1(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void adm1024_temp2(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void adm1024_alarms(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void adm1024_fan_div(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void adm1024_analog_out(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag,
-+ long *results);
-+static void adm1024_vid(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+
-+static int adm1024_id = 0;
-+
-+static struct i2c_driver adm1024_driver = {
-+ .owner = THIS_MODULE,
-+ .name = "ADM1024 sensor driver",
-+ .id = I2C_DRIVERID_ADM1024,
-+ .flags = I2C_DF_NOTIFY,
-+ .attach_adapter = adm1024_attach_adapter,
-+ .detach_client = adm1024_detach_client,
-+};
-+
-+/* The /proc/sys entries */
-+/* -- SENSORS SYSCTL START -- */
-+
-+#define ADM1024_SYSCTL_IN0 1000 /* Volts * 100 */
-+#define ADM1024_SYSCTL_IN1 1001
-+#define ADM1024_SYSCTL_IN2 1002
-+#define ADM1024_SYSCTL_IN3 1003
-+#define ADM1024_SYSCTL_IN4 1004
-+#define ADM1024_SYSCTL_IN5 1005
-+#define ADM1024_SYSCTL_FAN1 1101 /* Rotations/min */
-+#define ADM1024_SYSCTL_FAN2 1102
-+#define ADM1024_SYSCTL_TEMP 1250 /* Degrees Celcius * 100 */
-+#define ADM1024_SYSCTL_TEMP1 1290 /* Degrees Celcius */
-+#define ADM1024_SYSCTL_TEMP2 1295 /* Degrees Celcius */
-+#define ADM1024_SYSCTL_FAN_DIV 2000 /* 1, 2, 4 or 8 */
-+#define ADM1024_SYSCTL_ALARMS 2001 /* bitvector */
-+#define ADM1024_SYSCTL_ANALOG_OUT 2002
-+#define ADM1024_SYSCTL_VID 2003
-+
-+#define ADM1024_ALARM_IN0 0x0001
-+#define ADM1024_ALARM_IN1 0x0002
-+#define ADM1024_ALARM_IN2 0x0004
-+#define ADM1024_ALARM_IN3 0x0008
-+#define ADM1024_ALARM_IN4 0x0100
-+#define ADM1024_ALARM_IN5 0x0200
-+#define ADM1024_ALARM_FAN1 0x0040
-+#define ADM1024_ALARM_FAN2 0x0080
-+#define ADM1024_ALARM_TEMP 0x0010
-+#define ADM1024_ALARM_TEMP1 0x0020
-+#define ADM1024_ALARM_TEMP2 0x0001
-+#define ADM1024_ALARM_CHAS 0x1000
-+
-+/* -- SENSORS SYSCTL END -- */
-+
-+/* These files are created for each detected ADM1024. This is just a template;
-+ though at first sight, you might think we could use a statically
-+ allocated list, we need some way to get back to the parent - which
-+ is done through one of the 'extra' fields which are initialized
-+ when a new copy is allocated. */
-+static ctl_table adm1024_dir_table_template[] = {
-+ {ADM1024_SYSCTL_IN0, "in0", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &adm1024_in},
-+ {ADM1024_SYSCTL_IN1, "in1", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &adm1024_in},
-+ {ADM1024_SYSCTL_IN2, "in2", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &adm1024_in},
-+ {ADM1024_SYSCTL_IN3, "in3", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &adm1024_in},
-+ {ADM1024_SYSCTL_IN4, "in4", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &adm1024_in},
-+ {ADM1024_SYSCTL_IN5, "in5", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &adm1024_in},
-+ {ADM1024_SYSCTL_FAN1, "fan1", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &adm1024_fan},
-+ {ADM1024_SYSCTL_FAN2, "fan2", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &adm1024_fan},
-+ {ADM1024_SYSCTL_TEMP, "temp1", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &adm1024_temp},
-+ {ADM1024_SYSCTL_TEMP1, "temp2", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &adm1024_temp1},
-+ {ADM1024_SYSCTL_TEMP2, "temp3", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &adm1024_temp2},
-+ {ADM1024_SYSCTL_FAN_DIV, "fan_div", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &adm1024_fan_div},
-+ {ADM1024_SYSCTL_ALARMS, "alarms", NULL, 0, 0444, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &adm1024_alarms},
-+ {ADM1024_SYSCTL_ANALOG_OUT, "analog_out", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &adm1024_analog_out},
-+ {ADM1024_SYSCTL_VID, "vid", NULL, 0, 0444, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &adm1024_vid},
-+ {0}
-+};
-+
-+static int adm1024_attach_adapter(struct i2c_adapter *adapter)
-+{
-+ return i2c_detect(adapter, &addr_data, adm1024_detect);
-+}
-+
-+static int adm1024_detect(struct i2c_adapter *adapter, int address,
-+ unsigned short flags, int kind)
-+{
-+ int i;
-+ struct i2c_client *new_client;
-+ struct adm1024_data *data;
-+ int err = 0;
-+ const char *type_name = "";
-+ const char *client_name = "";
-+
-+ /* Make sure we aren't probing the ISA bus!! This is just a safety check
-+ at this moment; i2c_detect really won't call us. */
-+#ifdef DEBUG
-+ if (i2c_is_isa_adapter(adapter)) {
-+ printk
-+ ("adm1024.o: adm1024_detect called for an ISA bus adapter?!?\n");
-+ return 0;
-+ }
-+#endif
-+
-+ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
-+ goto ERROR0;
-+
-+ /* OK. For now, we presume we have a valid client. We now create the
-+ client structure, even though we cannot fill it completely yet.
-+ But it allows us to access adm1024_{read,write}_value. */
-+
-+ if (!(data = kmalloc(sizeof(struct adm1024_data), GFP_KERNEL))) {
-+ err = -ENOMEM;
-+ goto ERROR0;
-+ }
-+
-+ new_client = &data->client;
-+ new_client->addr = address;
-+ new_client->data = data;
-+ new_client->adapter = adapter;
-+ new_client->driver = &adm1024_driver;
-+ new_client->flags = 0;
-+
-+ /* Now, we do the remaining detection. */
-+
-+ if (kind < 0) {
-+ if((adm1024_read_value(new_client, ADM1024_REG_CONFIG) & 0x80) != 0x00)
-+ goto ERROR1;
-+ }
-+
-+ /* Determine the chip type. */
-+ if (kind <= 0) {
-+ i = adm1024_read_value(new_client, ADM1024_REG_COMPANY_ID);
-+ if (i == 0x41)
-+ kind = adm1024;
-+ else {
-+ if (kind == 0)
-+ printk
-+ ("adm1024.o: Ignoring 'force' parameter for unknown chip at "
-+ "adapter %d, address 0x%02x\n",
-+ i2c_adapter_id(adapter), address);
-+ goto ERROR1;
-+ }
-+ }
-+
-+ if (kind == adm1024) {
-+ type_name = "adm1024";
-+ client_name = "ADM1024 chip";
-+ } else {
-+#ifdef DEBUG
-+ printk("adm1024.o: Internal error: unknown kind (%d)?!?",
-+ kind);
-+#endif
-+ goto ERROR1;
-+ }
-+
-+ /* Fill in the remaining client fields and put it into the global list */
-+ strcpy(new_client->name, client_name);
-+ data->type = kind;
-+
-+ new_client->id = adm1024_id++;
-+ data->valid = 0;
-+ init_MUTEX(&data->update_lock);
-+
-+ /* Tell the I2C layer a new client has arrived */
-+ if ((err = i2c_attach_client(new_client)))
-+ goto ERROR3;
-+
-+ /* Register a new directory entry with module sensors */
-+ if ((i = i2c_register_entry(new_client,
-+ type_name,
-+ adm1024_dir_table_template)) < 0) {
-+ err = i;
-+ goto ERROR4;
-+ }
-+ data->sysctl_id = i;
-+
-+ /* Initialize the ADM1024 chip */
-+ adm1024_init_client(new_client);
-+ return 0;
-+
-+/* OK, this is not exactly good programming practice, usually. But it is
-+ very code-efficient in this case. */
-+
-+ ERROR4:
-+ i2c_detach_client(new_client);
-+ ERROR3:
-+ ERROR1:
-+ kfree(data);
-+ ERROR0:
-+ return err;
-+}
-+
-+static int adm1024_detach_client(struct i2c_client *client)
-+{
-+ int err;
-+
-+ i2c_deregister_entry(((struct adm1024_data *) (client->data))->
-+ sysctl_id);
-+
-+ if ((err = i2c_detach_client(client))) {
-+ printk
-+ ("adm1024.o: Client deregistration failed, client not detached.\n");
-+ return err;
-+ }
-+
-+ kfree(client->data);
-+
-+ return 0;
-+}
-+
-+static int adm1024_read_value(struct i2c_client *client, u8 reg)
-+{
-+ return 0xFF & i2c_smbus_read_byte_data(client, reg);
-+}
-+
-+static int adm1024_write_value(struct i2c_client *client, u8 reg, u8 value)
-+{
-+ return i2c_smbus_write_byte_data(client, reg, value);
-+}
-+
-+static void adm1024_init_client(struct i2c_client *client)
-+{
-+ /* Enable temperature channel 2 */
-+ adm1024_write_value(client, ADM1024_REG_CHANNEL_MODE, adm1024_read_value(client, ADM1024_REG_CHANNEL_MODE) | 0x04);
-+
-+ /* Start monitoring */
-+ adm1024_write_value(client, ADM1024_REG_CONFIG, 0x07);
-+}
-+
-+static void adm1024_update_client(struct i2c_client *client)
-+{
-+ struct adm1024_data *data = client->data;
-+ u8 i;
-+
-+ down(&data->update_lock);
-+
-+ if (
-+ (jiffies - data->last_updated >
-+ (data->type == adm1024 ? HZ / 2 : HZ * 2))
-+ || (jiffies < data->last_updated) || !data->valid) {
-+
-+#ifdef DEBUG
-+ printk("Starting adm1024 update\n");
-+#endif
-+ for (i = 0; i <= 5; i++) {
-+ data->in[i] =
-+ adm1024_read_value(client, ADM1024_REG_IN(i));
-+ data->in_min[i] =
-+ adm1024_read_value(client,
-+ ADM1024_REG_IN_MIN(i));
-+ data->in_max[i] =
-+ adm1024_read_value(client,
-+ ADM1024_REG_IN_MAX(i));
-+ }
-+ data->fan[0] =
-+ adm1024_read_value(client, ADM1024_REG_FAN1);
-+ data->fan_min[0] =
-+ adm1024_read_value(client, ADM1024_REG_FAN1_MIN);
-+ data->fan[1] =
-+ adm1024_read_value(client, ADM1024_REG_FAN2);
-+ data->fan_min[1] =
-+ adm1024_read_value(client, ADM1024_REG_FAN2_MIN);
-+ data->temp =
-+ (adm1024_read_value(client, ADM1024_REG_TEMP) << 1) +
-+ ((adm1024_read_value
-+ (client, ADM1024_REG_TEMP_CONFIG) & 0x80) >> 7);
-+ data->temp_os_max =
-+ adm1024_read_value(client, ADM1024_REG_TOS);
-+ data->temp_os_hyst =
-+ adm1024_read_value(client, ADM1024_REG_THYST);
-+ data->temp1 =
-+ adm1024_read_value(client, ADM1024_REG_EXT_TEMP1);
-+ data->temp1_os_max =
-+ adm1024_read_value(client, ADM1024_REG_EXT_TEMP1_HIGH);
-+ data->temp1_os_hyst =
-+ adm1024_read_value(client, ADM1024_REG_EXT_TEMP1_LOW);
-+ data->temp2 =
-+ adm1024_read_value(client, ADM1024_REG_2_5V);
-+ data->temp2_os_max =
-+ adm1024_read_value(client, ADM1024_REG_2_5V_HIGH);
-+ data->temp2_os_hyst =
-+ adm1024_read_value(client, ADM1024_REG_2_5V_LOW);
-+
-+ i = adm1024_read_value(client, ADM1024_REG_VID_FAN_DIV);
-+ data->fan_div[0] = (i >> 4) & 0x03;
-+ data->fan_div[1] = (i >> 6) & 0x03;
-+ data->vid = i & 0x0f;
-+ data->vid |=
-+ (adm1024_read_value(client, ADM1024_REG_VID4) & 0x01)
-+ << 4;
-+
-+ data->alarms =
-+ adm1024_read_value(client,
-+ ADM1024_REG_INT1_STAT) +
-+ (adm1024_read_value(client, ADM1024_REG_INT2_STAT) <<
-+ 8);
-+ data->analog_out =
-+ adm1024_read_value(client, ADM1024_REG_ANALOG_OUT);
-+ data->last_updated = jiffies;
-+ data->valid = 1;
-+ }
-+
-+ up(&data->update_lock);
-+}
-+
-+
-+/* The next few functions are the call-back functions of the /proc/sys and
-+ sysctl files. Which function is used is defined in the ctl_table in
-+ the extra1 field.
-+ Each function must return the magnitude (power of 10 to divide the date
-+ with) if it is called with operation==SENSORS_PROC_REAL_INFO. It must
-+ put a maximum of *nrels elements in results reflecting the data of this
-+ file, and set *nrels to the number it actually put in it, if operation==
-+ SENSORS_PROC_REAL_READ. Finally, it must get upto *nrels elements from
-+ results and write them to the chip, if operations==SENSORS_PROC_REAL_WRITE.
-+ Note that on SENSORS_PROC_REAL_READ, I do not check whether results is
-+ large enough (by checking the incoming value of *nrels). This is not very
-+ good practice, but as long as you put less than about 5 values in results,
-+ you can assume it is large enough. */
-+void adm1024_in(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+
-+ int scales[6] = { 250, 225, 330, 500, 1200, 270 };
-+
-+ struct adm1024_data *data = client->data;
-+ int nr = ctl_name - ADM1024_SYSCTL_IN0;
-+
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 2;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ adm1024_update_client(client);
-+ results[0] =
-+ IN_FROM_REG(data->in_min[nr], nr) * scales[nr] / 192;
-+ results[1] =
-+ IN_FROM_REG(data->in_max[nr], nr) * scales[nr] / 192;
-+ results[2] =
-+ IN_FROM_REG(data->in[nr], nr) * scales[nr] / 192;
-+ *nrels_mag = 3;
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ if (*nrels_mag >= 1) {
-+ data->in_min[nr] =
-+ IN_TO_REG((results[0] * 192) / scales[nr], nr);
-+ adm1024_write_value(client, ADM1024_REG_IN_MIN(nr),
-+ data->in_min[nr]);
-+ }
-+ if (*nrels_mag >= 2) {
-+ data->in_max[nr] =
-+ IN_TO_REG((results[1] * 192) / scales[nr], nr);
-+ adm1024_write_value(client, ADM1024_REG_IN_MAX(nr),
-+ data->in_max[nr]);
-+ }
-+ }
-+}
-+
-+void adm1024_fan(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct adm1024_data *data = client->data;
-+ int nr = ctl_name - ADM1024_SYSCTL_FAN1 + 1;
-+
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 0;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ adm1024_update_client(client);
-+ results[0] = FAN_FROM_REG(data->fan_min[nr - 1],
-+ DIV_FROM_REG(data->
-+ fan_div[nr - 1]));
-+ results[1] =
-+ FAN_FROM_REG(data->fan[nr - 1],
-+ DIV_FROM_REG(data->fan_div[nr - 1]));
-+ *nrels_mag = 2;
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ if (*nrels_mag >= 1) {
-+ data->fan_min[nr - 1] = FAN_TO_REG(results[0],
-+ DIV_FROM_REG
-+ (data->
-+ fan_div[nr -
-+ 1]));
-+ adm1024_write_value(client,
-+ nr ==
-+ 1 ? ADM1024_REG_FAN1_MIN :
-+ ADM1024_REG_FAN2_MIN,
-+ data->fan_min[nr - 1]);
-+ }
-+ }
-+}
-+
-+
-+void adm1024_temp(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct adm1024_data *data = client->data;
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 1;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ adm1024_update_client(client);
-+ results[0] = TEMP_LIMIT_FROM_REG(data->temp_os_max);
-+ results[1] = TEMP_LIMIT_FROM_REG(data->temp_os_hyst);
-+ results[2] = TEMP_FROM_REG(data->temp);
-+ *nrels_mag = 3;
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ if (*nrels_mag >= 1) {
-+ data->temp_os_max = TEMP_LIMIT_TO_REG(results[0]);
-+ adm1024_write_value(client, ADM1024_REG_TOS,
-+ data->temp_os_max);
-+ }
-+ if (*nrels_mag >= 2) {
-+ data->temp_os_hyst = TEMP_LIMIT_TO_REG(results[1]);
-+ adm1024_write_value(client, ADM1024_REG_THYST,
-+ data->temp_os_hyst);
-+ }
-+ }
-+}
-+
-+void adm1024_temp1(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct adm1024_data *data = client->data;
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 1;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ adm1024_update_client(client);
-+ results[0] = TEMP_LIMIT_FROM_REG(data->temp1_os_max);
-+ results[1] = TEMP_LIMIT_FROM_REG(data->temp1_os_hyst);
-+ results[2] = EXT_TEMP_FROM_REG(data->temp1);
-+ *nrels_mag = 3;
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ if (*nrels_mag >= 1) {
-+ data->temp1_os_max = TEMP_LIMIT_TO_REG(results[0]);
-+ adm1024_write_value(client, ADM1024_REG_EXT_TEMP1_HIGH,
-+ data->temp1_os_max);
-+ }
-+ if (*nrels_mag >= 2) {
-+ data->temp1_os_hyst = TEMP_LIMIT_TO_REG(results[1]);
-+ adm1024_write_value(client, ADM1024_REG_EXT_TEMP1_LOW,
-+ data->temp1_os_hyst);
-+ }
-+ }
-+}
-+
-+void adm1024_temp2(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct adm1024_data *data = client->data;
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 1;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ adm1024_update_client(client);
-+ results[0] = TEMP_LIMIT_FROM_REG(data->temp2_os_max);
-+ results[1] = TEMP_LIMIT_FROM_REG(data->temp2_os_hyst);
-+ results[2] = EXT_TEMP_FROM_REG(data->temp2);
-+ *nrels_mag = 3;
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ if (*nrels_mag >= 1) {
-+ data->temp2_os_max = TEMP_LIMIT_TO_REG(results[0]);
-+ adm1024_write_value(client, ADM1024_REG_2_5V_HIGH,
-+ data->temp2_os_max);
-+ }
-+ if (*nrels_mag >= 2) {
-+ data->temp2_os_hyst = TEMP_LIMIT_TO_REG(results[1]);
-+ adm1024_write_value(client, ADM1024_REG_2_5V_LOW,
-+ data->temp2_os_hyst);
-+ }
-+ }
-+}
-+
-+void adm1024_alarms(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct adm1024_data *data = client->data;
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 0;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ adm1024_update_client(client);
-+ results[0] = ALARMS_FROM_REG(data->alarms);
-+ *nrels_mag = 1;
-+ }
-+}
-+
-+void adm1024_fan_div(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results)
-+{
-+ struct adm1024_data *data = client->data;
-+ int old;
-+
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 0;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ adm1024_update_client(client);
-+ results[0] = DIV_FROM_REG(data->fan_div[0]);
-+ results[1] = DIV_FROM_REG(data->fan_div[1]);
-+ *nrels_mag = 2;
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ old = adm1024_read_value(client, ADM1024_REG_VID_FAN_DIV);
-+ if (*nrels_mag >= 2) {
-+ data->fan_div[1] = DIV_TO_REG(results[1]);
-+ old = (old & 0x3f) | (data->fan_div[1] << 6);
-+ }
-+ if (*nrels_mag >= 1) {
-+ data->fan_div[0] = DIV_TO_REG(results[0]);
-+ old = (old & 0xcf) | (data->fan_div[0] << 4);
-+ adm1024_write_value(client,
-+ ADM1024_REG_VID_FAN_DIV, old);
-+ }
-+ }
-+}
-+
-+void adm1024_analog_out(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results)
-+{
-+ struct adm1024_data *data = client->data;
-+
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 0;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ adm1024_update_client(client);
-+ results[0] = data->analog_out;
-+ *nrels_mag = 1;
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ if (*nrels_mag >= 1) {
-+ data->analog_out = results[0];
-+ adm1024_write_value(client, ADM1024_REG_ANALOG_OUT,
-+ data->analog_out);
-+ }
-+ }
-+}
-+
-+void adm1024_vid(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct adm1024_data *data = client->data;
-+
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 2;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ adm1024_update_client(client);
-+ results[0] = VID_FROM_REG(data->vid);
-+ *nrels_mag = 1;
-+ }
-+}
-+
-+static int __init sm_adm1024_init(void)
-+{
-+ printk("adm1024.o version %s (%s)\n", LM_VERSION, LM_DATE);
-+ return i2c_add_driver(&adm1024_driver);
-+}
-+
-+static void __exit sm_adm1024_exit(void)
-+{
-+ i2c_del_driver(&adm1024_driver);
-+}
-+
-+
-+
-+MODULE_AUTHOR
-+ ("Frodo Looijaard <frodol@dds.nl> and Philip Edelbrock <phil@netroedge.com>");
-+MODULE_DESCRIPTION("ADM1024 driver");
-+
-+MODULE_LICENSE("GPL");
-+
-+module_init(sm_adm1024_init);
-+module_exit(sm_adm1024_exit);
---- linux-old/drivers/sensors/adm1025.c Thu Jan 1 00:00:00 1970
-+++ linux/drivers/sensors/adm1025.c Mon Dec 13 20:18:43 2004
-@@ -0,0 +1,594 @@
-+/*
-+ adm1025.c - Part of lm_sensors, Linux kernel modules for hardware
-+ monitoring
-+ Copyright (c) 2000 Chen-Yuan Wu <gwu@esoft.com>
-+ Copyright (c) 2003-2004 Jean Delvare <khali@linux-fr.org>
-+
-+ Based on the adm9240 driver.
-+
-+ 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., 675 Mass Ave, Cambridge, MA 02139, USA.
-+*/
-+
-+/* Supports the Analog Devices ADM1025 and the Philips NE1619.
-+ See doc/chips/adm1025 for details */
-+
-+#include <linux/module.h>
-+#include <linux/slab.h>
-+#include <linux/i2c.h>
-+#include <linux/i2c-proc.h>
-+#include <linux/init.h>
-+#define LM_DATE "20041007"
-+#define LM_VERSION "2.8.8"
-+#include <linux/sensors_vid.h>
-+
-+MODULE_LICENSE("GPL");
-+
-+/* Addresses to scan */
-+static unsigned short normal_i2c[] = { SENSORS_I2C_END };
-+static unsigned short normal_i2c_range[] = { 0x2c, 0x2e, SENSORS_I2C_END };
-+static unsigned int normal_isa[] = { SENSORS_ISA_END };
-+static unsigned int normal_isa_range[] = { SENSORS_ISA_END };
-+
-+/* Insmod parameters */
-+SENSORS_INSMOD_2(adm1025, ne1619);
-+
-+/* Many ADM1025 constants specified below */
-+
-+
-+/* The ADM1025 registers */
-+
-+/* These are all read-only */
-+#define ADM1025_REG_2_5V 0x20 /* not used directly, see */
-+#define ADM1025_REG_VCCP1 0x21 /* ADM1025_REG_IN(nr) below */
-+#define ADM1025_REG_3_3V 0x22
-+#define ADM1025_REG_5V 0x23
-+#define ADM1025_REG_12V 0x24
-+#define ADM1025_REG_VCC 0x25
-+
-+#define ADM1025_REG_RTEMP 0x26 /* not used directly, see */
-+#define ADM1025_REG_LTEMP 0x27 /* ADM1025_REG_TEMP(nr) below */
-+
-+#define ADM1025_REG_COMPANY_ID 0x3E /* 0x41 for Analog Devices,
-+ 0xA1 for Philips */
-+#define ADM1025_REG_DIE_REV 0x3F /* 0x20-0x2F for ADM1025 and compatible */
-+
-+#define ADM1025_REG_STATUS1 0x41
-+#define ADM1025_REG_STATUS2 0x42
-+
-+#define ADM1025_REG_VID 0x47
-+#define ADM1025_REG_VID4 0x49 /* actually R/W
-+ but we don't write to it */
-+
-+/* These are read/write */
-+#define ADM1025_REG_2_5V_HIGH 0x2B /* not used directly, see */
-+#define ADM1025_REG_2_5V_LOW 0x2C /* ADM1025_REG_IN_MAX(nr) and */
-+#define ADM1025_REG_VCCP1_HIGH 0x2D /* ADM1025_REG_IN_MIN(nr) below */
-+#define ADM1025_REG_VCCP1_LOW 0x2E
-+#define ADM1025_REG_3_3V_HIGH 0x2F
-+#define ADM1025_REG_3_3V_LOW 0x30
-+#define ADM1025_REG_5V_HIGH 0x31
-+#define ADM1025_REG_5V_LOW 0x32
-+#define ADM1025_REG_12V_HIGH 0x33
-+#define ADM1025_REG_12V_LOW 0x34
-+#define ADM1025_REG_VCC_HIGH 0x35
-+#define ADM1025_REG_VCC_LOW 0x36
-+
-+#define ADM1025_REG_RTEMP_HIGH 0x37 /* not used directly, see */
-+#define ADM1025_REG_RTEMP_LOW 0x38 /* ADM1025_REG_TEMP_MAX(nr) and */
-+#define ADM1025_REG_LTEMP_HIGH 0x39 /* ADM1025_REG_TEMP_MIN(nr) below */
-+#define ADM1025_REG_LTEMP_LOW 0x3A
-+
-+#define ADM1025_REG_CONFIG 0x40
-+
-+/* Useful macros */
-+#define ADM1025_REG_IN(nr) (ADM1025_REG_2_5V + (nr))
-+#define ADM1025_REG_IN_MAX(nr) (ADM1025_REG_2_5V_HIGH + (nr) * 2)
-+#define ADM1025_REG_IN_MIN(nr) (ADM1025_REG_2_5V_LOW + (nr) * 2)
-+#define ADM1025_REG_TEMP(nr) (ADM1025_REG_RTEMP + (nr))
-+#define ADM1025_REG_TEMP_HIGH(nr) (ADM1025_REG_RTEMP_HIGH + (nr) * 2)
-+#define ADM1025_REG_TEMP_LOW(nr) (ADM1025_REG_RTEMP_LOW + (nr) * 2)
-+
-+/* Conversions. Rounding and limit checking is only done on the TO_REG
-+ variants. Note that you should be a bit careful with which arguments
-+ these macros are called: arguments may be evaluated more than once.
-+ Fixing this is just not worth it. */
-+#define IN_TO_REG(val) SENSORS_LIMIT(val, 0, 255)
-+#define IN_FROM_REG(val) (val)
-+
-+#define TEMP_FROM_REG(val) (((val)>=0x80?(val)-0x100:(val))*10)
-+#define TEMP_TO_REG(val) SENSORS_LIMIT(((val)<0?(((val)-5)/10):\
-+ ((val)+5)/10),-128,127)
-+
-+#define ALARMS_FROM_REG(val) (val)
-+
-+/* For each registered ADM1025, we need to keep some data in memory. That
-+ data is pointed to by adm1025_list[NR]->data. The structure itself is
-+ dynamically allocated, at the same time when a new adm1025 client is
-+ allocated. */
-+struct adm1025_data {
-+ struct i2c_client client;
-+ int sysctl_id;
-+ enum chips type;
-+
-+ struct semaphore update_lock;
-+ char valid; /* !=0 if following fields are valid */
-+ unsigned long last_updated; /* In jiffies */
-+
-+ u8 in[6]; /* Register value */
-+ u8 in_max[6]; /* Register value */
-+ u8 in_min[6]; /* Register value */
-+ u8 temp[2]; /* Register value */
-+ u8 temp_high[2]; /* Register value */
-+ u8 temp_low[2]; /* Register value */
-+ u16 alarms; /* Register encoding, combined */
-+ u8 vid; /* Register value combined */
-+ u8 vrm;
-+};
-+
-+
-+static int adm1025_attach_adapter(struct i2c_adapter *adapter);
-+static int adm1025_detect(struct i2c_adapter *adapter, int address,
-+ unsigned short flags, int kind);
-+static int adm1025_detach_client(struct i2c_client *client);
-+static void adm1025_update_client(struct i2c_client *client);
-+static void adm1025_init_client(struct i2c_client *client);
-+
-+
-+static void adm1025_in(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void adm1025_temp(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void adm1025_alarms(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void adm1025_vid(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void adm1025_vrm(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+
-+static int adm1025_id = 0;
-+
-+static struct i2c_driver adm1025_driver = {
-+ .owner = THIS_MODULE,
-+ .name = "ADM1025 sensor driver",
-+ .id = I2C_DRIVERID_ADM1025,
-+ .flags = I2C_DF_NOTIFY,
-+ .attach_adapter = adm1025_attach_adapter,
-+ .detach_client = adm1025_detach_client,
-+};
-+
-+/* The /proc/sys entries */
-+/* -- SENSORS SYSCTL START -- */
-+
-+#define ADM1025_SYSCTL_IN0 1000 /* Volts * 100 */
-+#define ADM1025_SYSCTL_IN1 1001
-+#define ADM1025_SYSCTL_IN2 1002
-+#define ADM1025_SYSCTL_IN3 1003
-+#define ADM1025_SYSCTL_IN4 1004
-+#define ADM1025_SYSCTL_IN5 1005
-+
-+#define ADM1025_SYSCTL_RTEMP 1250 /* Degrees Celcius * 10 */
-+#define ADM1025_SYSCTL_TEMP 1251
-+
-+#define ADM1025_SYSCTL_ALARMS 2001 /* bitvector */
-+#define ADM1025_SYSCTL_VID 2003 /* Volts * 1000 */
-+#define ADM1025_SYSCTL_VRM 2004
-+
-+#define ADM1025_ALARM_IN0 0x0001
-+#define ADM1025_ALARM_IN1 0x0002
-+#define ADM1025_ALARM_IN2 0x0004
-+#define ADM1025_ALARM_IN3 0x0008
-+#define ADM1025_ALARM_IN4 0x0100
-+#define ADM1025_ALARM_IN5 0x0200
-+#define ADM1025_ALARM_RTEMP 0x0020
-+#define ADM1025_ALARM_TEMP 0x0010
-+#define ADM1025_ALARM_RFAULT 0x4000
-+
-+/* -- SENSORS SYSCTL END -- */
-+
-+/* These files are created for each detected ADM1025. This is just a template;
-+ though at first sight, you might think we could use a statically
-+ allocated list, we need some way to get back to the parent - which
-+ is done through one of the 'extra' fields which are initialized
-+ when a new copy is allocated. */
-+static ctl_table adm1025_dir_table_template[] = {
-+ {ADM1025_SYSCTL_IN0, "in0", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &adm1025_in},
-+ {ADM1025_SYSCTL_IN1, "in1", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &adm1025_in},
-+ {ADM1025_SYSCTL_IN2, "in2", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &adm1025_in},
-+ {ADM1025_SYSCTL_IN3, "in3", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &adm1025_in},
-+ {ADM1025_SYSCTL_IN4, "in4", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &adm1025_in},
-+ {ADM1025_SYSCTL_IN5, "in5", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &adm1025_in},
-+ {ADM1025_SYSCTL_RTEMP, "temp1", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &adm1025_temp},
-+ {ADM1025_SYSCTL_TEMP, "temp2", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &adm1025_temp},
-+ {ADM1025_SYSCTL_ALARMS, "alarms", NULL, 0, 0444, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &adm1025_alarms},
-+ {ADM1025_SYSCTL_VID, "vid", NULL, 0, 0444, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &adm1025_vid},
-+ {ADM1025_SYSCTL_VRM, "vrm", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &adm1025_vrm},
-+ {0}
-+};
-+
-+static int adm1025_attach_adapter(struct i2c_adapter *adapter)
-+{
-+ return i2c_detect(adapter, &addr_data, adm1025_detect);
-+}
-+
-+static int adm1025_detect(struct i2c_adapter *adapter, int address,
-+ unsigned short flags, int kind)
-+{
-+ int i;
-+ struct i2c_client *new_client;
-+ struct adm1025_data *data;
-+ int err = 0;
-+ const char *type_name = "";
-+ const char *client_name = "";
-+
-+ /* Make sure we aren't probing the ISA bus!! This is just a safety check
-+ at this moment; i2c_detect really won't call us. */
-+#ifdef DEBUG
-+ if (i2c_is_isa_adapter(adapter)) {
-+ printk
-+ ("adm1025.o: adm1025_detect called for an ISA bus adapter?!?\n");
-+ return 0;
-+ }
-+#endif
-+
-+ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
-+ goto ERROR0;
-+
-+ /* OK. For now, we presume we have a valid client. We now create the
-+ client structure, even though we cannot fill it completely yet.
-+ But it allows us to access adm1025_{read,write}_value. */
-+
-+ if (!(data = kmalloc(sizeof(struct adm1025_data), GFP_KERNEL))) {
-+ err = -ENOMEM;
-+ goto ERROR0;
-+ }
-+
-+ new_client = &data->client;
-+ new_client->addr = address;
-+ new_client->data = data;
-+ new_client->adapter = adapter;
-+ new_client->driver = &adm1025_driver;
-+ new_client->flags = 0;
-+
-+ /* Now, we do the remaining detection. */
-+
-+ if (kind < 0) {
-+ if ((i2c_smbus_read_byte_data(new_client,
-+ ADM1025_REG_CONFIG) & 0x80) != 0x00
-+ || (i2c_smbus_read_byte_data(new_client,
-+ ADM1025_REG_STATUS1) & 0xC0) != 0x00
-+ || (i2c_smbus_read_byte_data(new_client,
-+ ADM1025_REG_STATUS2) & 0xBC) != 0x00)
-+ goto ERROR1;
-+ }
-+
-+ /* Determine the chip type. */
-+ if (kind <= 0) {
-+ u8 man_id, chip_id;
-+
-+ man_id = i2c_smbus_read_byte_data(new_client,
-+ ADM1025_REG_COMPANY_ID);
-+ chip_id = i2c_smbus_read_byte_data(new_client,
-+ ADM1025_REG_DIE_REV);
-+
-+ if (man_id == 0x41) { /* Analog Devices */
-+ if ((chip_id & 0xF0) == 0x20) /* ADM1025 */
-+ kind = adm1025;
-+ } else if (man_id == 0xA1) { /* Philips */
-+ if (address != 0x2E
-+ && (chip_id & 0xF0) == 0x20) /* NE1619 */
-+ kind = ne1619;
-+ }
-+ }
-+
-+ if (kind <= 0) { /* Identification failed */
-+ printk("adm1025.o: Unsupported chip.\n");
-+ goto ERROR1;
-+ }
-+
-+ if (kind == adm1025) {
-+ type_name = "adm1025";
-+ client_name = "ADM1025 chip";
-+ } else if (kind == ne1619) {
-+ type_name = "ne1619";
-+ client_name = "NE1619 chip";
-+ } else {
-+#ifdef DEBUG
-+ printk("adm1025.o: Internal error: unknown kind (%d)?!?",
-+ kind);
-+#endif
-+ goto ERROR1;
-+ }
-+
-+ /* Fill in the remaining client fields and put it into the global list */
-+ strcpy(new_client->name, client_name);
-+ data->type = kind;
-+
-+ new_client->id = adm1025_id++;
-+ data->valid = 0;
-+ init_MUTEX(&data->update_lock);
-+
-+ /* Tell the I2C layer a new client has arrived */
-+ if ((err = i2c_attach_client(new_client)))
-+ goto ERROR3;
-+
-+ /* Register a new directory entry with module sensors */
-+ if ((i = i2c_register_entry(new_client,
-+ type_name,
-+ adm1025_dir_table_template)) < 0) {
-+ err = i;
-+ goto ERROR4;
-+ }
-+ data->sysctl_id = i;
-+
-+ /* Initialize the ADM1025 chip */
-+ adm1025_init_client(new_client);
-+ return 0;
-+
-+/* OK, this is not exactly good programming practice, usually. But it is
-+ very code-efficient in this case. */
-+
-+ ERROR4:
-+ i2c_detach_client(new_client);
-+ ERROR3:
-+ ERROR1:
-+ kfree(data);
-+ ERROR0:
-+ return err;
-+}
-+
-+static int adm1025_detach_client(struct i2c_client *client)
-+{
-+ int err;
-+
-+ i2c_deregister_entry(((struct adm1025_data *) (client->data))->
-+ sysctl_id);
-+
-+ if ((err = i2c_detach_client(client))) {
-+ printk
-+ ("adm1025.o: Client deregistration failed, client not detached.\n");
-+ return err;
-+ }
-+
-+ kfree(client->data);
-+
-+ return 0;
-+}
-+
-+/* Called when we have found a new ADM1025. */
-+static void adm1025_init_client(struct i2c_client *client)
-+{
-+ struct adm1025_data *data = client->data;
-+ u8 reg;
-+ int i;
-+
-+ data->vrm = 82;
-+
-+ /* Set high limits
-+ Usually we avoid setting limits on driver init, but it happens
-+ that the ADM1025 comes with stupid default limits (all registers
-+ set to 0). In case the chip has not gone through any limit
-+ setting yet, we better set the high limits to the max so that
-+ no alarm triggers. */
-+ for (i=0; i<6; i++) {
-+ reg = i2c_smbus_read_byte_data(client,
-+ ADM1025_REG_IN_MAX(i));
-+ if (reg == 0)
-+ i2c_smbus_write_byte_data(client,
-+ ADM1025_REG_IN_MAX(i),
-+ 0xFF);
-+ }
-+ for (i=0; i<2; i++) {
-+ reg = i2c_smbus_read_byte_data(client,
-+ ADM1025_REG_TEMP_HIGH(i));
-+ if (reg == 0)
-+ i2c_smbus_write_byte_data(client,
-+ ADM1025_REG_TEMP_HIGH(i),
-+ 0x7F);
-+ }
-+
-+ /* Start monitoring */
-+ reg = i2c_smbus_read_byte_data(client, ADM1025_REG_CONFIG);
-+ i2c_smbus_write_byte_data(client, ADM1025_REG_CONFIG, (reg|0x01)&0x7F);
-+}
-+
-+static void adm1025_update_client(struct i2c_client *client)
-+{
-+ struct adm1025_data *data = client->data;
-+ u8 nr;
-+
-+ down(&data->update_lock);
-+
-+ if ((jiffies - data->last_updated > 2 * HZ)
-+ || (jiffies < data->last_updated) || !data->valid) {
-+#ifdef DEBUG
-+ printk("Starting adm1025 update\n");
-+#endif
-+
-+ /* Voltages */
-+ for (nr = 0; nr < 6; nr++) {
-+ data->in[nr] = i2c_smbus_read_byte_data(client, ADM1025_REG_IN(nr));
-+ data->in_min[nr] = i2c_smbus_read_byte_data(client, ADM1025_REG_IN_MIN(nr));
-+ data->in_max[nr] = i2c_smbus_read_byte_data(client, ADM1025_REG_IN_MAX(nr));
-+ }
-+
-+ /* Temperatures */
-+ for (nr = 0; nr < 2; nr++) {
-+ data->temp[nr] = i2c_smbus_read_byte_data(client, ADM1025_REG_TEMP(nr));
-+ data->temp_high[nr] = i2c_smbus_read_byte_data(client, ADM1025_REG_TEMP_HIGH(nr));
-+ data->temp_low[nr] = i2c_smbus_read_byte_data(client, ADM1025_REG_TEMP_LOW(nr));
-+ }
-+
-+ /* VID */
-+ data->vid = (i2c_smbus_read_byte_data(client, ADM1025_REG_VID) & 0x0f)
-+ + ((i2c_smbus_read_byte_data(client, ADM1025_REG_VID4) & 0x01) << 4);
-+
-+ /* Alarms */
-+ data->alarms = (i2c_smbus_read_byte_data(client, ADM1025_REG_STATUS1) & 0x3f)
-+ + ((i2c_smbus_read_byte_data(client, ADM1025_REG_STATUS2) & 0x43) << 8);
-+
-+ data->last_updated = jiffies;
-+ data->valid = 1;
-+ }
-+
-+ up(&data->update_lock);
-+}
-+
-+
-+/* The next few functions are the call-back functions of the /proc/sys and
-+ sysctl files. Which function is used is defined in the ctl_table in
-+ the extra1 field.
-+ Each function must return the magnitude (power of 10 to divide the data
-+ with) if it is called with operation==SENSORS_PROC_REAL_INFO. It must
-+ put a maximum of *nrels elements in results reflecting the data of this
-+ file, and set *nrels to the number it actually put in it, if operation==
-+ SENSORS_PROC_REAL_READ. Finally, it must get upto *nrels elements from
-+ results and write them to the chip, if operations==SENSORS_PROC_REAL_WRITE.
-+ Note that on SENSORS_PROC_REAL_READ, I do not check whether results is
-+ large enough (by checking the incoming value of *nrels). This is not very
-+ good practice, but as long as you put less than about 5 values in results,
-+ you can assume it is large enough. */
-+void adm1025_in(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ int scales[6] = { 250, 225, 330, 500, 1200, 330 };
-+
-+ struct adm1025_data *data = client->data;
-+ int nr = ctl_name - ADM1025_SYSCTL_IN0;
-+
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 2;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ adm1025_update_client(client);
-+ results[0] = (IN_FROM_REG(data->in_min[nr]) * scales[nr] + 96) / 192;
-+ results[1] = (IN_FROM_REG(data->in_max[nr]) * scales[nr] + 96) / 192;
-+ results[2] = (IN_FROM_REG(data->in[nr]) * scales[nr] + 96) / 192;
-+ *nrels_mag = 3;
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ if (*nrels_mag >= 1) {
-+ data->in_min[nr] = IN_TO_REG((results[0] * 192 + scales[nr] / 2)
-+ / scales[nr]);
-+ i2c_smbus_write_byte_data(client, ADM1025_REG_IN_MIN(nr),
-+ data->in_min[nr]);
-+ }
-+ if (*nrels_mag >= 2) {
-+ data->in_max[nr] = IN_TO_REG((results[1] * 192 + scales[nr] / 2)
-+ / scales[nr]);
-+ i2c_smbus_write_byte_data(client, ADM1025_REG_IN_MAX(nr),
-+ data->in_max[nr]);
-+ }
-+ }
-+}
-+
-+void adm1025_temp(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct adm1025_data *data = client->data;
-+ int nr = ctl_name - ADM1025_SYSCTL_RTEMP;
-+
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 1;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ adm1025_update_client(client);
-+ results[0] = TEMP_FROM_REG(data->temp_high[nr]);
-+ results[1] = TEMP_FROM_REG(data->temp_low[nr]);
-+ results[2] = TEMP_FROM_REG(data->temp[nr]);
-+ *nrels_mag = 3;
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ if (*nrels_mag >= 1) {
-+ data->temp_high[nr] = TEMP_TO_REG(results[0]);
-+ i2c_smbus_write_byte_data(client, ADM1025_REG_TEMP_HIGH(nr),
-+ data->temp_high[nr]);
-+ }
-+ if (*nrels_mag >= 2) {
-+ data->temp_low[nr] = TEMP_TO_REG(results[1]);
-+ i2c_smbus_write_byte_data(client, ADM1025_REG_TEMP_LOW(nr),
-+ data->temp_low[nr]);
-+ }
-+ }
-+}
-+
-+void adm1025_alarms(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct adm1025_data *data = client->data;
-+
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 0;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ adm1025_update_client(client);
-+ results[0] = ALARMS_FROM_REG(data->alarms);
-+ *nrels_mag = 1;
-+ }
-+}
-+
-+void adm1025_vid(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct adm1025_data *data = client->data;
-+
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 3;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ adm1025_update_client(client);
-+ results[0] = vid_from_reg(data->vid, data->vrm);
-+ *nrels_mag = 1;
-+ }
-+}
-+
-+void adm1025_vrm(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct adm1025_data *data = client->data;
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 1;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ results[0] = data->vrm;
-+ *nrels_mag = 1;
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ if (*nrels_mag >= 1)
-+ data->vrm = results[0];
-+ }
-+}
-+
-+static int __init sm_adm1025_init(void)
-+{
-+ printk("adm1025.o version %s (%s)\n", LM_VERSION, LM_DATE);
-+ return i2c_add_driver(&adm1025_driver);
-+}
-+
-+static void __exit sm_adm1025_exit(void)
-+{
-+ i2c_del_driver(&adm1025_driver);
-+}
-+
-+
-+
-+MODULE_AUTHOR("Chen-Yuan Wu <gwu@esoft.com>"
-+ " and Jean Delvare <khali@linux-fr.org>");
-+MODULE_DESCRIPTION("ADM1025 driver");
-+
-+module_init(sm_adm1025_init);
-+module_exit(sm_adm1025_exit);
---- linux-old/drivers/sensors/adm1026.c Thu Jan 1 00:00:00 1970
-+++ linux/drivers/sensors/adm1026.c Mon Dec 13 20:18:44 2004
-@@ -0,0 +1,1745 @@
-+/*
-+ adm1026.c - Part of lm_sensors, Linux kernel modules for hardware
-+ monitoring
-+ Copyright (c) 2002, 2003 Philip Pokorny <ppokorny@penguincomputing.com>
-+
-+ 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., 675 Mass Ave, Cambridge, MA 02139, USA.
-+
-+ CHANGELOG
-+
-+ 2003-03-13 Initial development
-+ 2003-05-07 First Release. Includes GPIO fixup and full
-+ functionality.
-+ 2003-05-18 Minor fixups and tweaks.
-+ Print GPIO config after fixup.
-+ Adjust fan MIN if DIV changes.
-+ 2003-05-21 Fix printing of FAN/GPIO config
-+ Fix silly bug in fan_div logic
-+ Fix fan_min handling so that 0xff is 0 is 0xff
-+ 2003-05-25 Fix more silly typos...
-+ 2003-06-11 Change FAN_xx_REG macros to use different scaling
-+ Most (all?) drivers assume two pulses per rev fans
-+ and the old scaling was producing double the RPM's
-+ Thanks to Jerome Hsiao @ Arima for pointing this out.
-+ 2004-01-27 Remove use of temporary ID.
-+ Define addresses as a range.
-+*/
-+
-+#include <linux/version.h>
-+#include <linux/module.h>
-+#include <linux/slab.h>
-+#include <linux/i2c.h>
-+#include <linux/i2c-proc.h>
-+#include <linux/init.h>
-+#define LM_DATE "20041007"
-+#define LM_VERSION "2.8.8"
-+#include <linux/sensors_vid.h>
-+
-+#ifndef I2C_DRIVERID_ADM1026
-+#define I2C_DRIVERID_ADM1026 1048
-+#endif
-+
-+/* Addresses to scan */
-+static unsigned short normal_i2c[] = { SENSORS_I2C_END };
-+static unsigned short normal_i2c_range[] = { 0x2c, 0x2e, SENSORS_I2C_END };
-+static unsigned int normal_isa[] = { SENSORS_ISA_END };
-+static unsigned int normal_isa_range[] = { SENSORS_ISA_END };
-+
-+/* Insmod parameters */
-+SENSORS_INSMOD_1(adm1026);
-+
-+static int gpio_input[17] = { -1, -1, -1, -1, -1, -1, -1, -1, -1,
-+ -1, -1, -1, -1, -1, -1, -1, -1 };
-+static int gpio_output[17] = { -1, -1, -1, -1, -1, -1, -1, -1, -1,
-+ -1, -1, -1, -1, -1, -1, -1, -1 };
-+static int gpio_inverted[17] = { -1, -1, -1, -1, -1, -1, -1, -1, -1,
-+ -1, -1, -1, -1, -1, -1, -1, -1 };
-+static int gpio_normal[17] = { -1, -1, -1, -1, -1, -1, -1, -1, -1,
-+ -1, -1, -1, -1, -1, -1, -1, -1 };
-+static int gpio_fan[8] = { -1, -1, -1, -1, -1, -1, -1, -1 };
-+MODULE_PARM(gpio_input,"1-17i");
-+MODULE_PARM_DESC(gpio_input,"List of GPIO pins (0-16) to program as inputs");
-+MODULE_PARM(gpio_output,"1-17i");
-+MODULE_PARM_DESC(gpio_output,"List of GPIO pins (0-16) to program as outputs");
-+MODULE_PARM(gpio_inverted,"1-17i");
-+MODULE_PARM_DESC(gpio_inverted,"List of GPIO pins (0-16) to program as inverted");
-+MODULE_PARM(gpio_normal,"1-17i");
-+MODULE_PARM_DESC(gpio_normal,"List of GPIO pins (0-16) to program as normal/non-inverted");
-+MODULE_PARM(gpio_fan,"1-8i");
-+MODULE_PARM_DESC(gpio_fan,"List of GPIO pins (0-7) to program as fan tachs");
-+
-+/* Many ADM1026 constants specified below */
-+
-+/* The ADM1026 registers */
-+#define ADM1026_REG_CONFIG1 (0x00)
-+#define CFG1_MONITOR (0x01)
-+#define CFG1_INT_ENABLE (0x02)
-+#define CFG1_INT_CLEAR (0x04)
-+#define CFG1_AIN8_9 (0x08)
-+#define CFG1_THERM_HOT (0x10)
-+#define CFG1_DAC_AFC (0x20)
-+#define CFG1_PWM_AFC (0x40)
-+#define CFG1_RESET (0x80)
-+#define ADM1026_REG_CONFIG2 (0x01)
-+/* CONFIG2 controls FAN0/GPIO0 through FAN7/GPIO7 */
-+#define ADM1026_REG_CONFIG3 (0x07)
-+#define CFG3_GPIO16_ENABLE (0x01)
-+#define CFG3_CI_CLEAR (0x02)
-+#define CFG3_VREF_250 (0x04)
-+#define CFG3_GPIO16_DIR (0x40)
-+#define CFG3_GPIO16_POL (0x80)
-+#define ADM1026_REG_E2CONFIG (0x13)
-+#define E2CFG_READ (0x01)
-+#define E2CFG_WRITE (0x02)
-+#define E2CFG_ERASE (0x04)
-+#define E2CFG_ROM (0x08)
-+#define E2CFG_CLK_EXT (0x80)
-+
-+/* There are 10 general analog inputs and 7 dedicated inputs
-+ * They are:
-+ * 0 - 9 = AIN0 - AIN9
-+ * 10 = Vbat
-+ * 11 = 3.3V Standby
-+ * 12 = 3.3V Main
-+ * 13 = +5V
-+ * 14 = Vccp (CPU core voltage)
-+ * 15 = +12V
-+ * 16 = -12V
-+ */
-+static u16 REG_IN[] = {
-+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35,
-+ 0x36, 0x37, 0x27, 0x29, 0x26, 0x2a,
-+ 0x2b, 0x2c, 0x2d, 0x2e, 0x2f
-+ };
-+static u16 REG_IN_MIN[] = {
-+ 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d,
-+ 0x5e, 0x5f, 0x6d, 0x49, 0x6b, 0x4a,
-+ 0x4b, 0x4c, 0x4d, 0x4e, 0x4f
-+ };
-+static u16 REG_IN_MAX[] = {
-+ 0x50, 0x51, 0x52, 0x53, 0x54, 0x55,
-+ 0x56, 0x57, 0x6c, 0x41, 0x6a, 0x42,
-+ 0x43, 0x44, 0x45, 0x46, 0x47
-+ };
-+#define ADM1026_REG_IN(nr) (REG_IN[(nr)])
-+#define ADM1026_REG_IN_MIN(nr) (REG_IN_MIN[(nr)])
-+#define ADM1026_REG_IN_MAX(nr) (REG_IN_MAX[(nr)])
-+
-+/* Temperatures are:
-+ * 0 - Internal
-+ * 1 - External 1
-+ * 2 - External 2
-+ */
-+static u16 REG_TEMP[] = { 0x1f, 0x28, 0x29 };
-+static u16 REG_TEMP_MIN[] = { 0x69, 0x48, 0x49 };
-+static u16 REG_TEMP_MAX[] = { 0x68, 0x40, 0x41 };
-+static u16 REG_TEMP_TMIN[] = { 0x10, 0x11, 0x12 };
-+static u16 REG_TEMP_THERM[] = { 0x0d, 0x0e, 0x0f };
-+static u16 REG_TEMP_OFFSET[] = { 0x1e, 0x6e, 0x6f };
-+#define ADM1026_REG_TEMP(nr) (REG_TEMP[(nr)])
-+#define ADM1026_REG_TEMP_MIN(nr) (REG_TEMP_MIN[(nr)])
-+#define ADM1026_REG_TEMP_MAX(nr) (REG_TEMP_MAX[(nr)])
-+#define ADM1026_REG_TEMP_TMIN(nr) (REG_TEMP_TMIN[(nr)])
-+#define ADM1026_REG_TEMP_THERM(nr) (REG_TEMP_THERM[(nr)])
-+#define ADM1026_REG_TEMP_OFFSET(nr) (REG_TEMP_OFFSET[(nr)])
-+
-+#define ADM1026_REG_FAN(nr) (0x38 + (nr))
-+#define ADM1026_REG_FAN_MIN(nr) (0x60 + (nr))
-+#define ADM1026_REG_FAN_DIV_0_3 (0x02)
-+#define ADM1026_REG_FAN_DIV_4_7 (0x03)
-+
-+#define ADM1026_REG_DAC (0x04)
-+#define ADM1026_REG_PWM (0x05)
-+
-+#define ADM1026_REG_GPIO_CFG_0_3 (0x08)
-+#define ADM1026_REG_GPIO_CFG_4_7 (0x09)
-+#define ADM1026_REG_GPIO_CFG_8_11 (0x0a)
-+#define ADM1026_REG_GPIO_CFG_12_15 (0x0b)
-+/* CFG_16 in REG_CFG3 */
-+#define ADM1026_REG_GPIO_STATUS_0_7 (0x24)
-+#define ADM1026_REG_GPIO_STATUS_8_15 (0x25)
-+/* STATUS_16 in REG_STATUS4 */
-+#define ADM1026_REG_GPIO_MASK_0_7 (0x1c)
-+#define ADM1026_REG_GPIO_MASK_8_15 (0x1d)
-+/* MASK_16 in REG_MASK4 */
-+
-+#define ADM1026_REG_COMPANY 0x16
-+#define ADM1026_REG_VERSTEP 0x17
-+/* These are the recognized values for the above regs */
-+#define ADM1026_COMPANY_ANALOG_DEV 0x41
-+#define ADM1026_VERSTEP_GENERIC 0x40
-+#define ADM1026_VERSTEP_ADM1026 0x44
-+
-+#define ADM1026_REG_MASK1 0x18
-+#define ADM1026_REG_MASK2 0x19
-+#define ADM1026_REG_MASK3 0x1a
-+#define ADM1026_REG_MASK4 0x1b
-+
-+#define ADM1026_REG_STATUS1 0x20
-+#define ADM1026_REG_STATUS2 0x21
-+#define ADM1026_REG_STATUS3 0x22
-+#define ADM1026_REG_STATUS4 0x23
-+
-+/* Conversions. Rounding and limit checking is only done on the TO_REG
-+ variants. Note that you should be a bit careful with which arguments
-+ these macros are called: arguments may be evaluated more than once.
-+ */
-+
-+/* IN are scaled acording to built-in resistors. These are the
-+ * voltages corresponding to 3/4 of full scale (192 or 0xc0)
-+ * NOTE: The -12V input needs an additional factor to account
-+ * for the Vref pullup resistor.
-+ * NEG12_OFFSET = SCALE * Vref / V-192 - Vref
-+ * = 13875 * 2.50 / 1.875 - 2500
-+ * = 16000
-+ */
-+#if 1
-+/* The values in this table are based on Table II, page 15 of the
-+ * datasheet.
-+ */
-+static int adm1026_scaling[] = { /* .001 Volts */
-+ 2250, 2250, 2250, 2250, 2250, 2250,
-+ 1875, 1875, 1875, 1875, 3000, 3330,
-+ 3330, 4995, 2250, 12000, 13875
-+ };
-+#define NEG12_OFFSET 16000
-+#else
-+/* The values in this table are based on the resistors in
-+ * Figure 5 on page 16. But the 3.3V inputs are not in
-+ * the figure and the values for the 5V input are wrong.
-+ * For 5V, I'm guessing that R2 at 55.2k is right, but
-+ * the total resistance should be 1400 or 1449 like the
-+ * other inputs. Using 1449, gives 4.922V at 192.
-+ */
-+static int adm1026_scaling[] = { /* .001 Volts */
-+ 2249, 2249, 2249, 2249, 2249, 2249,
-+ 1875, 1875, 1875, 1875, 3329, 3329,
-+ 3329, 4922, 2249, 11969, 13889
-+ };
-+#define NEG12_OFFSET 16019
-+#endif
-+
-+#define SCALE(val,from,to) (((val)*(to) + ((from)/2))/(from))
-+#define INS_TO_REG(n,val) (SENSORS_LIMIT(SCALE(val,adm1026_scaling[n],192),0,255))
-+#if 0 /* If we have extended A/D bits */
-+#define INSEXT_FROM_REG(n,val,ext) (SCALE((val)*4 + (ext),192*4,adm1026_scaling[n]))
-+#define INS_FROM_REG(n,val) (INSEXT_FROM_REG(n,val,0))
-+#else
-+#define INS_FROM_REG(n,val) (SCALE(val,192,adm1026_scaling[n]))
-+#endif
-+
-+/* FAN speed is measured using 22.5kHz clock and counts for 2 pulses
-+ * and we assume a 2 pulse-per-rev fan tach signal
-+ * 22500 kHz * 60 (sec/min) * 2 (pulse) / 2 (pulse/rev) == 1350000
-+ */
-+#define FAN_TO_REG(val,div) ((val)<=0 ? 0xff : SENSORS_LIMIT(1350000/((val)*(div)),1,254))
-+#define FAN_FROM_REG(val,div) ((val)==0?-1:(val)==0xff ? 0 : 1350000/((val)*(div)))
-+#define DIV_FROM_REG(val) (1<<(val))
-+#define DIV_TO_REG(val) ((val)>=8 ? 3 : (val)>=4 ? 2 : (val)>=2 ? 1 : 0)
-+
-+/* Temperature is reported in 1 degC increments */
-+#define TEMP_TO_REG(val) (SENSORS_LIMIT(val,-127,127))
-+#define TEMP_FROM_REG(val) (val)
-+#define OFFSET_TO_REG(val) (SENSORS_LIMIT(val,-127,127))
-+#define OFFSET_FROM_REG(val) (val)
-+
-+#define PWM_TO_REG(val) (SENSORS_LIMIT(val,0,255))
-+#define PWM_FROM_REG(val) (val)
-+
-+/* Analog output is a voltage, but it's used like a PWM
-+ * Seems like this should be scaled, but to be consistent
-+ * with other drivers, we do it this way.
-+ */
-+#define DAC_TO_REG(val) (SENSORS_LIMIT(val,0,255))
-+#define DAC_FROM_REG(val) (val)
-+
-+/* sensors_vid.h defines vid_from_reg() */
-+#define VID_FROM_REG(val,vrm) (vid_from_reg(val,vrm))
-+
-+#define ALARMS_FROM_REG(val) (val)
-+
-+/* Unlike some other drivers we DO NOT set initial limits. Use
-+ * the config file to set limits.
-+ */
-+
-+/* Typically used with systems using a v9.1 VRM spec ? */
-+#define ADM1026_INIT_VRM 91
-+#define ADM1026_INIT_VID -1
-+
-+/* Chip sampling rates
-+ *
-+ * Some sensors are not updated more frequently than once per second
-+ * so it doesn't make sense to read them more often than that.
-+ * We cache the results and return the saved data if the driver
-+ * is called again before a second has elapsed.
-+ *
-+ * Also, there is significant configuration data for this chip
-+ * So, we keep the config data up to date in the cache
-+ * when it is written and only sample it once every 5 *minutes*
-+ */
-+#define ADM1026_DATA_INTERVAL (1 * HZ)
-+#define ADM1026_CONFIG_INTERVAL (5 * 60 * HZ)
-+
-+/* We allow for multiple chips in a single system.
-+ *
-+ * For each registered ADM1026, we need to keep state information
-+ * at client->data. The adm1026_data structure is dynamically
-+ * allocated, when a new client structure is allocated. */
-+
-+struct adm1026_data {
-+ struct i2c_client client;
-+ struct semaphore lock;
-+ int sysctl_id;
-+ enum chips type;
-+
-+ struct semaphore update_lock;
-+ int valid; /* !=0 if following fields are valid */
-+ unsigned long last_reading; /* In jiffies */
-+ unsigned long last_config; /* In jiffies */
-+
-+ u8 in[17]; /* Register value */
-+ u8 in_max[17]; /* Register value */
-+ u8 in_min[17]; /* Register value */
-+ s8 temp[3]; /* Register value */
-+ s8 temp_min[3]; /* Register value */
-+ s8 temp_max[3]; /* Register value */
-+ s8 temp_tmin[3]; /* Register value */
-+ s8 temp_therm[3]; /* Register value */
-+ s8 temp_offset[3]; /* Register value */
-+ u8 fan[8]; /* Register value */
-+ u8 fan_min[8]; /* Register value */
-+ u8 fan_div[8]; /* Decoded value */
-+ u8 pwm; /* Register value */
-+ u8 analog_out; /* Register value */
-+ int vid; /* Decoded value */
-+ u8 vrm; /* VRM version */
-+ long alarms; /* Register encoding, combined */
-+ long alarm_mask; /* Register encoding, combined */
-+ long gpio; /* Register encoding, combined */
-+ long gpio_mask; /* Register encoding, combined */
-+ u8 gpio_config[17]; /* Decoded value */
-+ u8 config1; /* Register value */
-+ u8 config2; /* Register value */
-+ u8 config3; /* Register value */
-+};
-+
-+static int adm1026_attach_adapter(struct i2c_adapter *adapter);
-+static int adm1026_detect(struct i2c_adapter *adapter, int address,
-+ unsigned short flags, int kind);
-+static int adm1026_detach_client(struct i2c_client *client);
-+
-+static int adm1026_read_value(struct i2c_client *client, u8 register);
-+static int adm1026_write_value(struct i2c_client *client, u8 register, int value);
-+static void adm1026_print_gpio(struct i2c_client *client);
-+static void adm1026_fixup_gpio(struct i2c_client *client);
-+static void adm1026_update_client(struct i2c_client *client);
-+static void adm1026_init_client(struct i2c_client *client);
-+
-+
-+static void adm1026_in(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results);
-+static void adm1026_in16(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results);
-+static void adm1026_fan(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void adm1026_fixup_fan_min(struct i2c_client *client,
-+ int fan, int old_div);
-+static void adm1026_fan_div(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void adm1026_temp(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void adm1026_temp_offset(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void adm1026_temp_tmin(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void adm1026_temp_therm(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void adm1026_vid(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void adm1026_vrm(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void adm1026_alarms(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void adm1026_alarm_mask(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void adm1026_gpio(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void adm1026_gpio_mask(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void adm1026_pwm(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void adm1026_analog_out(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void adm1026_afc(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+
-+static struct i2c_driver adm1026_driver = {
-+ .owner = THIS_MODULE,
-+ .name = "ADM1026 compatible sensor driver",
-+ .id = I2C_DRIVERID_ADM1026,
-+ .flags = I2C_DF_NOTIFY,
-+ .attach_adapter = &adm1026_attach_adapter,
-+ .detach_client = &adm1026_detach_client,
-+};
-+
-+/* Unique ID assigned to each ADM1026 detected */
-+static int adm1026_id = 0;
-+
-+/* -- SENSORS SYSCTL START -- */
-+#define ADM1026_SYSCTL_FAN0 1000
-+#define ADM1026_SYSCTL_FAN1 1001
-+#define ADM1026_SYSCTL_FAN2 1002
-+#define ADM1026_SYSCTL_FAN3 1003
-+#define ADM1026_SYSCTL_FAN4 1004
-+#define ADM1026_SYSCTL_FAN5 1005
-+#define ADM1026_SYSCTL_FAN6 1006
-+#define ADM1026_SYSCTL_FAN7 1007
-+#define ADM1026_SYSCTL_FAN_DIV 1008
-+#define ADM1026_SYSCTL_GPIO 1009
-+#define ADM1026_SYSCTL_GPIO_MASK 1010
-+#define ADM1026_SYSCTL_ALARMS 1011
-+#define ADM1026_SYSCTL_ALARM_MASK 1012
-+#define ADM1026_SYSCTL_IN0 1013
-+#define ADM1026_SYSCTL_IN1 1014
-+#define ADM1026_SYSCTL_IN2 1015
-+#define ADM1026_SYSCTL_IN3 1016
-+#define ADM1026_SYSCTL_IN4 1017
-+#define ADM1026_SYSCTL_IN5 1018
-+#define ADM1026_SYSCTL_IN6 1019
-+#define ADM1026_SYSCTL_IN7 1020
-+#define ADM1026_SYSCTL_IN8 1021
-+#define ADM1026_SYSCTL_IN9 1022
-+#define ADM1026_SYSCTL_IN10 1023
-+#define ADM1026_SYSCTL_IN11 1024
-+#define ADM1026_SYSCTL_IN12 1025
-+#define ADM1026_SYSCTL_IN13 1026
-+#define ADM1026_SYSCTL_IN14 1027
-+#define ADM1026_SYSCTL_IN15 1028
-+#define ADM1026_SYSCTL_IN16 1029
-+#define ADM1026_SYSCTL_PWM 1030
-+#define ADM1026_SYSCTL_ANALOG_OUT 1031
-+#define ADM1026_SYSCTL_AFC 1032
-+#define ADM1026_SYSCTL_TEMP1 1033
-+#define ADM1026_SYSCTL_TEMP2 1034
-+#define ADM1026_SYSCTL_TEMP3 1035
-+#define ADM1026_SYSCTL_TEMP_OFFSET1 1036
-+#define ADM1026_SYSCTL_TEMP_OFFSET2 1037
-+#define ADM1026_SYSCTL_TEMP_OFFSET3 1038
-+#define ADM1026_SYSCTL_TEMP_THERM1 1039
-+#define ADM1026_SYSCTL_TEMP_THERM2 1040
-+#define ADM1026_SYSCTL_TEMP_THERM3 1041
-+#define ADM1026_SYSCTL_TEMP_TMIN1 1042
-+#define ADM1026_SYSCTL_TEMP_TMIN2 1043
-+#define ADM1026_SYSCTL_TEMP_TMIN3 1044
-+#define ADM1026_SYSCTL_VID 1045
-+#define ADM1026_SYSCTL_VRM 1046
-+
-+#define ADM1026_ALARM_TEMP2 (1L << 0)
-+#define ADM1026_ALARM_TEMP3 (1L << 1)
-+#define ADM1026_ALARM_IN9 (1L << 1)
-+#define ADM1026_ALARM_IN11 (1L << 2)
-+#define ADM1026_ALARM_IN12 (1L << 3)
-+#define ADM1026_ALARM_IN13 (1L << 4)
-+#define ADM1026_ALARM_IN14 (1L << 5)
-+#define ADM1026_ALARM_IN15 (1L << 6)
-+#define ADM1026_ALARM_IN16 (1L << 7)
-+#define ADM1026_ALARM_IN0 (1L << 8)
-+#define ADM1026_ALARM_IN1 (1L << 9)
-+#define ADM1026_ALARM_IN2 (1L << 10)
-+#define ADM1026_ALARM_IN3 (1L << 11)
-+#define ADM1026_ALARM_IN4 (1L << 12)
-+#define ADM1026_ALARM_IN5 (1L << 13)
-+#define ADM1026_ALARM_IN6 (1L << 14)
-+#define ADM1026_ALARM_IN7 (1L << 15)
-+#define ADM1026_ALARM_FAN0 (1L << 16)
-+#define ADM1026_ALARM_FAN1 (1L << 17)
-+#define ADM1026_ALARM_FAN2 (1L << 18)
-+#define ADM1026_ALARM_FAN3 (1L << 19)
-+#define ADM1026_ALARM_FAN4 (1L << 20)
-+#define ADM1026_ALARM_FAN5 (1L << 21)
-+#define ADM1026_ALARM_FAN6 (1L << 22)
-+#define ADM1026_ALARM_FAN7 (1L << 23)
-+#define ADM1026_ALARM_TEMP1 (1L << 24)
-+#define ADM1026_ALARM_IN10 (1L << 25)
-+#define ADM1026_ALARM_IN8 (1L << 26)
-+#define ADM1026_ALARM_THERM (1L << 27)
-+#define ADM1026_ALARM_AFC_FAN (1L << 28)
-+#define ADM1026_ALARM_UNUSED (1L << 29)
-+#define ADM1026_ALARM_CI (1L << 30)
-+/* -- SENSORS SYSCTL END -- */
-+
-+/* The /proc/sys entries */
-+/* These files are created for each detected ADM1026. This is just a template;
-+ * The actual list is built from this and additional per-chip
-+ * custom lists below. Note the XXX_LEN macros. These must be
-+ * compile time constants because they will be used to allocate
-+ * space for the final template passed to i2c_register_entry.
-+ * We depend on the ability of GCC to evaluate expressions at
-+ * compile time to turn these expressions into compile time
-+ * constants, but this can generate a warning.
-+ */
-+static ctl_table adm1026_common[] = {
-+ {ADM1026_SYSCTL_IN0, "in0", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &adm1026_in},
-+ {ADM1026_SYSCTL_IN1, "in1", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &adm1026_in},
-+ {ADM1026_SYSCTL_IN2, "in2", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &adm1026_in},
-+ {ADM1026_SYSCTL_IN3, "in3", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &adm1026_in},
-+ {ADM1026_SYSCTL_IN4, "in4", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &adm1026_in},
-+ {ADM1026_SYSCTL_IN5, "in5", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &adm1026_in},
-+ {ADM1026_SYSCTL_IN6, "in6", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &adm1026_in},
-+ {ADM1026_SYSCTL_IN7, "in7", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &adm1026_in},
-+ {ADM1026_SYSCTL_IN8, "in8", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &adm1026_in},
-+ {ADM1026_SYSCTL_IN9, "in9", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &adm1026_in},
-+ {ADM1026_SYSCTL_IN10, "in10", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &adm1026_in},
-+ {ADM1026_SYSCTL_IN11, "in11", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &adm1026_in},
-+ {ADM1026_SYSCTL_IN12, "in12", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &adm1026_in},
-+ {ADM1026_SYSCTL_IN13, "in13", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &adm1026_in},
-+ {ADM1026_SYSCTL_IN14, "in14", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &adm1026_in},
-+ {ADM1026_SYSCTL_IN15, "in15", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &adm1026_in},
-+ {ADM1026_SYSCTL_IN16, "in16", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &adm1026_in16},
-+
-+ {ADM1026_SYSCTL_FAN0, "fan0", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &adm1026_fan},
-+ {ADM1026_SYSCTL_FAN1, "fan1", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &adm1026_fan},
-+ {ADM1026_SYSCTL_FAN2, "fan2", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &adm1026_fan},
-+ {ADM1026_SYSCTL_FAN3, "fan3", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &adm1026_fan},
-+ {ADM1026_SYSCTL_FAN4, "fan4", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &adm1026_fan},
-+ {ADM1026_SYSCTL_FAN5, "fan5", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &adm1026_fan},
-+ {ADM1026_SYSCTL_FAN6, "fan6", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &adm1026_fan},
-+ {ADM1026_SYSCTL_FAN7, "fan7", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &adm1026_fan},
-+ {ADM1026_SYSCTL_FAN_DIV, "fan_div", NULL, 0, 0644, NULL,
-+ &i2c_proc_real, &i2c_sysctl_real, NULL, &adm1026_fan_div},
-+
-+ {ADM1026_SYSCTL_TEMP1, "temp1", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &adm1026_temp},
-+ {ADM1026_SYSCTL_TEMP2, "temp2", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &adm1026_temp},
-+ {ADM1026_SYSCTL_TEMP3, "temp3", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &adm1026_temp},
-+ {ADM1026_SYSCTL_TEMP_OFFSET1, "temp1_offset", NULL, 0, 0644, NULL,
-+ &i2c_proc_real, &i2c_sysctl_real, NULL, &adm1026_temp_offset},
-+ {ADM1026_SYSCTL_TEMP_OFFSET2, "temp2_offset", NULL, 0, 0644, NULL,
-+ &i2c_proc_real, &i2c_sysctl_real, NULL, &adm1026_temp_offset},
-+ {ADM1026_SYSCTL_TEMP_OFFSET3, "temp3_offset", NULL, 0, 0644, NULL,
-+ &i2c_proc_real, &i2c_sysctl_real, NULL, &adm1026_temp_offset},
-+ {ADM1026_SYSCTL_TEMP_TMIN1, "temp1_tmin", NULL, 0, 0644, NULL,
-+ &i2c_proc_real, &i2c_sysctl_real, NULL, &adm1026_temp_tmin},
-+ {ADM1026_SYSCTL_TEMP_TMIN2, "temp2_tmin", NULL, 0, 0644, NULL,
-+ &i2c_proc_real, &i2c_sysctl_real, NULL, &adm1026_temp_tmin},
-+ {ADM1026_SYSCTL_TEMP_TMIN3, "temp3_tmin", NULL, 0, 0644, NULL,
-+ &i2c_proc_real, &i2c_sysctl_real, NULL, &adm1026_temp_tmin},
-+ {ADM1026_SYSCTL_TEMP_THERM1, "temp1_therm", NULL, 0, 0644, NULL,
-+ &i2c_proc_real, &i2c_sysctl_real, NULL, &adm1026_temp_therm},
-+ {ADM1026_SYSCTL_TEMP_THERM2, "temp2_therm", NULL, 0, 0644, NULL,
-+ &i2c_proc_real, &i2c_sysctl_real, NULL, &adm1026_temp_therm},
-+ {ADM1026_SYSCTL_TEMP_THERM3, "temp3_therm", NULL, 0, 0644, NULL,
-+ &i2c_proc_real, &i2c_sysctl_real, NULL, &adm1026_temp_therm},
-+
-+ {ADM1026_SYSCTL_VID, "vid", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &adm1026_vid},
-+ {ADM1026_SYSCTL_VRM, "vrm", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &adm1026_vrm},
-+
-+ {ADM1026_SYSCTL_ALARMS, "alarms", NULL, 0, 0444, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &adm1026_alarms},
-+ {ADM1026_SYSCTL_ALARM_MASK, "alarm_mask", NULL, 0, 0644, NULL,
-+ &i2c_proc_real, &i2c_sysctl_real, NULL, &adm1026_alarm_mask},
-+
-+ {ADM1026_SYSCTL_GPIO, "gpio", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &adm1026_gpio},
-+ {ADM1026_SYSCTL_GPIO_MASK, "gpio_mask", NULL, 0, 0644, NULL,
-+ &i2c_proc_real, &i2c_sysctl_real, NULL, &adm1026_gpio_mask},
-+
-+ {ADM1026_SYSCTL_PWM, "pwm", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &adm1026_pwm},
-+ {ADM1026_SYSCTL_ANALOG_OUT, "analog_out", NULL, 0, 0644, NULL,
-+ &i2c_proc_real, &i2c_sysctl_real, NULL, &adm1026_analog_out},
-+ {ADM1026_SYSCTL_AFC, "afc", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &adm1026_afc},
-+
-+ {0}
-+};
-+#define CTLTBL_COMMON (sizeof(adm1026_common)/sizeof(adm1026_common[0]))
-+
-+#define MAX2(a,b) ((a)>(b)?(a):(b))
-+#define MAX3(a,b,c) ((a)>(b)?MAX2((a),(c)):MAX2((b),(c)))
-+#define MAX4(a,b,c,d) ((a)>(b)?MAX3((a),(c),(d)):MAX3((b),(c),(d)))
-+
-+#define CTLTBL_MAX (CTLTBL_COMMON)
-+
-+/* This function is called when:
-+ * the module is loaded
-+ * a new adapter is loaded
-+ */
-+int adm1026_attach_adapter(struct i2c_adapter *adapter)
-+{
-+ return i2c_detect(adapter, &addr_data, adm1026_detect);
-+}
-+
-+/* This function is called by i2c_detect */
-+int adm1026_detect(struct i2c_adapter *adapter, int address,
-+ unsigned short flags, int kind)
-+{
-+ int i;
-+ int company, verstep ;
-+ struct i2c_client *new_client;
-+ struct adm1026_data *data;
-+ int err = 0;
-+ const char *type_name = "";
-+ struct ctl_table template[CTLTBL_MAX] ;
-+ struct ctl_table * template_next = template ;
-+
-+ if (i2c_is_isa_adapter(adapter)) {
-+ /* This chip has no ISA interface */
-+ goto ERROR0 ;
-+ }
-+
-+ if (!i2c_check_functionality(adapter,
-+ I2C_FUNC_SMBUS_BYTE_DATA)) {
-+ /* We need to be able to do byte I/O */
-+ goto ERROR0 ;
-+ }
-+
-+ /* OK. For now, we presume we have a valid client. We now create the
-+ client structure, even though we cannot fill it completely yet.
-+ But it allows us to access adm1026_{read,write}_value. */
-+
-+ if (!(data = kmalloc(sizeof(struct adm1026_data), GFP_KERNEL))) {
-+ err = -ENOMEM;
-+ goto ERROR0;
-+ }
-+
-+ new_client = &data->client;
-+ new_client->addr = address;
-+ new_client->data = data;
-+ new_client->adapter = adapter;
-+ new_client->driver = &adm1026_driver;
-+ new_client->flags = 0;
-+
-+ /* Now, we do the remaining detection. */
-+
-+ company = adm1026_read_value(new_client, ADM1026_REG_COMPANY);
-+ verstep = adm1026_read_value(new_client, ADM1026_REG_VERSTEP);
-+
-+#ifdef DEBUG
-+ printk("adm1026: Detecting device at %d,0x%02x with"
-+ " COMPANY: 0x%02x and VERSTEP: 0x%02x\n",
-+ i2c_adapter_id(new_client->adapter), new_client->addr,
-+ company, verstep
-+ );
-+#endif
-+
-+ /* If auto-detecting, Determine the chip type. */
-+ if (kind <= 0) {
-+#ifdef DEBUG
-+ printk("adm1026: Autodetecting device at %d,0x%02x ...\n",
-+ i2c_adapter_id(adapter), address );
-+#endif
-+ if( company == ADM1026_COMPANY_ANALOG_DEV
-+ && verstep == ADM1026_VERSTEP_ADM1026 ) {
-+ kind = adm1026 ;
-+ } else if( company == ADM1026_COMPANY_ANALOG_DEV
-+ && (verstep & 0xf0) == ADM1026_VERSTEP_GENERIC ) {
-+ printk("adm1026: Unrecgonized stepping 0x%02x"
-+ " Defaulting to ADM1026.\n", verstep );
-+ kind = adm1026 ;
-+ } else if( (verstep & 0xf0) == ADM1026_VERSTEP_GENERIC ) {
-+ printk("adm1026: Found version/stepping 0x%02x"
-+ " Assuming generic ADM1026.\n", verstep );
-+ kind = any_chip ;
-+ } else {
-+#ifdef DEBUG
-+ printk("adm1026: Autodetection failed\n");
-+#endif
-+ /* Not an ADM1026 ... */
-+ if( kind == 0 ) { /* User used force=x,y */
-+ printk("adm1026: Generic ADM1026 Version 6 not"
-+ " found at %d,0x%02x. Try force_adm1026.\n",
-+ i2c_adapter_id(adapter), address );
-+ }
-+ err = 0 ;
-+ goto ERROR1;
-+ }
-+ }
-+
-+ /* Fill in the chip specific driver values */
-+ switch (kind) {
-+ case any_chip :
-+ type_name = "adm1026";
-+ strcpy(new_client->name, "Generic ADM1026");
-+ template_next = template ; /* None used */
-+ break ;
-+ case adm1026 :
-+ type_name = "adm1026";
-+ strcpy(new_client->name, "Analog Devices ADM1026");
-+ template_next = template ;
-+ break ;
-+#if 0
-+ /* Example of another adm1026 "compatible" device */
-+ case adx1000 :
-+ type_name = "adx1000";
-+ strcpy(new_client->name, "Compatible ADX1000");
-+ memcpy( template, adx_specific, sizeof(adx_specific) );
-+ template_next = template + CTLTBL_ADX1000 ;
-+ break ;
-+#endif
-+ default :
-+ printk("adm1026: Internal error, invalid kind (%d)!", kind);
-+ err = -EFAULT ;
-+ goto ERROR1;
-+ }
-+
-+ /* Fill in the remaining client fields */
-+ new_client->id = adm1026_id++;
-+ printk("adm1026(%d): Assigning ID %d to %s at %d,0x%02x\n",
-+ new_client->id, new_client->id, new_client->name,
-+ i2c_adapter_id(new_client->adapter),
-+ new_client->addr
-+ );
-+
-+ /* Housekeeping values */
-+ data->type = kind;
-+ data->valid = 0;
-+
-+ /* Set the VRM version */
-+ data->vrm = ADM1026_INIT_VRM ;
-+ data->vid = ADM1026_INIT_VID ;
-+
-+ init_MUTEX(&data->update_lock);
-+
-+ /* Initialize the ADM1026 chip */
-+ adm1026_init_client(new_client);
-+
-+ /* Tell the I2C layer a new client has arrived */
-+ if ((err = i2c_attach_client(new_client)))
-+ goto ERROR1;
-+
-+ /* Finish out the template */
-+ memcpy(template_next, adm1026_common, sizeof(adm1026_common));
-+
-+ /* Register a new directory entry with module sensors */
-+ if ((i = i2c_register_entry(new_client,
-+ type_name,
-+ template)) < 0) {
-+ err = i;
-+ goto ERROR2;
-+ }
-+ data->sysctl_id = i;
-+
-+ return 0;
-+
-+ /* Error out and cleanup code */
-+ ERROR2:
-+ i2c_detach_client(new_client);
-+ ERROR1:
-+ kfree(data);
-+ ERROR0:
-+ return err;
-+}
-+
-+int adm1026_detach_client(struct i2c_client *client)
-+{
-+ int err;
-+ int id ;
-+
-+ id = client->id;
-+ i2c_deregister_entry(((struct adm1026_data *)(client->data))->sysctl_id);
-+
-+ if ((err = i2c_detach_client(client))) {
-+ printk("adm1026(%d): Client deregistration failed,"
-+ " client not detached.\n", id );
-+ return err;
-+ }
-+
-+ kfree(client->data);
-+
-+ return 0;
-+}
-+
-+int adm1026_read_value(struct i2c_client *client, u8 reg)
-+{
-+ int res;
-+
-+ if( reg < 0x80 ) {
-+ /* "RAM" locations */
-+ res = i2c_smbus_read_byte_data(client, reg) & 0xff ;
-+ } else {
-+ /* EEPROM, do nothing */
-+ res = 0 ;
-+ }
-+
-+ return res ;
-+}
-+
-+int adm1026_write_value(struct i2c_client *client, u8 reg, int value)
-+{
-+ int res ;
-+
-+ if( reg < 0x80 ) {
-+ /* "RAM" locations */
-+ res = i2c_smbus_write_byte_data(client, reg, value);
-+ } else {
-+ /* EEPROM, do nothing */
-+ res = 0 ;
-+ }
-+
-+ return res ;
-+}
-+
-+/* Called when we have found a new ADM1026. */
-+void adm1026_init_client(struct i2c_client *client)
-+{
-+ int value ;
-+ int i;
-+ struct adm1026_data *data = client->data;
-+
-+#ifdef DEBUG
-+ printk("adm1026(%d): Initializing device\n", client->id);
-+#endif
-+
-+ /* Read chip config */
-+ data->config1 = adm1026_read_value(client, ADM1026_REG_CONFIG1);
-+ data->config2 = adm1026_read_value(client, ADM1026_REG_CONFIG2);
-+ data->config3 = adm1026_read_value(client, ADM1026_REG_CONFIG3);
-+
-+ /* Inform user of chip config */
-+#ifdef DEBUG
-+ printk("adm1026(%d): ADM1026_REG_CONFIG1 is: 0x%02x\n",
-+ client->id, data->config1 );
-+#endif
-+ if( (data->config1 & CFG1_MONITOR) == 0 ) {
-+ printk("adm1026(%d): Monitoring not currently enabled.\n",
-+ client->id );
-+ }
-+ if( data->config1 & CFG1_INT_ENABLE ) {
-+ printk("adm1026(%d): SMBALERT interrupts are enabled.\n",
-+ client->id );
-+ }
-+ if( data->config1 & CFG1_AIN8_9 ) {
-+ printk("adm1026(%d): in8 and in9 enabled. temp3 disabled.\n",
-+ client->id );
-+ } else {
-+ printk("adm1026(%d): temp3 enabled. in8 and in9 disabled.\n",
-+ client->id );
-+ }
-+ if( data->config1 & CFG1_THERM_HOT ) {
-+ printk("adm1026(%d): Automatic THERM, PWM, and temp limits enabled.\n",
-+ client->id );
-+ }
-+
-+ value = data->config3 ;
-+ if( data->config3 & CFG3_GPIO16_ENABLE ) {
-+ printk("adm1026(%d): GPIO16 enabled. THERM pin disabled.\n",
-+ client->id );
-+ } else {
-+ printk("adm1026(%d): THERM pin enabled. GPIO16 disabled.\n",
-+ client->id );
-+ }
-+ if( data->config3 & CFG3_VREF_250 ) {
-+ printk("adm1026(%d): Vref is 2.50 Volts.\n", client->id );
-+ } else {
-+ printk("adm1026(%d): Vref is 1.82 Volts.\n", client->id );
-+ }
-+
-+ /* Read and pick apart the existing GPIO configuration */
-+ value = 0 ;
-+ for( i = 0 ; i <= 15 ; ++i ) {
-+ if( (i & 0x03) == 0 ) {
-+ value = adm1026_read_value(client,
-+ ADM1026_REG_GPIO_CFG_0_3 + i/4 );
-+ }
-+ data->gpio_config[i] = value & 0x03 ;
-+ value >>= 2 ;
-+ }
-+ data->gpio_config[16] = (data->config3 >> 6) & 0x03 ;
-+
-+ /* ... and then print it */
-+ adm1026_print_gpio(client);
-+
-+ /* If the user asks us to reprogram the GPIO config, then
-+ * do it now. But only if this is the first ADM1026.
-+ */
-+ if( client->id == 0
-+ && (gpio_input[0] != -1 || gpio_output[0] != -1
-+ || gpio_inverted[0] != -1 || gpio_normal[0] != -1
-+ || gpio_fan[0] != -1 ) ) {
-+ adm1026_fixup_gpio(client);
-+ }
-+
-+ /* WE INTENTIONALLY make no changes to the limits,
-+ * offsets, pwms and fans. If they were
-+ * configured, we don't want to mess with them.
-+ * If they weren't, the default is generally safe
-+ * and will suffice until 'sensors -s' can be run.
-+ */
-+
-+ /* Start monitoring */
-+ value = adm1026_read_value(client, ADM1026_REG_CONFIG1);
-+
-+ /* Set MONITOR, clear interrupt acknowledge and s/w reset */
-+ value = (value | CFG1_MONITOR) & (~CFG1_INT_CLEAR & ~CFG1_RESET) ;
-+#ifdef DEBUG
-+ printk("adm1026(%d): Setting CONFIG to: 0x%02x\n", client->id, value );
-+#endif
-+ data->config1 = value ;
-+ adm1026_write_value(client, ADM1026_REG_CONFIG1, value);
-+
-+}
-+
-+void adm1026_print_gpio(struct i2c_client *client)
-+{
-+ struct adm1026_data *data = client->data;
-+ int i ;
-+
-+ printk("adm1026(%d): GPIO config is:\nadm1026(%d):",
-+ client->id, client->id );
-+ for( i = 0 ; i <= 7 ; ++i ) {
-+ if( data->config2 & (1 << i) ) {
-+ printk( " %sGP%s%d",
-+ data->gpio_config[i] & 0x02 ? "" : "!",
-+ data->gpio_config[i] & 0x01 ? "OUT" : "IN",
-+ i );
-+ } else {
-+ printk( " FAN%d", i );
-+ }
-+ }
-+ printk( "\nadm1026(%d):", client->id );
-+ for( i = 8 ; i <= 15 ; ++i ) {
-+ printk( " %sGP%s%d",
-+ data->gpio_config[i] & 0x02 ? "" : "!",
-+ data->gpio_config[i] & 0x01 ? "OUT" : "IN",
-+ i );
-+ }
-+ if( data->config3 & CFG3_GPIO16_ENABLE ) {
-+ printk( " %sGP%s16\n",
-+ data->gpio_config[16] & 0x02 ? "" : "!",
-+ data->gpio_config[16] & 0x01 ? "OUT" : "IN" );
-+ } else {
-+ /* GPIO16 is THERM */
-+ printk( " THERM\n" );
-+ }
-+}
-+
-+void adm1026_fixup_gpio(struct i2c_client *client)
-+{
-+ struct adm1026_data *data = client->data;
-+ int i ;
-+ int value ;
-+
-+ /* Make the changes requested. */
-+ /* We may need to unlock/stop monitoring or soft-reset the
-+ * chip before we can make changes. This hasn't been
-+ * tested much. FIXME
-+ */
-+
-+ /* Make outputs */
-+ for( i = 0 ; i <= 16 ; ++i ) {
-+ if( gpio_output[i] >= 0 && gpio_output[i] <= 16 ) {
-+ data->gpio_config[gpio_output[i]] |= 0x01 ;
-+ }
-+ /* if GPIO0-7 is output, it isn't a FAN tach */
-+ if( gpio_output[i] >= 0 && gpio_output[i] <= 7 ) {
-+ data->config2 |= 1 << gpio_output[i] ;
-+ }
-+ }
-+
-+ /* Input overrides output */
-+ for( i = 0 ; i <= 16 ; ++i ) {
-+ if( gpio_input[i] >= 0 && gpio_input[i] <= 16 ) {
-+ data->gpio_config[gpio_input[i]] &= ~ 0x01 ;
-+ }
-+ /* if GPIO0-7 is input, it isn't a FAN tach */
-+ if( gpio_input[i] >= 0 && gpio_input[i] <= 7 ) {
-+ data->config2 |= 1 << gpio_input[i] ;
-+ }
-+ }
-+
-+ /* Inverted */
-+ for( i = 0 ; i <= 16 ; ++i ) {
-+ if( gpio_inverted[i] >= 0 && gpio_inverted[i] <= 16 ) {
-+ data->gpio_config[gpio_inverted[i]] &= ~ 0x02 ;
-+ }
-+ }
-+
-+ /* Normal overrides inverted */
-+ for( i = 0 ; i <= 16 ; ++i ) {
-+ if( gpio_normal[i] >= 0 && gpio_normal[i] <= 16 ) {
-+ data->gpio_config[gpio_normal[i]] |= 0x02 ;
-+ }
-+ }
-+
-+ /* Fan overrides input and output */
-+ for( i = 0 ; i <= 7 ; ++i ) {
-+ if( gpio_fan[i] >= 0 && gpio_fan[i] <= 7 ) {
-+ data->config2 &= ~( 1 << gpio_fan[i] );
-+ }
-+ }
-+
-+ /* Write new configs to registers */
-+ adm1026_write_value(client, ADM1026_REG_CONFIG2, data->config2);
-+ data->config3 = (data->config3 & 0x3f)
-+ | ((data->gpio_config[16] & 0x03) << 6) ;
-+ adm1026_write_value(client, ADM1026_REG_CONFIG3, data->config3);
-+ for( i = 15, value = 0 ; i >= 0 ; --i ) {
-+ value <<= 2 ;
-+ value |= data->gpio_config[i] & 0x03 ;
-+ if( (i & 0x03) == 0 ) {
-+ adm1026_write_value(client,
-+ ADM1026_REG_GPIO_CFG_0_3 + i/4,
-+ value );
-+ value = 0 ;
-+ }
-+ }
-+
-+ /* Print the new config */
-+ adm1026_print_gpio(client);
-+}
-+
-+void adm1026_update_client(struct i2c_client *client)
-+{
-+ struct adm1026_data *data = client->data;
-+ int i;
-+ long value, alarms, gpio ;
-+
-+ down(&data->update_lock);
-+
-+ if (!data->valid
-+ || (jiffies - data->last_reading > ADM1026_DATA_INTERVAL )) {
-+ /* Things that change quickly */
-+
-+#ifdef DEBUG
-+ printk("adm1026(%d): Reading sensor values\n", client->id);
-+#endif
-+ for (i = 0 ; i <= 16 ; ++i) {
-+ data->in[i] =
-+ adm1026_read_value(client, ADM1026_REG_IN(i));
-+ }
-+
-+ for (i = 0 ; i <= 7 ; ++i) {
-+ data->fan[i] =
-+ adm1026_read_value(client, ADM1026_REG_FAN(i));
-+ }
-+
-+ for (i = 0 ; i <= 2 ; ++i) {
-+ /* NOTE: temp[] is s8 and we assume 2's complement
-+ * "conversion" in the assignment */
-+ data->temp[i] =
-+ adm1026_read_value(client, ADM1026_REG_TEMP(i));
-+ }
-+
-+ data->pwm = adm1026_read_value(client, ADM1026_REG_PWM);
-+ data->analog_out = adm1026_read_value(client, ADM1026_REG_DAC);
-+
-+ /* GPIO16 is MSbit of alarms, move it to gpio */
-+ alarms = adm1026_read_value(client, ADM1026_REG_STATUS4);
-+ gpio = alarms & 0x80 ? 0x0100 : 0 ; /* GPIO16 */
-+ alarms &= 0x7f ;
-+ alarms <<= 8 ;
-+ alarms |= adm1026_read_value(client, ADM1026_REG_STATUS3);
-+ alarms <<= 8 ;
-+ alarms |= adm1026_read_value(client, ADM1026_REG_STATUS2);
-+ alarms <<= 8 ;
-+ alarms |= adm1026_read_value(client, ADM1026_REG_STATUS1);
-+ data->alarms = alarms ;
-+
-+ /* Read the GPIO values */
-+ gpio |= adm1026_read_value(client, ADM1026_REG_GPIO_STATUS_8_15);
-+ gpio <<= 8 ;
-+ gpio |= adm1026_read_value(client, ADM1026_REG_GPIO_STATUS_0_7);
-+ data->gpio = gpio ;
-+
-+ data->last_reading = jiffies ;
-+ }; /* last_reading */
-+
-+ if (!data->valid
-+ || (jiffies - data->last_config > ADM1026_CONFIG_INTERVAL) ) {
-+ /* Things that don't change often */
-+
-+#ifdef DEBUG
-+ printk("adm1026(%d): Reading config values\n", client->id);
-+#endif
-+ for (i = 0 ; i <= 16 ; ++i) {
-+ data->in_min[i] =
-+ adm1026_read_value(client, ADM1026_REG_IN_MIN(i));
-+ data->in_max[i] =
-+ adm1026_read_value(client, ADM1026_REG_IN_MAX(i));
-+ }
-+
-+ value = adm1026_read_value(client, ADM1026_REG_FAN_DIV_0_3)
-+ | (adm1026_read_value(client, ADM1026_REG_FAN_DIV_4_7) << 8);
-+ for (i = 0 ; i <= 7 ; ++i) {
-+ data->fan_min[i] =
-+ adm1026_read_value(client, ADM1026_REG_FAN_MIN(i));
-+ data->fan_div[i] = DIV_FROM_REG(value & 0x03);
-+ value >>= 2 ;
-+ }
-+
-+ for (i = 0; i <= 2; ++i) {
-+ /* NOTE: temp_xxx[] are s8 and we assume 2's complement
-+ * "conversion" in the assignment */
-+ data->temp_min[i] =
-+ adm1026_read_value(client, ADM1026_REG_TEMP_MIN(i));
-+ data->temp_max[i] =
-+ adm1026_read_value(client, ADM1026_REG_TEMP_MAX(i));
-+ data->temp_tmin[i] =
-+ adm1026_read_value(client, ADM1026_REG_TEMP_TMIN(i));
-+ data->temp_therm[i] =
-+ adm1026_read_value(client, ADM1026_REG_TEMP_THERM(i));
-+ data->temp_offset[i] =
-+ adm1026_read_value(client, ADM1026_REG_TEMP_OFFSET(i));
-+ }
-+
-+ /* Read the STATUS/alarm masks */
-+ alarms = adm1026_read_value(client, ADM1026_REG_MASK4);
-+ gpio = alarms & 0x80 ? 0x0100 : 0 ; /* GPIO16 */
-+ alarms = (alarms & 0x7f) << 8 ;
-+ alarms |= adm1026_read_value(client, ADM1026_REG_MASK3);
-+ alarms <<= 8 ;
-+ alarms |= adm1026_read_value(client, ADM1026_REG_MASK2);
-+ alarms <<= 8 ;
-+ alarms |= adm1026_read_value(client, ADM1026_REG_MASK1);
-+ data->alarm_mask = alarms ;
-+
-+ /* Read the GPIO values */
-+ gpio |= adm1026_read_value(client, ADM1026_REG_GPIO_MASK_8_15);
-+ gpio <<= 8 ;
-+ gpio |= adm1026_read_value(client, ADM1026_REG_GPIO_MASK_0_7);
-+ data->gpio_mask = gpio ;
-+
-+ /* Read the GPIO config */
-+ data->config2 = adm1026_read_value(client, ADM1026_REG_CONFIG2);
-+ data->config3 = adm1026_read_value(client, ADM1026_REG_CONFIG3);
-+ data->gpio_config[16] = (data->config3 >> 6) & 0x03 ;
-+
-+ value = 0 ;
-+ for( i = 0 ; i <= 15 ; ++i ) {
-+ if( (i & 0x03) == 0 ) {
-+ value = adm1026_read_value(client,
-+ ADM1026_REG_GPIO_CFG_0_3 + i/4 );
-+ }
-+ data->gpio_config[i] = value & 0x03 ;
-+ value >>= 2 ;
-+ }
-+
-+ data->last_config = jiffies;
-+ }; /* last_config */
-+
-+ /* We don't know where or even _if_ the VID might be on the GPIO
-+ * pins. But the datasheet gives an example config showing
-+ * GPIO11-15 being used to monitor VID0-4, so we go with that
-+ * but make the vid WRITEABLE so if it's wrong, the user can
-+ * set it in /etc/sensors.conf perhaps using an expression or
-+ * 0 to trigger a re-read from the GPIO pins.
-+ */
-+ if( data->vid == ADM1026_INIT_VID ) {
-+ /* Hasn't been set yet, make a bold assumption */
-+ printk("adm1026(%d): Setting VID from GPIO11-15.\n",
-+ client->id );
-+ data->vid = (data->gpio >> 11) & 0x1f ;
-+ }
-+
-+ data->valid = 1;
-+
-+ up(&data->update_lock);
-+}
-+
-+
-+/* The following functions are the call-back functions of the /proc/sys and
-+ sysctl files. The appropriate function is referenced in the ctl_table
-+ extra1 field.
-+
-+ Each function must return the magnitude (power of 10 to divide the
-+ data with) if it is called with operation set to SENSORS_PROC_REAL_INFO.
-+ It must put a maximum of *nrels elements in results reflecting the
-+ data of this file, and set *nrels to the number it actually put in
-+ it, if operation is SENSORS_PROC_REAL_READ. Finally, it must get
-+ up to *nrels elements from results and write them to the chip, if
-+ operations is SENSORS_PROC_REAL_WRITE.
-+ */
-+void adm1026_in(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct adm1026_data *data = client->data;
-+ int nr = ctl_name - ADM1026_SYSCTL_IN0;
-+
-+ /* We handle in0 - in15 here. in16 (-12V) is handled below */
-+ if (nr < 0 || nr > 15)
-+ return ; /* ERROR */
-+
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 3; /* 1.000 */
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ adm1026_update_client(client);
-+ results[0] = INS_FROM_REG(nr,data->in_min[nr]);
-+ results[1] = INS_FROM_REG(nr,data->in_max[nr]);
-+ results[2] = INS_FROM_REG(nr,data->in[nr]);
-+ *nrels_mag = 3;
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ down(&data->update_lock);
-+ if (*nrels_mag > 1) {
-+ data->in_max[nr] = INS_TO_REG(nr,results[1]);
-+ adm1026_write_value(client, ADM1026_REG_IN_MAX(nr),
-+ data->in_max[nr]);
-+ }
-+ if (*nrels_mag > 0) {
-+ data->in_min[nr] = INS_TO_REG(nr,results[0]);
-+ adm1026_write_value(client, ADM1026_REG_IN_MIN(nr),
-+ data->in_min[nr]);
-+ }
-+ up(&data->update_lock);
-+ }
-+}
-+
-+void adm1026_in16(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct adm1026_data *data = client->data;
-+ int nr = ctl_name - ADM1026_SYSCTL_IN0;
-+
-+ /* We handle in16 (-12V) here */
-+ if (nr != 16)
-+ return ; /* ERROR */
-+
-+ /* Apply offset and swap min/max so that min is 90% of
-+ * target and max is 110% of target.
-+ */
-+
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 3; /* 1.000 */
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ adm1026_update_client(client);
-+ results[0] = INS_FROM_REG(nr,data->in_max[nr])-NEG12_OFFSET ;
-+ results[1] = INS_FROM_REG(nr,data->in_min[nr])-NEG12_OFFSET ;
-+ results[2] = INS_FROM_REG(nr,data->in[nr])-NEG12_OFFSET ;
-+ *nrels_mag = 3;
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ down(&data->update_lock);
-+ if (*nrels_mag > 1) {
-+ data->in_min[nr] = INS_TO_REG(nr,results[1]+NEG12_OFFSET);
-+ adm1026_write_value(client, ADM1026_REG_IN_MIN(nr),
-+ data->in_min[nr]);
-+ }
-+ if (*nrels_mag > 0) {
-+ data->in_max[nr] = INS_TO_REG(nr,results[0]+NEG12_OFFSET);
-+ adm1026_write_value(client, ADM1026_REG_IN_MAX(nr),
-+ data->in_max[nr]);
-+ }
-+ up(&data->update_lock);
-+ }
-+}
-+
-+void adm1026_fan(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct adm1026_data *data = client->data;
-+ int nr = ctl_name - ADM1026_SYSCTL_FAN0 ;
-+
-+ if (nr < 0 || nr > 7)
-+ return ; /* ERROR */
-+
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 0;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ adm1026_update_client(client);
-+ results[0] = FAN_FROM_REG(data->fan_min[nr], data->fan_div[nr]);
-+ results[1] = FAN_FROM_REG(data->fan[nr], data->fan_div[nr]);
-+ *nrels_mag = 2;
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ down(&data->update_lock);
-+ if (*nrels_mag > 0) {
-+ data->fan_min[nr] = FAN_TO_REG(results[0],
-+ data->fan_div[nr]);
-+ adm1026_write_value(client, ADM1026_REG_FAN_MIN(nr),
-+ data->fan_min[nr]);
-+ }
-+ up(&data->update_lock);
-+ }
-+}
-+
-+/* Adjust fan_min to account for new fan divisor */
-+void adm1026_fixup_fan_min(struct i2c_client *client, int fan, int old_div)
-+{
-+ struct adm1026_data *data = client->data;
-+ int new_div = data->fan_div[fan] ;
-+ int new_min;
-+
-+ /* 0 and 0xff are special. Don't adjust them */
-+ if( data->fan_min[fan] == 0 || data->fan_min[fan] == 0xff ) {
-+ return ;
-+ }
-+
-+ new_min = data->fan_min[fan] * old_div / new_div ;
-+ new_min = SENSORS_LIMIT(new_min, 1, 254);
-+ data->fan_min[fan] = new_min ;
-+ adm1026_write_value(client, ADM1026_REG_FAN_MIN(fan), new_min);
-+}
-+
-+void adm1026_fan_div(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct adm1026_data *data = client->data;
-+ int i ;
-+ int value, div, old ;
-+
-+ if (ctl_name != ADM1026_SYSCTL_FAN_DIV)
-+ return ; /* ERROR */
-+
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 0;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ adm1026_update_client(client);
-+ for( i = 0 ; i <= 7 ; ++i ) {
-+ results[i] = data->fan_div[i] ;
-+ }
-+ *nrels_mag = 8;
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ down(&data->update_lock);
-+ value = 0 ;
-+ for( i = 7 ; i >= 0 ; --i ) {
-+ value <<= 2 ;
-+ if (*nrels_mag > i) {
-+ old = data->fan_div[i] ;
-+ div = DIV_TO_REG(results[i]) ;
-+ data->fan_div[i] = DIV_FROM_REG(div) ;
-+ if( data->fan_div[i] != old ) {
-+ adm1026_fixup_fan_min(client,i,old);
-+ }
-+ } else {
-+ div = DIV_TO_REG(data->fan_div[i]) ;
-+ }
-+ value |= div ;
-+ }
-+ adm1026_write_value(client, ADM1026_REG_FAN_DIV_0_3,
-+ value & 0xff);
-+ adm1026_write_value(client, ADM1026_REG_FAN_DIV_4_7,
-+ (value >> 8) & 0xff);
-+ up(&data->update_lock);
-+ }
-+}
-+
-+void adm1026_temp(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct adm1026_data *data = client->data;
-+ int nr = ctl_name - ADM1026_SYSCTL_TEMP1 ;
-+
-+ if (nr < 0 || nr > 2)
-+ return ; /* ERROR */
-+
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 0;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ adm1026_update_client(client);
-+ results[0] = TEMP_FROM_REG(data->temp_min[nr]);
-+ results[1] = TEMP_FROM_REG(data->temp_max[nr]);
-+ results[2] = TEMP_FROM_REG(data->temp[nr]);
-+ *nrels_mag = 3;
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ down(&data->update_lock);
-+ if (*nrels_mag > 1) {
-+ data->temp_max[nr] = TEMP_TO_REG(results[1]);
-+ adm1026_write_value(client, ADM1026_REG_TEMP_MAX(nr),
-+ data->temp_max[nr]);
-+ }
-+ if (*nrels_mag > 0) {
-+ data->temp_min[nr] = TEMP_TO_REG(results[0]);
-+ adm1026_write_value(client, ADM1026_REG_TEMP_MIN(nr),
-+ data->temp_min[nr]);
-+ }
-+ up(&data->update_lock);
-+ }
-+}
-+
-+void adm1026_temp_offset(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct adm1026_data *data = client->data;
-+ int nr = ctl_name - ADM1026_SYSCTL_TEMP_OFFSET1 ;
-+
-+ if (nr < 0 || nr > 2)
-+ return ; /* ERROR */
-+
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 0;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ adm1026_update_client(client);
-+ results[0] = TEMP_FROM_REG(data->temp_offset[nr]);
-+ *nrels_mag = 1;
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ down(&data->update_lock);
-+ if (*nrels_mag > 0) {
-+ data->temp_offset[nr] = TEMP_TO_REG(results[0]);
-+ adm1026_write_value(client, ADM1026_REG_TEMP_OFFSET(nr),
-+ data->temp_offset[nr]);
-+ }
-+ up(&data->update_lock);
-+ }
-+}
-+
-+void adm1026_temp_tmin(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct adm1026_data *data = client->data;
-+ int nr = ctl_name - ADM1026_SYSCTL_TEMP_TMIN1 ;
-+
-+ if (nr < 0 || nr > 2)
-+ return ; /* ERROR */
-+
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 0;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ adm1026_update_client(client);
-+ results[0] = TEMP_FROM_REG(data->temp_tmin[nr]);
-+ *nrels_mag = 1;
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ down(&data->update_lock);
-+ if (*nrels_mag > 0) {
-+ data->temp_tmin[nr] = TEMP_TO_REG(results[0]);
-+ adm1026_write_value(client, ADM1026_REG_TEMP_TMIN(nr),
-+ data->temp_tmin[nr]);
-+ }
-+ up(&data->update_lock);
-+ }
-+}
-+
-+void adm1026_temp_therm(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct adm1026_data *data = client->data;
-+ int nr = ctl_name - ADM1026_SYSCTL_TEMP_THERM1 ;
-+
-+ if (nr < 0 || nr > 2)
-+ return ; /* ERROR */
-+
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 0;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ adm1026_update_client(client);
-+ results[0] = TEMP_FROM_REG(data->temp_therm[nr]);
-+ *nrels_mag = 1;
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ down(&data->update_lock);
-+ if (*nrels_mag > 0) {
-+ data->temp_therm[nr] = TEMP_TO_REG(results[0]);
-+ adm1026_write_value(client, ADM1026_REG_TEMP_THERM(nr),
-+ data->temp_therm[nr]);
-+ }
-+ up(&data->update_lock);
-+ }
-+}
-+
-+void adm1026_pwm(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct adm1026_data *data = client->data;
-+
-+ if (ctl_name != ADM1026_SYSCTL_PWM)
-+ return ; /* ERROR */
-+
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 0;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ adm1026_update_client(client);
-+ results[0] = PWM_FROM_REG(data->pwm);
-+ results[1] = 1 ; /* Always enabled */
-+ *nrels_mag = 2;
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ down(&data->update_lock);
-+ /* PWM enable is read-only */
-+ if (*nrels_mag > 0) {
-+ data->pwm = PWM_TO_REG(results[0]);
-+ adm1026_write_value(client, ADM1026_REG_PWM,
-+ data->pwm);
-+ }
-+ up(&data->update_lock);
-+ }
-+}
-+
-+void adm1026_analog_out(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct adm1026_data *data = client->data;
-+
-+ if (ctl_name != ADM1026_SYSCTL_ANALOG_OUT)
-+ return ; /* ERROR */
-+
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 0; /* 0 - 255 */
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ adm1026_update_client(client);
-+ results[0] = DAC_FROM_REG(data->analog_out);
-+ *nrels_mag = 1;
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ down(&data->update_lock);
-+ if (*nrels_mag > 0) {
-+ data->analog_out = DAC_TO_REG(results[0]);
-+ adm1026_write_value(client, ADM1026_REG_DAC,
-+ data->analog_out);
-+ }
-+ up(&data->update_lock);
-+ }
-+}
-+
-+void adm1026_afc(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct adm1026_data *data = client->data;
-+
-+ if (ctl_name != ADM1026_SYSCTL_AFC)
-+ return ; /* ERROR */
-+
-+ /* PWM auto fan control, DAC auto fan control */
-+
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 0;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ adm1026_update_client(client);
-+ results[0] = (data->config1 & CFG1_PWM_AFC) != 0 ;
-+ results[1] = (data->config1 & CFG1_DAC_AFC) != 0 ;
-+ *nrels_mag = 2;
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ down(&data->update_lock);
-+ if (*nrels_mag > 1) {
-+ data->config1 = (data->config1 & ~CFG1_DAC_AFC)
-+ | (results[1] ? CFG1_DAC_AFC : 0) ;
-+ }
-+ if (*nrels_mag > 0) {
-+ data->config1 = (data->config1 & ~CFG1_PWM_AFC)
-+ | (results[0] ? CFG1_PWM_AFC : 0) ;
-+ adm1026_write_value(client, ADM1026_REG_CONFIG1,
-+ data->config1);
-+ }
-+ up(&data->update_lock);
-+ }
-+}
-+
-+void adm1026_vid(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct adm1026_data *data = client->data;
-+
-+ if( ctl_name != ADM1026_SYSCTL_VID )
-+ return ; /* ERROR */
-+
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 3;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ adm1026_update_client(client);
-+ results[0] = VID_FROM_REG((data->vid)&0x3f,data->vrm);
-+ *nrels_mag = 1;
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ down(&data->update_lock);
-+ /* Hmmm... There isn't a VID_TO_REG mapping */
-+ if (*nrels_mag > 0) {
-+ if( results[0] >= 0 ) {
-+ data->vid = results[0] & 0x3f ;
-+ } else {
-+ data->vid = ADM1026_INIT_VID ;
-+ }
-+ }
-+ up(&data->update_lock);
-+ }
-+
-+}
-+
-+void adm1026_vrm(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct adm1026_data *data = client->data;
-+
-+ if( ctl_name != ADM1026_SYSCTL_VRM )
-+ return ; /* ERROR */
-+
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 1;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ results[0] = data->vrm ;
-+ *nrels_mag = 1;
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ if (*nrels_mag > 0) {
-+ data->vrm = results[0] ;
-+ }
-+ }
-+}
-+
-+void adm1026_alarms(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct adm1026_data *data = client->data;
-+
-+ if( ctl_name != ADM1026_SYSCTL_ALARMS )
-+ return ; /* ERROR */
-+
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 0;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ adm1026_update_client(client);
-+ results[0] = data->alarms ;
-+ *nrels_mag = 1;
-+ }
-+ /* FIXME: Perhaps we should implement a write function
-+ * to clear an alarm?
-+ */
-+}
-+
-+void adm1026_alarm_mask(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results)
-+{
-+ struct adm1026_data *data = client->data;
-+ unsigned long mask ;
-+
-+ if( ctl_name != ADM1026_SYSCTL_ALARM_MASK )
-+ return ; /* ERROR */
-+
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 0;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ adm1026_update_client(client);
-+ results[0] = data->alarm_mask ;
-+ *nrels_mag = 1;
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ down(&data->update_lock);
-+ if (*nrels_mag > 0) {
-+ data->alarm_mask = results[0] & 0x7fffffff ;
-+ mask = data->alarm_mask
-+ | (data->gpio_mask & 0x10000 ? 0x80000000 : 0) ;
-+ adm1026_write_value(client, ADM1026_REG_MASK1,
-+ mask & 0xff);
-+ mask >>= 8 ;
-+ adm1026_write_value(client, ADM1026_REG_MASK2,
-+ mask & 0xff);
-+ mask >>= 8 ;
-+ adm1026_write_value(client, ADM1026_REG_MASK3,
-+ mask & 0xff);
-+ mask >>= 8 ;
-+ adm1026_write_value(client, ADM1026_REG_MASK4,
-+ mask & 0xff);
-+ }
-+ up(&data->update_lock);
-+ }
-+}
-+
-+void adm1026_gpio(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct adm1026_data *data = client->data;
-+ long gpio ;
-+
-+ if( ctl_name != ADM1026_SYSCTL_GPIO )
-+ return ; /* ERROR */
-+
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 0;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ adm1026_update_client(client);
-+ results[0] = data->gpio ;
-+ *nrels_mag = 1;
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ down(&data->update_lock);
-+ if (*nrels_mag > 0) {
-+ data->gpio = results[0] & 0x1ffff ;
-+ gpio = data->gpio ;
-+ adm1026_write_value(client,
-+ ADM1026_REG_GPIO_STATUS_0_7,
-+ gpio & 0xff );
-+ gpio >>= 8 ;
-+ adm1026_write_value(client,
-+ ADM1026_REG_GPIO_STATUS_8_15,
-+ gpio & 0xff );
-+ gpio = ((gpio >> 1) & 0x80)
-+ | (data->alarms >> 24 & 0x7f);
-+ adm1026_write_value(client,
-+ ADM1026_REG_STATUS4,
-+ gpio & 0xff );
-+ }
-+ up(&data->update_lock);
-+ }
-+}
-+
-+void adm1026_gpio_mask(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results)
-+{
-+ struct adm1026_data *data = client->data;
-+ long mask ;
-+
-+ if( ctl_name != ADM1026_SYSCTL_GPIO_MASK )
-+ return ; /* ERROR */
-+
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 0;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ adm1026_update_client(client);
-+ results[0] = data->gpio_mask ;
-+ *nrels_mag = 1;
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ down(&data->update_lock);
-+ if (*nrels_mag > 0) {
-+ data->gpio_mask = results[0] & 0x1ffff ;
-+ mask = data->gpio_mask ;
-+ adm1026_write_value(client, ADM1026_REG_GPIO_MASK_0_7,
-+ mask & 0xff);
-+ mask >>= 8 ;
-+ adm1026_write_value(client, ADM1026_REG_GPIO_MASK_8_15,
-+ mask & 0xff);
-+ mask = ((mask >> 1) & 0x80)
-+ | (data->alarm_mask >> 24 & 0x7f);
-+ adm1026_write_value(client, ADM1026_REG_MASK1,
-+ mask & 0xff);
-+ }
-+ up(&data->update_lock);
-+ }
-+}
-+
-+static int __init sm_adm1026_init(void)
-+{
-+ printk("adm1026: Version %s (%s)\n", LM_VERSION, LM_DATE);
-+ printk("adm1026: See http://www.penguincomputing.com/lm_sensors for more info.\n" );
-+ return i2c_add_driver(&adm1026_driver);
-+}
-+
-+static void __exit sm_adm1026_exit(void)
-+{
-+ i2c_del_driver(&adm1026_driver);
-+}
-+
-+MODULE_LICENSE("GPL");
-+MODULE_AUTHOR("Philip Pokorny <ppokorny@penguincomputing.com");
-+MODULE_DESCRIPTION("ADM1026 driver");
-+
-+module_init(sm_adm1026_init);
-+module_exit(sm_adm1026_exit);
---- linux-old/drivers/sensors/adm9240.c Thu Jan 1 00:00:00 1970
-+++ linux/drivers/sensors/adm9240.c Mon Dec 13 20:18:44 2004
-@@ -0,0 +1,713 @@
-+/*
-+ adm9240.c - Part of lm_sensors, Linux kernel modules for hardware
-+ monitoring
-+ Copyright (C) 1999 Frodo Looijaard <frodol@dds.nl>
-+ and Philip Edelbrock <phil@netroedge.com>
-+
-+ 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., 675 Mass Ave, Cambridge, MA 02139, USA.
-+*/
-+
-+/* Supports ADM9240, DS1780, and LM81. See doc/chips/adm9240 for details */
-+
-+/*
-+ A couple notes about the ADM9240:
-+
-+* It claims to be 'LM7x' register compatible. This must be in reference
-+ to only the LM78, because it is missing stuff to emulate LM75's as well.
-+ (like the Winbond W83781 does)
-+
-+* This driver was written from rev. 0 of the PDF, but it seems well
-+ written and complete (unlike the W83781 which is horrible and has
-+ supposidly gone through a few revisions.. rev 0 of that one must
-+ have been in crayon on construction paper...)
-+
-+* All analog inputs can range from 0 to 2.5, eventhough some inputs are
-+ marked as being 5V, 12V, etc. I don't have any real voltages going
-+ into my prototype, so I'm not sure that things are computed right,
-+ but at least the limits seem to be working OK.
-+
-+* Another curiousity is that the fan_div seems to be read-only. I.e.,
-+ any written value to it doesn't seem to make any difference. The
-+ fan_div seems to be 'stuck' at 2 (which isn't a bad value in most cases).
-+
-+
-+ --Phil
-+
-+*/
-+
-+#include <linux/module.h>
-+#include <linux/slab.h>
-+#include <linux/i2c.h>
-+#include <linux/i2c-proc.h>
-+#include <linux/init.h>
-+#define LM_DATE "20041007"
-+#define LM_VERSION "2.8.8"
-+
-+/* Addresses to scan */
-+static unsigned short normal_i2c[] = { SENSORS_I2C_END };
-+static unsigned short normal_i2c_range[] = { 0x2c, 0x2f, SENSORS_I2C_END };
-+static unsigned int normal_isa[] = { SENSORS_ISA_END };
-+static unsigned int normal_isa_range[] = { SENSORS_ISA_END };
-+
-+/* Insmod parameters */
-+SENSORS_INSMOD_3(adm9240, ds1780, lm81);
-+
-+/* Many ADM9240 constants specified below */
-+
-+#define ADM9240_REG_IN_MAX(nr) (0x2b + (nr) * 2)
-+#define ADM9240_REG_IN_MIN(nr) (0x2c + (nr) * 2)
-+#define ADM9240_REG_IN(nr) (0x20 + (nr))
-+
-+/* The ADM9240 registers */
-+#define ADM9240_REG_TEST 0x15
-+#define ADM9240_REG_ANALOG_OUT 0x19
-+/* These are all read-only */
-+#define ADM9240_REG_2_5V 0x20
-+#define ADM9240_REG_VCCP1 0x21
-+#define ADM9240_REG_3_3V 0x22
-+#define ADM9240_REG_5V 0x23
-+#define ADM9240_REG_12V 0x24
-+#define ADM9240_REG_VCCP2 0x25
-+#define ADM9240_REG_TEMP 0x27
-+#define ADM9240_REG_FAN1 0x28
-+#define ADM9240_REG_FAN2 0x29
-+#define ADM9240_REG_COMPANY_ID 0x3E /* 0x23 for ADM9240; 0xDA for DS1780 */
-+ /* 0x01 for LM81 */
-+#define ADM9240_REG_DIE_REV 0x3F
-+/* These are read/write */
-+#define ADM9240_REG_2_5V_HIGH 0x2B
-+#define ADM9240_REG_2_5V_LOW 0x2C
-+#define ADM9240_REG_VCCP1_HIGH 0x2D
-+#define ADM9240_REG_VCCP1_LOW 0x2E
-+#define ADM9240_REG_3_3V_HIGH 0x2F
-+#define ADM9240_REG_3_3V_LOW 0x30
-+#define ADM9240_REG_5V_HIGH 0x31
-+#define ADM9240_REG_5V_LOW 0x32
-+#define ADM9240_REG_12V_HIGH 0x33
-+#define ADM9240_REG_12V_LOW 0x34
-+#define ADM9240_REG_VCCP2_HIGH 0x35
-+#define ADM9240_REG_VCCP2_LOW 0x36
-+#define ADM9240_REG_TCRIT_LIMIT 0x37 /* LM81 only - not supported */
-+#define ADM9240_REG_LOW_LIMIT 0x38 /* LM81 only - not supported */
-+#define ADM9240_REG_TOS 0x39
-+#define ADM9240_REG_THYST 0x3A
-+#define ADM9240_REG_FAN1_MIN 0x3B
-+#define ADM9240_REG_FAN2_MIN 0x3C
-+
-+#define ADM9240_REG_CONFIG 0x40
-+#define ADM9240_REG_INT1_STAT 0x41
-+#define ADM9240_REG_INT2_STAT 0x42
-+#define ADM9240_REG_INT1_MASK 0x43
-+#define ADM9240_REG_INT2_MASK 0x44
-+
-+#define ADM9240_REG_COMPAT 0x45 /* dummy compat. register for other drivers? */
-+#define ADM9240_REG_CHASSIS_CLEAR 0x46
-+#define ADM9240_REG_VID_FAN_DIV 0x47
-+#define ADM9240_REG_I2C_ADDR 0x48
-+#define ADM9240_REG_VID4 0x49
-+#define ADM9240_REG_TEMP_CONFIG 0x4B
-+#define ADM9240_REG_EXTMODE1 0x4C /* LM81 only - not supported */
-+#define ADM9240_REG_EXTMODE2 0x4D /* LM81 only - not supported */
-+
-+/* Conversions. Rounding and limit checking is only done on the TO_REG
-+ variants. Note that you should be a bit careful with which arguments
-+ these macros are called: arguments may be evaluated more than once.
-+ Fixing this is just not worth it. */
-+#define IN_TO_REG(val,nr) (SENSORS_LIMIT((val), 0, 255))
-+#define IN_FROM_REG(val,nr) (val)
-+
-+static inline u8 FAN_TO_REG(long rpm, int div)
-+{
-+ if (rpm == 0)
-+ return 255;
-+ rpm = SENSORS_LIMIT(rpm, 1, 1000000);
-+ return SENSORS_LIMIT((1350000 + rpm * div / 2) / (rpm * div), 1,
-+ 254);
-+}
-+
-+#define FAN_FROM_REG(val,div) ((val)==0?-1:\
-+ (val)==255?0:1350000/((div)*(val)))
-+
-+#define TEMP_FROM_REG(temp) ((temp)<256 ? (temp) * 5 : \
-+ ((temp) - 512) * 5)
-+
-+#define TEMP_LIMIT_FROM_REG(val) (((val)>=0x80?(val)-0x100:(val))*10)
-+
-+#define TEMP_LIMIT_TO_REG(val) SENSORS_LIMIT(((val)<0?(((val)-5)/10)+256:\
-+ ((val)+5)/10), \
-+ 0,255)
-+
-+#define ALARMS_FROM_REG(val) (val)
-+
-+#define DIV_FROM_REG(val) (1 << (val))
-+#define DIV_TO_REG(val) ((val)==1?0:((val)==8?3:((val)==4?2:1)))
-+
-+#define VID_FROM_REG(val) ((val)==0x1f?0:(val)>=0x10?510-(val)*10:\
-+ 205-(val)*5)
-+
-+/* For each registered ADM9240, we need to keep some data in memory. */
-+struct adm9240_data {
-+ struct i2c_client client;
-+ int sysctl_id;
-+ enum chips type;
-+
-+ struct semaphore update_lock;
-+ char valid; /* !=0 if following fields are valid */
-+ unsigned long last_updated; /* In jiffies */
-+
-+ u8 in[6]; /* Register value */
-+ u8 in_max[6]; /* Register value */
-+ u8 in_min[6]; /* Register value */
-+ u8 fan[2]; /* Register value */
-+ u8 fan_min[2]; /* Register value */
-+ u8 fan_div[2]; /* Register encoding, shifted right */
-+ int temp; /* Temp, shifted right */
-+ u8 temp_os_max; /* Register value */
-+ u8 temp_os_hyst; /* Register value */
-+ u16 alarms; /* Register encoding, combined */
-+ u8 analog_out; /* Register value */
-+ u8 vid; /* Register value combined */
-+};
-+
-+
-+static int adm9240_attach_adapter(struct i2c_adapter *adapter);
-+static int adm9240_detect(struct i2c_adapter *adapter, int address,
-+ unsigned short flags, int kind);
-+static int adm9240_detach_client(struct i2c_client *client);
-+
-+static int adm9240_read_value(struct i2c_client *client, u8 reg);
-+static int adm9240_write_value(struct i2c_client *client, u8 reg, u8 value);
-+static void adm9240_update_client(struct i2c_client *client);
-+static void adm9240_init_client(struct i2c_client *client);
-+
-+
-+static void adm9240_in(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void adm9240_fan(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void adm9240_temp(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void adm9240_alarms(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void adm9240_fan_div(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void adm9240_analog_out(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag,
-+ long *results);
-+static void adm9240_vid(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+
-+static int adm9240_id = 0;
-+
-+static struct i2c_driver adm9240_driver = {
-+ .owner = THIS_MODULE,
-+ .name = "ADM9240 sensor driver",
-+ .id = I2C_DRIVERID_ADM9240,
-+ .flags = I2C_DF_NOTIFY,
-+ .attach_adapter = adm9240_attach_adapter,
-+ .detach_client = adm9240_detach_client,
-+};
-+
-+/* The /proc/sys entries */
-+
-+/* -- SENSORS SYSCTL START -- */
-+
-+#define ADM9240_SYSCTL_IN0 1000 /* Volts * 100 */
-+#define ADM9240_SYSCTL_IN1 1001
-+#define ADM9240_SYSCTL_IN2 1002
-+#define ADM9240_SYSCTL_IN3 1003
-+#define ADM9240_SYSCTL_IN4 1004
-+#define ADM9240_SYSCTL_IN5 1005
-+#define ADM9240_SYSCTL_FAN1 1101 /* Rotations/min */
-+#define ADM9240_SYSCTL_FAN2 1102
-+#define ADM9240_SYSCTL_TEMP 1250 /* Degrees Celcius * 100 */
-+#define ADM9240_SYSCTL_FAN_DIV 2000 /* 1, 2, 4 or 8 */
-+#define ADM9240_SYSCTL_ALARMS 2001 /* bitvector */
-+#define ADM9240_SYSCTL_ANALOG_OUT 2002
-+#define ADM9240_SYSCTL_VID 2003
-+
-+#define ADM9240_ALARM_IN0 0x0001
-+#define ADM9240_ALARM_IN1 0x0002
-+#define ADM9240_ALARM_IN2 0x0004
-+#define ADM9240_ALARM_IN3 0x0008
-+#define ADM9240_ALARM_IN4 0x0100
-+#define ADM9240_ALARM_IN5 0x0200
-+#define ADM9240_ALARM_FAN1 0x0040
-+#define ADM9240_ALARM_FAN2 0x0080
-+#define ADM9240_ALARM_TEMP 0x0010
-+#define ADM9240_ALARM_CHAS 0x1000
-+
-+/* -- SENSORS SYSCTL END -- */
-+
-+/* These files are created for each detected ADM9240. This is just a template;
-+ though at first sight, you might think we could use a statically
-+ allocated list, we need some way to get back to the parent - which
-+ is done through one of the 'extra' fields which are initialized
-+ when a new copy is allocated. */
-+static ctl_table adm9240_dir_table_template[] = {
-+ {ADM9240_SYSCTL_IN0, "in0", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &adm9240_in},
-+ {ADM9240_SYSCTL_IN1, "in1", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &adm9240_in},
-+ {ADM9240_SYSCTL_IN2, "in2", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &adm9240_in},
-+ {ADM9240_SYSCTL_IN3, "in3", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &adm9240_in},
-+ {ADM9240_SYSCTL_IN4, "in4", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &adm9240_in},
-+ {ADM9240_SYSCTL_IN5, "in5", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &adm9240_in},
-+ {ADM9240_SYSCTL_FAN1, "fan1", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &adm9240_fan},
-+ {ADM9240_SYSCTL_FAN2, "fan2", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &adm9240_fan},
-+ {ADM9240_SYSCTL_TEMP, "temp", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &adm9240_temp},
-+ {ADM9240_SYSCTL_FAN_DIV, "fan_div", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &adm9240_fan_div},
-+ {ADM9240_SYSCTL_ALARMS, "alarms", NULL, 0, 0444, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &adm9240_alarms},
-+ {ADM9240_SYSCTL_ANALOG_OUT, "analog_out", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &adm9240_analog_out},
-+ {ADM9240_SYSCTL_VID, "vid", NULL, 0, 0444, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &adm9240_vid},
-+ {0}
-+};
-+
-+static int adm9240_attach_adapter(struct i2c_adapter *adapter)
-+{
-+ return i2c_detect(adapter, &addr_data, adm9240_detect);
-+}
-+
-+static int adm9240_detect(struct i2c_adapter *adapter, int address,
-+ unsigned short flags, int kind)
-+{
-+ int i;
-+ struct i2c_client *new_client;
-+ struct adm9240_data *data;
-+ int err = 0;
-+ const char *type_name = "";
-+ const char *client_name = "";
-+
-+ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
-+ goto ERROR0;
-+
-+ /* OK. For now, we presume we have a valid client. We now create the
-+ client structure, even though we cannot fill it completely yet.
-+ But it allows us to access adm9240_{read,write}_value. */
-+
-+ if (!(data = kmalloc(sizeof(struct adm9240_data), GFP_KERNEL))) {
-+ err = -ENOMEM;
-+ goto ERROR0;
-+ }
-+
-+
-+ new_client = &data->client;
-+ new_client->addr = address;
-+ new_client->data = data;
-+ new_client->adapter = adapter;
-+ new_client->driver = &adm9240_driver;
-+ new_client->flags = 0;
-+
-+ /* Now, we do the remaining detection. */
-+
-+ if (kind < 0) {
-+ if (
-+ ((adm9240_read_value
-+ (new_client, ADM9240_REG_CONFIG) & 0x80) != 0x00)
-+ ||
-+ (adm9240_read_value(new_client, ADM9240_REG_I2C_ADDR)
-+ != address))
-+ goto ERROR1;
-+ }
-+
-+ /* Determine the chip type. */
-+ if (kind <= 0) {
-+ i = adm9240_read_value(new_client, ADM9240_REG_COMPANY_ID);
-+ if (i == 0x23)
-+ kind = adm9240;
-+ else if (i == 0xda)
-+ kind = ds1780;
-+ else if (i == 0x01)
-+ kind = lm81;
-+ else {
-+ if (kind == 0)
-+ printk
-+ ("adm9240.o: Ignoring 'force' parameter for unknown chip at "
-+ "adapter %d, address 0x%02x\n",
-+ i2c_adapter_id(adapter), address);
-+ goto ERROR1;
-+ }
-+ }
-+
-+ if (kind == adm9240) {
-+ type_name = "adm9240";
-+ client_name = "ADM9240 chip";
-+ } else if (kind == ds1780) {
-+ type_name = "ds1780";
-+ client_name = "DS1780 chip";
-+ } else if (kind == lm81) {
-+ type_name = "lm81";
-+ client_name = "LM81 chip";
-+ } else {
-+#ifdef DEBUG
-+ printk("adm9240.o: Internal error: unknown kind (%d)?!?",
-+ kind);
-+#endif
-+ goto ERROR1;
-+ }
-+
-+ /* Fill in the remaining client fields and put it into the global list */
-+ strcpy(new_client->name, client_name);
-+ data->type = kind;
-+
-+ new_client->id = adm9240_id++;
-+ data->valid = 0;
-+ init_MUTEX(&data->update_lock);
-+
-+ /* Tell the I2C layer a new client has arrived */
-+ if ((err = i2c_attach_client(new_client)))
-+ goto ERROR3;
-+
-+ /* Register a new directory entry with module sensors */
-+ if ((i = i2c_register_entry(new_client,
-+ type_name,
-+ adm9240_dir_table_template)) < 0) {
-+ err = i;
-+ goto ERROR4;
-+ }
-+ data->sysctl_id = i;
-+
-+ /* Initialize the ADM9240 chip */
-+ adm9240_init_client(new_client);
-+ return 0;
-+
-+/* OK, this is not exactly good programming practice, usually. But it is
-+ very code-efficient in this case. */
-+
-+ ERROR4:
-+ i2c_detach_client(new_client);
-+ ERROR3:
-+ ERROR1:
-+ kfree(data);
-+ ERROR0:
-+ return err;
-+}
-+
-+static int adm9240_detach_client(struct i2c_client *client)
-+{
-+ int err;
-+
-+ i2c_deregister_entry(((struct adm9240_data *) (client->data))->
-+ sysctl_id);
-+
-+ if ((err = i2c_detach_client(client))) {
-+ printk
-+ ("adm9240.o: Client deregistration failed, client not detached.\n");
-+ return err;
-+ }
-+
-+ kfree(client->data);
-+
-+ return 0;
-+}
-+
-+
-+static int adm9240_read_value(struct i2c_client *client, u8 reg)
-+{
-+ return i2c_smbus_read_byte_data(client, reg);
-+}
-+
-+static int adm9240_write_value(struct i2c_client *client, u8 reg, u8 value)
-+{
-+ return i2c_smbus_write_byte_data(client, reg, value);
-+}
-+
-+/* Called when we have found a new ADM9240. */
-+static void adm9240_init_client(struct i2c_client *client)
-+{
-+ /* Start monitoring */
-+ adm9240_write_value(client, ADM9240_REG_CONFIG, 0x01);
-+}
-+
-+static void adm9240_update_client(struct i2c_client *client)
-+{
-+ struct adm9240_data *data = client->data;
-+ u8 i;
-+
-+ down(&data->update_lock);
-+
-+ if (
-+ (jiffies - data->last_updated >
-+ (data->type == adm9240 ? HZ / 2 : HZ * 2))
-+ || (jiffies < data->last_updated) || !data->valid) {
-+
-+#ifdef DEBUG
-+ printk("Starting adm9240 update\n");
-+#endif
-+ for (i = 0; i <= 5; i++) {
-+ data->in[i] =
-+ adm9240_read_value(client, ADM9240_REG_IN(i));
-+ data->in_min[i] =
-+ adm9240_read_value(client,
-+ ADM9240_REG_IN_MIN(i));
-+ data->in_max[i] =
-+ adm9240_read_value(client,
-+ ADM9240_REG_IN_MAX(i));
-+ }
-+ data->fan[0] =
-+ adm9240_read_value(client, ADM9240_REG_FAN1);
-+ data->fan_min[0] =
-+ adm9240_read_value(client, ADM9240_REG_FAN1_MIN);
-+ data->fan[1] =
-+ adm9240_read_value(client, ADM9240_REG_FAN2);
-+ data->fan_min[1] =
-+ adm9240_read_value(client, ADM9240_REG_FAN2_MIN);
-+ data->temp =
-+ (adm9240_read_value(client, ADM9240_REG_TEMP) << 1) +
-+ ((adm9240_read_value
-+ (client, ADM9240_REG_TEMP_CONFIG) & 0x80) >> 7);
-+ data->temp_os_max =
-+ adm9240_read_value(client, ADM9240_REG_TOS);
-+ data->temp_os_hyst =
-+ adm9240_read_value(client, ADM9240_REG_THYST);
-+
-+ i = adm9240_read_value(client, ADM9240_REG_VID_FAN_DIV);
-+ data->fan_div[0] = (i >> 4) & 0x03;
-+ data->fan_div[1] = (i >> 6) & 0x03;
-+ data->vid = i & 0x0f;
-+ data->vid |=
-+ (adm9240_read_value(client, ADM9240_REG_VID4) & 0x01)
-+ << 4;
-+
-+ data->alarms =
-+ adm9240_read_value(client,
-+ ADM9240_REG_INT1_STAT) +
-+ (adm9240_read_value(client, ADM9240_REG_INT2_STAT) <<
-+ 8);
-+ data->analog_out =
-+ adm9240_read_value(client, ADM9240_REG_ANALOG_OUT);
-+ data->last_updated = jiffies;
-+ data->valid = 1;
-+ }
-+
-+ up(&data->update_lock);
-+}
-+
-+
-+/* The next few functions are the call-back functions of the /proc/sys and
-+ sysctl files. Which function is used is defined in the ctl_table in
-+ the extra1 field.
-+ Each function must return the magnitude (power of 10 to divide the date
-+ with) if it is called with operation==SENSORS_PROC_REAL_INFO. It must
-+ put a maximum of *nrels elements in results reflecting the data of this
-+ file, and set *nrels to the number it actually put in it, if operation==
-+ SENSORS_PROC_REAL_READ. Finally, it must get upto *nrels elements from
-+ results and write them to the chip, if operations==SENSORS_PROC_REAL_WRITE.
-+ Note that on SENSORS_PROC_REAL_READ, I do not check whether results is
-+ large enough (by checking the incoming value of *nrels). This is not very
-+ good practice, but as long as you put less than about 5 values in results,
-+ you can assume it is large enough. */
-+void adm9240_in(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+
-+ int scales[6] = { 250, 270, 330, 500, 1200, 270 };
-+
-+ struct adm9240_data *data = client->data;
-+ int nr = ctl_name - ADM9240_SYSCTL_IN0;
-+
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 2;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ adm9240_update_client(client);
-+ results[0] =
-+ IN_FROM_REG(data->in_min[nr], nr) * scales[nr] / 192;
-+ results[1] =
-+ IN_FROM_REG(data->in_max[nr], nr) * scales[nr] / 192;
-+ results[2] =
-+ IN_FROM_REG(data->in[nr], nr) * scales[nr] / 192;
-+ *nrels_mag = 3;
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ if (*nrels_mag >= 1) {
-+ data->in_min[nr] =
-+ IN_TO_REG((results[0] * 192) / scales[nr], nr);
-+ adm9240_write_value(client, ADM9240_REG_IN_MIN(nr),
-+ data->in_min[nr]);
-+ }
-+ if (*nrels_mag >= 2) {
-+ data->in_max[nr] =
-+ IN_TO_REG((results[1] * 192) / scales[nr], nr);
-+ adm9240_write_value(client, ADM9240_REG_IN_MAX(nr),
-+ data->in_max[nr]);
-+ }
-+ }
-+}
-+
-+void adm9240_fan(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct adm9240_data *data = client->data;
-+ int nr = ctl_name - ADM9240_SYSCTL_FAN1 + 1;
-+
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 0;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ adm9240_update_client(client);
-+ results[0] = FAN_FROM_REG(data->fan_min[nr - 1],
-+ DIV_FROM_REG(data->
-+ fan_div[nr - 1]));
-+ results[1] =
-+ FAN_FROM_REG(data->fan[nr - 1],
-+ DIV_FROM_REG(data->fan_div[nr - 1]));
-+ *nrels_mag = 2;
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ if (*nrels_mag >= 1) {
-+ data->fan_min[nr - 1] = FAN_TO_REG(results[0],
-+ DIV_FROM_REG
-+ (data->
-+ fan_div[nr -
-+ 1]));
-+ adm9240_write_value(client,
-+ nr ==
-+ 1 ? ADM9240_REG_FAN1_MIN :
-+ ADM9240_REG_FAN2_MIN,
-+ data->fan_min[nr - 1]);
-+ }
-+ }
-+}
-+
-+
-+void adm9240_temp(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct adm9240_data *data = client->data;
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 1;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ adm9240_update_client(client);
-+ results[0] = TEMP_LIMIT_FROM_REG(data->temp_os_max);
-+ results[1] = TEMP_LIMIT_FROM_REG(data->temp_os_hyst);
-+ results[2] = TEMP_FROM_REG(data->temp);
-+ *nrels_mag = 3;
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ if (*nrels_mag >= 1) {
-+ data->temp_os_max = TEMP_LIMIT_TO_REG(results[0]);
-+ adm9240_write_value(client, ADM9240_REG_TOS,
-+ data->temp_os_max);
-+ }
-+ if (*nrels_mag >= 2) {
-+ data->temp_os_hyst = TEMP_LIMIT_TO_REG(results[1]);
-+ adm9240_write_value(client, ADM9240_REG_THYST,
-+ data->temp_os_hyst);
-+ }
-+ }
-+}
-+
-+void adm9240_alarms(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct adm9240_data *data = client->data;
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 0;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ adm9240_update_client(client);
-+ results[0] = ALARMS_FROM_REG(data->alarms);
-+ *nrels_mag = 1;
-+ }
-+}
-+
-+void adm9240_fan_div(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results)
-+{
-+ struct adm9240_data *data = client->data;
-+ int old;
-+
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 0;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ adm9240_update_client(client);
-+ results[0] = DIV_FROM_REG(data->fan_div[0]);
-+ results[1] = DIV_FROM_REG(data->fan_div[1]);
-+ *nrels_mag = 2;
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ old = adm9240_read_value(client, ADM9240_REG_VID_FAN_DIV);
-+ if (*nrels_mag >= 2) {
-+ data->fan_div[1] = DIV_TO_REG(results[1]);
-+ old = (old & 0x3f) | (data->fan_div[1] << 6);
-+ }
-+ if (*nrels_mag >= 1) {
-+ data->fan_div[0] = DIV_TO_REG(results[0]);
-+ old = (old & 0xcf) | (data->fan_div[0] << 4);
-+ adm9240_write_value(client,
-+ ADM9240_REG_VID_FAN_DIV, old);
-+ }
-+ }
-+}
-+
-+void adm9240_analog_out(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results)
-+{
-+ struct adm9240_data *data = client->data;
-+
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 0;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ adm9240_update_client(client);
-+ results[0] = data->analog_out;
-+ *nrels_mag = 1;
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ if (*nrels_mag >= 1) {
-+ data->analog_out = results[0];
-+ adm9240_write_value(client, ADM9240_REG_ANALOG_OUT,
-+ data->analog_out);
-+ }
-+ }
-+}
-+
-+void adm9240_vid(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct adm9240_data *data = client->data;
-+
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 2;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ adm9240_update_client(client);
-+ results[0] = VID_FROM_REG(data->vid);
-+ *nrels_mag = 1;
-+ }
-+}
-+
-+static int __init sm_adm9240_init(void)
-+{
-+ printk("adm9240.o version %s (%s)\n", LM_VERSION, LM_DATE);
-+ return i2c_add_driver(&adm9240_driver);
-+}
-+
-+static void __exit sm_adm9240_exit(void)
-+{
-+ i2c_del_driver(&adm9240_driver);
-+}
-+
-+
-+
-+MODULE_AUTHOR
-+ ("Frodo Looijaard <frodol@dds.nl> and Philip Edelbrock <phil@netroedge.com>");
-+MODULE_LICENSE("GPL");
-+MODULE_DESCRIPTION("ADM9240 driver");
-+
-+module_init(sm_adm9240_init);
-+module_exit(sm_adm9240_exit);
---- linux-old/drivers/sensors/asb100.c Thu Jan 1 00:00:00 1970
-+++ linux/drivers/sensors/asb100.c Mon Dec 13 20:18:45 2004
-@@ -0,0 +1,1025 @@
-+/*
-+ asb100.c - Part of lm_sensors, Linux kernel modules for hardware
-+ monitoring
-+
-+ Copyright (c) 2003 Mark M. Hoffman <mhoffman@lightlink.com>
-+
-+ (derived from w83781d.c)
-+
-+ Copyright (c) 1998 - 2003 Frodo Looijaard <frodol@dds.nl>,
-+ Philip Edelbrock <phil@netroedge.com>, and
-+ Mark Studebaker <mdsxyz123@yahoo.com>
-+
-+ 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., 675 Mass Ave, Cambridge, MA 02139, USA.
-+*/
-+
-+/*
-+ This driver supports the hardware sensor chips: Asus ASB100 and
-+ ASB100-A "BACH".
-+
-+ ASB100-A supports pwm1, while plain ASB100 does not. There is no known
-+ way for the driver to tell which one is there.
-+
-+ Chip #vin #fanin #pwm #temp wchipid vendid i2c ISA
-+ asb100 7 3 1 4 0x31 0x0694 yes no
-+*/
-+
-+//#define DEBUG 1
-+
-+#include <linux/module.h>
-+#include <linux/slab.h>
-+#include <linux/i2c.h>
-+#include <linux/i2c-proc.h>
-+#include <linux/init.h>
-+#define LM_DATE "20041007"
-+#define LM_VERSION "2.8.8"
-+#include <linux/sensors_vid.h>
-+#include "lm75.h"
-+
-+#ifndef I2C_DRIVERID_ASB100
-+#define I2C_DRIVERID_ASB100 1043
-+#endif
-+
-+/* I2C addresses to scan */
-+static unsigned short normal_i2c[] = { SENSORS_I2C_END };
-+static unsigned short normal_i2c_range[] = { 0x28, 0x2f, SENSORS_I2C_END };
-+
-+/* ISA addresses to scan (none) */
-+static unsigned int normal_isa[] = { SENSORS_ISA_END };
-+static unsigned int normal_isa_range[] = { SENSORS_ISA_END };
-+
-+/* default VRM to 9.0 instead of 8.2 */
-+#define ASB100_DEFAULT_VRM 90
-+
-+/* Insmod parameters */
-+SENSORS_INSMOD_1(asb100);
-+SENSORS_MODULE_PARM(force_subclients, "List of subclient addresses: " \
-+ "{bus, clientaddr, subclientaddr1, subclientaddr2}");
-+
-+/* Voltage IN registers 0-6 */
-+#define ASB100_REG_IN(nr) (0x20 + (nr))
-+#define ASB100_REG_IN_MAX(nr) (0x2b + (nr * 2))
-+#define ASB100_REG_IN_MIN(nr) (0x2c + (nr * 2))
-+
-+/* FAN IN registers 1-3 */
-+#define ASB100_REG_FAN(nr) (0x27 + (nr))
-+#define ASB100_REG_FAN_MIN(nr) (0x3a + (nr))
-+
-+/* TEMPERATURE registers 1-4 */
-+static const u16 asb100_reg_temp[] = {0, 0x27, 0x150, 0x250, 0x17};
-+static const u16 asb100_reg_temp_max[] = {0, 0x39, 0x155, 0x255, 0x18};
-+static const u16 asb100_reg_temp_hyst[] = {0, 0x3a, 0x153, 0x253, 0x19};
-+
-+#define ASB100_REG_TEMP(nr) (asb100_reg_temp[nr])
-+#define ASB100_REG_TEMP_MAX(nr) (asb100_reg_temp_max[nr])
-+#define ASB100_REG_TEMP_HYST(nr) (asb100_reg_temp_hyst[nr])
-+
-+#define ASB100_REG_TEMP2_CONFIG 0x0152
-+#define ASB100_REG_TEMP3_CONFIG 0x0252
-+
-+
-+#define ASB100_REG_CONFIG 0x40
-+#define ASB100_REG_ALARM1 0x41
-+#define ASB100_REG_ALARM2 0x42
-+#define ASB100_REG_SMIM1 0x43
-+#define ASB100_REG_SMIM2 0x44
-+#define ASB100_REG_VID_FANDIV 0x47
-+#define ASB100_REG_I2C_ADDR 0x48
-+#define ASB100_REG_CHIPID 0x49
-+#define ASB100_REG_I2C_SUBADDR 0x4a
-+#define ASB100_REG_PIN 0x4b
-+#define ASB100_REG_IRQ 0x4c
-+#define ASB100_REG_BANK 0x4e
-+#define ASB100_REG_CHIPMAN 0x4f
-+
-+#define ASB100_REG_WCHIPID 0x58
-+
-+/* bit 7 -> enable, bits 0-3 -> duty cycle */
-+#define ASB100_REG_PWM1 0x59
-+
-+/* CONVERSIONS
-+ Rounding and limit checking is only done on the TO_REG variants. */
-+
-+/* These constants are a guess, consistent w/ w83781d */
-+#define ASB100_IN_MIN ( 0)
-+#define ASB100_IN_MAX (408)
-+
-+/* IN: 1/100 V (0V to 4.08V)
-+ REG: 16mV/bit */
-+static u8 IN_TO_REG(unsigned val)
-+{
-+ unsigned nval = SENSORS_LIMIT(val, ASB100_IN_MIN, ASB100_IN_MAX);
-+ return (nval * 10 + 8) / 16;
-+}
-+
-+static unsigned IN_FROM_REG(u8 reg)
-+{
-+ return (reg * 16 + 5) / 10;
-+}
-+
-+static u8 FAN_TO_REG(long rpm, int div)
-+{
-+ if (rpm == 0)
-+ return 255;
-+ rpm = SENSORS_LIMIT(rpm, 1, 1000000);
-+ return SENSORS_LIMIT((1350000 + rpm * div / 2) / (rpm * div), 1, 254);
-+}
-+
-+static int FAN_FROM_REG(u8 val, int div)
-+{
-+ return val==0 ? -1 : val==255 ? 0 : 1350000/(val*div);
-+}
-+
-+/* These constants are a guess, consistent w/ w83781d */
-+#define ASB100_TEMP_MIN (-1280)
-+#define ASB100_TEMP_MAX ( 1270)
-+
-+/* TEMP: 1/10 degrees C (-128C to +127C)
-+ REG: 1C/bit, two's complement */
-+static u8 TEMP_TO_REG(int temp)
-+{
-+ int ntemp = SENSORS_LIMIT(temp, ASB100_TEMP_MIN, ASB100_TEMP_MAX);
-+ ntemp += (ntemp<0 ? -5 : 5);
-+ return (u8)(ntemp / 10);
-+}
-+
-+static int TEMP_FROM_REG(u8 reg)
-+{
-+ return (s8)reg * 10;
-+}
-+
-+/* PWM: 0 - 255 per sensors documentation
-+ REG: (6.25% duty cycle per bit) */
-+static u8 ASB100_PWM_TO_REG(int pwm)
-+{
-+ pwm = SENSORS_LIMIT(pwm, 0, 255);
-+ return (u8)(pwm / 16);
-+}
-+
-+static int ASB100_PWM_FROM_REG(u8 reg)
-+{
-+ return reg * 16;
-+}
-+
-+#define ALARMS_FROM_REG(val) (val)
-+
-+#define DIV_FROM_REG(val) (1 << (val))
-+
-+/* FAN DIV: 1, 2, 4, or 8 (defaults to 2)
-+ REG: 0, 1, 2, or 3 (respectively) (defaults to 1) */
-+static u8 DIV_TO_REG(long val)
-+{
-+ return val==8 ? 3 : val==4 ? 2 : val==1 ? 0 : 1;
-+}
-+
-+/* For each registered client, we need to keep some data in memory. That
-+ data is pointed to by client->data. The structure itself is
-+ dynamically allocated, at the same time the client itself is allocated. */
-+struct asb100_data {
-+ struct i2c_client client;
-+ struct semaphore lock;
-+ int sysctl_id;
-+ enum chips type;
-+
-+ struct semaphore update_lock;
-+ unsigned long last_updated; /* In jiffies */
-+
-+ /* array of 2 pointers to subclients */
-+ struct i2c_client *lm75[2];
-+
-+ char valid; /* !=0 if following fields are valid */
-+ u8 in[7]; /* Register value */
-+ u8 in_max[7]; /* Register value */
-+ u8 in_min[7]; /* Register value */
-+ u8 fan[3]; /* Register value */
-+ u8 fan_min[3]; /* Register value */
-+ u16 temp[4]; /* Register value (0 and 3 are u8 only) */
-+ u16 temp_max[4]; /* Register value (0 and 3 are u8 only) */
-+ u16 temp_hyst[4]; /* Register value (0 and 3 are u8 only) */
-+ u8 fan_div[3]; /* Register encoding, right justified */
-+ u8 pwm; /* Register encoding */
-+ u8 vid; /* Register encoding, combined */
-+ u32 alarms; /* Register encoding, combined */
-+ u8 vrm;
-+};
-+
-+static int asb100_attach_adapter(struct i2c_adapter *adapter);
-+static int asb100_detect(struct i2c_adapter *adapter, int address,
-+ unsigned short flags, int kind);
-+static int asb100_detach_client(struct i2c_client *client);
-+
-+static int asb100_read_value(struct i2c_client *client, u16 reg);
-+static void asb100_write_value(struct i2c_client *client, u16 reg, u16 val);
-+static void asb100_update_client(struct i2c_client *client);
-+static void asb100_init_client(struct i2c_client *client);
-+
-+static void asb100_in(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void asb100_fan(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void asb100_temp(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void asb100_temp_add(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void asb100_vid(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void asb100_vrm(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void asb100_alarms(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void asb100_fan_div(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void asb100_pwm(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+
-+static struct i2c_driver asb100_driver = {
-+ .owner = THIS_MODULE,
-+ .name = "asb100",
-+ .id = I2C_DRIVERID_ASB100,
-+ .flags = I2C_DF_NOTIFY,
-+ .attach_adapter = asb100_attach_adapter,
-+ .detach_client = asb100_detach_client,
-+};
-+
-+/* The /proc/sys entries */
-+/* -- SENSORS SYSCTL START -- */
-+
-+#define ASB100_SYSCTL_IN0 1000 /* Volts * 100 */
-+#define ASB100_SYSCTL_IN1 1001
-+#define ASB100_SYSCTL_IN2 1002
-+#define ASB100_SYSCTL_IN3 1003
-+#define ASB100_SYSCTL_IN4 1004
-+#define ASB100_SYSCTL_IN5 1005
-+#define ASB100_SYSCTL_IN6 1006
-+
-+#define ASB100_SYSCTL_FAN1 1101 /* Rotations/min */
-+#define ASB100_SYSCTL_FAN2 1102
-+#define ASB100_SYSCTL_FAN3 1103
-+
-+#define ASB100_SYSCTL_TEMP1 1200 /* Degrees Celcius * 10 */
-+#define ASB100_SYSCTL_TEMP2 1201
-+#define ASB100_SYSCTL_TEMP3 1202
-+#define ASB100_SYSCTL_TEMP4 1203
-+
-+#define ASB100_SYSCTL_VID 1300 /* Volts * 1000 */
-+#define ASB100_SYSCTL_VRM 1301
-+
-+#define ASB100_SYSCTL_PWM1 1401 /* 0-255 => 0-100% duty cycle */
-+
-+#define ASB100_SYSCTL_FAN_DIV 2000 /* 1, 2, 4 or 8 */
-+#define ASB100_SYSCTL_ALARMS 2001 /* bitvector */
-+
-+#define ASB100_ALARM_IN0 0x0001 /* ? */
-+#define ASB100_ALARM_IN1 0x0002 /* ? */
-+#define ASB100_ALARM_IN2 0x0004
-+#define ASB100_ALARM_IN3 0x0008
-+#define ASB100_ALARM_TEMP1 0x0010
-+#define ASB100_ALARM_TEMP2 0x0020
-+#define ASB100_ALARM_FAN1 0x0040
-+#define ASB100_ALARM_FAN2 0x0080
-+#define ASB100_ALARM_IN4 0x0100
-+#define ASB100_ALARM_IN5 0x0200 /* ? */
-+#define ASB100_ALARM_IN6 0x0400 /* ? */
-+#define ASB100_ALARM_FAN3 0x0800
-+#define ASB100_ALARM_CHAS 0x1000
-+#define ASB100_ALARM_TEMP3 0x2000
-+
-+#define ASB100_ALARM_IN7 0x10000 /* ? */
-+#define ASB100_ALARM_IN8 0x20000 /* ? */
-+
-+/* -- SENSORS SYSCTL END -- */
-+
-+/* These files are created for each detected chip. This is just a template;
-+ though at first sight, you might think we could use a statically
-+ allocated list, we need some way to get back to the parent - which
-+ is done through one of the 'extra' fields which are initialized
-+ when a new copy is allocated. */
-+
-+/* no datasheet - but we did get some hints from someone who
-+ claimed to have the datasheet */
-+#define ASB100_SYSCTL_IN(nr) {ASB100_SYSCTL_IN##nr, "in" #nr, NULL, 0, \
-+ 0644, NULL, &i2c_proc_real, &i2c_sysctl_real, NULL, &asb100_in}
-+#define ASB100_SYSCTL_FAN(nr) {ASB100_SYSCTL_FAN##nr, "fan" #nr, NULL, 0, \
-+ 0644, NULL, &i2c_proc_real, &i2c_sysctl_real, NULL, &asb100_fan}
-+#define ASB100_SYSCTL_TEMP(nr, func) {ASB100_SYSCTL_TEMP##nr, "temp" #nr, \
-+ NULL, 0, 0644, NULL, &i2c_proc_real, &i2c_sysctl_real, NULL, func}
-+static ctl_table asb100_dir_table_template[] = {
-+ ASB100_SYSCTL_IN(0),
-+ ASB100_SYSCTL_IN(1),
-+ ASB100_SYSCTL_IN(2),
-+ ASB100_SYSCTL_IN(3),
-+ ASB100_SYSCTL_IN(4),
-+ ASB100_SYSCTL_IN(5),
-+ ASB100_SYSCTL_IN(6),
-+
-+ ASB100_SYSCTL_FAN(1),
-+ ASB100_SYSCTL_FAN(2),
-+ ASB100_SYSCTL_FAN(3),
-+
-+ ASB100_SYSCTL_TEMP(1, &asb100_temp),
-+ ASB100_SYSCTL_TEMP(2, &asb100_temp_add),
-+ ASB100_SYSCTL_TEMP(3, &asb100_temp_add),
-+ ASB100_SYSCTL_TEMP(4, &asb100_temp),
-+
-+ {ASB100_SYSCTL_VID, "vid", NULL, 0, 0444, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &asb100_vid},
-+ {ASB100_SYSCTL_VRM, "vrm", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &asb100_vrm},
-+ {ASB100_SYSCTL_FAN_DIV, "fan_div", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &asb100_fan_div},
-+ {ASB100_SYSCTL_ALARMS, "alarms", NULL, 0, 0444, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &asb100_alarms},
-+ {ASB100_SYSCTL_PWM1, "pwm1", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &asb100_pwm},
-+ {0}
-+};
-+
-+/* This function is called when:
-+ asb100_driver is inserted (when this module is loaded), for each
-+ available adapter
-+ when a new adapter is inserted (and asb100_driver is still present)
-+ */
-+static int asb100_attach_adapter(struct i2c_adapter *adapter)
-+{
-+ return i2c_detect(adapter, &addr_data, asb100_detect);
-+}
-+
-+static int asb100_detect_subclients(struct i2c_adapter *adapter, int address,
-+ int kind, struct i2c_client *new_client)
-+{
-+ int i, id, err;
-+ struct asb100_data *data = new_client->data;
-+
-+ data->lm75[0] = kmalloc(sizeof(struct i2c_client), GFP_KERNEL);
-+ if (!(data->lm75[0])) {
-+ err = -ENOMEM;
-+ goto ERROR_SC_0;
-+ }
-+ memset(data->lm75[0], 0x00, sizeof(struct i2c_client));
-+
-+ data->lm75[1] = kmalloc(sizeof(struct i2c_client), GFP_KERNEL);
-+ if (!(data->lm75[1])) {
-+ err = -ENOMEM;
-+ goto ERROR_SC_1;
-+ }
-+ memset(data->lm75[1], 0x00, sizeof(struct i2c_client));
-+
-+ id = i2c_adapter_id(adapter);
-+
-+ if (force_subclients[0] == id && force_subclients[1] == address) {
-+ for (i = 2; i <= 3; i++) {
-+ if (force_subclients[i] < 0x48 ||
-+ force_subclients[i] > 0x4f) {
-+ printk(KERN_ERR "asb100.o: invalid subclient "
-+ "address %d; must be 0x48-0x4f\n",
-+ force_subclients[i]);
-+ err = -ENODEV;
-+ goto ERROR_SC_2;
-+ }
-+ }
-+ asb100_write_value(new_client, ASB100_REG_I2C_SUBADDR,
-+ (force_subclients[2] & 0x07) |
-+ ((force_subclients[3] & 0x07) <<4));
-+ data->lm75[0]->addr = force_subclients[2];
-+ data->lm75[1]->addr = force_subclients[3];
-+ } else {
-+ int val = asb100_read_value(new_client, ASB100_REG_I2C_SUBADDR);
-+ data->lm75[0]->addr = 0x48 + (val & 0x07);
-+ data->lm75[1]->addr = 0x48 + ((val >> 4) & 0x07);
-+ }
-+
-+ if(data->lm75[0]->addr == data->lm75[1]->addr) {
-+ printk(KERN_ERR "asb100.o: duplicate addresses 0x%x "
-+ "for subclients\n", data->lm75[0]->addr);
-+ err = -ENODEV;
-+ goto ERROR_SC_2;
-+ }
-+
-+ for (i = 0; i <= 1; i++) {
-+ data->lm75[i]->data = NULL;
-+ data->lm75[i]->adapter = adapter;
-+ data->lm75[i]->driver = &asb100_driver;
-+ data->lm75[i]->flags = 0;
-+ strcpy(data->lm75[i]->name, "asb100 subclient");
-+ }
-+
-+ if ((err = i2c_attach_client(data->lm75[0]))) {
-+ printk(KERN_ERR "asb100.o: Subclient %d registration "
-+ "at address 0x%x failed.\n", i, data->lm75[0]->addr);
-+ goto ERROR_SC_2;
-+ }
-+
-+ if ((err = i2c_attach_client(data->lm75[1]))) {
-+ printk(KERN_ERR "asb100.o: Subclient %d registration "
-+ "at address 0x%x failed.\n", i, data->lm75[1]->addr);
-+ goto ERROR_SC_3;
-+ }
-+
-+ return 0;
-+
-+/* Undo inits in case of errors */
-+ERROR_SC_3:
-+ i2c_detach_client(data->lm75[0]);
-+ERROR_SC_2:
-+ kfree(data->lm75[1]);
-+ERROR_SC_1:
-+ kfree(data->lm75[0]);
-+ERROR_SC_0:
-+ return err;
-+}
-+
-+static int asb100_detect(struct i2c_adapter *adapter, int address,
-+ unsigned short flags, int kind)
-+{
-+ int err;
-+ struct i2c_client *new_client;
-+ struct asb100_data *data;
-+
-+ /* asb100 is SMBus only */
-+ if (i2c_is_isa_adapter(adapter)) {
-+ pr_debug("asb100.o: detect failed, "
-+ "cannot attach to legacy adapter!\n");
-+ err = -ENODEV;
-+ goto ERROR0;
-+ }
-+
-+ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
-+ pr_debug("asb100.o: detect failed, "
-+ "smbus byte data not supported!\n");
-+ err = -ENODEV;
-+ goto ERROR0;
-+ }
-+
-+ /* OK. For now, we presume we have a valid client. We now create the
-+ client structure, even though we cannot fill it completely yet.
-+ But it allows us to access asb100_{read,write}_value. */
-+
-+ if (!(data = kmalloc(sizeof(struct asb100_data), GFP_KERNEL))) {
-+ pr_debug("asb100.o: detect failed, kmalloc failed!\n");
-+ err = -ENOMEM;
-+ goto ERROR0;
-+ }
-+
-+ new_client = &data->client;
-+ new_client->addr = address;
-+ init_MUTEX(&data->lock);
-+ new_client->data = data;
-+ new_client->adapter = adapter;
-+ new_client->driver = &asb100_driver;
-+ new_client->flags = 0;
-+
-+ /* Now, we do the remaining detection. */
-+
-+ /* The chip may be stuck in some other bank than bank 0. This may
-+ make reading other information impossible. Specify a force=... or
-+ force_*=... parameter, and the chip will be reset to the right
-+ bank. */
-+ if (kind < 0) {
-+
-+ int val1 = asb100_read_value(new_client, ASB100_REG_BANK);
-+ int val2 = asb100_read_value(new_client, ASB100_REG_CHIPMAN);
-+
-+ /* If we're in bank 0 */
-+ if ( (!(val1 & 0x07)) &&
-+ /* Check for ASB100 ID (low byte) */
-+ ( ((!(val1 & 0x80)) && (val2 != 0x94)) ||
-+ /* Check for ASB100 ID (high byte ) */
-+ ((val1 & 0x80) && (val2 != 0x06)) ) ) {
-+ pr_debug("asb100.o: detect failed, "
-+ "bad chip id 0x%02x!\n", val2);
-+ err = -ENODEV;
-+ goto ERROR1;
-+ }
-+
-+ } /* kind < 0 */
-+
-+ /* We have either had a force parameter, or we have already detected
-+ Winbond. Put it now into bank 0 and Vendor ID High Byte */
-+ asb100_write_value(new_client, ASB100_REG_BANK,
-+ (asb100_read_value(new_client, ASB100_REG_BANK) & 0x78) | 0x80);
-+
-+ /* Determine the chip type. */
-+ if (kind <= 0) {
-+ int val1 = asb100_read_value(new_client, ASB100_REG_WCHIPID);
-+ int val2 = asb100_read_value(new_client, ASB100_REG_CHIPMAN);
-+
-+ if ((val1 == 0x31) && (val2 == 0x06))
-+ kind = asb100;
-+ else {
-+ if (kind == 0)
-+ printk (KERN_WARNING "asb100.o: Ignoring "
-+ "'force' parameter for unknown chip "
-+ "at adapter %d, address 0x%02x.\n",
-+ i2c_adapter_id(adapter), address);
-+ err = -ENODEV;
-+ goto ERROR1;
-+ }
-+ }
-+
-+ /* Fill in remaining client fields and put it into the global list */
-+ strcpy(new_client->name, "ASB100 chip");
-+ data->type = kind;
-+
-+ data->valid = 0;
-+ init_MUTEX(&data->update_lock);
-+
-+ /* Tell the I2C layer a new client has arrived */
-+ if ((err = i2c_attach_client(new_client)))
-+ goto ERROR1;
-+
-+ /* Attach secondary lm75 clients */
-+ if ((err = asb100_detect_subclients(adapter, address, kind,
-+ new_client)))
-+ goto ERROR2;
-+
-+ /* Initialize the chip */
-+ asb100_init_client(new_client);
-+
-+ /* Register a new directory entry with module sensors */
-+ if ((data->sysctl_id = i2c_register_entry(new_client, "asb100",
-+ asb100_dir_table_template)) < 0) {
-+ err = data->sysctl_id;
-+ goto ERROR3;
-+ }
-+
-+ return 0;
-+
-+ERROR3:
-+ i2c_detach_client(data->lm75[0]);
-+ kfree(data->lm75[1]);
-+ kfree(data->lm75[0]);
-+ERROR2:
-+ i2c_detach_client(new_client);
-+ERROR1:
-+ kfree(data);
-+ERROR0:
-+ return err;
-+}
-+
-+static int asb100_detach_client(struct i2c_client *client)
-+{
-+ int err;
-+ struct asb100_data *data = client->data;
-+
-+ /* remove sysctl table (primary client only) */
-+ if ((data))
-+ i2c_deregister_entry(data->sysctl_id);
-+
-+ if ((err = i2c_detach_client(client))) {
-+ printk (KERN_ERR "asb100.o: Client deregistration failed; "
-+ "client not detached.\n");
-+ return err;
-+ }
-+
-+ if (data) {
-+ /* primary client */
-+ kfree(data);
-+ } else {
-+ /* subclients */
-+ kfree(client);
-+ }
-+
-+ return 0;
-+}
-+
-+/* The SMBus locks itself, usually, but nothing may access the Winbond between
-+ bank switches. ISA access must always be locked explicitly!
-+ We ignore the W83781D BUSY flag at this moment - it could lead to deadlocks,
-+ would slow down the W83781D access and should not be necessary.
-+ There are some ugly typecasts here, but the good news is - they should
-+ nowhere else be necessary! */
-+static int asb100_read_value(struct i2c_client *client, u16 reg)
-+{
-+ struct asb100_data *data = client->data;
-+ struct i2c_client *cl;
-+ int res, bank;
-+
-+ down(&data->lock);
-+
-+ bank = (reg >> 8) & 0x0f;
-+ if (bank > 2)
-+ /* switch banks */
-+ i2c_smbus_write_byte_data(client, ASB100_REG_BANK, bank);
-+
-+ if (bank == 0 || bank > 2) {
-+ res = i2c_smbus_read_byte_data(client, reg & 0xff);
-+ } else {
-+ /* switch to subclient */
-+ cl = data->lm75[bank - 1];
-+
-+ /* convert from ISA to LM75 I2C addresses */
-+ switch (reg & 0xff) {
-+ case 0x50: /* TEMP */
-+ res = swab16(i2c_smbus_read_word_data (cl, 0));
-+ break;
-+ case 0x52: /* CONFIG */
-+ res = i2c_smbus_read_byte_data(cl, 1);
-+ break;
-+ case 0x53: /* HYST */
-+ res = swab16(i2c_smbus_read_word_data (cl, 2));
-+ break;
-+ case 0x55: /* MAX */
-+ default:
-+ res = swab16(i2c_smbus_read_word_data (cl, 3));
-+ break;
-+ }
-+ }
-+
-+ if (bank > 2)
-+ i2c_smbus_write_byte_data(client, ASB100_REG_BANK, 0);
-+
-+ up(&data->lock);
-+
-+ return res;
-+}
-+
-+static void asb100_write_value(struct i2c_client *client, u16 reg, u16 value)
-+{
-+ struct asb100_data *data = client->data;
-+ struct i2c_client *cl;
-+ int bank;
-+
-+ down(&data->lock);
-+
-+ bank = (reg >> 8) & 0x0f;
-+ if (bank > 2)
-+ /* switch banks */
-+ i2c_smbus_write_byte_data(client, ASB100_REG_BANK, bank);
-+
-+ if (bank == 0 || bank > 2) {
-+ i2c_smbus_write_byte_data(client, reg & 0xff, value & 0xff);
-+ } else {
-+ /* switch to subclient */
-+ cl = data->lm75[bank - 1];
-+
-+ /* convert from ISA to LM75 I2C addresses */
-+ switch (reg & 0xff) {
-+ case 0x52: /* CONFIG */
-+ i2c_smbus_write_byte_data(cl, 1, value & 0xff);
-+ break;
-+ case 0x53: /* HYST */
-+ i2c_smbus_write_word_data(cl, 2, swab16(value));
-+ break;
-+ case 0x55: /* MAX */
-+ i2c_smbus_write_word_data(cl, 3, swab16(value));
-+ break;
-+ }
-+ }
-+
-+ if (bank > 2)
-+ i2c_smbus_write_byte_data(client, ASB100_REG_BANK, 0);
-+
-+ up(&data->lock);
-+}
-+
-+static void asb100_init_client(struct i2c_client *client)
-+{
-+ struct asb100_data *data = client->data;
-+ int vid = 0;
-+
-+ vid = asb100_read_value(client, ASB100_REG_VID_FANDIV) & 0x0f;
-+ vid |= (asb100_read_value(client, ASB100_REG_CHIPID) & 0x01) << 4;
-+ data->vrm = ASB100_DEFAULT_VRM;
-+ vid = vid_from_reg(vid, data->vrm);
-+
-+ /* Start monitoring */
-+ asb100_write_value(client, ASB100_REG_CONFIG,
-+ (asb100_read_value(client, ASB100_REG_CONFIG) & 0xf7) | 0x01);
-+}
-+
-+static void asb100_update_client(struct i2c_client *client)
-+{
-+ struct asb100_data *data = client->data;
-+ int i;
-+
-+ down(&data->update_lock);
-+
-+ if (time_after(jiffies - data->last_updated, HZ + HZ / 2) ||
-+ time_before(jiffies, data->last_updated) || !data->valid) {
-+
-+ pr_debug("asb100.o: starting device update...\n");
-+
-+ /* 7 voltage inputs */
-+ for (i = 0; i < 7; i++) {
-+ data->in[i] = asb100_read_value(client,
-+ ASB100_REG_IN(i));
-+ data->in_min[i] = asb100_read_value(client,
-+ ASB100_REG_IN_MIN(i));
-+ data->in_max[i] = asb100_read_value(client,
-+ ASB100_REG_IN_MAX(i));
-+ }
-+
-+ /* 3 fan inputs */
-+ for (i = 1; i <= 3; i++) {
-+ data->fan[i-1] = asb100_read_value(client,
-+ ASB100_REG_FAN(i));
-+ data->fan_min[i-1] = asb100_read_value(client,
-+ ASB100_REG_FAN_MIN(i));
-+ }
-+
-+ /* 4 temperature inputs */
-+ for (i = 1; i <= 4; i++) {
-+ data->temp[i-1] = asb100_read_value(client,
-+ ASB100_REG_TEMP(i));
-+ data->temp_max[i-1] = asb100_read_value(client,
-+ ASB100_REG_TEMP_MAX(i));
-+ data->temp_hyst[i-1] = asb100_read_value(client,
-+ ASB100_REG_TEMP_HYST(i));
-+ }
-+
-+ /* VID and fan divisors */
-+ i = asb100_read_value(client, ASB100_REG_VID_FANDIV);
-+ data->vid = i & 0x0f;
-+ data->vid |= (asb100_read_value(client,
-+ ASB100_REG_CHIPID) & 0x01) << 4;
-+ data->fan_div[0] = (i >> 4) & 0x03;
-+ data->fan_div[1] = (i >> 6) & 0x03;
-+ data->fan_div[2] = (asb100_read_value(client,
-+ ASB100_REG_PIN) >> 6) & 0x03;
-+
-+ /* PWM */
-+ data->pwm = asb100_read_value(client, ASB100_REG_PWM1);
-+
-+ /* alarms */
-+ data->alarms = asb100_read_value(client, ASB100_REG_ALARM1) +
-+ (asb100_read_value(client, ASB100_REG_ALARM2) << 8);
-+
-+ data->last_updated = jiffies;
-+ data->valid = 1;
-+
-+ pr_debug("asb100.o: ... update complete.\n");
-+ }
-+
-+ up(&data->update_lock);
-+}
-+
-+
-+/* The next few functions are the call-back functions of the /proc/sys and
-+ sysctl files. Which function is used is defined in the ctl_table in
-+ the extra1 field.
-+ Each function must return the magnitude (power of 10 to divide the date
-+ with) if it is called with operation==SENSORS_PROC_REAL_INFO. It must
-+ put a maximum of *nrels elements in results reflecting the data of this
-+ file, and set *nrels to the number it actually put in it, if operation==
-+ SENSORS_PROC_REAL_READ. Finally, it must get upto *nrels elements from
-+ results and write them to the chip, if operations==SENSORS_PROC_REAL_WRITE.
-+ Note that on SENSORS_PROC_REAL_READ, I do not check whether results is
-+ large enough (by checking the incoming value of *nrels). This is not very
-+ good practice, but as long as you put less than about 5 values in results,
-+ you can assume it is large enough. */
-+static void asb100_in(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct asb100_data *data = client->data;
-+ int nr = ctl_name - ASB100_SYSCTL_IN0;
-+
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 2;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ asb100_update_client(client);
-+ results[0] = IN_FROM_REG(data->in_min[nr]);
-+ results[1] = IN_FROM_REG(data->in_max[nr]);
-+ results[2] = IN_FROM_REG(data->in[nr]);
-+ *nrels_mag = 3;
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ if (*nrels_mag >= 1) {
-+ data->in_min[nr] = IN_TO_REG(results[0]);
-+ asb100_write_value(client, ASB100_REG_IN_MIN(nr),
-+ data->in_min[nr]);
-+ }
-+ if (*nrels_mag >= 2) {
-+ data->in_max[nr] = IN_TO_REG(results[1]);
-+ asb100_write_value(client, ASB100_REG_IN_MAX(nr),
-+ data->in_max[nr]);
-+ }
-+ }
-+}
-+
-+void asb100_fan(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct asb100_data *data = client->data;
-+ int nr = ctl_name - ASB100_SYSCTL_FAN1 + 1;
-+
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 0;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ asb100_update_client(client);
-+ results[0] = FAN_FROM_REG(data->fan_min[nr - 1],
-+ DIV_FROM_REG(data->fan_div[nr - 1]));
-+ results[1] = FAN_FROM_REG(data->fan[nr - 1],
-+ DIV_FROM_REG(data->fan_div[nr - 1]));
-+ *nrels_mag = 2;
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ if (*nrels_mag >= 1) {
-+ data->fan_min[nr - 1] =
-+ FAN_TO_REG(results[0],
-+ DIV_FROM_REG(data->fan_div[nr-1]));
-+ asb100_write_value(client,
-+ ASB100_REG_FAN_MIN(nr),
-+ data->fan_min[nr - 1]);
-+ }
-+ }
-+}
-+
-+void asb100_temp(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct asb100_data *data = client->data;
-+ int nr = ctl_name - ASB100_SYSCTL_TEMP1;
-+
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 1;
-+
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ asb100_update_client(client);
-+ results[0] = TEMP_FROM_REG(data->temp_max[nr]);
-+ results[1] = TEMP_FROM_REG(data->temp_hyst[nr]);
-+ results[2] = TEMP_FROM_REG(data->temp[nr]);
-+ *nrels_mag = 3;
-+
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ if (*nrels_mag >= 1) {
-+ data->temp_max[nr] = TEMP_TO_REG(results[0]);
-+ asb100_write_value(client, ASB100_REG_TEMP_MAX(nr+1),
-+ data->temp_max[nr]);
-+ }
-+ if (*nrels_mag >= 2) {
-+ data->temp_hyst[nr] = TEMP_TO_REG(results[1]);
-+ asb100_write_value(client, ASB100_REG_TEMP_HYST(nr+1),
-+ data->temp_hyst[nr]);
-+ }
-+ }
-+}
-+
-+void asb100_temp_add(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results)
-+{
-+ struct asb100_data *data = client->data;
-+ int nr = ctl_name - ASB100_SYSCTL_TEMP1;
-+
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 1;
-+
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ asb100_update_client(client);
-+
-+ results[0] = LM75_TEMP_FROM_REG(data->temp_max[nr]);
-+ results[1] = LM75_TEMP_FROM_REG(data->temp_hyst[nr]);
-+ results[2] = LM75_TEMP_FROM_REG(data->temp[nr]);
-+ *nrels_mag = 3;
-+
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ if (*nrels_mag >= 1) {
-+ data->temp_max[nr] =
-+ LM75_TEMP_TO_REG(results[0]);
-+ asb100_write_value(client, ASB100_REG_TEMP_MAX(nr+1),
-+ data->temp_max[nr]);
-+ }
-+ if (*nrels_mag >= 2) {
-+ data->temp_hyst[nr] =
-+ LM75_TEMP_TO_REG(results[1]);
-+ asb100_write_value(client, ASB100_REG_TEMP_HYST(nr+1),
-+ data->temp_hyst[nr]);
-+ }
-+ }
-+}
-+
-+void asb100_vid(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct asb100_data *data = client->data;
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 3;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ asb100_update_client(client);
-+ results[0] = vid_from_reg(data->vid, data->vrm);
-+ *nrels_mag = 1;
-+ }
-+}
-+
-+void asb100_vrm(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct asb100_data *data = client->data;
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 1;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ results[0] = data->vrm;
-+ *nrels_mag = 1;
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ if (*nrels_mag >= 1)
-+ data->vrm = results[0];
-+ }
-+}
-+
-+void asb100_alarms(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct asb100_data *data = client->data;
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 0;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ asb100_update_client(client);
-+ results[0] = ALARMS_FROM_REG(data->alarms);
-+ *nrels_mag = 1;
-+ }
-+}
-+
-+void asb100_fan_div(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results)
-+{
-+ struct asb100_data *data = client->data;
-+ int old, old2;
-+
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 0;
-+
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ asb100_update_client(client);
-+ results[0] = DIV_FROM_REG(data->fan_div[0]);
-+ results[1] = DIV_FROM_REG(data->fan_div[1]);
-+ results[2] = DIV_FROM_REG(data->fan_div[2]);
-+ *nrels_mag = 3;
-+
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ old = asb100_read_value(client, ASB100_REG_VID_FANDIV);
-+ if (*nrels_mag >= 3) {
-+ data->fan_div[2] = DIV_TO_REG(results[2]);
-+ old2 = asb100_read_value(client, ASB100_REG_PIN);
-+ old2 = (old2 & 0x3f) | ((data->fan_div[2] & 0x03) << 6);
-+ asb100_write_value(client, ASB100_REG_PIN, old2);
-+ }
-+ if (*nrels_mag >= 2) {
-+ data->fan_div[1] = DIV_TO_REG(results[1]);
-+ old = (old & 0x3f) | ((data->fan_div[1] & 0x03) << 6);
-+ }
-+ if (*nrels_mag >= 1) {
-+ data->fan_div[0] = DIV_TO_REG(results[0]);
-+ old = (old & 0xcf) | ((data->fan_div[0] & 0x03) << 4);
-+ asb100_write_value(client, ASB100_REG_VID_FANDIV, old);
-+ }
-+ }
-+}
-+
-+void asb100_pwm(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct asb100_data *data = client->data;
-+
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 0;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ asb100_update_client(client);
-+ results[0] = ASB100_PWM_FROM_REG(data->pwm & 0x0f);
-+ results[1] = (data->pwm & 0x80) ? 1 : 0;
-+ *nrels_mag = 2;
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ u8 val = data->pwm;
-+ if (*nrels_mag >= 1) {
-+ val = 0x0f & ASB100_PWM_TO_REG(results[0]);
-+ if (*nrels_mag >= 2) {
-+ if (results[1])
-+ val |= 0x80;
-+ else
-+ val &= ~0x80;
-+ }
-+ asb100_write_value(client, ASB100_REG_PWM1, val);
-+ }
-+ }
-+}
-+
-+static int __init asb100_init(void)
-+{
-+ printk(KERN_INFO "asb100.o version %s (%s)\n", LM_VERSION, LM_DATE);
-+ return i2c_add_driver(&asb100_driver);
-+}
-+
-+static void __exit asb100_exit(void)
-+{
-+ i2c_del_driver(&asb100_driver);
-+}
-+
-+MODULE_AUTHOR( "Mark M. Hoffman <mhoffman@lightlink.com>, "
-+ "Frodo Looijaard <frodol@dds.nl>, "
-+ "Philip Edelbrock <phil@netroedge.com>, and"
-+ "Mark Studebaker <mdsxyz123@yahoo.com>");
-+
-+MODULE_DESCRIPTION("ASB100 'Bach' driver");
-+MODULE_LICENSE("GPL");
-+
-+module_init(asb100_init);
-+module_exit(asb100_exit);
-+
---- linux-old/drivers/sensors/bt869.c Thu Jan 1 00:00:00 1970
-+++ linux/drivers/sensors/bt869.c Mon Dec 13 20:18:45 2004
-@@ -0,0 +1,891 @@
-+/*
-+ bt869.c - Part of lm_sensors, Linux kernel modules for hardware
-+ monitoring
-+
-+ Copyright (c) 1998, 1999 Frodo Looijaard <frodol@dds.nl>
-+ Copyright (c) 2001, 2002 Stephen Davies <steve@daviesfam.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., 675 Mass Ave, Cambridge, MA 02139, USA.
-+*/
-+
-+
-+#define DEBUG 1
-+
-+#include <linux/module.h>
-+#include <linux/slab.h>
-+#include <linux/i2c.h>
-+#include <linux/i2c-proc.h>
-+#include <linux/init.h>
-+#define LM_DATE "20041007"
-+#define LM_VERSION "2.8.8"
-+
-+MODULE_LICENSE("GPL");
-+
-+/* Addresses to scan */
-+static unsigned short normal_i2c[] = { SENSORS_I2C_END };
-+
-+/* found only at 0x44 or 0x45 */
-+static unsigned short normal_i2c_range[] = { 0x44, 0x45, SENSORS_I2C_END };
-+static unsigned int normal_isa[] = { SENSORS_ISA_END };
-+static unsigned int normal_isa_range[] = { SENSORS_ISA_END };
-+
-+/* Insmod parameters */
-+SENSORS_INSMOD_1(bt869);
-+
-+/* Many bt869 constants specified below */
-+
-+/* The bt869 registers */
-+/* Coming soon: Many, many registers */
-+
-+/* Conversions. Rounding and limit checking is only done on the TO_REG
-+ variants. Note that you should be a bit careful with which arguments
-+ these macros are called: arguments may be evaluated more than once.
-+ Fixing this is just not worth it. */
-+
-+ /*none */
-+
-+/* Initial values */
-+/*none*/
-+
-+/* Each client has this additional data */
-+struct bt869_data {
-+ struct i2c_client client;
-+ int sysctl_id;
-+
-+ struct semaphore update_lock;
-+ char valid; /* !=0 if following fields are valid */
-+ unsigned long last_updated; /* In jiffies */
-+
-+ u8 status[3]; /* Register values */
-+ u16 res[2]; /* Resolution XxY */
-+ u8 ntsc; /* 1=NTSC, 0=PAL */
-+ u8 half; /* go half res */
-+ u8 depth; /* screen depth */
-+ u8 colorbars; /* turn on/off colorbar calibration screen */
-+ u8 svideo; /* output format: (2=RGB) 1=SVIDEO, 0=Composite */
-+};
-+
-+static int bt869_attach_adapter(struct i2c_adapter *adapter);
-+static int bt869_detect(struct i2c_adapter *adapter, int address,
-+ unsigned short flags, int kind);
-+static void bt869_init_client(struct i2c_client *client);
-+static int bt869_detach_client(struct i2c_client *client);
-+static int bt869_read_value(struct i2c_client *client, u8 reg);
-+static int bt869_write_value(struct i2c_client *client, u8 reg, u16 value);
-+static void bt869_write_values(struct i2c_client *client, u16 *values);
-+static void bt869_status(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void bt869_ntsc(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void bt869_res(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void bt869_half(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void bt869_colorbars(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void bt869_svideo(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void bt869_depth(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void bt869_update_client(struct i2c_client *client);
-+
-+
-+/* This is the driver that will be inserted */
-+static struct i2c_driver bt869_driver = {
-+ .owner = THIS_MODULE,
-+ .name = "BT869 video-output chip driver",
-+ .id = I2C_DRIVERID_BT869,
-+ .flags = I2C_DF_NOTIFY,
-+ .attach_adapter = bt869_attach_adapter,
-+ .detach_client = bt869_detach_client,
-+};
-+
-+/* -- SENSORS SYSCTL START -- */
-+#define BT869_SYSCTL_STATUS 1000
-+#define BT869_SYSCTL_NTSC 1001
-+#define BT869_SYSCTL_HALF 1002
-+#define BT869_SYSCTL_RES 1003
-+#define BT869_SYSCTL_COLORBARS 1004
-+#define BT869_SYSCTL_DEPTH 1005
-+#define BT869_SYSCTL_SVIDEO 1006
-+
-+/* -- SENSORS SYSCTL END -- */
-+
-+/* These files are created for each detected bt869. This is just a template;
-+ though at first sight, you might think we could use a statically
-+ allocated list, we need some way to get back to the parent - which
-+ is done through one of the 'extra' fields which are initialized
-+ when a new copy is allocated. */
-+static ctl_table bt869_dir_table_template[] = {
-+ {BT869_SYSCTL_STATUS, "status", NULL, 0, 0444, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &bt869_status},
-+ {BT869_SYSCTL_NTSC, "ntsc", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &bt869_ntsc},
-+ {BT869_SYSCTL_RES, "res", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &bt869_res},
-+ {BT869_SYSCTL_HALF, "half", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &bt869_half},
-+ {BT869_SYSCTL_COLORBARS, "colorbars", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &bt869_colorbars},
-+ {BT869_SYSCTL_DEPTH, "depth", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &bt869_depth},
-+ {BT869_SYSCTL_SVIDEO, "svideo", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &bt869_svideo},
-+ {0}
-+};
-+
-+/* ******************
-+
-+720x576, 27.5MHz, PAL, no overscan compensation.
-+
-+This mode should be use for digital video, DVD playback etc.
-+
-+NOTE: This mode for PAL, see 720x480 for an equivalent NTSC mode
-+NOTE: -- Steve Davies <steve@daviesfam.org>
-+
-+
-+Compatible X modeline:
-+
-+ Mode "720x576-BT869"
-+ DotClock 27.5
-+ HTimings 720 744 800 880
-+ VTimings 576 581 583 625
-+ EndMode
-+
-+
-+625LINE=1 625 line output format
-+BST_AMP[7:0]=x57 87 Burst ampl. multiplication factor (PAL std??)
-+BY_PLL=0 Use the PLL
-+CATTENUATE[2:0]=0 No chroma attenuation
-+CCF1B1[7:0]=0 close caption stuff
-+CCF1B2[7:0]=0 close caption stuff
-+CCF2B1[7:0]=0 close caption stuff
-+CCF2B2[7:0]=0 close caption stuff
-+CCORING[2:0]=0 Bypass chroma coring
-+CCR_START[8:0]=0 [CCR_START[8]=0; CCR_START[7:0]=0] Close-caption clock runin start from hsync
-+CC_ADD[11:0]=xD2 210 [CC_ADD[11:8]=0; CC_ADD[7:0]=xD2] Close-caption DTO increment
-+CHECK_STAT=0 Don't check monitor status
-+CLPF[1:0]=0 Hoz chroma lowpass filter=Bypass
-+DACDISA=1 Disable DACA
-+DACDISB=0 Don't disable DACB
-+DACDISC=0 Don't disable DACC
-+DACOFF=0 Don't disable the DACs
-+DATDLY = 0 normal
-+DATSWP=0 normal
-+DCHROMA=0 Don't blank chroma
-+DIS_FFILT=1 Disable flickerfilter
-+DIS_GMSHC=1 Disable chroma psuedo-gamma removal
-+DIS_GMSHY=1 Disable luma pseudo gamma removal
-+DIS_GMUSHC=1 Disable chroma anti-pseudo gamma removal
-+DIS_GMUSHY=1 Disable luma anti-pseudo gamma removal
-+DIS_SCRESET=0 Normal subcarrier phase resets
-+DIS_YFLPF=0 Disable Luma initial hoz low pass filter
-+DIV2=0 Input pixel rate not divided by 2
-+ECBAR=0 No colour bars
-+ECCF1=0 Disable closed caption
-+ECCF2=0 Disable closed caption
-+ECCGATE=0 Normal close caption encoding
-+ECLIP=0 0=disable clipping
-+EN_ASYNC=0 set to 0 for normal operation
-+EN_BLANKO=0 BLANK is an input
-+EN_DOT=0 Disables dot clock sync on BLANK pin
-+EN_OUT=1 Allows outputs to be enabled
-+EN_XCLK=1 Use CLKI pin as clock source
-+ESTATUS[1:0]=0 Used to select readback register
-+FIELDI=0 Logical 1 on FIELD indicates even field
-+F_SELC[2:0]=0 5 line chroma flickerfilter
-+F_SELY[2:0]=0 5 line luma flickerfilter
-+HBURST_BEGIN[7:0]=x98 152 Chroma burst start point in clocks
-+HBURST_END[7:0]=x58 88 Chroma burst end point in clocks - 128
-+HSYNCI=0 Active low HSYNC
-+HSYNC_WIDTH[7:0]=x80 128 Analogue sync width in clocks
-+HSYNOFFSET[9:0]=0 [HSYNOFFSET[9:8]=0; HSYNOFFSET[7:0]=0] hsync in "standard position"
-+HSYNWIDTH[5:0]=2 2 pixel hsync width
-+H_ACTIVE[9:0]=x2D0 720 [H_ACTIVE[9:8]=2; H_ACTIVE[7:0]=xD0] Active pixels per line
-+H_BLANKI[8:0]=x84 132 [H_BLANKI[8]=0; H_BLANKI[7:0]=x84] End of blanking of input video
-+H_BLANKO[9:0]=x120 288 [H_BLANKO[9:8]=1; H_BLANKO[7:0]=x20] End of blanking from hoz sync leading edge
-+H_CLKI[10:0]=x378 888 [H_CLKI[10:8]=3; H_CLKI[7:0]=x78] Input line length total in clocks
-+H_CLKO[11:0]=x6e0 1760 [H_CLKO[11:8]=6; H_CLKO[7:0]=xe0] Output clocks per line
-+H_FRACT[7:0]=0 0 fractional input clocks per line
-+IN_MODE[2:0]=0 24Bit RGB muxed
-+LUMADLY[1:0]=0 0 pixel delay on Y_DLY luma
-+MCB[7:0]=x49 73 Mult factor for CB prior to subcarrier mod.
-+MCR[7:0]=x82 130 Mult factor for CR prior to subcarrier mod.
-+MODE2X=0 Don't divide clock input by 2
-+MSC[31:0]=x2945E0B4 692445365 [MSC[31:24]=x29; MSC[23:16]=x45; MSC[15:8]=xE0; MSC[7:0]=xB4] Subcarrier incr.
-+MY[7:0]=x8C 140 Mult factor for Y
-+NI_OUT=0 Normal interlaced output
-+OUT_MODE[1:0]=0 video0-3 is CVBS, Y, C, Y_DLY
-+OUT_MUXA[1:0]=0 Don't care as DACA is disabled
-+OUT_MUXB[1:0]=1 Output video[1] (Y) on DACB
-+OUT_MUXC[1:0]=2 Output video[2] (C) on DACC
-+PAL_MD=1 Video output in PAL mode
-+PHASE_OFF[7:0]=0 Subcarrier phase offset
-+PLL_FRACT[15:0]=x30 48 [PLL_FRACT[15:8]=0x0; PLL_FRACT[7:0]=x30] frac portion of pll multiplier
-+PLL_INT[5:0]=0x0C 12 Int portion of pll multiplier
-+SETUP=0 7.5-IRE setup disabled
-+SLAVER=1
-+SRESET=0 Don't do a software reset
-+SYNC_AMP[7:0]=xF0 240 Sync amp mult. factor (PAL std???)
-+VBLANKDLY=0 Extra line of blanking in 2nd field?
-+VSYNCI=0 Active low VSYNC
-+VSYNC_DUR=0 2.5line VSYNC duration on output
-+VSYNCOFFSET[10:0]=0 [VSYNOFFSET[10:8]=0; VSYNOFFSET[7:0]=0] VSYNC in standard position
-+VSYNWIDTH[2:0]=1 1 line of vsync width
-+V_ACTIVEI[9:0]=x240 576 [V_ACTIVEI[9:0]=2; V_ACTIVEI[7:0]=x40] Active input lines
-+V_ACTIVEO[8:0]=x122 290 [V_ACTIVE0[8]=1; V_ACTIVEO[7:0]=x22]
-+V_BLANKI[7:0]=x2A 42 Input lines from vsync to first active line
-+V_BLANKO[7:0]=x16 22
-+V_LINESI[9:0]=x271 625 [V_LINESI[9:8]=2; V_LINESI[7:0]=x71] Number of input lines
-+V_SCALE[13:0]=x1000 4096 [V_SCALE[13:8]=x10; V_SCALE[7:0]=0] Vert scale coefficient="none"?
-+YATTENUATE[2:0]=0 no luma attenuation
-+YCORING[2:0]=0 Luma-coring bypass
-+YLPF[1:0]=0 Luma hoz low pass filter=bypass
-+
-+***************** */
-+
-+static u16 registers_720_576[] =
-+ {
-+ 0x6e, 0x00, /* HSYNOFFSET[7:0]=0 */
-+ 0x70, 0x02, /* HSYNOFFSET[9:8]=0; HSYNWIDTH[5:0]=2 */
-+ 0x72, 0x00, /* VSYNOFFSET[7:0]=0 */
-+ 0x74, 0x01, /* DATDLY = 0; DATSWP=0; VSYNOFFSET[10:8]=0; VSYNWIDTH[2:0]=1 */
-+ 0x76, 0xe0, /* H_CLKO[7:0]=xe0 */
-+ 0x78, 0xd0, /* H_ACTIVE[7:0]=xD0 */
-+ 0x7a, 0x80, /* HSYNC_WIDTH[7:0]=x80 */
-+ 0x7c, 0x98, /* HBURST_BEGIN[7:0]=x98 */
-+ 0x7e, 0x58, /* HBURST_END[7:0]=x58 */
-+ 0x80, 0x20, /* H_BLANKO[7:0]=x20 */
-+ 0x82, 0x16, /* V_BLANKO[7:0]=x16 */
-+ 0x84, 0x22, /* V_ACTIVEO[7:0]=x22 */
-+ 0x86, 0xa6, /* V_ACTIVE0[8]=1; H_ACTIVE[9:8]=2; H_CLKO[11:8]=6 */
-+ 0x88, 0x00, /* H_FRACT[7:0]=0 */
-+ 0x8a, 0x78, /* H_CLKI[7:0]=x78 */
-+ 0x8c, 0x80, /* H_BLANKI[7:0]=x84 */
-+ 0x8e, 0x03, /* VBLANKDLY=0; H_BLANKI[8]=0; H_CLKI[10:8]=3 */
-+ 0x90, 0x71, /* V_LINESI[7:0]=x71 */
-+ 0x92, 0x2a, /* V_BLANKI[7:0]=x2A */
-+ 0x94, 0x40, /* V_ACTIVEI[7:0]=x40 */
-+ 0x96, 0x0a, /* CLPF[1:0]=0; YLPF[1:0]=0; V_ACTIVEI[9:0]=2; V_LINESI[9:8]=2 */
-+ 0x98, 0x00, /* V_SCALE[7:0]=0 */
-+ 0x9a, 0x50, /* H_BLANKO[9:8]=1; V_SCALE[13:8]=x10 */
-+ 0x9c, 0x30, /* PLL_FRACT[7:0]=x30 */
-+ 0x9e, 0x0, /* PLL_FRACT[15:8]=0x0 */
-+ 0xa0, 0x8c, /* EN_XCLK=1; BY_PLL=0; PLL_INT[5:0]=0x0C */
-+ 0xa2, 0x24, /* ECLIP=0; PAL_MD=1; DIS_SCRESET=0; VSYNC_DUR=0; 625LINE=1; SETUP=0; NI_OUT=0 */
-+ 0xa4, 0xf0, /* SYNC_AMP[7:0]=xF0 */
-+ 0xa6, 0x57, /* BST_AMP[7:0]=x57 */
-+ 0xa8, 0x82, /* MCR[7:0]=x82 */
-+ 0xaa, 0x49, /* MCB[7:0]=x49 */
-+ 0xac, 0x8c, /* MY[7:0]=x8C */
-+ 0xae, 0xb4, /* MSC[7:0]=xb4 */
-+ 0xb0, 0xe0, /* MSC[15:8]=xe0 */
-+ 0xb2, 0x45, /* MSC[23:16]=x45 */
-+ 0xb4, 0x29, /* MSC[31:24]=x29 */
-+ 0xb6, 0x00, /* PHASE_OFF[7:0]=0 */
-+ //0xba, 0x21, /* SRESET=0; CHECK_STAT=0; SLAVER=1; DACOFF=0; DACDISC=0; DACDISB=0; DACDISA=1 */
-+ 0xc4, 0x01, /* ESTATUS[1:0]=0; ECCF2=0; ECCF1=0; ECCGATE=0; ECBAR=0; DCHROMA=0; EN_OUT=1 */
-+ 0xc6, 0x00, /* EN_BLANKO=0; EN_DOT=0; FIELDI=0; VSYNCI=0; HSYNCI=0; IN_MODE[2:0]=0(24bRGB) */
-+ 0xc8, 0x40, /* DIS_YFLPF=0; DIS_FFILT=1; F_SELC[2:0]=0; F_SELY[2:0]=0 */
-+ 0xca, 0xc0, /* DIS_GMUSHY=1; DIS_GMSHY=1; YCORING[2:0]=0; YATTENUATE[2:0]=0 */
-+ 0xcc, 0xc0, /* DIS_GMUSHC=1; DIS_GMSHC=1; CCORING[2:0]=0; CATTENUATE[2:0]=0 */
-+ //0xce, 0x24, /* OUT_MUXC=2 [C]; OUT_MUXB=1 [Y]; OUT_MUXA=0 [CVBS, but disabled]*/
-+ //0xce, 0x04, /* OUT_MUXC=0 [CVBS]; OUT_MUXB=1 [Y]; OUT_MUXA=0 [CVBS, but disabled]*/
-+ 0xd6, 0x00, /* OUT_MODE[1:0]=0; LUMADLY[1:0]=0 */
-+ 0, 0
-+ };
-+
-+
-+/* ******************
-+
-+720x480, 27.5MHz, NTSC no overscan compensation.
-+
-+This mode should be use for digital video, DVD playback etc.
-+
-+NOTE: This mode for NTSC, see 720x576 for an equivalent PAL mode
-+NOTE: -- Steve Davies <steve@daviesfam.org>
-+
-+Compatible X modeline:
-+
-+ Mode "720x480-BT869"
-+ DotClock 27.5
-+ HTimings 720 744 800 872
-+ VTimings 480 483 485 525
-+ EndMode
-+
-+
-+625LINE=0 not 625 line output format
-+BST_AMP[7:0]=x74 116 Burst ampl. multiplication factor (NTSC std??)
-+BY_PLL=0 Use the PLL
-+CATTENUATE[2:0]=0 No chroma attenuation
-+CCF1B1[7:0]=0 close caption stuff
-+CCF1B2[7:0]=0 close caption stuff
-+CCF2B1[7:0]=0 close caption stuff
-+CCF2B2[7:0]=0 close caption stuff
-+CCORING[2:0]=0 Bypass chroma coring
-+CCR_START[8:0]=0 [CCR_START[8]=0; CCR_START[7:0]=0] Close-caption clock runin start from hsync
-+CC_ADD[11:0]=xD2 210 [CC_ADD[11:8]=0; CC_ADD[7:0]=xD2] Close-caption DTO increment
-+CHECK_STAT=0 Don't check monitor status
-+CLPF[1:0]=0 Hoz chroma lowpass filter=Bypass
-+DACDISA=1 Disable DACA
-+DACDISB=0 Don't disable DACB
-+DACDISC=0 Don't disable DACC
-+DACOFF=0 Don't disable the DACs
-+DATDLY = 0 normal
-+DATSWP=0 normal
-+DCHROMA=0 Don't blank chroma
-+DIS_FFILT=1 Disable flickerfilter
-+DIS_GMSHC=1 Disable chroma psuedo-gamma removal
-+DIS_GMSHY=1 Disable luma pseudo gamma removal
-+DIS_GMUSHC=1 Disable chroma anti-pseudo gamma removal
-+DIS_GMUSHY=1 Disable luma anti-pseudo gamma removal
-+DIS_SCRESET=0 Normal subcarrier phase resets
-+DIS_YFLPF=0 Disable Luma initial hoz low pass filter
-+DIV2=0 Input pixel rate not divided by 2
-+ECBAR=0 No colour bars
-+ECCF1=0 Disable closed caption
-+ECCF2=0 Disable closed caption
-+ECCGATE=0 Normal close caption encoding
-+ECLIP=0 0=disable clipping
-+EN_ASYNC=0 set to 0 for normal operation
-+EN_BLANKO=0 BLANK is an input
-+EN_DOT=0 Disables dot clock sync on BLANK pin
-+EN_OUT=1 Allows outputs to be enabled
-+EN_XCLK=1 Use CLKI pin as clock source
-+ESTATUS[1:0]=0 Used to select readback register
-+FIELDI=0 Logical 1 on FIELD indicates even field
-+F_SELC[2:0]=0 5 line chroma flickerfilter
-+F_SELY[2:0]=0 5 line luma flickerfilter
-+HBURST_BEGIN[7:0]=x92 146 Chroma burst start point in clocks
-+HBURST_END[7:0]=x57 87 Chroma burst end point in clocks - 128
-+HSYNCI=0 Active low HSYNC
-+HSYNC_WIDTH[7:0]=x80 128 Analogue sync width in clocks
-+HSYNOFFSET[9:0]=0 [HSYNOFFSET[9:8]=0; HSYNOFFSET[7:0]=0] hsync in "standard position"
-+HSYNWIDTH[5:0]=2 2 pixel hsync width
-+H_ACTIVE[9:0]=x2D0 720 [H_ACTIVE[9:8]=2; H_ACTIVE[7:0]=xD0] Active pixels per line
-+H_BLANKI[8:0]=x80 128 [H_BLANKI[8]=0; H_BLANKI[7:0]=x80] End of blanking of input video
-+H_BLANKO[9:0]=x102 258 [H_BLANKO[9:8]=1; H_BLANKO[7:0]=x2] End of blanking from hoz sync leading edge
-+H_CLKI[10:0]=x368 872 [H_CLKI[10:8]=3; H_CLKI[7:0]=x68] Input line length total in clocks
-+H_CLKO[11:0]=x6d0 1744 [H_CLKO[11:8]=6; H_CLKO[7:0]=xD0] Output clocks per line
-+H_FRACT[7:0]=0 0 fractional input clocks per line
-+IN_MODE[2:0]=0 24Bit RGB muxed
-+LUMADLY[1:0]=0 0 pixel delay on Y_DLY luma
-+MCB[7:0]=x43 67 Mult factor for CB prior to subcarrier mod.
-+MCR[7:0]=x77 119 Mult factor for CR prior to subcarrier mod.
-+MODE2X=0 Don't divide clock input by 2
-+MSC[31:0]=x215282E5 559055589 [MSC[31:24]=x21; MSC[23:16]=x52; MSC[15:8]=x82; MSC[7:0]=xE5] Subcarrier incr.
-+MY[7:0]=x85 133 Mult factor for Y
-+NI_OUT=0 Normal interlaced output
-+OUT_MODE[1:0]=0 video0-3 is CVBS, Y, C, Y_DLY
-+OUT_MUXA[1:0]=0 Don't care as DACA is disabled
-+OUT_MUXB[1:0]=1 Output video[1] (Y) on DACB
-+OUT_MUXC[1:0]=2 Output video[2] (C) on DACC
-+PAL_MD=0 Video output in PAL mode? No.
-+PHASE_OFF[7:0]=0 Subcarrier phase offset
-+PLL_FRACT[15:0]=x30 48 [PLL_FRACT[15:8]=0x0; PLL_FRACT[7:0]=x30] frac portion of pll multiplier
-+PLL_INT[5:0]=0x0C 12 Int portion of pll multiplier
-+SETUP=1 7.5-IRE enabled for NTSC
-+SLAVER=1
-+SRESET=0 Don't do a software reset
-+SYNC_AMP[7:0]=xE5 229 Sync amp mult. factor (PAL std???)
-+VBLANKDLY=0 Extra line of blanking in 2nd field?
-+VSYNCI=0 Active low VSYNC
-+VSYNC_DUR=1 2.5line VSYNC duration on output (Yes for NTSC)
-+VSYNCOFFSET[10:0]=0 [VSYNOFFSET[10:8]=0; VSYNOFFSET[7:0]=0] VSYNC in standard position
-+VSYNWIDTH[2:0]=1 1 line of vsync width
-+V_ACTIVEI[9:0]=x1E0 480 [V_ACTIVEI[9:0]=1; V_ACTIVEI[7:0]=xE0] Active input lines
-+V_ACTIVEO[8:0]=xF0 240 [V_ACTIVE0[8]=0; V_ACTIVEO[7:0]=xF0]
-+V_BLANKI[7:0]=x2A 42 Input lines from vsync to first active line
-+V_BLANKO[7:0]=x16 22
-+V_LINESI[9:0]=x20D 525 [V_LINESI[9:8]=2; V_LINESI[7:0]=x0D] Number of input lines
-+V_SCALE[13:0]=x1000 4096 [V_SCALE[13:8]=x10; V_SCALE[7:0]=0] Vert scale coefficient="none"?
-+YATTENUATE[2:0]=0 no luma attenuation
-+YCORING[2:0]=0 Luma-coring bypass
-+YLPF[1:0]=0 Luma hoz low pass filter=bypass
-+
-+***************** */
-+
-+static u16 registers_720_480[] =
-+ {
-+ 0x6e, 0x00, /* HSYNOFFSET[7:0]=0 */
-+ 0x70, 0x02, /* HSYNOFFSET[9:8]=0; HSYNWIDTH[5:0]=2 */
-+ 0x72, 0x00, /* VSYNOFFSET[7:0]=0 */
-+ 0x74, 0x01, /* DATDLY = 0; DATSWP=0; VSYNOFFSET[10:8]=0; VSYNWIDTH[2:0]=1 */
-+ 0x76, 0xD0, /* H_CLKO[7:0]=xD0 */
-+ 0x78, 0xD0, /* H_ACTIVE[7:0]=xD0 */
-+ 0x7a, 0x80, /* HSYNC_WIDTH[7:0]=x80 */
-+ 0x7c, 0x92, /* HBURST_BEGIN[7:0]=x92 */
-+ 0x7e, 0x57, /* HBURST_END[7:0]=x57 */
-+ 0x80, 0x02, /* H_BLANKO[7:0]=x2 */
-+ 0x82, 0x16, /* V_BLANKO[7:0]=x16 */
-+ 0x84, 0xF0, /* V_ACTIVEO[7:0]=xF0 */
-+ 0x86, 0x26, /* V_ACTIVE0[8]=0; H_ACTIVE[9:8]=2; H_CLKO[11:8]=6 */
-+ 0x88, 0x00, /* H_FRACT[7:0]=0 */
-+ 0x8a, 0xD0, /* H_CLKI[7:0]=xD0 */
-+ 0x8c, 0x80, /* H_BLANKI[7:0]=x80 */
-+ 0x8e, 0x03, /* VBLANKDLY=0; H_BLANKI[8]=0; H_CLKI[10:8]=3 */
-+ 0x90, 0x0D, /* V_LINESI[7:0]=x0D */
-+ 0x92, 0x2A, /* V_BLANKI[7:0]=x2A */
-+ 0x94, 0xE0, /* V_ACTIVEI[7:0]=xE0 */
-+ 0x96, 0x06, /* CLPF[1:0]=0; YLPF[1:0]=0; V_ACTIVEI[9:8]=1; V_LINESI[9:8]=2 */
-+ 0x98, 0x00, /* V_SCALE[7:0]=0 */
-+ 0x9a, 0x50, /* H_BLANKO[9:8]=1; V_SCALE[13:8]=x10 */
-+ 0x9c, 0x30, /* PLL_FRACT[7:0]=x30 */
-+ 0x9e, 0x0, /* PLL_FRACT[15:8]=0x0 */
-+ 0xa0, 0x8c, /* EN_XCLK=1; BY_PLL=0; PLL_INT[5:0]=0x0C */
-+ 0xa2, 0x0A, /* ECLIP=0; PAL_MD=0; DIS_SCRESET=0; VSYNC_DUR=1; 625LINE=0; SETUP=1; NI_OUT=0 */
-+ 0xa4, 0xE5, /* SYNC_AMP[7:0]=xE5 */
-+ 0xa6, 0x74, /* BST_AMP[7:0]=x74 */
-+ 0xa8, 0x77, /* MCR[7:0]=x77 */
-+ 0xaa, 0x43, /* MCB[7:0]=x43 */
-+ 0xac, 0x85, /* MY[7:0]=x85 */
-+ 0xae, 0xE5, /* MSC[7:0]=xE5 */
-+ 0xb0, 0x82, /* MSC[15:8]=x82 */
-+ 0xb2, 0x52, /* MSC[23:16]=x52 */
-+ 0xb4, 0x21, /* MSC[31:24]=x21 */
-+ 0xb6, 0x00, /* PHASE_OFF[7:0]=0 */
-+ //0xba, 0x21, /* SRESET=0; CHECK_STAT=0; SLAVER=1; DACOFF=0; DACDISC=0; DACDISB=0; DACDISA=1 */
-+ 0xc4, 0x01, /* ESTATUS[1:0]=0; ECCF2=0; ECCF1=0; ECCGATE=0; ECBAR=0; DCHROMA=0; EN_OUT=1 */
-+ 0xc6, 0x00, /* EN_BLANKO=0; EN_DOT=0; FIELDI=0; VSYNCI=0; HSYNCI=0; IN_MODE[2:0]=0(24bRGB) */
-+ 0xc8, 0x40, /* DIS_YFLPF=0; DIS_FFILT=1; F_SELC[2:0]=0; F_SELY[2:0]=0 */
-+ 0xca, 0xc0, /* DIS_GMUSHY=1; DIS_GMSHY=1; YCORING[2:0]=0; YATTENUATE[2:0]=0 */
-+ 0xcc, 0xc0, /* DIS_GMUSHC=1; DIS_GMSHC=1; CCORING[2:0]=0; CATTENUATE[2:0]=0 */
-+ //0xce, 0x24, /* OUT_MUXC=2 [C]; OUT_MUXB=1 [Y]; OUT_MUXA=0 [CVBS, but disabled]*/
-+ //0xce, 0x04, /* OUT_MUXC=0 [CVBS]; OUT_MUXB=1 [Y]; OUT_MUXA=0 [CVBS, but disabled]*/
-+ 0xd6, 0x00, /* OUT_MODE[1:0]=0; LUMADLY[1:0]=0 */
-+ 0, 0
-+ };
-+
-+
-+int bt869_id = 0;
-+
-+static int bt869_attach_adapter(struct i2c_adapter *adapter)
-+{
-+ return i2c_detect(adapter, &addr_data, bt869_detect);
-+}
-+
-+/* This function is called by i2c_detect */
-+int bt869_detect(struct i2c_adapter *adapter, int address,
-+ unsigned short flags, int kind)
-+{
-+ int i, cur;
-+ struct i2c_client *new_client;
-+ struct bt869_data *data;
-+ int err = 0;
-+ const char *type_name, *client_name;
-+
-+
-+ printk("bt869.o: probing address %d .\n", address);
-+ /* Make sure we aren't probing the ISA bus!! This is just a safety check
-+ at this moment; i2c_detect really won't call us. */
-+#ifdef DEBUG
-+ if (i2c_is_isa_adapter(adapter)) {
-+ printk
-+ ("bt869.o: bt869_detect called for an ISA bus adapter?!?\n");
-+ return 0;
-+ }
-+#endif
-+
-+ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_READ_BYTE |
-+ I2C_FUNC_SMBUS_WRITE_BYTE_DATA))
-+ goto ERROR0;
-+
-+ /* OK. For now, we presume we have a valid client. We now create the
-+ client structure, even though we cannot fill it completely yet.
-+ But it allows us to access bt869_{read,write}_value. */
-+ if (!(data = kmalloc(sizeof(struct bt869_data), GFP_KERNEL))) {
-+ err = -ENOMEM;
-+ goto ERROR0;
-+ }
-+
-+ new_client = &data->client;
-+ new_client->addr = address;
-+ new_client->data = data;
-+ new_client->adapter = adapter;
-+ new_client->driver = &bt869_driver;
-+ new_client->flags = 0;
-+
-+ /* Now, we do the remaining detection. It is lousy. */
-+ i2c_smbus_write_byte_data(new_client, 0xC4, 0); /* set status bank 0 */
-+ cur = i2c_smbus_read_byte(new_client);
-+ printk("bt869.o: address 0x%X testing-->0x%X\n", address, cur);
-+ if ((cur & 0xE0) != 0x20)
-+ goto ERROR1;
-+
-+ /* Determine the chip type */
-+ kind = ((cur & 0x20) >> 5);
-+
-+ if (kind) {
-+ type_name = "bt869";
-+ client_name = "bt869 chip";
-+ printk("bt869.o: BT869 detected\n");
-+ } else {
-+ type_name = "bt868";
-+ client_name = "bt868 chip";
-+ printk("bt869.o: BT868 detected\n");
-+ }
-+
-+ /* Fill in the remaining client fields and put it into the global list */
-+ strcpy(new_client->name, client_name);
-+
-+ new_client->id = bt869_id++;
-+ data->valid = 0;
-+ init_MUTEX(&data->update_lock);
-+
-+ /* Tell the I2C layer a new client has arrived */
-+ if ((err = i2c_attach_client(new_client)))
-+ goto ERROR3;
-+
-+ /* Register a new directory entry with module sensors */
-+ if ((i = i2c_register_entry(new_client, type_name,
-+ bt869_dir_table_template)) < 0) {
-+ err = i;
-+ goto ERROR4;
-+ }
-+ data->sysctl_id = i;
-+
-+ bt869_init_client((struct i2c_client *) new_client);
-+ return 0;
-+
-+/* OK, this is not exactly good programming practice, usually. But it is
-+ very code-efficient in this case. */
-+
-+ ERROR4:
-+ i2c_detach_client(new_client);
-+ ERROR3:
-+ ERROR1:
-+ kfree(data);
-+ ERROR0:
-+ return err;
-+}
-+
-+static int bt869_detach_client(struct i2c_client *client)
-+{
-+ int err;
-+
-+ i2c_deregister_entry(((struct bt869_data *) (client->data))->
-+ sysctl_id);
-+
-+ if ((err = i2c_detach_client(client))) {
-+ printk
-+ ("bt869.o: Client deregistration failed, client not detached.\n");
-+ return err;
-+ }
-+
-+ kfree(client->data);
-+
-+ return 0;
-+}
-+
-+
-+/* All registers are byte-sized.
-+ bt869 uses a high-byte first convention, which is exactly opposite to
-+ the usual practice. */
-+static int bt869_read_value(struct i2c_client *client, u8 reg)
-+{
-+ return i2c_smbus_read_byte(client);
-+}
-+
-+/* All registers are byte-sized.
-+ bt869 uses a high-byte first convention, which is exactly opposite to
-+ the usual practice. */
-+static int bt869_write_value(struct i2c_client *client, u8 reg, u16 value)
-+{
-+#ifdef DEBUG
-+ printk("bt869.o: write_value(0x%X, 0x%X)\n", reg, value);
-+#endif
-+ return i2c_smbus_write_byte_data(client, reg, value);
-+}
-+
-+static void bt869_write_values(struct i2c_client *client, u16 *values)
-+{
-+ /* writes set of registers from array. 0,0 marks end of table */
-+ while (*values) {
-+ bt869_write_value(client, values[0], values[1]);
-+ values += 2;
-+ }
-+}
-+
-+static void bt869_init_client(struct i2c_client *client)
-+{
-+ struct bt869_data *data = client->data;
-+
-+ /* Initialize the bt869 chip */
-+ bt869_write_value(client, 0x0ba, 0x80);
-+ // bt869_write_value(client,0x0D6, 0x00);
-+ /* Be a slave to the clock on the Voodoo3 */
-+ bt869_write_value(client, 0xa0, 0x80);
-+ bt869_write_value(client, 0xba, 0x20);
-+ /* depth =16bpp */
-+ bt869_write_value(client, 0x0C6, 0x001);
-+ bt869_write_value(client, 0xC4, 1);
-+ /* Flicker free enable and config */
-+ bt869_write_value(client, 0xC8, 0);
-+ data->res[0] = 640;
-+ data->res[1] = 480;
-+ data->ntsc = 1;
-+ data->half = 0;
-+ data->colorbars = 0;
-+ data->svideo = 0;
-+ data->depth = 16;
-+
-+}
-+
-+static void bt869_update_client(struct i2c_client *client)
-+{
-+ struct bt869_data *data = client->data;
-+
-+ down(&data->update_lock);
-+
-+ if ((jiffies - data->last_updated > HZ + HZ / 2) ||
-+ (jiffies < data->last_updated) || !data->valid) {
-+#ifdef DEBUG
-+ printk("Starting bt869 update\n");
-+#endif
-+ if ((data->res[0] == 800) && (data->res[1] == 600)) {
-+ /* 800x600 built-in mode */
-+ bt869_write_value(client, 0xB8,
-+ (2 + (!data->ntsc)));
-+ bt869_write_value(client, 0xa0, 0x80 + 0x11);
-+ printk("bt869.o: writing into config -->0x%X\n",
-+ (2 + (!data->ntsc)));
-+ }
-+ else if ((data->res[0] == 720) && (data->res[1] == 576)) {
-+ /* 720x576 no-overscan-compensation mode suitable for PAL DVD playback */
-+ data->ntsc = 0; /* This mode always PAL */
-+ bt869_write_values(client, registers_720_576);
-+ }
-+ else if ((data->res[0] == 720) && (data->res[1] == 480)) {
-+ /* 720x480 no-overscan-compensation mode suitable for NTSC DVD playback */
-+ data->ntsc = 1; /* This mode always NTSC */
-+ bt869_write_values(client, registers_720_480);
-+ }
-+ else {
-+ /* 640x480 built-in mode */
-+ bt869_write_value(client, 0xB8, (!data->ntsc));
-+ bt869_write_value(client, 0xa0, 0x80 + 0x0C);
-+ printk("bt869.o: writing into config -->0x%X\n",
-+ (0 + (!data->ntsc)));
-+ if ((data->res[0] != 640) || (data->res[1] != 480)) {
-+ printk
-+ ("bt869.o: Warning: arbitrary resolutions not supported yet. Using 640x480.\n");
-+ data->res[0] = 640;
-+ data->res[1] = 480;
-+ }
-+ }
-+ /* Set colour depth */
-+ if ((data->depth != 24) && (data->depth != 16))
-+ data->depth = 16;
-+ if (data->depth == 16)
-+ bt869_write_value(client, 0x0C6, 0x001);
-+ if (data->depth == 24)
-+ bt869_write_value(client, 0x0C6, 0x000);
-+ /* set "half" resolution mode */
-+ bt869_write_value(client, 0xd4, data->half << 6);
-+ /* Set composite/svideo mode, also enable the right dacs */
-+ switch (data->svideo) {
-+ case 2: /* RGB */
-+ /* requires hardware mod on Voodoo3 to get all outputs,
-+ untested in practice... Feedback to steve@daviesfam.org please */
-+ bt869_write_value(client, 0xd6, 0x0c);
-+ bt869_write_value(client, 0xce, 0x24);
-+ bt869_write_value(client, 0xba, 0x20);
-+ break;
-+ case 1: /* Svideo*/
-+ bt869_write_value(client, 0xce, 0x24);
-+ bt869_write_value(client, 0xba, 0x21);
-+ break;
-+ default: /* Composite */
-+ bt869_write_value(client, 0xce, 0x0);
-+ bt869_write_value(client, 0xba, 0x21);
-+ break;
-+ }
-+ /* Enable outputs */
-+ bt869_write_value(client, 0xC4, 1);
-+ /* Issue timing reset */
-+ bt869_write_value(client, 0x6c, 0x80);
-+
-+/* Read back status registers */
-+ bt869_write_value(client, 0xC4,
-+ 1 | (data->colorbars << 2));
-+ data->status[0] = bt869_read_value(client, 1);
-+ bt869_write_value(client, 0xC4,
-+ 0x41 | (data->colorbars << 2));
-+ data->status[1] = bt869_read_value(client, 1);
-+ bt869_write_value(client, 0xC4,
-+ 0x81 | (data->colorbars << 2));
-+ data->status[2] = bt869_read_value(client, 1);
-+ bt869_write_value(client, 0xC4,
-+ 0x0C1 | (data->colorbars << 2));
-+ data->last_updated = jiffies;
-+ data->valid = 1;
-+ }
-+ up(&data->update_lock);
-+}
-+
-+
-+void bt869_status(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct bt869_data *data = client->data;
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 0;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ bt869_update_client(client);
-+ results[0] = data->status[0];
-+ results[1] = data->status[1];
-+ results[2] = data->status[2];
-+ *nrels_mag = 3;
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ printk
-+ ("bt869.o: Warning: write was requested on read-only proc file: status\n");
-+ }
-+}
-+
-+
-+void bt869_ntsc(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct bt869_data *data = client->data;
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 0;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ bt869_update_client(client);
-+ results[0] = data->ntsc;
-+ *nrels_mag = 1;
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ if (*nrels_mag >= 1) {
-+ data->ntsc = (results[0] > 0);
-+ }
-+ bt869_update_client(client);
-+ }
-+}
-+
-+
-+void bt869_svideo(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct bt869_data *data = client->data;
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 0;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ bt869_update_client(client);
-+ results[0] = data->svideo;
-+ *nrels_mag = 1;
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ if (*nrels_mag >= 1) {
-+ data->svideo = results[0];
-+ }
-+ bt869_update_client(client);
-+ }
-+}
-+
-+
-+void bt869_res(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct bt869_data *data = client->data;
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 0;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ bt869_update_client(client);
-+ results[0] = data->res[0];
-+ results[1] = data->res[1];
-+ *nrels_mag = 2;
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ if (*nrels_mag >= 1) {
-+ data->res[0] = results[0];
-+ }
-+ if (*nrels_mag >= 2) {
-+ data->res[1] = results[1];
-+ }
-+ bt869_update_client(client);
-+ }
-+}
-+
-+
-+void bt869_half(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct bt869_data *data = client->data;
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 0;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ bt869_update_client(client);
-+ results[0] = data->half;
-+ *nrels_mag = 1;
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ if (*nrels_mag >= 1) {
-+ data->half = (results[0] > 0);
-+ bt869_update_client(client);
-+ }
-+ }
-+}
-+
-+void bt869_colorbars(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results)
-+{
-+ struct bt869_data *data = client->data;
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 0;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ bt869_update_client(client);
-+ results[0] = data->colorbars;
-+ *nrels_mag = 1;
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ if (*nrels_mag >= 1) {
-+ data->colorbars = (results[0] > 0);
-+ bt869_update_client(client);
-+ }
-+ }
-+}
-+
-+void bt869_depth(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct bt869_data *data = client->data;
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 0;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ bt869_update_client(client);
-+ results[0] = data->depth;
-+ *nrels_mag = 1;
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ if (*nrels_mag >= 1) {
-+ data->depth = results[0];
-+ bt869_update_client(client);
-+ }
-+ }
-+}
-+
-+static int __init sm_bt869_init(void)
-+{
-+ printk("bt869.o version %s (%s)\n", LM_VERSION, LM_DATE);
-+ return i2c_add_driver(&bt869_driver);
-+}
-+
-+static void __exit sm_bt869_exit(void)
-+{
-+ i2c_del_driver(&bt869_driver);
-+}
-+
-+
-+
-+MODULE_AUTHOR
-+ ("Frodo Looijaard <frodol@dds.nl>, Philip Edelbrock <phil@netroedge.com>, Stephen Davies <steve@daviesfam.org>");
-+MODULE_DESCRIPTION("bt869 driver");
-+
-+module_init(sm_bt869_init);
-+module_exit(sm_bt869_exit);
---- linux-old/drivers/sensors/ddcmon.c Thu Jan 1 00:00:00 1970
-+++ linux/drivers/sensors/ddcmon.c Mon Dec 13 20:18:45 2004
-@@ -0,0 +1,591 @@
-+/*
-+ ddcmon.c - Part of lm_sensors, Linux kernel modules for hardware
-+ monitoring
-+ Copyright (c) 1998, 1999, 2000 Frodo Looijaard <frodol@dds.nl>,
-+ Philip Edelbrock <phil@netroedge.com>,
-+ and Mark Studebaker <mdsxyz123@yahoo.com>
-+ Copyright (c) 2003 Jean Delvare <khali@linux-fr.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., 675 Mass Ave, Cambridge, MA 02139, USA.
-+*/
-+
-+#include <linux/module.h>
-+#include <linux/slab.h>
-+#include <linux/i2c.h>
-+#include <linux/i2c-proc.h>
-+#include <linux/init.h>
-+#define LM_DATE "20041007"
-+#define LM_VERSION "2.8.8"
-+
-+MODULE_LICENSE("GPL");
-+
-+/* Addresses to scan */
-+static unsigned short normal_i2c[] = { 0x50, SENSORS_I2C_END };
-+static unsigned short normal_i2c_range[] = { SENSORS_I2C_END };
-+static unsigned int normal_isa[] = { SENSORS_ISA_END };
-+static unsigned int normal_isa_range[] = { SENSORS_ISA_END };
-+
-+/* Insmod parameters */
-+SENSORS_INSMOD_1(ddcmon);
-+
-+static int checksum = 0;
-+MODULE_PARM(checksum, "i");
-+MODULE_PARM_DESC(checksum, "Only accept eeproms whose checksum is correct");
-+
-+/* Many constants specified below */
-+
-+/* DDCMON registers */
-+/* vendor section */
-+#define DDCMON_REG_MAN_ID 0x08
-+#define DDCMON_REG_PROD_ID 0x0A
-+#define DDCMON_REG_SERIAL 0x0C
-+#define DDCMON_REG_WEEK 0x10
-+#define DDCMON_REG_YEAR 0x11
-+/* EDID version */
-+#define DDCMON_REG_EDID_VER 0x12
-+#define DDCMON_REG_EDID_REV 0x13
-+/* display information */
-+#define DDCMON_REG_HORSIZE 0x15
-+#define DDCMON_REG_VERSIZE 0x16
-+#define DDCMON_REG_GAMMA 0x17
-+#define DDCMON_REG_DPMS_FLAGS 0x18
-+/* supported timings */
-+#define DDCMON_REG_ESTABLISHED_TIMINGS 0x23
-+#define DDCMON_REG_STANDARD_TIMINGS 0x26
-+#define DDCMON_REG_TIMBASE 0x36
-+#define DDCMON_REG_TIMINCR 18
-+#define DDCMON_REG_TIMNUM 4
-+
-+#define DDCMON_REG_CHECKSUM 0x7f
-+
-+/* Size of DDCMON in bytes */
-+#define DDCMON_SIZE 128
-+
-+/* Each client has this additional data */
-+struct ddcmon_data {
-+ struct i2c_client client;
-+ int sysctl_id;
-+
-+ struct semaphore update_lock;
-+ char valid; /* !=0 if following fields are valid */
-+ unsigned long last_updated; /* In jiffies */
-+
-+ u8 data[DDCMON_SIZE]; /* Register values */
-+};
-+
-+
-+static int ddcmon_attach_adapter(struct i2c_adapter *adapter);
-+static int ddcmon_detect(struct i2c_adapter *adapter, int address,
-+ unsigned short flags, int kind);
-+static int ddcmon_detach_client(struct i2c_client *client);
-+
-+static void ddcmon_idcall(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void ddcmon_size(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void ddcmon_sync(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void ddcmon_maxclock(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void ddcmon_timings(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void ddcmon_serial(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void ddcmon_time(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void ddcmon_edid(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void ddcmon_gamma(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void ddcmon_dpms(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void ddcmon_standard_timing(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void ddcmon_update_client(struct i2c_client *client);
-+
-+
-+/* This is the driver that will be inserted */
-+static struct i2c_driver ddcmon_driver = {
-+ .owner = THIS_MODULE,
-+ .name = "DDCMON READER",
-+ .id = I2C_DRIVERID_DDCMON,
-+ .flags = I2C_DF_NOTIFY,
-+ .attach_adapter = ddcmon_attach_adapter,
-+ .detach_client = ddcmon_detach_client,
-+};
-+
-+/* -- SENSORS SYSCTL START -- */
-+
-+#define DDCMON_SYSCTL_ID 1010
-+#define DDCMON_SYSCTL_SIZE 1011
-+#define DDCMON_SYSCTL_SYNC 1012
-+#define DDCMON_SYSCTL_TIMINGS 1013
-+#define DDCMON_SYSCTL_SERIAL 1014
-+#define DDCMON_SYSCTL_TIME 1015
-+#define DDCMON_SYSCTL_EDID 1016
-+#define DDCMON_SYSCTL_GAMMA 1017
-+#define DDCMON_SYSCTL_DPMS 1018
-+#define DDCMON_SYSCTL_TIMING1 1021
-+#define DDCMON_SYSCTL_TIMING2 1022
-+#define DDCMON_SYSCTL_TIMING3 1023
-+#define DDCMON_SYSCTL_TIMING4 1024
-+#define DDCMON_SYSCTL_TIMING5 1025
-+#define DDCMON_SYSCTL_TIMING6 1026
-+#define DDCMON_SYSCTL_TIMING7 1027
-+#define DDCMON_SYSCTL_TIMING8 1028
-+#define DDCMON_SYSCTL_MAXCLOCK 1029
-+
-+/* -- SENSORS SYSCTL END -- */
-+
-+/* These files are created for each detected DDCMON. This is just a template;
-+ though at first sight, you might think we could use a statically
-+ allocated list, we need some way to get back to the parent - which
-+ is done through one of the 'extra' fields which are initialized
-+ when a new copy is allocated. */
-+static ctl_table ddcmon_dir_table_template[] = {
-+ {DDCMON_SYSCTL_ID, "id", NULL, 0, 0444, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &ddcmon_idcall},
-+ {DDCMON_SYSCTL_SIZE, "size", NULL, 0, 0444, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &ddcmon_size},
-+ {DDCMON_SYSCTL_SYNC, "sync", NULL, 0, 0444, NULL,
-+ &i2c_proc_real, &i2c_sysctl_real, NULL, &ddcmon_sync},
-+ {DDCMON_SYSCTL_TIMINGS, "timings", NULL, 0, 0444, NULL,
-+ &i2c_proc_real, &i2c_sysctl_real, NULL, &ddcmon_timings},
-+ {DDCMON_SYSCTL_SERIAL, "serial", NULL, 0, 0444, NULL,
-+ &i2c_proc_real, &i2c_sysctl_real, NULL, &ddcmon_serial},
-+ {DDCMON_SYSCTL_TIME, "time", NULL, 0, 0444, NULL,
-+ &i2c_proc_real, &i2c_sysctl_real, NULL, &ddcmon_time},
-+ {DDCMON_SYSCTL_EDID, "edid", NULL, 0, 0444, NULL,
-+ &i2c_proc_real, &i2c_sysctl_real, NULL, &ddcmon_edid},
-+ {DDCMON_SYSCTL_GAMMA, "gamma", NULL, 0, 0444, NULL,
-+ &i2c_proc_real, &i2c_sysctl_real, NULL, &ddcmon_gamma},
-+ {DDCMON_SYSCTL_DPMS, "dpms", NULL, 0, 0444, NULL,
-+ &i2c_proc_real, &i2c_sysctl_real, NULL, &ddcmon_dpms},
-+ {DDCMON_SYSCTL_TIMING1, "timing1", NULL, 0, 0444, NULL,
-+ &i2c_proc_real, &i2c_sysctl_real, NULL, &ddcmon_standard_timing},
-+ {DDCMON_SYSCTL_TIMING2, "timing2", NULL, 0, 0444, NULL,
-+ &i2c_proc_real, &i2c_sysctl_real, NULL, &ddcmon_standard_timing},
-+ {DDCMON_SYSCTL_TIMING3, "timing3", NULL, 0, 0444, NULL,
-+ &i2c_proc_real, &i2c_sysctl_real, NULL, &ddcmon_standard_timing},
-+ {DDCMON_SYSCTL_TIMING4, "timing4", NULL, 0, 0444, NULL,
-+ &i2c_proc_real, &i2c_sysctl_real, NULL, &ddcmon_standard_timing},
-+ {DDCMON_SYSCTL_TIMING5, "timing5", NULL, 0, 0444, NULL,
-+ &i2c_proc_real, &i2c_sysctl_real, NULL, &ddcmon_standard_timing},
-+ {DDCMON_SYSCTL_TIMING6, "timing6", NULL, 0, 0444, NULL,
-+ &i2c_proc_real, &i2c_sysctl_real, NULL, &ddcmon_standard_timing},
-+ {DDCMON_SYSCTL_TIMING7, "timing7", NULL, 0, 0444, NULL,
-+ &i2c_proc_real, &i2c_sysctl_real, NULL, &ddcmon_standard_timing},
-+ {DDCMON_SYSCTL_TIMING8, "timing8", NULL, 0, 0444, NULL,
-+ &i2c_proc_real, &i2c_sysctl_real, NULL, &ddcmon_standard_timing},
-+ {DDCMON_SYSCTL_MAXCLOCK, "maxclock", NULL, 0, 0444, NULL,
-+ &i2c_proc_real, &i2c_sysctl_real, NULL, &ddcmon_maxclock},
-+ {0}
-+};
-+
-+static int ddcmon_id = 0;
-+
-+static int ddcmon_attach_adapter(struct i2c_adapter *adapter)
-+{
-+ return i2c_detect(adapter, &addr_data, ddcmon_detect);
-+}
-+
-+/* This function is called by i2c_detect */
-+int ddcmon_detect(struct i2c_adapter *adapter, int address,
-+ unsigned short flags, int kind)
-+{
-+ int i, cs;
-+ struct i2c_client *new_client;
-+ struct ddcmon_data *data;
-+ int err = 0;
-+ const char *type_name, *client_name;
-+
-+ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
-+ goto ERROR0;
-+
-+ /* OK. For now, we presume we have a valid client. We now create the
-+ client structure, even though we cannot fill it completely yet.
-+ But it allows us to access ddcmon_{read,write}_value. */
-+ if (!(data = kmalloc(sizeof(struct ddcmon_data), GFP_KERNEL))) {
-+ err = -ENOMEM;
-+ goto ERROR0;
-+ }
-+
-+ new_client = &data->client;
-+ memset(data->data, 0xff, DDCMON_SIZE);
-+ new_client->addr = address;
-+ new_client->data = data;
-+ new_client->adapter = adapter;
-+ new_client->driver = &ddcmon_driver;
-+ new_client->flags = 0;
-+
-+ /* prevent 24RF08 corruption (just in case) */
-+ i2c_smbus_write_quick(new_client, 0);
-+
-+ /* Now, we do the remaining detection. */
-+ if (checksum) {
-+ int cs = 0;
-+ for (i = 0; i < 0x80; i++)
-+ cs += i2c_smbus_read_byte_data(new_client, i);
-+ if ((cs & 0xff) != 0)
-+ goto ERROR1;
-+ }
-+
-+ /* Verify the first 8 locations 0x00FFFFFFFFFFFF00 */
-+ /* Allow force and force_ddcmon arguments */
-+ if(kind < 0)
-+ {
-+ for(i = 0; i < 8; i++) {
-+ cs = i2c_smbus_read_byte_data(new_client, i);
-+ if(i == 0 || i == 7) {
-+ if(cs != 0)
-+ goto ERROR1;
-+ } else if(cs != 0xff)
-+ goto ERROR1;
-+ }
-+ }
-+
-+ type_name = "ddcmon";
-+ client_name = "DDC Monitor";
-+
-+ /* Fill in the remaining client fields and put it in the global list */
-+ strcpy(new_client->name, client_name);
-+
-+ new_client->id = ddcmon_id++;
-+ data->valid = 0;
-+ init_MUTEX(&data->update_lock);
-+
-+ /* Tell the I2C layer a new client has arrived */
-+ if ((err = i2c_attach_client(new_client)))
-+ goto ERROR3;
-+
-+ /* Register a new directory entry with module sensors */
-+ if ((i = i2c_register_entry(new_client, type_name,
-+ ddcmon_dir_table_template)) < 0) {
-+ err = i;
-+ goto ERROR4;
-+ }
-+ data->sysctl_id = i;
-+
-+ return 0;
-+
-+ ERROR4:
-+ i2c_detach_client(new_client);
-+ ERROR3:
-+ ERROR1:
-+ kfree(data);
-+ ERROR0:
-+ return err;
-+}
-+
-+static int ddcmon_detach_client(struct i2c_client *client)
-+{
-+ int err;
-+
-+ i2c_deregister_entry(((struct ddcmon_data *) (client->data))->
-+ sysctl_id);
-+ if ((err = i2c_detach_client(client))) {
-+ printk
-+ ("ddcmon.o: Client deregistration failed, client not detached.\n");
-+ return err;
-+ }
-+ kfree(client->data);
-+ return 0;
-+}
-+
-+static void ddcmon_update_client(struct i2c_client *client)
-+{
-+ struct ddcmon_data *data = client->data;
-+ int i, j;
-+
-+ down(&data->update_lock);
-+
-+ if ((jiffies - data->last_updated > 300 * HZ) ||
-+ (jiffies < data->last_updated) || !data->valid) {
-+ if (i2c_check_functionality(client->adapter,
-+ I2C_FUNC_SMBUS_READ_I2C_BLOCK))
-+ {
-+ for (i=0; i<DDCMON_SIZE; i+=I2C_SMBUS_I2C_BLOCK_MAX)
-+ if (i2c_smbus_read_i2c_block_data(client,
-+ i, data->data + i)
-+ != I2C_SMBUS_I2C_BLOCK_MAX) {
-+ printk(KERN_WARNING "ddcmon.o: block read fail at 0x%.2x!\n", i);
-+ goto DONE;
-+ }
-+ } else {
-+ if (i2c_smbus_write_byte(client, 0)) {
-+ printk(KERN_WARNING "ddcmon.o: read start fail at 0!\n");
-+ goto DONE;
-+ }
-+ for (i = 0; i < DDCMON_SIZE; i++) {
-+ j = i2c_smbus_read_byte(client);
-+ if (j < 0) {
-+ printk(KERN_WARNING "eeprom.o: read fail at 0x%.2x!\n", i);
-+ goto DONE;
-+ }
-+ data->data[i] = (u8) j;
-+ }
-+ }
-+ data->last_updated = jiffies;
-+ data->valid = 1;
-+ }
-+DONE:
-+ up(&data->update_lock);
-+}
-+
-+
-+void ddcmon_idcall(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results)
-+{
-+ struct ddcmon_data *data = client->data;
-+
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 0;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ ddcmon_update_client(client);
-+ results[0] = data->data[DDCMON_REG_MAN_ID + 1] |
-+ (data->data[DDCMON_REG_MAN_ID] << 8);
-+ results[1] = data->data[DDCMON_REG_PROD_ID + 1] |
-+ (data->data[DDCMON_REG_PROD_ID] << 8);
-+ *nrels_mag = 2;
-+ }
-+}
-+
-+void ddcmon_size(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results)
-+{
-+ struct ddcmon_data *data = client->data;
-+
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 0;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ ddcmon_update_client(client);
-+ results[0] = data->data[DDCMON_REG_VERSIZE];
-+ results[1] = data->data[DDCMON_REG_HORSIZE];
-+ *nrels_mag = 2;
-+ }
-+}
-+
-+void ddcmon_sync(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results)
-+{
-+ int i, j;
-+ struct ddcmon_data *data = client->data;
-+
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 0;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ ddcmon_update_client(client);
-+ *nrels_mag = 4;
-+ /* look for monitor limits entry */
-+ for(i = DDCMON_REG_TIMBASE;
-+ i < DDCMON_REG_TIMBASE +
-+ (DDCMON_REG_TIMNUM * DDCMON_REG_TIMINCR);
-+ i += DDCMON_REG_TIMINCR) {
-+ if (data->data[i] == 0x00
-+ && data->data[i + 1] == 0x00
-+ && data->data[i + 2] == 0x00
-+ && data->data[i + 3] == 0xfd) {
-+ for(j = 0; j < 4; j++)
-+ results[j] = data->data[i + j + 5];
-+ return;
-+ }
-+ }
-+ for(j = 0; j < 4; j++)
-+ results[j] = 0;
-+ }
-+}
-+
-+void ddcmon_maxclock(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results)
-+{
-+ int i;
-+ struct ddcmon_data *data = client->data;
-+
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 0;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ ddcmon_update_client(client);
-+ *nrels_mag = 1;
-+ /* look for monitor limits entry */
-+ for(i = DDCMON_REG_TIMBASE;
-+ i < DDCMON_REG_TIMBASE +
-+ (DDCMON_REG_TIMNUM * DDCMON_REG_TIMINCR);
-+ i += DDCMON_REG_TIMINCR) {
-+ if (data->data[i] == 0x00
-+ && data->data[i + 1] == 0x00
-+ && data->data[i + 2] == 0x00
-+ && data->data[i + 3] == 0xfd) {
-+ results[0] = (data->data[i + 9] == 0xff ?
-+ 0 : data->data[i + 9] * 10);
-+ return;
-+ }
-+ }
-+ results[0] = 0;
-+ }
-+}
-+
-+void ddcmon_timings(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results)
-+{
-+ struct ddcmon_data *data = client->data;
-+
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 0;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ ddcmon_update_client(client);
-+ results[0] = data->data[DDCMON_REG_ESTABLISHED_TIMINGS] |
-+ (data->data[DDCMON_REG_ESTABLISHED_TIMINGS + 1] << 8) |
-+ (data->data[DDCMON_REG_ESTABLISHED_TIMINGS + 2] << 16);
-+ *nrels_mag = 1;
-+ }
-+}
-+
-+void ddcmon_serial(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results)
-+{
-+ struct ddcmon_data *data = client->data;
-+
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 0;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ ddcmon_update_client(client);
-+ results[0] = data->data[DDCMON_REG_SERIAL] |
-+ (data->data[DDCMON_REG_SERIAL + 1] << 8) |
-+ (data->data[DDCMON_REG_SERIAL + 2] << 16) |
-+ (data->data[DDCMON_REG_SERIAL + 3] << 24);
-+ *nrels_mag = 1;
-+ }
-+}
-+
-+void ddcmon_time(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results)
-+{
-+ struct ddcmon_data *data = client->data;
-+
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 0;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ ddcmon_update_client(client);
-+ results[0] = data->data[DDCMON_REG_YEAR] + 1990;
-+ results[1] = data->data[DDCMON_REG_WEEK];
-+ *nrels_mag = 2;
-+ }
-+}
-+
-+void ddcmon_edid(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results)
-+{
-+ struct ddcmon_data *data = client->data;
-+
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 0;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ ddcmon_update_client(client);
-+ results[0] = data->data[DDCMON_REG_EDID_VER];
-+ results[1] = data->data[DDCMON_REG_EDID_REV];
-+ *nrels_mag = 2;
-+ }
-+}
-+
-+void ddcmon_gamma(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results)
-+{
-+ struct ddcmon_data *data = client->data;
-+
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 2;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ ddcmon_update_client(client);
-+ results[0] = 100 + data->data[DDCMON_REG_GAMMA];
-+ *nrels_mag = 1;
-+ }
-+}
-+
-+void ddcmon_dpms(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results)
-+{
-+ struct ddcmon_data *data = client->data;
-+
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 0;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ ddcmon_update_client(client);
-+ results[0] = data->data[DDCMON_REG_DPMS_FLAGS];
-+ *nrels_mag = 1;
-+ }
-+}
-+
-+void ddcmon_standard_timing(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results)
-+{
-+ struct ddcmon_data *data = client->data;
-+ int nr = ctl_name - DDCMON_SYSCTL_TIMING1;
-+
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 0;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ ddcmon_update_client(client);
-+ /* If both bytes of the timing are 0x00 or 0x01, then the timing
-+ slot is unused. */
-+ if ((data->data[DDCMON_REG_STANDARD_TIMINGS + nr * 2]
-+ | data->data[DDCMON_REG_STANDARD_TIMINGS + nr * 2 + 1]) & 0xfe) {
-+ results[0] = (data->data[DDCMON_REG_STANDARD_TIMINGS + nr * 2] + 31) * 8;
-+ switch (data->data[DDCMON_REG_STANDARD_TIMINGS + nr * 2 + 1] >> 6) {
-+ /* We don't care about rounding issues there, it really
-+ should be OK without it. */
-+ case 0x00:
-+ results[1] = results[0]; /* unconfirmed */
-+ break;
-+ case 0x01:
-+ results[1] = results[0] * 3 / 4;
-+ break;
-+ case 0x02:
-+ results[1] = results[0] * 4 / 5;
-+ break;
-+ case 0x03:
-+ results[1] = results[0] * 9 / 16;
-+ break;
-+ }
-+ results[2] = (data->data[DDCMON_REG_STANDARD_TIMINGS + nr * 2 + 1] & 0x3f) + 60;
-+ } else {
-+ results[0] = 0;
-+ results[1] = 0;
-+ results[2] = 0;
-+ }
-+ *nrels_mag = 3;
-+ }
-+}
-+
-+static int __init sm_ddcmon_init(void)
-+{
-+ printk("ddcmon.o version %s (%s)\n", LM_VERSION, LM_DATE);
-+ return i2c_add_driver(&ddcmon_driver);
-+}
-+
-+static void __exit sm_ddcmon_exit(void)
-+{
-+ i2c_del_driver(&ddcmon_driver);
-+}
-+
-+
-+
-+MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl>, "
-+ "Philip Edelbrock <phil@netroedge.com>, "
-+ "Mark Studebaker <mdsxyz123@yahoo.com> "
-+ "and Jean Delvare <khali@linux-fr.org>");
-+MODULE_DESCRIPTION("DDCMON driver");
-+
-+module_init(sm_ddcmon_init);
-+module_exit(sm_ddcmon_exit);
---- linux-old/drivers/sensors/ds1621.c Thu Jan 1 00:00:00 1970
-+++ linux/drivers/sensors/ds1621.c Mon Dec 13 20:18:45 2004
-@@ -0,0 +1,528 @@
-+/*
-+ ds1621.c - Part of lm_sensors, Linux kernel modules for hardware
-+ monitoring
-+ Christian W. Zuckschwerdt <zany@triq.net> 2000-11-23
-+ based on lm75.c by Frodo Looijaard <frodol@dds.nl>
-+
-+ 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., 675 Mass Ave, Cambridge, MA 02139, USA.
-+*/
-+
-+/* Supports DS1621. See doc/chips/ds1621 for details */
-+
-+#include <linux/module.h>
-+#include <linux/slab.h>
-+#include <linux/i2c.h>
-+#include <linux/i2c-proc.h>
-+#include <linux/init.h>
-+#define LM_DATE "20041007"
-+#define LM_VERSION "2.8.8"
-+
-+MODULE_LICENSE("GPL");
-+
-+/* Addresses to scan */
-+static unsigned short normal_i2c[] = { SENSORS_I2C_END };
-+static unsigned short normal_i2c_range[] = { 0x48, 0x4f, SENSORS_I2C_END };
-+static unsigned int normal_isa[] = { SENSORS_ISA_END };
-+static unsigned int normal_isa_range[] = { SENSORS_ISA_END };
-+
-+/* Insmod parameters */
-+SENSORS_INSMOD_1(ds1621);
-+
-+/* Many DS1621 constants specified below */
-+
-+/* Config register used for detection */
-+/* 7 6 5 4 3 2 1 0 */
-+/* |Done|THF |TLF |NVB | 1 | 0 |POL |1SHOT| */
-+#define DS1621_REG_CONFIG_MASK 0x0C
-+#define DS1621_REG_CONFIG_VAL 0x08
-+#define DS1621_REG_CONFIG_POLARITY 0x02
-+#define DS1621_REG_CONFIG_1SHOT 0x01
-+#define DS1621_REG_CONFIG_DONE 0x80
-+
-+/* Note: the done bit is always unset if continuous conversion is in progress.
-+ We need to stop the continuous conversion or switch to single shot
-+ before this bit becomes available!
-+ */
-+
-+/* The DS1621 registers */
-+#define DS1621_REG_TEMP 0xAA /* word, RO */
-+#define DS1621_REG_TEMP_OVER 0xA1 /* word, RW */
-+#define DS1621_REG_TEMP_HYST 0xA2 /* word, RW -- it's a low temp trigger */
-+#define DS1621_REG_CONF 0xAC /* byte, RW */
-+#define DS1621_REG_TEMP_COUNTER 0xA8 /* byte, RO */
-+#define DS1621_REG_TEMP_SLOPE 0xA9 /* byte, RO */
-+#define DS1621_COM_START 0xEE /* no data */
-+#define DS1621_COM_STOP 0x22 /* no data */
-+
-+/* Conversions. Rounding and limit checking is only done on the TO_REG
-+ variants. Note that you should be a bit careful with which arguments
-+ these macros are called: arguments may be evaluated more than once.
-+ Fixing this is just not worth it. */
-+#define TEMP_FROM_REG(val) ((((val & 0x7fff) >> 7) * 5) | \
-+ ((val & 0x8000)?-256:0))
-+#define TEMP_TO_REG(val) (SENSORS_LIMIT((val<0 ? (0x200+((val)/5))<<7 : \
-+ (((val) + 2) / 5) << 7),0,0xffff))
-+#define ALARMS_FROM_REG(val) ((val) & \
-+ (DS1621_ALARM_TEMP_HIGH | DS1621_ALARM_TEMP_LOW))
-+#define ITEMP_FROM_REG(val) ((((val & 0x7fff) >> 8)) | \
-+ ((val & 0x8000)?-256:0))
-+
-+/* Each client has this additional data */
-+struct ds1621_data {
-+ struct i2c_client client;
-+ int sysctl_id;
-+
-+ struct semaphore update_lock;
-+ char valid; /* !=0 if following fields are valid */
-+ unsigned long last_updated; /* In jiffies */
-+
-+ u16 temp, temp_over, temp_hyst; /* Register values, word */
-+ u8 conf; /* Register encoding, combined */
-+
-+ char enable; /* !=0 if we're expected to restart the conversion */
-+ u8 temp_int, temp_counter, temp_slope; /* Register values, byte */
-+};
-+
-+static int ds1621_attach_adapter(struct i2c_adapter *adapter);
-+static int ds1621_detect(struct i2c_adapter *adapter, int address,
-+ unsigned short flags, int kind);
-+static void ds1621_init_client(struct i2c_client *client);
-+static int ds1621_detach_client(struct i2c_client *client);
-+
-+static int ds1621_read_value(struct i2c_client *client, u8 reg);
-+static int ds1621_write_value(struct i2c_client *client, u8 reg, u16 value);
-+static void ds1621_temp(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void ds1621_alarms(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void ds1621_enable(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void ds1621_continuous(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void ds1621_polarity(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void ds1621_update_client(struct i2c_client *client);
-+
-+
-+/* This is the driver that will be inserted */
-+static struct i2c_driver ds1621_driver = {
-+ .owner = THIS_MODULE,
-+ .name = "DS1621 sensor driver",
-+ .id = I2C_DRIVERID_DS1621,
-+ .flags = I2C_DF_NOTIFY,
-+ .attach_adapter = ds1621_attach_adapter,
-+ .detach_client = ds1621_detach_client,
-+};
-+
-+/* -- SENSORS SYSCTL START -- */
-+#define DS1621_SYSCTL_TEMP 1200 /* Degrees Celcius * 10 */
-+#define DS1621_SYSCTL_ALARMS 2001 /* bitvector */
-+#define DS1621_ALARM_TEMP_HIGH 0x40
-+#define DS1621_ALARM_TEMP_LOW 0x20
-+#define DS1621_SYSCTL_ENABLE 2002
-+#define DS1621_SYSCTL_CONTINUOUS 2003
-+#define DS1621_SYSCTL_POLARITY 2004
-+
-+/* -- SENSORS SYSCTL END -- */
-+
-+/* These files are created for each detected DS1621. This is just a template;
-+ though at first sight, you might think we could use a statically
-+ allocated list, we need some way to get back to the parent - which
-+ is done through one of the 'extra' fields which are initialized
-+ when a new copy is allocated. */
-+static ctl_table ds1621_dir_table_template[] = {
-+ {DS1621_SYSCTL_TEMP, "temp", NULL, 0, 0644, NULL,
-+ &i2c_proc_real, &i2c_sysctl_real, NULL, &ds1621_temp},
-+ {DS1621_SYSCTL_ALARMS, "alarms", NULL, 0, 0444, NULL,
-+ &i2c_proc_real, &i2c_sysctl_real, NULL, &ds1621_alarms},
-+ {DS1621_SYSCTL_ENABLE, "enable", NULL, 0, 0644, NULL,
-+ &i2c_proc_real, &i2c_sysctl_real, NULL, &ds1621_enable},
-+ {DS1621_SYSCTL_CONTINUOUS, "continuous", NULL, 0, 0644, NULL,
-+ &i2c_proc_real, &i2c_sysctl_real, NULL, &ds1621_continuous},
-+ {DS1621_SYSCTL_POLARITY, "polarity", NULL, 0, 0644, NULL,
-+ &i2c_proc_real, &i2c_sysctl_real, NULL, &ds1621_polarity},
-+ {0}
-+};
-+
-+static int ds1621_id = 0;
-+
-+static int ds1621_attach_adapter(struct i2c_adapter *adapter)
-+{
-+ return i2c_detect(adapter, &addr_data, ds1621_detect);
-+}
-+
-+/* This function is called by i2c_detect */
-+int ds1621_detect(struct i2c_adapter *adapter, int address,
-+ unsigned short flags, int kind)
-+{
-+ int i, conf;
-+ struct i2c_client *new_client;
-+ struct ds1621_data *data;
-+ int err = 0;
-+ const char *type_name, *client_name;
-+
-+ /* Make sure we aren't probing the ISA bus!! This is just a safety check
-+ at this moment; i2c_detect really won't call us. */
-+#ifdef DEBUG
-+ if (i2c_is_isa_adapter(adapter)) {
-+ printk
-+ ("ds1621.o: ds1621_detect called for an ISA bus adapter?!?\n");
-+ return 0;
-+ }
-+#endif
-+
-+ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA |
-+ I2C_FUNC_SMBUS_WORD_DATA |
-+ I2C_FUNC_SMBUS_WRITE_BYTE))
-+ goto ERROR0;
-+
-+ /* OK. For now, we presume we have a valid client. We now create the
-+ client structure, even though we cannot fill it completely yet.
-+ But it allows us to access ds1621_{read,write}_value. */
-+ if (!(data = kmalloc(sizeof(struct ds1621_data), GFP_KERNEL))) {
-+ err = -ENOMEM;
-+ goto ERROR0;
-+ }
-+
-+ new_client = &data->client;
-+ new_client->addr = address;
-+ new_client->data = data;
-+ new_client->adapter = adapter;
-+ new_client->driver = &ds1621_driver;
-+ new_client->flags = 0;
-+
-+ /* Now, we do the remaining detection. It is lousy. */
-+ if (kind < 0) {
-+ conf = i2c_smbus_read_byte_data(new_client,
-+ DS1621_REG_CONF);
-+ if ((conf & DS1621_REG_CONFIG_MASK)
-+ != DS1621_REG_CONFIG_VAL)
-+ goto ERROR1;
-+ }
-+
-+ /* Determine the chip type - only one kind supported! */
-+ if (kind <= 0)
-+ kind = ds1621;
-+
-+ if (kind == ds1621) {
-+ type_name = "ds1621";
-+ client_name = "DS1621 chip";
-+ } else {
-+#ifdef DEBUG
-+ printk("ds1621.o: Internal error: unknown kind (%d)?!?",
-+ kind);
-+#endif
-+ goto ERROR1;
-+ }
-+
-+ /* Fill in remaining client fields and put it into the global list */
-+ strcpy(new_client->name, client_name);
-+
-+ new_client->id = ds1621_id++;
-+ data->valid = 0;
-+ init_MUTEX(&data->update_lock);
-+
-+ /* Tell the I2C layer a new client has arrived */
-+ if ((err = i2c_attach_client(new_client)))
-+ goto ERROR3;
-+
-+ /* Register a new directory entry with module sensors */
-+ if ((i = i2c_register_entry(new_client, type_name,
-+ ds1621_dir_table_template)) < 0) {
-+ err = i;
-+ goto ERROR4;
-+ }
-+ data->sysctl_id = i;
-+
-+ ds1621_init_client(new_client);
-+ return 0;
-+
-+/* OK, this is not exactly good programming practice, usually. But it is
-+ very code-efficient in this case. */
-+
-+ ERROR4:
-+ i2c_detach_client(new_client);
-+ ERROR3:
-+ ERROR1:
-+ kfree(data);
-+ ERROR0:
-+ return err;
-+}
-+
-+static int ds1621_detach_client(struct i2c_client *client)
-+{
-+ int err;
-+
-+ i2c_deregister_entry(((struct ds1621_data *) (client->data))->
-+ sysctl_id);
-+
-+ if ((err = i2c_detach_client(client))) {
-+ printk
-+ ("ds1621.o: Client deregistration failed, client not detached.\n");
-+ return err;
-+ }
-+
-+ kfree(client->data);
-+
-+ return 0;
-+}
-+
-+
-+/* All registers are word-sized, except for the configuration register.
-+ DS1621 uses a high-byte first convention, which is exactly opposite to
-+ the usual practice. */
-+static int ds1621_read_value(struct i2c_client *client, u8 reg)
-+{
-+ if ((reg == DS1621_REG_CONF) || (reg == DS1621_REG_TEMP_COUNTER)
-+ || (reg == DS1621_REG_TEMP_SLOPE))
-+ return i2c_smbus_read_byte_data(client, reg);
-+ else
-+ return swab16(i2c_smbus_read_word_data(client, reg));
-+}
-+
-+/* All registers are word-sized, except for the configuration register.
-+ DS1621 uses a high-byte first convention, which is exactly opposite to
-+ the usual practice. */
-+static int ds1621_write_value(struct i2c_client *client, u8 reg, u16 value)
-+{
-+ if ( (reg == DS1621_COM_START) || (reg == DS1621_COM_STOP) )
-+ return i2c_smbus_write_byte(client, reg);
-+ else
-+ if ((reg == DS1621_REG_CONF) || (reg == DS1621_REG_TEMP_COUNTER)
-+ || (reg == DS1621_REG_TEMP_SLOPE))
-+ return i2c_smbus_write_byte_data(client, reg, value);
-+ else
-+ return i2c_smbus_write_word_data(client, reg, swab16(value));
-+}
-+
-+static void ds1621_init_client(struct i2c_client *client)
-+{
-+ int reg;
-+
-+ reg = ds1621_read_value(client, DS1621_REG_CONF);
-+ /* start the continous conversion */
-+ if(reg & 0x01)
-+ ds1621_write_value(client, DS1621_REG_CONF, reg & 0xfe);
-+}
-+
-+static void ds1621_update_client(struct i2c_client *client)
-+{
-+ struct ds1621_data *data = client->data;
-+ u8 new_conf;
-+
-+ down(&data->update_lock);
-+
-+ if ((jiffies - data->last_updated > HZ + HZ / 2) ||
-+ (jiffies < data->last_updated) || !data->valid) {
-+
-+#ifdef DEBUG
-+ printk("Starting ds1621 update\n");
-+#endif
-+
-+ data->conf = ds1621_read_value(client, DS1621_REG_CONF);
-+
-+ data->temp = ds1621_read_value(client,
-+ DS1621_REG_TEMP);
-+ data->temp_over = ds1621_read_value(client,
-+ DS1621_REG_TEMP_OVER);
-+ data->temp_hyst = ds1621_read_value(client,
-+ DS1621_REG_TEMP_HYST);
-+
-+ /* wait for the DONE bit before reading extended values */
-+
-+ if (data->conf & DS1621_REG_CONFIG_DONE) {
-+ data->temp_counter = ds1621_read_value(client,
-+ DS1621_REG_TEMP_COUNTER);
-+ data->temp_slope = ds1621_read_value(client,
-+ DS1621_REG_TEMP_SLOPE);
-+ data->temp_int = ITEMP_FROM_REG(data->temp);
-+ /* restart the conversion */
-+ if (data->enable)
-+ ds1621_write_value(client, DS1621_COM_START, 0);
-+ }
-+
-+ /* reset alarms if neccessary */
-+ new_conf = data->conf;
-+ if (data->temp < data->temp_over)
-+ new_conf &= ~DS1621_ALARM_TEMP_HIGH;
-+ if (data->temp > data->temp_hyst)
-+ new_conf &= ~DS1621_ALARM_TEMP_LOW;
-+ if (data->conf != new_conf)
-+ ds1621_write_value(client, DS1621_REG_CONF,
-+ new_conf);
-+
-+ data->last_updated = jiffies;
-+ data->valid = 1;
-+ }
-+
-+ up(&data->update_lock);
-+}
-+
-+
-+void ds1621_temp(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct ds1621_data *data = client->data;
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ if (!(data->conf & DS1621_REG_CONFIG_DONE) ||
-+ (data->temp_counter > data->temp_slope) ||
-+ (data->temp_slope == 0)) {
-+ *nrels_mag = 1;
-+ } else {
-+ *nrels_mag = 2;
-+ }
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ ds1621_update_client(client);
-+ /* decide wether to calculate more precise temp */
-+ if (!(data->conf & DS1621_REG_CONFIG_DONE) ||
-+ (data->temp_counter > data->temp_slope) ||
-+ (data->temp_slope == 0)) {
-+ results[0] = TEMP_FROM_REG(data->temp_over);
-+ results[1] = TEMP_FROM_REG(data->temp_hyst);
-+ results[2] = TEMP_FROM_REG(data->temp);
-+ } else {
-+ results[0] = TEMP_FROM_REG(data->temp_over)*10;
-+ results[1] = TEMP_FROM_REG(data->temp_hyst)*10;
-+ results[2] = data->temp_int * 100 - 25 +
-+ ((data->temp_slope - data->temp_counter) *
-+ 100 / data->temp_slope);
-+ }
-+ *nrels_mag = 3;
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ if (*nrels_mag >= 1) {
-+ data->temp_over = TEMP_TO_REG(results[0]);
-+ ds1621_write_value(client, DS1621_REG_TEMP_OVER,
-+ data->temp_over);
-+ }
-+ if (*nrels_mag >= 2) {
-+ data->temp_hyst = TEMP_TO_REG(results[1]);
-+ ds1621_write_value(client, DS1621_REG_TEMP_HYST,
-+ data->temp_hyst);
-+ }
-+ }
-+}
-+
-+void ds1621_alarms(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct ds1621_data *data = client->data;
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 0;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ ds1621_update_client(client);
-+ results[0] = ALARMS_FROM_REG(data->conf);
-+ *nrels_mag = 1;
-+ }
-+}
-+
-+void ds1621_enable(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ /* If you really screw up your chip (like I did) this is */
-+ /* sometimes needed to (re)start the continous conversion */
-+ /* there is no data to read so this might hang your SMBus! */
-+
-+ struct ds1621_data *data = client->data;
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 0;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ ds1621_update_client(client);
-+ results[0] = !(data->conf & DS1621_REG_CONFIG_DONE);
-+ *nrels_mag = 1;
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ if (*nrels_mag >= 1) {
-+ if (results[0]) {
-+ ds1621_write_value(client, DS1621_COM_START, 0);
-+ data->enable=1;
-+ } else {
-+ ds1621_write_value(client, DS1621_COM_STOP, 0);
-+ data->enable=0;
-+ }
-+ } else {
-+ ds1621_write_value(client, DS1621_COM_START, 0);
-+ data->enable=1;
-+ }
-+ }
-+}
-+
-+void ds1621_continuous(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct ds1621_data *data = client->data;
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 0;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ ds1621_update_client(client);
-+ results[0] = !(data->conf & DS1621_REG_CONFIG_1SHOT);
-+ *nrels_mag = 1;
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ ds1621_update_client(client);
-+ if (*nrels_mag >= 1) {
-+ if (results[0]) {
-+ ds1621_write_value(client, DS1621_REG_CONF,
-+ data->conf & ~DS1621_REG_CONFIG_1SHOT);
-+ } else {
-+ ds1621_write_value(client, DS1621_REG_CONF,
-+ data->conf | DS1621_REG_CONFIG_1SHOT);
-+ }
-+ } else {
-+ ds1621_write_value(client, DS1621_REG_CONF,
-+ data->conf & ~DS1621_REG_CONFIG_1SHOT);
-+ }
-+ }
-+}
-+
-+void ds1621_polarity(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct ds1621_data *data = client->data;
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 0;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ ds1621_update_client(client);
-+ results[0] = !(!(data->conf & DS1621_REG_CONFIG_POLARITY));
-+ *nrels_mag = 1;
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ ds1621_update_client(client);
-+ if (*nrels_mag >= 1) {
-+ if (results[0]) {
-+ ds1621_write_value(client, DS1621_REG_CONF,
-+ data->conf | DS1621_REG_CONFIG_POLARITY);
-+ } else {
-+ ds1621_write_value(client, DS1621_REG_CONF,
-+ data->conf & ~DS1621_REG_CONFIG_POLARITY);
-+ }
-+ }
-+ }
-+}
-+
-+static int __init sm_ds1621_init(void)
-+{
-+ printk("ds1621.o version %s (%s)\n", LM_VERSION, LM_DATE);
-+ return i2c_add_driver(&ds1621_driver);
-+}
-+
-+static void __exit sm_ds1621_exit(void)
-+{
-+ i2c_del_driver(&ds1621_driver);
-+}
-+
-+
-+
-+MODULE_AUTHOR("Christian W. Zuckschwerdt <zany@triq.net>");
-+MODULE_DESCRIPTION("DS1621 driver");
-+
-+module_init(sm_ds1621_init);
-+module_exit(sm_ds1621_exit);
---- linux-old/drivers/sensors/eeprom.c Thu Jan 1 00:00:00 1970
-+++ linux/drivers/sensors/eeprom.c Mon Dec 13 20:18:45 2004
-@@ -0,0 +1,418 @@
-+/*
-+ eeprom.c - Part of lm_sensors, Linux kernel modules for hardware
-+ monitoring
-+ Copyright (c) 1998, 1999 Frodo Looijaard <frodol@dds.nl> and
-+ Philip Edelbrock <phil@netroedge.com>
-+
-+ 2003-08-18 Jean Delvare <khali@linux-fr.org>
-+ Divide the eeprom in 2-row (arbitrary) slices. This significantly
-+ speeds sensors up, as well as various scripts using the eeprom
-+ module.
-+
-+ 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., 675 Mass Ave, Cambridge, MA 02139, USA.
-+*/
-+
-+#include <linux/module.h>
-+#include <linux/slab.h>
-+#include <linux/i2c.h>
-+#include <linux/i2c-proc.h>
-+#include <linux/init.h>
-+#include <linux/sched.h> /* for capable() */
-+#define LM_DATE "20041007"
-+#define LM_VERSION "2.8.8"
-+
-+MODULE_LICENSE("GPL");
-+
-+/* Addresses to scan */
-+static unsigned short normal_i2c[] = { SENSORS_I2C_END };
-+static unsigned short normal_i2c_range[] = { 0x50, 0x57, SENSORS_I2C_END };
-+static unsigned int normal_isa[] = { SENSORS_ISA_END };
-+static unsigned int normal_isa_range[] = { SENSORS_ISA_END };
-+
-+/* Insmod parameters */
-+SENSORS_INSMOD_1(eeprom);
-+
-+static int checksum = 0;
-+MODULE_PARM(checksum, "i");
-+MODULE_PARM_DESC(checksum,
-+ "Only accept eeproms whose checksum is correct");
-+
-+
-+/* Many constants specified below */
-+
-+/* EEPROM registers */
-+#define EEPROM_REG_CHECKSUM 0x3f
-+
-+/* possible natures */
-+#define NATURE_UNKNOWN 0
-+#define NATURE_VAIO 1
-+
-+/* Size of EEPROM in bytes */
-+#define EEPROM_SIZE 256
-+
-+/* Each client has this additional data */
-+struct eeprom_data {
-+ struct i2c_client client;
-+ int sysctl_id;
-+
-+ struct semaphore update_lock;
-+ u8 valid; /* bitfield, bit!=0 if slice is valid */
-+ unsigned long last_updated[8]; /* In jiffies, 8 slices */
-+
-+ u8 data[EEPROM_SIZE]; /* Register values */
-+ u8 nature;
-+};
-+
-+
-+static int eeprom_attach_adapter(struct i2c_adapter *adapter);
-+static int eeprom_detect(struct i2c_adapter *adapter, int address,
-+ unsigned short flags, int kind);
-+static int eeprom_detach_client(struct i2c_client *client);
-+
-+#if 0
-+static int eeprom_write_value(struct i2c_client *client, u8 reg,
-+ u8 value);
-+#endif
-+
-+static void eeprom_contents(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void eeprom_update_client(struct i2c_client *client, u8 slice);
-+
-+
-+/* This is the driver that will be inserted */
-+static struct i2c_driver eeprom_driver = {
-+ .owner = THIS_MODULE,
-+ .name = "EEPROM READER",
-+ .id = I2C_DRIVERID_EEPROM,
-+ .flags = I2C_DF_NOTIFY,
-+ .attach_adapter = eeprom_attach_adapter,
-+ .detach_client = eeprom_detach_client,
-+};
-+
-+/* -- SENSORS SYSCTL START -- */
-+
-+#define EEPROM_SYSCTL1 1000
-+#define EEPROM_SYSCTL2 1001
-+#define EEPROM_SYSCTL3 1002
-+#define EEPROM_SYSCTL4 1003
-+#define EEPROM_SYSCTL5 1004
-+#define EEPROM_SYSCTL6 1005
-+#define EEPROM_SYSCTL7 1006
-+#define EEPROM_SYSCTL8 1007
-+#define EEPROM_SYSCTL9 1008
-+#define EEPROM_SYSCTL10 1009
-+#define EEPROM_SYSCTL11 1010
-+#define EEPROM_SYSCTL12 1011
-+#define EEPROM_SYSCTL13 1012
-+#define EEPROM_SYSCTL14 1013
-+#define EEPROM_SYSCTL15 1014
-+#define EEPROM_SYSCTL16 1015
-+
-+/* -- SENSORS SYSCTL END -- */
-+
-+/* These files are created for each detected EEPROM. This is just a template;
-+ though at first sight, you might think we could use a statically
-+ allocated list, we need some way to get back to the parent - which
-+ is done through one of the 'extra' fields which are initialized
-+ when a new copy is allocated. */
-+static ctl_table eeprom_dir_table_template[] = {
-+ {EEPROM_SYSCTL1, "00", NULL, 0, 0444, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &eeprom_contents},
-+ {EEPROM_SYSCTL2, "10", NULL, 0, 0444, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &eeprom_contents},
-+ {EEPROM_SYSCTL3, "20", NULL, 0, 0444, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &eeprom_contents},
-+ {EEPROM_SYSCTL4, "30", NULL, 0, 0444, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &eeprom_contents},
-+ {EEPROM_SYSCTL5, "40", NULL, 0, 0444, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &eeprom_contents},
-+ {EEPROM_SYSCTL6, "50", NULL, 0, 0444, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &eeprom_contents},
-+ {EEPROM_SYSCTL7, "60", NULL, 0, 0444, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &eeprom_contents},
-+ {EEPROM_SYSCTL8, "70", NULL, 0, 0444, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &eeprom_contents},
-+ {EEPROM_SYSCTL9, "80", NULL, 0, 0444, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &eeprom_contents},
-+ {EEPROM_SYSCTL10, "90", NULL, 0, 0444, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &eeprom_contents},
-+ {EEPROM_SYSCTL11, "a0", NULL, 0, 0444, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &eeprom_contents},
-+ {EEPROM_SYSCTL12, "b0", NULL, 0, 0444, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &eeprom_contents},
-+ {EEPROM_SYSCTL13, "c0", NULL, 0, 0444, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &eeprom_contents},
-+ {EEPROM_SYSCTL14, "d0", NULL, 0, 0444, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &eeprom_contents},
-+ {EEPROM_SYSCTL15, "e0", NULL, 0, 0444, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &eeprom_contents},
-+ {EEPROM_SYSCTL16, "f0", NULL, 0, 0444, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &eeprom_contents},
-+ {0}
-+};
-+
-+static int eeprom_id = 0;
-+
-+static int eeprom_attach_adapter(struct i2c_adapter *adapter)
-+{
-+ return i2c_detect(adapter, &addr_data, eeprom_detect);
-+}
-+
-+/* This function is called by i2c_detect */
-+int eeprom_detect(struct i2c_adapter *adapter, int address,
-+ unsigned short flags, int kind)
-+{
-+ int i;
-+ struct i2c_client *new_client;
-+ struct eeprom_data *data;
-+ int err = 0;
-+ const char *type_name, *client_name;
-+
-+ /* Make sure we aren't probing the ISA bus!! This is just a safety check
-+ at this moment; i2c_detect really won't call us. */
-+#ifdef DEBUG
-+ if (i2c_is_isa_adapter(adapter)) {
-+ printk
-+ ("eeprom.o: eeprom_detect called for an ISA bus adapter?!?\n");
-+ return 0;
-+ }
-+#endif
-+
-+ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
-+ goto ERROR0;
-+
-+ /* OK. For now, we presume we have a valid client. We now create the
-+ client structure, even though we cannot fill it completely yet.
-+ But it allows us to access eeprom_{read,write}_value. */
-+ if (!(data = kmalloc(sizeof(struct eeprom_data), GFP_KERNEL))) {
-+ err = -ENOMEM;
-+ goto ERROR0;
-+ }
-+
-+ new_client = &data->client;
-+ memset(data->data, 0xff, EEPROM_SIZE);
-+ new_client->addr = address;
-+ new_client->data = data;
-+ new_client->adapter = adapter;
-+ new_client->driver = &eeprom_driver;
-+ new_client->flags = 0;
-+
-+ /* prevent 24RF08 corruption */
-+ i2c_smbus_write_quick(new_client, 0);
-+
-+ /* Now, we do the remaining detection. It is not there, unless you force
-+ the checksum to work out. */
-+ if (checksum) {
-+ int cs = 0;
-+ for (i = 0; i <= 0x3e; i++)
-+ cs += i2c_smbus_read_byte_data(new_client, i);
-+ cs &= 0xff;
-+ if (i2c_smbus_read_byte_data
-+ (new_client, EEPROM_REG_CHECKSUM) != cs)
-+ goto ERROR1;
-+ }
-+
-+ data->nature = NATURE_UNKNOWN;
-+ /* Detect the Vaio nature of EEPROMs.
-+ We use the "PCG-" prefix as the signature. */
-+ if (address == 0x57)
-+ {
-+ if (i2c_smbus_read_byte_data(new_client, 0x80) == 'P'
-+ && i2c_smbus_read_byte_data(new_client, 0x81) == 'C'
-+ && i2c_smbus_read_byte_data(new_client, 0x82) == 'G'
-+ && i2c_smbus_read_byte_data(new_client, 0x83) == '-')
-+ data->nature = NATURE_VAIO;
-+ }
-+
-+ /* Determine the chip type - only one kind supported! */
-+ if (kind <= 0)
-+ kind = eeprom;
-+
-+ if (kind == eeprom) {
-+ type_name = "eeprom";
-+ client_name = "EEPROM chip";
-+ } else {
-+#ifdef DEBUG
-+ printk("eeprom.o: Internal error: unknown kind (%d)?!?",
-+ kind);
-+#endif
-+ goto ERROR1;
-+ }
-+
-+ /* Fill in the remaining client fields and put it into the global list */
-+ strcpy(new_client->name, client_name);
-+
-+ new_client->id = eeprom_id++;
-+ data->valid = 0;
-+ init_MUTEX(&data->update_lock);
-+
-+ /* Tell the I2C layer a new client has arrived */
-+ if ((err = i2c_attach_client(new_client)))
-+ goto ERROR3;
-+
-+ /* Register a new directory entry with module sensors */
-+ if ((i = i2c_register_entry(new_client, type_name,
-+ eeprom_dir_table_template)) < 0) {
-+ err = i;
-+ goto ERROR4;
-+ }
-+ data->sysctl_id = i;
-+
-+ return 0;
-+
-+/* OK, this is not exactly good programming practice, usually. But it is
-+ very code-efficient in this case. */
-+
-+ ERROR4:
-+ i2c_detach_client(new_client);
-+ ERROR3:
-+ ERROR1:
-+ kfree(data);
-+ ERROR0:
-+ return err;
-+}
-+
-+static int eeprom_detach_client(struct i2c_client *client)
-+{
-+ int err;
-+
-+ i2c_deregister_entry(((struct eeprom_data *) (client->data))->
-+ sysctl_id);
-+
-+ if ((err = i2c_detach_client(client))) {
-+ printk
-+ ("eeprom.o: Client deregistration failed, client not detached.\n");
-+ return err;
-+ }
-+
-+ kfree(client->data);
-+
-+ return 0;
-+}
-+
-+
-+#if 0
-+/* No writes yet (PAE) */
-+static int eeprom_write_value(struct i2c_client *client, u8 reg, u8 value)
-+{
-+ return i2c_smbus_write_byte_data(client, reg, value);
-+}
-+#endif
-+
-+static void eeprom_update_client(struct i2c_client *client, u8 slice)
-+{
-+ struct eeprom_data *data = client->data;
-+ int i, j;
-+
-+ down(&data->update_lock);
-+
-+ if (!(data->valid & (1 << slice))
-+ || (jiffies - data->last_updated[slice] > 300 * HZ)
-+ || (jiffies < data->last_updated[slice])) {
-+
-+#ifdef DEBUG
-+ printk("Starting eeprom update, slice %u\n", slice);
-+#endif
-+
-+ if (i2c_check_functionality(client->adapter,
-+ I2C_FUNC_SMBUS_READ_I2C_BLOCK))
-+ {
-+ for (i = slice << 5; i < (slice + 1) << 5;
-+ i += I2C_SMBUS_I2C_BLOCK_MAX)
-+ if (i2c_smbus_read_i2c_block_data(client,
-+ i, data->data + i)
-+ != I2C_SMBUS_I2C_BLOCK_MAX) {
-+ printk(KERN_WARNING "eeprom.o: block read fail at 0x%.2x!\n", i);
-+ goto DONE;
-+ }
-+ } else {
-+ if (i2c_smbus_write_byte(client, slice << 5)) {
-+ printk(KERN_WARNING "eeprom.o: read start fail at 0x%.2x!\n", slice << 5);
-+ goto DONE;
-+ }
-+ for (i = slice << 5; i < (slice + 1) << 5; i++) {
-+ j = i2c_smbus_read_byte(client);
-+ if (j < 0) {
-+ printk(KERN_WARNING "eeprom.o: read fail at 0x%.2x!\n", i);
-+ goto DONE;
-+ }
-+ data->data[i] = (u8) j;
-+ }
-+ }
-+ data->last_updated[slice] = jiffies;
-+ data->valid |= (1 << slice);
-+ }
-+DONE:
-+ up(&data->update_lock);
-+}
-+
-+
-+void eeprom_contents(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results)
-+{
-+ int i;
-+ int nr = ctl_name - EEPROM_SYSCTL1;
-+ struct eeprom_data *data = client->data;
-+
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 0;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ eeprom_update_client(client, nr >> 1);
-+ /* Hide Vaio security settings to regular users */
-+ if (nr == 0 && data->nature == NATURE_VAIO
-+ && !capable(CAP_SYS_ADMIN))
-+ for (i = 0; i < 16; i++)
-+ results[i] = 0;
-+ else
-+ for (i = 0; i < 16; i++)
-+ results[i] = data->data[i + nr * 16];
-+#ifdef DEBUG
-+ printk("eeprom.o: 0x%X EEPROM contents (row %d):",
-+ client->addr, nr + 1);
-+ if (nr == 0 && data->nature == NATURE_VAIO)
-+ printk(" <hidden for security reasons>\n");
-+ else {
-+ for (i = 0; i < 16; i++)
-+ printk(" 0x%02X", data->data[i + nr * 16]);
-+ printk("\n");
-+ }
-+#endif
-+ *nrels_mag = 16;
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+
-+/* No writes to the EEPROM (yet, anyway) (PAE) */
-+ printk("eeprom.o: No writes to EEPROMs supported!\n");
-+ }
-+}
-+
-+static int __init sm_eeprom_init(void)
-+{
-+ printk("eeprom.o version %s (%s)\n", LM_VERSION, LM_DATE);
-+ return i2c_add_driver(&eeprom_driver);
-+}
-+
-+static void __exit sm_eeprom_exit(void)
-+{
-+ i2c_del_driver(&eeprom_driver);
-+}
-+
-+
-+
-+MODULE_AUTHOR
-+ ("Frodo Looijaard <frodol@dds.nl> and Philip Edelbrock <phil@netroedge.com>");
-+MODULE_DESCRIPTION("EEPROM driver");
-+
-+module_init(sm_eeprom_init);
-+module_exit(sm_eeprom_exit);
---- linux-old/drivers/sensors/fscpos.c Thu Jan 1 00:00:00 1970
-+++ linux/drivers/sensors/fscpos.c Mon Dec 13 20:18:46 2004
-@@ -0,0 +1,690 @@
-+/*
-+ fscpos.c - Part of lm_sensors, Linux kernel modules for hardware
-+ monitoring
-+ Copyright (c) 2001 Hermann Jung <hej@odn.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., 675 Mass Ave, Cambridge, MA 02139, USA.
-+*/
-+
-+/*
-+ fujitsu siemens poseidon chip,
-+ module based on lm80.c
-+ Copyright (c) 1998, 1999 Frodo Looijaard <frodol@dds.nl>
-+ and Philip Edelbrock <phil@netroedge.com>
-+*/
-+
-+#include <linux/module.h>
-+#include <linux/slab.h>
-+#include <linux/i2c.h>
-+#include <linux/i2c-proc.h>
-+#include <linux/init.h>
-+#define LM_DATE "20041007"
-+#define LM_VERSION "2.8.8"
-+
-+/* Addresses to scan */
-+static unsigned short normal_i2c[] = { 0x73, SENSORS_I2C_END };
-+static unsigned short normal_i2c_range[] = { SENSORS_I2C_END };
-+static unsigned int normal_isa[] = { SENSORS_ISA_END };
-+static unsigned int normal_isa_range[] = { SENSORS_ISA_END };
-+
-+/* Insmod parameters */
-+SENSORS_INSMOD_1(fscpos);
-+
-+/* The FSCPOS registers */
-+
-+/* chip identification */
-+#define FSCPOS_REG_IDENT_0 0x00
-+#define FSCPOS_REG_IDENT_1 0x01
-+#define FSCPOS_REG_IDENT_2 0x02
-+#define FSCPOS_REG_REVISION 0x03
-+
-+/* global control and status */
-+#define FSCPOS_REG_EVENT_STATE 0x04
-+#define FSCPOS_REG_CONTROL 0x05
-+
-+/* watchdog */
-+#define FSCPOS_REG_WDOG_PRESET 0x28
-+#define FSCPOS_REG_WDOG_STATE 0x23
-+#define FSCPOS_REG_WDOG_CONTROL 0x21
-+
-+/* fan 0 */
-+#define FSCPOS_REG_FAN0_MIN 0x55
-+#define FSCPOS_REG_FAN0_ACT 0x0e
-+#define FSCPOS_REG_FAN0_STATE 0x0d
-+#define FSCPOS_REG_FAN0_RIPPLE 0x0f
-+
-+/* fan 1 */
-+#define FSCPOS_REG_FAN1_MIN 0x65
-+#define FSCPOS_REG_FAN1_ACT 0x6b
-+#define FSCPOS_REG_FAN1_STATE 0x62
-+#define FSCPOS_REG_FAN1_RIPPLE 0x6f
-+
-+/* fan 2 */
-+/* min speed fan2 not supported */
-+#define FSCPOS_REG_FAN2_ACT 0xab
-+#define FSCPOS_REG_FAN2_STATE 0xa2
-+#define FSCPOS_REG_FAN2_RIPPLE 0x0af
-+
-+/* voltage supervision */
-+#define FSCPOS_REG_VOLT_12 0x45
-+#define FSCPOS_REG_VOLT_5 0x42
-+#define FSCPOS_REG_VOLT_BATT 0x48
-+
-+/* temperatures */
-+/* sensor 0 */
-+#define FSCPOS_REG_TEMP0_ACT 0x64
-+#define FSCPOS_REG_TEMP0_STATE 0x71
-+
-+/* sensor 1 */
-+#define FSCPOS_REG_TEMP1_ACT 0x32
-+#define FSCPOS_REG_TEMP1_STATE 0x81
-+
-+/* sensor 2 */
-+#define FSCPOS_REG_TEMP2_ACT 0x35
-+#define FSCPOS_REG_TEMP2_STATE 0x91
-+
-+
-+
-+
-+/* Conversions. Rounding and limit checking is only done on the TO_REG
-+ variants. Note that you should be a bit careful with which arguments
-+ these macros are called: arguments may be evaluated more than once.
-+ Fixing this is just not worth it. */
-+
-+#define IN_TO_REG(val,nr) (SENSORS_LIMIT((val),0,255))
-+#define IN_FROM_REG(val,nr) (val)
-+
-+/* Initial limits */
-+
-+/* For each registered FSCPOS, we need to keep some data in memory. That
-+ data is pointed to by fscpos_list[NR]->data. The structure itself is
-+ dynamically allocated, at the same time when a new fscpos client is
-+ allocated. */
-+struct fscpos_data {
-+ struct i2c_client client;
-+ int sysctl_id;
-+
-+ struct semaphore update_lock;
-+ char valid; /* !=0 if following fields are valid */
-+ unsigned long last_updated; /* In jiffies */
-+
-+ u8 revision; /* revision of chip */
-+ u8 global_event; /* global event status */
-+ u8 global_control; /* global control register */
-+ u8 watchdog[3]; /* watchdog */
-+ u8 volt[3]; /* 12, 5, battery current */
-+ u8 temp_act[3]; /* temperature */
-+ u8 temp_status[3]; /* status of sensor */
-+ u8 fan_act[3]; /* fans revolutions per second */
-+ u8 fan_status[3]; /* fan status */
-+ u8 fan_min[3]; /* fan min value for rps */
-+ u8 fan_ripple[3]; /* divider for rps */
-+};
-+
-+
-+static int fscpos_attach_adapter(struct i2c_adapter *adapter);
-+static int fscpos_detect(struct i2c_adapter *adapter, int address,
-+ unsigned short flags, int kind);
-+static int fscpos_detach_client(struct i2c_client *client);
-+
-+static int fscpos_read_value(struct i2c_client *client, u8 register);
-+static int fscpos_write_value(struct i2c_client *client, u8 register,
-+ u8 value);
-+static void fscpos_update_client(struct i2c_client *client);
-+static void fscpos_init_client(struct i2c_client *client);
-+
-+
-+static void fscpos_in(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results);
-+static void fscpos_fan(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void fscpos_fan_internal(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results,
-+ int nr, int reg_state, int reg_min, int res_ripple);
-+static void fscpos_temp(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void fscpos_volt(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void fscpos_wdog(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+
-+static int fscpos_id = 0;
-+
-+static struct i2c_driver fscpos_driver = {
-+ .owner = THIS_MODULE,
-+ .name = "FSCPOS sensor driver",
-+ .id = I2C_DRIVERID_FSCPOS,
-+ .flags = I2C_DF_NOTIFY,
-+ .attach_adapter = fscpos_attach_adapter,
-+ .detach_client = fscpos_detach_client,
-+};
-+
-+/* -- SENSORS SYSCTL START -- */
-+#define FSCPOS_SYSCTL_VOLT0 1000 /* 12 volt supply */
-+#define FSCPOS_SYSCTL_VOLT1 1001 /* 5 volt supply */
-+#define FSCPOS_SYSCTL_VOLT2 1002 /* batterie voltage*/
-+#define FSCPOS_SYSCTL_FAN0 1101 /* state, min, ripple, actual value fan 0 */
-+#define FSCPOS_SYSCTL_FAN1 1102 /* state, min, ripple, actual value fan 1 */
-+#define FSCPOS_SYSCTL_FAN2 1103 /* state, min, ripple, actual value fan 2 */
-+#define FSCPOS_SYSCTL_TEMP0 1201 /* state and value of sensor 0, cpu die */
-+#define FSCPOS_SYSCTL_TEMP1 1202 /* state and value of sensor 1, motherboard */
-+#define FSCPOS_SYSCTL_TEMP2 1203 /* state and value of sensor 2, chassis */
-+#define FSCPOS_SYSCTL_REV 2000 /* Revision */
-+#define FSCPOS_SYSCTL_EVENT 2001 /* global event status */
-+#define FSCPOS_SYSCTL_CONTROL 2002 /* global control byte */
-+#define FSCPOS_SYSCTL_WDOG 2003 /* state, min, ripple, actual value fan 2 */
-+/* -- SENSORS SYSCTL END -- */
-+
-+/* These files are created for each detected FSCPOS. This is just a template;
-+ though at first sight, you might think we could use a statically
-+ allocated list, we need some way to get back to the parent - which
-+ is done through one of the 'extra' fields which are initialized
-+ when a new copy is allocated. */
-+static ctl_table fscpos_dir_table_template[] = {
-+ {FSCPOS_SYSCTL_REV, "rev", NULL, 0, 0444, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &fscpos_in},
-+ {FSCPOS_SYSCTL_EVENT, "alarms", NULL, 0, 0444, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &fscpos_in},
-+ {FSCPOS_SYSCTL_CONTROL, "control", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &fscpos_in},
-+ {FSCPOS_SYSCTL_TEMP0, "temp1", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &fscpos_temp},
-+ {FSCPOS_SYSCTL_TEMP1, "temp2", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &fscpos_temp},
-+ {FSCPOS_SYSCTL_TEMP2, "temp3", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &fscpos_temp},
-+ {FSCPOS_SYSCTL_VOLT0, "in0", NULL, 0, 0444, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &fscpos_volt},
-+ {FSCPOS_SYSCTL_VOLT1, "in1", NULL, 0, 0444, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &fscpos_volt},
-+ {FSCPOS_SYSCTL_VOLT2, "in2", NULL, 0, 0444, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &fscpos_volt},
-+ {FSCPOS_SYSCTL_FAN0, "fan1", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &fscpos_fan},
-+ {FSCPOS_SYSCTL_FAN1, "fan2", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &fscpos_fan},
-+ {FSCPOS_SYSCTL_FAN2, "fan3", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &fscpos_fan},
-+ {FSCPOS_SYSCTL_WDOG, "wdog", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &fscpos_wdog},
-+ {0}
-+};
-+
-+static int fscpos_attach_adapter(struct i2c_adapter *adapter)
-+{
-+ return i2c_detect(adapter, &addr_data, fscpos_detect);
-+}
-+
-+int fscpos_detect(struct i2c_adapter *adapter, int address,
-+ unsigned short flags, int kind)
-+{
-+ int i;
-+ struct i2c_client *new_client;
-+ struct fscpos_data *data;
-+ int err = 0;
-+ const char *type_name, *client_name;
-+
-+ /* Make sure we aren't probing the ISA bus!! This is just a safety check
-+ at this moment; i2c_detect really won't call us. */
-+#ifdef DEBUG
-+ if (i2c_is_isa_adapter(adapter)) {
-+ printk
-+ ("fscpos.o: fscpos_detect called for an ISA bus adapter?!?\n");
-+ return 0;
-+ }
-+#endif
-+
-+ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
-+ goto ERROR0;
-+
-+ /* OK. For now, we presume we have a valid client. We now create the
-+ client structure, even though we cannot fill it completely yet.
-+ But it allows us to access fscpos_{read,write}_value. */
-+ if (!(data = kmalloc(sizeof(struct fscpos_data), GFP_KERNEL))) {
-+ err = -ENOMEM;
-+ goto ERROR0;
-+ }
-+
-+ new_client = &data->client;
-+ new_client->addr = address;
-+ new_client->data = data;
-+ new_client->adapter = adapter;
-+ new_client->driver = &fscpos_driver;
-+ new_client->flags = 0;
-+
-+ /* Do the remaining detection unless force or force_fscpos parameter */
-+ if (kind < 0) {
-+ if (fscpos_read_value(new_client, FSCPOS_REG_IDENT_0) != 0x50)
-+ goto ERROR1;
-+ if (fscpos_read_value(new_client, FSCPOS_REG_IDENT_1) != 0x45)
-+ goto ERROR1;
-+ if (fscpos_read_value(new_client, FSCPOS_REG_IDENT_2) != 0x47)
-+ goto ERROR1;
-+ }
-+
-+ kind = fscpos;
-+
-+ type_name = "fscpos";
-+ client_name = "fsc poseidon chip";
-+
-+ /* Fill in the remaining client fields and put it into the global list */
-+ strcpy(new_client->name, client_name);
-+
-+ new_client->id = fscpos_id++;
-+ data->valid = 0;
-+ init_MUTEX(&data->update_lock);
-+
-+ /* Tell the I2C layer a new client has arrived */
-+ if ((err = i2c_attach_client(new_client)))
-+ goto ERROR3;
-+
-+ /* Register a new directory entry with module sensors */
-+ if ((i = i2c_register_entry(new_client, type_name,
-+ fscpos_dir_table_template)) < 0) {
-+ err = i;
-+ goto ERROR4;
-+ }
-+ data->sysctl_id = i;
-+
-+ fscpos_init_client(new_client);
-+ return 0;
-+
-+/* OK, this is not exactly good programming practice, usually. But it is
-+ very code-efficient in this case. */
-+ ERROR4:
-+ i2c_detach_client(new_client);
-+ ERROR3:
-+ ERROR1:
-+ kfree(data);
-+ ERROR0:
-+ return err;
-+}
-+
-+static int fscpos_detach_client(struct i2c_client *client)
-+{
-+ int err;
-+
-+ i2c_deregister_entry(((struct fscpos_data *) (client->data))->
-+ sysctl_id);
-+
-+ if ((err = i2c_detach_client(client))) {
-+ printk
-+ ("fscpos.o: Client deregistration failed, client not detached.\n");
-+ return err;
-+ }
-+
-+ kfree(client->data);
-+
-+ return 0;
-+}
-+
-+static int fscpos_read_value(struct i2c_client *client, u8 reg)
-+{
-+#ifdef DEBUG
-+ printk("fscpos: read reg 0x%02x\n",reg);
-+#endif
-+ return i2c_smbus_read_byte_data(client, reg);
-+}
-+
-+static int fscpos_write_value(struct i2c_client *client, u8 reg, u8 value)
-+{
-+#ifdef DEBUG
-+ printk("fscpos: write reg 0x%02x, val 0x%02x\n",reg, value);
-+#endif
-+ return i2c_smbus_write_byte_data(client, reg, value);
-+}
-+
-+/* Called when we have found a new FSCPOS. It should set limits, etc. */
-+static void fscpos_init_client(struct i2c_client *client)
-+{
-+ struct fscpos_data *data = client->data;
-+
-+ /* read revision from chip */
-+ data->revision = fscpos_read_value(client,FSCPOS_REG_REVISION);
-+ /* setup missing fan2_min value */
-+ data->fan_min[2] = 0xff;
-+}
-+
-+static void fscpos_update_client(struct i2c_client *client)
-+{
-+ struct fscpos_data *data = client->data;
-+
-+ down(&data->update_lock);
-+
-+ if ((jiffies - data->last_updated > 2 * HZ) ||
-+ (jiffies < data->last_updated) || !data->valid) {
-+
-+#ifdef DEBUG
-+ printk("Starting fscpos update\n");
-+#endif
-+ data->temp_act[0] = fscpos_read_value(client, FSCPOS_REG_TEMP0_ACT);
-+ data->temp_act[1] = fscpos_read_value(client, FSCPOS_REG_TEMP1_ACT);
-+ data->temp_act[2] = fscpos_read_value(client, FSCPOS_REG_TEMP2_ACT);
-+ data->temp_status[0] = fscpos_read_value(client, FSCPOS_REG_TEMP0_STATE);
-+ data->temp_status[1] = fscpos_read_value(client, FSCPOS_REG_TEMP1_STATE);
-+ data->temp_status[2] = fscpos_read_value(client, FSCPOS_REG_TEMP2_STATE);
-+
-+ data->volt[0] = fscpos_read_value(client, FSCPOS_REG_VOLT_12);
-+ data->volt[1] = fscpos_read_value(client, FSCPOS_REG_VOLT_5);
-+ data->volt[2] = fscpos_read_value(client, FSCPOS_REG_VOLT_BATT);
-+
-+ data->fan_act[0] = fscpos_read_value(client, FSCPOS_REG_FAN0_ACT);
-+ data->fan_act[1] = fscpos_read_value(client, FSCPOS_REG_FAN1_ACT);
-+ data->fan_act[2] = fscpos_read_value(client, FSCPOS_REG_FAN2_ACT);
-+ data->fan_status[0] = fscpos_read_value(client, FSCPOS_REG_FAN0_STATE);
-+ data->fan_status[1] = fscpos_read_value(client, FSCPOS_REG_FAN1_STATE);
-+ data->fan_status[2] = fscpos_read_value(client, FSCPOS_REG_FAN2_STATE);
-+ data->fan_min[0] = fscpos_read_value(client, FSCPOS_REG_FAN0_MIN);
-+ data->fan_min[1] = fscpos_read_value(client, FSCPOS_REG_FAN1_MIN);
-+ /* fan2_min is not supported */
-+ data->fan_ripple[0] = fscpos_read_value(client, FSCPOS_REG_FAN0_RIPPLE);
-+ data->fan_ripple[1] = fscpos_read_value(client, FSCPOS_REG_FAN1_RIPPLE);
-+ data->fan_ripple[2] = fscpos_read_value(client, FSCPOS_REG_FAN2_RIPPLE);
-+
-+ data->watchdog[0] = fscpos_read_value(client, FSCPOS_REG_WDOG_PRESET);
-+ data->watchdog[1] = fscpos_read_value(client, FSCPOS_REG_WDOG_STATE);
-+ data->watchdog[2] = fscpos_read_value(client, FSCPOS_REG_WDOG_CONTROL);
-+
-+ data->global_event = fscpos_read_value(client, FSCPOS_REG_EVENT_STATE);
-+
-+ data->last_updated = jiffies;
-+ data->valid = 1;
-+ }
-+
-+ up(&data->update_lock);
-+}
-+
-+
-+/* The next few functions are the call-back functions of the /proc/sys and
-+ sysctl files. Which function is used is defined in the ctl_table in
-+ the extra1 field.
-+ Each function must return the magnitude (power of 10 to divide the date
-+ with) if it is called with operation==SENSORS_PROC_REAL_INFO. It must
-+ put a maximum of *nrels elements in results reflecting the data of this
-+ file, and set *nrels to the number it actually put in it, if operation==
-+ SENSORS_PROC_REAL_READ. Finally, it must get upto *nrels elements from
-+ results and write them to the chip, if operations==SENSORS_PROC_REAL_WRITE.
-+ Note that on SENSORS_PROC_REAL_READ, I do not check whether results is
-+ large enough (by checking the incoming value of *nrels). This is not very
-+ good practice, but as long as you put less than about 5 values in results,
-+ you can assume it is large enough. */
-+void fscpos_in(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct fscpos_data *data = client->data;
-+
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 0;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ fscpos_update_client(client);
-+ switch(ctl_name) {
-+ case FSCPOS_SYSCTL_REV:
-+ results[0] = data->revision ;
-+ break;
-+ case FSCPOS_SYSCTL_EVENT:
-+ results[0] = data->global_event & 0x1f;
-+ break;
-+ case FSCPOS_SYSCTL_CONTROL:
-+ results[0] = data->global_control & 0x01;
-+ break;
-+ default:
-+ printk("fscpos: ctl_name %d not supported\n",
-+ ctl_name);
-+ *nrels_mag = 0;
-+ return;
-+ }
-+ *nrels_mag = 1;
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ if((ctl_name == FSCPOS_SYSCTL_CONTROL) && (*nrels_mag >= 1)) {
-+ data->global_control = (results[0] & 0x01);
-+ printk("fscpos: writing 0x%02x to global_control\n",
-+ data->global_control);
-+ fscpos_write_value(client,FSCPOS_REG_CONTROL,
-+ data->global_control);
-+ }
-+ else
-+ printk("fscpos: writing to chip not supported\n");
-+ }
-+}
-+
-+#define TEMP_FROM_REG(val) (val-128)
-+
-+
-+void fscpos_temp(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct fscpos_data *data = client->data;
-+
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 0;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ fscpos_update_client(client);
-+ switch(ctl_name) {
-+ case FSCPOS_SYSCTL_TEMP0:
-+ results[0] = data->temp_status[0] & 0x03;
-+ results[1] = TEMP_FROM_REG(data->temp_act[0]);
-+ break;
-+ case FSCPOS_SYSCTL_TEMP1:
-+ results[0] = data->temp_status[1] & 0x03;
-+ results[1] = TEMP_FROM_REG(data->temp_act[1]);
-+ break;
-+ case FSCPOS_SYSCTL_TEMP2:
-+ results[0] = data->temp_status[2] & 0x03;
-+ results[1] = TEMP_FROM_REG(data->temp_act[2]);
-+ break;
-+ default:
-+ printk("fscpos: ctl_name %d not supported\n",
-+ ctl_name);
-+ *nrels_mag = 0;
-+ return;
-+ }
-+ *nrels_mag = 2;
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ if(*nrels_mag >= 1) {
-+ switch(ctl_name) {
-+ case FSCPOS_SYSCTL_TEMP0:
-+ data->temp_status[0] =
-+ (data->temp_status[0] & ~0x02)
-+ | (results[0] & 0x02);
-+ printk("fscpos: writing value 0x%02x "
-+ "to temp0_status\n",
-+ data->temp_status[0]);
-+ fscpos_write_value(client,
-+ FSCPOS_REG_TEMP0_STATE,
-+ data->temp_status[0] & 0x02);
-+ break;
-+ case FSCPOS_SYSCTL_TEMP1:
-+ data->temp_status[1] = (data->temp_status[1] & ~0x02) | (results[0] & 0x02);
-+ printk("fscpos: writing value 0x%02x to temp1_status\n", data->temp_status[1]);
-+ fscpos_write_value(client,FSCPOS_REG_TEMP1_STATE,
-+ data->temp_status[1] & 0x02);
-+ break;
-+ case FSCPOS_SYSCTL_TEMP2:
-+ data->temp_status[2] = (data->temp_status[2] & ~0x02) | (results[0] & 0x02);
-+ printk("fscpos: writing value 0x%02x to temp2_status\n", data->temp_status[2]);
-+ fscpos_write_value(client,FSCPOS_REG_TEMP2_STATE,
-+ data->temp_status[2] & 0x02);
-+ break;
-+ default:
-+ printk("fscpos: ctl_name %d not supported\n",ctl_name);
-+ }
-+ }
-+ else
-+ printk("fscpos: writing to chip not supported\n");
-+ }
-+}
-+
-+#define VOLT_FROM_REG(val,mult) (val*mult/255)
-+
-+void fscpos_volt(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct fscpos_data *data = client->data;
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 2;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ fscpos_update_client(client);
-+ switch(ctl_name) {
-+ case FSCPOS_SYSCTL_VOLT0:
-+ results[0] = VOLT_FROM_REG(data->volt[0],1420);
-+ break;
-+ case FSCPOS_SYSCTL_VOLT1:
-+ results[0] = VOLT_FROM_REG(data->volt[1],660);
-+ break;
-+ case FSCPOS_SYSCTL_VOLT2:
-+ results[0] = VOLT_FROM_REG(data->volt[2],330);
-+ break;
-+ default:
-+ printk("fscpos: ctl_name %d not supported\n",
-+ ctl_name);
-+ *nrels_mag = 0;
-+ return;
-+ }
-+ *nrels_mag = 1;
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ printk("fscpos: writing to chip not supported\n");
-+ }
-+}
-+
-+void fscpos_fan(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+
-+ switch(ctl_name) {
-+ case FSCPOS_SYSCTL_FAN0:
-+ fscpos_fan_internal(client,operation,ctl_name,nrels_mag,results,
-+ 0,FSCPOS_REG_FAN0_STATE,FSCPOS_REG_FAN0_MIN,
-+ FSCPOS_REG_FAN0_RIPPLE);
-+ break;
-+ case FSCPOS_SYSCTL_FAN1:
-+ fscpos_fan_internal(client,operation,ctl_name,nrels_mag,results,
-+ 1,FSCPOS_REG_FAN1_STATE,FSCPOS_REG_FAN1_MIN,
-+ FSCPOS_REG_FAN1_RIPPLE);
-+ break;
-+ case FSCPOS_SYSCTL_FAN2:
-+ fscpos_fan_internal(client,operation,ctl_name,nrels_mag,results,
-+ 2,FSCPOS_REG_FAN2_STATE,0xff,
-+ FSCPOS_REG_FAN2_RIPPLE);
-+ break;
-+ default:
-+ printk("fscpos: illegal fan nr %d\n",ctl_name);
-+ }
-+}
-+
-+#define RPM_FROM_REG(val) (val*60)
-+
-+void fscpos_fan_internal(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results, int nr,
-+ int reg_state, int reg_min, int reg_ripple )
-+{
-+ struct fscpos_data *data = client->data;
-+
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 0;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ fscpos_update_client(client);
-+ results[0] = data->fan_status[nr] & 0x04;
-+ results[1] = data->fan_min[nr];
-+ results[2] = data->fan_ripple[nr] & 0x03;
-+ results[3] = RPM_FROM_REG(data->fan_act[nr]);
-+ *nrels_mag = 4;
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ if(*nrels_mag >= 1) {
-+ data->fan_status[nr] = results[0] & 0x04;
-+ printk("fscpos: writing value 0x%02x to fan%d_status\n",
-+ data->fan_status[nr],nr);
-+ fscpos_write_value(client,reg_state,
-+ data->fan_status[nr]);
-+ }
-+ if((*nrels_mag >= 2) && (nr < 2)) {
-+ /* minimal speed for fan2 not supported */
-+ data->fan_min[nr] = results[1];
-+ printk("fscpos: writing value 0x%02x to fan%d_min\n",
-+ data->fan_min[nr],nr);
-+ fscpos_write_value(client,reg_min,
-+ data->fan_min[nr]);
-+ }
-+ if(*nrels_mag >= 3) {
-+ if((results[2] & 0x03) == 0) {
-+ printk("fscpos: fan%d ripple 0 not allowed\n",nr);
-+ return;
-+ }
-+ data->fan_ripple[nr] = results[2] & 0x03;
-+ printk("fscpos: writing value 0x%02x to fan%d_ripple\n",
-+ data->fan_ripple[nr],nr);
-+ fscpos_write_value(client,reg_ripple,
-+ data->fan_ripple[nr]);
-+ }
-+ }
-+}
-+
-+void fscpos_wdog(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct fscpos_data *data = client->data;
-+
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 0;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ fscpos_update_client(client);
-+ results[0] = data->watchdog[0] ;
-+ results[1] = data->watchdog[1] & 0x02;
-+ results[2] = data->watchdog[2] & 0xb0;
-+ *nrels_mag = 3;
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ if (*nrels_mag >= 1) {
-+ data->watchdog[0] = results[0] & 0xff;
-+ printk("fscpos: writing value 0x%02x to wdog_preset\n",
-+ data->watchdog[0]);
-+ fscpos_write_value(client,FSCPOS_REG_WDOG_PRESET,
-+ data->watchdog[0]);
-+ }
-+ if (*nrels_mag >= 2) {
-+ data->watchdog[1] = results[1] & 0x02;
-+ printk("fscpos: writing value 0x%02x to wdog_state\n",
-+ data->watchdog[1]);
-+ fscpos_write_value(client,FSCPOS_REG_WDOG_STATE,
-+ data->watchdog[1]);
-+ }
-+ if (*nrels_mag >= 3) {
-+ data->watchdog[2] = results[2] & 0xb0;
-+ printk("fscpos: writing value 0x%02x to wdog_control\n",
-+ data->watchdog[2]);
-+ fscpos_write_value(client,FSCPOS_REG_WDOG_CONTROL,
-+ data->watchdog[2]);
-+ }
-+ }
-+}
-+
-+static int __init sm_fscpos_init(void)
-+{
-+ printk("fscpos.o version %s (%s)\n", LM_VERSION, LM_DATE);
-+ return i2c_add_driver(&fscpos_driver);
-+}
-+
-+static void __exit sm_fscpos_exit(void)
-+{
-+ i2c_del_driver(&fscpos_driver);
-+}
-+
-+
-+
-+MODULE_AUTHOR
-+ ("Hermann Jung <hej@odn.de> based on work from Frodo Looijaard <frodol@dds.nl> and Philip Edelbrock <phil@netroedge.com>");
-+MODULE_DESCRIPTION("fujitsu siemens poseidon chip driver");
-+MODULE_LICENSE("GPL");
-+
-+module_init(sm_fscpos_init);
-+module_exit(sm_fscpos_exit);
---- linux-old/drivers/sensors/fscscy.c Thu Jan 1 00:00:00 1970
-+++ linux/drivers/sensors/fscscy.c Mon Dec 13 20:18:46 2004
-@@ -0,0 +1,915 @@
-+/*
-+ fscscy.c - Part of lm_sensors, Linux kernel modules for hardware
-+ monitoring
-+ Copyright (c) 2001 Martin Knoblauch <mkn@teraport.de, knobi@knobisoft.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., 675 Mass Ave, Cambridge, MA 02139, USA.
-+*/
-+
-+/*
-+ fujitsu siemens scylla chip,
-+ module based on lm80.c, fscpos.c
-+ Copyright (c) 1998, 1999 Frodo Looijaard <frodol@dds.nl>
-+ and Philip Edelbrock <phil@netroedge.com>
-+*/
-+
-+#include <linux/module.h>
-+#include <linux/slab.h>
-+#include <linux/i2c.h>
-+#include <linux/i2c-proc.h>
-+#include <linux/init.h>
-+#define LM_DATE "20041007"
-+#define LM_VERSION "2.8.8"
-+
-+MODULE_LICENSE("GPL");
-+
-+/* Addresses to scan */
-+static unsigned short normal_i2c[] = { 0x73, SENSORS_I2C_END };
-+static unsigned short normal_i2c_range[] = { SENSORS_I2C_END };
-+static unsigned int normal_isa[] = { SENSORS_ISA_END };
-+static unsigned int normal_isa_range[] = { SENSORS_ISA_END };
-+
-+/* Insmod parameters */
-+SENSORS_INSMOD_1(fscscy);
-+
-+/* The FSCSCY registers */
-+
-+/* chip identification */
-+#define FSCSCY_REG_IDENT_0 0x00
-+#define FSCSCY_REG_IDENT_1 0x01
-+#define FSCSCY_REG_IDENT_2 0x02
-+#define FSCSCY_REG_REVISION 0x03
-+
-+/* global control and status */
-+#define FSCSCY_REG_EVENT_STATE 0x04
-+#define FSCSCY_REG_CONTROL 0x05
-+
-+/* watchdog */
-+#define FSCSCY_REG_WDOG_PRESET 0x28
-+#define FSCSCY_REG_WDOG_STATE 0x23
-+#define FSCSCY_REG_WDOG_CONTROL 0x21
-+
-+/*
-+** Fan definitions
-+**
-+** _RPMMIN: Minimum speed. Can be set via interface, but only for three of the fans
-+** FAN1_RPMMIN is wired to Fan 0 (CPU Fans)
-+** FAN4_RPMMIN is wired to Fan 2 (PS Fans ??)
-+** FAN5_RPMMIN is wired to Fan 3 (AUX Fans ??)
-+** _ACT: Actual Fan Speed
-+** _STATE: Fan status register
-+** _RIPPLE: Fan speed multiplier
-+*/
-+
-+/* fan 0 */
-+#define FSCSCY_REG_FAN0_RPMMIN 0x65
-+#define FSCSCY_REG_FAN0_ACT 0x6b
-+#define FSCSCY_REG_FAN0_STATE 0x62
-+#define FSCSCY_REG_FAN0_RIPPLE 0x6f
-+
-+/* fan 1 */
-+#define FSCSCY_REG_FAN1_RPMMIN FSCSCY_REG_FAN0_RPMMIN
-+#define FSCSCY_REG_FAN1_ACT 0x6c
-+#define FSCSCY_REG_FAN1_STATE 0x61
-+#define FSCSCY_REG_FAN1_RIPPLE 0x6f
-+
-+/* fan 2 */
-+#define FSCSCY_REG_FAN2_RPMMIN 0x55
-+#define FSCSCY_REG_FAN2_ACT 0x0e
-+#define FSCSCY_REG_FAN2_STATE 0x0d
-+#define FSCSCY_REG_FAN2_RIPPLE 0x0f
-+
-+/* fan 3 */
-+#define FSCSCY_REG_FAN3_RPMMIN 0xa5
-+#define FSCSCY_REG_FAN3_ACT 0xab
-+#define FSCSCY_REG_FAN3_STATE 0xa2
-+#define FSCSCY_REG_FAN3_RIPPLE 0xaf
-+
-+/* fan 4 */
-+#define FSCSCY_REG_FAN4_RPMMIN FSCSCY_REG_FAN2_RPMMIN
-+#define FSCSCY_REG_FAN4_ACT 0x5c
-+#define FSCSCY_REG_FAN4_STATE 0x52
-+#define FSCSCY_REG_FAN4_RIPPLE 0x0f
-+
-+/* fan 5 */
-+#define FSCSCY_REG_FAN5_RPMMIN FSCSCY_REG_FAN3_RPMMIN
-+#define FSCSCY_REG_FAN5_ACT 0xbb
-+#define FSCSCY_REG_FAN5_STATE 0xb2
-+#define FSCSCY_REG_FAN5_RIPPLE 0xbf
-+
-+/* voltage supervision */
-+#define FSCSCY_REG_VOLT_12 0x45
-+#define FSCSCY_REG_VOLT_5 0x42
-+#define FSCSCY_REG_VOLT_BATT 0x48
-+
-+/* temperatures */
-+/* sensor 0 */
-+#define FSCSCY_REG_TEMP0_ACT 0x64
-+#define FSCSCY_REG_TEMP0_STATE 0x71
-+#define FSCSCY_REG_TEMP0_LIM 0x76
-+
-+/* sensor 1 */
-+#define FSCSCY_REG_TEMP1_ACT 0xD0
-+#define FSCSCY_REG_TEMP1_STATE 0xD1
-+#define FSCSCY_REG_TEMP1_LIM 0xD6
-+
-+/* sensor 2 */
-+#define FSCSCY_REG_TEMP2_ACT 0x32
-+#define FSCSCY_REG_TEMP2_STATE 0x81
-+#define FSCSCY_REG_TEMP2_LIM 0x86
-+
-+/* sensor3 */
-+#define FSCSCY_REG_TEMP3_ACT 0x35
-+#define FSCSCY_REG_TEMP3_STATE 0x91
-+#define FSCSCY_REG_TEMP3_LIM 0x96
-+
-+/* PCI Load */
-+#define FSCSCY_REG_PCILOAD 0x1a
-+
-+/* Intrusion Sensor */
-+#define FSCSCY_REG_INTR_STATE 0x13
-+#define FSCSCY_REG_INTR_CTRL 0x12
-+
-+/* Conversions. Rounding and limit checking is only done on the TO_REG
-+ variants. Note that you should be a bit careful with which arguments
-+ these macros are called: arguments may be evaluated more than once.
-+ Fixing this is just not worth it. */
-+
-+#define IN_TO_REG(val,nr) (SENSORS_LIMIT((val),0,255))
-+#define IN_FROM_REG(val,nr) (val)
-+
-+/* Initial limits */
-+
-+/* For each registered FSCSCY, we need to keep some data in memory. That
-+ data is pointed to by fscscy_list[NR]->data. The structure itself is
-+ dynamically allocated, at the same time when a new fscscy client is
-+ allocated. */
-+struct fscscy_data {
-+ struct i2c_client client;
-+ int sysctl_id;
-+
-+ struct semaphore update_lock;
-+ char valid; /* !=0 if following fields are valid */
-+ unsigned long last_updated; /* In jiffies */
-+
-+ u8 revision; /* revision of chip */
-+ u8 global_event; /* global event status */
-+ u8 global_control; /* global control register */
-+ u8 watchdog[3]; /* watchdog */
-+ u8 volt[3]; /* 12, 5, battery current */
-+ u8 volt_min[3]; /* minimum voltages over module "lifetime" */
-+ u8 volt_max[3]; /* maximum voltages over module "lifetime" */
-+ u8 temp_act[4]; /* temperature */
-+ u8 temp_status[4]; /* status of temp. sensor */
-+ u8 temp_lim[4]; /* limit temperature of temp. sensor */
-+ u8 temp_min[4]; /* minimum of temp. sensor, this is just calculated by the module */
-+ u8 temp_max[4]; /* maximum of temp. sensor, this is just calculsted by the module */
-+ u8 fan_act[6]; /* fans revolutions per second */
-+ u8 fan_status[6]; /* fan status */
-+ u8 fan_rpmmin[6]; /* fan min value for rps */
-+ u8 fan_ripple[6]; /* divider for rps */
-+ u8 fan_min[6]; /* minimum RPM over module "lifetime" */
-+ u8 fan_max[6]; /* maximum RPM over module "lifetime" */
-+ u8 pciload; /* PCILoad value */
-+ u8 intr_status; /* Intrusion Status */
-+ u8 intr_control; /* Intrusion Control */
-+};
-+
-+
-+static int fscscy_attach_adapter(struct i2c_adapter *adapter);
-+static int fscscy_detect(struct i2c_adapter *adapter, int address,
-+ unsigned short flags, int kind);
-+static int fscscy_detach_client(struct i2c_client *client);
-+
-+static int fscscy_read_value(struct i2c_client *client, u8 register);
-+static int fscscy_write_value(struct i2c_client *client, u8 register,
-+ u8 value);
-+static void fscscy_update_client(struct i2c_client *client);
-+static void fscscy_init_client(struct i2c_client *client);
-+
-+
-+static void fscscy_in(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results);
-+static void fscscy_fan(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void fscscy_fan_internal(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results,
-+ int nr, int reg_state, int reg_min, int res_ripple);
-+static void fscscy_temp(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void fscscy_volt(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void fscscy_wdog(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void fscscy_pciload(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void fscscy_intrusion(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+
-+static int fscscy_id = 0;
-+
-+static struct i2c_driver fscscy_driver = {
-+ .owner = THIS_MODULE,
-+ .name = "FSCSCY sensor driver",
-+ .id = I2C_DRIVERID_FSCSCY,
-+ .flags = I2C_DF_NOTIFY,
-+ .attach_adapter = fscscy_attach_adapter,
-+ .detach_client = fscscy_detach_client,
-+};
-+
-+/* The /proc/sys entries */
-+
-+/* -- SENSORS SYSCTL START -- */
-+#define FSCSCY_SYSCTL_VOLT0 1000 /* 12 volt supply */
-+#define FSCSCY_SYSCTL_VOLT1 1001 /* 5 volt supply */
-+#define FSCSCY_SYSCTL_VOLT2 1002 /* batterie voltage*/
-+#define FSCSCY_SYSCTL_FAN0 1101 /* state, min, ripple, actual value fan 0 */
-+#define FSCSCY_SYSCTL_FAN1 1102 /* state, min, ripple, actual value fan 1 */
-+#define FSCSCY_SYSCTL_FAN2 1103 /* state, min, ripple, actual value fan 2 */
-+#define FSCSCY_SYSCTL_FAN3 1104 /* state, min, ripple, actual value fan 3 */
-+#define FSCSCY_SYSCTL_FAN4 1105 /* state, min, ripple, actual value fan 4 */
-+#define FSCSCY_SYSCTL_FAN5 1106 /* state, min, ripple, actual value fan 5 */
-+#define FSCSCY_SYSCTL_TEMP0 1201 /* state and value of sensor 0, cpu die */
-+#define FSCSCY_SYSCTL_TEMP1 1202 /* state and value of sensor 1, motherboard */
-+#define FSCSCY_SYSCTL_TEMP2 1203 /* state and value of sensor 2, chassis */
-+#define FSCSCY_SYSCTL_TEMP3 1204 /* state and value of sensor 3, chassis */
-+#define FSCSCY_SYSCTL_REV 2000 /* Revision */
-+#define FSCSCY_SYSCTL_EVENT 2001 /* global event status */
-+#define FSCSCY_SYSCTL_CONTROL 2002 /* global control byte */
-+#define FSCSCY_SYSCTL_WDOG 2003 /* state, min, ripple, actual value fan 2 */
-+#define FSCSCY_SYSCTL_PCILOAD 2004 /* PCILoad value */
-+#define FSCSCY_SYSCTL_INTRUSION 2005 /* state, control for intrusion sensor */
-+
-+/* -- SENSORS SYSCTL END -- */
-+
-+/* These files are created for each detected FSCSCY. This is just a template;
-+ though at first sight, you might think we could use a statically
-+ allocated list, we need some way to get back to the parent - which
-+ is done through one of the 'extra' fields which are initialized
-+ when a new copy is allocated. */
-+static ctl_table fscscy_dir_table_template[] = {
-+ {FSCSCY_SYSCTL_REV, "rev", NULL, 0, 0444, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &fscscy_in},
-+ {FSCSCY_SYSCTL_EVENT, "alarms", NULL, 0, 0444, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &fscscy_in},
-+ {FSCSCY_SYSCTL_CONTROL, "control", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &fscscy_in},
-+ {FSCSCY_SYSCTL_TEMP0, "temp1", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &fscscy_temp},
-+ {FSCSCY_SYSCTL_TEMP1, "temp2", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &fscscy_temp},
-+ {FSCSCY_SYSCTL_TEMP2, "temp3", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &fscscy_temp},
-+ {FSCSCY_SYSCTL_TEMP3, "temp4", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &fscscy_temp},
-+ {FSCSCY_SYSCTL_VOLT0, "in0", NULL, 0, 0444, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &fscscy_volt},
-+ {FSCSCY_SYSCTL_VOLT1, "in1", NULL, 0, 0444, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &fscscy_volt},
-+ {FSCSCY_SYSCTL_VOLT2, "in2", NULL, 0, 0444, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &fscscy_volt},
-+ {FSCSCY_SYSCTL_FAN0, "fan1", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &fscscy_fan},
-+ {FSCSCY_SYSCTL_FAN1, "fan2", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &fscscy_fan},
-+ {FSCSCY_SYSCTL_FAN2, "fan3", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &fscscy_fan},
-+ {FSCSCY_SYSCTL_FAN3, "fan4", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &fscscy_fan},
-+ {FSCSCY_SYSCTL_FAN4, "fan5", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &fscscy_fan},
-+ {FSCSCY_SYSCTL_FAN5, "fan6", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &fscscy_fan},
-+ {FSCSCY_SYSCTL_WDOG, "wdog", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &fscscy_wdog},
-+ {FSCSCY_SYSCTL_PCILOAD, "pciload", NULL, 0, 0444, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &fscscy_pciload},
-+ {FSCSCY_SYSCTL_INTRUSION, "intrusion", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &fscscy_intrusion},
-+ {0}
-+};
-+
-+static int fscscy_attach_adapter(struct i2c_adapter *adapter)
-+{
-+ return i2c_detect(adapter, &addr_data, fscscy_detect);
-+}
-+
-+int fscscy_detect(struct i2c_adapter *adapter, int address,
-+ unsigned short flags, int kind)
-+{
-+ int i;
-+ struct i2c_client *new_client;
-+ struct fscscy_data *data;
-+ int err = 0;
-+ const char *type_name, *client_name;
-+
-+ /* Make sure we aren't probing the ISA bus!! This is just a safety check
-+ at this moment; i2c_detect really won't call us. */
-+#ifdef DEBUG
-+ if (i2c_is_isa_adapter(adapter)) {
-+ printk
-+ ("fscscy.o: fscscy_detect called for an ISA bus adapter?!?\n");
-+ return 0;
-+ }
-+#endif
-+
-+ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
-+ goto ERROR0;
-+
-+ /* OK. For now, we presume we have a valid client. We now create the
-+ client structure, even though we cannot fill it completely yet.
-+ But it allows us to access fscscy_{read,write}_value. */
-+ if (!(data = kmalloc(sizeof(struct fscscy_data), GFP_KERNEL))) {
-+ err = -ENOMEM;
-+ goto ERROR0;
-+ }
-+
-+ new_client = &data->client;
-+ new_client->addr = address;
-+ new_client->data = data;
-+ new_client->adapter = adapter;
-+ new_client->driver = &fscscy_driver;
-+ new_client->flags = 0;
-+
-+ /* Do the remaining detection unless force or force_fscscy parameter */
-+ if (kind < 0) {
-+ if (fscscy_read_value(new_client, FSCSCY_REG_IDENT_0) != 0x53)
-+ goto ERROR1;
-+ if (fscscy_read_value(new_client, FSCSCY_REG_IDENT_1) != 0x43)
-+ goto ERROR1;
-+ if (fscscy_read_value(new_client, FSCSCY_REG_IDENT_2) != 0x59)
-+ goto ERROR1;
-+ }
-+
-+ kind = fscscy;
-+
-+ type_name = "fscscy";
-+ client_name = "fsc scylla chip";
-+
-+ /* Fill in the remaining client fields and put it into the global list */
-+ strcpy(new_client->name, client_name);
-+
-+ new_client->id = fscscy_id++;
-+ data->valid = 0;
-+ init_MUTEX(&data->update_lock);
-+
-+ /* Tell the I2C layer a new client has arrived */
-+ if ((err = i2c_attach_client(new_client)))
-+ goto ERROR3;
-+
-+ /* Register a new directory entry with module sensors */
-+ if ((i = i2c_register_entry(new_client, type_name,
-+ fscscy_dir_table_template)) < 0) {
-+ err = i;
-+ goto ERROR4;
-+ }
-+ data->sysctl_id = i;
-+
-+ fscscy_init_client(new_client);
-+ return 0;
-+
-+/* OK, this is not exactly good programming practice, usually. But it is
-+ very code-efficient in this case. */
-+ ERROR4:
-+ i2c_detach_client(new_client);
-+ ERROR3:
-+ ERROR1:
-+ kfree(data);
-+ ERROR0:
-+ return err;
-+}
-+
-+static int fscscy_detach_client(struct i2c_client *client)
-+{
-+ int err;
-+
-+ i2c_deregister_entry(((struct fscscy_data *) (client->data))->
-+ sysctl_id);
-+
-+ if ((err = i2c_detach_client(client))) {
-+ printk
-+ ("fscscy.o: Client deregistration failed, client not detached.\n");
-+ return err;
-+ }
-+
-+ kfree(client->data);
-+
-+ return 0;
-+}
-+
-+static int fscscy_read_value(struct i2c_client *client, u8 reg)
-+{
-+#ifdef DEBUG
-+ printk("fscscy: read reg 0x%02x\n",reg);
-+#endif
-+ return i2c_smbus_read_byte_data(client, reg);
-+}
-+
-+static int fscscy_write_value(struct i2c_client *client, u8 reg, u8 value)
-+{
-+#ifdef DEBUG
-+ printk("fscscy: write reg 0x%02x, val 0x%02x\n",reg, value);
-+#endif
-+ return i2c_smbus_write_byte_data(client, reg, value);
-+}
-+
-+/* Called when we have found a new FSCSCY. It should set limits, etc. */
-+static void fscscy_init_client(struct i2c_client *client)
-+{
-+ struct fscscy_data *data = client->data;
-+
-+ /* read revision from chip */
-+ data->revision = fscscy_read_value(client,FSCSCY_REG_REVISION);
-+
-+ /* Initialize min/max values from chip */
-+ data->fan_min[0] = data->fan_max[0] = fscscy_read_value(client, FSCSCY_REG_FAN0_ACT);
-+ data->fan_min[1] = data->fan_max[1] = fscscy_read_value(client, FSCSCY_REG_FAN1_ACT);
-+ data->fan_min[2] = data->fan_max[2] = fscscy_read_value(client, FSCSCY_REG_FAN2_ACT);
-+ data->fan_min[3] = data->fan_max[3] = fscscy_read_value(client, FSCSCY_REG_FAN3_ACT);
-+ data->fan_min[4] = data->fan_max[4] = fscscy_read_value(client, FSCSCY_REG_FAN4_ACT);
-+ data->fan_min[4] = data->fan_max[5] = fscscy_read_value(client, FSCSCY_REG_FAN5_ACT);
-+ data->temp_min[0] = data->temp_max[0] = fscscy_read_value(client, FSCSCY_REG_TEMP0_ACT);
-+ data->temp_min[1] = data->temp_max[1] = fscscy_read_value(client, FSCSCY_REG_TEMP1_ACT);
-+ data->temp_min[2] = data->temp_max[2] = fscscy_read_value(client, FSCSCY_REG_TEMP2_ACT);
-+ data->temp_min[3] = data->temp_max[3] = fscscy_read_value(client, FSCSCY_REG_TEMP3_ACT);
-+ data->volt_min[0] = data->volt_max[0] = fscscy_read_value(client, FSCSCY_REG_VOLT_12);
-+ data->volt_min[1] = data->volt_max[1] = fscscy_read_value(client, FSCSCY_REG_VOLT_5);
-+ data->volt_min[2] = data->volt_max[2] = fscscy_read_value(client, FSCSCY_REG_VOLT_BATT);
-+}
-+
-+static void fscscy_update_client(struct i2c_client *client)
-+{
-+ struct fscscy_data *data = client->data;
-+
-+ down(&data->update_lock);
-+
-+ if ((jiffies - data->last_updated > 2 * HZ) ||
-+ (jiffies < data->last_updated) || !data->valid) {
-+
-+#ifdef DEBUG
-+ printk("Starting fscscy update\n");
-+#endif
-+ data->temp_act[0] = fscscy_read_value(client, FSCSCY_REG_TEMP0_ACT);
-+ if (data->temp_min[0] > data->temp_act[0]) data->temp_min[0] = data->temp_act[0];
-+ if (data->temp_max[0] < data->temp_act[0]) data->temp_max[0] = data->temp_act[0];
-+ data->temp_act[1] = fscscy_read_value(client, FSCSCY_REG_TEMP1_ACT);
-+ if (data->temp_min[1] > data->temp_act[1]) data->temp_min[1] = data->temp_act[1];
-+ if (data->temp_max[1] < data->temp_act[1]) data->temp_max[1] = data->temp_act[1];
-+ data->temp_act[2] = fscscy_read_value(client, FSCSCY_REG_TEMP2_ACT);
-+ if (data->temp_min[2] > data->temp_act[2]) data->temp_min[2] = data->temp_act[2];
-+ if (data->temp_max[2] < data->temp_act[2]) data->temp_max[2] = data->temp_act[2];
-+ data->temp_act[3] = fscscy_read_value(client, FSCSCY_REG_TEMP3_ACT);
-+ if (data->temp_min[3] > data->temp_act[3]) data->temp_min[3] = data->temp_act[3];
-+ if (data->temp_max[3] < data->temp_act[3]) data->temp_max[3] = data->temp_act[3];
-+ data->temp_status[0] = fscscy_read_value(client, FSCSCY_REG_TEMP0_STATE);
-+ data->temp_status[1] = fscscy_read_value(client, FSCSCY_REG_TEMP1_STATE);
-+ data->temp_status[2] = fscscy_read_value(client, FSCSCY_REG_TEMP2_STATE);
-+ data->temp_status[3] = fscscy_read_value(client, FSCSCY_REG_TEMP3_STATE);
-+ data->temp_lim[0] = fscscy_read_value(client, FSCSCY_REG_TEMP0_LIM);
-+ data->temp_lim[1] = fscscy_read_value(client, FSCSCY_REG_TEMP1_LIM);
-+ data->temp_lim[2] = fscscy_read_value(client, FSCSCY_REG_TEMP2_LIM);
-+ data->temp_lim[3] = fscscy_read_value(client, FSCSCY_REG_TEMP3_LIM);
-+
-+ data->volt[0] = fscscy_read_value(client, FSCSCY_REG_VOLT_12);
-+ if (data->volt_min[0] > data->volt[0]) data->volt_min[0] = data->volt[0];
-+ if (data->volt_max[0] < data->volt[0]) data->volt_max[0] = data->volt[0];
-+ data->volt[1] = fscscy_read_value(client, FSCSCY_REG_VOLT_5);
-+ if (data->volt_min[1] > data->volt[1]) data->volt_min[1] = data->volt[1];
-+ if (data->volt_max[1] < data->volt[1]) data->volt_max[1] = data->volt[1];
-+ data->volt[2] = fscscy_read_value(client, FSCSCY_REG_VOLT_BATT);
-+ if (data->volt_min[2] > data->volt[2]) data->volt_min[2] = data->volt[2];
-+ if (data->volt_max[2] < data->volt[2]) data->volt_max[2] = data->volt[2];
-+
-+ data->fan_act[0] = fscscy_read_value(client, FSCSCY_REG_FAN0_ACT);
-+ if (data->fan_min[0] > data->fan_act[0]) data->fan_min[0] = data->fan_act[0];
-+ if (data->fan_max[0] < data->fan_act[0]) data->fan_max[0] = data->fan_act[0];
-+ data->fan_act[1] = fscscy_read_value(client, FSCSCY_REG_FAN1_ACT);
-+ if (data->fan_min[1] > data->fan_act[1]) data->fan_min[1] = data->fan_act[1];
-+ if (data->fan_max[1] < data->fan_act[1]) data->fan_max[1] = data->fan_act[1];
-+ data->fan_act[2] = fscscy_read_value(client, FSCSCY_REG_FAN2_ACT);
-+ if (data->fan_min[2] > data->fan_act[2]) data->fan_min[2] = data->fan_act[2];
-+ if (data->fan_max[2] < data->fan_act[2]) data->fan_max[2] = data->fan_act[2];
-+ data->fan_act[3] = fscscy_read_value(client, FSCSCY_REG_FAN3_ACT);
-+ if (data->fan_min[3] > data->fan_act[3]) data->fan_min[3] = data->fan_act[3];
-+ if (data->fan_max[3] < data->fan_act[3]) data->fan_max[3] = data->fan_act[3];
-+ data->fan_act[4] = fscscy_read_value(client, FSCSCY_REG_FAN4_ACT);
-+ if (data->fan_min[4] > data->fan_act[4]) data->fan_min[4] = data->fan_act[4];
-+ if (data->fan_max[4] < data->fan_act[4]) data->fan_max[4] = data->fan_act[4];
-+ data->fan_act[5] = fscscy_read_value(client, FSCSCY_REG_FAN5_ACT);
-+ if (data->fan_min[5] > data->fan_act[5]) data->fan_min[5] = data->fan_act[5];
-+ if (data->fan_max[5] < data->fan_act[5]) data->fan_max[5] = data->fan_act[5];
-+ data->fan_status[0] = fscscy_read_value(client, FSCSCY_REG_FAN0_STATE);
-+ data->fan_status[1] = fscscy_read_value(client, FSCSCY_REG_FAN1_STATE);
-+ data->fan_status[2] = fscscy_read_value(client, FSCSCY_REG_FAN2_STATE);
-+ data->fan_status[3] = fscscy_read_value(client, FSCSCY_REG_FAN3_STATE);
-+ data->fan_status[4] = fscscy_read_value(client, FSCSCY_REG_FAN4_STATE);
-+ data->fan_status[5] = fscscy_read_value(client, FSCSCY_REG_FAN5_STATE);
-+ data->fan_rpmmin[0] = fscscy_read_value(client, FSCSCY_REG_FAN0_RPMMIN);
-+ data->fan_rpmmin[1] = fscscy_read_value(client, FSCSCY_REG_FAN1_RPMMIN);
-+ data->fan_rpmmin[2] = fscscy_read_value(client, FSCSCY_REG_FAN2_RPMMIN);
-+ data->fan_rpmmin[3] = fscscy_read_value(client, FSCSCY_REG_FAN3_RPMMIN);
-+ data->fan_rpmmin[4] = fscscy_read_value(client, FSCSCY_REG_FAN4_RPMMIN);
-+ data->fan_rpmmin[5] = fscscy_read_value(client, FSCSCY_REG_FAN5_RPMMIN);
-+ data->fan_ripple[0] = fscscy_read_value(client, FSCSCY_REG_FAN0_RIPPLE);
-+ data->fan_ripple[1] = fscscy_read_value(client, FSCSCY_REG_FAN1_RIPPLE);
-+ data->fan_ripple[2] = fscscy_read_value(client, FSCSCY_REG_FAN2_RIPPLE);
-+ data->fan_ripple[3] = fscscy_read_value(client, FSCSCY_REG_FAN3_RIPPLE);
-+ data->fan_ripple[4] = fscscy_read_value(client, FSCSCY_REG_FAN4_RIPPLE);
-+ data->fan_ripple[5] = fscscy_read_value(client, FSCSCY_REG_FAN5_RIPPLE);
-+
-+ data->watchdog[0] = fscscy_read_value(client, FSCSCY_REG_WDOG_PRESET);
-+ data->watchdog[1] = fscscy_read_value(client, FSCSCY_REG_WDOG_STATE);
-+ data->watchdog[2] = fscscy_read_value(client, FSCSCY_REG_WDOG_CONTROL);
-+
-+ data->global_event = fscscy_read_value(client, FSCSCY_REG_EVENT_STATE);
-+ data->global_control = fscscy_read_value(client, FSCSCY_REG_CONTROL);
-+ data->pciload = fscscy_read_value(client, FSCSCY_REG_PCILOAD);
-+ data->intr_status = fscscy_read_value(client, FSCSCY_REG_INTR_STATE);
-+ data->intr_control = fscscy_read_value(client, FSCSCY_REG_INTR_CTRL);
-+
-+ data->last_updated = jiffies;
-+ data->valid = 1;
-+ }
-+
-+ up(&data->update_lock);
-+}
-+
-+
-+/* The next few functions are the call-back functions of the /proc/sys and
-+ sysctl files. Which function is used is defined in the ctl_table in
-+ the extra1 field.
-+ Each function must return the magnitude (power of 10 to divide the date
-+ with) if it is called with operation==SENSORS_PROC_REAL_INFO. It must
-+ put a maximum of *nrels elements in results reflecting the data of this
-+ file, and set *nrels to the number it actually put in it, if operation==
-+ SENSORS_PROC_REAL_READ. Finally, it must get upto *nrels elements from
-+ results and write them to the chip, if operations==SENSORS_PROC_REAL_WRITE.
-+ Note that on SENSORS_PROC_REAL_READ, I do not check whether results is
-+ large enough (by checking the incoming value of *nrels). This is not very
-+ good practice, but as long as you put less than about 5 values in results,
-+ you can assume it is large enough. */
-+void fscscy_in(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct fscscy_data *data = client->data;
-+
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 0;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ fscscy_update_client(client);
-+ switch(ctl_name) {
-+ case FSCSCY_SYSCTL_REV:
-+ results[0] = data->revision ;
-+ break;
-+ case FSCSCY_SYSCTL_EVENT:
-+ results[0] = data->global_event & 0x9f; /* MKN */
-+ break;
-+ case FSCSCY_SYSCTL_CONTROL:
-+ results[0] = data->global_control & 0x19; /* MKN */
-+ break;
-+ default:
-+ printk("fscscy: ctl_name %d not supported\n",
-+ ctl_name);
-+ *nrels_mag = 0;
-+ return;
-+ }
-+ *nrels_mag = 1;
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ if((ctl_name == FSCSCY_SYSCTL_CONTROL) && (*nrels_mag >= 1)) {
-+ data->global_control = (data->global_control & 0x18) | (results[0] & 0x01); /* MKN */
-+ printk("fscscy: writing 0x%02x to global_control\n",
-+ data->global_control);
-+ fscscy_write_value(client,FSCSCY_REG_CONTROL,
-+ data->global_control);
-+ }
-+ else
-+ printk("fscscy: writing to chip not supported\n");
-+ }
-+}
-+
-+#define TEMP_FROM_REG(val) (val-128)
-+
-+
-+void fscscy_temp(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct fscscy_data *data = client->data;
-+
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 0;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ fscscy_update_client(client);
-+ switch(ctl_name) {
-+ case FSCSCY_SYSCTL_TEMP0:
-+ results[0] = data->temp_status[0] & 0x03;
-+ results[1] = TEMP_FROM_REG(data->temp_act[0]);
-+ results[2] = TEMP_FROM_REG(data->temp_lim[0]);
-+ results[3] = TEMP_FROM_REG(data->temp_min[0]);
-+ results[4] = TEMP_FROM_REG(data->temp_max[0]);
-+ break;
-+ case FSCSCY_SYSCTL_TEMP1:
-+ results[0] = data->temp_status[1] & 0x03;
-+ results[1] = TEMP_FROM_REG(data->temp_act[1]);
-+ results[2] = TEMP_FROM_REG(data->temp_lim[1]);
-+ results[3] = TEMP_FROM_REG(data->temp_min[1]);
-+ results[4] = TEMP_FROM_REG(data->temp_max[1]);
-+ break;
-+ case FSCSCY_SYSCTL_TEMP2:
-+ results[0] = data->temp_status[2] & 0x03;
-+ results[1] = TEMP_FROM_REG(data->temp_act[2]);
-+ results[2] = TEMP_FROM_REG(data->temp_lim[2]);
-+ results[3] = TEMP_FROM_REG(data->temp_min[2]);
-+ results[4] = TEMP_FROM_REG(data->temp_max[2]);
-+ break;
-+ case FSCSCY_SYSCTL_TEMP3:
-+ results[0] = data->temp_status[3] & 0x03;
-+ results[1] = TEMP_FROM_REG(data->temp_act[3]);
-+ results[2] = TEMP_FROM_REG(data->temp_lim[3]);
-+ results[3] = TEMP_FROM_REG(data->temp_min[3]);
-+ results[4] = TEMP_FROM_REG(data->temp_max[3]);
-+ break;
-+ default:
-+ printk("fscscy: ctl_name %d not supported\n",
-+ ctl_name);
-+ *nrels_mag = 0;
-+ return;
-+ }
-+ *nrels_mag = 5;
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ if(*nrels_mag >= 1) {
-+ switch(ctl_name) {
-+ case FSCSCY_SYSCTL_TEMP0:
-+ data->temp_status[0] =
-+ (data->temp_status[0] & ~0x02)
-+ | (results[0] & 0x02);
-+ printk("fscscy: writing value 0x%02x "
-+ "to temp0_status\n",
-+ data->temp_status[0]);
-+ fscscy_write_value(client,
-+ FSCSCY_REG_TEMP0_STATE,
-+ data->temp_status[0] & 0x02);
-+ break;
-+ case FSCSCY_SYSCTL_TEMP1:
-+ data->temp_status[1] = (data->temp_status[1] & ~0x02) | (results[0] & 0x02);
-+ printk("fscscy: writing value 0x%02x to temp1_status\n", data->temp_status[1]);
-+ fscscy_write_value(client,FSCSCY_REG_TEMP1_STATE,
-+ data->temp_status[1] & 0x02);
-+ break;
-+ case FSCSCY_SYSCTL_TEMP2:
-+ data->temp_status[2] = (data->temp_status[2] & ~0x02) | (results[0] & 0x02);
-+ printk("fscscy: writing value 0x%02x to temp2_status\n", data->temp_status[2]);
-+ fscscy_write_value(client,FSCSCY_REG_TEMP2_STATE,
-+ data->temp_status[2] & 0x02);
-+ break;
-+ case FSCSCY_SYSCTL_TEMP3:
-+ data->temp_status[3] = (data->temp_status[3] & ~0x02) | (results[0] & 0x02);
-+ printk("fscscy: writing value 0x%02x to temp3_status\n", data->temp_status[3]);
-+ fscscy_write_value(client,FSCSCY_REG_TEMP3_STATE,
-+ data->temp_status[3] & 0x02);
-+ break;
-+ default:
-+ printk("fscscy: ctl_name %d not supported\n",ctl_name);
-+ }
-+ }
-+ else
-+ printk("fscscy: writing to chip not supported\n");
-+ }
-+}
-+
-+#define VOLT_FROM_REG(val,mult) (val*mult/255)
-+
-+void fscscy_volt(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct fscscy_data *data = client->data;
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 2;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ fscscy_update_client(client);
-+ switch(ctl_name) {
-+ case FSCSCY_SYSCTL_VOLT0:
-+ results[0] = VOLT_FROM_REG(data->volt[0],1420);
-+ results[1] = VOLT_FROM_REG(data->volt_min[0],1420);
-+ results[2] = VOLT_FROM_REG(data->volt_max[0],1420);
-+ break;
-+ case FSCSCY_SYSCTL_VOLT1:
-+ results[0] = VOLT_FROM_REG(data->volt[1],660);
-+ results[1] = VOLT_FROM_REG(data->volt_min[1],660);
-+ results[2] = VOLT_FROM_REG(data->volt_max[1],660);
-+ break;
-+ case FSCSCY_SYSCTL_VOLT2:
-+ results[0] = VOLT_FROM_REG(data->volt[2],330);
-+ results[1] = VOLT_FROM_REG(data->volt_min[2],330);
-+ results[2] = VOLT_FROM_REG(data->volt_max[2],330);
-+ break;
-+ default:
-+ printk("fscscy: ctl_name %d not supported\n",
-+ ctl_name);
-+ *nrels_mag = 0;
-+ return;
-+ }
-+ *nrels_mag = 3;
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ printk("fscscy: writing to chip not supported\n");
-+ }
-+}
-+
-+void fscscy_fan(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+
-+ switch(ctl_name) {
-+ case FSCSCY_SYSCTL_FAN0:
-+ fscscy_fan_internal(client,operation,ctl_name,nrels_mag,results,
-+ 0,FSCSCY_REG_FAN0_STATE,FSCSCY_REG_FAN0_RPMMIN,
-+ FSCSCY_REG_FAN0_RIPPLE);
-+ break;
-+ case FSCSCY_SYSCTL_FAN1:
-+ fscscy_fan_internal(client,operation,ctl_name,nrels_mag,results,
-+ 1,FSCSCY_REG_FAN1_STATE,FSCSCY_REG_FAN1_RPMMIN,
-+ FSCSCY_REG_FAN1_RIPPLE);
-+ break;
-+ case FSCSCY_SYSCTL_FAN2:
-+ fscscy_fan_internal(client,operation,ctl_name,nrels_mag,results,
-+ 2,FSCSCY_REG_FAN2_STATE,FSCSCY_REG_FAN2_RPMMIN,
-+ FSCSCY_REG_FAN2_RIPPLE);
-+ break;
-+ case FSCSCY_SYSCTL_FAN3:
-+ fscscy_fan_internal(client,operation,ctl_name,nrels_mag,results,
-+ 3,FSCSCY_REG_FAN3_STATE,FSCSCY_REG_FAN3_RPMMIN,
-+ FSCSCY_REG_FAN3_RIPPLE);
-+ break;
-+ case FSCSCY_SYSCTL_FAN4:
-+ fscscy_fan_internal(client,operation,ctl_name,nrels_mag,results,
-+ 4,FSCSCY_REG_FAN4_STATE,FSCSCY_REG_FAN4_RPMMIN,
-+ FSCSCY_REG_FAN4_RIPPLE);
-+ break;
-+ case FSCSCY_SYSCTL_FAN5:
-+ fscscy_fan_internal(client,operation,ctl_name,nrels_mag,results,
-+ 5,FSCSCY_REG_FAN5_STATE,FSCSCY_REG_FAN5_RPMMIN,
-+ FSCSCY_REG_FAN5_RIPPLE);
-+ break;
-+ default:
-+ printk("fscscy: illegal fan nr %d\n",ctl_name);
-+ }
-+}
-+
-+#define RPM_FROM_REG(val) (val*60)
-+
-+void fscscy_fan_internal(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results, int nr,
-+ int reg_state, int reg_min, int reg_ripple )
-+{
-+ struct fscscy_data *data = client->data;
-+
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 0;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ fscscy_update_client(client);
-+ results[0] = data->fan_status[nr] & 0x0f; /* MKN */
-+ results[1] = data->fan_rpmmin[nr];
-+ results[2] = data->fan_ripple[nr] & 0x03;
-+ results[3] = RPM_FROM_REG(data->fan_act[nr]);
-+ results[4] = RPM_FROM_REG(data->fan_min[nr]);
-+ results[5] = RPM_FROM_REG(data->fan_max[nr]);
-+ *nrels_mag = 6;
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ if(*nrels_mag >= 1) {
-+ data->fan_status[nr] = (data->fan_status[nr] & 0x0b) | (results[0] & 0x04); /* MKN */
-+ printk("fscscy: writing value 0x%02x to fan%d_status\n",
-+ data->fan_status[nr],nr);
-+ fscscy_write_value(client,reg_state,
-+ data->fan_status[nr]);
-+ }
-+ if(*nrels_mag >= 2) {
-+ if((results[1] & 0xff) == 0) {
-+ printk("fscscy: fan%d rpmmin 0 not allowed for safety reasons\n",nr);
-+ return;
-+ }
-+ data->fan_rpmmin[nr] = results[1];
-+ printk("fscscy: writing value 0x%02x to fan%d_min\n",
-+ data->fan_rpmmin[nr],nr);
-+ fscscy_write_value(client,reg_min,
-+ data->fan_rpmmin[nr]);
-+ }
-+ if(*nrels_mag >= 3) {
-+ if((results[2] & 0x03) == 0) {
-+ printk("fscscy: fan%d ripple 0 is nonsense/not allowed\n",nr);
-+ return;
-+ }
-+ data->fan_ripple[nr] = results[2] & 0x03;
-+ printk("fscscy: writing value 0x%02x to fan%d_ripple\n",
-+ data->fan_ripple[nr],nr);
-+ fscscy_write_value(client,reg_ripple,
-+ data->fan_ripple[nr]);
-+ }
-+ }
-+}
-+
-+void fscscy_wdog(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct fscscy_data *data = client->data;
-+
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 0;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ fscscy_update_client(client);
-+ results[0] = data->watchdog[0] ;
-+ results[1] = data->watchdog[1] & 0x02;
-+ results[2] = data->watchdog[2] & 0xb0;
-+ *nrels_mag = 3;
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ if (*nrels_mag >= 1) {
-+ data->watchdog[0] = results[0] & 0xff;
-+ printk("fscscy: writing value 0x%02x to wdog_preset\n",
-+ data->watchdog[0]);
-+ fscscy_write_value(client,FSCSCY_REG_WDOG_PRESET,
-+ data->watchdog[0]);
-+ }
-+ if (*nrels_mag >= 2) {
-+ data->watchdog[1] = results[1] & 0x02;
-+ printk("fscscy: writing value 0x%02x to wdog_state\n",
-+ data->watchdog[1]);
-+ fscscy_write_value(client,FSCSCY_REG_WDOG_STATE,
-+ data->watchdog[1]);
-+ }
-+ if (*nrels_mag >= 3) {
-+ data->watchdog[2] = results[2] & 0xb0;
-+ printk("fscscy: writing value 0x%02x to wdog_control\n",
-+ data->watchdog[2]);
-+ fscscy_write_value(client,FSCSCY_REG_WDOG_CONTROL,
-+ data->watchdog[2]);
-+ }
-+ }
-+}
-+
-+void fscscy_pciload(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct fscscy_data *data = client->data;
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 0;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ fscscy_update_client(client);
-+ results[0] = data->pciload;
-+ *nrels_mag = 1;
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ printk("fscscy: writing PCILOAD to chip not supported\n");
-+ }
-+}
-+
-+void fscscy_intrusion(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct fscscy_data *data = client->data;
-+
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 0;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ fscscy_update_client(client);
-+ results[0] = data->intr_control & 0x80;
-+ results[1] = data->intr_status & 0xc0;
-+ *nrels_mag = 2;
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ if (*nrels_mag >= 1) {
-+ data->intr_control = results[0] & 0x80;
-+ printk("fscscy: writing value 0x%02x to intr_control\n",
-+ data->intr_control);
-+ fscscy_write_value(client,FSCSCY_REG_INTR_CTRL,
-+ data->intr_control);
-+ }
-+ }
-+}
-+
-+static int __init sm_fscscy_init(void)
-+{
-+ printk("fscscy.o version %s (%s)\n", LM_VERSION, LM_DATE);
-+ return i2c_add_driver(&fscscy_driver);
-+}
-+
-+static void __exit sm_fscscy_exit(void)
-+{
-+ i2c_del_driver(&fscscy_driver);
-+}
-+
-+
-+
-+MODULE_AUTHOR
-+ ("Martin Knoblauch <mkn@teraport.de> based on work (fscpos) from Hermann Jung <hej@odn.de>");
-+MODULE_DESCRIPTION("fujitsu siemens scylla chip driver");
-+
-+module_init(sm_fscscy_init);
-+module_exit(sm_fscscy_exit);
---- linux-old/drivers/sensors/gl518sm.c Thu Jan 1 00:00:00 1970
-+++ linux/drivers/sensors/gl518sm.c Mon Dec 13 20:18:46 2004
-@@ -0,0 +1,989 @@
-+/*
-+ gl518sm.c - Part of lm_sensors, Linux kernel modules for hardware
-+ monitoring
-+ Copyright (c) 1998, 1999 Frodo Looijaard <frodol@dds.nl>,
-+ Kyösti Mälkki <kmalkki@cc.hut.fi>
-+
-+ 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., 675 Mass Ave, Cambridge, MA 02139, USA.
-+
-+*/
-+
-+#include <linux/module.h>
-+#include <linux/slab.h>
-+#include <linux/i2c.h>
-+#include <linux/i2c-proc.h>
-+#include <linux/init.h>
-+#ifdef __SMP__
-+#include <linux/smp_lock.h>
-+#endif
-+#define LM_DATE "20041007"
-+#define LM_VERSION "2.8.8"
-+
-+MODULE_LICENSE("GPL");
-+
-+/* Addresses to scan */
-+static unsigned short normal_i2c[] = { 0x2c, 0x2d, SENSORS_I2C_END };
-+static unsigned short normal_i2c_range[] = { SENSORS_I2C_END };
-+static unsigned int normal_isa[] = { SENSORS_ISA_END };
-+static unsigned int normal_isa_range[] = { SENSORS_ISA_END };
-+
-+/* Insmod parameters */
-+SENSORS_INSMOD_2(gl518sm_r00, gl518sm_r80);
-+
-+/* Defining this will enable debug messages for the voltage iteration
-+ code used with rev 0 ICs */
-+#undef DEBUG_VIN
-+
-+/* Many GL518 constants specified below */
-+
-+/* The GL518 registers */
-+#define GL518_REG_CHIP_ID 0x00
-+#define GL518_REG_REVISION 0x01
-+#define GL518_REG_VENDOR_ID 0x02
-+#define GL518_REG_CONF 0x03
-+#define GL518_REG_TEMP 0x04
-+#define GL518_REG_TEMP_OVER 0x05
-+#define GL518_REG_TEMP_HYST 0x06
-+#define GL518_REG_FAN_COUNT 0x07
-+#define GL518_REG_FAN_LIMIT 0x08
-+#define GL518_REG_VIN1_LIMIT 0x09
-+#define GL518_REG_VIN2_LIMIT 0x0a
-+#define GL518_REG_VIN3_LIMIT 0x0b
-+#define GL518_REG_VDD_LIMIT 0x0c
-+#define GL518_REG_VIN3 0x0d
-+#define GL518_REG_MISC 0x0f
-+#define GL518_REG_ALARM 0x10
-+#define GL518_REG_MASK 0x11
-+#define GL518_REG_INT 0x12
-+#define GL518_REG_VIN2 0x13
-+#define GL518_REG_VIN1 0x14
-+#define GL518_REG_VDD 0x15
-+
-+
-+/* Conversions. Rounding and limit checking is only done on the TO_REG
-+ variants. Note that you should be a bit careful with which arguments
-+ these macros are called: arguments may be evaluated more than once.
-+ Fixing this is just not worth it. */
-+
-+#define TEMP_TO_REG(val) (SENSORS_LIMIT(((((val)<0?(val)-5:(val)+5) / 10)+119),\
-+ 0,255))
-+#define TEMP_FROM_REG(val) (((val) - 119) * 10)
-+
-+static inline u8 FAN_TO_REG(long rpm, int div)
-+{
-+ if (rpm == 0)
-+ return 255;
-+ rpm = SENSORS_LIMIT(rpm, 1, 1000000);
-+ return SENSORS_LIMIT((960000 + rpm * div / 2) / (rpm * div), 1,
-+ 254);
-+}
-+
-+#define FAN_FROM_REG(val,div) \
-+ ( (val)==0 ? 0 : (val)==255 ? 0 : (960000/((val)*(div))) )
-+
-+#define IN_TO_REG(val) (SENSORS_LIMIT((((val)*10+8)/19),0,255))
-+#define IN_FROM_REG(val) (((val)*19)/10)
-+
-+#define VDD_TO_REG(val) (SENSORS_LIMIT((((val)*10+11)/23),0,255))
-+#define VDD_FROM_REG(val) (((val)*23)/10)
-+
-+#define DIV_TO_REG(val) ((val)==8?3:(val)==4?2:(val)==1?0:1)
-+#define DIV_FROM_REG(val) (1 << (val))
-+
-+#define ALARMS_FROM_REG(val) val
-+
-+#define BEEP_ENABLE_TO_REG(val) ((val)?0:1)
-+#define BEEP_ENABLE_FROM_REG(val) ((val)?0:1)
-+
-+#define BEEPS_TO_REG(val) ((val) & 0x7f)
-+#define BEEPS_FROM_REG(val) ((val) & 0x7f)
-+
-+/* Each client has this additional data */
-+struct gl518_data {
-+ struct i2c_client client;
-+ int sysctl_id;
-+ enum chips type;
-+
-+ struct semaphore update_lock;
-+
-+ int iterate_lock;
-+ int quit_thread;
-+ struct task_struct *thread;
-+ wait_queue_head_t wq;
-+ char valid; /* !=0 if following fields are valid */
-+ unsigned long last_updated; /* In jiffies */
-+ unsigned long last_updated_v00;
-+ /* In jiffies (used only by rev00 chips) */
-+
-+ u8 voltage[4]; /* Register values; [0] = VDD */
-+ u8 voltage_min[4]; /* Register values; [0] = VDD */
-+ u8 voltage_max[4]; /* Register values; [0] = VDD */
-+ u8 iter_voltage[4]; /* Register values; [0] = VDD */
-+ u8 fan[2];
-+ u8 fan_min[2];
-+ u8 temp; /* Register values */
-+ u8 temp_over; /* Register values */
-+ u8 temp_hyst; /* Register values */
-+ u8 alarms, beeps; /* Register value */
-+ u8 alarm_mask; /* Register value */
-+ u8 fan_div[2]; /* Register encoding, shifted right */
-+ u8 beep_enable; /* Boolean */
-+ u8 iterate; /* Voltage iteration mode */
-+};
-+
-+static int gl518_attach_adapter(struct i2c_adapter *adapter);
-+static int gl518_detect(struct i2c_adapter *adapter, int address,
-+ unsigned short flags, int kind);
-+static void gl518_init_client(struct i2c_client *client);
-+static int gl518_detach_client(struct i2c_client *client);
-+
-+static int gl518_read_value(struct i2c_client *client, u8 reg);
-+static int gl518_write_value(struct i2c_client *client, u8 reg, u16 value);
-+static void gl518_update_client(struct i2c_client *client);
-+
-+static void gl518_update_client_rev00(struct i2c_client *client);
-+static void gl518_update_iterate(struct i2c_client *client);
-+
-+static void gl518_vin(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void gl518_fan(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void gl518_temp(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void gl518_fan_div(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void gl518_alarms(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void gl518_beep(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void gl518_fan1off(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void gl518_iterate(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+
-+/* This is the driver that will be inserted */
-+static struct i2c_driver gl518_driver = {
-+ .owner = THIS_MODULE,
-+ .name = "GL518SM sensor chip driver",
-+ .id = I2C_DRIVERID_GL518,
-+ .flags = I2C_DF_NOTIFY,
-+ .attach_adapter = gl518_attach_adapter,
-+ .detach_client = gl518_detach_client,
-+};
-+
-+/* -- SENSORS SYSCTL START -- */
-+
-+#define GL518_SYSCTL_VDD 1000 /* Volts * 100 */
-+#define GL518_SYSCTL_VIN1 1001
-+#define GL518_SYSCTL_VIN2 1002
-+#define GL518_SYSCTL_VIN3 1003
-+#define GL518_SYSCTL_FAN1 1101 /* RPM */
-+#define GL518_SYSCTL_FAN2 1102
-+#define GL518_SYSCTL_TEMP 1200 /* Degrees Celcius * 10 */
-+#define GL518_SYSCTL_FAN_DIV 2000 /* 1, 2, 4 or 8 */
-+#define GL518_SYSCTL_ALARMS 2001 /* bitvector */
-+#define GL518_SYSCTL_BEEP 2002 /* bitvector */
-+#define GL518_SYSCTL_FAN1OFF 2003
-+#define GL518_SYSCTL_ITERATE 2004
-+
-+#define GL518_ALARM_VDD 0x01
-+#define GL518_ALARM_VIN1 0x02
-+#define GL518_ALARM_VIN2 0x04
-+#define GL518_ALARM_VIN3 0x08
-+#define GL518_ALARM_TEMP 0x10
-+#define GL518_ALARM_FAN1 0x20
-+#define GL518_ALARM_FAN2 0x40
-+
-+/* -- SENSORS SYSCTL END -- */
-+
-+/* These files are created for each detected GL518. This is just a template;
-+ though at first sight, you might think we could use a statically
-+ allocated list, we need some way to get back to the parent - which
-+ is done through one of the 'extra' fields which are initialized
-+ when a new copy is allocated. */
-+static ctl_table gl518_dir_table_template[] = {
-+ {GL518_SYSCTL_VIN1, "in1", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &gl518_vin},
-+ {GL518_SYSCTL_VIN2, "in2", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &gl518_vin},
-+ {GL518_SYSCTL_VIN3, "in3", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &gl518_vin},
-+ {GL518_SYSCTL_VDD, "in0", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &gl518_vin},
-+ {GL518_SYSCTL_FAN1, "fan1", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &gl518_fan},
-+ {GL518_SYSCTL_FAN2, "fan2", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &gl518_fan},
-+ {GL518_SYSCTL_TEMP, "temp", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &gl518_temp},
-+ {GL518_SYSCTL_FAN_DIV, "fan_div", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &gl518_fan_div},
-+ {GL518_SYSCTL_ALARMS, "alarms", NULL, 0, 0444, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &gl518_alarms},
-+ {GL518_SYSCTL_BEEP, "beep", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &gl518_beep},
-+ {GL518_SYSCTL_FAN1OFF, "fan1off", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &gl518_fan1off},
-+ {GL518_SYSCTL_ITERATE, "iterate", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &gl518_iterate},
-+ {0}
-+};
-+
-+/* I choose here for semi-static GL518SM allocation. Complete dynamic
-+ allocation could also be used; the code needed for this would probably
-+ take more memory than the datastructure takes now. */
-+#define MAX_GL518_NR 4
-+static struct i2c_client *gl518_list[MAX_GL518_NR];
-+
-+static int gl518_attach_adapter(struct i2c_adapter *adapter)
-+{
-+ return i2c_detect(adapter, &addr_data, gl518_detect);
-+}
-+
-+static int gl518_detect(struct i2c_adapter *adapter, int address,
-+ unsigned short flags, int kind)
-+{
-+ int i;
-+ struct i2c_client *new_client;
-+ struct gl518_data *data;
-+ int err = 0;
-+ const char *type_name = "";
-+ const char *client_name = "";
-+
-+ /* Make sure we aren't probing the ISA bus!! This is just a safety check
-+ at this moment; i2c_detect really won't call us. */
-+#ifdef DEBUG
-+ if (i2c_is_isa_adapter(adapter)) {
-+ printk
-+ ("gl518sm.o: gl518_detect called for an ISA bus adapter?!?\n");
-+ return 0;
-+ }
-+#endif
-+
-+ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA |
-+ I2C_FUNC_SMBUS_WORD_DATA))
-+ goto ERROR0;
-+
-+ /* OK. For now, we presume we have a valid client. We now create the
-+ client structure, even though we cannot fill it completely yet.
-+ But it allows us to access gl518_{read,write}_value. */
-+
-+ if (!(data = kmalloc(sizeof(struct gl518_data), GFP_KERNEL))) {
-+ err = -ENOMEM;
-+ goto ERROR0;
-+ }
-+
-+ new_client = &data->client;
-+ new_client->addr = address;
-+ new_client->data = data;
-+ new_client->adapter = adapter;
-+ new_client->driver = &gl518_driver;
-+ new_client->flags = 0;
-+
-+ /* Now, we do the remaining detection. */
-+
-+ if (kind < 0) {
-+ if (
-+ (gl518_read_value(new_client, GL518_REG_CHIP_ID) !=
-+ 0x80)
-+ || (gl518_read_value(new_client, GL518_REG_CONF) &
-+ 0x80)) goto ERROR1;
-+ }
-+
-+ /* Determine the chip type. */
-+ if (kind <= 0) {
-+ i = gl518_read_value(new_client, GL518_REG_REVISION);
-+ if (i == 0x00)
-+ kind = gl518sm_r00;
-+ else if (i == 0x80)
-+ kind = gl518sm_r80;
-+ else {
-+ if (kind == 0)
-+ printk
-+ ("gl518sm.o: Ignoring 'force' parameter for unknown chip at "
-+ "adapter %d, address 0x%02x\n",
-+ i2c_adapter_id(adapter), address);
-+ goto ERROR1;
-+ }
-+ }
-+
-+ type_name = "gl518sm";
-+ if (kind == gl518sm_r00) {
-+ client_name = "GL518SM Revision 0x00 chip";
-+ } else if (kind == gl518sm_r80) {
-+ client_name = "GL518SM Revision 0x80 chip";
-+ } else {
-+#ifdef DEBUG
-+ printk("gl518sm.o: Internal error: unknown kind (%d)?!?",
-+ kind);
-+#endif
-+ goto ERROR1;
-+ }
-+
-+ /* Fill in the remaining client fields and put it into the global list */
-+ strcpy(new_client->name, client_name);
-+ data->type = kind;
-+
-+ for (i = 0; i < MAX_GL518_NR; i++)
-+ if (!gl518_list[i])
-+ break;
-+ if (i == MAX_GL518_NR) {
-+ printk
-+ ("gl518sm.o: No empty slots left, recompile and heighten "
-+ "MAX_GL518_NR!\n");
-+ err = -ENOMEM;
-+ goto ERROR2;
-+ }
-+ gl518_list[i] = new_client;
-+ new_client->id = i;
-+ data->valid = 0;
-+ init_MUTEX(&data->update_lock);
-+
-+ /* Tell the I2C layer a new client has arrived */
-+ if ((err = i2c_attach_client(new_client)))
-+ goto ERROR3;
-+
-+ /* Register a new directory entry with module sensors */
-+ if ((i = i2c_register_entry((struct i2c_client *) new_client,
-+ type_name,
-+ gl518_dir_table_template)) < 0) {
-+ err = i;
-+ goto ERROR4;
-+ }
-+ data->sysctl_id = i;
-+
-+ /* Initialize the GL518SM chip */
-+ if (kind == gl518sm_r00)
-+ data->iterate = 0;
-+ else
-+ data->iterate = 3;
-+ data->iterate_lock = 0;
-+ data->quit_thread = 0;
-+ data->thread = NULL;
-+ data->alarm_mask = 0xff;
-+ data->voltage[0]=data->voltage[1]=data->voltage[2]=0;
-+ gl518_init_client((struct i2c_client *) new_client);
-+ return 0;
-+
-+/* OK, this is not exactly good programming practice, usually. But it is
-+ very code-efficient in this case. */
-+
-+ ERROR4:
-+ i2c_detach_client(new_client);
-+ ERROR3:
-+ for (i = 0; i < MAX_GL518_NR; i++)
-+ if (new_client == gl518_list[i])
-+ gl518_list[i] = NULL;
-+ ERROR2:
-+ ERROR1:
-+ kfree(data);
-+ ERROR0:
-+ return err;
-+}
-+
-+
-+/* Called when we have found a new GL518SM. It should set limits, etc. */
-+static void gl518_init_client(struct i2c_client *client)
-+{
-+ /* Power-on defaults (bit 7=1) */
-+ gl518_write_value(client, GL518_REG_CONF, 0x80);
-+
-+ /* No noisy output (bit 2=1), Comparator mode (bit 3=0), two fans (bit4=0),
-+ standby mode (bit6=0) */
-+ gl518_write_value(client, GL518_REG_CONF, 0x04);
-+
-+ /* Never interrupts */
-+ gl518_write_value(client, GL518_REG_MASK, 0x00);
-+
-+ /* Clear status register (bit 5=1), start (bit6=1) */
-+ gl518_write_value(client, GL518_REG_CONF, 0x24);
-+ gl518_write_value(client, GL518_REG_CONF, 0x44);
-+}
-+
-+static int gl518_detach_client(struct i2c_client *client)
-+{
-+ int err, i;
-+ struct gl518_data *data = client->data;
-+
-+ i2c_deregister_entry(((struct gl518_data *) (client->data))->
-+ sysctl_id);
-+
-+ if ((err = i2c_detach_client(client))) {
-+ printk
-+ ("gl518sm.o: Client deregistration failed, client not detached.\n");
-+ return err;
-+ }
-+
-+ for (i = 0; i < MAX_GL518_NR; i++)
-+ if (client == gl518_list[i])
-+ break;
-+ if ((i == MAX_GL518_NR)) {
-+ printk("gl518sm.o: Client to detach not found.\n");
-+ return -ENOENT;
-+ }
-+ gl518_list[i] = NULL;
-+
-+ if (data->thread) {
-+ data->quit_thread = 1;
-+ wake_up_interruptible(&data->wq);
-+ }
-+
-+ kfree(client->data);
-+
-+ return 0;
-+}
-+
-+
-+/* Registers 0x07 to 0x0c are word-sized, others are byte-sized
-+ GL518 uses a high-byte first convention, which is exactly opposite to
-+ the usual practice. */
-+static int gl518_read_value(struct i2c_client *client, u8 reg)
-+{
-+ if ((reg >= 0x07) && (reg <= 0x0c))
-+ return swab16(i2c_smbus_read_word_data(client, reg));
-+ else
-+ return i2c_smbus_read_byte_data(client, reg);
-+}
-+
-+/* Registers 0x07 to 0x0c are word-sized, others are byte-sized
-+ GL518 uses a high-byte first convention, which is exactly opposite to
-+ the usual practice. */
-+static int gl518_write_value(struct i2c_client *client, u8 reg, u16 value)
-+{
-+ if ((reg >= 0x07) && (reg <= 0x0c))
-+ return i2c_smbus_write_word_data(client, reg, swab16(value));
-+ else
-+ return i2c_smbus_write_byte_data(client, reg, value);
-+}
-+
-+static void gl518_update_client(struct i2c_client *client)
-+{
-+ struct gl518_data *data = client->data;
-+ int val;
-+
-+ down(&data->update_lock);
-+
-+ if ((jiffies - data->last_updated > HZ + HZ / 2) ||
-+ (jiffies < data->last_updated) || !data->valid) {
-+
-+#ifdef DEBUG
-+ printk("Starting gl518 update\n");
-+#endif
-+
-+ data->alarms = gl518_read_value(client, GL518_REG_INT);
-+ data->beeps = gl518_read_value(client, GL518_REG_ALARM);
-+
-+ val = gl518_read_value(client, GL518_REG_VDD_LIMIT);
-+ data->voltage_min[0] = val & 0xff;
-+ data->voltage_max[0] = (val >> 8) & 0xff;
-+ val = gl518_read_value(client, GL518_REG_VIN1_LIMIT);
-+ data->voltage_min[1] = val & 0xff;
-+ data->voltage_max[1] = (val >> 8) & 0xff;
-+ val = gl518_read_value(client, GL518_REG_VIN2_LIMIT);
-+ data->voltage_min[2] = val & 0xff;
-+ data->voltage_max[2] = (val >> 8) & 0xff;
-+ val = gl518_read_value(client, GL518_REG_VIN3_LIMIT);
-+ data->voltage_min[3] = val & 0xff;
-+ data->voltage_max[3] = (val >> 8) & 0xff;
-+
-+ val = gl518_read_value(client, GL518_REG_FAN_COUNT);
-+ data->fan[0] = (val >> 8) & 0xff;
-+ data->fan[1] = val & 0xff;
-+
-+ val = gl518_read_value(client, GL518_REG_FAN_LIMIT);
-+ data->fan_min[0] = (val >> 8) & 0xff;
-+ data->fan_min[1] = val & 0xff;
-+
-+ data->temp = gl518_read_value(client, GL518_REG_TEMP);
-+ data->temp_over =
-+ gl518_read_value(client, GL518_REG_TEMP_OVER);
-+ data->temp_hyst =
-+ gl518_read_value(client, GL518_REG_TEMP_HYST);
-+
-+ val = gl518_read_value(client, GL518_REG_MISC);
-+ data->fan_div[0] = (val >> 6) & 0x03;
-+ data->fan_div[1] = (val >> 4) & 0x03;
-+
-+ data->alarms &= data->alarm_mask;
-+
-+ val = gl518_read_value(client, GL518_REG_CONF);
-+ data->beep_enable = (val >> 2) & 1;
-+
-+#ifndef DEBUG_VIN
-+ if (data->type != gl518sm_r00) {
-+ data->voltage[0] =
-+ gl518_read_value(client, GL518_REG_VDD);
-+ data->voltage[1] =
-+ gl518_read_value(client, GL518_REG_VIN1);
-+ data->voltage[2] =
-+ gl518_read_value(client, GL518_REG_VIN2);
-+ data->voltage[3] =
-+ gl518_read_value(client, GL518_REG_VIN3);
-+ } else
-+ gl518_update_client_rev00(client);
-+#else
-+ gl518_update_client_rev00(client);
-+#endif
-+
-+ data->last_updated = jiffies;
-+ data->valid = 1;
-+ }
-+
-+ up(&data->update_lock);
-+}
-+
-+/* Here we decide how to run the iteration code.
-+ When called, we trigger the iteration and report the last
-+ measured voltage. No delay for user apps */
-+static void gl518_update_client_rev00(struct i2c_client *client)
-+{
-+ struct gl518_data *data = client->data;
-+ int i;
-+
-+ if (data->iterate == 1) { /* 10 sec delay */
-+ /* as that update is slow, we consider the data valid for 30 seconds */
-+ if (
-+ ((jiffies - data->last_updated_v00 > 30 * HZ)
-+ || (data->alarms & 7)
-+ || (!data->valid)) && (!data->iterate_lock)) {
-+ data->iterate_lock = 1;
-+ gl518_update_iterate(client);
-+ data->iterate_lock = 0;
-+ }
-+ for (i = 0; i < 4; i++)
-+ data->voltage[i] = data->iter_voltage[i];
-+ } else if (data->iterate == 2) { /* show results of last iteration */
-+ for (i = 0; i < 4; i++)
-+ data->voltage[i] = data->iter_voltage[i];
-+ wake_up_interruptible(&data->wq);
-+ } else { /* no iteration */
-+ data->voltage[3] =
-+ gl518_read_value(client, GL518_REG_VIN3);
-+ }
-+}
-+
-+static int gl518_update_thread(void *c)
-+{
-+ struct i2c_client *client = c;
-+ struct gl518_data *data = client->data;
-+
-+#ifdef __SMP__
-+ lock_kernel();
-+#endif
-+ exit_mm(current);
-+ current->session = 1;
-+ current->pgrp = 1;
-+ sigfillset(&current->blocked);
-+ current->fs->umask = 0;
-+ strcpy(current->comm, "gl518sm");
-+
-+ init_waitqueue_head(&(data->wq));
-+ data->thread = current;
-+
-+#ifdef __SMP__
-+ unlock_kernel();
-+#endif
-+
-+ for (;;) {
-+ if (!data->iterate_lock) {
-+ data->iterate_lock = 1;
-+ gl518_update_iterate(client);
-+ data->iterate_lock = 0;
-+ }
-+
-+ if ((data->quit_thread) || signal_pending(current))
-+ break;
-+ interruptible_sleep_on(&data->wq);
-+ }
-+
-+ data->thread = NULL;
-+ data->quit_thread = 0;
-+ return 0;
-+}
-+
-+/* This updates vdd, vin1, vin2 values by doing slow and multiple
-+ comparisons for the GL518SM rev 00 that lacks support for direct
-+ reading of these values. Values are kept in iter_voltage */
-+
-+static void gl518_update_iterate(struct i2c_client *client)
-+{
-+ struct gl518_data *data = client->data;
-+ int i, j, loop_more = 1, min[3], max[3], delta[3];
-+ int alarm, beeps, irqs;
-+
-+#define VIN_REG(c) c==0?GL518_REG_VDD_LIMIT:\
-+ c==1?GL518_REG_VIN1_LIMIT:\
-+ GL518_REG_VIN2_LIMIT
-+
-+ /* disable beeps & irqs for vin0-2 */
-+ beeps = gl518_read_value(client, GL518_REG_ALARM);
-+ irqs = gl518_read_value(client, GL518_REG_MASK);
-+ gl518_write_value(client, GL518_REG_ALARM, beeps & ~0x7);
-+ gl518_write_value(client, GL518_REG_MASK, irqs & ~0x7);
-+
-+ alarm = data->alarms;
-+
-+ for (i = 0; i < 3; i++) {
-+ if (alarm & (1 << i)) {
-+ min[i] = 0;
-+ max[i] = 127;
-+ } else {
-+ min[i] = data->voltage_min[i];
-+ max[i] =
-+ (data->voltage_max[i] +
-+ data->voltage_min[i]) / 2;
-+ }
-+ delta[i] = (max[i] - min[i]) / 2;
-+ }
-+
-+ for (j = 0; (j < 10 && loop_more); j++) {
-+
-+ for (i = 0; i < 3; i++)
-+ gl518_write_value(client, VIN_REG(i),
-+ max[i] << 8 | min[i]);
-+
-+ if ((data->thread) &&
-+ ((data->quit_thread) || signal_pending(current)))
-+ goto finish;
-+
-+ /* we wait now 1.5 seconds before comparing */
-+ current->state = TASK_INTERRUPTIBLE;
-+ schedule_timeout(HZ + HZ / 2);
-+
-+ alarm = gl518_read_value(client, GL518_REG_INT);
-+
-+#ifdef DEBUG_VIN
-+ printk("gl518sm: iteration %2d: %4d%c %4d%c %4d%c\n", j,
-+ max[0], (alarm & 1) ? '!' : ' ',
-+ max[1], (alarm & 2) ? '!' : ' ',
-+ max[2], (alarm & 4) ? '!' : ' ');
-+#endif
-+
-+ for (loop_more = 0, i = 0; i < 3; i++) {
-+ if (alarm & (1 << i))
-+ max[i] += delta[i];
-+ else
-+ max[i] -= delta[i];
-+
-+ if (delta[i])
-+ loop_more++;
-+ delta[i] >>= 1;
-+ }
-+
-+ }
-+
-+ for (i = 0; i < 3; i++)
-+ if (alarm & (1 << i))
-+ max[i]++;
-+
-+#ifdef DEBUG_VIN
-+ printk("gl518sm: final :%5d %5d %5d\n", max[0], max[1],
-+ max[2]);
-+ printk("gl518sm: meter :%5d %5d %5d\n", data->voltage[0],
-+ data->voltage[1], data->voltage[2]);
-+#endif
-+
-+ /* update values, including vin3 */
-+ for (i = 0; i < 3; i++) {
-+ data->iter_voltage[i] = max[i];
-+ }
-+ data->iter_voltage[3] = gl518_read_value(client, GL518_REG_VIN3);
-+ data->last_updated_v00 = jiffies;
-+
-+ finish:
-+
-+ /* reset values */
-+ for (i = 0; i < 3; i++) {
-+ gl518_write_value(client, VIN_REG(i),
-+ data->voltage_max[i] << 8 | data->
-+ voltage_min[i]);
-+ }
-+
-+ gl518_write_value(client, GL518_REG_ALARM, beeps);
-+ gl518_write_value(client, GL518_REG_MASK, irqs);
-+
-+#undef VIN_REG
-+}
-+
-+void gl518_temp(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct gl518_data *data = client->data;
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 1;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ gl518_update_client(client);
-+ results[0] = TEMP_FROM_REG(data->temp_over);
-+ results[1] = TEMP_FROM_REG(data->temp_hyst);
-+ results[2] = TEMP_FROM_REG(data->temp);
-+ *nrels_mag = 3;
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ if (*nrels_mag >= 1) {
-+ data->temp_over = TEMP_TO_REG(results[0]);
-+ gl518_write_value(client, GL518_REG_TEMP_OVER,
-+ data->temp_over);
-+ }
-+ if (*nrels_mag >= 2) {
-+ data->temp_hyst = TEMP_TO_REG(results[1]);
-+ gl518_write_value(client, GL518_REG_TEMP_HYST,
-+ data->temp_hyst);
-+ }
-+ }
-+}
-+
-+void gl518_vin(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct gl518_data *data = client->data;
-+ int nr = ctl_name - GL518_SYSCTL_VDD;
-+ int regnr, old = 0;
-+
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 2;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ gl518_update_client(client);
-+ results[0] = nr ? IN_FROM_REG(data->voltage_min[nr]) :
-+ VDD_FROM_REG(data->voltage_min[nr]);
-+ results[1] = nr ? IN_FROM_REG(data->voltage_max[nr]) :
-+ VDD_FROM_REG(data->voltage_max[nr]);
-+ results[2] = nr ? IN_FROM_REG(data->voltage[nr]) :
-+ VDD_FROM_REG(data->voltage[nr]);
-+ *nrels_mag = 3;
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ regnr =
-+ nr == 0 ? GL518_REG_VDD_LIMIT : nr ==
-+ 1 ? GL518_REG_VIN1_LIMIT : nr ==
-+ 2 ? GL518_REG_VIN2_LIMIT : GL518_REG_VIN3_LIMIT;
-+ if (*nrels_mag == 1)
-+ old = gl518_read_value(client, regnr) & 0xff00;
-+ if (*nrels_mag >= 2) {
-+ data->voltage_max[nr] =
-+ nr ? IN_TO_REG(results[1]) :
-+ VDD_TO_REG(results[1]);
-+ old = data->voltage_max[nr] << 8;
-+ }
-+ if (*nrels_mag >= 1) {
-+ data->voltage_min[nr] =
-+ nr ? IN_TO_REG(results[0]) :
-+ VDD_TO_REG(results[0]);
-+ old |= data->voltage_min[nr];
-+ gl518_write_value(client, regnr, old);
-+ }
-+ }
-+}
-+
-+
-+void gl518_fan(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct gl518_data *data = client->data;
-+ int nr = ctl_name - GL518_SYSCTL_FAN1;
-+ int old;
-+
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 0;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ gl518_update_client(client);
-+ results[0] = FAN_FROM_REG(data->fan_min[nr],
-+ DIV_FROM_REG(data->fan_div[nr]));
-+ results[1] =
-+ FAN_FROM_REG(data->fan[nr],
-+ DIV_FROM_REG(data->fan_div[nr]));
-+ *nrels_mag = 2;
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ if (*nrels_mag >= 1) {
-+ data->fan_min[nr] = FAN_TO_REG(results[0],
-+ DIV_FROM_REG(data->
-+ fan_div
-+ [nr]));
-+ old =
-+ gl518_read_value(client, GL518_REG_FAN_LIMIT);
-+
-+ if (nr == 0) {
-+ old =
-+ (old & 0x00ff) | (data->
-+ fan_min[0] << 8);
-+ if (results[0] == 0)
-+ data->alarm_mask &= ~0x20;
-+ else
-+ data->alarm_mask |= 0x20;
-+ } else {
-+ old = (old & 0xff00) | data->fan_min[1];
-+ if (results[0] == 0)
-+ data->alarm_mask &= ~0x40;
-+ else
-+ data->alarm_mask |= 0x40;
-+ }
-+ gl518_write_value(client, GL518_REG_FAN_LIMIT,
-+ old);
-+ }
-+ }
-+}
-+
-+
-+void gl518_alarms(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct gl518_data *data = client->data;
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 0;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ gl518_update_client(client);
-+ results[0] = ALARMS_FROM_REG(data->alarms);
-+ *nrels_mag = 1;
-+ }
-+}
-+
-+void gl518_beep(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct gl518_data *data = client->data;
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 0;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ gl518_update_client(client);
-+ results[0] = BEEP_ENABLE_FROM_REG(data->beep_enable);
-+ results[1] = BEEPS_FROM_REG(data->beeps);
-+ *nrels_mag = 2;
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ if (*nrels_mag >= 1) {
-+ data->beep_enable = BEEP_ENABLE_TO_REG(results[0]);
-+ gl518_write_value(client, GL518_REG_CONF,
-+ (gl518_read_value(client,
-+ GL518_REG_CONF)
-+ & 0xfb) | (data->
-+ beep_enable << 2));
-+ }
-+ if (*nrels_mag >= 2) {
-+ data->beeps =
-+ BEEPS_TO_REG(results[1]) & data->alarm_mask;
-+ gl518_write_value(client, GL518_REG_ALARM,
-+ data->beeps);
-+ }
-+ }
-+}
-+
-+
-+void gl518_fan_div(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct gl518_data *data = client->data;
-+ int old;
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 0;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ gl518_update_client(client);
-+ results[0] = DIV_FROM_REG(data->fan_div[0]);
-+ results[1] = DIV_FROM_REG(data->fan_div[1]);
-+ *nrels_mag = 2;
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ old = gl518_read_value(client, GL518_REG_MISC);
-+ if (*nrels_mag >= 2) {
-+ data->fan_div[1] = DIV_TO_REG(results[1]);
-+ old = (old & 0xcf) | (data->fan_div[1] << 4);
-+ }
-+ if (*nrels_mag >= 1) {
-+ data->fan_div[0] = DIV_TO_REG(results[0]);
-+ old = (old & 0x3f) | (data->fan_div[0] << 6);
-+ }
-+ gl518_write_value(client, GL518_REG_MISC, old);
-+ }
-+}
-+
-+void gl518_fan1off(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ int old;
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 0;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ results[0] =
-+ ((gl518_read_value(client, GL518_REG_MISC) & 0x08) !=
-+ 0);
-+ results[1] =
-+ ((gl518_read_value(client, GL518_REG_CONF) & 0x10) !=
-+ 0);
-+ *nrels_mag = 2;
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ if (*nrels_mag >= 1) {
-+ old =
-+ gl518_read_value(client,
-+ GL518_REG_MISC) & 0xf7;
-+ if (results[0])
-+ old |= 0x08;
-+ gl518_write_value(client, GL518_REG_MISC, old);
-+ }
-+ if (*nrels_mag >= 2) {
-+ old =
-+ gl518_read_value(client,
-+ GL518_REG_CONF) & 0xef;
-+ if (results[1])
-+ old |= 0x10;
-+ gl518_write_value(client, GL518_REG_CONF, old);
-+ }
-+ }
-+}
-+
-+void gl518_iterate(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct gl518_data *data = client->data;
-+ int i;
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 0;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ results[0] = data->iterate;
-+ *nrels_mag = 1;
-+ } else if (operation == SENSORS_PROC_REAL_WRITE &&
-+ data->type == gl518sm_r00 ) {
-+ if ((*nrels_mag >= 1) && (data->iterate != results[0])) {
-+ data->iterate = results[0];
-+ for (i = 0; i < 4; i++) {
-+ data->voltage[i] = 0;
-+ data->iter_voltage[i] = 0;
-+ }
-+ data->valid = 0;
-+
-+ if ((data->iterate != 2) && (data->thread)) {
-+ data->quit_thread = 1;
-+ wake_up_interruptible(&data->wq);
-+ } else if ((data->iterate == 2) && (!data->thread)) {
-+ init_waitqueue_head(&(data->wq));
-+ kernel_thread(gl518_update_thread,
-+ (void *) client, 0);
-+ }
-+ }
-+ }
-+}
-+
-+static int __init sm_gl518sm_init(void)
-+{
-+ printk("gl518sm.o version %s (%s)\n", LM_VERSION, LM_DATE);
-+ return i2c_add_driver(&gl518_driver);
-+}
-+
-+static void __exit sm_gl518sm_exit(void)
-+{
-+ i2c_del_driver(&gl518_driver);
-+}
-+
-+
-+
-+MODULE_AUTHOR
-+ ("Frodo Looijaard <frodol@dds.nl> and Kyösti Mälkki <kmalkki@cc.hut.fi>");
-+MODULE_DESCRIPTION("GL518SM driver");
-+
-+module_init(sm_gl518sm_init);
-+module_exit(sm_gl518sm_exit);
---- linux-old/drivers/sensors/gl520sm.c Thu Jan 1 00:00:00 1970
-+++ linux/drivers/sensors/gl520sm.c Mon Dec 13 20:18:47 2004
-@@ -0,0 +1,809 @@
-+/*
-+ gl520sm.c - Part of lm_sensors, Linux kernel modules for hardware
-+ monitoring
-+ Copyright (c) 1998, 1999 Frodo Looijaard <frodol@dds.nl>,
-+ Kyösti Mälkki <kmalkki@cc.hut.fi>
-+
-+ 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., 675 Mass Ave, Cambridge, MA 02139, USA.
-+
-+*/
-+
-+#include <linux/module.h>
-+#include <linux/slab.h>
-+#include <linux/i2c.h>
-+#include <linux/i2c-proc.h>
-+#include <linux/init.h>
-+#define LM_DATE "20041007"
-+#define LM_VERSION "2.8.8"
-+
-+MODULE_LICENSE("GPL");
-+
-+/* Addresses to scan */
-+static unsigned short normal_i2c[] = { 0x2c, 0x2d, SENSORS_I2C_END };
-+static unsigned short normal_i2c_range[] = { SENSORS_I2C_END };
-+static unsigned int normal_isa[] = { SENSORS_ISA_END };
-+static unsigned int normal_isa_range[] = { SENSORS_ISA_END };
-+
-+/* Insmod parameters */
-+SENSORS_INSMOD_1(gl520sm);
-+
-+/* Many GL520 constants specified below
-+One of the inputs can be configured as either temp or voltage.
-+That's why _TEMP2 and _VIN4 access the same register
-+*/
-+
-+/* The GL520 registers */
-+#define GL520_REG_CHIP_ID 0x00
-+#define GL520_REG_REVISION 0x01
-+#define GL520_REG_VID 0x02
-+#define GL520_REG_CONF 0x03
-+#define GL520_REG_TEMP1 0x04
-+#define GL520_REG_TEMP1_OVER 0x05
-+#define GL520_REG_TEMP1_HYST 0x06
-+#define GL520_REG_FAN_COUNT 0x07
-+#define GL520_REG_FAN_LIMIT 0x08
-+#define GL520_REG_VIN1_LIMIT 0x09
-+#define GL520_REG_VIN2_LIMIT 0x0a
-+#define GL520_REG_VIN3_LIMIT 0x0b
-+#define GL520_REG_VDD_LIMIT 0x0c
-+#define GL520_REG_VIN3 0x0d
-+#define GL520_REG_VIN4 0x0e
-+#define GL520_REG_TEMP2 0x0e
-+#define GL520_REG_MISC 0x0f
-+#define GL520_REG_ALARM 0x10
-+#define GL520_REG_MASK 0x11
-+#define GL520_REG_INT 0x12
-+#define GL520_REG_VIN2 0x13
-+#define GL520_REG_VIN1 0x14
-+#define GL520_REG_VDD 0x15
-+#define GL520_REG_TEMP2_OVER 0x17
-+#define GL520_REG_VIN4_MAX 0x17
-+#define GL520_REG_TEMP2_HYST 0x18
-+#define GL520_REG_VIN4_MIN 0x18
-+
-+
-+/* Conversions. Rounding and limit checking is only done on the TO_REG
-+ variants. Note that you should be a bit careful with which arguments
-+ these macros are called: arguments may be evaluated more than once.
-+ Fixing this is just not worth it. */
-+
-+#define TEMP_TO_REG(val) (SENSORS_LIMIT(((((val)<0?(val)-5:(val)+5) / 10)+130),\
-+ 0,255))
-+#define TEMP_FROM_REG(val) (((val) - 130) * 10)
-+
-+static inline u8 FAN_TO_REG(long rpm, int div)
-+{
-+ if (rpm == 0)
-+ return 255;
-+ rpm = SENSORS_LIMIT(rpm, 1, 1000000);
-+ return SENSORS_LIMIT((960000 + rpm * div / 2) / (rpm * div), 1,
-+ 254);
-+}
-+
-+#define FAN_FROM_REG(val,div) \
-+ ( (val)==0 ? 0 : (val)==255 ? 0 : (960000/((val)*(div))) )
-+
-+#define IN_TO_REG(val) (SENSORS_LIMIT((((val)*10+8)/19),0,255))
-+#define IN_FROM_REG(val) (((val)*19)/10)
-+
-+#define VDD_TO_REG(val) (SENSORS_LIMIT((((val)*10+11)/23),0,255))
-+#define VDD_FROM_REG(val) (((val)*23)/10)
-+
-+#define DIV_TO_REG(val) ((val)==8?3:(val)==4?2:(val)==1?0:1)
-+#define DIV_FROM_REG(val) (1 << (val))
-+
-+#define ALARMS_FROM_REG(val) val
-+
-+#define BEEP_ENABLE_TO_REG(val) ((val)?0:1)
-+#define BEEP_ENABLE_FROM_REG(val) ((val)?0:1)
-+
-+#define BEEPS_TO_REG(val) (val)
-+#define BEEPS_FROM_REG(val) (val)
-+
-+#define VID_FROM_REG(val) ((val)==0x1f?0:(val)>=0x10?510-(val)*10:\
-+ 205-(val)*5)
-+
-+/* Each client has this additional data */
-+struct gl520_data {
-+ struct i2c_client client;
-+ int sysctl_id;
-+ enum chips type;
-+
-+ struct semaphore update_lock;
-+ char valid; /* !=0 if following fields are valid */
-+ unsigned long last_updated; /* In jiffies */
-+
-+ u8 voltage[5]; /* Register values; [0] = VDD */
-+ u8 voltage_min[5]; /* Register values; [0] = VDD */
-+ u8 voltage_max[5]; /* Register values; [0] = VDD */
-+ u8 fan[2];
-+ u8 fan_min[2];
-+ u8 temp[2]; /* Register values */
-+ u8 temp_over[2]; /* Register values */
-+ u8 temp_hyst[2]; /* Register values */
-+ u8 alarms, beeps, vid; /* Register value */
-+ u8 alarm_mask; /* Register value */
-+ u8 fan_div[2]; /* Register encoding, shifted right */
-+ u8 beep_enable; /* Boolean */
-+ u8 two_temps; /* Boolean */
-+};
-+
-+static int gl520_attach_adapter(struct i2c_adapter *adapter);
-+static int gl520_detect(struct i2c_adapter *adapter, int address,
-+ unsigned short flags, int kind);
-+static void gl520_init_client(struct i2c_client *client);
-+static int gl520_detach_client(struct i2c_client *client);
-+
-+static int gl520_read_value(struct i2c_client *client, u8 reg);
-+static int gl520_write_value(struct i2c_client *client, u8 reg, u16 value);
-+static void gl520_update_client(struct i2c_client *client);
-+
-+static void gl520_vin(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void gl520_vid(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void gl520_fan(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void gl520_temp(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void gl520_fan_div(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void gl520_alarms(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void gl520_beep(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void gl520_fan1off(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void gl520_config(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+
-+/* This is the driver that will be inserted */
-+static struct i2c_driver gl520_driver = {
-+ .owner = THIS_MODULE,
-+ .name = "GL520SM sensor chip driver",
-+ .id = I2C_DRIVERID_GL520,
-+ .flags = I2C_DF_NOTIFY,
-+ .attach_adapter = gl520_attach_adapter,
-+ .detach_client = gl520_detach_client,
-+};
-+/* -- SENSORS SYSCTL START -- */
-+
-+#define GL520_SYSCTL_VDD 1000 /* Volts * 100 */
-+#define GL520_SYSCTL_VIN1 1001
-+#define GL520_SYSCTL_VIN2 1002
-+#define GL520_SYSCTL_VIN3 1003
-+#define GL520_SYSCTL_VIN4 1004
-+#define GL520_SYSCTL_FAN1 1101 /* RPM */
-+#define GL520_SYSCTL_FAN2 1102
-+#define GL520_SYSCTL_TEMP1 1200 /* Degrees Celcius * 10 */
-+#define GL520_SYSCTL_TEMP2 1201 /* Degrees Celcius * 10 */
-+#define GL520_SYSCTL_VID 1300
-+#define GL520_SYSCTL_FAN_DIV 2000 /* 1, 2, 4 or 8 */
-+#define GL520_SYSCTL_ALARMS 2001 /* bitvector */
-+#define GL520_SYSCTL_BEEP 2002 /* bitvector */
-+#define GL520_SYSCTL_FAN1OFF 2003
-+#define GL520_SYSCTL_CONFIG 2004
-+
-+#define GL520_ALARM_VDD 0x01
-+#define GL520_ALARM_VIN1 0x02
-+#define GL520_ALARM_VIN2 0x04
-+#define GL520_ALARM_VIN3 0x08
-+#define GL520_ALARM_TEMP1 0x10
-+#define GL520_ALARM_FAN1 0x20
-+#define GL520_ALARM_FAN2 0x40
-+#define GL520_ALARM_TEMP2 0x80
-+#define GL520_ALARM_VIN4 0x80
-+
-+/* -- SENSORS SYSCTL END -- */
-+
-+/* These files are created for each detected GL520. This is just a template;
-+ though at first sight, you might think we could use a statically
-+ allocated list, we need some way to get back to the parent - which
-+ is done through one of the 'extra' fields which are initialized
-+ when a new copy is allocated. */
-+static ctl_table gl520_dir_table_template[] = {
-+ {GL520_SYSCTL_VIN1, "vin1", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &gl520_vin},
-+ {GL520_SYSCTL_VIN2, "vin2", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &gl520_vin},
-+ {GL520_SYSCTL_VIN3, "vin3", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &gl520_vin},
-+ {GL520_SYSCTL_VIN4, "vin4", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &gl520_vin},
-+ {GL520_SYSCTL_VDD, "vdd", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &gl520_vin},
-+ {GL520_SYSCTL_VID, "vid", NULL, 0, 0444, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &gl520_vid},
-+ {GL520_SYSCTL_FAN1, "fan1", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &gl520_fan},
-+ {GL520_SYSCTL_FAN2, "fan2", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &gl520_fan},
-+ {GL520_SYSCTL_TEMP1, "temp1", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &gl520_temp},
-+ {GL520_SYSCTL_TEMP2, "temp2", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &gl520_temp},
-+ {GL520_SYSCTL_FAN_DIV, "fan_div", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &gl520_fan_div},
-+ {GL520_SYSCTL_ALARMS, "alarms", NULL, 0, 0444, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &gl520_alarms},
-+ {GL520_SYSCTL_BEEP, "beep", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &gl520_beep},
-+ {GL520_SYSCTL_FAN1OFF, "fan1off", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &gl520_fan1off},
-+ {GL520_SYSCTL_CONFIG, "config", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &gl520_config},
-+ {0}
-+};
-+
-+static int gl520_id = 0;
-+
-+static int gl520_attach_adapter(struct i2c_adapter *adapter)
-+{
-+ return i2c_detect(adapter, &addr_data, gl520_detect);
-+}
-+
-+static int gl520_detect(struct i2c_adapter *adapter, int address,
-+ unsigned short flags, int kind)
-+{
-+ int i;
-+ struct i2c_client *new_client;
-+ struct gl520_data *data;
-+ int err = 0;
-+ const char *type_name = "";
-+ char client_name[32];
-+
-+ /* Make sure we aren't probing the ISA bus!! This is just a safety check
-+ at this moment; i2c_detect really won't call us. */
-+#ifdef DEBUG
-+ if (i2c_is_isa_adapter(adapter)) {
-+ printk
-+ ("gl520sm.o: gl520_detect called for an ISA bus adapter?!?\n");
-+ return 0;
-+ }
-+#endif
-+
-+ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA |
-+ I2C_FUNC_SMBUS_WORD_DATA))
-+ goto ERROR0;
-+
-+ /* OK. For now, we presume we have a valid client. We now create the
-+ client structure, even though we cannot fill it completely yet.
-+ But it allows us to access gl520_{read,write}_value. */
-+
-+ if (!(data = kmalloc(sizeof(struct gl520_data), GFP_KERNEL))) {
-+ err = -ENOMEM;
-+ goto ERROR0;
-+ }
-+
-+ new_client = &data->client;
-+ new_client->addr = address;
-+ new_client->data = data;
-+ new_client->adapter = adapter;
-+ new_client->driver = &gl520_driver;
-+ new_client->flags = 0;
-+
-+ /* Determine the chip type. */
-+
-+ if (gl520_read_value(new_client, GL520_REG_CHIP_ID) != 0x20) {
-+ printk
-+ ("gl520sm.o: Ignoring 'force' parameter for unknown chip at "
-+ "adapter %d, address 0x%02x\n",
-+ i2c_adapter_id(adapter), address);
-+ goto ERROR1;
-+ } else {
-+ kind = gl520sm;
-+ }
-+
-+ i = gl520_read_value(new_client, GL520_REG_REVISION);
-+ if (kind == gl520sm) {
-+ type_name = "gl520sm";
-+ sprintf(client_name, "GL520SM Revision %02x chip", i);
-+ } else {
-+#ifdef DEBUG
-+ printk("gl520sm.o: Internal error: unknown kind (%d)?!?",
-+ kind);
-+#endif
-+ goto ERROR1;
-+ }
-+
-+ /* Fill in the remaining client fields and put it into the global list */
-+ strcpy(new_client->name, client_name);
-+ data->type = kind;
-+
-+ new_client->id = gl520_id++;
-+ data->valid = 0;
-+ init_MUTEX(&data->update_lock);
-+
-+ /* Tell the I2C layer a new client has arrived */
-+ if ((err = i2c_attach_client(new_client)))
-+ goto ERROR3;
-+
-+ /* Register a new directory entry with module sensors */
-+ if ((i = i2c_register_entry(new_client,
-+ type_name,
-+ gl520_dir_table_template)) < 0) {
-+ err = i;
-+ goto ERROR4;
-+ }
-+ data->sysctl_id = i;
-+
-+ /* Initialize the GL520SM chip */
-+ data->alarm_mask = 0xff;
-+ gl520_init_client(new_client);
-+ if (data->two_temps)
-+ data->voltage_max[4] = data->voltage_min[4] =
-+ data->voltage[4] = 0;
-+ else
-+ data->temp_hyst[1] = data->temp_over[1] =
-+ data->temp[1] = 0;
-+
-+ return 0;
-+
-+/* OK, this is not exactly good programming practice, usually. But it is
-+ very code-efficient in this case. */
-+
-+ ERROR4:
-+ i2c_detach_client(new_client);
-+ ERROR3:
-+ ERROR1:
-+ kfree(data);
-+ ERROR0:
-+ return err;
-+}
-+
-+
-+/* Called when we have found a new GL520SM. */
-+static void gl520_init_client(struct i2c_client *client)
-+{
-+ struct gl520_data *data = (struct gl520_data *)(client->data);
-+ u8 oldconf, conf;
-+
-+ conf = oldconf = gl520_read_value(client, GL520_REG_CONF);
-+ data->two_temps = !(conf & 0x10);
-+
-+ /* If IRQ# is disabled, we can safely force comparator mode */
-+ if (!(conf & 0x20))
-+ conf &= 0xf7;
-+
-+ /* Enable monitoring if needed */
-+ conf |= 0x40;
-+
-+ if (conf != oldconf)
-+ gl520_write_value(client, GL520_REG_CONF, conf);
-+}
-+
-+static int gl520_detach_client(struct i2c_client *client)
-+{
-+ int err;
-+
-+ i2c_deregister_entry(((struct gl520_data *) (client->data))->
-+ sysctl_id);
-+
-+ if ((err = i2c_detach_client(client))) {
-+ printk
-+ ("gl520sm.o: Client deregistration failed, client not detached.\n");
-+ return err;
-+ }
-+
-+ kfree(client->data);
-+
-+ return 0;
-+}
-+
-+
-+/* Registers 0x07 to 0x0c are word-sized, others are byte-sized
-+ GL520 uses a high-byte first convention, which is exactly opposite to
-+ the usual practice. */
-+static int gl520_read_value(struct i2c_client *client, u8 reg)
-+{
-+ if ((reg >= 0x07) && (reg <= 0x0c))
-+ return swab16(i2c_smbus_read_word_data(client, reg));
-+ else
-+ return i2c_smbus_read_byte_data(client, reg);
-+}
-+
-+/* Registers 0x07 to 0x0c are word-sized, others are byte-sized
-+ GL520 uses a high-byte first convention, which is exactly opposite to
-+ the usual practice. */
-+static int gl520_write_value(struct i2c_client *client, u8 reg, u16 value)
-+{
-+ if ((reg >= 0x07) && (reg <= 0x0c))
-+ return i2c_smbus_write_word_data(client, reg, swab16(value));
-+ else
-+ return i2c_smbus_write_byte_data(client, reg, value);
-+}
-+
-+static void gl520_update_client(struct i2c_client *client)
-+{
-+ struct gl520_data *data = client->data;
-+ int val;
-+
-+ down(&data->update_lock);
-+
-+ if ((jiffies - data->last_updated > HZ + HZ / 2) ||
-+ (jiffies < data->last_updated) || !data->valid) {
-+
-+#ifdef DEBUG
-+ printk("Starting gl520 update\n");
-+#endif
-+
-+ data->alarms = gl520_read_value(client, GL520_REG_INT);
-+ data->beeps = gl520_read_value(client, GL520_REG_ALARM);
-+ data->vid = gl520_read_value(client, GL520_REG_VID) & 0x1f;
-+
-+ val = gl520_read_value(client, GL520_REG_VDD_LIMIT);
-+ data->voltage_min[0] = val & 0xff;
-+ data->voltage_max[0] = (val >> 8) & 0xff;
-+ val = gl520_read_value(client, GL520_REG_VIN1_LIMIT);
-+ data->voltage_min[1] = val & 0xff;
-+ data->voltage_max[1] = (val >> 8) & 0xff;
-+ val = gl520_read_value(client, GL520_REG_VIN2_LIMIT);
-+ data->voltage_min[2] = val & 0xff;
-+ data->voltage_max[2] = (val >> 8) & 0xff;
-+ val = gl520_read_value(client, GL520_REG_VIN3_LIMIT);
-+ data->voltage_min[3] = val & 0xff;
-+ data->voltage_max[3] = (val >> 8) & 0xff;
-+
-+ val = gl520_read_value(client, GL520_REG_FAN_COUNT);
-+ data->fan[0] = (val >> 8) & 0xff;
-+ data->fan[1] = val & 0xff;
-+
-+ val = gl520_read_value(client, GL520_REG_FAN_LIMIT);
-+ data->fan_min[0] = (val >> 8) & 0xff;
-+ data->fan_min[1] = val & 0xff;
-+
-+ data->temp[0] = gl520_read_value(client, GL520_REG_TEMP1);
-+ data->temp_over[0] =
-+ gl520_read_value(client, GL520_REG_TEMP1_OVER);
-+ data->temp_hyst[0] =
-+ gl520_read_value(client, GL520_REG_TEMP1_HYST);
-+
-+ val = gl520_read_value(client, GL520_REG_MISC);
-+ data->fan_div[0] = (val >> 6) & 0x03;
-+ data->fan_div[1] = (val >> 4) & 0x03;
-+
-+ data->alarms &= data->alarm_mask;
-+
-+ val = gl520_read_value(client, GL520_REG_CONF);
-+ data->beep_enable = (val >> 2) & 1;
-+
-+ data->voltage[0] = gl520_read_value(client, GL520_REG_VDD);
-+ data->voltage[1] =
-+ gl520_read_value(client, GL520_REG_VIN1);
-+ data->voltage[2] =
-+ gl520_read_value(client, GL520_REG_VIN2);
-+ data->voltage[3] =
-+ gl520_read_value(client, GL520_REG_VIN3);
-+
-+ /* Temp1 and Vin4 are the same input */
-+ if (data->two_temps) {
-+ data->temp[1] =
-+ gl520_read_value(client, GL520_REG_TEMP2);
-+ data->temp_over[1] =
-+ gl520_read_value(client, GL520_REG_TEMP2_OVER);
-+ data->temp_hyst[1] =
-+ gl520_read_value(client, GL520_REG_TEMP2_HYST);
-+ } else {
-+ data->voltage[4] =
-+ gl520_read_value(client, GL520_REG_VIN4);
-+ data->voltage_min[4] =
-+ gl520_read_value(client, GL520_REG_VIN4_MIN);
-+ data->voltage_max[4] =
-+ gl520_read_value(client, GL520_REG_VIN4_MAX);
-+ }
-+
-+ data->last_updated = jiffies;
-+ data->valid = 1;
-+ }
-+
-+ up(&data->update_lock);
-+}
-+
-+void gl520_temp(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct gl520_data *data = client->data;
-+ int nr = ctl_name - GL520_SYSCTL_TEMP1;
-+ int regnr;
-+
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 1;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ gl520_update_client(client);
-+ results[0] = TEMP_FROM_REG(data->temp_over[nr]);
-+ results[1] = TEMP_FROM_REG(data->temp_hyst[nr]);
-+ results[2] = TEMP_FROM_REG(data->temp[nr]);
-+ *nrels_mag = 3;
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ if ((nr == 1) && (!data->two_temps))
-+ return;
-+ regnr =
-+ nr == 0 ? GL520_REG_TEMP1_OVER : GL520_REG_TEMP2_OVER;
-+ if (*nrels_mag >= 1) {
-+ data->temp_over[nr] = TEMP_TO_REG(results[0]);
-+ gl520_write_value(client, regnr,
-+ data->temp_over[nr]);
-+ }
-+ regnr =
-+ nr == 0 ? GL520_REG_TEMP1_HYST : GL520_REG_TEMP2_HYST;
-+ if (*nrels_mag >= 2) {
-+ data->temp_hyst[nr] = TEMP_TO_REG(results[1]);
-+ gl520_write_value(client, regnr,
-+ data->temp_hyst[nr]);
-+ }
-+ }
-+}
-+
-+void gl520_vin(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct gl520_data *data = client->data;
-+ int nr = ctl_name - GL520_SYSCTL_VDD;
-+ int regnr, old = 0;
-+
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 2;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ gl520_update_client(client);
-+ results[0] = nr ? IN_FROM_REG(data->voltage_min[nr]) :
-+ VDD_FROM_REG(data->voltage_min[nr]);
-+ results[1] = nr ? IN_FROM_REG(data->voltage_max[nr]) :
-+ VDD_FROM_REG(data->voltage_max[nr]);
-+ results[2] = nr ? IN_FROM_REG(data->voltage[nr]) :
-+ VDD_FROM_REG(data->voltage[nr]);
-+ *nrels_mag = 3;
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ if (nr != 4) {
-+ regnr =
-+ nr == 0 ? GL520_REG_VDD_LIMIT : nr ==
-+ 1 ? GL520_REG_VIN1_LIMIT : nr ==
-+ 2 ? GL520_REG_VIN2_LIMIT :
-+ GL520_REG_VIN3_LIMIT;
-+ if (*nrels_mag == 1)
-+ old =
-+ gl520_read_value(client,
-+ regnr) & 0xff00;
-+ if (*nrels_mag >= 2) {
-+ data->voltage_max[nr] =
-+ nr ? IN_TO_REG(results[1]) :
-+ VDD_TO_REG(results[1]);
-+ old = data->voltage_max[nr] << 8;
-+ }
-+ if (*nrels_mag >= 1) {
-+ data->voltage_min[nr] =
-+ nr ? IN_TO_REG(results[0]) :
-+ VDD_TO_REG(results[0]);
-+ old |= data->voltage_min[nr];
-+ gl520_write_value(client, regnr, old);
-+ }
-+ } else if (!data->two_temps) {
-+ if (*nrels_mag == 1)
-+ gl520_write_value(client,
-+ GL520_REG_VIN4_MIN,
-+ IN_TO_REG(results[0]));
-+ if (*nrels_mag >= 2)
-+ gl520_write_value(client,
-+ GL520_REG_VIN4_MAX,
-+ IN_TO_REG(results[1]));
-+ }
-+ }
-+}
-+
-+
-+void gl520_fan(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct gl520_data *data = client->data;
-+ int nr = ctl_name - GL520_SYSCTL_FAN1;
-+ int old;
-+
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 0;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ gl520_update_client(client);
-+ results[0] = FAN_FROM_REG(data->fan_min[nr],
-+ DIV_FROM_REG(data->fan_div[nr]));
-+ results[1] =
-+ FAN_FROM_REG(data->fan[nr],
-+ DIV_FROM_REG(data->fan_div[nr]));
-+ *nrels_mag = 2;
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ if (*nrels_mag >= 1) {
-+ data->fan_min[nr] = FAN_TO_REG(results[0],
-+ DIV_FROM_REG(data->
-+ fan_div
-+ [nr]));
-+ old =
-+ gl520_read_value(client, GL520_REG_FAN_LIMIT);
-+
-+ if (nr == 0) {
-+ old =
-+ (old & 0x00ff) | (data->
-+ fan_min[nr] << 8);
-+ if (results[0] == 0)
-+ data->alarm_mask &= ~0x20;
-+ else
-+ data->alarm_mask |= 0x20;
-+ } else {
-+ old = (old & 0xff00) | data->fan_min[nr];
-+ if (results[0] == 0)
-+ data->alarm_mask &= ~0x40;
-+ else
-+ data->alarm_mask |= 0x40;
-+ }
-+ gl520_write_value(client, GL520_REG_FAN_LIMIT,
-+ old);
-+ }
-+ }
-+}
-+
-+
-+void gl520_alarms(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct gl520_data *data = client->data;
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 0;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ gl520_update_client(client);
-+ results[0] = ALARMS_FROM_REG(data->alarms);
-+ *nrels_mag = 1;
-+ }
-+}
-+
-+void gl520_beep(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct gl520_data *data = client->data;
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 0;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ gl520_update_client(client);
-+ results[0] = BEEP_ENABLE_FROM_REG(data->beep_enable);
-+ results[1] = BEEPS_FROM_REG(data->beeps);
-+ *nrels_mag = 2;
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ if (*nrels_mag >= 1) {
-+ data->beep_enable = BEEP_ENABLE_TO_REG(results[0]);
-+ gl520_write_value(client, GL520_REG_CONF,
-+ (gl520_read_value(client,
-+ GL520_REG_CONF)
-+ & 0xfb) | (data->
-+ beep_enable << 2));
-+ }
-+ if (*nrels_mag >= 2) {
-+ data->beeps =
-+ BEEPS_TO_REG(results[1]) & data->alarm_mask;
-+ gl520_write_value(client, GL520_REG_ALARM,
-+ data->beeps);
-+ }
-+ }
-+}
-+
-+
-+void gl520_fan_div(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct gl520_data *data = client->data;
-+ int old;
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 0;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ gl520_update_client(client);
-+ results[0] = DIV_FROM_REG(data->fan_div[0]);
-+ results[1] = DIV_FROM_REG(data->fan_div[1]);
-+ *nrels_mag = 2;
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ old = gl520_read_value(client, GL520_REG_MISC);
-+ if (*nrels_mag >= 2) {
-+ data->fan_div[1] = DIV_TO_REG(results[1]);
-+ old = (old & 0xcf) | (data->fan_div[1] << 4);
-+ }
-+ if (*nrels_mag >= 1) {
-+ data->fan_div[0] = DIV_TO_REG(results[0]);
-+ old = (old & 0x3f) | (data->fan_div[0] << 6);
-+ }
-+ gl520_write_value(client, GL520_REG_MISC, old);
-+ }
-+}
-+
-+void gl520_vid(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct gl520_data *data = client->data;
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 2;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ gl520_update_client(client);
-+ results[0] = VID_FROM_REG(data->vid);
-+ *nrels_mag = 1;
-+ }
-+}
-+
-+void gl520_fan1off(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ int old;
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 0;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ results[0] =
-+ ((gl520_read_value(client, GL520_REG_MISC) & 0x04) !=
-+ 0);
-+ *nrels_mag = 1;
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ if (*nrels_mag >= 1) {
-+ old =
-+ gl520_read_value(client,
-+ GL520_REG_MISC) & 0xfb;
-+ if (results[0])
-+ old |= 0x04;
-+ gl520_write_value(client, GL520_REG_MISC, old);
-+ }
-+ }
-+}
-+
-+void gl520_config(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct gl520_data *data = client->data;
-+ int old;
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 0;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ results[0] =
-+ ((gl520_read_value(client, GL520_REG_CONF) & 0x10) ==
-+ 0);
-+ data->two_temps = results[0];
-+ *nrels_mag = 1;
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ if (*nrels_mag >= 1) {
-+ old =
-+ gl520_read_value(client,
-+ GL520_REG_CONF) & 0xef;
-+ if (!results[1]) {
-+ old |= 0x10;
-+ data->two_temps = 0;
-+ data->temp_hyst[1] = data->temp_over[1] =
-+ data->temp[1] = 0;
-+ } else {
-+ data->two_temps = 1;
-+ data->voltage_max[4] = data->voltage_min[4] =
-+ data->voltage[4] = 0;
-+ }
-+ gl520_write_value(client, GL520_REG_CONF, old);
-+ }
-+ }
-+}
-+
-+static int __init sm_gl520sm_init(void)
-+{
-+ printk("gl520sm.o version %s (%s)\n", LM_VERSION, LM_DATE);
-+ return i2c_add_driver(&gl520_driver);
-+}
-+
-+static void __exit sm_gl520sm_exit(void)
-+{
-+ i2c_del_driver(&gl520_driver);
-+}
-+
-+
-+
-+MODULE_AUTHOR
-+ ("Frodo Looijaard <frodol@dds.nl> and Kyösti Mälkki <kmalkki@cc.hut.fi>");
-+MODULE_DESCRIPTION("GL520SM driver");
-+
-+module_init(sm_gl520sm_init);
-+module_exit(sm_gl520sm_exit);
---- linux-old/drivers/sensors/it87.c Thu Jan 1 00:00:00 1970
-+++ linux/drivers/sensors/it87.c Mon Dec 13 20:18:47 2004
-@@ -0,0 +1,1128 @@
-+/*
-+ it87.c - Part of lm_sensors, Linux kernel modules for hardware
-+ monitoring.
-+
-+ Supports: IT8705F Super I/O chip w/LPC interface
-+ IT8712F Super I/O chup w/LPC interface & SMbus
-+ Sis950 A clone of the IT8705F
-+
-+ Copyright (c) 2001 Chris Gauthron <chrisg@0-in.com>
-+ Largely inspired by lm78.c of the same package
-+
-+ 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., 675 Mass Ave, Cambridge, MA 02139, USA.
-+*/
-+
-+/*
-+ djg@pdp8.net David Gesswein 7/18/01
-+ Modified to fix bug with not all alarms enabled.
-+ Added ability to read battery voltage and select temperature sensor
-+ type at module load time.
-+*/
-+
-+/*
-+ michael.hufer@gmx.de Michael Hufer 09/07/03
-+ Modified configure (enable/disable) chip reset at module load time.
-+ Added ability to read and set fan pwm registers and the smart
-+ guardian (sg) features of the chip.
-+*/
-+
-+#include <linux/module.h>
-+#include <linux/slab.h>
-+#include <linux/ioport.h>
-+#include <linux/i2c.h>
-+#include <linux/i2c-proc.h>
-+#include <linux/init.h>
-+#include <asm/io.h>
-+#define LM_DATE "20041007"
-+#define LM_VERSION "2.8.8"
-+
-+MODULE_LICENSE("GPL");
-+
-+/* Addresses to scan */
-+static unsigned short normal_i2c[] = { SENSORS_I2C_END };
-+static unsigned short normal_i2c_range[] = { 0x20, 0x2f, SENSORS_I2C_END };
-+static unsigned int normal_isa[] = { 0x0290, SENSORS_ISA_END };
-+static unsigned int normal_isa_range[] = { SENSORS_ISA_END };
-+
-+/* Insmod parameters */
-+SENSORS_INSMOD_4(it87, it8705, it8712, sis950);
-+
-+
-+#define REG 0x2e /* The register to read/write */
-+#define DEV 0x07 /* Register: Logical device select */
-+#define VAL 0x2f /* The value to read/write */
-+#define PME 0x04 /* The device with the fan registers in it */
-+#define DEVID 0x20 /* Register: Device ID */
-+
-+static inline void
-+superio_outb(int reg, int val)
-+{
-+ outb(reg, REG);
-+ outb(val, VAL);
-+}
-+
-+static inline int
-+superio_inb(int reg)
-+{
-+ outb(reg, REG);
-+ return inb(VAL);
-+}
-+
-+static inline void
-+superio_select(void)
-+{
-+ outb(DEV, REG);
-+ outb(PME, VAL);
-+}
-+
-+static inline void
-+superio_enter(void)
-+{
-+ outb(0x87, REG);
-+ outb(0x01, REG);
-+ outb(0x55, REG);
-+ outb(0x55, REG);
-+}
-+
-+static inline void
-+superio_exit(void)
-+{
-+ outb(0x02, REG);
-+ outb(0x02, VAL);
-+}
-+
-+/* just IT8712F for now - this should be extended to support the other
-+ chips as well */
-+#define IT87_DEVID_MATCH(id) ((id) == 0x8712)
-+
-+#define IT87_ACT_REG 0x30
-+#define IT87_BASE_REG 0x60
-+
-+/* Update battery voltage after every reading if true */
-+static int update_vbat = 0;
-+
-+/* Reset the registers on init */
-+static int reset = 0;
-+
-+/* Many IT87 constants specified below */
-+
-+/* Length of ISA address segment */
-+#define IT87_EXTENT 8
-+
-+/* Where are the ISA address/data registers relative to the base address */
-+#define IT87_ADDR_REG_OFFSET 5
-+#define IT87_DATA_REG_OFFSET 6
-+
-+/*----- The IT87 registers -----*/
-+
-+#define IT87_REG_CONFIG 0x00
-+
-+#define IT87_REG_ALARM1 0x01
-+#define IT87_REG_ALARM2 0x02
-+#define IT87_REG_ALARM3 0x03
-+
-+#define IT87_REG_VID 0x0a
-+#define IT87_REG_FAN_DIV 0x0b
-+
-+#define IT87_REG_FAN(nr) (0x0c + (nr))
-+#define IT87_REG_FAN_MIN(nr) (0x0f + (nr))
-+#define IT87_REG_FAN_CTRL 0x13
-+
-+/* pwm and smart guardian registers */
-+
-+#define IT87_REG_FAN_ONOFF 0x14
-+#define IT87_REG_PWM(nr) (0x14 + (nr))
-+#define IT87_REG_SG_TL_OFF(nr) (0x58 + (nr)*8)
-+#define IT87_REG_SG_TL_LOW(nr) (0x59 + (nr)*8)
-+#define IT87_REG_SG_TL_MED(nr) (0x5a + (nr)*8)
-+#define IT87_REG_SG_TL_HI(nr) (0x5b + (nr)*8)
-+#define IT87_REG_SG_TL_OVR(nr) (0x5c + (nr)*8)
-+#define IT87_REG_SG_PWM_LOW(nr) (0x5d + (nr)*8)
-+#define IT87_REG_SG_PWM_MED(nr) (0x5e + (nr)*8)
-+#define IT87_REG_SG_PWM_HI(nr) (0x5f + (nr)*8)
-+
-+/* Monitors: 9 voltage (0 to 7, battery), 3 temp (1 to 3), 3 fan (1 to 3) */
-+
-+#define IT87_REG_VIN(nr) (0x20 + (nr))
-+#define IT87_REG_TEMP(nr) (0x28 + (nr))
-+
-+#define IT87_REG_VIN_MAX(nr) (0x30 + (nr) * 2)
-+#define IT87_REG_VIN_MIN(nr) (0x31 + (nr) * 2)
-+#define IT87_REG_TEMP_HIGH(nr) (0x3e + (nr) * 2)
-+#define IT87_REG_TEMP_LOW(nr) (0x3f + (nr) * 2)
-+
-+#define IT87_REG_I2C_ADDR 0x48
-+
-+#define IT87_REG_VIN_ENABLE 0x50
-+#define IT87_REG_TEMP_ENABLE 0x51
-+
-+#define IT87_REG_CHIPID 0x58
-+
-+/* sensor pin types */
-+#define UNUSED 0
-+#define THERMISTOR 2
-+#define PIIDIODE 3
-+
-+/* Conversions. Limit checking is only done on the TO_REG
-+ variants. Note that you should be a bit careful with which arguments
-+ these macros are called: arguments may be evaluated more than once.
-+ Fixing this is just not worth it. */
-+#define IN_TO_REG(val) (SENSORS_LIMIT((((val) * 10 + 8)/16),0,255))
-+#define IN_FROM_REG(val) (((val) * 16 + 5) / 10)
-+
-+static inline u8 FAN_TO_REG(long rpm, int div)
-+{
-+ if (rpm == 0)
-+ return 255;
-+ rpm = SENSORS_LIMIT(rpm, 1, 1000000);
-+ return SENSORS_LIMIT((1350000 + rpm * div / 2) / (rpm * div), 1,
-+ 254);
-+}
-+
-+#define FAN_FROM_REG(val,div) ((val)==0?-1:(val)==255?0:1350000/((val)*(div)))
-+
-+#define TEMP_TO_REG(val) (SENSORS_LIMIT(((val)<0?(((val)-5)/10):\
-+ ((val)+5)/10),-127,127))
-+#define TEMP_FROM_REG(val) (((val)>0x80?(val)-0x100:(val))*10)
-+
-+#define VID_FROM_REG(val) ((val)==0x1f?0:(val)>=0x10?510-(val)*10:\
-+ 205-(val)*5)
-+#define ALARMS_FROM_REG(val) (val)
-+
-+extern inline u8 DIV_TO_REG(long val)
-+{
-+ u8 i;
-+ for( i = 0; i <= 7; i++ )
-+ {
-+ if( val>>i == 1 )
-+ return i;
-+ }
-+ return 1;
-+}
-+#define DIV_FROM_REG(val) (1 << (val))
-+
-+/* For each registered IT87, we need to keep some data in memory. That
-+ data is pointed to by it87_list[NR]->data. The structure itself is
-+ dynamically allocated, at the same time when a new it87 client is
-+ allocated. */
-+struct it87_data {
-+ struct i2c_client client;
-+ struct semaphore lock;
-+ int sysctl_id;
-+ enum chips type;
-+
-+ struct semaphore update_lock;
-+ char valid; /* !=0 if following fields are valid */
-+ unsigned long last_updated; /* In jiffies */
-+
-+ u8 in[9]; /* Register value */
-+ u8 in_max[9]; /* Register value */
-+ u8 in_min[9]; /* Register value */
-+ u8 fan[3]; /* Register value */
-+ u8 fan_min[3]; /* Register value */
-+ u8 temp[3]; /* Register value */
-+ u8 temp_high[3]; /* Register value */
-+ u8 temp_low[3]; /* Register value */
-+ u8 fan_div[3]; /* Register encoding, shifted right */
-+ u8 vid; /* Register encoding, combined */
-+ u32 alarms; /* Register encoding, combined */
-+ u8 pwm[3]; /* Register value */
-+ u8 fan_ctl[2]; /* Register encoding */
-+ u8 sg_tl[3][5]; /* Register value */
-+ u8 sg_pwm[3][3]; /* Register value */
-+ u8 sens[3]; /* 2 = Thermistor,
-+ 3 = PII/Celeron diode */
-+};
-+
-+
-+static int it87_attach_adapter(struct i2c_adapter *adapter);
-+static int it87_find(int *address);
-+static int it87_detect(struct i2c_adapter *adapter, int address,
-+ unsigned short flags, int kind);
-+static int it87_detach_client(struct i2c_client *client);
-+
-+static int it87_read_value(struct i2c_client *client, u8 register);
-+static int it87_write_value(struct i2c_client *client, u8 register,
-+ u8 value);
-+static void it87_update_client(struct i2c_client *client);
-+static void it87_init_client(struct i2c_client *client);
-+
-+
-+static void it87_in(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results);
-+static void it87_fan(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void it87_temp(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void it87_vid(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void it87_alarms(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void it87_fan_div(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void it87_fan_ctl(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void it87_pwm(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void it87_sgpwm(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void it87_sgtl(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void it87_sens(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+
-+static struct i2c_driver it87_driver = {
-+ .owner = THIS_MODULE,
-+ .name = "IT87xx sensor driver",
-+ .id = I2C_DRIVERID_IT87,
-+ .flags = I2C_DF_NOTIFY,
-+ .attach_adapter = it87_attach_adapter,
-+ .detach_client = it87_detach_client,
-+};
-+
-+static int it87_id = 0;
-+
-+/* The /proc/sys entries */
-+
-+/* -- SENSORS SYSCTL START -- */
-+#define IT87_SYSCTL_IN0 1000 /* Volts * 100 */
-+#define IT87_SYSCTL_IN1 1001
-+#define IT87_SYSCTL_IN2 1002
-+#define IT87_SYSCTL_IN3 1003
-+#define IT87_SYSCTL_IN4 1004
-+#define IT87_SYSCTL_IN5 1005
-+#define IT87_SYSCTL_IN6 1006
-+#define IT87_SYSCTL_IN7 1007
-+#define IT87_SYSCTL_IN8 1008
-+#define IT87_SYSCTL_FAN1 1101 /* Rotations/min */
-+#define IT87_SYSCTL_FAN2 1102
-+#define IT87_SYSCTL_FAN3 1103
-+#define IT87_SYSCTL_TEMP1 1200 /* Degrees Celcius * 10 */
-+#define IT87_SYSCTL_TEMP2 1201 /* Degrees Celcius * 10 */
-+#define IT87_SYSCTL_TEMP3 1202 /* Degrees Celcius * 10 */
-+#define IT87_SYSCTL_VID 1300 /* Volts * 100 */
-+#define IT87_SYSCTL_FAN_DIV 2000 /* 1, 2, 4 or 8 */
-+#define IT87_SYSCTL_ALARMS 2004 /* bitvector */
-+
-+#define IT87_SYSCTL_PWM1 1401
-+#define IT87_SYSCTL_PWM2 1402
-+#define IT87_SYSCTL_PWM3 1403
-+#define IT87_SYSCTL_FAN_CTL 1501
-+#define IT87_SYSCTL_FAN_ON_OFF 1502
-+#define IT87_SYSCTL_SENS1 1601 /* 1, 2, or Beta (3000-5000) */
-+#define IT87_SYSCTL_SENS2 1602
-+#define IT87_SYSCTL_SENS3 1603
-+
-+#define IT87_ALARM_IN0 0x000100
-+#define IT87_ALARM_IN1 0x000200
-+#define IT87_ALARM_IN2 0x000400
-+#define IT87_ALARM_IN3 0x000800
-+#define IT87_ALARM_IN4 0x001000
-+#define IT87_ALARM_IN5 0x002000
-+#define IT87_ALARM_IN6 0x004000
-+#define IT87_ALARM_IN7 0x008000
-+#define IT87_ALARM_FAN1 0x0001
-+#define IT87_ALARM_FAN2 0x0002
-+#define IT87_ALARM_FAN3 0x0004
-+#define IT87_ALARM_TEMP1 0x00010000
-+#define IT87_ALARM_TEMP2 0x00020000
-+#define IT87_ALARM_TEMP3 0x00040000
-+
-+/* -- SENSORS SYSCTL END -- */
-+
-+/* These files are created for each detected IT87. This is just a template;
-+ though at first sight, you might think we could use a statically
-+ allocated list, we need some way to get back to the parent - which
-+ is done through one of the 'extra' fields which are initialized
-+ when a new copy is allocated. */
-+static ctl_table it87_dir_table_template[] = {
-+ {IT87_SYSCTL_IN0, "in0", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &it87_in},
-+ {IT87_SYSCTL_IN1, "in1", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &it87_in},
-+ {IT87_SYSCTL_IN2, "in2", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &it87_in},
-+ {IT87_SYSCTL_IN3, "in3", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &it87_in},
-+ {IT87_SYSCTL_IN4, "in4", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &it87_in},
-+ {IT87_SYSCTL_IN5, "in5", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &it87_in},
-+ {IT87_SYSCTL_IN6, "in6", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &it87_in},
-+ {IT87_SYSCTL_IN7, "in7", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &it87_in},
-+ {IT87_SYSCTL_IN8, "in8", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &it87_in},
-+ {IT87_SYSCTL_FAN1, "fan1", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &it87_fan},
-+ {IT87_SYSCTL_FAN2, "fan2", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &it87_fan},
-+ {IT87_SYSCTL_FAN3, "fan3", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &it87_fan},
-+ {IT87_SYSCTL_TEMP1, "temp1", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &it87_temp},
-+ {IT87_SYSCTL_TEMP2, "temp2", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &it87_temp},
-+ {IT87_SYSCTL_TEMP3, "temp3", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &it87_temp},
-+ {IT87_SYSCTL_VID, "vid", NULL, 0, 0444, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &it87_vid},
-+ {IT87_SYSCTL_FAN_DIV, "fan_div", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &it87_fan_div},
-+ {IT87_SYSCTL_ALARMS, "alarms", NULL, 0, 0444, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &it87_alarms},
-+ {IT87_SYSCTL_FAN_CTL, "fan_ctl", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &it87_fan_ctl},
-+ {IT87_SYSCTL_FAN_ON_OFF, "fan_on_off", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &it87_fan_ctl},
-+ {IT87_SYSCTL_PWM1, "pwm1", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &it87_pwm},
-+ {IT87_SYSCTL_PWM2, "pwm2", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &it87_pwm},
-+ {IT87_SYSCTL_PWM3, "pwm3", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &it87_pwm},
-+ {IT87_SYSCTL_PWM1, "sg_pwm1", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &it87_sgpwm},
-+ {IT87_SYSCTL_PWM2, "sg_pwm2", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &it87_sgpwm},
-+ {IT87_SYSCTL_PWM3, "sg_pwm3", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &it87_sgpwm},
-+ {IT87_SYSCTL_PWM1, "sg_tl1", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &it87_sgtl},
-+ {IT87_SYSCTL_PWM2, "sg_tl2", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &it87_sgtl},
-+ {IT87_SYSCTL_PWM3, "sg_tl3", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &it87_sgtl},
-+ {IT87_SYSCTL_SENS1, "sensor1", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &it87_sens},
-+ {IT87_SYSCTL_SENS2, "sensor2", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &it87_sens},
-+ {IT87_SYSCTL_SENS3, "sensor3", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &it87_sens},
-+ {0}
-+};
-+
-+
-+/* This function is called when:
-+ * it87_driver is inserted (when this module is loaded), for each
-+ available adapter
-+ * when a new adapter is inserted (and it87_driver is still present) */
-+static int it87_attach_adapter(struct i2c_adapter *adapter)
-+{
-+ return i2c_detect(adapter, &addr_data, it87_detect);
-+}
-+
-+static int it87_find(int *address)
-+{
-+ u16 val;
-+
-+ superio_enter();
-+ val = (superio_inb(DEVID) << 8) |
-+ superio_inb(DEVID + 1);
-+ if (!IT87_DEVID_MATCH(val)) {
-+ superio_exit();
-+ return -ENODEV;
-+ }
-+
-+ superio_select();
-+ val = (superio_inb(IT87_BASE_REG) << 8) |
-+ superio_inb(IT87_BASE_REG + 1);
-+ superio_exit();
-+ *address = val & ~(IT87_EXTENT - 1);
-+ if (*address == 0) {
-+ return -ENODEV;
-+ }
-+ return 0;
-+}
-+
-+/* This function is called by i2c_detect */
-+int it87_detect(struct i2c_adapter *adapter, int address,
-+ unsigned short flags, int kind)
-+{
-+ int i;
-+ struct i2c_client *new_client;
-+ struct it87_data *data;
-+ int err = 0;
-+ const char *type_name = "";
-+ const char *client_name = "";
-+ int is_isa = i2c_is_isa_adapter(adapter);
-+
-+ if (!is_isa
-+ && !i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
-+ return 0;
-+
-+ if (is_isa
-+ && check_region(address, IT87_EXTENT))
-+ return 0;
-+
-+ /* Probe whether there is anything available on this address. Already
-+ done for SMBus clients */
-+ if (is_isa && kind < 0) {
-+#define REALLY_SLOW_IO
-+ /* We need the timeouts for at least some IT87-like chips.
-+ But only if we read 'undefined' registers. */
-+ i = inb_p(address + 1);
-+ if (inb_p(address + 2) != i
-+ || inb_p(address + 3) != i
-+ || inb_p(address + 7) != i)
-+ return -ENODEV;
-+#undef REALLY_SLOW_IO
-+
-+ /* Let's just hope nothing breaks here */
-+ i = inb_p(address + 5) & 0x7f;
-+ outb_p(~i & 0x7f, address + 5);
-+ if ((inb_p(address + 5) & 0x7f) != (~i & 0x7f)) {
-+ outb_p(i, address + 5);
-+ return -ENODEV;
-+ }
-+ }
-+
-+ /* OK. For now, we presume we have a valid client. We now create the
-+ client structure, even though we cannot fill it completely yet.
-+ But it allows us to access it87_{read,write}_value. */
-+
-+ if (!(data = kmalloc(sizeof(struct it87_data), GFP_KERNEL))) {
-+ err = -ENOMEM;
-+ goto ERROR0;
-+ }
-+
-+ new_client = &data->client;
-+ if (is_isa)
-+ init_MUTEX(&data->lock);
-+ new_client->addr = address;
-+ new_client->data = data;
-+ new_client->adapter = adapter;
-+ new_client->driver = &it87_driver;
-+ new_client->flags = 0;
-+
-+ /* Now, we do the remaining detection. */
-+
-+ if (kind < 0) {
-+ if ((it87_read_value(new_client, IT87_REG_CONFIG) & 0x80)
-+ || (!is_isa
-+ && it87_read_value(new_client, IT87_REG_I2C_ADDR) != address)) {
-+ err = -ENODEV;
-+ goto ERROR1;
-+ }
-+ }
-+
-+ /* Determine the chip type. */
-+ if (kind <= 0) {
-+ i = it87_read_value(new_client, IT87_REG_CHIPID);
-+ if (i == 0x90) {
-+ kind = it87;
-+ }
-+ else {
-+ if (kind == 0)
-+ printk
-+ ("it87.o: Ignoring 'force' parameter for unknown chip at "
-+ "adapter %d, address 0x%02x\n",
-+ i2c_adapter_id(adapter), address);
-+ err = -ENODEV;
-+ goto ERROR1;
-+ }
-+ }
-+
-+ if (kind == it87) {
-+ type_name = "it87";
-+ client_name = "IT87 chip";
-+ } /* else if (kind == it8712) {
-+ type_name = "it8712";
-+ client_name = "IT87-J chip";
-+ } */ else {
-+#ifdef DEBUG
-+ printk("it87.o: Internal error: unknown kind (%d)?!?",
-+ kind);
-+#endif
-+ goto ERROR1;
-+ }
-+
-+ /* Reserve the ISA region */
-+ if (is_isa)
-+ request_region(address, IT87_EXTENT, type_name);
-+
-+ /* Fill in the remaining client fields and put it into the global list */
-+ strcpy(new_client->name, client_name);
-+ data->type = kind;
-+
-+ new_client->id = it87_id++;
-+ data->valid = 0;
-+ init_MUTEX(&data->update_lock);
-+
-+ /* Tell the I2C layer a new client has arrived */
-+ if ((err = i2c_attach_client(new_client)))
-+ goto ERROR3;
-+
-+ /* Register a new directory entry with module sensors */
-+ if ((i = i2c_register_entry(new_client,
-+ type_name,
-+ it87_dir_table_template)) < 0) {
-+ err = i;
-+ goto ERROR4;
-+ }
-+ data->sysctl_id = i;
-+
-+ /* Initialize the IT87 chip */
-+ it87_init_client(new_client);
-+ return 0;
-+
-+/* OK, this is not exactly good programming practice, usually. But it is
-+ very code-efficient in this case. */
-+
-+ ERROR4:
-+ i2c_detach_client(new_client);
-+ ERROR3:
-+ if (is_isa)
-+ release_region(address, IT87_EXTENT);
-+ ERROR1:
-+ kfree(data);
-+ ERROR0:
-+ return err;
-+}
-+
-+static int it87_detach_client(struct i2c_client *client)
-+{
-+ int err;
-+
-+ i2c_deregister_entry(((struct it87_data *) (client->data))->
-+ sysctl_id);
-+
-+ if ((err = i2c_detach_client(client))) {
-+ printk
-+ ("it87.o: Client deregistration failed, client not detached.\n");
-+ return err;
-+ }
-+
-+ if(i2c_is_isa_client(client))
-+ release_region(client->addr, IT87_EXTENT);
-+ kfree(client->data);
-+
-+ return 0;
-+}
-+
-+/* The SMBus locks itself, but ISA access must be locked explicitely!
-+ We don't want to lock the whole ISA bus, so we lock each client
-+ separately.
-+ We ignore the IT87 BUSY flag at this moment - it could lead to deadlocks,
-+ would slow down the IT87 access and should not be necessary.
-+ There are some ugly typecasts here, but the good new is - they should
-+ nowhere else be necessary! */
-+static int it87_read_value(struct i2c_client *client, u8 reg)
-+{
-+ int res;
-+ if (i2c_is_isa_client(client)) {
-+ down(&(((struct it87_data *) (client->data))->lock));
-+ outb_p(reg, client->addr + IT87_ADDR_REG_OFFSET);
-+ res = inb_p(client->addr + IT87_DATA_REG_OFFSET);
-+ up(&(((struct it87_data *) (client->data))->lock));
-+ return res;
-+ } else
-+ return i2c_smbus_read_byte_data(client, reg);
-+}
-+
-+/* The SMBus locks itself, but ISA access muse be locked explicitely!
-+ We don't want to lock the whole ISA bus, so we lock each client
-+ separately.
-+ We ignore the IT87 BUSY flag at this moment - it could lead to deadlocks,
-+ would slow down the IT87 access and should not be necessary.
-+ There are some ugly typecasts here, but the good new is - they should
-+ nowhere else be necessary! */
-+static int it87_write_value(struct i2c_client *client, u8 reg, u8 value)
-+{
-+ if (i2c_is_isa_client(client)) {
-+ down(&(((struct it87_data *) (client->data))->lock));
-+ outb_p(reg, client->addr + IT87_ADDR_REG_OFFSET);
-+ outb_p(value, client->addr + IT87_DATA_REG_OFFSET);
-+ up(&(((struct it87_data *) (client->data))->lock));
-+ return 0;
-+ } else
-+ return i2c_smbus_write_byte_data(client, reg, value);
-+}
-+
-+/* Called when we have found a new IT87. */
-+static void it87_init_client(struct i2c_client *client)
-+{
-+ int tmp;
-+
-+ if (reset) {
-+ /* Reset all except Watchdog values and last conversion values
-+ This sets fan-divs to 2, among others */
-+ it87_write_value(client, IT87_REG_CONFIG, 0x80);
-+ }
-+
-+ /* Check if temperature channnels are reset manually or by some reason */
-+ tmp = it87_read_value(client, IT87_REG_TEMP_ENABLE);
-+ if ((tmp & 0x3f) == 0) {
-+ /* Temp1,Temp3=thermistor; Temp2=thermal diode */
-+ tmp = (tmp & 0xc0) | 0x2a;
-+ it87_write_value(client, IT87_REG_TEMP_ENABLE, tmp);
-+ }
-+
-+ /* Check if voltage monitors are reset manually or by some reason */
-+ tmp = it87_read_value(client, IT87_REG_VIN_ENABLE);
-+ if ((tmp & 0xff) == 0) {
-+ /* Enable all voltage monitors */
-+ it87_write_value(client, IT87_REG_VIN_ENABLE, 0xff);
-+ }
-+
-+ /* Check if tachometers are reset manually or by some reason */
-+ tmp = it87_read_value(client, IT87_REG_FAN_CTRL);
-+ if ((tmp & 0x70) == 0) {
-+ /* Enable all fan tachometers */
-+ tmp = (tmp & 0x8f) | 0x70;
-+ it87_write_value(client, IT87_REG_FAN_CTRL, tmp);
-+ }
-+
-+ /* Start monitoring */
-+ it87_write_value(client, IT87_REG_CONFIG,
-+ (it87_read_value(client, IT87_REG_CONFIG) & 0x36)
-+ | (update_vbat ? 0x41 : 0x01));
-+}
-+
-+static void it87_update_client(struct i2c_client *client)
-+{
-+ struct it87_data *data = client->data;
-+ int i, tmp, tmp2;
-+
-+ down(&data->update_lock);
-+
-+ if ((jiffies - data->last_updated > HZ + HZ / 2) ||
-+ (jiffies < data->last_updated) || !data->valid) {
-+
-+ if (update_vbat) {
-+ /* Cleared after each update, so reenable. Value
-+ returned by this read will be previous value */
-+ it87_write_value(client, IT87_REG_CONFIG,
-+ it87_read_value(client, IT87_REG_CONFIG) | 0x40);
-+ }
-+ for (i = 0; i <= 7; i++) {
-+ data->in[i] =
-+ it87_read_value(client, IT87_REG_VIN(i));
-+ data->in_min[i] =
-+ it87_read_value(client, IT87_REG_VIN_MIN(i));
-+ data->in_max[i] =
-+ it87_read_value(client, IT87_REG_VIN_MAX(i));
-+ }
-+ data->in[8] =
-+ it87_read_value(client, IT87_REG_VIN(8));
-+ /* VBAT sensor doesn't have limit registers, set
-+ to min and max value */
-+ data->in_min[8] = 0;
-+ data->in_max[8] = 255;
-+
-+ for (i = 1; i <= 3; i++) {
-+ data->fan[i - 1] =
-+ it87_read_value(client, IT87_REG_FAN(i));
-+ data->fan_min[i - 1] =
-+ it87_read_value(client, IT87_REG_FAN_MIN(i));
-+ }
-+ for (i = 1; i <= 3; i++) {
-+ data->temp[i - 1] =
-+ it87_read_value(client, IT87_REG_TEMP(i));
-+ data->temp_high[i - 1] =
-+ it87_read_value(client, IT87_REG_TEMP_HIGH(i));
-+ data->temp_low[i - 1] =
-+ it87_read_value(client, IT87_REG_TEMP_LOW(i));
-+ }
-+
-+ /* The 8705 does not have VID capability */
-+ /*if (data->type == it8712) {
-+ data->vid = it87_read_value(client, IT87_REG_VID);
-+ data->vid &= 0x1f;
-+ }
-+ else */ {
-+ data->vid = 0x1f;
-+ }
-+
-+ i = it87_read_value(client, IT87_REG_FAN_DIV);
-+ data->fan_div[0] = i & 0x07;
-+ data->fan_div[1] = (i >> 3) & 0x07;
-+ data->fan_div[2] = ( (i&0x40)==0x40 ? 3 : 1 );
-+
-+ for( i = 1; i <= 3; i++ ) {
-+ data->pwm[i-1] = it87_read_value(client, IT87_REG_PWM(i));
-+ data->sg_tl[i-1][0] = it87_read_value(client, IT87_REG_SG_TL_OFF(i));
-+ data->sg_tl[i-1][1] = it87_read_value(client, IT87_REG_SG_TL_LOW(i));
-+ data->sg_tl[i-1][2] = it87_read_value(client, IT87_REG_SG_TL_MED(i));
-+ data->sg_tl[i-1][3] = it87_read_value(client, IT87_REG_SG_TL_HI(i));
-+ data->sg_tl[i-1][4] = it87_read_value(client, IT87_REG_SG_TL_OVR(i));
-+ data->sg_pwm[i-1][0] = it87_read_value(client, IT87_REG_SG_PWM_LOW(i));
-+ data->sg_pwm[i-1][1] = it87_read_value(client, IT87_REG_SG_PWM_MED(i));
-+ data->sg_pwm[i-1][2] = it87_read_value(client, IT87_REG_SG_PWM_HI(i));
-+ }
-+ data->alarms =
-+ it87_read_value(client, IT87_REG_ALARM1) |
-+ (it87_read_value(client, IT87_REG_ALARM2) << 8) |
-+ (it87_read_value(client, IT87_REG_ALARM3) << 16);
-+ data->fan_ctl[0] = it87_read_value(client, IT87_REG_FAN_CTRL);
-+ data->fan_ctl[1] = it87_read_value(client, IT87_REG_FAN_ONOFF);
-+
-+ tmp = it87_read_value(client, IT87_REG_TEMP_ENABLE);
-+ for(i = 0; i < 3; i++) {
-+ tmp2 = (tmp >> i) & 0x09;
-+ if(tmp2 == 0x01)
-+ data->sens[i] = PIIDIODE;
-+ else if(tmp2 == 0x08)
-+ data->sens[i] = THERMISTOR;
-+ else
-+ data->sens[i] = UNUSED;
-+ }
-+
-+ data->last_updated = jiffies;
-+ data->valid = 1;
-+ }
-+
-+ up(&data->update_lock);
-+}
-+
-+
-+/* The next few functions are the call-back functions of the /proc/sys and
-+ sysctl files. Which function is used is defined in the ctl_table in
-+ the extra1 field.
-+ - Each function must return the magnitude (power of 10 to divide the
-+ data with) if it is called with operation==SENSORS_PROC_REAL_INFO.
-+ - It must put a maximum of *nrels elements in results reflecting the
-+ data of this file, and set *nrels to the number it actually put
-+ in it, if operation==SENSORS_PROC_REAL_READ.
-+ - Finally, it must get upto *nrels elements from results and write them
-+ to the chip, if operations==SENSORS_PROC_REAL_WRITE.
-+ Note that on SENSORS_PROC_REAL_READ, I do not check whether results is
-+ large enough (by checking the incoming value of *nrels). This is not very
-+ good practice, but as long as you put less than about 5 values in results,
-+ you can assume it is large enough. */
-+void it87_in(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct it87_data *data = client->data;
-+ int nr = ctl_name - IT87_SYSCTL_IN0;
-+
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 2;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ it87_update_client(client);
-+ results[0] = IN_FROM_REG(data->in_min[nr]);
-+ results[1] = IN_FROM_REG(data->in_max[nr]);
-+ results[2] = IN_FROM_REG(data->in[nr]);
-+ *nrels_mag = 3;
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ if (*nrels_mag >= 1) {
-+ data->in_min[nr] = IN_TO_REG(results[0]);
-+ it87_write_value(client, IT87_REG_VIN_MIN(nr),
-+ data->in_min[nr]);
-+ }
-+ if (*nrels_mag >= 2) {
-+ data->in_max[nr] = IN_TO_REG(results[1]);
-+ it87_write_value(client, IT87_REG_VIN_MAX(nr),
-+ data->in_max[nr]);
-+ }
-+ }
-+}
-+
-+void it87_fan(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct it87_data *data = client->data;
-+ int nr = ctl_name - IT87_SYSCTL_FAN1 + 1;
-+
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 0;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ it87_update_client(client);
-+ results[0] = FAN_FROM_REG(data->fan_min[nr - 1],
-+ DIV_FROM_REG(data->fan_div[nr - 1]));
-+ results[1] = FAN_FROM_REG(data->fan[nr - 1],
-+ DIV_FROM_REG(data->fan_div[nr - 1]));
-+ *nrels_mag = 2;
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ if (*nrels_mag >= 1) {
-+ data->fan_min[nr - 1] = FAN_TO_REG(results[0],
-+ DIV_FROM_REG(data->fan_div[nr - 1]));
-+ it87_write_value(client, IT87_REG_FAN_MIN(nr),
-+ data->fan_min[nr - 1]);
-+ }
-+ }
-+}
-+
-+
-+void it87_temp(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct it87_data *data = client->data;
-+ int nr = ctl_name - IT87_SYSCTL_TEMP1 + 1;
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 1;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ it87_update_client(client);
-+ results[0] = TEMP_FROM_REG(data->temp_high[nr - 1]);
-+ results[1] = TEMP_FROM_REG(data->temp_low[nr - 1]);
-+ results[2] = TEMP_FROM_REG(data->temp[nr - 1]);
-+ *nrels_mag = 3;
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ if (*nrels_mag >= 1) {
-+ data->temp_high[nr - 1] = TEMP_TO_REG(results[0]);
-+ it87_write_value(client, IT87_REG_TEMP_HIGH(nr),
-+ data->temp_high[nr - 1]);
-+ }
-+ if (*nrels_mag >= 2) {
-+ data->temp_low[nr - 1] = TEMP_TO_REG(results[1]);
-+ it87_write_value(client, IT87_REG_TEMP_LOW(nr),
-+ data->temp_low[nr - 1]);
-+ }
-+ }
-+}
-+
-+void it87_pwm(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct it87_data *data = client->data;
-+ int nr = ctl_name - IT87_SYSCTL_PWM1 + 1;
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 0;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ it87_update_client(client);
-+ results[0] = data->pwm[nr - 1];
-+ *nrels_mag = 1;
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ if (*nrels_mag >= 1) {
-+ data->pwm[nr - 1] = results[0];
-+ it87_write_value(client, IT87_REG_PWM(nr), data->pwm[nr - 1]);
-+ }
-+ }
-+}
-+
-+void it87_sgpwm(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct it87_data *data = client->data;
-+ int nr = ctl_name - IT87_SYSCTL_PWM1 + 1;
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 0;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ it87_update_client(client);
-+ results[0] = data->sg_pwm[nr - 1][0];
-+ results[1] = data->sg_pwm[nr - 1][1];
-+ results[2] = data->sg_pwm[nr - 1][2];
-+ *nrels_mag = 3;
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ if (*nrels_mag >= 1) {
-+ data->sg_pwm[nr - 1][0] = results[0];
-+ it87_write_value(client, IT87_REG_SG_PWM_LOW(nr), data->sg_pwm[nr - 1][0]);
-+ }
-+ if (*nrels_mag >= 2) {
-+ data->sg_pwm[nr - 1][1] = results[1];
-+ it87_write_value(client, IT87_REG_SG_PWM_MED(nr), data->sg_pwm[nr - 1][1]);
-+ }
-+ if (*nrels_mag >= 3) {
-+ data->sg_pwm[nr - 1][2] = results[2];
-+ it87_write_value(client, IT87_REG_SG_PWM_HI(nr), data->sg_pwm[nr - 1][2]);
-+ }
-+ }
-+}
-+
-+void it87_sgtl(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct it87_data *data = client->data;
-+ int nr = ctl_name - IT87_SYSCTL_PWM1 + 1;
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 1;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ it87_update_client(client);
-+ results[0] = TEMP_FROM_REG(data->sg_tl[nr - 1][0]);
-+ results[1] = TEMP_FROM_REG(data->sg_tl[nr - 1][1]);
-+ results[2] = TEMP_FROM_REG(data->sg_tl[nr - 1][2]);
-+ results[3] = TEMP_FROM_REG(data->sg_tl[nr - 1][3]);
-+ results[4] = TEMP_FROM_REG(data->sg_tl[nr - 1][4]);
-+ *nrels_mag = 5;
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ if (*nrels_mag >= 1) {
-+ data->sg_tl[nr - 1][0] = TEMP_TO_REG(results[0]);
-+ it87_write_value(client, IT87_REG_SG_TL_OFF(nr), data->sg_tl[nr - 1][0]);
-+ }
-+ if (*nrels_mag >= 2) {
-+ data->sg_tl[nr - 1][1] = TEMP_TO_REG(results[1]);
-+ it87_write_value(client, IT87_REG_SG_TL_LOW(nr), data->sg_tl[nr - 1][1]);
-+ }
-+ if (*nrels_mag >= 3) {
-+ data->sg_tl[nr - 1][2] = TEMP_TO_REG(results[2]);
-+ it87_write_value(client, IT87_REG_SG_TL_MED(nr), data->sg_tl[nr - 1][2]);
-+ }
-+ if (*nrels_mag >= 4) {
-+ data->sg_tl[nr - 1][3] = TEMP_TO_REG(results[3]);
-+ it87_write_value(client, IT87_REG_SG_TL_HI(nr), data->sg_tl[nr - 1][3]);
-+ }
-+ if (*nrels_mag >= 5) {
-+ data->sg_tl[nr - 1][4] = TEMP_TO_REG(results[4]);
-+ it87_write_value(client, IT87_REG_SG_TL_OVR(nr), data->sg_tl[nr - 1][4]);
-+ }
-+ }
-+}
-+
-+void it87_vid(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct it87_data *data = client->data;
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 2;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ it87_update_client(client);
-+ results[0] = VID_FROM_REG(data->vid);
-+ *nrels_mag = 1;
-+ }
-+}
-+
-+void it87_alarms(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results)
-+{
-+ struct it87_data *data = client->data;
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 0;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ it87_update_client(client);
-+ results[0] = ALARMS_FROM_REG(data->alarms);
-+ *nrels_mag = 1;
-+ }
-+}
-+
-+void it87_fan_div(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct it87_data *data = client->data;
-+ int old;
-+
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 0;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ it87_update_client(client);
-+ results[0] = DIV_FROM_REG(data->fan_div[0]);
-+ results[1] = DIV_FROM_REG(data->fan_div[1]);
-+ results[2] = DIV_FROM_REG(data->fan_div[2]);;
-+ *nrels_mag = 3;
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ old = it87_read_value(client, IT87_REG_FAN_DIV);
-+ if (*nrels_mag >= 3) {
-+ data->fan_div[2] = DIV_TO_REG(results[2]);
-+ if( data->fan[2]!=3 ) {
-+ data->fan_div[2] = 1;
-+ old = (old & 0xbf);
-+ } else {
-+ old = (old | 0x40);
-+ }
-+ }
-+ if (*nrels_mag >= 2) {
-+ data->fan_div[1] = DIV_TO_REG(results[1]);
-+ old = (old & 0xc3) | (data->fan_div[1] << 3);
-+ }
-+ if (*nrels_mag >= 1) {
-+ data->fan_div[0] = DIV_TO_REG(results[0]);
-+ old = (old & 0xf8) | data->fan_div[0];
-+ it87_write_value(client, IT87_REG_FAN_DIV, old);
-+ }
-+ }
-+}
-+
-+void it87_fan_ctl(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct it87_data *data = client->data;
-+ int index = ctl_name - IT87_SYSCTL_FAN_CTL;
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 0;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ it87_update_client(client);
-+ results[0] = data->fan_ctl[index];
-+ *nrels_mag = 1;
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ if (*nrels_mag >= 1) {
-+ data->fan_ctl[index] = results[0];
-+ if( index == 0 )
-+ it87_write_value(client, IT87_REG_FAN_CTRL, data->fan_ctl[index] );
-+ else
-+ it87_write_value(client, IT87_REG_FAN_ONOFF, data->fan_ctl[index] );
-+ }
-+ }
-+}
-+
-+void it87_sens(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct it87_data *data = client->data;
-+ int nr = 1 + ctl_name - IT87_SYSCTL_SENS1;
-+ u8 tmp, val1, val2;
-+
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 0;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ results[0] = data->sens[nr - 1];
-+ *nrels_mag = 1;
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ if (*nrels_mag >= 1) {
-+ val1 = 0x01 << (nr - 1);
-+ val2 = 0x08 << (nr - 1);
-+ tmp = it87_read_value(client, IT87_REG_TEMP_ENABLE);
-+ switch (results[0]) {
-+ case PIIDIODE:
-+ tmp &= ~ val2;
-+ tmp |= val1;
-+ break;
-+ case THERMISTOR:
-+ tmp &= ~ val1;
-+ tmp |= val2;
-+ break;
-+ case UNUSED:
-+ tmp &= ~ val1;
-+ tmp &= ~ val2;
-+ break;
-+ default:
-+ printk(KERN_ERR "it87.o: Invalid sensor type %ld; "
-+ "must be 0 (unused), 2 (thermistor) "
-+ "or 3 (diode)\n", results[0]);
-+ return;
-+ }
-+ it87_write_value(client,
-+ IT87_REG_TEMP_ENABLE, tmp);
-+ data->sens[nr - 1] = results[0];
-+ }
-+ }
-+}
-+
-+static int __init sm_it87_init(void)
-+{
-+ int addr;
-+
-+ printk("it87.o version %s (%s)\n", LM_VERSION, LM_DATE);
-+ if (!it87_find(&addr)) {
-+ normal_isa[0] = addr;
-+ }
-+ return i2c_add_driver(&it87_driver);
-+}
-+
-+static void __exit sm_it87_exit(void)
-+{
-+ i2c_del_driver(&it87_driver);
-+}
-+
-+
-+
-+MODULE_AUTHOR("Chris Gauthron <chrisg@0-in.com>");
-+MODULE_DESCRIPTION("IT8705F, IT8712F, Sis950 driver");
-+MODULE_PARM(update_vbat, "i");
-+MODULE_PARM_DESC(update_vbat, "Update vbat if set else return powerup value");
-+MODULE_PARM(reset, "i");
-+MODULE_PARM_DESC(reset, "Reset the chip's registers, default no");
-+
-+module_init(sm_it87_init);
-+module_exit(sm_it87_exit);
---- linux-old/drivers/sensors/lm75.c Thu Jan 1 00:00:00 1970
-+++ linux/drivers/sensors/lm75.c Mon Dec 13 20:18:47 2004
-@@ -0,0 +1,331 @@
-+/*
-+ lm75.c - Part of lm_sensors, Linux kernel modules for hardware
-+ monitoring
-+ Copyright (c) 1998, 1999 Frodo Looijaard <frodol@dds.nl>
-+
-+ 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., 675 Mass Ave, Cambridge, MA 02139, USA.
-+*/
-+
-+#include <linux/module.h>
-+#include <linux/slab.h>
-+#include <linux/i2c.h>
-+#include <linux/i2c-proc.h>
-+#include <linux/init.h>
-+#define LM_DATE "20041007"
-+#define LM_VERSION "2.8.8"
-+#include "lm75.h"
-+
-+/* Addresses to scan */
-+static unsigned short normal_i2c[] = { SENSORS_I2C_END };
-+static unsigned short normal_i2c_range[] = { 0x48, 0x4f, SENSORS_I2C_END };
-+static unsigned int normal_isa[] = { SENSORS_ISA_END };
-+static unsigned int normal_isa_range[] = { SENSORS_ISA_END };
-+
-+/* Insmod parameters */
-+SENSORS_INSMOD_1(lm75);
-+
-+/* Many LM75 constants specified below */
-+
-+/* The LM75 registers */
-+#define LM75_REG_TEMP 0x00
-+#define LM75_REG_CONF 0x01
-+#define LM75_REG_TEMP_HYST 0x02
-+#define LM75_REG_TEMP_OS 0x03
-+
-+/* Each client has this additional data */
-+struct lm75_data {
-+ struct i2c_client client;
-+ int sysctl_id;
-+
-+ struct semaphore update_lock;
-+ char valid; /* !=0 if following fields are valid */
-+ unsigned long last_updated; /* In jiffies */
-+
-+ u16 temp, temp_os, temp_hyst; /* Register values */
-+};
-+
-+static int lm75_attach_adapter(struct i2c_adapter *adapter);
-+static int lm75_detect(struct i2c_adapter *adapter, int address,
-+ unsigned short flags, int kind);
-+static void lm75_init_client(struct i2c_client *client);
-+static int lm75_detach_client(struct i2c_client *client);
-+
-+static int lm75_read_value(struct i2c_client *client, u8 reg);
-+static int lm75_write_value(struct i2c_client *client, u8 reg, u16 value);
-+static void lm75_temp(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void lm75_update_client(struct i2c_client *client);
-+
-+
-+/* This is the driver that will be inserted */
-+static struct i2c_driver lm75_driver = {
-+ .owner = THIS_MODULE,
-+ .name = "LM75 sensor chip driver",
-+ .id = I2C_DRIVERID_LM75,
-+ .flags = I2C_DF_NOTIFY,
-+ .attach_adapter = lm75_attach_adapter,
-+ .detach_client = lm75_detach_client,
-+};
-+
-+/* -- SENSORS SYSCTL START -- */
-+
-+#define LM75_SYSCTL_TEMP 1200 /* Degrees Celcius * 10 */
-+
-+/* -- SENSORS SYSCTL END -- */
-+
-+/* These files are created for each detected LM75. This is just a template;
-+ though at first sight, you might think we could use a statically
-+ allocated list, we need some way to get back to the parent - which
-+ is done through one of the 'extra' fields which are initialized
-+ when a new copy is allocated. */
-+static ctl_table lm75_dir_table_template[] = {
-+ {LM75_SYSCTL_TEMP, "temp", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &lm75_temp},
-+ {0}
-+};
-+
-+static int lm75_id = 0;
-+
-+static int lm75_attach_adapter(struct i2c_adapter *adapter)
-+{
-+ return i2c_detect(adapter, &addr_data, lm75_detect);
-+}
-+
-+/* This function is called by i2c_detect */
-+int lm75_detect(struct i2c_adapter *adapter, int address,
-+ unsigned short flags, int kind)
-+{
-+ int i;
-+ struct i2c_client *new_client;
-+ struct lm75_data *data;
-+ int err = 0;
-+ const char *type_name, *client_name;
-+
-+ /* Make sure we aren't probing the ISA bus!! This is just a safety check
-+ at this moment; i2c_detect really won't call us. */
-+#ifdef DEBUG
-+ if (i2c_is_isa_adapter(adapter)) {
-+ printk
-+ ("lm75.o: lm75_detect called for an ISA bus adapter?!?\n");
-+ return 0;
-+ }
-+#endif
-+
-+ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA |
-+ I2C_FUNC_SMBUS_WORD_DATA))
-+ goto error0;
-+
-+ /* OK. For now, we presume we have a valid client. We now create the
-+ client structure, even though we cannot fill it completely yet.
-+ But it allows us to access lm75_{read,write}_value. */
-+ if (!(data = kmalloc(sizeof(struct lm75_data), GFP_KERNEL))) {
-+ err = -ENOMEM;
-+ goto error0;
-+ }
-+
-+ new_client = &data->client;
-+ new_client->addr = address;
-+ new_client->data = data;
-+ new_client->adapter = adapter;
-+ new_client->driver = &lm75_driver;
-+ new_client->flags = 0;
-+
-+ /* Now, we do the remaining detection. There is no identification-
-+ dedicated register so we have to rely on several tricks:
-+ unused bits, registers cycling over 8-address boundaries,
-+ addresses 0x04-0x07 returning the last read value.
-+ The cycling+unused addresses combination is not tested,
-+ since it would significantly slow the detection down and would
-+ hardly add any value. */
-+ if (kind < 0) {
-+ int cur, conf, hyst, os;
-+
-+ /* Unused addresses */
-+ cur = i2c_smbus_read_word_data(new_client, 0);
-+ conf = i2c_smbus_read_byte_data(new_client, 1);
-+ hyst = i2c_smbus_read_word_data(new_client, 2);
-+ if (i2c_smbus_read_word_data(new_client, 4) != hyst
-+ || i2c_smbus_read_word_data(new_client, 5) != hyst
-+ || i2c_smbus_read_word_data(new_client, 6) != hyst
-+ || i2c_smbus_read_word_data(new_client, 7) != hyst)
-+ goto error1;
-+ os = i2c_smbus_read_word_data(new_client, 3);
-+ if (i2c_smbus_read_word_data(new_client, 4) != os
-+ || i2c_smbus_read_word_data(new_client, 5) != os
-+ || i2c_smbus_read_word_data(new_client, 6) != os
-+ || i2c_smbus_read_word_data(new_client, 7) != os)
-+ goto error1;
-+
-+ /* Unused bits */
-+ if (conf & 0xe0)
-+ goto error1;
-+
-+ /* Addresses cycling */
-+ for (i = 8; i < 0xff; i += 8)
-+ if (i2c_smbus_read_byte_data(new_client, i + 1) != conf
-+ || i2c_smbus_read_word_data(new_client, i + 2) != hyst
-+ || i2c_smbus_read_word_data(new_client, i + 3) != os)
-+ goto error1;
-+ }
-+
-+ /* Determine the chip type - only one kind supported! */
-+ if (kind <= 0)
-+ kind = lm75;
-+
-+ if (kind == lm75) {
-+ type_name = "lm75";
-+ client_name = "LM75 chip";
-+ } else {
-+ pr_debug("lm75.o: Internal error: unknown kind (%d)?!?", kind);
-+ goto error1;
-+ }
-+
-+ /* Fill in the remaining client fields and put it into the global list */
-+ strcpy(new_client->name, client_name);
-+
-+ new_client->id = lm75_id++;
-+ data->valid = 0;
-+ init_MUTEX(&data->update_lock);
-+
-+ /* Tell the I2C layer a new client has arrived */
-+ if ((err = i2c_attach_client(new_client)))
-+ goto error3;
-+
-+ /* Register a new directory entry with module sensors */
-+ if ((i = i2c_register_entry(new_client, type_name,
-+ lm75_dir_table_template)) < 0) {
-+ err = i;
-+ goto error4;
-+ }
-+ data->sysctl_id = i;
-+
-+ lm75_init_client(new_client);
-+ return 0;
-+
-+/* OK, this is not exactly good programming practice, usually. But it is
-+ very code-efficient in this case. */
-+
-+ error4:
-+ i2c_detach_client(new_client);
-+ error3:
-+ error1:
-+ kfree(data);
-+ error0:
-+ return err;
-+}
-+
-+static int lm75_detach_client(struct i2c_client *client)
-+{
-+ struct lm75_data *data = client->data;
-+
-+ i2c_deregister_entry(data->sysctl_id);
-+ i2c_detach_client(client);
-+ kfree(client->data);
-+ return 0;
-+}
-+
-+/* All registers are word-sized, except for the configuration register.
-+ LM75 uses a high-byte first convention, which is exactly opposite to
-+ the usual practice. */
-+static int lm75_read_value(struct i2c_client *client, u8 reg)
-+{
-+ if (reg == LM75_REG_CONF)
-+ return i2c_smbus_read_byte_data(client, reg);
-+ else
-+ return swab16(i2c_smbus_read_word_data(client, reg));
-+}
-+
-+/* All registers are word-sized, except for the configuration register.
-+ LM75 uses a high-byte first convention, which is exactly opposite to
-+ the usual practice. */
-+static int lm75_write_value(struct i2c_client *client, u8 reg, u16 value)
-+{
-+ if (reg == LM75_REG_CONF)
-+ return i2c_smbus_write_byte_data(client, reg, value);
-+ else
-+ return i2c_smbus_write_word_data(client, reg, swab16(value));
-+}
-+
-+static void lm75_init_client(struct i2c_client *client)
-+{
-+ /* Initialize the LM75 chip */
-+ lm75_write_value(client, LM75_REG_CONF, 0);
-+}
-+
-+static void lm75_update_client(struct i2c_client *client)
-+{
-+ struct lm75_data *data = client->data;
-+
-+ down(&data->update_lock);
-+
-+ if ((jiffies - data->last_updated > HZ + HZ / 2) ||
-+ (jiffies < data->last_updated) || !data->valid) {
-+ pr_debug("Starting lm75 update\n");
-+
-+ data->temp = lm75_read_value(client, LM75_REG_TEMP);
-+ data->temp_os = lm75_read_value(client, LM75_REG_TEMP_OS);
-+ data->temp_hyst =
-+ lm75_read_value(client, LM75_REG_TEMP_HYST);
-+ data->last_updated = jiffies;
-+ data->valid = 1;
-+ }
-+
-+ up(&data->update_lock);
-+}
-+
-+
-+void lm75_temp(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct lm75_data *data = client->data;
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 1;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ lm75_update_client(client);
-+ results[0] = LM75_TEMP_FROM_REG(data->temp_os);
-+ results[1] = LM75_TEMP_FROM_REG(data->temp_hyst);
-+ results[2] = LM75_TEMP_FROM_REG(data->temp);
-+ *nrels_mag = 3;
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ if (*nrels_mag >= 1) {
-+ data->temp_os = LM75_TEMP_TO_REG(results[0]);
-+ lm75_write_value(client, LM75_REG_TEMP_OS,
-+ data->temp_os);
-+ }
-+ if (*nrels_mag >= 2) {
-+ data->temp_hyst = LM75_TEMP_TO_REG(results[1]);
-+ lm75_write_value(client, LM75_REG_TEMP_HYST,
-+ data->temp_hyst);
-+ }
-+ }
-+}
-+
-+static int __init sm_lm75_init(void)
-+{
-+ printk(KERN_INFO "lm75.o version %s (%s)\n", LM_VERSION, LM_DATE);
-+ return i2c_add_driver(&lm75_driver);
-+}
-+
-+static void __exit sm_lm75_exit(void)
-+{
-+ i2c_del_driver(&lm75_driver);
-+}
-+
-+MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl>");
-+MODULE_DESCRIPTION("LM75 driver");
-+MODULE_LICENSE("GPL");
-+
-+module_init(sm_lm75_init);
-+module_exit(sm_lm75_exit);
---- linux-old/drivers/sensors/lm75.h Thu Jan 1 00:00:00 1970
-+++ linux/drivers/sensors/lm75.h Mon Dec 13 20:18:47 2004
-@@ -0,0 +1,49 @@
-+/*
-+ lm75.h - Part of lm_sensors, Linux kernel modules for hardware
-+ monitoring
-+ Copyright (c) 2003 Mark M. Hoffman <mhoffman@lightlink.com>
-+
-+ 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., 675 Mass Ave, Cambridge, MA 02139, USA.
-+*/
-+
-+/*
-+ This file contains common code for encoding/decoding LM75 type
-+ temperature readings, which are emulated by many of the chips
-+ we support. As the user is unlikely to load more than one driver
-+ which contains this code, we don't worry about the wasted space.
-+*/
-+
-+#include <linux/i2c-proc.h>
-+
-+/* straight from the datasheet */
-+#define LM75_TEMP_MIN (-550)
-+#define LM75_TEMP_MAX 1250
-+
-+/* TEMP: 0.1C/bit (-55C to +125C)
-+ REG: (0.5C/bit, two's complement) << 7 */
-+static inline u16 LM75_TEMP_TO_REG(int temp)
-+{
-+ int ntemp = SENSORS_LIMIT(temp, LM75_TEMP_MIN, LM75_TEMP_MAX);
-+ ntemp += (ntemp<0 ? -2 : 2);
-+ return (u16)((ntemp / 5) << 7);
-+}
-+
-+static inline int LM75_TEMP_FROM_REG(u16 reg)
-+{
-+ /* use integer division instead of equivalent right shift to
-+ guarantee arithmetic shift and preserve the sign */
-+ return ((s16)reg / 128) * 5;
-+}
-+
---- linux-old/drivers/sensors/lm78.c Thu Jan 1 00:00:00 1970
-+++ linux/drivers/sensors/lm78.c Mon Dec 13 20:18:47 2004
-@@ -0,0 +1,729 @@
-+/*
-+ lm78.c - Part of lm_sensors, Linux kernel modules for hardware
-+ monitoring
-+ Copyright (c) 1998, 1999 Frodo Looijaard <frodol@dds.nl>
-+
-+ 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., 675 Mass Ave, Cambridge, MA 02139, USA.
-+*/
-+
-+#include <linux/module.h>
-+#include <linux/slab.h>
-+#include <linux/ioport.h>
-+#include <linux/i2c.h>
-+#include <linux/i2c-proc.h>
-+#include <linux/init.h>
-+#include <asm/io.h>
-+#define LM_DATE "20041007"
-+#define LM_VERSION "2.8.8"
-+
-+MODULE_LICENSE("GPL");
-+
-+/* Addresses to scan */
-+static unsigned short normal_i2c[] = { SENSORS_I2C_END };
-+static unsigned short normal_i2c_range[] = { 0x20, 0x2f, SENSORS_I2C_END };
-+static unsigned int normal_isa[] = { 0x0290, SENSORS_ISA_END };
-+static unsigned int normal_isa_range[] = { SENSORS_ISA_END };
-+
-+/* Insmod parameters */
-+SENSORS_INSMOD_3(lm78, lm78j, lm79);
-+
-+/* Many LM78 constants specified below */
-+
-+/* Length of ISA address segment */
-+#define LM78_EXTENT 8
-+
-+/* Where are the ISA address/data registers relative to the base address */
-+#define LM78_ADDR_REG_OFFSET 5
-+#define LM78_DATA_REG_OFFSET 6
-+
-+/* The LM78 registers */
-+#define LM78_REG_IN_MAX(nr) (0x2b + (nr) * 2)
-+#define LM78_REG_IN_MIN(nr) (0x2c + (nr) * 2)
-+#define LM78_REG_IN(nr) (0x20 + (nr))
-+
-+#define LM78_REG_FAN_MIN(nr) (0x3a + (nr))
-+#define LM78_REG_FAN(nr) (0x27 + (nr))
-+
-+#define LM78_REG_TEMP 0x27
-+#define LM78_REG_TEMP_OVER 0x39
-+#define LM78_REG_TEMP_HYST 0x3a
-+
-+#define LM78_REG_ALARM1 0x41
-+#define LM78_REG_ALARM2 0x42
-+
-+#define LM78_REG_VID_FANDIV 0x47
-+
-+#define LM78_REG_CONFIG 0x40
-+#define LM78_REG_CHIPID 0x49
-+#define LM78_REG_I2C_ADDR 0x48
-+
-+
-+/* Conversions. Limit checking is only done on the TO_REG
-+ variants. Note that you should be a bit careful with which arguments
-+ these macros are called: arguments may be evaluated more than once.
-+ Fixing this is just not worth it. */
-+#define IN_TO_REG(val) (SENSORS_LIMIT((((val) * 10 + 8)/16),0,255))
-+#define IN_FROM_REG(val) (((val) * 16 + 5) / 10)
-+
-+static inline u8 FAN_TO_REG(long rpm, int div)
-+{
-+ if (rpm == 0)
-+ return 255;
-+ rpm = SENSORS_LIMIT(rpm, 1, 1000000);
-+ return SENSORS_LIMIT((1350000 + rpm * div / 2) / (rpm * div), 1,
-+ 254);
-+}
-+
-+#define FAN_FROM_REG(val,div) ((val)==0?-1:(val)==255?0:1350000/((val)*(div)))
-+
-+#define TEMP_TO_REG(val) (SENSORS_LIMIT(((val)<0?(((val)-5)/10):\
-+ ((val)+5)/10),0,255))
-+#define TEMP_FROM_REG(val) (((val)>0x80?(val)-0x100:(val))*10)
-+
-+#define VID_FROM_REG(val) ((val)==0x1f?0:(val)>=0x10?510-(val)*10:\
-+ 205-(val)*5)
-+#define ALARMS_FROM_REG(val) (val)
-+
-+#define DIV_TO_REG(val) ((val)==8?3:(val)==4?2:(val)==1?0:1)
-+#define DIV_FROM_REG(val) (1 << (val))
-+
-+/* There are some complications in a module like this. First off, LM78 chips
-+ may be both present on the SMBus and the ISA bus, and we have to handle
-+ those cases separately at some places. Second, there might be several
-+ LM78 chips available (well, actually, that is probably never done; but
-+ it is a clean illustration of how to handle a case like that). Finally,
-+ a specific chip may be attached to *both* ISA and SMBus, and we would
-+ not like to detect it double. Fortunately, in the case of the LM78 at
-+ least, a register tells us what SMBus address we are on, so that helps
-+ a bit - except if there could be more than one SMBus. Groan. No solution
-+ for this yet. */
-+
-+/* This module may seem overly long and complicated. In fact, it is not so
-+ bad. Quite a lot of bookkeeping is done. A real driver can often cut
-+ some corners. */
-+
-+/* For each registered LM78, we need to keep some data in memory. That
-+ data is pointed to by lm78_list[NR]->data. The structure itself is
-+ dynamically allocated, at the same time when a new lm78 client is
-+ allocated. */
-+struct lm78_data {
-+ struct i2c_client client;
-+ struct semaphore lock;
-+ int sysctl_id;
-+ enum chips type;
-+
-+ struct semaphore update_lock;
-+ char valid; /* !=0 if following fields are valid */
-+ unsigned long last_updated; /* In jiffies */
-+
-+ u8 in[7]; /* Register value */
-+ u8 in_max[7]; /* Register value */
-+ u8 in_min[7]; /* Register value */
-+ u8 fan[3]; /* Register value */
-+ u8 fan_min[3]; /* Register value */
-+ u8 temp; /* Register value */
-+ u8 temp_over; /* Register value */
-+ u8 temp_hyst; /* Register value */
-+ u8 fan_div[3]; /* Register encoding, shifted right */
-+ u8 vid; /* Register encoding, combined */
-+ u16 alarms; /* Register encoding, combined */
-+};
-+
-+
-+static int lm78_attach_adapter(struct i2c_adapter *adapter);
-+static int lm78_detect(struct i2c_adapter *adapter, int address,
-+ unsigned short flags, int kind);
-+static int lm78_detach_client(struct i2c_client *client);
-+
-+static int lm78_read_value(struct i2c_client *client, u8 register);
-+static int lm78_write_value(struct i2c_client *client, u8 register,
-+ u8 value);
-+static void lm78_update_client(struct i2c_client *client);
-+static void lm78_init_client(struct i2c_client *client);
-+
-+
-+static void lm78_in(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results);
-+static void lm78_fan(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void lm78_temp(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void lm78_vid(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void lm78_alarms(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void lm78_fan_div(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+
-+static struct i2c_driver lm78_driver = {
-+ .owner = THIS_MODULE,
-+ .name = "LM78(-J) and LM79 sensor driver",
-+ .id = I2C_DRIVERID_LM78,
-+ .flags = I2C_DF_NOTIFY,
-+ .attach_adapter = lm78_attach_adapter,
-+ .detach_client = lm78_detach_client,
-+};
-+
-+static int lm78_id = 0;
-+
-+/* The /proc/sys entries */
-+
-+/* -- SENSORS SYSCTL START -- */
-+#define LM78_SYSCTL_IN0 1000 /* Volts * 100 */
-+#define LM78_SYSCTL_IN1 1001
-+#define LM78_SYSCTL_IN2 1002
-+#define LM78_SYSCTL_IN3 1003
-+#define LM78_SYSCTL_IN4 1004
-+#define LM78_SYSCTL_IN5 1005
-+#define LM78_SYSCTL_IN6 1006
-+#define LM78_SYSCTL_FAN1 1101 /* Rotations/min */
-+#define LM78_SYSCTL_FAN2 1102
-+#define LM78_SYSCTL_FAN3 1103
-+#define LM78_SYSCTL_TEMP 1200 /* Degrees Celcius * 10 */
-+#define LM78_SYSCTL_VID 1300 /* Volts * 100 */
-+#define LM78_SYSCTL_FAN_DIV 2000 /* 1, 2, 4 or 8 */
-+#define LM78_SYSCTL_ALARMS 2001 /* bitvector */
-+
-+#define LM78_ALARM_IN0 0x0001
-+#define LM78_ALARM_IN1 0x0002
-+#define LM78_ALARM_IN2 0x0004
-+#define LM78_ALARM_IN3 0x0008
-+#define LM78_ALARM_IN4 0x0100
-+#define LM78_ALARM_IN5 0x0200
-+#define LM78_ALARM_IN6 0x0400
-+#define LM78_ALARM_FAN1 0x0040
-+#define LM78_ALARM_FAN2 0x0080
-+#define LM78_ALARM_FAN3 0x0800
-+#define LM78_ALARM_TEMP 0x0010
-+#define LM78_ALARM_BTI 0x0020
-+#define LM78_ALARM_CHAS 0x1000
-+#define LM78_ALARM_FIFO 0x2000
-+#define LM78_ALARM_SMI_IN 0x4000
-+
-+/* -- SENSORS SYSCTL END -- */
-+
-+/* These files are created for each detected LM78. This is just a template;
-+ though at first sight, you might think we could use a statically
-+ allocated list, we need some way to get back to the parent - which
-+ is done through one of the 'extra' fields which are initialized
-+ when a new copy is allocated. */
-+static ctl_table lm78_dir_table_template[] = {
-+ {LM78_SYSCTL_IN0, "in0", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &lm78_in},
-+ {LM78_SYSCTL_IN1, "in1", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &lm78_in},
-+ {LM78_SYSCTL_IN2, "in2", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &lm78_in},
-+ {LM78_SYSCTL_IN3, "in3", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &lm78_in},
-+ {LM78_SYSCTL_IN4, "in4", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &lm78_in},
-+ {LM78_SYSCTL_IN5, "in5", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &lm78_in},
-+ {LM78_SYSCTL_IN6, "in6", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &lm78_in},
-+ {LM78_SYSCTL_FAN1, "fan1", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &lm78_fan},
-+ {LM78_SYSCTL_FAN2, "fan2", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &lm78_fan},
-+ {LM78_SYSCTL_FAN3, "fan3", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &lm78_fan},
-+ {LM78_SYSCTL_TEMP, "temp", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &lm78_temp},
-+ {LM78_SYSCTL_VID, "vid", NULL, 0, 0444, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &lm78_vid},
-+ {LM78_SYSCTL_FAN_DIV, "fan_div", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &lm78_fan_div},
-+ {LM78_SYSCTL_ALARMS, "alarms", NULL, 0, 0444, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &lm78_alarms},
-+ {0}
-+};
-+
-+
-+/* This function is called when:
-+ * lm78_driver is inserted (when this module is loaded), for each
-+ available adapter
-+ * when a new adapter is inserted (and lm78_driver is still present) */
-+static int lm78_attach_adapter(struct i2c_adapter *adapter)
-+{
-+ return i2c_detect(adapter, &addr_data, lm78_detect);
-+}
-+
-+/* This function is called by i2c_detect */
-+int lm78_detect(struct i2c_adapter *adapter, int address,
-+ unsigned short flags, int kind)
-+{
-+ int i;
-+ struct i2c_client *new_client;
-+ struct lm78_data *data;
-+ int err = 0;
-+ const char *type_name = "";
-+ const char *client_name = "";
-+ int is_isa = i2c_is_isa_adapter(adapter);
-+
-+ if (!is_isa
-+ && !i2c_check_functionality(adapter,
-+ I2C_FUNC_SMBUS_BYTE_DATA)) goto
-+ ERROR0;
-+
-+ if (is_isa) {
-+ if (check_region(address, LM78_EXTENT))
-+ goto ERROR0;
-+ }
-+
-+ /* Probe whether there is anything available on this address. Already
-+ done for SMBus clients */
-+ if (kind < 0) {
-+ if (is_isa) {
-+
-+#define REALLY_SLOW_IO
-+ /* We need the timeouts for at least some LM78-like chips. But only
-+ if we read 'undefined' registers. */
-+ i = inb_p(address + 1);
-+ if (inb_p(address + 2) != i)
-+ goto ERROR0;
-+ if (inb_p(address + 3) != i)
-+ goto ERROR0;
-+ if (inb_p(address + 7) != i)
-+ goto ERROR0;
-+#undef REALLY_SLOW_IO
-+
-+ /* Let's just hope nothing breaks here */
-+ i = inb_p(address + 5) & 0x7f;
-+ outb_p(~i & 0x7f, address + 5);
-+ if ((inb_p(address + 5) & 0x7f) != (~i & 0x7f)) {
-+ outb_p(i, address + 5);
-+ return 0;
-+ }
-+ }
-+ }
-+
-+ /* OK. For now, we presume we have a valid client. We now create the
-+ client structure, even though we cannot fill it completely yet.
-+ But it allows us to access lm78_{read,write}_value. */
-+
-+ if (!(data = kmalloc(sizeof(struct lm78_data), GFP_KERNEL))) {
-+ err = -ENOMEM;
-+ goto ERROR0;
-+ }
-+
-+ new_client = &data->client;
-+ if (is_isa)
-+ init_MUTEX(&data->lock);
-+ new_client->addr = address;
-+ new_client->data = data;
-+ new_client->adapter = adapter;
-+ new_client->driver = &lm78_driver;
-+ new_client->flags = 0;
-+
-+ /* Now, we do the remaining detection. */
-+
-+ if (kind < 0) {
-+ if (lm78_read_value(new_client, LM78_REG_CONFIG) & 0x80)
-+ goto ERROR1;
-+ if (!is_isa
-+ && (lm78_read_value(new_client, LM78_REG_I2C_ADDR) !=
-+ address)) goto ERROR1;
-+ }
-+
-+ /* Determine the chip type. */
-+ if (kind <= 0) {
-+ i = lm78_read_value(new_client, LM78_REG_CHIPID);
-+ if (i == 0x00 || i == 0x20)
-+ kind = lm78;
-+ else if (i == 0x40)
-+ kind = lm78j;
-+ else if ((i & 0xfe) == 0xc0)
-+ kind = lm79;
-+ else {
-+ if (kind == 0)
-+ printk
-+ ("lm78.o: Ignoring 'force' parameter for unknown chip at "
-+ "adapter %d, address 0x%02x\n",
-+ i2c_adapter_id(adapter), address);
-+ goto ERROR1;
-+ }
-+ }
-+
-+ if (kind == lm78) {
-+ type_name = "lm78";
-+ client_name = "LM78 chip";
-+ } else if (kind == lm78j) {
-+ type_name = "lm78-j";
-+ client_name = "LM78-J chip";
-+ } else if (kind == lm79) {
-+ type_name = "lm79";
-+ client_name = "LM79 chip";
-+ } else {
-+#ifdef DEBUG
-+ printk("lm78.o: Internal error: unknown kind (%d)?!?",
-+ kind);
-+#endif
-+ goto ERROR1;
-+ }
-+
-+ /* Reserve the ISA region */
-+ if (is_isa)
-+ request_region(address, LM78_EXTENT, type_name);
-+
-+ /* Fill in the remaining client fields and put it into the global list */
-+ strcpy(new_client->name, client_name);
-+ data->type = kind;
-+
-+ new_client->id = lm78_id++;
-+ data->valid = 0;
-+ init_MUTEX(&data->update_lock);
-+
-+ /* Tell the I2C layer a new client has arrived */
-+ if ((err = i2c_attach_client(new_client)))
-+ goto ERROR3;
-+
-+ /* Register a new directory entry with module sensors */
-+ if ((i = i2c_register_entry(new_client,
-+ type_name,
-+ lm78_dir_table_template)) < 0) {
-+ err = i;
-+ goto ERROR4;
-+ }
-+ data->sysctl_id = i;
-+
-+ /* Initialize the LM78 chip */
-+ lm78_init_client(new_client);
-+ return 0;
-+
-+/* OK, this is not exactly good programming practice, usually. But it is
-+ very code-efficient in this case. */
-+
-+ ERROR4:
-+ i2c_detach_client(new_client);
-+ ERROR3:
-+ if (is_isa)
-+ release_region(address, LM78_EXTENT);
-+ ERROR1:
-+ kfree(data);
-+ ERROR0:
-+ return err;
-+}
-+
-+static int lm78_detach_client(struct i2c_client *client)
-+{
-+ int err;
-+
-+ i2c_deregister_entry(((struct lm78_data *) (client->data))->
-+ sysctl_id);
-+
-+ if ((err = i2c_detach_client(client))) {
-+ printk
-+ ("lm78.o: Client deregistration failed, client not detached.\n");
-+ return err;
-+ }
-+
-+ if(i2c_is_isa_client(client))
-+ release_region(client->addr, LM78_EXTENT);
-+ kfree(client->data);
-+
-+ return 0;
-+}
-+
-+/* The SMBus locks itself, but ISA access must be locked explicitely!
-+ We don't want to lock the whole ISA bus, so we lock each client
-+ separately.
-+ We ignore the LM78 BUSY flag at this moment - it could lead to deadlocks,
-+ would slow down the LM78 access and should not be necessary.
-+ There are some ugly typecasts here, but the good new is - they should
-+ nowhere else be necessary! */
-+static int lm78_read_value(struct i2c_client *client, u8 reg)
-+{
-+ int res;
-+ if (i2c_is_isa_client(client)) {
-+ down(&(((struct lm78_data *) (client->data))->lock));
-+ outb_p(reg, client->addr + LM78_ADDR_REG_OFFSET);
-+ res = inb_p(client->addr + LM78_DATA_REG_OFFSET);
-+ up(&(((struct lm78_data *) (client->data))->lock));
-+ return res;
-+ } else
-+ return i2c_smbus_read_byte_data(client, reg);
-+}
-+
-+/* The SMBus locks itself, but ISA access muse be locked explicitely!
-+ We don't want to lock the whole ISA bus, so we lock each client
-+ separately.
-+ We ignore the LM78 BUSY flag at this moment - it could lead to deadlocks,
-+ would slow down the LM78 access and should not be necessary.
-+ There are some ugly typecasts here, but the good new is - they should
-+ nowhere else be necessary! */
-+static int lm78_write_value(struct i2c_client *client, u8 reg, u8 value)
-+{
-+ if (i2c_is_isa_client(client)) {
-+ down(&(((struct lm78_data *) (client->data))->lock));
-+ outb_p(reg, client->addr + LM78_ADDR_REG_OFFSET);
-+ outb_p(value, client->addr + LM78_DATA_REG_OFFSET);
-+ up(&(((struct lm78_data *) (client->data))->lock));
-+ return 0;
-+ } else
-+ return i2c_smbus_write_byte_data(client, reg, value);
-+}
-+
-+/* Called when we have found a new LM78. */
-+static void lm78_init_client(struct i2c_client *client)
-+{
-+ u8 config = lm78_read_value(client, LM78_REG_CONFIG);
-+
-+ /* Start monitoring */
-+ if (!(config & 0x01))
-+ lm78_write_value(client, LM78_REG_CONFIG,
-+ (config & 0xf7) | 0x01);
-+}
-+
-+static void lm78_update_client(struct i2c_client *client)
-+{
-+ struct lm78_data *data = client->data;
-+ int i;
-+
-+ down(&data->update_lock);
-+
-+ if ((jiffies - data->last_updated > HZ + HZ / 2) ||
-+ (jiffies < data->last_updated) || !data->valid) {
-+
-+#ifdef DEBUG
-+ printk("Starting lm78 update\n");
-+#endif
-+ for (i = 0; i <= 6; i++) {
-+ data->in[i] =
-+ lm78_read_value(client, LM78_REG_IN(i));
-+ data->in_min[i] =
-+ lm78_read_value(client, LM78_REG_IN_MIN(i));
-+ data->in_max[i] =
-+ lm78_read_value(client, LM78_REG_IN_MAX(i));
-+ }
-+ for (i = 1; i <= 3; i++) {
-+ data->fan[i - 1] =
-+ lm78_read_value(client, LM78_REG_FAN(i));
-+ data->fan_min[i - 1] =
-+ lm78_read_value(client, LM78_REG_FAN_MIN(i));
-+ }
-+ data->temp = lm78_read_value(client, LM78_REG_TEMP);
-+ data->temp_over =
-+ lm78_read_value(client, LM78_REG_TEMP_OVER);
-+ data->temp_hyst =
-+ lm78_read_value(client, LM78_REG_TEMP_HYST);
-+ i = lm78_read_value(client, LM78_REG_VID_FANDIV);
-+ data->vid = i & 0x0f;
-+ if (data->type == lm79)
-+ data->vid |=
-+ (lm78_read_value(client, LM78_REG_CHIPID) &
-+ 0x01) << 4;
-+ else
-+ data->vid |= 0x10;
-+ data->fan_div[0] = (i >> 4) & 0x03;
-+ data->fan_div[1] = i >> 6;
-+ data->alarms = lm78_read_value(client, LM78_REG_ALARM1) +
-+ (lm78_read_value(client, LM78_REG_ALARM2) << 8);
-+ data->last_updated = jiffies;
-+ data->valid = 1;
-+
-+ data->fan_div[2] = 1;
-+ }
-+
-+ up(&data->update_lock);
-+}
-+
-+
-+/* The next few functions are the call-back functions of the /proc/sys and
-+ sysctl files. Which function is used is defined in the ctl_table in
-+ the extra1 field.
-+ Each function must return the magnitude (power of 10 to divide the date
-+ with) if it is called with operation==SENSORS_PROC_REAL_INFO. It must
-+ put a maximum of *nrels elements in results reflecting the data of this
-+ file, and set *nrels to the number it actually put in it, if operation==
-+ SENSORS_PROC_REAL_READ. Finally, it must get upto *nrels elements from
-+ results and write them to the chip, if operations==SENSORS_PROC_REAL_WRITE.
-+ Note that on SENSORS_PROC_REAL_READ, I do not check whether results is
-+ large enough (by checking the incoming value of *nrels). This is not very
-+ good practice, but as long as you put less than about 5 values in results,
-+ you can assume it is large enough. */
-+void lm78_in(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct lm78_data *data = client->data;
-+ int nr = ctl_name - LM78_SYSCTL_IN0;
-+
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 2;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ lm78_update_client(client);
-+ results[0] = IN_FROM_REG(data->in_min[nr]);
-+ results[1] = IN_FROM_REG(data->in_max[nr]);
-+ results[2] = IN_FROM_REG(data->in[nr]);
-+ *nrels_mag = 3;
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ if (*nrels_mag >= 1) {
-+ data->in_min[nr] = IN_TO_REG(results[0]);
-+ lm78_write_value(client, LM78_REG_IN_MIN(nr),
-+ data->in_min[nr]);
-+ }
-+ if (*nrels_mag >= 2) {
-+ data->in_max[nr] = IN_TO_REG(results[1]);
-+ lm78_write_value(client, LM78_REG_IN_MAX(nr),
-+ data->in_max[nr]);
-+ }
-+ }
-+}
-+
-+void lm78_fan(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct lm78_data *data = client->data;
-+ int nr = ctl_name - LM78_SYSCTL_FAN1 + 1;
-+
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 0;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ lm78_update_client(client);
-+ results[0] = FAN_FROM_REG(data->fan_min[nr - 1],
-+ DIV_FROM_REG(data->
-+ fan_div[nr - 1]));
-+ results[1] =
-+ FAN_FROM_REG(data->fan[nr - 1],
-+ DIV_FROM_REG(data->fan_div[nr - 1]));
-+ *nrels_mag = 2;
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ if (*nrels_mag >= 1) {
-+ data->fan_min[nr - 1] = FAN_TO_REG(results[0],
-+ DIV_FROM_REG
-+ (data->
-+ fan_div[nr -
-+ 1]));
-+ lm78_write_value(client, LM78_REG_FAN_MIN(nr),
-+ data->fan_min[nr - 1]);
-+ }
-+ }
-+}
-+
-+
-+void lm78_temp(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct lm78_data *data = client->data;
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 1;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ lm78_update_client(client);
-+ results[0] = TEMP_FROM_REG(data->temp_over);
-+ results[1] = TEMP_FROM_REG(data->temp_hyst);
-+ results[2] = TEMP_FROM_REG(data->temp);
-+ *nrels_mag = 3;
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ if (*nrels_mag >= 1) {
-+ data->temp_over = TEMP_TO_REG(results[0]);
-+ lm78_write_value(client, LM78_REG_TEMP_OVER,
-+ data->temp_over);
-+ }
-+ if (*nrels_mag >= 2) {
-+ data->temp_hyst = TEMP_TO_REG(results[1]);
-+ lm78_write_value(client, LM78_REG_TEMP_HYST,
-+ data->temp_hyst);
-+ }
-+ }
-+}
-+
-+void lm78_vid(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct lm78_data *data = client->data;
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 2;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ lm78_update_client(client);
-+ results[0] = VID_FROM_REG(data->vid);
-+ *nrels_mag = 1;
-+ }
-+}
-+
-+void lm78_alarms(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct lm78_data *data = client->data;
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 0;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ lm78_update_client(client);
-+ results[0] = ALARMS_FROM_REG(data->alarms);
-+ *nrels_mag = 1;
-+ }
-+}
-+
-+/* Note: we save and restore the fan minimum here, because its value is
-+ determined in part by the fan divisor. This follows the principle of
-+ least surprise: the user doesn't expect the fan minimum to change just
-+ because the divisor changed. */
-+void lm78_fan_div(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct lm78_data *data = client->data;
-+ int old, min;
-+
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 0;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ lm78_update_client(client);
-+ results[0] = DIV_FROM_REG(data->fan_div[0]);
-+ results[1] = DIV_FROM_REG(data->fan_div[1]);
-+ results[2] = 2;
-+ *nrels_mag = 3;
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ old = lm78_read_value(client, LM78_REG_VID_FANDIV);
-+ if (*nrels_mag >= 2) {
-+ min = FAN_FROM_REG(data->fan_min[1],
-+ DIV_FROM_REG(data->fan_div[1]));
-+ data->fan_div[1] = DIV_TO_REG(results[1]);
-+ old = (old & 0x3f) | (data->fan_div[1] << 6);
-+ data->fan_min[1] = FAN_TO_REG(min,
-+ DIV_FROM_REG(data->fan_div[1]));
-+ lm78_write_value(client, LM78_REG_FAN_MIN(2),
-+ data->fan_min[1]);
-+ }
-+ if (*nrels_mag >= 1) {
-+ min = FAN_FROM_REG(data->fan_min[0],
-+ DIV_FROM_REG(data->fan_div[0]));
-+ data->fan_div[0] = DIV_TO_REG(results[0]);
-+ old = (old & 0xcf) | (data->fan_div[0] << 4);
-+ data->fan_min[0] = FAN_TO_REG(min,
-+ DIV_FROM_REG(data->fan_div[0]));
-+ lm78_write_value(client, LM78_REG_FAN_MIN(1),
-+ data->fan_min[0]);
-+ lm78_write_value(client, LM78_REG_VID_FANDIV, old);
-+ }
-+ }
-+}
-+
-+static int __init sm_lm78_init(void)
-+{
-+ printk("lm78.o version %s (%s)\n", LM_VERSION, LM_DATE);
-+ return i2c_add_driver(&lm78_driver);
-+}
-+
-+static void __exit sm_lm78_exit(void)
-+{
-+ i2c_del_driver(&lm78_driver);
-+}
-+
-+
-+
-+MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl>");
-+MODULE_DESCRIPTION("LM78, LM78-J and LM79 driver");
-+
-+module_init(sm_lm78_init);
-+module_exit(sm_lm78_exit);
---- linux-old/drivers/sensors/lm80.c Thu Jan 1 00:00:00 1970
-+++ linux/drivers/sensors/lm80.c Mon Dec 13 20:18:48 2004
-@@ -0,0 +1,606 @@
-+/*
-+ lm80.c - Part of lm_sensors, Linux kernel modules for hardware
-+ monitoring
-+ Copyright (c) 1998, 1999 Frodo Looijaard <frodol@dds.nl>
-+ and Philip Edelbrock <phil@netroedge.com>
-+
-+ 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., 675 Mass Ave, Cambridge, MA 02139, USA.
-+*/
-+
-+#include <linux/module.h>
-+#include <linux/slab.h>
-+#include <linux/i2c.h>
-+#include <linux/i2c-proc.h>
-+#include <linux/init.h>
-+#define LM_DATE "20041007"
-+#define LM_VERSION "2.8.8"
-+
-+MODULE_LICENSE("GPL");
-+
-+/* Addresses to scan */
-+static unsigned short normal_i2c[] = { SENSORS_I2C_END };
-+static unsigned short normal_i2c_range[] = { 0x20, 0x2f, SENSORS_I2C_END };
-+static unsigned int normal_isa[] = { SENSORS_ISA_END };
-+static unsigned int normal_isa_range[] = { SENSORS_ISA_END };
-+
-+/* Insmod parameters */
-+SENSORS_INSMOD_1(lm80);
-+
-+/* Many LM80 constants specified below */
-+
-+/* The LM80 registers */
-+#define LM80_REG_IN_MAX(nr) (0x2a + (nr) * 2)
-+#define LM80_REG_IN_MIN(nr) (0x2b + (nr) * 2)
-+#define LM80_REG_IN(nr) (0x20 + (nr))
-+
-+#define LM80_REG_FAN1_MIN 0x3c
-+#define LM80_REG_FAN2_MIN 0x3d
-+#define LM80_REG_FAN1 0x28
-+#define LM80_REG_FAN2 0x29
-+
-+#define LM80_REG_TEMP 0x27
-+#define LM80_REG_TEMP_HOT_MAX 0x38
-+#define LM80_REG_TEMP_HOT_HYST 0x39
-+#define LM80_REG_TEMP_OS_MAX 0x3a
-+#define LM80_REG_TEMP_OS_HYST 0x3b
-+
-+#define LM80_REG_CONFIG 0x00
-+#define LM80_REG_ALARM1 0x01
-+#define LM80_REG_ALARM2 0x02
-+#define LM80_REG_MASK1 0x03
-+#define LM80_REG_MASK2 0x04
-+#define LM80_REG_FANDIV 0x05
-+#define LM80_REG_RES 0x06
-+
-+
-+/* Conversions. Rounding and limit checking is only done on the TO_REG
-+ variants. Note that you should be a bit careful with which arguments
-+ these macros are called: arguments may be evaluated more than once.
-+ Fixing this is just not worth it. */
-+
-+#define IN_TO_REG(val) (SENSORS_LIMIT((val),0,255))
-+#define IN_FROM_REG(val) (val)
-+
-+static inline unsigned char FAN_TO_REG(unsigned rpm, unsigned div)
-+{
-+ if (rpm == 0)
-+ return 255;
-+ rpm = SENSORS_LIMIT(rpm, 1, 1000000);
-+ return SENSORS_LIMIT((1350000 + rpm * div / 2) / (rpm * div), 1,
-+ 254);
-+}
-+
-+#define FAN_FROM_REG(val,div) ((val)==0?-1:\
-+ (val)==255?0:1350000/((div)*(val)))
-+
-+static inline long TEMP_FROM_REG(u16 temp)
-+{
-+ long res;
-+
-+ temp >>= 4;
-+ if (temp < 0x0800)
-+ res = 625 * (long) temp;
-+ else
-+ res = ((long) temp - 0x01000) * 625;
-+
-+ return res / 100;
-+}
-+
-+#define TEMP_LIMIT_FROM_REG(val) (((val)>0x80?(val)-0x100:(val))*100)
-+
-+#define TEMP_LIMIT_TO_REG(val) SENSORS_LIMIT(((val)<0?(((val)-50)/100):\
-+ ((val)+50)/100), \
-+ 0,255)
-+
-+#define ALARMS_FROM_REG(val) (val)
-+
-+#define DIV_FROM_REG(val) (1 << (val))
-+#define DIV_TO_REG(val) ((val)==8?3:(val)==4?2:(val)==1?0:1)
-+
-+struct lm80_data {
-+ struct i2c_client client;
-+ int sysctl_id;
-+
-+ struct semaphore update_lock;
-+ char valid; /* !=0 if following fields are valid */
-+ unsigned long last_updated; /* In jiffies */
-+
-+ u8 in[7]; /* Register value */
-+ u8 in_max[7]; /* Register value */
-+ u8 in_min[7]; /* Register value */
-+ u8 fan[2]; /* Register value */
-+ u8 fan_min[2]; /* Register value */
-+ u8 fan_div[2]; /* Register encoding, shifted right */
-+ u16 temp; /* Register values, shifted right */
-+ u8 temp_hot_max; /* Register value */
-+ u8 temp_hot_hyst; /* Register value */
-+ u8 temp_os_max; /* Register value */
-+ u8 temp_os_hyst; /* Register value */
-+ u16 alarms; /* Register encoding, combined */
-+};
-+
-+
-+
-+static int lm80_attach_adapter(struct i2c_adapter *adapter);
-+static int lm80_detect(struct i2c_adapter *adapter, int address,
-+ unsigned short flags, int kind);
-+static int lm80_detach_client(struct i2c_client *client);
-+
-+static int lm80_read_value(struct i2c_client *client, u8 reg);
-+static int lm80_write_value(struct i2c_client *client, u8 reg, u8 value);
-+static void lm80_update_client(struct i2c_client *client);
-+static void lm80_init_client(struct i2c_client *client);
-+
-+
-+static void lm80_in(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results);
-+static void lm80_fan(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void lm80_temp(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void lm80_alarms(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void lm80_fan_div(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+
-+static int lm80_id = 0;
-+
-+static struct i2c_driver lm80_driver = {
-+ .owner = THIS_MODULE,
-+ .name = "LM80 sensor driver",
-+ .id = I2C_DRIVERID_LM80,
-+ .flags = I2C_DF_NOTIFY,
-+ .attach_adapter = lm80_attach_adapter,
-+ .detach_client = lm80_detach_client,
-+};
-+
-+/* The /proc/sys entries */
-+
-+/* -- SENSORS SYSCTL START -- */
-+
-+#define LM80_SYSCTL_IN0 1000 /* Volts * 100 */
-+#define LM80_SYSCTL_IN1 1001
-+#define LM80_SYSCTL_IN2 1002
-+#define LM80_SYSCTL_IN3 1003
-+#define LM80_SYSCTL_IN4 1004
-+#define LM80_SYSCTL_IN5 1005
-+#define LM80_SYSCTL_IN6 1006
-+#define LM80_SYSCTL_FAN1 1101 /* Rotations/min */
-+#define LM80_SYSCTL_FAN2 1102
-+#define LM80_SYSCTL_TEMP 1250 /* Degrees Celcius * 100 */
-+#define LM80_SYSCTL_FAN_DIV 2000 /* 1, 2, 4 or 8 */
-+#define LM80_SYSCTL_ALARMS 2001 /* bitvector */
-+
-+#define LM80_ALARM_IN0 0x0001
-+#define LM80_ALARM_IN1 0x0002
-+#define LM80_ALARM_IN2 0x0004
-+#define LM80_ALARM_IN3 0x0008
-+#define LM80_ALARM_IN4 0x0010
-+#define LM80_ALARM_IN5 0x0020
-+#define LM80_ALARM_IN6 0x0040
-+#define LM80_ALARM_FAN1 0x0400
-+#define LM80_ALARM_FAN2 0x0800
-+#define LM80_ALARM_TEMP_HOT 0x0100
-+#define LM80_ALARM_TEMP_OS 0x2000
-+#define LM80_ALARM_CHAS 0x1000
-+#define LM80_ALARM_BTI 0x0200
-+#define LM80_ALARM_INT_IN 0x0080
-+
-+/* -- SENSORS SYSCTL END -- */
-+
-+/* These files are created for each detected LM80. This is just a template;
-+ though at first sight, you might think we could use a statically
-+ allocated list, we need some way to get back to the parent - which
-+ is done through one of the 'extra' fields which are initialized
-+ when a new copy is allocated. */
-+static ctl_table lm80_dir_table_template[] = {
-+ {LM80_SYSCTL_IN0, "in0", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &lm80_in},
-+ {LM80_SYSCTL_IN1, "in1", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &lm80_in},
-+ {LM80_SYSCTL_IN2, "in2", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &lm80_in},
-+ {LM80_SYSCTL_IN3, "in3", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &lm80_in},
-+ {LM80_SYSCTL_IN4, "in4", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &lm80_in},
-+ {LM80_SYSCTL_IN5, "in5", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &lm80_in},
-+ {LM80_SYSCTL_IN6, "in6", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &lm80_in},
-+ {LM80_SYSCTL_FAN1, "fan1", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &lm80_fan},
-+ {LM80_SYSCTL_FAN2, "fan2", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &lm80_fan},
-+ {LM80_SYSCTL_TEMP, "temp", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &lm80_temp},
-+ {LM80_SYSCTL_FAN_DIV, "fan_div", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &lm80_fan_div},
-+ {LM80_SYSCTL_ALARMS, "alarms", NULL, 0, 0444, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &lm80_alarms},
-+ {0}
-+};
-+
-+static int lm80_attach_adapter(struct i2c_adapter *adapter)
-+{
-+ return i2c_detect(adapter, &addr_data, lm80_detect);
-+}
-+
-+int lm80_detect(struct i2c_adapter *adapter, int address,
-+ unsigned short flags, int kind)
-+{
-+ int i, cur;
-+ struct i2c_client *new_client;
-+ struct lm80_data *data;
-+ int err = 0;
-+ const char *type_name, *client_name;
-+
-+ /* Make sure we aren't probing the ISA bus!! This is just a safety check
-+ at this moment; i2c_detect really won't call us. */
-+#ifdef DEBUG
-+ if (i2c_is_isa_adapter(adapter)) {
-+ printk
-+ ("lm80.o: lm80_detect called for an ISA bus adapter?!?\n");
-+ return 0;
-+ }
-+#endif
-+
-+ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
-+ goto ERROR0;
-+
-+ /* OK. For now, we presume we have a valid client. We now create the
-+ client structure, even though we cannot fill it completely yet.
-+ But it allows us to access lm80_{read,write}_value. */
-+ if (!(data = kmalloc(sizeof(struct lm80_data), GFP_KERNEL))) {
-+ err = -ENOMEM;
-+ goto ERROR0;
-+ }
-+
-+ new_client = &data->client;
-+ new_client->addr = address;
-+ new_client->data = data;
-+ new_client->adapter = adapter;
-+ new_client->driver = &lm80_driver;
-+ new_client->flags = 0;
-+
-+ /* Now, we do the remaining detection. It is lousy. */
-+ if (lm80_read_value(new_client, LM80_REG_ALARM2) & 0xc0)
-+ goto ERROR1;
-+ for (i = 0x2a; i <= 0x3d; i++) {
-+ cur = i2c_smbus_read_byte_data(new_client, i);
-+ if ((i2c_smbus_read_byte_data(new_client, i + 0x40) != cur)
-+ || (i2c_smbus_read_byte_data(new_client, i + 0x80) !=
-+ cur)
-+ || (i2c_smbus_read_byte_data(new_client, i + 0xc0) !=
-+ cur)) goto ERROR1;
-+ }
-+
-+ /* Determine the chip type - only one kind supported! */
-+ if (kind <= 0)
-+ kind = lm80;
-+
-+ if (kind == lm80) {
-+ type_name = "lm80";
-+ client_name = "LM80 chip";
-+ } else {
-+#ifdef DEBUG
-+ printk("lm80.o: Internal error: unknown kind (%d)?!?",
-+ kind);
-+#endif
-+ goto ERROR1;
-+ }
-+
-+ /* Fill in the remaining client fields and put it into the global list */
-+ strcpy(new_client->name, client_name);
-+
-+ new_client->id = lm80_id++;
-+ data->valid = 0;
-+ init_MUTEX(&data->update_lock);
-+
-+ /* Tell the I2C layer a new client has arrived */
-+ if ((err = i2c_attach_client(new_client)))
-+ goto ERROR3;
-+
-+ /* Register a new directory entry with module sensors */
-+ if ((i = i2c_register_entry(new_client, type_name,
-+ lm80_dir_table_template)) < 0) {
-+ err = i;
-+ goto ERROR4;
-+ }
-+ data->sysctl_id = i;
-+
-+ lm80_init_client(new_client);
-+ return 0;
-+
-+/* OK, this is not exactly good programming practice, usually. But it is
-+ very code-efficient in this case. */
-+ ERROR4:
-+ i2c_detach_client(new_client);
-+ ERROR3:
-+ ERROR1:
-+ kfree(data);
-+ ERROR0:
-+ return err;
-+}
-+
-+static int lm80_detach_client(struct i2c_client *client)
-+{
-+ int err;
-+
-+ i2c_deregister_entry(((struct lm80_data *) (client->data))->
-+ sysctl_id);
-+
-+ if ((err = i2c_detach_client(client))) {
-+ printk
-+ ("lm80.o: Client deregistration failed, client not detached.\n");
-+ return err;
-+ }
-+
-+ kfree(client->data);
-+
-+ return 0;
-+}
-+
-+static int lm80_read_value(struct i2c_client *client, u8 reg)
-+{
-+ return i2c_smbus_read_byte_data(client, reg);
-+}
-+
-+static int lm80_write_value(struct i2c_client *client, u8 reg, u8 value)
-+{
-+ return i2c_smbus_write_byte_data(client, reg, value);
-+}
-+
-+/* Called when we have found a new LM80. */
-+static void lm80_init_client(struct i2c_client *client)
-+{
-+ /* Reset all except Watchdog values and last conversion values
-+ This sets fan-divs to 2, among others. This makes most other
-+ initializations unnecessary */
-+ lm80_write_value(client, LM80_REG_CONFIG, 0x80);
-+ /* Set 11-bit temperature resolution */
-+ lm80_write_value(client, LM80_REG_RES, 0x08);
-+
-+ /* Start monitoring */
-+ lm80_write_value(client, LM80_REG_CONFIG, 0x01);
-+}
-+
-+static void lm80_update_client(struct i2c_client *client)
-+{
-+ struct lm80_data *data = client->data;
-+ int i;
-+
-+ down(&data->update_lock);
-+
-+ if ((jiffies - data->last_updated > 2 * HZ) ||
-+ (jiffies < data->last_updated) || !data->valid) {
-+
-+#ifdef DEBUG
-+ printk("Starting lm80 update\n");
-+#endif
-+ for (i = 0; i <= 6; i++) {
-+ data->in[i] =
-+ lm80_read_value(client, LM80_REG_IN(i));
-+ data->in_min[i] =
-+ lm80_read_value(client, LM80_REG_IN_MIN(i));
-+ data->in_max[i] =
-+ lm80_read_value(client, LM80_REG_IN_MAX(i));
-+ }
-+ data->fan[0] = lm80_read_value(client, LM80_REG_FAN1);
-+ data->fan_min[0] =
-+ lm80_read_value(client, LM80_REG_FAN1_MIN);
-+ data->fan[1] = lm80_read_value(client, LM80_REG_FAN2);
-+ data->fan_min[1] =
-+ lm80_read_value(client, LM80_REG_FAN2_MIN);
-+
-+ data->temp =
-+ (lm80_read_value(client, LM80_REG_TEMP) << 8) |
-+ (lm80_read_value(client, LM80_REG_RES) & 0xf0);
-+ data->temp_os_max =
-+ lm80_read_value(client, LM80_REG_TEMP_OS_MAX);
-+ data->temp_os_hyst =
-+ lm80_read_value(client, LM80_REG_TEMP_OS_HYST);
-+ data->temp_hot_max =
-+ lm80_read_value(client, LM80_REG_TEMP_HOT_MAX);
-+ data->temp_hot_hyst =
-+ lm80_read_value(client, LM80_REG_TEMP_HOT_HYST);
-+
-+ i = lm80_read_value(client, LM80_REG_FANDIV);
-+ data->fan_div[0] = (i >> 2) & 0x03;
-+ data->fan_div[1] = (i >> 4) & 0x03;
-+ data->alarms = lm80_read_value(client, LM80_REG_ALARM1) +
-+ (lm80_read_value(client, LM80_REG_ALARM2) << 8);
-+ data->last_updated = jiffies;
-+ data->valid = 1;
-+ }
-+
-+ up(&data->update_lock);
-+}
-+
-+
-+/* The next few functions are the call-back functions of the /proc/sys and
-+ sysctl files. Which function is used is defined in the ctl_table in
-+ the extra1 field.
-+ Each function must return the magnitude (power of 10 to divide the date
-+ with) if it is called with operation==SENSORS_PROC_REAL_INFO. It must
-+ put a maximum of *nrels elements in results reflecting the data of this
-+ file, and set *nrels to the number it actually put in it, if operation==
-+ SENSORS_PROC_REAL_READ. Finally, it must get upto *nrels elements from
-+ results and write them to the chip, if operations==SENSORS_PROC_REAL_WRITE.
-+ Note that on SENSORS_PROC_REAL_READ, I do not check whether results is
-+ large enough (by checking the incoming value of *nrels). This is not very
-+ good practice, but as long as you put less than about 5 values in results,
-+ you can assume it is large enough. */
-+void lm80_in(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct lm80_data *data = client->data;
-+ int nr = ctl_name - LM80_SYSCTL_IN0;
-+
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 2;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ lm80_update_client(client);
-+ results[0] = IN_FROM_REG(data->in_min[nr]);
-+ results[1] = IN_FROM_REG(data->in_max[nr]);
-+ results[2] = IN_FROM_REG(data->in[nr]);
-+ *nrels_mag = 3;
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ if (*nrels_mag >= 1) {
-+ data->in_min[nr] = IN_TO_REG(results[0]);
-+ lm80_write_value(client, LM80_REG_IN_MIN(nr),
-+ data->in_min[nr]);
-+ }
-+ if (*nrels_mag >= 2) {
-+ data->in_max[nr] = IN_TO_REG(results[1]);
-+ lm80_write_value(client, LM80_REG_IN_MAX(nr),
-+ data->in_max[nr]);
-+ }
-+ }
-+}
-+
-+void lm80_fan(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct lm80_data *data = client->data;
-+ int nr = ctl_name - LM80_SYSCTL_FAN1 + 1;
-+
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 0;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ lm80_update_client(client);
-+ results[0] = FAN_FROM_REG(data->fan_min[nr - 1],
-+ DIV_FROM_REG(data->
-+ fan_div[nr - 1]));
-+ results[1] =
-+ FAN_FROM_REG(data->fan[nr - 1],
-+ DIV_FROM_REG(data->fan_div[nr - 1]));
-+ *nrels_mag = 2;
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ if (*nrels_mag >= 1) {
-+ data->fan_min[nr - 1] = FAN_TO_REG(results[0],
-+ DIV_FROM_REG
-+ (data->
-+ fan_div[nr -
-+ 1]));
-+ lm80_write_value(client,
-+ nr ==
-+ 1 ? LM80_REG_FAN1_MIN :
-+ LM80_REG_FAN2_MIN,
-+ data->fan_min[nr - 1]);
-+ }
-+ }
-+}
-+
-+
-+void lm80_temp(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct lm80_data *data = client->data;
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 2;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ lm80_update_client(client);
-+ results[0] = TEMP_LIMIT_FROM_REG(data->temp_hot_max);
-+ results[1] = TEMP_LIMIT_FROM_REG(data->temp_hot_hyst);
-+ results[2] = TEMP_LIMIT_FROM_REG(data->temp_os_max);
-+ results[3] = TEMP_LIMIT_FROM_REG(data->temp_os_hyst);
-+ results[4] = TEMP_FROM_REG(data->temp);
-+ *nrels_mag = 5;
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ if (*nrels_mag >= 1) {
-+ data->temp_hot_max = TEMP_LIMIT_TO_REG(results[0]);
-+ lm80_write_value(client, LM80_REG_TEMP_HOT_MAX,
-+ data->temp_hot_max);
-+ }
-+ if (*nrels_mag >= 2) {
-+ data->temp_hot_hyst =
-+ TEMP_LIMIT_TO_REG(results[1]);
-+ lm80_write_value(client, LM80_REG_TEMP_HOT_HYST,
-+ data->temp_hot_hyst);
-+ }
-+ if (*nrels_mag >= 3) {
-+ data->temp_os_max = TEMP_LIMIT_TO_REG(results[2]);
-+ lm80_write_value(client, LM80_REG_TEMP_OS_MAX,
-+ data->temp_os_max);
-+ }
-+ if (*nrels_mag >= 4) {
-+ data->temp_os_hyst = TEMP_LIMIT_TO_REG(results[3]);
-+ lm80_write_value(client, LM80_REG_TEMP_OS_HYST,
-+ data->temp_os_hyst);
-+ }
-+ }
-+}
-+
-+void lm80_alarms(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct lm80_data *data = client->data;
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 0;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ lm80_update_client(client);
-+ results[0] = ALARMS_FROM_REG(data->alarms);
-+ *nrels_mag = 1;
-+ }
-+}
-+
-+void lm80_fan_div(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct lm80_data *data = client->data;
-+ int old;
-+
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 0;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ lm80_update_client(client);
-+ results[0] = DIV_FROM_REG(data->fan_div[0]);
-+ results[1] = DIV_FROM_REG(data->fan_div[1]);
-+ results[2] = 2;
-+ *nrels_mag = 3;
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ old = lm80_read_value(client, LM80_REG_FANDIV);
-+ if (*nrels_mag >= 2) {
-+ data->fan_div[1] = DIV_TO_REG(results[1]);
-+ old = (old & 0xcf) | (data->fan_div[1] << 4);
-+ }
-+ if (*nrels_mag >= 1) {
-+ data->fan_div[0] = DIV_TO_REG(results[0]);
-+ old = (old & 0xf3) | (data->fan_div[0] << 2);
-+ lm80_write_value(client, LM80_REG_FANDIV, old);
-+ }
-+ }
-+}
-+
-+static int __init sm_lm80_init(void)
-+{
-+ printk("lm80.o version %s (%s)\n", LM_VERSION, LM_DATE);
-+ return i2c_add_driver(&lm80_driver);
-+}
-+
-+static void __exit sm_lm80_exit(void)
-+{
-+ i2c_del_driver(&lm80_driver);
-+}
-+
-+
-+
-+MODULE_AUTHOR
-+ ("Frodo Looijaard <frodol@dds.nl> and Philip Edelbrock <phil@netroedge.com>");
-+MODULE_DESCRIPTION("LM80 driver");
-+
-+module_init(sm_lm80_init);
-+module_exit(sm_lm80_exit);
---- linux-old/drivers/sensors/lm83.c Thu Jan 1 00:00:00 1970
-+++ linux/drivers/sensors/lm83.c Mon Dec 13 20:18:48 2004
-@@ -0,0 +1,513 @@
-+/*
-+ * lm83.c - Part of lm_sensors, Linux kernel modules for hardware
-+ * monitoring
-+ * Copyright (C) 2003 Jean Delvare <khali@linux-fr.org>
-+ *
-+ * Heavily inspired from the lm78, lm75 and adm1021 drivers. The LM83 is
-+ * a sensor chip made by National Semiconductor. It reports up to four
-+ * temperatures (its own plus up to three external ones) with a 1 deg
-+ * resolution and a 3-4 deg accuracy. Complete datasheet can be obtained
-+ * from National's website at:
-+ * http://www.national.com/pf/LM/LM83.html
-+ * Since the datasheet omits to give the chip stepping code, I give it
-+ * here: 0x03 (at register 0xff).
-+ *
-+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
-+ */
-+
-+#include <linux/module.h>
-+#include <linux/slab.h>
-+#include <linux/i2c.h>
-+#include <linux/i2c-proc.h>
-+#include <linux/init.h>
-+#define LM_DATE "20041007"
-+#define LM_VERSION "2.8.8"
-+
-+/*
-+ * Addresses to scan
-+ * Address is selected using 2 three-level pins, resulting in 9 possible
-+ * addresses.
-+ */
-+
-+static unsigned short normal_i2c[] = { SENSORS_I2C_END };
-+static unsigned short normal_i2c_range[] = { 0x18, 0x1a, 0x29, 0x2b,
-+ 0x4c, 0x4e, SENSORS_I2C_END };
-+static unsigned int normal_isa[] = { SENSORS_ISA_END };
-+static unsigned int normal_isa_range[] = { SENSORS_ISA_END };
-+
-+/*
-+ * Insmod parameters
-+ */
-+
-+SENSORS_INSMOD_1(lm83);
-+
-+/*
-+ * The LM83 registers
-+ * Manufacturer ID is 0x01 for National Semiconductor.
-+ */
-+
-+#define LM83_REG_R_MAN_ID 0xFE
-+#define LM83_REG_R_CHIP_ID 0xFF
-+#define LM83_REG_R_CONFIG 0x03
-+#define LM83_REG_W_CONFIG 0x09
-+#define LM83_REG_R_STATUS1 0x02
-+#define LM83_REG_R_STATUS2 0x35
-+#define LM83_REG_R_LOCAL_TEMP 0x00
-+#define LM83_REG_R_LOCAL_HIGH 0x05
-+#define LM83_REG_W_LOCAL_HIGH 0x0B
-+#define LM83_REG_R_REMOTE1_TEMP 0x30
-+#define LM83_REG_R_REMOTE1_HIGH 0x38
-+#define LM83_REG_W_REMOTE1_HIGH 0x50
-+#define LM83_REG_R_REMOTE2_TEMP 0x01
-+#define LM83_REG_R_REMOTE2_HIGH 0x07
-+#define LM83_REG_W_REMOTE2_HIGH 0x0D
-+#define LM83_REG_R_REMOTE3_TEMP 0x31
-+#define LM83_REG_R_REMOTE3_HIGH 0x3A
-+#define LM83_REG_W_REMOTE3_HIGH 0x52
-+#define LM83_REG_R_TCRIT 0x42
-+#define LM83_REG_W_TCRIT 0x5A
-+
-+/*
-+ * Conversions and various macros
-+ * The LM83 uses signed 8-bit values.
-+ */
-+
-+#define TEMP_FROM_REG(val) ((val) > 127 ? (val) - 0x100 : (val))
-+#define TEMP_TO_REG(val) ((val) <= -50 ? -50 + 0x100 : \
-+ (val) >= 127 ? 127 : \
-+ (val) >= 0 ? (val) : \
-+ (val) + 0x100)
-+
-+static const u8 LM83_REG_R_TEMP[] = {
-+ LM83_REG_R_LOCAL_TEMP,
-+ LM83_REG_R_REMOTE1_TEMP,
-+ LM83_REG_R_REMOTE2_TEMP,
-+ LM83_REG_R_REMOTE3_TEMP
-+};
-+
-+static const u8 LM83_REG_R_HIGH[] = {
-+ LM83_REG_R_LOCAL_HIGH,
-+ LM83_REG_R_REMOTE1_HIGH,
-+ LM83_REG_R_REMOTE2_HIGH,
-+ LM83_REG_R_REMOTE3_HIGH
-+};
-+
-+static const u8 LM83_REG_W_HIGH[] = {
-+ LM83_REG_W_LOCAL_HIGH,
-+ LM83_REG_W_REMOTE1_HIGH,
-+ LM83_REG_W_REMOTE2_HIGH,
-+ LM83_REG_W_REMOTE3_HIGH
-+};
-+
-+/*
-+ * Functions declaration
-+ */
-+
-+static int lm83_attach_adapter(struct i2c_adapter *adapter);
-+static int lm83_detect(struct i2c_adapter *adapter, int address, unsigned
-+ short flags, int kind);
-+static int lm83_detach_client(struct i2c_client *client);
-+static void lm83_update_client(struct i2c_client *client);
-+static void lm83_temp(struct i2c_client *client, int operation, int
-+ ctl_name, int *nrels_mag, long *results);
-+static void lm83_tcrit(struct i2c_client *client, int operation, int
-+ ctl_name, int *nrels_mag, long *results);
-+static void lm83_alarms(struct i2c_client *client, int operation, int
-+ ctl_name, int *nrels_mag, long *results);
-+
-+/*
-+ * Driver data (common to all clients)
-+ */
-+
-+static struct i2c_driver lm83_driver = {
-+ .owner = THIS_MODULE,
-+ .name = "LM83 sensor driver",
-+ .id = I2C_DRIVERID_LM83,
-+ .flags = I2C_DF_NOTIFY,
-+ .attach_adapter = lm83_attach_adapter,
-+ .detach_client = lm83_detach_client,
-+};
-+
-+/*
-+ * Client data (each client gets its own)
-+ */
-+
-+struct lm83_data
-+{
-+ struct i2c_client client;
-+ int sysctl_id;
-+
-+ struct semaphore update_lock;
-+ char valid; /* zero until following fields are valid */
-+ unsigned long last_updated; /* in jiffies */
-+
-+ /* registers values */
-+ u8 temp[4], temp_high[4], tcrit;
-+ u16 alarms; /* bitvector, combined */
-+};
-+
-+/*
-+ * Proc entries
-+ * These files are created for each detected LM83.
-+ */
-+
-+/* -- SENSORS SYSCTL START -- */
-+
-+#define LM83_SYSCTL_LOCAL_TEMP 1200
-+#define LM83_SYSCTL_REMOTE1_TEMP 1201
-+#define LM83_SYSCTL_REMOTE2_TEMP 1202
-+#define LM83_SYSCTL_REMOTE3_TEMP 1203
-+#define LM83_SYSCTL_TCRIT 1208
-+#define LM83_SYSCTL_ALARMS 1210
-+
-+#define LM83_ALARM_LOCAL_HIGH 0x0040
-+#define LM83_ALARM_LOCAL_CRIT 0x0001
-+#define LM83_ALARM_REMOTE1_HIGH 0x8000
-+#define LM83_ALARM_REMOTE1_CRIT 0x0100
-+#define LM83_ALARM_REMOTE1_OPEN 0x2000
-+#define LM83_ALARM_REMOTE2_HIGH 0x0010
-+#define LM83_ALARM_REMOTE2_CRIT 0x0002
-+#define LM83_ALARM_REMOTE2_OPEN 0x0004
-+#define LM83_ALARM_REMOTE3_HIGH 0x1000
-+#define LM83_ALARM_REMOTE3_CRIT 0x0200
-+#define LM83_ALARM_REMOTE3_OPEN 0x0400
-+
-+/* -- SENSORS SYSCTL END -- */
-+
-+
-+static ctl_table lm83_dir_table_template[] =
-+{
-+ {LM83_SYSCTL_LOCAL_TEMP, "temp1", NULL, 0, 0644, NULL,
-+ &i2c_proc_real, &i2c_sysctl_real, NULL, &lm83_temp},
-+ {LM83_SYSCTL_REMOTE1_TEMP, "temp2", NULL, 0, 0644, NULL,
-+ &i2c_proc_real, &i2c_sysctl_real, NULL, &lm83_temp},
-+ {LM83_SYSCTL_REMOTE2_TEMP, "temp3", NULL, 0, 0644, NULL,
-+ &i2c_proc_real, &i2c_sysctl_real, NULL, &lm83_temp},
-+ {LM83_SYSCTL_REMOTE3_TEMP, "temp4", NULL, 0, 0644, NULL,
-+ &i2c_proc_real, &i2c_sysctl_real, NULL, &lm83_temp},
-+ {LM83_SYSCTL_TCRIT, "tcrit", NULL, 0, 0644, NULL,
-+ &i2c_proc_real, &i2c_sysctl_real, NULL, &lm83_tcrit},
-+ {LM83_SYSCTL_ALARMS, "alarms", NULL, 0, 0444, NULL,
-+ &i2c_proc_real, &i2c_sysctl_real, NULL, &lm83_alarms},
-+ {0}
-+};
-+
-+/*
-+ * Internal variables
-+ */
-+
-+static int lm83_id = 0;
-+
-+/*
-+ * Real code
-+ */
-+
-+static int lm83_attach_adapter(struct i2c_adapter *adapter)
-+{
-+ return i2c_detect(adapter, &addr_data, lm83_detect);
-+}
-+
-+/*
-+ * The following function does more than just detection. If detection
-+ * succeeds, it also registers the new chip.
-+ */
-+static int lm83_detect(struct i2c_adapter *adapter, int address, unsigned
-+ short flags, int kind)
-+{
-+ struct i2c_client *new_client;
-+ struct lm83_data *data;
-+ int err = 0;
-+ const char *type_name = "";
-+ const char *client_name = "";
-+
-+#ifdef DEBUG
-+ if (i2c_is_isa_adapter(adapter))
-+ {
-+ printk("lm83.o: Called for an ISA bus adapter, aborting.\n");
-+ return 0;
-+ }
-+#endif
-+
-+ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
-+ {
-+#ifdef DEBUG
-+ printk("lm83.o: I2C bus doesn't support byte read mode, "
-+ "skipping.\n");
-+#endif
-+ return 0;
-+ }
-+
-+ if (!(data = kmalloc(sizeof(struct lm83_data), GFP_KERNEL)))
-+ {
-+ printk("lm83.o: Out of memory in lm83_detect (new_client).\n");
-+ return -ENOMEM;
-+ }
-+
-+ /*
-+ * The common I2C client data is placed right before the
-+ * LM83-specific data. The LM83-specific data is pointed to by the
-+ * data field from the I2C client data.
-+ */
-+
-+ new_client = &data->client;
-+ new_client->addr = address;
-+ new_client->data = data;
-+ new_client->adapter = adapter;
-+ new_client->driver = &lm83_driver;
-+ new_client->flags = 0;
-+
-+ /*
-+ * Now we do the remaining detection. A negative kind means that
-+ * the driver was loaded with no force parameter (default), so we
-+ * must both detect and identify the chip (actually there is only
-+ * one possible kind of chip for now, LM83). A zero kind means that
-+ * the driver was loaded with the force parameter, the detection
-+ * step shall be skipped. A positive kind means that the driver
-+ * was loaded with the force parameter and a given kind of chip is
-+ * requested, so both the detection and the identification steps
-+ * are skipped.
-+ */
-+
-+ /* Default to an LM83 if forced */
-+ if (kind == 0)
-+ kind = lm83;
-+
-+ if (kind < 0) /* detection */
-+ {
-+ if (((i2c_smbus_read_byte_data(new_client, LM83_REG_R_STATUS1)
-+ & 0xA8) != 0x00)
-+ || ((i2c_smbus_read_byte_data(new_client, LM83_REG_R_STATUS2)
-+ & 0x48) != 0x00)
-+ || ((i2c_smbus_read_byte_data(new_client, LM83_REG_R_CONFIG)
-+ & 0x41) != 0x00))
-+ {
-+#ifdef DEBUG
-+ printk(KERN_DEBUG "lm83.o: Detection failed at 0x%02x.\n",
-+ address);
-+#endif
-+ goto ERROR1;
-+ }
-+ }
-+
-+ if (kind <= 0) /* identification */
-+ {
-+ u8 man_id, chip_id;
-+
-+ man_id = i2c_smbus_read_byte_data(new_client, LM83_REG_R_MAN_ID);
-+ chip_id = i2c_smbus_read_byte_data(new_client, LM83_REG_R_CHIP_ID);
-+ if (man_id == 0x01) /* National Semiconductor */
-+ {
-+ if (chip_id == 0x03)
-+ kind = lm83;
-+ }
-+ }
-+
-+ if (kind <= 0) /* identification failed */
-+ {
-+ printk("lm83.o: Unsupported chip.\n");
-+ goto ERROR1;
-+ }
-+
-+ if (kind == lm83)
-+ {
-+ type_name = "lm83";
-+ client_name = "LM83 chip";
-+ }
-+ else
-+ {
-+ printk("lm83.o: Unknown kind %d.\n", kind);
-+ goto ERROR1;
-+ }
-+
-+ /*
-+ * OK, we got a valid chip so we can fill in the remaining client
-+ * fields.
-+ */
-+
-+ strcpy(new_client->name, client_name);
-+ new_client->id = lm83_id++;
-+ data->valid = 0;
-+ init_MUTEX(&data->update_lock);
-+
-+ /*
-+ * Tell the I2C layer a new client has arrived.
-+ */
-+
-+ if ((err = i2c_attach_client(new_client)))
-+ {
-+#ifdef DEBUG
-+ printk("lm83.o: Failed attaching client.\n");
-+#endif
-+ goto ERROR1;
-+ }
-+
-+ /*
-+ * Register a new directory entry.
-+ */
-+
-+ if ((err = i2c_register_entry(new_client, type_name,
-+ lm83_dir_table_template)) < 0)
-+ {
-+#ifdef DEBUG
-+ printk("lm83.o: Failed registering directory entry.\n");
-+#endif
-+ goto ERROR2;
-+ }
-+ data->sysctl_id = err;
-+
-+ /*
-+ * Initialize the LM83 chip
-+ * (Nothing to do for this one.)
-+ */
-+
-+ return 0;
-+
-+ ERROR2:
-+ i2c_detach_client(new_client);
-+ ERROR1:
-+ kfree(data);
-+ return err;
-+}
-+
-+static int lm83_detach_client(struct i2c_client *client)
-+{
-+ int err;
-+
-+ i2c_deregister_entry(((struct lm83_data *) (client->data))->sysctl_id);
-+ if ((err = i2c_detach_client(client)))
-+ {
-+ printk("lm83.o: Client deregistration failed, client not "
-+ "detached.\n");
-+ return err;
-+ }
-+
-+ kfree(client->data);
-+ return 0;
-+}
-+
-+static void lm83_update_client(struct i2c_client *client)
-+{
-+ struct lm83_data *data = client->data;
-+
-+ down(&data->update_lock);
-+
-+ if ((jiffies - data->last_updated > HZ * 2) ||
-+ (jiffies < data->last_updated) || !data->valid)
-+ {
-+ int nr;
-+#ifdef DEBUG
-+ printk("lm83.o: Updating LM83 data.\n");
-+#endif
-+ for (nr = 0; nr < 4 ; nr++)
-+ {
-+ data->temp[nr] =
-+ i2c_smbus_read_byte_data(client, LM83_REG_R_TEMP[nr]);
-+ data->temp_high[nr] =
-+ i2c_smbus_read_byte_data(client, LM83_REG_R_HIGH[nr]);
-+ }
-+ data->tcrit = i2c_smbus_read_byte_data(client, LM83_REG_R_TCRIT);
-+ data->alarms =
-+ i2c_smbus_read_byte_data(client, LM83_REG_R_STATUS1) +
-+ (i2c_smbus_read_byte_data(client, LM83_REG_R_STATUS2) << 8);
-+
-+ data->last_updated = jiffies;
-+ data->valid = 1;
-+ }
-+
-+ up(&data->update_lock);
-+}
-+
-+static void lm83_temp(struct i2c_client *client, int operation, int
-+ ctl_name, int *nrels_mag, long *results)
-+{
-+ struct lm83_data *data = client->data;
-+ int nr = ctl_name - LM83_SYSCTL_LOCAL_TEMP;
-+
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 0; /* magnitude */
-+ else if (operation == SENSORS_PROC_REAL_READ)
-+ {
-+ lm83_update_client(client);
-+ results[0] = TEMP_FROM_REG(data->temp_high[nr]);
-+ results[1] = TEMP_FROM_REG(data->temp[nr]);
-+ *nrels_mag = 2;
-+ }
-+ else if (operation == SENSORS_PROC_REAL_WRITE)
-+ {
-+ if (*nrels_mag >= 1)
-+ {
-+ data->temp_high[nr] = TEMP_TO_REG(results[0]);
-+ i2c_smbus_write_byte_data(client, LM83_REG_W_HIGH[nr],
-+ data->temp_high[nr]);
-+ }
-+ }
-+}
-+
-+static void lm83_tcrit(struct i2c_client *client, int operation, int
-+ ctl_name, int *nrels_mag, long *results)
-+{
-+ struct lm83_data *data = client->data;
-+
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 0; /* magnitude */
-+ else if (operation == SENSORS_PROC_REAL_READ)
-+ {
-+ lm83_update_client(client);
-+ results[0] = TEMP_FROM_REG(data->tcrit);
-+ *nrels_mag = 1;
-+ }
-+ else if (operation == SENSORS_PROC_REAL_WRITE)
-+ {
-+ if (*nrels_mag >= 1)
-+ {
-+ data->tcrit = TEMP_TO_REG(results[0]);
-+ i2c_smbus_write_byte_data(client, LM83_REG_W_TCRIT,
-+ data->tcrit);
-+ }
-+ }
-+}
-+
-+static void lm83_alarms(struct i2c_client *client, int operation, int
-+ ctl_name, int *nrels_mag, long *results)
-+{
-+ struct lm83_data *data = client->data;
-+
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 0; /* magnitude */
-+ else if (operation == SENSORS_PROC_REAL_READ)
-+ {
-+ lm83_update_client(client);
-+ results[0] = data->alarms;
-+ *nrels_mag = 1;
-+ }
-+}
-+
-+static int __init sm_lm83_init(void)
-+{
-+ printk(KERN_INFO "lm83.o version %s (%s)\n", LM_VERSION, LM_DATE);
-+ return i2c_add_driver(&lm83_driver);
-+}
-+
-+static void __exit sm_lm83_exit(void)
-+{
-+ i2c_del_driver(&lm83_driver);
-+}
-+
-+MODULE_AUTHOR("Jean Delvare <khali@linux-fr.org>");
-+MODULE_DESCRIPTION("LM83 sensor driver");
-+MODULE_LICENSE("GPL");
-+
-+module_init(sm_lm83_init);
-+module_exit(sm_lm83_exit);
---- linux-old/drivers/sensors/lm85.c Thu Jan 1 00:00:00 1970
-+++ linux/drivers/sensors/lm85.c Mon Dec 13 20:18:49 2004
-@@ -0,0 +1,2043 @@
-+/*
-+ lm85.c - Part of lm_sensors, Linux kernel modules for hardware
-+ monitoring
-+ Copyright (c) 1998, 1999 Frodo Looijaard <frodol@dds.nl>
-+ Copyright (c) 2002, 2003 Philip Pokorny <ppokorny@penguincomputing.com>
-+ Copyright (c) 2003 Margit Schubert-While <margitsw@t-online.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., 675 Mass Ave, Cambridge, MA 02139, USA.
-+
-+ CHANGELOG
-+
-+ 2002-11-13 First patch for LM85 functionality
-+ 2002-11-18 LM85 functionality mostly done
-+ 2002-12-02 Adding ADM1027 functionality
-+ 2002-12-06 Adding ADT7463 functionality
-+ 2003-01-09 Code cleanup.
-+ Save reserved bits in case they are implemented
-+ in a future chip. (Solve problem with lockups
-+ on ADM1027 due to chip initialization)
-+ Added chip initialization bypass option
-+ 2003-02-12 Add THERM asserted counts for ADT7463
-+ Added #ifdef so we can compile against 2.6.5
-+ without updating i2c-ids.h
-+ 2003-02-17 Prepare for switch to 2.7.0 development
-+ Implement tmin_control for ADT7463
-+ Expose THERM asserted counts to /proc
-+ Code cleanup
-+ 2003-02-19 Working with Margit and LM_SENSORS developers
-+ 2003-02-23 Removed chip initialization entirely
-+ Scale voltages in driver at Margit's request
-+ Change PWM from 0-100% to 0-255 per LM sensors standard
-+ 2003-02-27 Documentation and code cleanups
-+ Added this CHANGELOG
-+ Print additional precision for temperatures and voltages
-+ Many thanks to Margit Schubert-While and Brandt xxxxxx
-+ for help testing this version
-+ 2003-02-28 More diagnostic messages regarding BIOS setup
-+ 2003-03-01 Added Interrupt mask register support.
-+ 2003-03-08 Fixed problem with pseudo 16-bit registers
-+ Cleaned up some compiler warnings.
-+ Fixed problem with Operating Point and THERM counting
-+ 2003-03-21 Initial support for EMC6D100 and EMC6D101 chips
-+ 2003-06-30 Add support for EMC6D100 extra voltage inputs.
-+*/
-+
-+#include <linux/version.h>
-+#include <linux/module.h>
-+#include <linux/slab.h>
-+#include <linux/i2c.h>
-+#include <linux/i2c-proc.h>
-+#include <linux/init.h>
-+#define LM_DATE "20041007"
-+#define LM_VERSION "2.8.8"
-+#include <linux/sensors_vid.h>
-+
-+#ifndef I2C_DRIVERID_LM85
-+#define I2C_DRIVERID_LM85 1039
-+#endif
-+
-+/* Addresses to scan */
-+static unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, SENSORS_I2C_END };
-+static unsigned short normal_i2c_range[] = { SENSORS_I2C_END };
-+static unsigned int normal_isa[] = { SENSORS_ISA_END };
-+static unsigned int normal_isa_range[] = { SENSORS_ISA_END };
-+
-+/* Insmod parameters */
-+SENSORS_INSMOD_5(lm85b, lm85c, adm1027, adt7463, emc6d100);
-+
-+/* Many LM85 constants specified below */
-+
-+/* The LM85 registers */
-+#define LM85_REG_IN(nr) (0x20 + (nr))
-+#define LM85_REG_IN_MIN(nr) (0x44 + (nr) * 2)
-+#define LM85_REG_IN_MAX(nr) (0x45 + (nr) * 2)
-+
-+#define LM85_REG_TEMP(nr) (0x25 + (nr))
-+#define LM85_REG_TEMP_MIN(nr) (0x4e + (nr) * 2)
-+#define LM85_REG_TEMP_MAX(nr) (0x4f + (nr) * 2)
-+
-+/* Fan speeds are LSB, MSB (2 bytes) */
-+#define LM85_REG_FAN(nr) (0x28 + (nr) *2)
-+#define LM85_REG_FAN_MIN(nr) (0x54 + (nr) *2)
-+
-+#define LM85_REG_PWM(nr) (0x30 + (nr))
-+
-+#define ADT7463_REG_OPPOINT(nr) (0x33 + (nr))
-+
-+#define ADT7463_REG_TMIN_CTL1 0x36
-+#define ADT7463_REG_TMIN_CTL2 0x37
-+#define ADT7463_REG_TMIN_CTL 0x0136
-+
-+#define LM85_REG_DEVICE 0x3d
-+#define LM85_REG_COMPANY 0x3e
-+#define LM85_REG_VERSTEP 0x3f
-+/* These are the recognized values for the above regs */
-+#define LM85_DEVICE_ADX 0x27
-+#define LM85_COMPANY_NATIONAL 0x01
-+#define LM85_COMPANY_ANALOG_DEV 0x41
-+#define LM85_COMPANY_SMSC 0x5c
-+#define LM85_VERSTEP_VMASK 0xf0
-+#define LM85_VERSTEP_SMASK 0x0f
-+#define LM85_VERSTEP_GENERIC 0x60
-+#define LM85_VERSTEP_LM85C 0x60
-+#define LM85_VERSTEP_LM85B 0x62
-+#define LM85_VERSTEP_ADM1027 0x60
-+#define LM85_VERSTEP_ADT7463 0x62
-+#define LM85_VERSTEP_EMC6D100_A0 0x60
-+#define LM85_VERSTEP_EMC6D100_A1 0x61
-+
-+#define LM85_REG_CONFIG 0x40
-+
-+#define LM85_REG_ALARM1 0x41
-+#define LM85_REG_ALARM2 0x42
-+#define LM85_REG_ALARM 0x0141
-+
-+#define LM85_REG_VID 0x43
-+
-+/* Automated FAN control */
-+#define LM85_REG_AFAN_CONFIG(nr) (0x5c + (nr))
-+#define LM85_REG_AFAN_RANGE(nr) (0x5f + (nr))
-+#define LM85_REG_AFAN_SPIKE1 0x62
-+#define LM85_REG_AFAN_SPIKE2 0x63
-+#define LM85_REG_AFAN_MINPWM(nr) (0x64 + (nr))
-+#define LM85_REG_AFAN_LIMIT(nr) (0x67 + (nr))
-+#define LM85_REG_AFAN_CRITICAL(nr) (0x6a + (nr))
-+#define LM85_REG_AFAN_HYST1 0x6d
-+#define LM85_REG_AFAN_HYST2 0x6e
-+
-+#define LM85_REG_TACH_MODE 0x74
-+#define LM85_REG_SPINUP_CTL 0x75
-+
-+#define ADM1027_REG_TEMP_OFFSET(nr) (0x70 + (nr))
-+#define ADM1027_REG_CONFIG2 0x73
-+#define ADM1027_REG_INTMASK1 0x74
-+#define ADM1027_REG_INTMASK2 0x75
-+#define ADM1027_REG_INTMASK 0x0174
-+#define ADM1027_REG_EXTEND_ADC1 0x76
-+#define ADM1027_REG_EXTEND_ADC2 0x77
-+#define ADM1027_REG_EXTEND_ADC 0x0176
-+#define ADM1027_REG_CONFIG3 0x78
-+#define ADM1027_REG_FAN_PPR 0x7b
-+
-+#define ADT7463_REG_THERM 0x79
-+#define ADT7463_REG_THERM_LIMIT 0x7A
-+#define ADT7463_REG_CONFIG4 0x7D
-+
-+#define EMC6D100_REG_SFR 0x7c
-+#define EMC6D100_REG_ALARM3 0x7d
-+#define EMC6D100_REG_CONF 0x7f
-+#define EMC6D100_REG_INT_EN 0x80
-+/* IN5, IN6 and IN7 */
-+#define EMC6D100_REG_IN(nr) (0x70 + ((nr)-5))
-+#define EMC6D100_REG_IN_MIN(nr) (0x73 + ((nr)-5) * 2)
-+#define EMC6D100_REG_IN_MAX(nr) (0x74 + ((nr)-5) * 2)
-+
-+/* Conversions. Rounding and limit checking is only done on the TO_REG
-+ variants. Note that you should be a bit careful with which arguments
-+ these macros are called: arguments may be evaluated more than once.
-+ */
-+
-+/* IN are scaled 1.000 == 0xc0, mag = 3 */
-+#define IN_TO_REG(val) (SENSORS_LIMIT((((val)*0xc0+500)/1000),0,255))
-+#define INEXT_FROM_REG(val,ext) (((val)*1000 + (ext)*250 + 96)/0xc0)
-+#define IN_FROM_REG(val) (INEXT_FROM_REG(val,0))
-+
-+/* IN are scaled acording to built-in resistors */
-+static int lm85_scaling[] = { /* .001 Volts */
-+ 2500, 2250, 3300, 5000, 12000,
-+ 3300, 1500, 1800, /* EMC6D100 */
-+ };
-+#define SCALE(val,from,to) (((val)*(to) + ((from)/2))/(from))
-+#define INS_TO_REG(n,val) (SENSORS_LIMIT(SCALE(val,lm85_scaling[n],192),0,255))
-+#define INSEXT_FROM_REG(n,val,ext) (SCALE((val)*4 + (ext),192*4,lm85_scaling[n]))
-+#define INS_FROM_REG(n,val) (INSEXT_FROM_REG(n,val,0))
-+
-+/* FAN speed is measured using 90kHz clock */
-+#define FAN_TO_REG(val) (SENSORS_LIMIT( (val)<=0?0: 5400000/(val),0,65534))
-+#define FAN_FROM_REG(val) ((val)==0?-1:(val)==0xffff?0:5400000/(val))
-+
-+/* Temperature is reported in .01 degC increments */
-+#define TEMP_TO_REG(val) (SENSORS_LIMIT(((val)+50)/100,-127,127))
-+#define TEMPEXT_FROM_REG(val,ext) ((val)*100 + (ext)*25)
-+#define TEMP_FROM_REG(val) (TEMPEXT_FROM_REG(val,0))
-+#define EXTTEMP_TO_REG(val) (SENSORS_LIMIT((val)/25,-127,127))
-+#define OPPOINT_TO_REG(val) (SENSORS_LIMIT(val,-127,127))
-+#define OPPOINT_FROM_REG(val) (val)
-+
-+#define PWM_TO_REG(val) (SENSORS_LIMIT(val,0,255))
-+#define PWM_FROM_REG(val) (val)
-+
-+#define EXT_FROM_REG(val,sensor) (((val)>>(sensor * 2))&0x03)
-+
-+/* ZONEs have the following parameters:
-+ * Limit (low) temp, 1. degC
-+ * Hysteresis (below limit), 1. degC (0-15)
-+ * Range of speed control, .1 degC (2-80)
-+ * Critical (high) temp, 1. degC
-+ *
-+ * FAN PWMs have the following parameters:
-+ * Reference Zone, 1, 2, 3, etc.
-+ * Spinup time, .05 sec
-+ * PWM value at limit/low temp, 1 count
-+ * PWM Frequency, 1. Hz
-+ * PWM is Min or OFF below limit, flag
-+ * Invert PWM output, flag
-+ *
-+ * Some chips filter the temp, others the fan.
-+ * Filter constant (or disabled) .1 seconds
-+ */
-+
-+/* These are the zone temperature range encodings */
-+static int lm85_range_map[] = { /* .1 degC */
-+ 20, 25, 33, 40, 50, 66,
-+ 80, 100, 133, 160, 200, 266,
-+ 320, 400, 533, 800
-+ };
-+static int RANGE_TO_REG( int range )
-+{
-+ int i;
-+
-+ if( range >= lm85_range_map[15] ) { return 15 ; }
-+ for( i = 0 ; i < 15 ; ++i )
-+ if( range <= lm85_range_map[i] )
-+ break ;
-+ return( i & 0x0f );
-+}
-+#define RANGE_FROM_REG(val) (lm85_range_map[(val)&0x0f])
-+
-+/* These are the Acoustic Enhancement, or Temperature smoothing encodings
-+ * NOTE: The enable/disable bit is INCLUDED in these encodings as the
-+ * MSB (bit 3, value 8). If the enable bit is 0, the encoded value
-+ * is ignored, or set to 0.
-+ */
-+static int lm85_smooth_map[] = { /* .1 sec */
-+ 350, 176, 118, 70, 44, 30, 16, 8
-+/* 35.4 * 1/1, 1/2, 1/3, 1/5, 1/8, 1/12, 1/24, 1/48 */
-+ };
-+static int SMOOTH_TO_REG( int smooth )
-+{
-+ int i;
-+
-+ if( smooth <= 0 ) { return 0 ; } /* Disabled */
-+ for( i = 0 ; i < 7 ; ++i )
-+ if( smooth >= lm85_smooth_map[i] )
-+ break ;
-+ return( (i & 0x07) | 0x08 );
-+}
-+#define SMOOTH_FROM_REG(val) ((val)&0x08?lm85_smooth_map[(val)&0x07]:0)
-+
-+/* These are the fan spinup delay time encodings */
-+static int lm85_spinup_map[] = { /* .1 sec */
-+ 0, 1, 2, 4, 7, 10, 20, 40
-+ };
-+static int SPINUP_TO_REG( int spinup )
-+{
-+ int i;
-+
-+ if( spinup >= lm85_spinup_map[7] ) { return 7 ; }
-+ for( i = 0 ; i < 7 ; ++i )
-+ if( spinup <= lm85_spinup_map[i] )
-+ break ;
-+ return( i & 0x07 );
-+}
-+#define SPINUP_FROM_REG(val) (lm85_spinup_map[(val)&0x07])
-+
-+/* These are the PWM frequency encodings */
-+static int lm85_freq_map[] = { /* .1 Hz */
-+ 100, 150, 230, 300, 380, 470, 620, 980
-+ };
-+static int FREQ_TO_REG( int freq )
-+{
-+ int i;
-+
-+ if( freq >= lm85_freq_map[7] ) { return 7 ; }
-+ for( i = 0 ; i < 7 ; ++i )
-+ if( freq <= lm85_freq_map[i] )
-+ break ;
-+ return( i & 0x07 );
-+}
-+#define FREQ_FROM_REG(val) (lm85_freq_map[(val)&0x07])
-+
-+/* Since we can't use strings, I'm abusing these numbers
-+ * to stand in for the following meanings:
-+ * 1 -- PWM responds to Zone 1
-+ * 2 -- PWM responds to Zone 2
-+ * 3 -- PWM responds to Zone 3
-+ * 23 -- PWM responds to the higher temp of Zone 2 or 3
-+ * 123 -- PWM responds to highest of Zone 1, 2, or 3
-+ * 0 -- PWM is always at 0% (ie, off)
-+ * -1 -- PWM is always at 100%
-+ * -2 -- PWM responds to manual control
-+ */
-+static int lm85_zone_map[] = { 1, 2, 3, -1, 0, 23, 123, -2 };
-+static int ZONE_TO_REG( int zone )
-+{
-+ int i;
-+
-+ for( i = 0 ; i <= 7 ; ++i )
-+ if( zone == lm85_zone_map[i] )
-+ break ;
-+ if( i > 7 ) /* Not found. */
-+ i = 3; /* Always 100% */
-+ return( (i & 0x07)<<5 );
-+}
-+#define ZONE_FROM_REG(val) (lm85_zone_map[((val)>>5)&0x07])
-+
-+#define HYST_TO_REG(val) (SENSORS_LIMIT((-(val)+5)/10,0,15))
-+#define HYST_FROM_REG(val) (-(val)*10)
-+
-+#define OFFSET_TO_REG(val) (SENSORS_LIMIT((val)/25,-127,127))
-+#define OFFSET_FROM_REG(val) ((val)*25)
-+
-+#define PPR_MASK(fan) (0x03<<(fan *2))
-+#define PPR_TO_REG(val,fan) (SENSORS_LIMIT((val)-1,0,3)<<(fan *2))
-+#define PPR_FROM_REG(val,fan) ((((val)>>(fan * 2))&0x03)+1)
-+
-+/* sensors_vid.h defines vid_from_reg() */
-+#define VID_FROM_REG(val,vrm) (vid_from_reg((val),(vrm)))
-+
-+#define ALARMS_FROM_REG(val) (val)
-+
-+/* When converting to REG, we need to fixup the carry-over bit */
-+#define INTMASK_FROM_REG(val) (val)
-+#define INTMASK_TO_REG(val) (SENSORS_LIMIT((val)|((val)&0xff00?0x80:0),0,65535))
-+
-+/* Unlike some other drivers we DO NOT set initial limits. Use
-+ * the config file to set limits. Some users have reported
-+ * motherboards shutting down when we set limits in a previous
-+ * version of this driver. This may be caused by APM/ACPI
-+ * detecting an out-of-limit condition when we had the wrong
-+ * limits set.
-+ */
-+
-+/* Typically used with Pentium 4 systems v9.1 VRM spec */
-+#define LM85_INIT_VRM 91
-+
-+/* Chip sampling rates
-+ *
-+ * Some sensors are not updated more frequently than once per second
-+ * so it doesn't make sense to read them more often than that.
-+ * We cache the results and return the saved data if the driver
-+ * is called again before a second has elapsed.
-+ *
-+ * Also, there is significant configuration data for this chip
-+ * given the automatic PWM fan control that is possible. There
-+ * are about 47 bytes of config data to only 22 bytes of actual
-+ * readings. So, we keep the config data up to date in the cache
-+ * when it is written and only sample it once every 5 *minutes*
-+ */
-+#define LM85_DATA_INTERVAL (1 * HZ)
-+#define LM85_CONFIG_INTERVAL (5 * 60 * HZ)
-+
-+/* For each registered LM85, we need to keep some data in memory. That
-+ data is pointed to by client->data. The structure itself is
-+ dynamically allocated, when a new lm85 client is allocated. */
-+
-+/* LM85 can automatically adjust fan speeds based on temperature
-+ * This structure encapsulates an entire Zone config. There are
-+ * three zones (one for each temperature input) on the lm85
-+ */
-+struct lm85_zone {
-+ s8 limit; /* Low temp limit */
-+ u8 hyst; /* Low limit hysteresis. (0-15) */
-+ u8 range; /* Temp range, encoded */
-+ s8 critical; /* "All fans ON" temp limit */
-+};
-+
-+struct lm85_autofan {
-+ u8 config; /* Register value */
-+ u8 freq; /* PWM frequency, encoded */
-+ u8 min_pwm; /* Minimum PWM value, encoded */
-+ u8 min_off; /* Min PWM or OFF below "limit", flag */
-+};
-+
-+struct lm85_data {
-+ struct i2c_client client;
-+ struct semaphore lock;
-+ int sysctl_id;
-+ enum chips type;
-+
-+ struct semaphore update_lock;
-+ int valid; /* !=0 if following fields are valid */
-+ unsigned long last_reading; /* In jiffies */
-+ unsigned long last_config; /* In jiffies */
-+
-+ u8 in[8]; /* Register value */
-+ u8 in_max[8]; /* Register value */
-+ u8 in_min[8]; /* Register value */
-+ s8 temp[3]; /* Register value */
-+ s8 temp_min[3]; /* Register value */
-+ s8 temp_max[3]; /* Register value */
-+ s8 temp_offset[3]; /* Register value */
-+ u16 fan[4]; /* Register value */
-+ u16 fan_min[4]; /* Register value */
-+ u8 pwm[3]; /* Register value */
-+ u8 spinup_ctl; /* Register encoding, combined */
-+ u8 tach_mode; /* Register encoding, combined */
-+ u16 extend_adc; /* Register value */
-+ u8 fan_ppr; /* Register value */
-+ u8 smooth[3]; /* Register encoding */
-+ u8 vid; /* Register value */
-+ u8 vrm; /* VRM version */
-+ u8 syncpwm3; /* Saved PWM3 for TACH 2,3,4 config */
-+ s8 oppoint[3]; /* Register value */
-+ u16 tmin_ctl; /* Register value */
-+ long therm_total; /* Cummulative therm count */
-+ long therm_ovfl; /* Count of therm overflows */
-+ u8 therm_limit; /* Register value */
-+ u32 alarms; /* Register encoding, combined */
-+ u32 alarm_mask; /* Register encoding, combined */
-+ struct lm85_autofan autofan[3];
-+ struct lm85_zone zone[3];
-+};
-+
-+static int lm85_attach_adapter(struct i2c_adapter *adapter);
-+static int lm85_detect(struct i2c_adapter *adapter, int address,
-+ unsigned short flags, int kind);
-+static int lm85_detach_client(struct i2c_client *client);
-+static int lm85_read_value(struct i2c_client *client, u16 register);
-+static int lm85_write_value(struct i2c_client *client, u16 register, int value);
-+static void lm85_update_client(struct i2c_client *client);
-+static void lm85_init_client(struct i2c_client *client);
-+
-+
-+static void lm85_in(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results);
-+static void lm85_fan(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void lm85_temp(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void lm85_vid(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void lm85_vrm(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void lm85_alarms(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void lm85_pwm(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void lm85_zone(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void lm85_pwm_config(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void lm85_pwm_zone(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void lm85_smooth(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+
-+static void lm85_spinup_ctl(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void lm85_tach_mode(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+
-+static void adm1027_tach_mode(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void adm1027_temp_offset(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void adm1027_fan_ppr(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void adm1027_alarm_mask(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+
-+static void adt7463_tmin_ctl(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void adt7463_therm_signal(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+
-+static void emc6d100_in(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+
-+static struct i2c_driver lm85_driver = {
-+ .owner = THIS_MODULE,
-+ .name = "LM85 compatible sensor driver",
-+ .id = I2C_DRIVERID_LM85,
-+ .flags = I2C_DF_NOTIFY,
-+ .attach_adapter = &lm85_attach_adapter,
-+ .detach_client = &lm85_detach_client,
-+};
-+
-+/* Unique ID assigned to each LM85 detected */
-+static int lm85_id = 0;
-+
-+/* -- SENSORS SYSCTL START -- */
-+/* Common parameters */
-+#define LM85_SYSCTL_IN0 1000
-+#define LM85_SYSCTL_IN1 1001
-+#define LM85_SYSCTL_IN2 1002
-+#define LM85_SYSCTL_IN3 1003
-+#define LM85_SYSCTL_IN4 1004
-+#define LM85_SYSCTL_FAN1 1005
-+#define LM85_SYSCTL_FAN2 1006
-+#define LM85_SYSCTL_FAN3 1007
-+#define LM85_SYSCTL_FAN4 1008
-+#define LM85_SYSCTL_TEMP1 1009
-+#define LM85_SYSCTL_TEMP2 1010
-+#define LM85_SYSCTL_TEMP3 1011
-+#define LM85_SYSCTL_VID 1012
-+#define LM85_SYSCTL_ALARMS 1013
-+#define LM85_SYSCTL_PWM1 1014
-+#define LM85_SYSCTL_PWM2 1015
-+#define LM85_SYSCTL_PWM3 1016
-+#define LM85_SYSCTL_VRM 1017
-+#define LM85_SYSCTL_PWM_CFG1 1019
-+#define LM85_SYSCTL_PWM_CFG2 1020
-+#define LM85_SYSCTL_PWM_CFG3 1021
-+#define LM85_SYSCTL_PWM_ZONE1 1022
-+#define LM85_SYSCTL_PWM_ZONE2 1023
-+#define LM85_SYSCTL_PWM_ZONE3 1024
-+#define LM85_SYSCTL_ZONE1 1025
-+#define LM85_SYSCTL_ZONE2 1026
-+#define LM85_SYSCTL_ZONE3 1027
-+#define LM85_SYSCTL_SMOOTH1 1028
-+#define LM85_SYSCTL_SMOOTH2 1029
-+#define LM85_SYSCTL_SMOOTH3 1030
-+
-+/* Vendor specific values */
-+#define LM85_SYSCTL_SPINUP_CTL 1100
-+#define LM85_SYSCTL_TACH_MODE 1101
-+
-+/* Analog Devices variant of the LM85 */
-+#define ADM1027_SYSCTL_TACH_MODE 1200
-+#define ADM1027_SYSCTL_TEMP_OFFSET1 1201
-+#define ADM1027_SYSCTL_TEMP_OFFSET2 1202
-+#define ADM1027_SYSCTL_TEMP_OFFSET3 1203
-+#define ADM1027_SYSCTL_FAN_PPR 1204
-+#define ADM1027_SYSCTL_ALARM_MASK 1205
-+
-+/* Analog Devices variant of the LM85/ADM1027 */
-+#define ADT7463_SYSCTL_TMIN_CTL1 1300
-+#define ADT7463_SYSCTL_TMIN_CTL2 1301
-+#define ADT7463_SYSCTL_TMIN_CTL3 1302
-+#define ADT7463_SYSCTL_THERM_SIGNAL 1303
-+
-+/* SMSC variant of the LM85 */
-+#define EMC6D100_SYSCTL_IN5 1400
-+#define EMC6D100_SYSCTL_IN6 1401
-+#define EMC6D100_SYSCTL_IN7 1402
-+
-+#define LM85_ALARM_IN0 0x0001
-+#define LM85_ALARM_IN1 0x0002
-+#define LM85_ALARM_IN2 0x0004
-+#define LM85_ALARM_IN3 0x0008
-+#define LM85_ALARM_TEMP1 0x0010
-+#define LM85_ALARM_TEMP2 0x0020
-+#define LM85_ALARM_TEMP3 0x0040
-+#define LM85_ALARM_ALARM2 0x0080
-+#define LM85_ALARM_IN4 0x0100
-+#define LM85_ALARM_RESERVED 0x0200
-+#define LM85_ALARM_FAN1 0x0400
-+#define LM85_ALARM_FAN2 0x0800
-+#define LM85_ALARM_FAN3 0x1000
-+#define LM85_ALARM_FAN4 0x2000
-+#define LM85_ALARM_TEMP1_FAULT 0x4000
-+#define LM85_ALARM_TEMP3_FAULT 0x08000
-+#define LM85_ALARM_IN6 0x10000
-+#define LM85_ALARM_IN7 0x20000
-+#define LM85_ALARM_IN5 0x40000
-+/* -- SENSORS SYSCTL END -- */
-+
-+/* The /proc/sys entries */
-+/* These files are created for each detected LM85. This is just a template;
-+ * The actual list is built from this and additional per-chip
-+ * custom lists below. Note the XXX_LEN macros. These must be
-+ * compile time constants because they will be used to allocate
-+ * space for the final template passed to i2c_register_entry.
-+ * We depend on the ability of GCC to evaluate expressions at
-+ * compile time to turn these expressions into compile time
-+ * constants, but this can generate a warning.
-+ */
-+static ctl_table lm85_common[] = {
-+ {LM85_SYSCTL_IN0, "in0", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &lm85_in},
-+ {LM85_SYSCTL_IN1, "in1", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &lm85_in},
-+ {LM85_SYSCTL_IN2, "in2", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &lm85_in},
-+ {LM85_SYSCTL_IN3, "in3", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &lm85_in},
-+ {LM85_SYSCTL_IN4, "in4", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &lm85_in},
-+ {LM85_SYSCTL_FAN1, "fan1", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &lm85_fan},
-+ {LM85_SYSCTL_FAN2, "fan2", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &lm85_fan},
-+ {LM85_SYSCTL_FAN3, "fan3", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &lm85_fan},
-+ {LM85_SYSCTL_FAN4, "fan4", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &lm85_fan},
-+ {LM85_SYSCTL_TEMP1, "temp1", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &lm85_temp},
-+ {LM85_SYSCTL_TEMP2, "temp2", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &lm85_temp},
-+ {LM85_SYSCTL_TEMP3, "temp3", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &lm85_temp},
-+ {LM85_SYSCTL_VID, "vid", NULL, 0, 0444, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &lm85_vid},
-+ {LM85_SYSCTL_VRM, "vrm", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &lm85_vrm},
-+ {LM85_SYSCTL_ALARMS, "alarms", NULL, 0, 0444, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &lm85_alarms},
-+ {LM85_SYSCTL_PWM1, "pwm1", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &lm85_pwm},
-+ {LM85_SYSCTL_PWM2, "pwm2", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &lm85_pwm},
-+ {LM85_SYSCTL_PWM3, "pwm3", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &lm85_pwm},
-+ {LM85_SYSCTL_PWM_CFG1, "pwm1_cfg", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &lm85_pwm_config},
-+ {LM85_SYSCTL_PWM_CFG2, "pwm2_cfg", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &lm85_pwm_config},
-+ {LM85_SYSCTL_PWM_CFG3, "pwm3_cfg", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &lm85_pwm_config},
-+ {LM85_SYSCTL_PWM_ZONE1, "pwm1_zone", NULL, 0, 0644, NULL,
-+ &i2c_proc_real, &i2c_sysctl_real, NULL, &lm85_pwm_zone},
-+ {LM85_SYSCTL_PWM_ZONE2, "pwm2_zone", NULL, 0, 0644, NULL,
-+ &i2c_proc_real, &i2c_sysctl_real, NULL, &lm85_pwm_zone},
-+ {LM85_SYSCTL_PWM_ZONE3, "pwm3_zone", NULL, 0, 0644, NULL,
-+ &i2c_proc_real, &i2c_sysctl_real, NULL, &lm85_pwm_zone},
-+ {LM85_SYSCTL_ZONE1, "zone1", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &lm85_zone},
-+ {LM85_SYSCTL_ZONE2, "zone2", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &lm85_zone},
-+ {LM85_SYSCTL_ZONE3, "zone3", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &lm85_zone},
-+ {LM85_SYSCTL_SMOOTH1, "smooth1", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &lm85_smooth},
-+ {LM85_SYSCTL_SMOOTH2, "smooth2", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &lm85_smooth},
-+ {LM85_SYSCTL_SMOOTH3, "smooth3", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &lm85_smooth},
-+ {0}
-+};
-+#define CTLTBL_COMMON (sizeof(lm85_common)/sizeof(lm85_common[0]))
-+
-+/* NOTE: tach_mode is a shared name, but implemented with
-+ * different functions
-+ */
-+static ctl_table lm85_specific[] = {
-+ {LM85_SYSCTL_SPINUP_CTL, "spinup_ctl", NULL, 0, 0644, NULL,
-+ &i2c_proc_real, &i2c_sysctl_real, NULL, &lm85_spinup_ctl},
-+ {LM85_SYSCTL_TACH_MODE, "tach_mode", NULL, 0, 0644, NULL,
-+ &i2c_proc_real, &i2c_sysctl_real, NULL, &lm85_tach_mode},
-+/* {0} The doc generator needs this. */
-+};
-+#define CTLTBL_LM85 (sizeof(lm85_specific)/sizeof(lm85_specific[0]))
-+
-+static ctl_table adm1027_specific[] = {
-+ {ADM1027_SYSCTL_TACH_MODE, "tach_mode", NULL, 0, 0644, NULL,
-+ &i2c_proc_real, &i2c_sysctl_real, NULL, &adm1027_tach_mode},
-+ {ADM1027_SYSCTL_TEMP_OFFSET1, "temp1_offset", NULL, 0, 0644, NULL,
-+ &i2c_proc_real, &i2c_sysctl_real, NULL, &adm1027_temp_offset},
-+ {ADM1027_SYSCTL_TEMP_OFFSET2, "temp2_offset", NULL, 0, 0644, NULL,
-+ &i2c_proc_real, &i2c_sysctl_real, NULL, &adm1027_temp_offset},
-+ {ADM1027_SYSCTL_TEMP_OFFSET3, "temp3_offset", NULL, 0, 0644, NULL,
-+ &i2c_proc_real, &i2c_sysctl_real, NULL, &adm1027_temp_offset},
-+ {ADM1027_SYSCTL_FAN_PPR, "fan_ppr", NULL, 0, 0644, NULL,
-+ &i2c_proc_real, &i2c_sysctl_real, NULL, &adm1027_fan_ppr},
-+ {ADM1027_SYSCTL_ALARM_MASK, "alarm_mask", NULL, 0, 0644, NULL,
-+ &i2c_proc_real, &i2c_sysctl_real, NULL, &adm1027_alarm_mask},
-+/* {0} The doc generator needs this. */
-+};
-+#define CTLTBL_ADM1027 (sizeof(adm1027_specific)/sizeof(adm1027_specific[0]))
-+
-+static ctl_table adt7463_specific[] = {
-+ {ADT7463_SYSCTL_TMIN_CTL1, "tmin_ctl1", NULL, 0, 0644, NULL,
-+ &i2c_proc_real, &i2c_sysctl_real, NULL, &adt7463_tmin_ctl},
-+ {ADT7463_SYSCTL_TMIN_CTL2, "tmin_ctl2", NULL, 0, 0644, NULL,
-+ &i2c_proc_real, &i2c_sysctl_real, NULL, &adt7463_tmin_ctl},
-+ {ADT7463_SYSCTL_TMIN_CTL3, "tmin_ctl3", NULL, 0, 0644, NULL,
-+ &i2c_proc_real, &i2c_sysctl_real, NULL, &adt7463_tmin_ctl},
-+ {ADT7463_SYSCTL_THERM_SIGNAL, "therm_signal", NULL, 0, 0644, NULL,
-+ &i2c_proc_real, &i2c_sysctl_real, NULL, &adt7463_therm_signal},
-+/* {0} The doc generator needs this. */
-+};
-+#define CTLTBL_ADT7463 (sizeof(adt7463_specific)/sizeof(adt7463_specific[0]))
-+
-+static ctl_table emc6d100_specific[] = {
-+ {EMC6D100_SYSCTL_IN5, "in5", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &emc6d100_in},
-+ {EMC6D100_SYSCTL_IN6, "in6", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &emc6d100_in},
-+ {EMC6D100_SYSCTL_IN7, "in7", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &emc6d100_in},
-+/* {0} The doc generator needs this. */
-+};
-+#define CTLTBL_EMC6D100 (sizeof(emc6d100_specific)/sizeof(emc6d100_specific[0]))
-+
-+
-+#define MAX2(a,b) ((a)>(b)?(a):(b))
-+#define MAX3(a,b,c) ((a)>(b)?MAX2((a),(c)):MAX2((b),(c)))
-+#define MAX4(a,b,c,d) ((a)>(b)?MAX3((a),(c),(d)):MAX3((b),(c),(d)))
-+
-+#define CTLTBL_MAX (CTLTBL_COMMON + MAX3(CTLTBL_LM85, CTLTBL_ADM1027+CTLTBL_ADT7463, CTLTBL_EMC6D100))
-+
-+/* This function is called when:
-+ * lm85_driver is inserted (when this module is loaded), for each
-+ available adapter
-+ * when a new adapter is inserted (and lm85_driver is still present) */
-+int lm85_attach_adapter(struct i2c_adapter *adapter)
-+{
-+ return i2c_detect(adapter, &addr_data, lm85_detect);
-+}
-+
-+/* This function is called by i2c_detect */
-+int lm85_detect(struct i2c_adapter *adapter, int address,
-+ unsigned short flags, int kind)
-+{
-+ int i;
-+ int company, verstep ;
-+ struct i2c_client *new_client;
-+ struct lm85_data *data;
-+ int err = 0;
-+ const char *type_name = "";
-+ struct ctl_table template[CTLTBL_MAX] ;
-+ int template_used ;
-+
-+ if (i2c_is_isa_adapter(adapter)) {
-+ /* This chip has no ISA interface */
-+ goto ERROR0 ;
-+ };
-+
-+ if (!i2c_check_functionality(adapter,
-+ I2C_FUNC_SMBUS_BYTE_DATA)) {
-+ /* We need to be able to do byte I/O */
-+ goto ERROR0 ;
-+ };
-+
-+ /* OK. For now, we presume we have a valid client. We now create the
-+ client structure, even though we cannot fill it completely yet.
-+ But it allows us to access lm85_{read,write}_value. */
-+
-+ if (!(data = kmalloc(sizeof(struct lm85_data), GFP_KERNEL))) {
-+ err = -ENOMEM;
-+ goto ERROR0;
-+ }
-+
-+ new_client = &data->client;
-+ new_client->addr = address;
-+ new_client->data = data;
-+ new_client->adapter = adapter;
-+ new_client->driver = &lm85_driver;
-+ new_client->flags = 0;
-+
-+ /* Now, we do the remaining detection. */
-+
-+ company = lm85_read_value(new_client, LM85_REG_COMPANY);
-+ verstep = lm85_read_value(new_client, LM85_REG_VERSTEP);
-+
-+#ifdef DEBUG
-+ printk("lm85: Detecting device at %d,0x%02x with"
-+ " COMPANY: 0x%02x and VERSTEP: 0x%02x\n",
-+ i2c_adapter_id(new_client->adapter), new_client->addr,
-+ company, verstep
-+ );
-+#endif
-+
-+ /* If auto-detecting, Determine the chip type. */
-+ if (kind <= 0) {
-+#ifdef DEBUG
-+ printk("lm85: Autodetecting device at %d,0x%02x ...\n",
-+ i2c_adapter_id(adapter), address );
-+#endif
-+ if( company == LM85_COMPANY_NATIONAL
-+ && verstep == LM85_VERSTEP_LM85C ) {
-+ kind = lm85c ;
-+ } else if( company == LM85_COMPANY_NATIONAL
-+ && verstep == LM85_VERSTEP_LM85B ) {
-+ kind = lm85b ;
-+ } else if( company == LM85_COMPANY_NATIONAL
-+ && (verstep & LM85_VERSTEP_VMASK) == LM85_VERSTEP_GENERIC) {
-+ printk("lm85: Detected National Semiconductor chip\n");
-+ printk("lm85: Unrecgonized version/stepping 0x%02x"
-+ " Defaulting to Generic LM85.\n", verstep );
-+ kind = any_chip ;
-+ } else if( company == LM85_COMPANY_ANALOG_DEV
-+ && verstep == LM85_VERSTEP_ADM1027 ) {
-+ kind = adm1027 ;
-+ } else if( company == LM85_COMPANY_ANALOG_DEV
-+ && verstep == LM85_VERSTEP_ADT7463 ) {
-+ kind = adt7463 ;
-+ } else if( company == LM85_COMPANY_ANALOG_DEV
-+ && (verstep & LM85_VERSTEP_VMASK) == LM85_VERSTEP_GENERIC) {
-+ printk("lm85: Detected Analog Devices chip\n");
-+ printk("lm85: Unrecgonized version/stepping 0x%02x"
-+ " Defaulting to Generic LM85.\n", verstep );
-+ kind = any_chip ;
-+ } else if( company == LM85_COMPANY_SMSC
-+ && (verstep == LM85_VERSTEP_EMC6D100_A0
-+ || verstep == LM85_VERSTEP_EMC6D100_A1) ) {
-+ /* Unfortunately, we can't tell a '100 from a '101
-+ * from the registers. Since a '101 is a '100
-+ * in a package with fewer pins and therefore no
-+ * 3.3V, 1.5V or 1.8V inputs, perhaps if those
-+ * inputs read 0, then it's a '101.
-+ */
-+ kind = emc6d100 ;
-+ } else if( company == LM85_COMPANY_SMSC
-+ && (verstep & LM85_VERSTEP_VMASK) == LM85_VERSTEP_GENERIC) {
-+ printk("lm85: Detected SMSC chip\n");
-+ printk("lm85: Unrecognized version/stepping 0x%02x"
-+ " Defaulting to Generic LM85.\n", verstep );
-+ kind = any_chip ;
-+ } else if( kind == any_chip
-+ && (verstep & LM85_VERSTEP_VMASK) == LM85_VERSTEP_GENERIC) {
-+ printk("lm85: Generic LM85 Version 6 detected\n");
-+ /* Leave kind as "any_chip" */
-+ } else {
-+#ifdef DEBUG
-+ printk("lm85: Autodetection failed\n");
-+#endif
-+ /* Not an LM85 ... */
-+ if( kind == any_chip ) { /* User used force=x,y */
-+ printk("lm85: Generic LM85 Version 6 not"
-+ " found at %d,0x%02x. Try force_lm85c.\n",
-+ i2c_adapter_id(adapter), address );
-+ }
-+ err = 0 ;
-+ goto ERROR1;
-+ }
-+ }
-+
-+ /* Fill in the chip specific driver values */
-+ switch (kind) {
-+ case any_chip :
-+ type_name = "lm85";
-+ strcpy(new_client->name, "Generic LM85");
-+ template_used = 0 ;
-+ break ;
-+ case lm85b :
-+ type_name = "lm85b";
-+ strcpy(new_client->name, "National LM85-B");
-+ memcpy( template, lm85_specific, sizeof(lm85_specific) );
-+ template_used = CTLTBL_LM85 ;
-+ break ;
-+ case lm85c :
-+ type_name = "lm85c";
-+ strcpy(new_client->name, "National LM85-C");
-+ memcpy( template, lm85_specific, sizeof(lm85_specific) );
-+ template_used = CTLTBL_LM85 ;
-+ break ;
-+ case adm1027 :
-+ type_name = "adm1027";
-+ strcpy(new_client->name, "Analog Devices ADM1027");
-+ memcpy( template, adm1027_specific, sizeof(adm1027_specific) );
-+ template_used = CTLTBL_ADM1027 ;
-+ break ;
-+ case adt7463 :
-+ type_name = "adt7463";
-+ strcpy(new_client->name, "Analog Devices ADT7463");
-+ memcpy( template, adt7463_specific, sizeof(adt7463_specific) );
-+ template_used = CTLTBL_ADT7463 ;
-+ memcpy( template+template_used, adm1027_specific, sizeof(adm1027_specific) );
-+ template_used += CTLTBL_ADM1027 ;
-+ break ;
-+ case emc6d100 :
-+ type_name = "emc6d100";
-+ strcpy(new_client->name, "SMSC EMC6D100");
-+ memcpy(template, emc6d100_specific, sizeof(emc6d100_specific));
-+ template_used = CTLTBL_EMC6D100 ;
-+ break ;
-+ default :
-+ printk("lm85: Internal error, invalid kind (%d)!", kind);
-+ err = -EFAULT ;
-+ goto ERROR1;
-+ }
-+
-+ /* Fill in the remaining client fields */
-+ new_client->id = lm85_id++;
-+ printk("lm85: Assigning ID %d to %s at %d,0x%02x\n",
-+ new_client->id, new_client->name,
-+ i2c_adapter_id(new_client->adapter),
-+ new_client->addr
-+ );
-+
-+ /* Housekeeping values */
-+ data->type = kind;
-+ data->valid = 0;
-+
-+ /* Set the VRM version */
-+ data->vrm = LM85_INIT_VRM ;
-+
-+ /* Zero the accumulators */
-+ data->therm_total = 0;
-+ data->therm_ovfl = 0;
-+
-+ init_MUTEX(&data->update_lock);
-+
-+ /* Initialize the LM85 chip */
-+ lm85_init_client(new_client);
-+
-+ /* Tell the I2C layer a new client has arrived */
-+ if ((err = i2c_attach_client(new_client)))
-+ goto ERROR1;
-+
-+ /* Finish out the template */
-+ memcpy( template + template_used, lm85_common, sizeof(lm85_common) );
-+
-+ /* Register a new directory entry with module sensors */
-+ if ((i = i2c_register_entry(new_client,
-+ type_name,
-+ template)) < 0) {
-+ err = i;
-+ goto ERROR2;
-+ }
-+ data->sysctl_id = i;
-+
-+ return 0;
-+
-+ /* Error out and cleanup code */
-+ ERROR2:
-+ i2c_detach_client(new_client);
-+ ERROR1:
-+ kfree(data);
-+ ERROR0:
-+ return err;
-+}
-+
-+int lm85_detach_client(struct i2c_client *client)
-+{
-+ int err;
-+ int id ;
-+
-+ id = client->id;
-+ i2c_deregister_entry(((struct lm85_data *)(client->data))->sysctl_id);
-+
-+ if ((err = i2c_detach_client(client))) {
-+ printk("lm85(%d): Client deregistration failed,"
-+ " client not detached.\n", id );
-+ return err;
-+ }
-+
-+ kfree(client->data);
-+
-+ return 0;
-+}
-+
-+int lm85_read_value(struct i2c_client *client, u16 reg)
-+{
-+ int res;
-+
-+ /* What size location is it? */
-+ switch( reg ) {
-+ case LM85_REG_FAN(0) : /* Read WORD data */
-+ case LM85_REG_FAN(1) :
-+ case LM85_REG_FAN(2) :
-+ case LM85_REG_FAN(3) :
-+ case LM85_REG_FAN_MIN(0) :
-+ case LM85_REG_FAN_MIN(1) :
-+ case LM85_REG_FAN_MIN(2) :
-+ case LM85_REG_FAN_MIN(3) :
-+ case LM85_REG_ALARM : /* Read ALARM1 and ALARM2 */
-+ case ADM1027_REG_INTMASK : /* Read MASK1 and MASK2 */
-+ case ADM1027_REG_EXTEND_ADC : /* Read ADC1 and ADC2 */
-+ reg &= 0xff ; /* Pseudo words have address + 0x0100 */
-+ res = i2c_smbus_read_byte_data(client, reg) & 0xff ;
-+ res |= (i2c_smbus_read_byte_data(client, reg+1) & 0xff) << 8 ;
-+ break ;
-+ case ADT7463_REG_TMIN_CTL : /* Read WORD MSB, LSB */
-+ reg &= 0xff ; /* Pseudo words have address + 0x0100 */
-+ res = (i2c_smbus_read_byte_data(client, reg) & 0xff) << 8 ;
-+ res |= i2c_smbus_read_byte_data(client, reg+1) & 0xff ;
-+ break ;
-+ default: /* Read BYTE data */
-+ res = i2c_smbus_read_byte_data(client, reg & 0xff) & 0xff ;
-+ break ;
-+ }
-+
-+ return res ;
-+}
-+
-+int lm85_write_value(struct i2c_client *client, u16 reg, int value)
-+{
-+ int res ;
-+
-+ switch( reg ) {
-+ case LM85_REG_FAN(0) : /* Write WORD data */
-+ case LM85_REG_FAN(1) :
-+ case LM85_REG_FAN(2) :
-+ case LM85_REG_FAN(3) :
-+ case LM85_REG_FAN_MIN(0) :
-+ case LM85_REG_FAN_MIN(1) :
-+ case LM85_REG_FAN_MIN(2) :
-+ case LM85_REG_FAN_MIN(3) :
-+ case ADM1027_REG_INTMASK :
-+ /* NOTE: ALARM and ADC are read only, so not included here */
-+ reg &= 0xff ; /* Pseudo words have address + 0x0100 */
-+ res = i2c_smbus_write_byte_data(client, reg, value & 0xff) ;
-+ res |= i2c_smbus_write_byte_data(client, reg+1, (value>>8) & 0xff) ;
-+ break ;
-+ case ADT7463_REG_TMIN_CTL : /* Write WORD MSB, LSB */
-+ reg &= 0xff ; /* Pseudo words have address + 0x0100 */
-+ res = i2c_smbus_write_byte_data(client, reg, (value>>8) & 0xff);
-+ res |= i2c_smbus_write_byte_data(client, reg+1, value & 0xff) ;
-+ break ;
-+ default: /* Write BYTE data */
-+ res = i2c_smbus_write_byte_data(client, reg & 0xff, value);
-+ break ;
-+ }
-+
-+ return res ;
-+}
-+
-+/* Called when we have found a new LM85. It should set limits, etc. */
-+void lm85_init_client(struct i2c_client *client)
-+{
-+ int value;
-+ struct lm85_data *data = client->data;
-+
-+#ifdef DEBUG
-+ printk("lm85(%d): Initializing device\n", client->id);
-+#endif
-+
-+ /* Warn if part was not "READY" */
-+ value = lm85_read_value(client, LM85_REG_CONFIG);
-+#ifdef DEBUG
-+ printk("lm85(%d): LM85_REG_CONFIG is: 0x%02x\n", client->id, value );
-+#endif
-+ if( value & 0x02 ) {
-+ printk("lm85(%d): Client (%d,0x%02x) config is locked.\n",
-+ client->id,
-+ i2c_adapter_id(client->adapter), client->addr );
-+ };
-+ if( ! (value & 0x04) ) {
-+ printk("lm85(%d): Client (%d,0x%02x) is not ready.\n",
-+ client->id,
-+ i2c_adapter_id(client->adapter), client->addr );
-+ };
-+ if( (data->type == adm1027 || data->type == adt7463)
-+ && (value & 0x10)
-+ ) {
-+ printk("lm85(%d): Client (%d,0x%02x) VxI mode is set. "
-+ "Please report this to the lm85 maintainer.\n",
-+ client->id,
-+ i2c_adapter_id(client->adapter), client->addr );
-+ };
-+
-+ /* See if SYNC to PWM3 is set */
-+ if( data->type == adt7463
-+ && (lm85_read_value(client, LM85_REG_AFAN_SPIKE1) & 0x10)
-+ ) {
-+ printk("lm85(%d): Sync to PWM3 is set. Expect PWM3 "
-+ "to control fans 2, 3, and 4\n",
-+ client->id );
-+ };
-+
-+ /* See if PWM2 is #SMBALERT */
-+ if( (data->type == adm1027 || data->type == adt7463)
-+ && (lm85_read_value(client, ADM1027_REG_CONFIG3) & 0x01)
-+ ) {
-+ printk("lm85(%d): PWM2 is SMBALERT. PWM2 not available.\n",
-+ client->id );
-+ };
-+
-+ /* Check if 2.5V and 5V inputs are reconfigured */
-+ if( data->type == adt7463 ) {
-+ value = lm85_read_value(client, ADT7463_REG_CONFIG4);
-+ if( value & 0x01 ) {
-+ printk("lm85(%d): 2.5V input (in0) is SMBALERT. "
-+ "in0 not available.\n", client->id );
-+ };
-+ if( value & 0x02 ) {
-+ printk("lm85(%d): 5V input (in3) is THERM. "
-+ "in3 not available.\n", client->id );
-+ }
-+ };
-+
-+ /* FIXME? Display EMC6D100 config info? */
-+
-+ /* WE INTENTIONALLY make no changes to the limits,
-+ * offsets, pwms, fans and zones. If they were
-+ * configured, we don't want to mess with them.
-+ * If they weren't, the default is 100% PWM, no
-+ * control and will suffice until 'sensors -s'
-+ * can be run by the user.
-+ */
-+
-+ /* Start monitoring */
-+ value = lm85_read_value(client, LM85_REG_CONFIG);
-+ /* Try to clear LOCK, Set START, save everything else */
-+ value = ((value & ~ 0x02) | 0x01) & 0xff ;
-+#ifdef DEBUG
-+ printk("lm85(%d): Setting CONFIG to: 0x%02x\n", client->id, value );
-+#endif
-+ lm85_write_value(client, LM85_REG_CONFIG, value);
-+
-+}
-+
-+void lm85_update_client(struct i2c_client *client)
-+{
-+ struct lm85_data *data = client->data;
-+ int i;
-+
-+ down(&data->update_lock);
-+
-+ if (!data->valid
-+ || (jiffies - data->last_reading > LM85_DATA_INTERVAL )) {
-+ /* Things that change quickly */
-+
-+#ifdef DEBUG
-+ printk("lm85(%d): Reading sensor values\n", client->id);
-+#endif
-+ /* Have to read extended bits first to "freeze" the
-+ * more significant bits that are read later.
-+ */
-+ switch( data->type ) {
-+ case adm1027 :
-+ case adt7463 :
-+ data->extend_adc =
-+ lm85_read_value(client, ADM1027_REG_EXTEND_ADC);
-+ break ;
-+ default :
-+ data->extend_adc = 0 ;
-+ break ;
-+ }
-+
-+ for (i = 0; i <= 4; ++i) {
-+ data->in[i] =
-+ lm85_read_value(client, LM85_REG_IN(i));
-+ }
-+
-+ for (i = 0; i <= 3; ++i) {
-+ data->fan[i] =
-+ lm85_read_value(client, LM85_REG_FAN(i));
-+ }
-+
-+ for (i = 0; i <= 2; ++i) {
-+ data->temp[i] =
-+ lm85_read_value(client, LM85_REG_TEMP(i));
-+ }
-+
-+ for (i = 0; i <= 2; ++i) {
-+ data->pwm[i] =
-+ lm85_read_value(client, LM85_REG_PWM(i));
-+ }
-+
-+ data->alarms = lm85_read_value(client, LM85_REG_ALARM);
-+
-+ switch( ((struct lm85_data *)(client->data))->type ) {
-+ case adt7463 :
-+ /* REG_THERM code duplicated in therm_signal() */
-+ i = lm85_read_value(client, ADT7463_REG_THERM);
-+ if( data->therm_total < LONG_MAX - 256 ) {
-+ data->therm_total += i ;
-+ }
-+ if( i >= 255 ) {
-+ ++data->therm_ovfl ;
-+ }
-+ break ;
-+ case emc6d100 :
-+ /* Three more voltage sensors */
-+ for (i = 5; i <= 7; ++i) {
-+ data->in[i] =
-+ lm85_read_value(client, EMC6D100_REG_IN(i));
-+ }
-+ /* More alarm bits */
-+ data->alarms |=
-+ lm85_read_value(client, EMC6D100_REG_ALARM3) << 16;
-+
-+ break ;
-+ default : break ; /* no warnings */
-+ }
-+
-+ data->last_reading = jiffies ;
-+ }; /* last_reading */
-+
-+ if (!data->valid
-+ || (jiffies - data->last_config > LM85_CONFIG_INTERVAL) ) {
-+ /* Things that don't change often */
-+
-+#ifdef DEBUG
-+ printk("lm85(%d): Reading config values\n", client->id);
-+#endif
-+ for (i = 0; i <= 4; ++i) {
-+ data->in_min[i] =
-+ lm85_read_value(client, LM85_REG_IN_MIN(i));
-+ data->in_max[i] =
-+ lm85_read_value(client, LM85_REG_IN_MAX(i));
-+ }
-+
-+ for (i = 0; i <= 3; ++i) {
-+ data->fan_min[i] =
-+ lm85_read_value(client, LM85_REG_FAN_MIN(i));
-+ }
-+
-+ for (i = 0; i <= 2; ++i) {
-+ data->temp_min[i] =
-+ lm85_read_value(client, LM85_REG_TEMP_MIN(i));
-+ data->temp_max[i] =
-+ lm85_read_value(client, LM85_REG_TEMP_MAX(i));
-+ }
-+
-+ data->vid = lm85_read_value(client, LM85_REG_VID);
-+
-+ for (i = 0; i <= 2; ++i) {
-+ int val ;
-+ data->autofan[i].config =
-+ lm85_read_value(client, LM85_REG_AFAN_CONFIG(i));
-+ val = lm85_read_value(client, LM85_REG_AFAN_RANGE(i));
-+ data->autofan[i].freq = val & 0x07 ;
-+ data->zone[i].range = (val >> 4) & 0x0f ;
-+ data->autofan[i].min_pwm =
-+ lm85_read_value(client, LM85_REG_AFAN_MINPWM(i));
-+ data->zone[i].limit =
-+ lm85_read_value(client, LM85_REG_AFAN_LIMIT(i));
-+ data->zone[i].critical =
-+ lm85_read_value(client, LM85_REG_AFAN_CRITICAL(i));
-+ }
-+
-+ i = lm85_read_value(client, LM85_REG_AFAN_SPIKE1);
-+ data->smooth[0] = i & 0x0f ;
-+ data->syncpwm3 = i & 0x10 ; /* Save PWM3 config */
-+ data->autofan[0].min_off = i & 0x20 ;
-+ data->autofan[1].min_off = i & 0x40 ;
-+ data->autofan[2].min_off = i & 0x80 ;
-+ i = lm85_read_value(client, LM85_REG_AFAN_SPIKE2);
-+ data->smooth[1] = (i>>4) & 0x0f ;
-+ data->smooth[2] = i & 0x0f ;
-+
-+ i = lm85_read_value(client, LM85_REG_AFAN_HYST1);
-+ data->zone[0].hyst = (i>>4) & 0x0f ;
-+ data->zone[1].hyst = i & 0x0f ;
-+
-+ i = lm85_read_value(client, LM85_REG_AFAN_HYST2);
-+ data->zone[2].hyst = (i>>4) & 0x0f ;
-+
-+ switch( ((struct lm85_data *)(client->data))->type ) {
-+ case lm85b :
-+ case lm85c :
-+ data->tach_mode = lm85_read_value(client,
-+ LM85_REG_TACH_MODE );
-+ data->spinup_ctl = lm85_read_value(client,
-+ LM85_REG_SPINUP_CTL );
-+ break ;
-+ case adt7463 :
-+ for (i = 0; i <= 2; ++i) {
-+ data->oppoint[i] = lm85_read_value(client,
-+ ADT7463_REG_OPPOINT(i) );
-+ }
-+ data->tmin_ctl = lm85_read_value(client,
-+ ADT7463_REG_TMIN_CTL );
-+ data->therm_limit = lm85_read_value(client,
-+ ADT7463_REG_THERM_LIMIT );
-+ /* FALL THROUGH */
-+ case adm1027 :
-+ for (i = 0; i <= 2; ++i) {
-+ data->temp_offset[i] = lm85_read_value(client,
-+ ADM1027_REG_TEMP_OFFSET(i) );
-+ }
-+ data->tach_mode = lm85_read_value(client,
-+ ADM1027_REG_CONFIG3 );
-+ data->fan_ppr = lm85_read_value(client,
-+ ADM1027_REG_FAN_PPR );
-+ data->alarm_mask = lm85_read_value(client,
-+ ADM1027_REG_INTMASK );
-+ break ;
-+ case emc6d100 :
-+ for (i = 5; i <= 7; ++i) {
-+ data->in_min[i] =
-+ lm85_read_value(client, EMC6D100_REG_IN_MIN(i));
-+ data->in_max[i] =
-+ lm85_read_value(client, EMC6D100_REG_IN_MAX(i));
-+ }
-+ break ;
-+ default : break ; /* no warnings */
-+ }
-+
-+ data->last_config = jiffies;
-+ }; /* last_config */
-+
-+ data->valid = 1;
-+
-+ up(&data->update_lock);
-+}
-+
-+
-+/* The next functions are the call-back functions of the /proc/sys and
-+ sysctl files. Which function is used is defined in the ctl_table in
-+ the extra1 field.
-+ Each function must return the magnitude (power of 10 to divide the data
-+ with) if it is called with operation==SENSORS_PROC_REAL_INFO. It must
-+ put a maximum of *nrels elements in results reflecting the data of this
-+ file, and set *nrels to the number it actually put in it, if operation==
-+ SENSORS_PROC_REAL_READ. Finally, it must get upto *nrels elements from
-+ results and write them to the chip, if operations==SENSORS_PROC_REAL_WRITE.
-+ */
-+void lm85_in(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct lm85_data *data = client->data;
-+ int nr = ctl_name - LM85_SYSCTL_IN0;
-+
-+ if (nr < 0 || nr > 4)
-+ return ; /* ERROR */
-+
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 3; /* 1.000 */
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ int ext = 0 ;
-+ lm85_update_client(client);
-+ ext = EXT_FROM_REG(data->extend_adc, nr);
-+ results[0] = INS_FROM_REG(nr,data->in_min[nr]);
-+ results[1] = INS_FROM_REG(nr,data->in_max[nr]);
-+ results[2] = INSEXT_FROM_REG(nr,data->in[nr],ext);
-+ *nrels_mag = 3;
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ down(&data->update_lock);
-+ if (*nrels_mag > 1) {
-+ data->in_max[nr] = INS_TO_REG(nr,results[1]);
-+ lm85_write_value(client, LM85_REG_IN_MAX(nr),
-+ data->in_max[nr]);
-+ }
-+ if (*nrels_mag > 0) {
-+ data->in_min[nr] = INS_TO_REG(nr,results[0]);
-+ lm85_write_value(client, LM85_REG_IN_MIN(nr),
-+ data->in_min[nr]);
-+ }
-+ up(&data->update_lock);
-+ }
-+}
-+
-+void lm85_fan(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct lm85_data *data = client->data;
-+ int nr = ctl_name - LM85_SYSCTL_FAN1 ;
-+
-+ if (nr < 0 || nr > 3)
-+ return ; /* ERROR */
-+
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 0;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ lm85_update_client(client);
-+ results[0] = FAN_FROM_REG(data->fan_min[nr]);
-+ results[1] = FAN_FROM_REG(data->fan[nr]);
-+ *nrels_mag = 2;
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ down(&data->update_lock);
-+ if (*nrels_mag > 0) {
-+ data->fan_min[nr] = FAN_TO_REG(results[0]);
-+ lm85_write_value(client, LM85_REG_FAN_MIN(nr),
-+ data->fan_min[nr]);
-+ }
-+ up(&data->update_lock);
-+ }
-+}
-+
-+
-+void lm85_temp(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct lm85_data *data = client->data;
-+ int nr = ctl_name - LM85_SYSCTL_TEMP1 ;
-+
-+ if (nr < 0 || nr > 2)
-+ return ; /* ERROR */
-+
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 2;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ int ext = 0 ;
-+ lm85_update_client(client);
-+
-+ /* +5 for offset of temp data in ext reg */
-+ ext = EXT_FROM_REG(data->extend_adc, nr+5);
-+
-+ results[0] = TEMP_FROM_REG(data->temp_min[nr]);
-+ results[1] = TEMP_FROM_REG(data->temp_max[nr]);
-+ results[2] = TEMPEXT_FROM_REG(data->temp[nr],ext);
-+ *nrels_mag = 3;
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ down(&data->update_lock);
-+ if (*nrels_mag > 1) {
-+ data->temp_max[nr] = TEMP_TO_REG(results[1]);
-+ lm85_write_value(client, LM85_REG_TEMP_MAX(nr),
-+ data->temp_max[nr]);
-+ }
-+ if (*nrels_mag > 0) {
-+ data->temp_min[nr] = TEMP_TO_REG(results[0]);
-+ lm85_write_value(client, LM85_REG_TEMP_MIN(nr),
-+ data->temp_min[nr]);
-+ }
-+ up(&data->update_lock);
-+ }
-+}
-+
-+void lm85_pwm(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct lm85_data *data = client->data;
-+ int nr = ctl_name - LM85_SYSCTL_PWM1 ;
-+ int pwm_zone ;
-+
-+ if (nr < 0 || nr > 2)
-+ return ; /* ERROR */
-+
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 0;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ lm85_update_client(client);
-+ results[0] = PWM_FROM_REG(data->pwm[nr]);
-+ pwm_zone = ZONE_FROM_REG(data->autofan[nr].config);
-+ /* PWM "enabled" if not off (0) nor on (-1) */
-+ results[1] = pwm_zone != 0 && pwm_zone != -1 ;
-+ *nrels_mag = 2;
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ down(&data->update_lock);
-+ /* PWM enable is read-only */
-+ if (*nrels_mag > 0) {
-+ data->pwm[nr] = PWM_TO_REG(results[0]);
-+ lm85_write_value(client, LM85_REG_PWM(nr),
-+ data->pwm[nr]);
-+ }
-+ up(&data->update_lock);
-+ }
-+}
-+
-+void lm85_vid(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct lm85_data *data = client->data;
-+
-+ if( ctl_name != LM85_SYSCTL_VID )
-+ return ; /* ERROR */
-+
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 3;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ lm85_update_client(client);
-+ results[0] = VID_FROM_REG((data->vid)&0x3f,data->vrm);
-+ *nrels_mag = 1;
-+ }
-+}
-+
-+void lm85_vrm(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct lm85_data *data = client->data;
-+
-+ if( ctl_name != LM85_SYSCTL_VRM )
-+ return ; /* ERROR */
-+
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 1;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ results[0] = data->vrm ;
-+ *nrels_mag = 1;
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ down(&data->update_lock);
-+ if (*nrels_mag > 0) {
-+ data->vrm = results[0] ;
-+ }
-+ up(&data->update_lock);
-+ }
-+}
-+
-+void lm85_alarms(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct lm85_data *data = client->data;
-+
-+ if( ctl_name != LM85_SYSCTL_ALARMS )
-+ return ; /* ERROR */
-+
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 0;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ lm85_update_client(client);
-+ results[0] = ALARMS_FROM_REG(data->alarms);
-+ *nrels_mag = 1;
-+ }
-+}
-+
-+void lm85_spinup_ctl(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct lm85_data *data = client->data;
-+ int old;
-+
-+ if( ctl_name != LM85_SYSCTL_SPINUP_CTL )
-+ return ; /* ERROR */
-+
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 0;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ lm85_update_client(client);
-+ results[0] = (data->spinup_ctl & 1) != 0 ;
-+ results[1] = (data->spinup_ctl & 2) != 0 ;
-+ results[2] = (data->spinup_ctl & 4) != 0 ;
-+ *nrels_mag = 3;
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ down(&data->update_lock);
-+ old = data->spinup_ctl ;
-+ if (*nrels_mag > 2) {
-+ old = (old & (~4)) | (results[2]?4:0) ;
-+ }
-+ if (*nrels_mag > 1) {
-+ old = (old & (~2)) | (results[1]?2:0) ;
-+ }
-+ if (*nrels_mag > 0) {
-+ old = (old & (~1)) | (results[0]?1:0) ;
-+ lm85_write_value(client, LM85_REG_SPINUP_CTL, old);
-+ data->spinup_ctl = old ;
-+ }
-+ up(&data->update_lock);
-+ }
-+}
-+
-+void lm85_tach_mode(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct lm85_data *data = client->data;
-+ int old;
-+
-+ /* Tach Mode 1, Tach Mode 2, Tach Mode 3 & 4 */
-+
-+ if( ctl_name != LM85_SYSCTL_TACH_MODE )
-+ return ; /* ERROR */
-+
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 0;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ lm85_update_client(client);
-+ results[0] = (data->tach_mode & 0x03) ;
-+ results[1] = (data->tach_mode & 0x0c) >> 2 ;
-+ results[2] = (data->tach_mode & 0x30) >> 4 ;
-+ *nrels_mag = 3;
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ down(&data->update_lock);
-+ old = data->tach_mode ;
-+ if (*nrels_mag > 2) {
-+ old = (old & (~0x30)) | ((results[2]&3) << 4) ;
-+ }
-+ if (*nrels_mag > 1) {
-+ old = (old & (~0x0c)) | ((results[1]&3) << 2) ;
-+ }
-+ if (*nrels_mag > 0) {
-+ old = (old & (~0x03)) | (results[0]&3) ;
-+ lm85_write_value(client, LM85_REG_TACH_MODE, old);
-+ data->tach_mode = old ;
-+ }
-+ up(&data->update_lock);
-+ }
-+}
-+
-+void adm1027_tach_mode(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct lm85_data *data = client->data;
-+ int old;
-+
-+ /* Tach/DC 1, Tach/DC 2, Tach/DC 3, Tach/DC 4 */
-+
-+ if( ctl_name != ADM1027_SYSCTL_TACH_MODE )
-+ return ; /* ERROR */
-+
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 0;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ lm85_update_client(client);
-+ results[0] = (data->tach_mode & 0x10) != 0 ;
-+ results[1] = (data->tach_mode & 0x20) != 0 ;
-+ results[2] = (data->tach_mode & 0x40) != 0 ;
-+ results[3] = (data->tach_mode & 0x80) != 0 ;
-+ *nrels_mag = 4;
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ down(&data->update_lock);
-+ old = data->tach_mode ;
-+ if (*nrels_mag > 3) {
-+ old = (old & (~0x80)) | (results[3] ? 0x80 : 0) ;
-+ }
-+ if (*nrels_mag > 2) {
-+ old = (old & (~0x40)) | (results[2] ? 0x40 : 0) ;
-+ }
-+ if (*nrels_mag > 1) {
-+ old = (old & (~0x20)) | (results[1] ? 0x20 : 0) ;
-+ }
-+ if (*nrels_mag > 0) {
-+ old = (old & (~0x10)) | (results[0] ? 0x10 : 0) ;
-+
-+ /* Enable fast measurements if any TACH's are DC */
-+ old = (old & (~0x08)) | ((old&0xf0) ? 0x08 : 0) ;
-+
-+ lm85_write_value(client, ADM1027_REG_CONFIG3, old);
-+ data->tach_mode = old ;
-+ }
-+ up(&data->update_lock);
-+ }
-+}
-+
-+void lm85_pwm_config(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct lm85_data *data = client->data;
-+ int nr = ctl_name - LM85_SYSCTL_PWM_CFG1 ;
-+
-+ /* Spinup, min PWM, PWM Frequency, min below limit, Invert */
-+
-+ if (nr < 0 || nr > 2)
-+ return ; /* ERROR */
-+
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 1;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ lm85_update_client(client);
-+
-+ results[0] = SPINUP_FROM_REG(data->autofan[nr].config);
-+ results[1] = PWM_FROM_REG(data->autofan[nr].min_pwm)*10;
-+ results[2] = FREQ_FROM_REG(data->autofan[nr].freq);
-+ results[3] = data->autofan[nr].min_off ? 10 : 0 ;
-+ results[4] = (data->autofan[nr].config & 0x10) ? 10 : 0 ;
-+ *nrels_mag = 5;
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ int old_config ;
-+
-+ down(&data->update_lock);
-+ old_config = data->autofan[nr].config ;
-+ if (*nrels_mag > 4) {
-+ old_config = (old_config & (~0x10)) | (results[4]?0x10:0) ;
-+ }
-+ if (*nrels_mag > 3) {
-+ data->autofan[nr].min_off = results[3] != 0 ;
-+ lm85_write_value(client, LM85_REG_AFAN_SPIKE1,
-+ data->smooth[0]
-+ | data->syncpwm3
-+ | (data->autofan[0].min_off ? 0x20 : 0)
-+ | (data->autofan[1].min_off ? 0x40 : 0)
-+ | (data->autofan[2].min_off ? 0x80 : 0)
-+ );
-+ }
-+ if (*nrels_mag > 2) {
-+ data->autofan[nr].freq = FREQ_TO_REG(results[2]) ;
-+ lm85_write_value(client, LM85_REG_AFAN_RANGE(nr),
-+ (data->zone[nr].range << 4)
-+ | data->autofan[nr].freq
-+ );
-+ }
-+ if (*nrels_mag > 1) {
-+ data->autofan[nr].min_pwm = PWM_TO_REG((results[1]+5)/10);
-+ lm85_write_value(client, LM85_REG_AFAN_MINPWM(nr),
-+ data->autofan[nr].min_pwm
-+ );
-+ }
-+ if (*nrels_mag > 0) {
-+ old_config = (old_config & (~0x07)) | SPINUP_TO_REG(results[0]) ;
-+ lm85_write_value(client, LM85_REG_AFAN_CONFIG(nr), old_config);
-+ data->autofan[nr].config = old_config ;
-+ }
-+ up(&data->update_lock);
-+ }
-+}
-+
-+void lm85_smooth(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct lm85_data *data = client->data;
-+ int nr = ctl_name - LM85_SYSCTL_SMOOTH1 ;
-+
-+ if (nr < 0 || nr > 2)
-+ return ; /* ERROR */
-+
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 1;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ lm85_update_client(client);
-+ results[0] = SMOOTH_FROM_REG(data->smooth[nr]);
-+ *nrels_mag = 1;
-+
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ down(&data->update_lock);
-+ if( *nrels_mag > 0 ) {
-+ data->smooth[nr] = SMOOTH_TO_REG(results[0]);
-+ }
-+ if( nr == 0 ) {
-+ lm85_write_value(client, LM85_REG_AFAN_SPIKE1,
-+ data->smooth[0]
-+ | data->syncpwm3
-+ | (data->autofan[0].min_off ? 0x20 : 0)
-+ | (data->autofan[1].min_off ? 0x40 : 0)
-+ | (data->autofan[2].min_off ? 0x80 : 0)
-+ );
-+ } else {
-+ lm85_write_value(client, LM85_REG_AFAN_SPIKE2,
-+ (data->smooth[1] << 4) | data->smooth[2]);
-+ }
-+ up(&data->update_lock);
-+ }
-+}
-+
-+void lm85_zone(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct lm85_data *data = client->data;
-+ int nr = ctl_name - LM85_SYSCTL_ZONE1 ;
-+
-+ /* Limit, Hysteresis (neg), Range, Critical */
-+
-+ if (nr < 0 || nr > 2)
-+ return ; /* ERROR */
-+
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 1;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ lm85_update_client(client);
-+
-+ results[0] = TEMP_FROM_REG(data->zone[nr].limit) / 10;
-+ results[1] = HYST_FROM_REG(data->zone[nr].hyst);
-+ results[2] = RANGE_FROM_REG(data->zone[nr].range);
-+ results[3] = TEMP_FROM_REG(data->zone[nr].critical) / 10;
-+ *nrels_mag = 4;
-+
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ down(&data->update_lock);
-+ if (*nrels_mag > 3) {
-+ data->zone[nr].critical = TEMP_TO_REG(results[3]*10);
-+ lm85_write_value(client, LM85_REG_AFAN_CRITICAL(nr),
-+ data->zone[nr].critical );
-+ }
-+ if (*nrels_mag > 2) {
-+ data->zone[nr].range = RANGE_TO_REG(results[2]);
-+ lm85_write_value(client, LM85_REG_AFAN_RANGE(nr),
-+ (data->zone[nr].range << 4)
-+ | data->autofan[nr].freq
-+ );
-+ }
-+ if (*nrels_mag > 1) {
-+ data->zone[nr].hyst = HYST_TO_REG(results[1]);
-+ if( nr == 0 || nr == 1 ) {
-+ lm85_write_value(client, LM85_REG_AFAN_HYST1,
-+ (data->zone[0].hyst << 4)
-+ | data->zone[1].hyst
-+ );
-+ } else {
-+ lm85_write_value(client, LM85_REG_AFAN_HYST2,
-+ (data->zone[2].hyst << 4)
-+ );
-+ }
-+ }
-+ if (*nrels_mag > 0) {
-+ data->zone[nr].limit = TEMP_TO_REG(results[0]*10);
-+ lm85_write_value(client, LM85_REG_AFAN_LIMIT(nr),
-+ data->zone[nr].limit
-+ );
-+ }
-+ up(&data->update_lock);
-+ }
-+}
-+
-+void lm85_pwm_zone(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct lm85_data *data = client->data;
-+ int nr = ctl_name - LM85_SYSCTL_PWM_ZONE1 ;
-+
-+ if (nr < 0 || nr > 2)
-+ return ; /* ERROR */
-+
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 0;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ lm85_update_client(client);
-+ results[0] = ZONE_FROM_REG(data->autofan[nr].config);
-+ *nrels_mag = 1;
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ down(&data->update_lock);
-+ if (*nrels_mag > 0) {
-+ data->autofan[nr].config =
-+ (data->autofan[nr].config & (~0xe0))
-+ | ZONE_TO_REG(results[0]) ;
-+ lm85_write_value(client, LM85_REG_AFAN_CONFIG(nr),
-+ data->autofan[nr].config);
-+ }
-+ up(&data->update_lock);
-+ }
-+}
-+
-+void adm1027_temp_offset(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct lm85_data *data = client->data;
-+ int nr = ctl_name - ADM1027_SYSCTL_TEMP_OFFSET1 ;
-+
-+ if (nr < 0 || nr > 2)
-+ return ; /* ERROR */
-+
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 2;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ lm85_update_client(client);
-+ switch( data->type ) {
-+ case adm1027 :
-+ default :
-+ results[0] = TEMP_FROM_REG(data->temp_offset[nr]);
-+ break ;
-+ case adt7463 :
-+ results[0] = TEMPEXT_FROM_REG(0,data->temp_offset[nr]);
-+ break ;
-+ }
-+ *nrels_mag = 1;
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ down(&data->update_lock);
-+ if (*nrels_mag > 0) {
-+ switch( data->type ) {
-+ case adm1027 :
-+ default :
-+ data->temp_offset[nr] = TEMP_TO_REG(results[0]);
-+ break ;
-+ case adt7463 :
-+ data->temp_offset[nr] = EXTTEMP_TO_REG(results[0]);
-+ break ;
-+ };
-+ lm85_write_value(client, ADM1027_REG_TEMP_OFFSET(nr),
-+ data->temp_offset[nr]);
-+ }
-+ up(&data->update_lock);
-+ }
-+}
-+
-+void adm1027_fan_ppr(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct lm85_data *data = client->data;
-+ int old ;
-+
-+ if (ctl_name != ADM1027_SYSCTL_FAN_PPR)
-+ return ; /* ERROR */
-+
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 0;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ lm85_update_client(client);
-+ results[0] = PPR_FROM_REG(data->fan_ppr,0);
-+ results[1] = PPR_FROM_REG(data->fan_ppr,1);
-+ results[2] = PPR_FROM_REG(data->fan_ppr,2);
-+ results[3] = PPR_FROM_REG(data->fan_ppr,3);
-+ *nrels_mag = 4;
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ down(&data->update_lock);
-+ old = data->fan_ppr ;
-+ if (*nrels_mag > 3) {
-+ old = (old & ~PPR_MASK(3)) | PPR_TO_REG(results[3],3);
-+ };
-+ if (*nrels_mag > 2) {
-+ old = (old & ~PPR_MASK(2)) | PPR_TO_REG(results[2],2);
-+ };
-+ if (*nrels_mag > 1) {
-+ old = (old & ~PPR_MASK(1)) | PPR_TO_REG(results[1],1);
-+ };
-+ if (*nrels_mag > 0) {
-+ old = (old & ~PPR_MASK(0)) | PPR_TO_REG(results[0],0);
-+ lm85_write_value(client, ADM1027_REG_FAN_PPR, old);
-+ data->fan_ppr = old ;
-+ }
-+ up(&data->update_lock);
-+ }
-+}
-+
-+void adm1027_alarm_mask(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results)
-+{
-+ struct lm85_data *data = client->data;
-+
-+ if( ctl_name != ADM1027_SYSCTL_ALARM_MASK )
-+ return ; /* ERROR */
-+
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 0;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ lm85_update_client(client);
-+ results[0] = INTMASK_FROM_REG(data->alarm_mask);
-+ *nrels_mag = 1;
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ down(&data->update_lock);
-+ if (*nrels_mag > 0) {
-+ data->alarm_mask = INTMASK_TO_REG(results[0]);
-+ lm85_write_value(client, ADM1027_REG_INTMASK,
-+ data->alarm_mask);
-+ }
-+ up(&data->update_lock);
-+ }
-+}
-+
-+void adt7463_tmin_ctl(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct lm85_data *data = client->data;
-+ int nr = ctl_name - ADT7463_SYSCTL_TMIN_CTL1 ;
-+ u16 old ;
-+
-+ if (nr < 0 || nr > 2)
-+ return ; /* ERROR */
-+
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 0;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ old = data->tmin_ctl ;
-+ results[0] = (old & ( 0x2000 << nr )) != 0 ;
-+ results[1] = (old >> (nr*3)) & 0x07 ;
-+ results[2] = (old & ( 0x0400 << nr )) != 0 ;
-+ results[3] = OPPOINT_FROM_REG(data->oppoint[nr]);
-+ *nrels_mag = 4;
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ down(&data->update_lock);
-+ old = data->tmin_ctl ;
-+ if (*nrels_mag > 3) {
-+ data->oppoint[nr] = OPPOINT_TO_REG(results[3]);
-+ lm85_write_value(client, ADT7463_REG_OPPOINT(nr),
-+ data->oppoint[nr]);
-+ };
-+ if (*nrels_mag > 2) {
-+ if( results[2] ) {
-+ old |= (0x0400 << nr) ;
-+ } else {
-+ old &= ~(0x0400 << nr) ;
-+ }
-+ };
-+ if (*nrels_mag > 1) {
-+ old &= ~(0x07 << (nr*3)) ;
-+ old |= (results[1] & 0x07) << (nr*3) ;
-+ };
-+ if (*nrels_mag > 0) {
-+ if( results[0] ) {
-+ old |= 0x2000 << nr ;
-+ } else {
-+ old &= ~(0x2000 << nr) ;
-+ }
-+ lm85_write_value(client, ADT7463_REG_TMIN_CTL, old);
-+ data->tmin_ctl = old ;
-+ }
-+ up(&data->update_lock);
-+ }
-+}
-+
-+void adt7463_therm_signal(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results)
-+{
-+ struct lm85_data *data = client->data;
-+ int counts ;
-+
-+ if (ctl_name != ADT7463_SYSCTL_THERM_SIGNAL)
-+ return ; /* ERROR */
-+
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 0;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ /* Don't call update_client here because
-+ * ADT7463_REG_THERM has to be read every
-+ * 5 seconds to prevent lost counts
-+ */
-+ down(&data->update_lock);
-+ counts = lm85_read_value(client, ADT7463_REG_THERM) & 0xff;
-+ if( data->therm_total < LONG_MAX - 256 ) {
-+ data->therm_total += counts ;
-+ }
-+ if( counts >= 255 ) {
-+ ++data->therm_ovfl ;
-+ }
-+ up(&data->update_lock);
-+
-+ results[0] = data->therm_limit ;
-+ results[1] = data->therm_total ;
-+ results[2] = data->therm_ovfl ;
-+ *nrels_mag = 3;
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ down(&data->update_lock);
-+ /* therm_total and therm_ovfl are read only */
-+ if (*nrels_mag > 0) {
-+ data->therm_limit = SENSORS_LIMIT(results[0],0,255);
-+ lm85_write_value(client, ADT7463_REG_THERM_LIMIT,
-+ data->therm_limit);
-+ };
-+ up(&data->update_lock);
-+ }
-+}
-+
-+
-+void emc6d100_in(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct lm85_data *data = client->data;
-+ int nr = ctl_name - EMC6D100_SYSCTL_IN5 +5;
-+
-+ if (nr < 5 || nr > 7)
-+ return ; /* ERROR */
-+
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 3; /* 1.000 */
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ lm85_update_client(client);
-+ results[0] = INS_FROM_REG(nr,data->in_min[nr]);
-+ results[1] = INS_FROM_REG(nr,data->in_max[nr]);
-+ results[2] = INS_FROM_REG(nr,data->in[nr]);
-+ *nrels_mag = 3;
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ down(&data->update_lock);
-+ if (*nrels_mag > 1) {
-+ data->in_max[nr] = INS_TO_REG(nr,results[1]);
-+ lm85_write_value(client, EMC6D100_REG_IN_MAX(nr),
-+ data->in_max[nr]);
-+ }
-+ if (*nrels_mag > 0) {
-+ data->in_min[nr] = INS_TO_REG(nr,results[0]);
-+ lm85_write_value(client, EMC6D100_REG_IN_MIN(nr),
-+ data->in_min[nr]);
-+ }
-+ up(&data->update_lock);
-+ }
-+}
-+
-+
-+static int __init sm_lm85_init(void)
-+{
-+ printk("lm85: Version %s (%s)\n", LM_VERSION, LM_DATE);
-+ printk("lm85: See http://www.penguincomputing.com/lm_sensors for more info.\n" );
-+ return i2c_add_driver(&lm85_driver);
-+}
-+
-+static void __exit sm_lm85_exit(void)
-+{
-+ i2c_del_driver(&lm85_driver);
-+}
-+
-+/* Thanks to Richard Barrington for adding the LM85 to sensors-detect.
-+ * Thanks to Margit Schubert-While <margitsw@t-online.de> for help with
-+ * post 2.7.0 CVS changes
-+ */
-+MODULE_LICENSE("GPL");
-+MODULE_AUTHOR("Philip Pokorny <ppokorny@penguincomputing.com");
-+MODULE_DESCRIPTION("LM85-B, LM85-C driver");
-+
-+module_init(sm_lm85_init);
-+module_exit(sm_lm85_exit);
---- linux-old/drivers/sensors/lm87.c Thu Jan 1 00:00:00 1970
-+++ linux/drivers/sensors/lm87.c Mon Dec 13 20:18:49 2004
-@@ -0,0 +1,988 @@
-+/*
-+ LM87.c - Part of lm_sensors, Linux kernel modules for hardware
-+ monitoring
-+ Copyright (c) 2000 Frodo Looijaard <frodol@dds.nl>
-+ Philip Edelbrock <phil@netroedge.com>
-+ Stephen Rousset <stephen.rousset@rocketlogix.com>
-+ Dan Eaton <dan.eaton@rocketlogix.com>
-+
-+ 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., 675 Mass Ave, Cambridge, MA 02139, USA.
-+*/
-+
-+
-+#include <linux/module.h>
-+#include <linux/slab.h>
-+#include <linux/i2c.h>
-+#include <linux/i2c-proc.h>
-+#include <linux/init.h>
-+#define LM_DATE "20041007"
-+#define LM_VERSION "2.8.8"
-+#include <linux/sensors_vid.h>
-+
-+/* Chip configuration settings. These should be set to reflect the
-+HARDWARE configuration of your chip. By default (read: when all of
-+these are left commented out), this driver assumes that the
-+configuration is the same as National's defaults for the Channel Mode
-+register.
-+
-+Set to '1' the appropriate defines, as nessesary:
-+
-+ - External temp sensors 2 (possible second CPU temp)
-+ This will disable the 2.5V and Vccp2 readings.
-+ Ironically, National decided that you can read the
-+ temperature of a second CPU or it's core voltage,
-+ but not both! Comment out if FAULT is reported. */
-+
-+/* #define LM87_EXT2 1 */
-+
-+/* Aux analog input. When enabled, the Fan 1 reading
-+ will be disabled */
-+
-+/* #define LM87_AIN1 1 */
-+
-+/* Aux analog input 2. When enabled, the Fan 2 reading
-+ will be disabled */
-+
-+/* #define LM87_AIN2 1 */
-+
-+/* Internal Vcc is 5V instead of 3.3V */
-+
-+/* #define LM87_5V_VCC 1 */
-+
-+/* That's the end of the hardware config defines. I would have made
-+ them insmod params, but it would be too much work. ;') */
-+
-+
-+
-+/* Addresses to scan */
-+static unsigned short normal_i2c[] = { SENSORS_I2C_END };
-+static unsigned short normal_i2c_range[] = { 0x2c, 0x2e, SENSORS_I2C_END };
-+static unsigned int normal_isa[] = { SENSORS_ISA_END };
-+static unsigned int normal_isa_range[] = { SENSORS_ISA_END };
-+
-+/* Insmod parameters */
-+SENSORS_INSMOD_1(lm87);
-+
-+/* The following is the calculation for the register offset
-+ * for the monitored items minimum and maximum locations.
-+ */
-+#define LM87_REG_IN_MAX(nr) (0x2b + ((nr) * 2))
-+#define LM87_REG_IN_MIN(nr) (0x2c + ((nr) * 2))
-+#define LM87_REG_IN(nr) (0x20 + (nr))
-+
-+/* Initial limits */
-+
-+/*
-+ * LM87 register definition
-+ *
-+ */
-+
-+ /* The LM87 registers */
-+#define LM87_INT_TEMP_HI_LIMIT_LOCKABLE 0x13
-+#define LM87_EXT_TEMP_HI_LIMIT_LOCKABLE 0x14
-+#define LM87_REG_TEST 0x15
-+#define LM87_REG_CHANNEL_MODE 0x16
-+#define LM87_REG_INT_TEMP_HI_LIMIT 0x17
-+#define LM87_REG_EXT_TEMP_HI_LIMIT 0x18
-+#define LM87_REG_ANALOG_OUT 0x19
-+
-+ /* These are all read-only */
-+#define LM87_REG_2_5V_EXT_TEMP_2 0x20
-+#define LM87_REG_VCCP1 0x21
-+#define LM87_REG_3_3V 0x22
-+#define LM87_REG_5V 0x23
-+#define LM87_REG_12V 0x24
-+#define LM87_REG_VCCP2 0x25
-+#define LM87_REG_EXT_TEMP_1 0x26
-+#define LM87_REG_INT_TEMP 0x27 /* LM87 temp. */
-+#define LM87_REG_FAN1_AIN1 0x28
-+#define LM87_REG_FAN2_AIN2 0x29
-+
-+/* These are read/write */
-+#define LM87_REG_AIN1_LOW 0x1A
-+#define LM87_REG_AIN2_LOW 0x1B
-+#define LM87_REG_2_5V_EXT_TEMP_2_HIGH 0x2B
-+#define LM87_REG_2_5V_EXT_TEMP_2_LOW 0x2C
-+#define LM87_REG_VCCP1_HIGH 0x2D
-+#define LM87_REG_VCCP1_LOW 0x2E
-+#define LM87_REG_3_3V_HIGH 0x2F
-+#define LM87_REG_3_3V_LOW 0x30
-+#define LM87_REG_5V_HIGH 0x31
-+#define LM87_REG_5V_LOW 0x32
-+#define LM87_REG_12V_HIGH 0x33
-+#define LM87_REG_12V_LOW 0x34
-+#define LM87_REG_VCCP2_HIGH 0x35
-+#define LM87_REG_VCCP2_LOW 0x36
-+#define LM87_REG_EXT_TEMP_1_HIGH 0x37
-+#define LM87_REG_EXT_TEMP_1_LOW 0x38
-+#define LM87_REG_INT_TEMP_HIGH 0x39
-+#define LM87_REG_INT_TEMP_LOW 0x3A
-+#define LM87_REG_FAN1_AIN1_LIMIT 0x3B
-+#define LM87_REG_FAN2_AIN2_LIMIT 0x3C
-+#define LM87_REG_COMPANY_ID 0x3E
-+#define LM87_REG_DIE_REV 0x3F
-+
-+#define LM87_REG_CONFIG 0x40
-+#define LM87_REG_INT1_STAT 0x41
-+#define LM87_REG_INT2_STAT 0x42
-+#define LM87_REG_INT1_MASK 0x43
-+#define LM87_REG_INT2_MASK 0x44
-+#define LM87_REG_CHASSIS_CLEAR 0x46
-+#define LM87_REG_VID_FAN_DIV 0x47
-+#define LM87_REG_VID4 0x49
-+#define LM87_REG_CONFIG_2 0x4A
-+#define LM87_REG_INTRPT_STATUS_1_MIRROR 0x4C
-+#define LM87_REG_INTRPT_STATUS_2_MIRROR 0x4D
-+#define LM87_REG_SMBALERT_NUM_ENABLE 0x80
-+
-+
-+
-+/* Conversions. Rounding and limit checking is only done on the TO_REG
-+ variants. Note that you should be a bit careful with which arguments
-+ these macros are called: arguments may be evaluated more than once.
-+ Fixing this is just not worth it. */
-+
-+#define IN_TO_REG(val,nr) (SENSORS_LIMIT(((val) & 0xff),0,255))
-+#define IN_FROM_REG(val,nr) (val)
-+
-+static inline u8 FAN_TO_REG(long rpm, int div)
-+{
-+ if (rpm == 0)
-+ return 255;
-+ rpm = SENSORS_LIMIT(rpm, 1, 1000000);
-+ return SENSORS_LIMIT((1350000 + rpm * div / 2) / (rpm * div), 1,
-+ 254);
-+}
-+
-+#define FAN_FROM_REG(val,div) ((val)==0?-1:\
-+ (val)==255?0:1350000/((div)*(val)))
-+
-+#define TEMP_FROM_REG(temp) (temp * 10)
-+
-+#define TEMP_LIMIT_FROM_REG(val) (((val)>0x80?(val)-0x100:(val))*10)
-+
-+#define TEMP_LIMIT_TO_REG(val) SENSORS_LIMIT(((val)<0?(((val)-5)/10):\
-+ ((val)+5)/10),0,255)
-+#if 0
-+#define TEMP_FROM_REG(temp) \
-+ ((temp)<256?((((temp)&0x1fe) >> 1) * 10) + ((temp) & 1) * 5: \
-+ ((((temp)&0x1fe) >> 1) -255) * 10 - ((temp) & 1) * 5) \
-+
-+#define TEMP_LIMIT_FROM_REG(val) (val)
-+
-+#define TEMP_LIMIT_TO_REG(val) SENSORS_LIMIT((val),0,255)
-+#endif
-+
-+
-+#define ALARMS_FROM_REG(val) (val)
-+
-+#define DIV_FROM_REG(val) (1 << (val))
-+#define DIV_TO_REG(val) ((val)==1?0:((val)==8?3:((val)==4?2:1)))
-+
-+/* For each registered LM87, we need to keep some data in memory. That
-+ data is pointed to by LM87_list[NR]->data. The structure itself is
-+ dynamically allocated, at the same time when a new LM87 client is
-+ allocated. */
-+struct lm87_data {
-+ struct i2c_client client;
-+ int sysctl_id;
-+ enum chips type;
-+
-+ struct semaphore update_lock;
-+ char valid; /* !=0 if following fields are valid */
-+ unsigned long last_updated; /* In jiffies */
-+
-+ u8 in[6]; /* Scaled Register value */
-+ u8 in_max[6]; /* Scaled Register value */
-+ u8 in_min[6]; /* Scaled Register value */
-+ u8 ain1; /* Register value */
-+ u8 ain1_min; /* Register value */
-+ u8 ain1_max; /* Register value */
-+ u8 ain2; /* Register value */
-+ u8 ain2_min; /* Register value */
-+ u8 ain2_max; /* Register value */
-+ u8 fan; /* Register value */
-+ u8 fan_min; /* Register value */
-+ u8 fan_div; /* Register encoding, shifted right */
-+ u8 fan2; /* Register value */
-+ u8 fan2_min; /* Register value */
-+ u8 fan2_div; /* Register encoding, shifted right */
-+ int ext2_temp; /* Temp, shifted right */
-+ int ext_temp; /* Temp, shifted right */
-+ int int_temp; /* Temp, shifted right */
-+ u8 ext_temp_max; /* Register value */
-+ u8 ext_temp_min; /* Register value */
-+ u8 ext2_temp_max; /* Register value */
-+ u8 ext2_temp_min; /* Register value */
-+ u8 int_temp_max; /* Register value */
-+ u8 int_temp_min; /* Register value */
-+ u16 alarms; /* Register encoding, combined */
-+ u8 analog_out; /* Register value */
-+ u8 vid; /* Register value combined */
-+ u8 vrm; /* VRM version * 10 */
-+};
-+
-+static int lm87_attach_adapter(struct i2c_adapter *adapter);
-+static int lm87_detect(struct i2c_adapter *adapter, int address,
-+ unsigned short flags, int kind);
-+static int lm87_detach_client(struct i2c_client *client);
-+
-+static int lm87_read_value(struct i2c_client *client, u8 register);
-+static int lm87_write_value(struct i2c_client *client, u8 register,
-+ u8 value);
-+static void lm87_update_client(struct i2c_client *client);
-+static void lm87_init_client(struct i2c_client *client);
-+
-+
-+static void lm87_in(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+#if defined (LM87_AIN1) || defined (LM87_AIN2)
-+static void lm87_ain(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+#endif
-+static void lm87_fan(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void lm87_temp(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void lm87_alarms(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void lm87_fan_div(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void lm87_analog_out(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag,
-+ long *results);
-+static void lm87_vid(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void lm87_vrm(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+
-+static int lm87_id = 0;
-+
-+static struct i2c_driver LM87_driver = {
-+ .owner = THIS_MODULE,
-+ .name = "LM87 sensor driver",
-+ .id = I2C_DRIVERID_LM87,
-+ .flags = I2C_DF_NOTIFY,
-+ .attach_adapter = lm87_attach_adapter,
-+ .detach_client = lm87_detach_client,
-+};
-+
-+/* -- SENSORS SYSCTL START -- */
-+#define LM87_SYSCTL_IN0 1000 /* Volts * 100 */
-+#define LM87_SYSCTL_IN1 1001
-+#define LM87_SYSCTL_IN2 1002
-+#define LM87_SYSCTL_IN3 1003
-+#define LM87_SYSCTL_IN4 1004
-+#define LM87_SYSCTL_IN5 1005
-+#define LM87_SYSCTL_AIN1 1006
-+#define LM87_SYSCTL_AIN2 1007
-+#define LM87_SYSCTL_FAN1 1102
-+#define LM87_SYSCTL_FAN2 1103
-+#define LM87_SYSCTL_TEMP1 1250 /* Degrees Celcius * 100 */
-+#define LM87_SYSCTL_TEMP2 1251 /* Degrees Celcius * 100 */
-+#define LM87_SYSCTL_TEMP3 1252 /* Degrees Celcius * 100 */
-+#define LM87_SYSCTL_FAN_DIV 2000 /* 1, 2, 4 or 8 */
-+#define LM87_SYSCTL_ALARMS 2001 /* bitvector */
-+#define LM87_SYSCTL_ANALOG_OUT 2002
-+#define LM87_SYSCTL_VID 2003
-+#define LM87_SYSCTL_VRM 2004
-+
-+#define LM87_ALARM_IN0 0x0001
-+#define LM87_ALARM_IN1 0x0002
-+#define LM87_ALARM_IN2 0x0004
-+#define LM87_ALARM_IN3 0x0008
-+#define LM87_ALARM_TEMP1 0x0010
-+#define LM87_ALARM_TEMP2 0x0020
-+#define LM87_ALARM_TEMP3 0x0020 /* same?? */
-+#define LM87_ALARM_FAN1 0x0040
-+#define LM87_ALARM_FAN2 0x0080
-+#define LM87_ALARM_IN4 0x0100
-+#define LM87_ALARM_IN5 0x0200
-+#define LM87_ALARM_RESERVED1 0x0400
-+#define LM87_ALARM_RESERVED2 0x0800
-+#define LM87_ALARM_CHAS 0x1000
-+#define LM87_ALARM_THERM_SIG 0x2000
-+#define LM87_ALARM_TEMP2_FAULT 0x4000
-+#define LM87_ALARM_TEMP3_FAULT 0x08000
-+
-+/* -- SENSORS SYSCTL END -- */
-+
-+/* The /proc/sys entries */
-+/* These files are created for each detected LM87. This is just a template;
-+ though at first sight, you might think we could use a statically
-+ allocated list, we need some way to get back to the parent - which
-+ is done through one of the 'extra' fields which are initialized
-+ when a new copy is allocated. */
-+
-+static ctl_table LM87_dir_table_template[] = {
-+#ifdef LM87_AIN1
-+ {LM87_SYSCTL_AIN1, "in6", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &lm87_ain},
-+#endif
-+#ifdef LM87_AIN2
-+ {LM87_SYSCTL_AIN2, "in7", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &lm87_ain},
-+#endif
-+#ifndef LM87_EXT2
-+ {LM87_SYSCTL_IN0, "in0", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &lm87_in},
-+ {LM87_SYSCTL_IN5, "in5", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &lm87_in},
-+#endif
-+ {LM87_SYSCTL_IN1, "in1", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &lm87_in},
-+ {LM87_SYSCTL_IN2, "in2", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &lm87_in},
-+ {LM87_SYSCTL_IN3, "in3", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &lm87_in},
-+ {LM87_SYSCTL_IN4, "in4", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &lm87_in},
-+#ifndef LM87_AIN1
-+ {LM87_SYSCTL_FAN1, "fan1", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &lm87_fan},
-+ {LM87_SYSCTL_FAN_DIV, "fan_div", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &lm87_fan_div},
-+#define LM87_FANDIV_FLAG
-+#endif
-+#ifndef LM87_AIN2
-+ {LM87_SYSCTL_FAN2, "fan2", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &lm87_fan},
-+#ifndef LM87_FANDIV_FLAG
-+ {LM87_SYSCTL_FAN_DIV, "fan_div", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &lm87_fan_div},
-+#endif /* LM87_FANDIV_FLAG */
-+#endif /* LM87_AIN2 */
-+#ifdef LM87_EXT2
-+ {LM87_SYSCTL_TEMP3, "temp3", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &lm87_temp},
-+#endif
-+ {LM87_SYSCTL_TEMP2, "temp2", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &lm87_temp},
-+ {LM87_SYSCTL_TEMP1, "temp1", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &lm87_temp},
-+ {LM87_SYSCTL_ALARMS, "alarms", NULL, 0, 0444, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &lm87_alarms},
-+ {LM87_SYSCTL_ANALOG_OUT, "analog_out", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &lm87_analog_out},
-+ {LM87_SYSCTL_VID, "vid", NULL, 0, 0444, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &lm87_vid},
-+ {LM87_SYSCTL_VRM, "vrm", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &lm87_vrm},
-+ {0}
-+};
-+
-+static int lm87_attach_adapter(struct i2c_adapter *adapter)
-+{
-+ int error;
-+ struct i2c_client_address_data lm87_client_data;
-+
-+ lm87_client_data.normal_i2c = addr_data.normal_i2c;
-+ lm87_client_data.normal_i2c_range = addr_data.normal_i2c_range;
-+ lm87_client_data.probe = addr_data.probe;
-+ lm87_client_data.probe_range = addr_data.probe_range;
-+ lm87_client_data.ignore = addr_data.ignore;
-+ lm87_client_data.ignore_range = addr_data.ignore_range;
-+ lm87_client_data.force = addr_data.forces->force;
-+
-+ error = i2c_probe(adapter, &lm87_client_data, lm87_detect);
-+ i2c_detect(adapter, &addr_data, lm87_detect);
-+
-+ return error;
-+}
-+
-+static int lm87_detect(struct i2c_adapter *adapter, int address,
-+ unsigned short flags, int kind)
-+{
-+ int i;
-+ struct i2c_client *new_client;
-+ struct lm87_data *data;
-+ int err = 0;
-+ const char *type_name = "";
-+ const char *client_name = "";
-+
-+ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
-+ goto ERROR0;
-+
-+ /* OK. For now, we presume we have a valid client. We now create the
-+ client structure, even though we cannot fill it completely yet.
-+ But it allows us to access LM87_{read,write}_value. */
-+
-+ if (!(data = kmalloc(sizeof(struct lm87_data), GFP_KERNEL))) {
-+ err = -ENOMEM;
-+ goto ERROR0;
-+ }
-+
-+ new_client = &data->client;
-+ new_client->addr = address;
-+ new_client->data = data;
-+ new_client->adapter = adapter;
-+ new_client->driver = &LM87_driver;
-+ new_client->flags = 0;
-+
-+ /* Now, we do the remaining detection. */
-+
-+ if (kind < 0) {
-+ if (((lm87_read_value(new_client, LM87_REG_CONFIG) & 0x80)
-+ != 0x00) ||
-+ (lm87_read_value(new_client, LM87_REG_COMPANY_ID) != 0x02))
-+ goto ERROR1;
-+ }
-+
-+ /* Fill in the remaining client fields and put into the global list */
-+ type_name = "lm87";
-+ client_name = "LM87 chip";
-+ strcpy(new_client->name, client_name);
-+ data->type = kind;
-+
-+ new_client->id = lm87_id++;
-+ data->valid = 0;
-+ init_MUTEX(&data->update_lock);
-+
-+ /* Tell the I2C layer a new client has arrived */
-+ if ((err = i2c_attach_client(new_client)))
-+ goto ERROR3;
-+
-+ /* Register a new directory entry with module sensors */
-+ if ((i = i2c_register_entry(new_client,
-+ type_name,
-+ LM87_dir_table_template)) < 0) {
-+ err = i;
-+ goto ERROR4;
-+ }
-+ data->sysctl_id = i;
-+
-+ /* Initialize the LM87 chip */
-+ lm87_init_client(new_client);
-+ return 0;
-+
-+/* OK, this is not exactly good programming practice, usually. But it is
-+ very code-efficient in this case. */
-+
-+ ERROR4:
-+ i2c_detach_client(new_client);
-+ ERROR3:
-+ ERROR1:
-+ kfree(data);
-+ ERROR0:
-+ return err;
-+}
-+
-+static int lm87_detach_client(struct i2c_client *client)
-+{
-+ int err;
-+
-+ i2c_deregister_entry(((struct lm87_data *) (client->data))->
-+ sysctl_id);
-+
-+ if ((err = i2c_detach_client(client))) {
-+ printk
-+ ("lm87.o: Client deregistration failed, client not detached.\n");
-+ return err;
-+ }
-+
-+ kfree(client->data);
-+
-+ return 0;
-+}
-+
-+static int lm87_read_value(struct i2c_client *client, u8 reg)
-+{
-+ return 0xFF & i2c_smbus_read_byte_data(client, reg);
-+}
-+
-+static int lm87_write_value(struct i2c_client *client, u8 reg, u8 value)
-+{
-+ return i2c_smbus_write_byte_data(client, reg, value);
-+}
-+
-+/* Called when we have found a new LM87. It should set limits, etc. */
-+static void lm87_init_client(struct i2c_client *client)
-+{
-+ struct lm87_data *data = client->data;
-+
-+ /* Reset all except Watchdog values and last conversion values
-+ This sets fan-divs to 2, among others. This makes most other
-+ initializations unnecessary */
-+ lm87_write_value(client, LM87_REG_CONFIG, 0x80);
-+
-+ /* Setup Channel Mode register for configuration of monitoring
-+ * Default is 00000000b
-+ * bit 0 - Configures Fan 1/AIN 1 input (1 = AIN)
-+ * bit 1 - Configures Fan 2/AIN 2 input (1 = AIN)
-+ * bit 2 - Configures 2.5V&Vccp2/D2 input (1 = 2nd Therm.)
-+ * bit 3 - Configures Vcc for 5V/3.3V reading (0 = 3.3V)
-+ * bit 4 - Configures IRQ0 Enable if = 1
-+ * bit 5 - Configures IRQ1 Enable if = 1
-+ * bit 6 - Configures IRQ2 Enable if = 1
-+ * bit 7 - Configures VID/IRQ input as interrupts if = 1
-+ */
-+
-+/* I know, not clean, but it works. :'p */
-+ lm87_write_value(client, LM87_REG_CHANNEL_MODE,
-+#ifdef LM87_AIN1
-+ 0x01
-+#else
-+0
-+#endif
-+ |
-+#ifdef LM87_AIN2
-+ 0x02
-+#else
-+0
-+#endif
-+ |
-+#ifdef LM87_EXT2
-+ 0x04
-+#else
-+0
-+#endif
-+ |
-+#ifdef LM87_5V_VCC
-+0x08
-+#else
-+0
-+#endif
-+ );
-+
-+ data->vrm = DEFAULT_VRM;
-+
-+ /* Start monitoring */
-+ lm87_write_value(client, LM87_REG_CONFIG, 0x01);
-+}
-+
-+static void lm87_update_client(struct i2c_client *client)
-+{
-+ struct lm87_data *data = client->data;
-+ int i;
-+
-+ down(&data->update_lock);
-+
-+ if ((jiffies - data->last_updated > HZ) || /* 1 sec cache */
-+ (jiffies < data->last_updated) ||
-+ !data->valid) {
-+ for (i = 0; i <= 5; i++) {
-+ data->in[i] =
-+ lm87_read_value(client,LM87_REG_IN(i));
-+ data->in_min[i] =
-+ lm87_read_value(client,LM87_REG_IN_MIN(i));
-+ data->in_max[i] =
-+ lm87_read_value(client,LM87_REG_IN_MAX(i));
-+ }
-+ data->ain1 =
-+ lm87_read_value(client,LM87_REG_FAN1_AIN1);
-+ data->ain1_min =
-+ lm87_read_value(client,LM87_REG_AIN1_LOW);
-+ data->ain1_max =
-+ lm87_read_value(client,LM87_REG_FAN1_AIN1_LIMIT);
-+ data->ain2 =
-+ lm87_read_value(client,LM87_REG_FAN2_AIN2);
-+ data->ain2_min =
-+ lm87_read_value(client,LM87_REG_AIN2_LOW);
-+ data->ain2_max =
-+ lm87_read_value(client,LM87_REG_FAN2_AIN2_LIMIT);
-+
-+ data->fan =
-+ lm87_read_value(client, LM87_REG_FAN1_AIN1);
-+ data->fan_min =
-+ lm87_read_value(client, LM87_REG_FAN1_AIN1_LIMIT);
-+ data->fan2 =
-+ lm87_read_value(client, LM87_REG_FAN2_AIN2);
-+ data->fan2_min =
-+ lm87_read_value(client, LM87_REG_FAN2_AIN2_LIMIT);
-+
-+ data->ext2_temp =
-+ lm87_read_value(client, LM87_REG_2_5V_EXT_TEMP_2);
-+ data->ext_temp =
-+ lm87_read_value(client, LM87_REG_EXT_TEMP_1);
-+ data->int_temp =
-+ lm87_read_value(client, LM87_REG_INT_TEMP);
-+
-+ data->ext2_temp_max =
-+ lm87_read_value(client, LM87_REG_2_5V_EXT_TEMP_2_HIGH);
-+ data->ext2_temp_min =
-+ lm87_read_value(client, LM87_REG_2_5V_EXT_TEMP_2_LOW);
-+
-+ data->ext_temp_max =
-+ lm87_read_value(client, LM87_REG_EXT_TEMP_1_HIGH);
-+ data->ext_temp_min =
-+ lm87_read_value(client, LM87_REG_EXT_TEMP_1_LOW);
-+
-+ data->int_temp_max =
-+ lm87_read_value(client, LM87_REG_INT_TEMP_HIGH);
-+ data->int_temp_min =
-+ lm87_read_value(client, LM87_REG_INT_TEMP_LOW);
-+
-+ i = lm87_read_value(client, LM87_REG_VID_FAN_DIV);
-+ data->fan_div = (i >> 4) & 0x03;
-+ data->fan2_div = (i >> 6) & 0x03;
-+ data->vid = i & 0x0f;
-+ data->vid |=
-+ (lm87_read_value(client, LM87_REG_VID4) & 0x01)
-+ << 4;
-+ data->alarms =
-+ lm87_read_value(client, LM87_REG_INT1_STAT) +
-+ (lm87_read_value(client, LM87_REG_INT2_STAT) << 8);
-+ data->analog_out =
-+ lm87_read_value(client, LM87_REG_ANALOG_OUT);
-+ data->last_updated = jiffies;
-+ data->valid = 1;
-+ }
-+ up(&data->update_lock);
-+}
-+
-+
-+/* The next few functions are the call-back functions of the /proc/sys and
-+ sysctl files. Which function is used is defined in the ctl_table in
-+ the extra1 field.
-+ Each function must return the magnitude (power of 10 to divide the date
-+ with) if it is called with operation==SENSORS_PROC_REAL_INFO. It must
-+ put a maximum of *nrels elements in results reflecting the data of this
-+ file, and set *nrels to the number it actually put in it, if operation==
-+ SENSORS_PROC_REAL_READ. Finally, it must get upto *nrels elements from
-+ results and write them to the chip, if operations==SENSORS_PROC_REAL_WRITE.
-+ Note that on SENSORS_PROC_REAL_READ, I do not check whether results is
-+ large enough (by checking the incoming value of *nrels). This is not very
-+ good practice, but as long as you put less than about 5 values in results,
-+ you can assume it is large enough. */
-+void lm87_in(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ long scales[6] = { 250, 270,
-+#ifdef LM87_5V_VCC
-+500,
-+#else
-+330,
-+#endif
-+ 500, 1200, 270 };
-+
-+ struct lm87_data *data = client->data;
-+ int nr = ctl_name - LM87_SYSCTL_IN0;
-+
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 2;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ lm87_update_client(client);
-+ results[0] =
-+ ((long)data->in_min[nr] * scales[nr]) / 192;
-+ results[1] =
-+ ((long)data->in_max[nr] * scales[nr]) / 192;
-+ results[2] =
-+ ((long)data->in[nr] * scales[nr]) / 192;
-+ *nrels_mag = 3;
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ if (*nrels_mag >= 1) {
-+ data->in_min[nr] =
-+ (results[0] * 192) / scales[nr];
-+ lm87_write_value(client, LM87_REG_IN_MIN(nr),
-+ data->in_min[nr]);
-+ }
-+ if (*nrels_mag >= 2) {
-+ data->in_max[nr] =
-+ (results[1] * 192) / scales[nr];
-+ lm87_write_value(client, LM87_REG_IN_MAX(nr),
-+ data->in_max[nr]);
-+ }
-+ }
-+}
-+
-+#if defined (LM87_AIN1) || defined (LM87_AIN2)
-+void lm87_ain(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct lm87_data *data = client->data;
-+
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 0;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ lm87_update_client(client);
-+ if (ctl_name == LM87_SYSCTL_AIN1) {
-+ results[0] = data->ain1_min;
-+ results[1] = data->ain1_max;
-+ results[2] = data->ain1;
-+ } else {
-+ results[0] = data->ain2_min;
-+ results[1] = data->ain2_max;
-+ results[2] = data->ain2;
-+ }
-+ *nrels_mag = 3;
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ if (*nrels_mag >= 1) {
-+ if (ctl_name == LM87_SYSCTL_AIN1) {
-+ data->ain1_min = results[0];
-+ lm87_write_value(client, LM87_REG_AIN1_LOW,
-+ data->ain1_min);
-+ } else {
-+ data->ain2_min = results[0];
-+ lm87_write_value(client, LM87_REG_AIN2_LOW,
-+ data->ain2_min);
-+ }
-+ }
-+ if (*nrels_mag >= 2) {
-+ if (ctl_name == LM87_SYSCTL_AIN1) {
-+ data->ain1_max = results[1];
-+ lm87_write_value(client, LM87_REG_FAN1_AIN1_LIMIT,
-+ data->ain1_max);
-+ } else {
-+ data->ain2_max = results[1];
-+ lm87_write_value(client, LM87_REG_FAN2_AIN2_LIMIT,
-+ data->ain2_max);
-+ }
-+ }
-+ }
-+}
-+#endif
-+
-+void lm87_fan(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct lm87_data *data = client->data;
-+
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 0;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ lm87_update_client(client);
-+ if (ctl_name == LM87_SYSCTL_FAN1) {
-+ results[0] = FAN_FROM_REG(data->fan_min,
-+ DIV_FROM_REG(data->fan_div));
-+ results[1] = FAN_FROM_REG(data->fan,
-+ DIV_FROM_REG(data->fan_div));
-+ } else {
-+ results[0] = FAN_FROM_REG(data->fan2_min,
-+ DIV_FROM_REG(data->fan2_div));
-+ results[1] = FAN_FROM_REG(data->fan2,
-+ DIV_FROM_REG(data->fan2_div));
-+ }
-+ *nrels_mag = 2;
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ if (*nrels_mag >= 0) {
-+ if (ctl_name == LM87_SYSCTL_FAN1) {
-+ data->fan_min = FAN_TO_REG(results[0],
-+ DIV_FROM_REG
-+ (data->fan_div));
-+ lm87_write_value(client, LM87_REG_FAN1_AIN1_LIMIT,
-+ data->fan_min);
-+ } else {
-+ data->fan2_min = FAN_TO_REG(results[0],
-+ DIV_FROM_REG
-+ (data->fan2_div));
-+ lm87_write_value(client, LM87_REG_FAN2_AIN2_LIMIT,
-+ data->fan2_min);
-+ }
-+ }
-+ }
-+}
-+
-+
-+void lm87_temp(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct lm87_data *data = client->data;
-+
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 1;
-+ else if (operation == SENSORS_PROC_REAL_READ)
-+ {
-+ lm87_update_client(client);
-+
-+ /* find out which temp. is being requested */
-+ if (ctl_name == LM87_SYSCTL_TEMP3)
-+ {
-+ results[0] = TEMP_LIMIT_FROM_REG(data->ext2_temp_max);
-+ results[1] = TEMP_LIMIT_FROM_REG(data->ext2_temp_min);
-+ results[2] = TEMP_FROM_REG(data->ext2_temp);
-+ }
-+ else if(ctl_name == LM87_SYSCTL_TEMP2)
-+ {
-+ results[0] = TEMP_LIMIT_FROM_REG(data->ext_temp_max);
-+ results[1] = TEMP_LIMIT_FROM_REG(data->ext_temp_min);
-+ results[2] = TEMP_FROM_REG(data->ext_temp);
-+ }
-+ else if(ctl_name == LM87_SYSCTL_TEMP1)
-+ {
-+ results[0] = TEMP_LIMIT_FROM_REG(data->int_temp_max);
-+ results[1] = TEMP_LIMIT_FROM_REG(data->int_temp_min);
-+ results[2] = TEMP_FROM_REG(data->int_temp);
-+ }
-+ *nrels_mag = 3;
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ if (*nrels_mag >= 1) {
-+ if (ctl_name == LM87_SYSCTL_TEMP3) {
-+ data->ext2_temp_max = TEMP_LIMIT_TO_REG(results[0]);
-+ lm87_write_value(client, LM87_REG_2_5V_EXT_TEMP_2_HIGH,
-+ data->ext2_temp_max);
-+ }
-+ if (ctl_name == LM87_SYSCTL_TEMP2) {
-+ data->ext_temp_max = TEMP_LIMIT_TO_REG(results[0]);
-+ lm87_write_value(client, LM87_REG_EXT_TEMP_1_HIGH,
-+ data->ext_temp_max);
-+ }
-+ if (ctl_name == LM87_SYSCTL_TEMP1) {
-+ data->int_temp_max = TEMP_LIMIT_TO_REG(results[0]);
-+ lm87_write_value(client, LM87_REG_INT_TEMP_HIGH,
-+ data->int_temp_max);
-+ }
-+ }
-+ if (*nrels_mag >= 2) {
-+ if (ctl_name == LM87_SYSCTL_TEMP3) {
-+ data->ext2_temp_min = TEMP_LIMIT_TO_REG(results[1]);
-+ lm87_write_value(client, LM87_REG_2_5V_EXT_TEMP_2_LOW,
-+ data->ext2_temp_min);
-+ }
-+ if (ctl_name == LM87_SYSCTL_TEMP2) {
-+ data->ext_temp_min = TEMP_LIMIT_TO_REG(results[1]);
-+ lm87_write_value(client, LM87_REG_EXT_TEMP_1_LOW,
-+ data->ext_temp_min);
-+ }
-+ if (ctl_name == LM87_SYSCTL_TEMP1) {
-+ data->int_temp_min = TEMP_LIMIT_TO_REG(results[1]);
-+ lm87_write_value(client, LM87_REG_INT_TEMP_LOW,
-+ data->int_temp_min);
-+ }
-+ }
-+ }
-+}
-+
-+void lm87_alarms(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct lm87_data *data = client->data;
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 0;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ lm87_update_client(client);
-+ results[0] = ALARMS_FROM_REG(data->alarms);
-+ *nrels_mag = 1;
-+ }
-+}
-+
-+void lm87_fan_div(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results)
-+{
-+/* This gets a little hairy depending on the hardware config */
-+
-+ struct lm87_data *data = client->data;
-+ int old;
-+
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 0;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ lm87_update_client(client);
-+#ifndef LM87_AIN1
-+ results[0] = DIV_FROM_REG(data->fan_div);
-+# ifndef LM87_AIN2
-+ results[1] = DIV_FROM_REG(data->fan2_div);
-+ *nrels_mag = 2;
-+# else
-+ *nrels_mag = 1;
-+# endif
-+#else /* Must be referring to fan 2 */
-+ results[0] = DIV_FROM_REG(data->fan2_div);
-+ *nrels_mag = 1;
-+#endif
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ old = lm87_read_value(client, LM87_REG_VID_FAN_DIV);
-+/* Note: it's OK to change fan2 div even if fan2 isn't enabled */
-+#ifndef LM87_AIN1
-+ if (*nrels_mag >= 2) {
-+ data->fan2_div = DIV_TO_REG(results[1]);
-+ old = (old & 0x3f) | (data->fan2_div << 6);
-+ }
-+ if (*nrels_mag >= 1) {
-+ data->fan_div = DIV_TO_REG(results[0]);
-+ old = (old & 0xcf) | (data->fan_div << 4);
-+ lm87_write_value(client, LM87_REG_VID_FAN_DIV, old);
-+ }
-+#else /* Must be referring to fan 2 */
-+ if (*nrels_mag >= 1) {
-+ data->fan2_div = DIV_TO_REG(results[0]);
-+ old = (old & 0xcf) | (data->fan2_div << 6);
-+ lm87_write_value(client, LM87_REG_VID_FAN_DIV, old);
-+ }
-+#endif
-+ }
-+}
-+
-+void lm87_analog_out(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results)
-+{
-+ struct lm87_data *data = client->data;
-+
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 0;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ lm87_update_client(client);
-+ results[0] = data->analog_out;
-+ *nrels_mag = 1;
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ if (*nrels_mag >= 1) {
-+ data->analog_out = results[0];
-+ lm87_write_value(client, LM87_REG_ANALOG_OUT,
-+ data->analog_out);
-+ }
-+ }
-+}
-+
-+void lm87_vid(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct lm87_data *data = client->data;
-+
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 3;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ lm87_update_client(client);
-+ results[0] = vid_from_reg(data->vid, data->vrm);
-+ *nrels_mag = 1;
-+ }
-+}
-+
-+void lm87_vrm(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct lm87_data *data = client->data;
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 1;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ results[0] = data->vrm;
-+ *nrels_mag = 1;
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ if (*nrels_mag >= 1)
-+ data->vrm = results[0];
-+ }
-+}
-+
-+static int __init sm_lm87_init(void)
-+{
-+ printk("lm87.o version %s (%s)\n", LM_VERSION, LM_DATE);
-+ return i2c_add_driver(&LM87_driver);
-+}
-+
-+static void __exit sm_lm87_exit(void)
-+{
-+ i2c_del_driver(&LM87_driver);
-+}
-+
-+
-+
-+MODULE_LICENSE("GPL");
-+
-+MODULE_AUTHOR
-+ ("Frodo Looijaard <frodol@dds.nl>, Philip Edelbrock <phil@netroedge.com>, "
-+ "Mark Studebaker <mdsxyz123@yahoo.com>, and Stephen Rousset <stephen.rousset@rocketlogix.com>");
-+
-+MODULE_DESCRIPTION("LM87 driver");
-+
-+module_init(sm_lm87_init);
-+module_exit(sm_lm87_exit);
---- linux-old/drivers/sensors/lm90.c Thu Jan 1 00:00:00 1970
-+++ linux/drivers/sensors/lm90.c Mon Dec 13 20:18:49 2004
-@@ -0,0 +1,782 @@
-+/*
-+ * lm90.c - Part of lm_sensors, Linux kernel modules for hardware
-+ * monitoring
-+ * Copyright (C) 2003-2004 Jean Delvare <khali@linux-fr.org>
-+ *
-+ * Based on the lm83 driver. The LM90 is a sensor chip made by National
-+ * Semiconductor. It reports up to two temperatures (its own plus up to
-+ * one external one) with a 0.125 deg resolution (1 deg for local
-+ * temperature) and a 3-4 deg accuracy. Complete datasheet can be
-+ * obtained from National's website at:
-+ * http://www.national.com/pf/LM/LM90.html
-+ *
-+ * This driver also supports the LM89 and LM99, two other sensor chips
-+ * made by National Semiconductor. Both have an increased remote
-+ * temperature measurement accuracy (1 degree), and the LM99
-+ * additionally shifts remote temperatures (measured and limits) by 16
-+ * degrees, which allows for higher temperatures measurement. The
-+ * driver doesn't handle it since it can be done easily in user-space.
-+ * Complete datasheets can be obtained from National's website at:
-+ * http://www.national.com/pf/LM/LM89.html
-+ * http://www.national.com/pf/LM/LM99.html
-+ * Note that there is no way to differenciate between both chips.
-+ *
-+ * This driver also supports the LM86, another sensor chip made by
-+ * National Semiconductor. It is exactly similar to the LM90 except it
-+ * has a higher accuracy.
-+ * Complete datasheet can be obtained from National's website at:
-+ * http://www.national.com/pf/LM/LM86.html
-+ *
-+ * This driver also supports the ADM1032, a sensor chip made by Analog
-+ * Devices. That chip is similar to the LM90, with a few differences
-+ * that are not handled by this driver. Complete datasheet can be
-+ * obtained from Analog's website at:
-+ * http://products.analog.com/products/info.asp?product=ADM1032
-+ * Among others, it has a higher accuracy than the LM90, much like the
-+ * LM86 does.
-+ *
-+ * This driver also supports the MAX6657 and MAX6658, sensor chips made
-+ * by Maxim. These chips are similar to the LM86. Complete datasheet
-+ * can be obtained at Maxim's website at:
-+ * http://www.maxim-ic.com/quick_view2.cfm/qv_pk/2578
-+ * Note that there is no way to differenciate between both chips (but
-+ * no need either).
-+ *
-+ * Since the LM90 was the first chipset supported by this driver, most
-+ * comments will refer to this chipset, but are actually general and
-+ * concern all supported chipsets, unless mentioned otherwise.
-+ *
-+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
-+ */
-+
-+#include <linux/module.h>
-+#include <linux/slab.h>
-+#include <linux/i2c.h>
-+#include <linux/i2c-proc.h>
-+#include <linux/init.h>
-+#define LM_DATE "20041007"
-+#define LM_VERSION "2.8.8"
-+
-+#ifndef I2C_DRIVERID_LM90
-+#define I2C_DRIVERID_LM90 1042
-+#endif
-+
-+/*
-+ * Addresses to scan
-+ * Address is fully defined internally and cannot be changed.
-+ * LM86, LM89, LM90, LM99, ADM1032, MAX6657 and MAX6658 have address 0x4c.
-+ * LM89-1, and LM99-1 have address 0x4d.
-+ */
-+
-+static unsigned short normal_i2c[] = { 0x4c, 0x4d, SENSORS_I2C_END };
-+static unsigned short normal_i2c_range[] = { SENSORS_I2C_END };
-+static unsigned int normal_isa[] = { SENSORS_ISA_END };
-+static unsigned int normal_isa_range[] = { SENSORS_ISA_END };
-+
-+/*
-+ * Insmod parameters
-+ */
-+
-+SENSORS_INSMOD_5(lm90, adm1032, lm99, lm86, max6657);
-+
-+/*
-+ * The LM90 registers
-+ */
-+
-+#define LM90_REG_R_MAN_ID 0xFE
-+#define LM90_REG_R_CHIP_ID 0xFF
-+#define LM90_REG_R_CONFIG1 0x03
-+#define LM90_REG_W_CONFIG1 0x09
-+#define LM90_REG_R_CONFIG2 0xBF
-+#define LM90_REG_W_CONFIG2 0xBF
-+#define LM90_REG_R_CONVRATE 0x04
-+#define LM90_REG_W_CONVRATE 0x0A
-+#define LM90_REG_R_STATUS 0x02
-+#define LM90_REG_R_LOCAL_TEMP 0x00
-+#define LM90_REG_R_LOCAL_HIGH 0x05
-+#define LM90_REG_W_LOCAL_HIGH 0x0B
-+#define LM90_REG_R_LOCAL_LOW 0x06
-+#define LM90_REG_W_LOCAL_LOW 0x0C
-+#define LM90_REG_R_LOCAL_CRIT 0x20
-+#define LM90_REG_W_LOCAL_CRIT 0x20
-+#define LM90_REG_R_REMOTE_TEMPH 0x01
-+#define LM90_REG_R_REMOTE_TEMPL 0x10
-+#define LM90_REG_R_REMOTE_OFFSH 0x11
-+#define LM90_REG_W_REMOTE_OFFSH 0x11
-+#define LM90_REG_R_REMOTE_OFFSL 0x12
-+#define LM90_REG_W_REMOTE_OFFSL 0x12
-+#define LM90_REG_R_REMOTE_HIGHH 0x07
-+#define LM90_REG_W_REMOTE_HIGHH 0x0D
-+#define LM90_REG_R_REMOTE_HIGHL 0x13
-+#define LM90_REG_W_REMOTE_HIGHL 0x13
-+#define LM90_REG_R_REMOTE_LOWH 0x08
-+#define LM90_REG_W_REMOTE_LOWH 0x0E
-+#define LM90_REG_R_REMOTE_LOWL 0x14
-+#define LM90_REG_W_REMOTE_LOWL 0x14
-+#define LM90_REG_R_REMOTE_CRIT 0x19
-+#define LM90_REG_W_REMOTE_CRIT 0x19
-+#define LM90_REG_R_TCRIT_HYST 0x21
-+#define LM90_REG_W_TCRIT_HYST 0x21
-+
-+/*
-+ * Conversions and various macros
-+ * The LM90 uses signed 8-bit values for the local temperatures,
-+ * and signed 11-bit values for the remote temperatures (except
-+ * T_CRIT). The 11-bit conversion formulas may not round negative
-+ * numbers perfectly, but who cares?
-+ */
-+
-+#define TEMP1_FROM_REG(val) (val & 0x80 ? val-0x100 : val)
-+#define TEMP1_TO_REG(val) (val < 0 ? val+0x100 : val)
-+#define TEMP2_FROM_REG(val) (((val & 0x8000 ? val-0x10000 : val) \
-+ * 10 + 128) >> 8)
-+#define TEMP2_TO_REG(val) (((val << 8) / 10 + (val < 0 ? \
-+ 0x10000 : 0)) & 0xFFE0)
-+#define HYST_TO_REG(val) (val < 0 ? 0 : val > 31 ? 31 : val)
-+
-+/*
-+ * Functions declaration
-+ */
-+
-+static int lm90_attach_adapter(struct i2c_adapter *adapter);
-+static int lm90_detect(struct i2c_adapter *adapter, int address,
-+ unsigned short flags, int kind);
-+static void lm90_init_client(struct i2c_client *client);
-+static int lm90_detach_client(struct i2c_client *client);
-+static void lm90_local_temp(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void lm90_remote_temp(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void lm90_local_tcrit(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void lm90_remote_tcrit(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void lm90_local_hyst(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void lm90_remote_hyst(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void lm90_alarms(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+
-+/*
-+ * Driver data (common to all clients)
-+ */
-+
-+static struct i2c_driver lm90_driver = {
-+ .owner = THIS_MODULE,
-+ .name = "LM90/ADM1032 sensor driver",
-+ .id = I2C_DRIVERID_LM90,
-+ .flags = I2C_DF_NOTIFY,
-+ .attach_adapter = lm90_attach_adapter,
-+ .detach_client = lm90_detach_client
-+};
-+
-+/*
-+ * Client data (each client gets its own)
-+ */
-+
-+struct lm90_data
-+{
-+ struct i2c_client client;
-+ int sysctl_id;
-+
-+ struct semaphore update_lock;
-+ char valid; /* zero until following fields are valid */
-+ unsigned long last_updated; /* in jiffies */
-+
-+ /* registers values */
-+ u8 local_temp, local_high, local_low;
-+ u16 remote_temp, remote_high, remote_low; /* combined */
-+ u8 local_crit, remote_crit;
-+ u8 hyst; /* linked to two sysctl files (hyst1 RW, hyst2 RO) */
-+ u16 alarms; /* bitvector, combined */
-+};
-+
-+/*
-+ * Proc entries
-+ * These files are created for each detected LM90.
-+ */
-+
-+/* -- SENSORS SYSCTL START -- */
-+
-+#define LM90_SYSCTL_LOCAL_TEMP 1200
-+#define LM90_SYSCTL_REMOTE_TEMP 1201
-+#define LM90_SYSCTL_LOCAL_TCRIT 1204
-+#define LM90_SYSCTL_REMOTE_TCRIT 1205
-+#define LM90_SYSCTL_LOCAL_HYST 1207
-+#define LM90_SYSCTL_REMOTE_HYST 1208
-+#define LM90_SYSCTL_ALARMS 1210
-+
-+#define LM90_ALARM_LOCAL_HIGH 0x40
-+#define LM90_ALARM_LOCAL_LOW 0x20
-+#define LM90_ALARM_LOCAL_CRIT 0x01
-+#define LM90_ALARM_REMOTE_HIGH 0x10
-+#define LM90_ALARM_REMOTE_LOW 0x08
-+#define LM90_ALARM_REMOTE_CRIT 0x02
-+#define LM90_ALARM_REMOTE_OPEN 0x04
-+
-+/* -- SENSORS SYSCTL END -- */
-+
-+
-+static ctl_table lm90_dir_table_template[] =
-+{
-+ {LM90_SYSCTL_LOCAL_TEMP, "temp1", NULL, 0, 0644, NULL,
-+ &i2c_proc_real, &i2c_sysctl_real, NULL, &lm90_local_temp},
-+ {LM90_SYSCTL_REMOTE_TEMP, "temp2", NULL, 0, 0644, NULL,
-+ &i2c_proc_real, &i2c_sysctl_real, NULL, &lm90_remote_temp},
-+ {LM90_SYSCTL_LOCAL_TCRIT, "tcrit1", NULL, 0, 0644, NULL,
-+ &i2c_proc_real, &i2c_sysctl_real, NULL, &lm90_local_tcrit},
-+ {LM90_SYSCTL_REMOTE_TCRIT, "tcrit2", NULL, 0, 0644, NULL,
-+ &i2c_proc_real, &i2c_sysctl_real, NULL, &lm90_remote_tcrit},
-+ {LM90_SYSCTL_LOCAL_HYST, "hyst1", NULL, 0, 0644, NULL,
-+ &i2c_proc_real, &i2c_sysctl_real, NULL, &lm90_local_hyst},
-+ {LM90_SYSCTL_REMOTE_HYST, "hyst2", NULL, 0, 0444, NULL,
-+ &i2c_proc_real, &i2c_sysctl_real, NULL, &lm90_remote_hyst},
-+ {LM90_SYSCTL_ALARMS, "alarms", NULL, 0, 0444, NULL,
-+ &i2c_proc_real, &i2c_sysctl_real, NULL, &lm90_alarms},
-+ {0}
-+};
-+
-+/*
-+ * Internal variables
-+ */
-+
-+static int lm90_id = 0;
-+
-+/*
-+ * Real code
-+ */
-+
-+static int lm90_attach_adapter(struct i2c_adapter *adapter)
-+{
-+ return i2c_detect(adapter, &addr_data, lm90_detect);
-+}
-+
-+/*
-+ * The following function does more than just detection. If detection
-+ * succeeds, it also registers the new chip.
-+ */
-+static int lm90_detect(struct i2c_adapter *adapter, int address,
-+ unsigned short flags, int kind)
-+{
-+ struct i2c_client *new_client;
-+ struct lm90_data *data;
-+ int err = 0;
-+ const char *type_name = "";
-+ const char *client_name = "";
-+
-+#ifdef DEBUG
-+ if (i2c_is_isa_adapter(adapter))
-+ {
-+ printk("lm90.o: Called for an ISA bus adapter, aborting.\n");
-+ return 0;
-+ }
-+#endif
-+
-+ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
-+ {
-+#ifdef DEBUG
-+ printk("lm90.o: I2C bus doesn't support byte read mode, "
-+ "skipping.\n");
-+#endif
-+ return 0;
-+ }
-+
-+ if (!(data = kmalloc(sizeof(struct lm90_data), GFP_KERNEL)))
-+ {
-+ printk("lm90.o: Out of memory in lm90_detect (new_client).\n");
-+ return -ENOMEM;
-+ }
-+
-+ /*
-+ * The common I2C client data is placed right before the
-+ * LM90-specific data. The LM90-specific data is pointed to by the
-+ * data field from the I2C client data.
-+ */
-+
-+ new_client = &data->client;
-+ new_client->addr = address;
-+ new_client->data = data;
-+ new_client->adapter = adapter;
-+ new_client->driver = &lm90_driver;
-+ new_client->flags = 0;
-+
-+ /*
-+ * Now we do the remaining detection. A negative kind means that
-+ * the driver was loaded with no force parameter (default), so we
-+ * must both detect and identify the chip. A zero kind means that
-+ * the driver was loaded with the force parameter, the detection
-+ * step shall be skipped. A positive kind means that the driver
-+ * was loaded with the force parameter and a given kind of chip is
-+ * requested, so both the detection and the identification steps
-+ * are skipped.
-+ */
-+
-+ /* Default to an LM90 if forced */
-+ if (kind == 0)
-+ kind = lm90;
-+
-+ if (kind < 0) /* detection and identification */
-+ {
-+ u8 man_id, chip_id, reg_config1, reg_convrate;
-+
-+ man_id = i2c_smbus_read_byte_data(new_client,
-+ LM90_REG_R_MAN_ID);
-+ chip_id = i2c_smbus_read_byte_data(new_client,
-+ LM90_REG_R_CHIP_ID);
-+ reg_config1 = i2c_smbus_read_byte_data(new_client,
-+ LM90_REG_R_CONFIG1);
-+ reg_convrate = i2c_smbus_read_byte_data(new_client,
-+ LM90_REG_R_CONVRATE);
-+
-+ if (man_id == 0x01) /* National Semiconductor */
-+ {
-+ u8 reg_config2;
-+
-+ reg_config2 = i2c_smbus_read_byte_data(new_client,
-+ LM90_REG_R_CONFIG2);
-+
-+ if ((reg_config1 & 0x2A) == 0x00
-+ && (reg_config2 & 0xF8) == 0x00
-+ && reg_convrate <= 0x09)
-+ {
-+ if (address == 0x4C
-+ && (chip_id & 0xF0) == 0x20) /* LM90 */
-+ kind = lm90;
-+ else if ((chip_id & 0xF0) == 0x30) /* LM89/LM99 */
-+ kind = lm99;
-+ else if (address == 0x4C
-+ && (chip_id & 0xF0) == 0x10) /* LM86 */
-+ kind = lm99;
-+ }
-+ }
-+ else if (man_id == 0x41) /* Analog Devices */
-+ {
-+ if (address == 0x4C
-+ && (chip_id & 0xF0) == 0x40 /* ADM1032 */
-+ && (reg_config1 & 0x3F) == 0x00
-+ && reg_convrate <= 0x0A)
-+ kind = adm1032;
-+ }
-+ else if (man_id == 0x4D) /* Maxim */
-+ {
-+ if (address == 0x4C
-+ && (reg_config1 & 0x1F) == 0
-+ && reg_convrate <= 0x09)
-+ kind = max6657;
-+ }
-+ }
-+
-+ if (kind <= 0) /* identification failed */
-+ {
-+ printk("lm90.o: Unsupported chip.\n");
-+ goto ERROR1;
-+ }
-+
-+ if (kind == lm90)
-+ {
-+ type_name = "lm90";
-+ client_name = "LM90 chip";
-+ }
-+ else if (kind == adm1032)
-+ {
-+ type_name = "adm1032";
-+ client_name = "ADM1032 chip";
-+ }
-+ else if (kind == lm99)
-+ {
-+ type_name = "lm99";
-+ client_name = "LM99 chip";
-+ }
-+ else if (kind == lm86)
-+ {
-+ type_name = "lm86";
-+ client_name = "LM86 chip";
-+ }
-+ else if (kind == max6657)
-+ {
-+ type_name = "max6657";
-+ client_name = "MAX6657 chip";
-+ }
-+ else
-+ {
-+ printk("lm90.o: Unknown kind %d.\n", kind);
-+ goto ERROR1;
-+ }
-+
-+ /*
-+ * OK, we got a valid chip so we can fill in the remaining client
-+ * fields.
-+ */
-+
-+ strcpy(new_client->name, client_name);
-+ new_client->id = lm90_id++;
-+ data->valid = 0;
-+ init_MUTEX(&data->update_lock);
-+
-+ /*
-+ * Tell the I2C layer a new client has arrived.
-+ */
-+
-+ if ((err = i2c_attach_client(new_client)))
-+ {
-+#ifdef DEBUG
-+ printk("lm90.o: Failed attaching client.\n");
-+#endif
-+ goto ERROR1;
-+ }
-+
-+ /*
-+ * Register a new directory entry.
-+ */
-+
-+ if ((err = i2c_register_entry(new_client, type_name,
-+ lm90_dir_table_template)) < 0)
-+ {
-+#ifdef DEBUG
-+ printk("lm90.o: Failed registering directory entry.\n");
-+#endif
-+ goto ERROR2;
-+ }
-+ data->sysctl_id = err;
-+
-+ /*
-+ * Initialize the LM90 chip.
-+ */
-+
-+ lm90_init_client(new_client);
-+ return 0;
-+
-+ ERROR2:
-+ i2c_detach_client(new_client);
-+ ERROR1:
-+ kfree(data);
-+ return err;
-+}
-+
-+static void lm90_init_client(struct i2c_client *client)
-+{
-+ u8 config;
-+
-+ /*
-+ * Start the conversions.
-+ */
-+
-+ i2c_smbus_write_byte_data(client, LM90_REG_W_CONVRATE,
-+ 5); /* 2 Hz */
-+ config = i2c_smbus_read_byte_data(client, LM90_REG_R_CONFIG1);
-+ if (config & 0x40)
-+ i2c_smbus_write_byte_data(client, LM90_REG_W_CONFIG1,
-+ config & 0xBF); /* run */
-+}
-+
-+
-+static int lm90_detach_client(struct i2c_client *client)
-+{
-+ int err;
-+
-+ i2c_deregister_entry(((struct lm90_data *) (client->data))->sysctl_id);
-+ if ((err = i2c_detach_client(client)))
-+ {
-+ printk("lm90.o: Client deregistration failed, client not "
-+ "detached.\n");
-+ return err;
-+ }
-+
-+ kfree(client->data);
-+ return 0;
-+}
-+
-+static void lm90_update_client(struct i2c_client *client)
-+{
-+ struct lm90_data *data = client->data;
-+
-+ down(&data->update_lock);
-+
-+ if ((jiffies - data->last_updated > HZ * 2) ||
-+ (jiffies < data->last_updated) || !data->valid)
-+ {
-+ u8 oldh, newh;
-+#ifdef DEBUG
-+ printk("lm90.o: Updating data.\n");
-+#endif
-+
-+ data->local_temp =
-+ i2c_smbus_read_byte_data(client, LM90_REG_R_LOCAL_TEMP);
-+ data->local_high =
-+ i2c_smbus_read_byte_data(client, LM90_REG_R_LOCAL_HIGH);
-+ data->local_low =
-+ i2c_smbus_read_byte_data(client, LM90_REG_R_LOCAL_LOW);
-+ data->local_crit =
-+ i2c_smbus_read_byte_data(client, LM90_REG_R_LOCAL_CRIT);
-+
-+ /*
-+ * There is a trick here. We have to read two registers to
-+ * have the remote sensor temperature, but we have to beware
-+ * a conversion could occur inbetween the readings. The
-+ * datasheet says we should either use the one-shot
-+ * conversion register, which we don't want to do (disables
-+ * hardware monitoring) or monitor the busy bit, which is
-+ * impossible (we can't read the values and monitor that bit
-+ * at the exact same time). So the solution used here is to
-+ * read the high byte once, then the low byte, then the high
-+ * byte again. If the new high byte matches the old one,
-+ * then we have a valid reading. Else we have to read the low
-+ * byte again, and now we believe we have a correct reading.
-+ */
-+
-+ oldh =
-+ i2c_smbus_read_byte_data(client, LM90_REG_R_REMOTE_TEMPH);
-+ data->remote_temp =
-+ i2c_smbus_read_byte_data(client, LM90_REG_R_REMOTE_TEMPL);
-+ newh =
-+ i2c_smbus_read_byte_data(client, LM90_REG_R_REMOTE_TEMPH);
-+ if (newh != oldh)
-+ {
-+ data->remote_temp =
-+ i2c_smbus_read_byte_data(client, LM90_REG_R_REMOTE_TEMPL);
-+#ifdef DEBUG
-+ oldh = /* actually newer */
-+ i2c_smbus_read_byte_data(client, LM90_REG_R_REMOTE_TEMPH);
-+ if (newh != oldh)
-+ printk("lm90.o: Remote temperature may be wrong.\n");
-+#endif
-+ }
-+ data->remote_temp |= (newh << 8);
-+ data->remote_high =
-+ (i2c_smbus_read_byte_data(client, LM90_REG_R_REMOTE_HIGHH) << 8)
-+ + i2c_smbus_read_byte_data(client, LM90_REG_R_REMOTE_HIGHL);
-+ data->remote_low =
-+ (i2c_smbus_read_byte_data(client, LM90_REG_R_REMOTE_LOWH) << 8)
-+ + i2c_smbus_read_byte_data(client, LM90_REG_R_REMOTE_LOWL);
-+ data->remote_crit =
-+ i2c_smbus_read_byte_data(client, LM90_REG_R_REMOTE_CRIT);
-+
-+ data->hyst =
-+ i2c_smbus_read_byte_data(client, LM90_REG_R_TCRIT_HYST);
-+ data->alarms =
-+ i2c_smbus_read_byte_data(client, LM90_REG_R_STATUS);
-+
-+ data->last_updated = jiffies;
-+ data->valid = 1;
-+ }
-+
-+ up(&data->update_lock);
-+}
-+
-+static void lm90_local_temp(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results)
-+{
-+ struct lm90_data *data = client->data;
-+
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 0; /* magnitude */
-+ else if (operation == SENSORS_PROC_REAL_READ)
-+ {
-+ lm90_update_client(client);
-+ results[0] = TEMP1_FROM_REG(data->local_high);
-+ results[1] = TEMP1_FROM_REG(data->local_low);
-+ results[2] = TEMP1_FROM_REG(data->local_temp);
-+ *nrels_mag = 3;
-+ }
-+ else if (operation == SENSORS_PROC_REAL_WRITE)
-+ {
-+ if (*nrels_mag >= 1)
-+ {
-+ data->local_high = TEMP1_TO_REG(results[0]);
-+ i2c_smbus_write_byte_data(client, LM90_REG_W_LOCAL_HIGH,
-+ data->local_high);
-+ }
-+ if (*nrels_mag >= 2)
-+ {
-+ data->local_low = TEMP1_TO_REG(results[1]);
-+ i2c_smbus_write_byte_data(client, LM90_REG_W_LOCAL_LOW,
-+ data->local_low);
-+ }
-+ }
-+}
-+
-+static void lm90_remote_temp(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results)
-+{
-+ struct lm90_data *data = client->data;
-+
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 1; /* magnitude */
-+ else if (operation == SENSORS_PROC_REAL_READ)
-+ {
-+ lm90_update_client(client);
-+ results[0] = TEMP2_FROM_REG(data->remote_high);
-+ results[1] = TEMP2_FROM_REG(data->remote_low);
-+ results[2] = TEMP2_FROM_REG(data->remote_temp);
-+ *nrels_mag = 3;
-+ }
-+ else if (operation == SENSORS_PROC_REAL_WRITE)
-+ {
-+ if (*nrels_mag >= 1)
-+ {
-+ data->remote_high = TEMP2_TO_REG(results[0]);
-+ i2c_smbus_write_byte_data(client, LM90_REG_W_REMOTE_HIGHH,
-+ data->remote_high >> 8);
-+ i2c_smbus_write_byte_data(client, LM90_REG_W_REMOTE_HIGHL,
-+ data->remote_high & 0xFF);
-+ }
-+ if (*nrels_mag >= 2)
-+ {
-+ data->remote_low = TEMP2_TO_REG(results[1]);
-+ i2c_smbus_write_byte_data(client, LM90_REG_W_REMOTE_LOWH,
-+ data->remote_low >> 8);
-+ i2c_smbus_write_byte_data(client, LM90_REG_W_REMOTE_LOWL,
-+ data->remote_low & 0xFF);
-+ }
-+ }
-+}
-+
-+static void lm90_local_tcrit(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results)
-+{
-+ struct lm90_data *data = client->data;
-+
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 0; /* magnitude */
-+ else if (operation == SENSORS_PROC_REAL_READ)
-+ {
-+ lm90_update_client(client);
-+ results[0] = TEMP1_FROM_REG(data->local_crit);
-+ *nrels_mag = 1;
-+ }
-+ else if (operation == SENSORS_PROC_REAL_WRITE)
-+ {
-+ if (*nrels_mag >= 1)
-+ {
-+ data->local_crit = TEMP1_TO_REG(results[0]);
-+ i2c_smbus_write_byte_data(client, LM90_REG_W_LOCAL_CRIT,
-+ data->local_crit);
-+ }
-+ }
-+}
-+
-+static void lm90_remote_tcrit(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results)
-+{
-+ struct lm90_data *data = client->data;
-+
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 0; /* magnitude */
-+ else if (operation == SENSORS_PROC_REAL_READ)
-+ {
-+ lm90_update_client(client);
-+ results[0] = TEMP1_FROM_REG(data->remote_crit);
-+ *nrels_mag = 1;
-+ }
-+ else if (operation == SENSORS_PROC_REAL_WRITE)
-+ {
-+ if (*nrels_mag >= 1)
-+ {
-+ data->remote_crit = TEMP1_TO_REG(results[0]);
-+ i2c_smbus_write_byte_data(client, LM90_REG_W_REMOTE_CRIT,
-+ data->remote_crit);
-+ }
-+ }
-+}
-+
-+/*
-+ * One quick note about hysteresis. Internally, the hysteresis value
-+ * is held in a single register by the LM90, as a relative value.
-+ * This relative value applies to both the local critical temperature
-+ * and the remote critical temperature. Since all temperatures exported
-+ * through procfs have to be absolute, we have to do some conversions.
-+ * The solution retained here is to export two absolute values, one for
-+ * each critical temperature. In order not to confuse the users too
-+ * much, only one file is writable. Would we fail to do so, users
-+ * would probably attempt to write to both files, as if they were
-+ * independant, and since they aren't, they wouldn't understand why
-+ * setting one affects the other one (and would probably claim there's
-+ * a bug in the driver).
-+ */
-+
-+static void lm90_local_hyst(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results)
-+{
-+ struct lm90_data *data = client->data;
-+
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 0; /* magnitude */
-+ else if (operation == SENSORS_PROC_REAL_READ)
-+ {
-+ lm90_update_client(client);
-+ results[0] = TEMP1_FROM_REG(data->local_crit) -
-+ TEMP1_FROM_REG(data->hyst);
-+ *nrels_mag = 1;
-+ }
-+ else if (operation == SENSORS_PROC_REAL_WRITE)
-+ {
-+ if (*nrels_mag >= 1)
-+ {
-+ data->hyst = HYST_TO_REG(data->local_crit - results[0]);
-+ i2c_smbus_write_byte_data(client, LM90_REG_W_TCRIT_HYST,
-+ data->hyst);
-+ }
-+ }
-+}
-+
-+static void lm90_remote_hyst(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results)
-+{
-+ struct lm90_data *data = client->data;
-+
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 0; /* magnitude */
-+ else if (operation == SENSORS_PROC_REAL_READ)
-+ {
-+ lm90_update_client(client);
-+ results[0] = TEMP1_FROM_REG(data->remote_crit) -
-+ TEMP1_FROM_REG(data->hyst);
-+ *nrels_mag = 1;
-+ }
-+}
-+
-+static void lm90_alarms(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results)
-+{
-+ struct lm90_data *data = client->data;
-+
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 0; /* magnitude */
-+ else if (operation == SENSORS_PROC_REAL_READ)
-+ {
-+ lm90_update_client(client);
-+ results[0] = data->alarms;
-+ *nrels_mag = 1;
-+ }
-+}
-+
-+static int __init sm_lm90_init(void)
-+{
-+ printk(KERN_INFO "lm90.o version %s (%s)\n", LM_VERSION, LM_DATE);
-+ return i2c_add_driver(&lm90_driver);
-+}
-+
-+static void __exit sm_lm90_exit(void)
-+{
-+ i2c_del_driver(&lm90_driver);
-+}
-+
-+MODULE_AUTHOR("Jean Delvare <khali@linux-fr.org>");
-+MODULE_DESCRIPTION("LM90/ADM1032 sensor driver");
-+MODULE_LICENSE("GPL");
-+
-+module_init(sm_lm90_init);
-+module_exit(sm_lm90_exit);
---- linux-old/drivers/sensors/lm92.c Thu Jan 1 00:00:00 1970
-+++ linux/drivers/sensors/lm92.c Mon Dec 13 20:18:49 2004
-@@ -0,0 +1,421 @@
-+
-+/*
-+ * LM92 - Part of lm_sensors, Linux kernel modules for hardware
-+ * monitoring
-+ *
-+ * Author: Abraham van der Merwe <abraham@2d3d.co.za>
-+ *
-+ * Linux support for the National Semiconductor LM92 Temperature
-+ * Sensor.
-+ *
-+ * Based on code from the lm-sensors project which is available
-+ * at http://www.lm-sensors.nu/. lm87.c have been particularly
-+ * helpful (:
-+ *
-+ * This source code is free software; you can redistribute it and/or
-+ * modify it under the terms of the GNU General Public License
-+ * version 2 as published by the Free Software Foundation.
-+ */
-+
-+#include <linux/config.h>
-+#include <linux/module.h>
-+#include <linux/kernel.h>
-+#include <linux/string.h>
-+#include <linux/slab.h>
-+#include <linux/init.h>
-+#include <linux/i2c.h>
-+#include <linux/i2c-proc.h>
-+#include <linux/proc_fs.h>
-+#include <linux/sysctl.h>
-+#include <asm/semaphore.h>
-+#define LM_DATE "20041007"
-+#define LM_VERSION "2.8.8"
-+
-+/* if defined, 4 faults must occur consecutively to set alarm flags */
-+/* #define ENABLE_FAULT_QUEUE */
-+
-+#define LM92_REG_TEMPERATURE 0x00 /* ro, 16-bit */
-+#define LM92_REG_CONFIGURATION 0x01 /* rw, 8-bit */
-+#define LM92_REG_TRIP_HYSTERESIS 0x02 /* rw, 16-bit */
-+#define LM92_REG_TRIP_CRITICAL 0x03 /* rw, 16-bit */
-+#define LM92_REG_TRIP_LOW 0x04 /* rw, 16-bit */
-+#define LM92_REG_TRIP_HIGH 0x05 /* rw, 16-bit */
-+#define LM92_REG_MANUFACTURER 0x07 /* ro, 16-bit */
-+
-+#define LM92_MANUFACTURER_ID 0x8001
-+
-+#define TEMP_MIN (-4096)
-+#define TEMP_MAX 4095
-+
-+#define LIMIT(x) do { \
-+ if ((x) < TEMP_MIN) (x) = TEMP_MIN; \
-+ if ((x) > TEMP_MAX) (x) = TEMP_MAX; \
-+ } while (0)
-+
-+#define PROC_TO_NATIVE(x) ((x) / 625)
-+#define NATIVE_TO_PROC(x) ((x) * 625)
-+#define CELSIUS(x) ((x) * 16)
-+
-+static void lm92_temp (struct i2c_client *client,int operation,int ctl_name,int *nrels_mag,long *results);
-+static void lm92_alarms (struct i2c_client *client,int operation,int ctl_name,int *nrels_mag,long *results);
-+
-+/* -- SENSORS SYSCTL START -- */
-+#define LM92_SYSCTL_ALARMS 2001 /* high, low, critical */
-+#define LM92_SYSCTL_TEMP 1200 /* high, low, critical, hysteresis, input */
-+
-+#define LM92_ALARM_TEMP_HIGH 0x01
-+#define LM92_ALARM_TEMP_LOW 0x02
-+#define LM92_ALARM_TEMP_CRIT 0x04
-+#define LM92_TEMP_HIGH 0x08
-+#define LM92_TEMP_LOW 0x10
-+#define LM92_TEMP_CRIT 0x20
-+#define LM92_TEMP_HYST 0x40
-+#define LM92_TEMP_INPUT 0x80
-+
-+/* -- SENSORS SYSCTL END -- */
-+
-+static ctl_table lm92_dir_table[] = {
-+ {LM92_SYSCTL_TEMP, "temp", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &lm92_temp, NULL},
-+ {LM92_SYSCTL_ALARMS, "alarms", NULL, 0, 0444, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &lm92_alarms, NULL},
-+ {0}
-+};
-+
-+/* NOTE: all temperatures are degrees centigrade * 16 */
-+typedef struct {
-+ struct i2c_client client;
-+ int sysctl_id;
-+ unsigned long timestamp;
-+ struct {
-+ long high;
-+ long low;
-+ long crit;
-+ long hyst;
-+ long input;
-+ } temp;
-+ struct {
-+ long low;
-+ long high;
-+ long crit;
-+ } alarms;
-+} lm92_t;
-+
-+/* this is needed for each client driver method */
-+static struct i2c_driver lm92_driver;
-+
-+/* ensure exclusive access to chip and static variables */
-+static DECLARE_MUTEX (mutex);
-+
-+/* addresses to scan */
-+static unsigned short normal_i2c[] = { SENSORS_I2C_END };
-+static unsigned short normal_i2c_range[] = { 0x48, 0x4f, SENSORS_I2C_END };
-+static unsigned int normal_isa[] = { SENSORS_ISA_END };
-+static unsigned int normal_isa_range[] = { SENSORS_ISA_END };
-+
-+/* insmod parameters */
-+SENSORS_INSMOD_1 (lm92);
-+
-+static inline int lm92_write8 (struct i2c_client *client,u8 reg,u8 value)
-+{
-+ return (i2c_smbus_write_byte_data (client,reg,value) < 0 ? -EIO : 0);
-+}
-+
-+static inline int lm92_read16 (struct i2c_client *client,u8 reg,u16 *value)
-+{
-+ s32 tmp = i2c_smbus_read_word_data (client,reg);
-+
-+ if (tmp < 0) return (-EIO);
-+
-+ /* convert the data to little endian format */
-+ *value = swab16((u16) tmp);
-+
-+ return (0);
-+}
-+
-+static inline int lm92_write16 (struct i2c_client *client,u8 reg,u16 value)
-+{
-+ /* convert the data to big endian format */
-+ if (i2c_smbus_write_word_data(client, reg, swab16(value)) < 0)
-+ return -EIO;
-+
-+ return 0;
-+}
-+
-+static int lm92_read (struct i2c_client *client)
-+{
-+ lm92_t *data = (lm92_t *) client->data;
-+ u16 value[5];
-+
-+ if ((jiffies - data->timestamp) > HZ) {
-+ if (lm92_read16 (client,LM92_REG_TEMPERATURE,value) < 0 ||
-+ lm92_read16 (client,LM92_REG_TRIP_HYSTERESIS,value + 1) < 0 ||
-+ lm92_read16 (client,LM92_REG_TRIP_CRITICAL,value + 2) < 0 ||
-+ lm92_read16 (client,LM92_REG_TRIP_LOW,value + 3) < 0 ||
-+ lm92_read16 (client,LM92_REG_TRIP_HIGH,value + 4) < 0)
-+ return (-EIO);
-+
-+ data->temp.input = (s16) value[0] >> 3;
-+ data->temp.hyst = (s16) value[1] >> 3;
-+ data->temp.crit = (s16) value[2] >> 3;
-+ data->temp.low = (s16) value[3] >> 3;
-+ data->temp.high = (s16) value[4] >> 3;
-+
-+ data->alarms.low = value[0] & 1;
-+ data->alarms.high = (value[0] & 2) >> 1;
-+ data->alarms.crit = (value[0] & 4) >> 2;
-+
-+ data->timestamp = jiffies;
-+ }
-+
-+ return (0);
-+}
-+
-+static int lm92_write (struct i2c_client *client)
-+{
-+ lm92_t *data = (lm92_t *) client->data;
-+
-+ LIMIT (data->temp.hyst);
-+ LIMIT (data->temp.crit);
-+ LIMIT (data->temp.low);
-+ LIMIT (data->temp.high);
-+
-+ if (lm92_write16 (client,LM92_REG_TRIP_HYSTERESIS,((s16) data->temp.hyst << 3)) < 0 ||
-+ lm92_write16 (client,LM92_REG_TRIP_CRITICAL,((s16) data->temp.crit << 3)) < 0 ||
-+ lm92_write16 (client,LM92_REG_TRIP_LOW,((s16) data->temp.low << 3)) < 0 ||
-+ lm92_write16 (client,LM92_REG_TRIP_HIGH,((s16) data->temp.high << 3)) < 0)
-+ return (-EIO);
-+
-+ return (0);
-+}
-+
-+static void lm92_temp (struct i2c_client *client,int operation,int ctl_name,int *nrels_mag,long *results)
-+{
-+ if (!down_interruptible (&mutex)) {
-+ lm92_t *data = (lm92_t *) client->data;
-+
-+ if (operation == SENSORS_PROC_REAL_READ) {
-+ lm92_read (client);
-+ results[0] = NATIVE_TO_PROC (data->temp.input);
-+ results[1] = NATIVE_TO_PROC (data->temp.high);
-+ results[2] = NATIVE_TO_PROC (data->temp.low);
-+ results[3] = NATIVE_TO_PROC (data->temp.crit);
-+ results[4] = NATIVE_TO_PROC (data->temp.hyst);
-+ *nrels_mag = 5;
-+ } else if (operation == SENSORS_PROC_REAL_WRITE && *nrels_mag == 4) {
-+ data->temp.high = PROC_TO_NATIVE (results[0]);
-+ data->temp.low = PROC_TO_NATIVE (results[1]);
-+ data->temp.crit = PROC_TO_NATIVE (results[2]);
-+ data->temp.hyst = PROC_TO_NATIVE (results[3]);
-+ lm92_write (client);
-+ } else if (operation == SENSORS_PROC_REAL_INFO) {
-+ *nrels_mag = 4;
-+ }
-+
-+ up (&mutex);
-+ }
-+}
-+
-+static void lm92_alarms (struct i2c_client *client,int operation,int ctl_name,int *nrels_mag,long *results)
-+{
-+ if (!down_interruptible (&mutex)) {
-+ lm92_t *data = (lm92_t *) client->data;
-+
-+ if (operation == SENSORS_PROC_REAL_READ) {
-+ lm92_read (client);
-+ results[0] = data->alarms.high || (data->alarms.low << 1) || (data->alarms.crit << 2);
-+ *nrels_mag = 1;
-+ } else if (operation == SENSORS_PROC_REAL_INFO) {
-+ *nrels_mag = 0;
-+ }
-+
-+ up (&mutex);
-+ }
-+}
-+
-+static int max6635_check(struct i2c_client *client)
-+{
-+ int i;
-+ u16 temp_low, temp_high, temp_hyst, temp_crit;
-+ u8 conf;
-+
-+ temp_low = i2c_smbus_read_word_data(client, LM92_REG_TRIP_LOW);
-+ temp_high = i2c_smbus_read_word_data(client, LM92_REG_TRIP_HIGH);
-+ temp_hyst = i2c_smbus_read_word_data(client, LM92_REG_TRIP_HYSTERESIS);
-+ temp_crit = i2c_smbus_read_word_data(client, LM92_REG_TRIP_CRITICAL);
-+
-+ if ((temp_low & 0x7f00) || (temp_high & 0x7f00)
-+ || (temp_hyst & 0x7f00) || (temp_crit & 0x7f00))
-+ return 0;
-+
-+ conf = i2c_smbus_read_byte_data(client, LM92_REG_CONFIGURATION);
-+
-+ for (i=0; i<128; i+=16) {
-+ if (temp_low != i2c_smbus_read_word_data(client, LM92_REG_TRIP_LOW + i)
-+ || temp_high != i2c_smbus_read_word_data(client, LM92_REG_TRIP_HIGH + i)
-+ || temp_hyst != i2c_smbus_read_word_data(client, LM92_REG_TRIP_HYSTERESIS + i)
-+ || temp_crit != i2c_smbus_read_word_data(client, LM92_REG_TRIP_CRITICAL + i)
-+ || conf != i2c_smbus_read_byte_data(client, LM92_REG_CONFIGURATION + i))
-+ return 0;
-+ }
-+
-+ return 1;
-+}
-+
-+static int lm92_init_client (struct i2c_client *client)
-+{
-+ lm92_t *data = (lm92_t *) client->data;
-+ u8 value = 0;
-+ int result;
-+
-+ /* force reads to query the chip */
-+ data->timestamp = 0;
-+
-+ /* setup the configuration register */
-+
-+#ifdef ENABLE_FAULT_QUEUE
-+ value |= 0x10;
-+#endif /* #ifdef ENABLE_FAULT_QUEUE */
-+
-+ if (lm92_write8 (client,LM92_REG_CONFIGURATION,value) < 0)
-+ return (-ENODEV);
-+
-+ /* set default alarm trigger values */
-+
-+ data->temp.high = CELSIUS (64);
-+ data->temp.low = CELSIUS (10);
-+ data->temp.crit = CELSIUS (80);
-+ data->temp.hyst = CELSIUS (2);
-+
-+ if ((result = lm92_write (client)) < 0)
-+ return (result);
-+
-+ /* read everything once so that our cached data is updated */
-+
-+ if ((result = lm92_read (client)) < 0)
-+ return (result);
-+
-+ return (0);
-+}
-+
-+static int lm92_detect (struct i2c_adapter *adapter,int address,unsigned short flags,int kind)
-+{
-+ static int id = 0;
-+ struct i2c_client *client;
-+ lm92_t *data;
-+ int result;
-+ u16 manufacturer;
-+
-+ if (!i2c_check_functionality (adapter,I2C_FUNC_SMBUS_BYTE_DATA))
-+ return (-ENODEV);
-+
-+ if (!(data = kmalloc(sizeof(lm92_t), GFP_KERNEL)))
-+ return (-ENOMEM);
-+
-+ client = &data->client;
-+ client->addr = address;
-+ client->data = data;
-+ client->adapter = adapter;
-+ client->driver = &lm92_driver;
-+ client->flags = 0;
-+ strcpy (client->name,lm92_driver.name);
-+
-+ if (down_interruptible (&mutex)) {
-+ result = -ERESTARTSYS;
-+ goto ERROR1;
-+ }
-+
-+ if (kind < 0) {
-+ /* Is it an lm92? */
-+ if (address < 0x4c
-+ && (lm92_read16(client,LM92_REG_MANUFACTURER,&manufacturer) < 0
-+ || manufacturer != LM92_MANUFACTURER_ID)) {
-+ /* Is it a MAX6635/MAX6635/MAX6635? */
-+ if (!max6635_check(client)) {
-+ result = -ENODEV;
-+ goto ERROR2;
-+ }
-+ }
-+ }
-+
-+ if ((result = i2c_attach_client (client))) {
-+ goto ERROR2;
-+ }
-+
-+ if ((result = i2c_register_entry (client,client->name,lm92_dir_table)) < 0) {
-+ goto ERROR3;
-+ }
-+ data->sysctl_id = result;
-+
-+ if ((result = lm92_init_client (client)) < 0) {
-+ goto ERROR4;
-+ }
-+
-+ client->id = id++;
-+
-+ up (&mutex);
-+
-+ return (0);
-+
-+ERROR4:
-+ i2c_deregister_entry(data->sysctl_id);
-+ERROR3:
-+ i2c_detach_client(client);
-+ERROR2:
-+ up(&mutex);
-+ERROR1:
-+ kfree(data);
-+ return result;
-+}
-+
-+static int lm92_attach_adapter (struct i2c_adapter *adapter)
-+{
-+ return i2c_detect (adapter,&addr_data,lm92_detect);
-+}
-+
-+static int lm92_detach_client (struct i2c_client *client)
-+{
-+ int result;
-+
-+ i2c_deregister_entry (((lm92_t *) (client->data))->sysctl_id);
-+
-+ if ((result = i2c_detach_client (client)))
-+ return (result);
-+
-+ kfree(client->data);
-+
-+ return (0);
-+}
-+
-+
-+static struct i2c_driver lm92_driver = {
-+ .owner = THIS_MODULE,
-+ .name = "lm92",
-+ .id = I2C_DRIVERID_LM92,
-+ .flags = I2C_DF_NOTIFY,
-+ .attach_adapter = lm92_attach_adapter,
-+ .detach_client = lm92_detach_client,
-+};
-+
-+static int __init sm_lm92_init(void)
-+{
-+ printk ("lm92.o version %s (%s)\n",LM_VERSION,LM_DATE);
-+ return i2c_add_driver(&lm92_driver);
-+}
-+
-+
-+static void __exit sm_lm92_exit(void)
-+{
-+ i2c_del_driver(&lm92_driver);
-+}
-+
-+
-+
-+MODULE_AUTHOR ("Abraham van der Merwe <abraham@2d3d.co.za>");
-+MODULE_DESCRIPTION ("Linux support for LM92 Temperature Sensor");
-+
-+MODULE_LICENSE ("GPL");
-+
-+module_init(sm_lm92_init);
-+module_exit(sm_lm92_exit);
-+
---- linux-old/drivers/sensors/matorb.c Thu Jan 1 00:00:00 1970
-+++ linux/drivers/sensors/matorb.c Mon Dec 13 20:18:49 2004
-@@ -0,0 +1,286 @@
-+/*
-+ matorb.c - Part of lm_sensors, Linux kernel modules for hardware
-+ monitoring
-+ Copyright (c) 1998, 1999 Frodo Looijaard <frodol@dds.nl>
-+ and Philip Edelbrock <phil@netroedge.com>
-+
-+ 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., 675 Mass Ave, Cambridge, MA 02139, USA.
-+*/
-+
-+
-+#define DEBUG 1
-+
-+#include <linux/module.h>
-+#include <linux/slab.h>
-+#include <linux/i2c.h>
-+#include <linux/i2c-proc.h>
-+#include <linux/init.h>
-+#define LM_DATE "20041007"
-+#define LM_VERSION "2.8.8"
-+
-+MODULE_LICENSE("GPL");
-+
-+/* Addresses to scan */
-+static unsigned short normal_i2c[] = { 0x2E, SENSORS_I2C_END };
-+static unsigned short normal_i2c_range[] = { SENSORS_I2C_END };
-+static unsigned int normal_isa[] = { SENSORS_ISA_END };
-+static unsigned int normal_isa_range[] = { SENSORS_ISA_END };
-+
-+/* Insmod parameters */
-+SENSORS_INSMOD_1(matorb);
-+
-+/* Many MATORB constants specified below */
-+
-+
-+/* Each client has this additional data */
-+struct matorb_data {
-+ struct i2c_client client;
-+ int sysctl_id;
-+
-+ struct semaphore update_lock;
-+ char valid; /* !=0 if following fields are valid */
-+ unsigned long last_updated; /* In jiffies */
-+
-+};
-+
-+static int matorb_attach_adapter(struct i2c_adapter *adapter);
-+static int matorb_detect(struct i2c_adapter *adapter, int address,
-+ unsigned short flags, int kind);
-+static void matorb_init_client(struct i2c_client *client);
-+static int matorb_detach_client(struct i2c_client *client);
-+
-+static int matorb_write_value(struct i2c_client *client, u8 reg,
-+ u16 value);
-+static void matorb_disp(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void matorb_update_client(struct i2c_client *client);
-+
-+
-+/* This is the driver that will be inserted */
-+static struct i2c_driver matorb_driver = {
-+ .owner = THIS_MODULE,
-+ .name = "Matrix Orbital LCD driver",
-+ .id = I2C_DRIVERID_MATORB,
-+ .flags = I2C_DF_NOTIFY,
-+ .attach_adapter = matorb_attach_adapter,
-+ .detach_client = matorb_detach_client,
-+};
-+
-+/* -- SENSORS SYSCTL START -- */
-+#define MATORB_SYSCTL_DISP 1000
-+/* -- SENSORS SYSCTL END -- */
-+
-+/* These files are created for each detected MATORB. This is just a template;
-+ though at first sight, you might think we could use a statically
-+ allocated list, we need some way to get back to the parent - which
-+ is done through one of the 'extra' fields which are initialized
-+ when a new copy is allocated. */
-+static ctl_table matorb_dir_table_template[] = {
-+ {MATORB_SYSCTL_DISP, "disp", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &matorb_disp},
-+ {0}
-+};
-+
-+static int matorb_id = 0;
-+
-+static int matorb_attach_adapter(struct i2c_adapter *adapter)
-+{
-+ return i2c_detect(adapter, &addr_data, matorb_detect);
-+}
-+
-+/* This function is called by i2c_detect */
-+int matorb_detect(struct i2c_adapter *adapter, int address,
-+ unsigned short flags, int kind)
-+{
-+ int i, cur;
-+ struct i2c_client *new_client;
-+ struct matorb_data *data;
-+ int err = 0;
-+ const char *type_name = "matorb";
-+ const char *client_name = "matorb";
-+
-+ /* Make sure we aren't probing the ISA bus!! This is just a safety check
-+ at this moment; i2c_detect really won't call us. */
-+#ifdef DEBUG
-+ if (i2c_is_isa_adapter(adapter)) {
-+ printk
-+ ("matorb.o: matorb_detect called for an ISA bus adapter?!?\n");
-+ return 0;
-+ }
-+#endif
-+
-+ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WRITE_BYTE |
-+ I2C_FUNC_SMBUS_WRITE_BYTE_DATA))
-+ goto ERROR0;
-+
-+
-+ /* OK. For now, we presume we have a valid client. We now create the
-+ client structure, even though we cannot fill it completely yet.
-+ But it allows us to access matorb_{read,write}_value. */
-+ if (!(data = kmalloc(sizeof(struct matorb_data), GFP_KERNEL))) {
-+ err = -ENOMEM;
-+ goto ERROR0;
-+ }
-+
-+ new_client = &data->client;
-+ new_client->addr = address;
-+ new_client->data = data;
-+ new_client->adapter = adapter;
-+ new_client->driver = &matorb_driver;
-+ new_client->flags = 0;
-+
-+ /* Now, we do the remaining detection. It is lousy. */
-+ cur = i2c_smbus_write_byte_data(new_client, 0x0FE, 0x58); /* clear screen */
-+
-+ printk("matorb.o: debug detect 0x%X\n", cur);
-+
-+ /* Fill in the remaining client fields and put it into the global list */
-+ strcpy(new_client->name, client_name);
-+
-+ new_client->id = matorb_id++;
-+ data->valid = 0;
-+ init_MUTEX(&data->update_lock);
-+
-+ /* Tell the I2C layer a new client has arrived */
-+ if ((err = i2c_attach_client(new_client)))
-+ goto ERROR3;
-+
-+ /* Register a new directory entry with module sensors */
-+ if ((i = i2c_register_entry(new_client, type_name,
-+ matorb_dir_table_template)) < 0) {
-+ err = i;
-+ goto ERROR4;
-+ }
-+ data->sysctl_id = i;
-+
-+ matorb_init_client(new_client);
-+ return 0;
-+
-+/* OK, this is not exactly good programming practice, usually. But it is
-+ very code-efficient in this case. */
-+
-+ ERROR4:
-+ i2c_detach_client(new_client);
-+ ERROR3:
-+ kfree(data);
-+ ERROR0:
-+ return err;
-+}
-+
-+static int matorb_detach_client(struct i2c_client *client)
-+{
-+ int err;
-+
-+ i2c_deregister_entry(((struct matorb_data *) (client->data))->
-+ sysctl_id);
-+
-+ if ((err = i2c_detach_client(client))) {
-+ printk
-+ ("matorb.o: Client deregistration failed, client not detached.\n");
-+ return err;
-+ }
-+
-+ kfree(client->data);
-+
-+ return 0;
-+}
-+
-+
-+#if 0
-+/* All registers are word-sized, except for the configuration register.
-+ MATORB uses a high-byte first convention, which is exactly opposite to
-+ the usual practice. */
-+static int matorb_read_value(struct i2c_client *client, u8 reg)
-+{
-+ return -1; /* Doesn't support reads */
-+}
-+#endif
-+
-+/* All registers are word-sized, except for the configuration register.
-+ MATORB uses a high-byte first convention, which is exactly opposite to
-+ the usual practice. */
-+static int matorb_write_value(struct i2c_client *client, u8 reg, u16 value)
-+{
-+ if (reg == 0) {
-+ return i2c_smbus_write_byte(client, value);
-+ } else {
-+ return i2c_smbus_write_byte_data(client, reg, value);
-+ }
-+}
-+
-+static void matorb_init_client(struct i2c_client *client)
-+{
-+ /* Initialize the MATORB chip */
-+}
-+
-+static void matorb_update_client(struct i2c_client *client)
-+{
-+ struct matorb_data *data = client->data;
-+
-+ down(&data->update_lock);
-+
-+ if ((jiffies - data->last_updated > HZ + HZ / 2) ||
-+ (jiffies < data->last_updated) || !data->valid) {
-+
-+#ifdef DEBUG
-+ printk("Starting matorb update\n");
-+#endif
-+
-+/* nothing yet */
-+ data->last_updated = jiffies;
-+ data->valid = 1;
-+ }
-+
-+ up(&data->update_lock);
-+}
-+
-+
-+void matorb_disp(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ int i;
-+
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 0;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ matorb_update_client(client);
-+ results[0] = 0;
-+ *nrels_mag = 3;
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ for (i = 1; i <= *nrels_mag; i++) {
-+ matorb_write_value(client, 0, results[i - 1]);
-+ }
-+ }
-+}
-+
-+static int __init sm_matorb_init(void)
-+{
-+ printk("matorb.o version %s (%s)\n", LM_VERSION, LM_DATE);
-+ return i2c_add_driver(&matorb_driver);
-+}
-+
-+static void __exit sm_matorb_exit(void)
-+{
-+ i2c_del_driver(&matorb_driver);
-+}
-+
-+
-+
-+MODULE_AUTHOR
-+ ("Frodo Looijaard <frodol@dds.nl> and Philip Edelbrock <phil@netroedge.com>");
-+MODULE_DESCRIPTION("MATORB driver");
-+
-+module_init(sm_matorb_init);
-+module_exit(sm_matorb_exit);
---- linux-old/drivers/sensors/max6650.c Thu Jan 1 00:00:00 1970
-+++ linux/drivers/sensors/max6650.c Mon Dec 13 20:18:50 2004
-@@ -0,0 +1,545 @@
-+/*
-+ * max6650.c - Part of lm_sensors, Linux kernel modules for hardware
-+ * monitoring.
-+ *
-+ * Author: John Morris <john.morris@spirentcom.com>
-+ *
-+ * Copyright (c) 2003 Spirent Communications
-+ *
-+ * This module has only been tested with the MAX6651 chip. It should
-+ * work with the MAX6650 also, though with reduced functionality. It
-+ * does not yet distinguish max6650 and max6651 chips.
-+ *
-+ * Tha datasheet was last seen at:
-+ *
-+ * http://pdfserv.maxim-ic.com/en/ds/MAX6650-MAX6651.pdf
-+ *
-+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
-+ */
-+
-+#include <linux/module.h>
-+#include <linux/slab.h>
-+#include <linux/i2c.h>
-+#include <linux/i2c-proc.h>
-+#include <linux/i2c-id.h>
-+#include <linux/init.h>
-+#define LM_DATE "20041007"
-+#define LM_VERSION "2.8.8"
-+
-+#ifndef I2C_DRIVERID_MAX6650
-+#define I2C_DRIVERID_MAX6650 1044
-+#endif
-+
-+/*
-+ * Addresses to scan. There are four disjoint possibilities, by pin config.
-+ */
-+
-+static unsigned short normal_i2c[] = {0x1b, 0x1f, 0x48, 0x4b, SENSORS_I2C_END};
-+static unsigned short normal_i2c_range[] = { SENSORS_I2C_END };
-+static unsigned int normal_isa[] = { SENSORS_ISA_END };
-+static unsigned int normal_isa_range[] = { SENSORS_ISA_END };
-+
-+/*
-+ * Insmod parameters
-+ */
-+
-+SENSORS_INSMOD_1(max6650);
-+
-+/*
-+ * MAX 6650/6651 registers
-+ */
-+
-+#define MAX6650_REG_SPEED 0x00
-+#define MAX6650_REG_CONFIG 0x02
-+#define MAX6650_REG_GPIO_DEF 0x04
-+#define MAX6650_REG_DAC 0x06
-+#define MAX6650_REG_ALARM_EN 0x08
-+#define MAX6650_REG_ALARM 0x0A
-+#define MAX6650_REG_TACH0 0x0C
-+#define MAX6650_REG_TACH1 0x0E
-+#define MAX6650_REG_TACH2 0x10
-+#define MAX6650_REG_TACH3 0x12
-+#define MAX6650_REG_GPIO_STAT 0x14
-+#define MAX6650_REG_COUNT 0x16
-+
-+/*
-+ * Config register bits
-+ */
-+
-+#define MAX6650_CFG_MODE_MASK 0x30
-+#define MAX6650_CFG_MODE_ON 0x00
-+#define MAX6650_CFG_MODE_OFF 0x10
-+#define MAX6650_CFG_MODE_CLOSED_LOOP 0x20
-+#define MAX6650_CFG_MODE_OPEN_LOOP 0x30
-+
-+static const u8 tach_reg[] =
-+{
-+ MAX6650_REG_TACH0, MAX6650_REG_TACH1,
-+ MAX6650_REG_TACH2, MAX6650_REG_TACH3
-+};
-+
-+#define MAX6650_INT_CLK 254000 /* Default clock speed - 254 kHz */
-+
-+/*
-+ * Functions declaration
-+ */
-+
-+static void max6650_fan (struct i2c_client *client, int operation, int
-+ ctl_name, int *nrels_mag, long *results);
-+static void max6650_speed (struct i2c_client *client, int operation, int
-+ ctl_name, int *nrels_mag, long *results);
-+static void max6650_xdump (struct i2c_client *client, int operation, int
-+ ctl_name, int *nrels_mag, long *results);
-+static int max6650_detect(struct i2c_adapter *adapter, int address, unsigned
-+ short flags, int kind);
-+static int max6650_attach_adapter(struct i2c_adapter *adapter);
-+static int max6650_detach_client(struct i2c_client *client);
-+static void max6650_init_client(struct i2c_client *client);
-+static int max6650_read(struct i2c_client *client, u8 reg);
-+
-+/*
-+ * Driver data (common to all clients)
-+ */
-+
-+
-+static struct i2c_driver max6650_driver = {
-+ .owner = THIS_MODULE,
-+ .name = "MAX6650/1 sensor driver",
-+ .id = I2C_DRIVERID_MAX6650,
-+ .flags = I2C_DF_NOTIFY,
-+ .attach_adapter = max6650_attach_adapter,
-+ .detach_client = max6650_detach_client
-+};
-+
-+/*
-+ * Client data (each client gets its own)
-+ */
-+
-+struct max6650_data
-+{
-+ struct i2c_client client;
-+ int sysctl_id;
-+ struct semaphore update_lock;
-+ char valid; /* zero until following fields are valid */
-+ unsigned long last_updated; /* in jiffies */
-+
-+ /* register values */
-+
-+ u8 speed;
-+ u8 config;
-+ u8 tach[4];
-+ u8 count;
-+};
-+
-+/*
-+ * Proc entries
-+ * These files are created for each detected max6650.
-+ */
-+
-+/* -- SENSORS SYSCTL START -- */
-+
-+#define MAX6650_SYSCTL_FAN1 1101
-+#define MAX6650_SYSCTL_FAN2 1102
-+#define MAX6650_SYSCTL_FAN3 1103
-+#define MAX6650_SYSCTL_FAN4 1104
-+#define MAX6650_SYSCTL_SPEED 1105
-+#define MAX6650_SYSCTL_XDUMP 1106
-+
-+
-+/* -- SENSORS SYSCTL END -- */
-+
-+
-+static ctl_table max6650_dir_table_template[] =
-+{
-+ {MAX6650_SYSCTL_FAN1, "fan1", NULL, 0, 0644, NULL,
-+ &i2c_proc_real, &i2c_sysctl_real, NULL, &max6650_fan},
-+ {MAX6650_SYSCTL_FAN2, "fan2", NULL, 0, 0644, NULL,
-+ &i2c_proc_real, &i2c_sysctl_real, NULL, &max6650_fan},
-+ {MAX6650_SYSCTL_FAN3, "fan3", NULL, 0, 0644, NULL,
-+ &i2c_proc_real, &i2c_sysctl_real, NULL, &max6650_fan},
-+ {MAX6650_SYSCTL_FAN4, "fan4", NULL, 0, 0644, NULL,
-+ &i2c_proc_real, &i2c_sysctl_real, NULL, &max6650_fan},
-+ {MAX6650_SYSCTL_SPEED, "speed", NULL, 0, 0644, NULL,
-+ &i2c_proc_real, &i2c_sysctl_real, NULL, &max6650_speed},
-+ {MAX6650_SYSCTL_XDUMP, "xdump", NULL, 0, 0644, NULL,
-+ &i2c_proc_real, &i2c_sysctl_real, NULL, &max6650_xdump},
-+ {0}
-+};
-+
-+/*
-+ * Internal variables
-+ */
-+
-+static int max6650_id = 0;
-+
-+/*
-+ * Real code
-+ */
-+
-+static int max6650_attach_adapter(struct i2c_adapter *adapter)
-+{
-+ return i2c_detect(adapter, &addr_data, max6650_detect);
-+}
-+
-+/*
-+ * The following function does more than just detection. If detection
-+ * succeeds, it also registers the new chip.
-+ */
-+
-+static int max6650_detect(struct i2c_adapter *adapter, int address, unsigned
-+ short flags, int kind)
-+{
-+ struct i2c_client *new_client;
-+ struct max6650_data *data;
-+ int err = 0;
-+ const char *type_name = "";
-+ const char *client_name = "";
-+
-+#ifdef DEBUG
-+ if (i2c_is_isa_adapter(adapter)) {
-+ printk("max6650.o: Called for an ISA bus adapter, aborting.\n");
-+ return 0;
-+ }
-+#endif
-+
-+ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
-+#ifdef DEBUG
-+ printk("max6650.o: I2C bus doesn't support byte read mode, skipping.\n");
-+#endif
-+ return 0;
-+ }
-+
-+ if (!(data = kmalloc(sizeof(struct max6650_data), GFP_KERNEL))) {
-+ printk("max6650.o: Out of memory in max6650_detect (new_client).\n");
-+ return -ENOMEM;
-+ }
-+
-+ /*
-+ * The common I2C client data is placed right before the
-+ * max6650-specific data. The max6650-specific data is pointed to by the
-+ * data field from the I2C client data.
-+ */
-+
-+ new_client = &data->client;
-+ new_client->addr = address;
-+ new_client->data = data;
-+ new_client->adapter = adapter;
-+ new_client->driver = &max6650_driver;
-+ new_client->flags = 0;
-+
-+ /*
-+ * Now we do the remaining detection. A negative kind means that
-+ * the driver was loaded with no force parameter (default), so we
-+ * must both detect and identify the chip (actually there is only
-+ * one possible kind of chip for now, max6650). A zero kind means that
-+ * the driver was loaded with the force parameter, the detection
-+ * step shall be skipped. A positive kind means that the driver
-+ * was loaded with the force parameter and a given kind of chip is
-+ * requested, so both the detection and the identification steps
-+ * are skipped.
-+ *
-+ * Currently I can find no way to distinguish between a MAX6650 and
-+ * a MAX6651. This driver has only been tried on the latter.
-+ */
-+
-+ if (kind < 0) { /* detection */
-+ if (
-+ (max6650_read(new_client, MAX6650_REG_CONFIG) & 0xC0) ||
-+ (max6650_read(new_client, MAX6650_REG_GPIO_STAT) & 0xE0) ||
-+ (max6650_read(new_client, MAX6650_REG_ALARM_EN) & 0xE0) ||
-+ (max6650_read(new_client, MAX6650_REG_ALARM) & 0xE0) ||
-+ (max6650_read(new_client, MAX6650_REG_COUNT) & 0xFC)
-+ )
-+ {
-+#ifdef DEBUG
-+ printk("max6650.o: max6650 detection failed at 0x%02x.\n",
-+ address);
-+#endif
-+ goto ERROR1;
-+ }
-+ }
-+
-+ if (kind <= 0) { /* identification */
-+ kind = max6650;
-+ }
-+
-+ if (kind <= 0) { /* identification failed */
-+ printk("max6650.o: Unsupported chip.\n");
-+ goto ERROR1;
-+ }
-+
-+ if (kind == max6650) {
-+ type_name = "max6650";
-+ client_name = "max6650 chip";
-+ } else {
-+ printk("max6650.o: Unknown kind %d.\n", kind);
-+ goto ERROR1;
-+ }
-+
-+ /*
-+ * OK, we got a valid chip so we can fill in the remaining client
-+ * fields.
-+ */
-+
-+ strcpy(new_client->name, client_name);
-+ new_client->id = max6650_id++;
-+ data->valid = 0;
-+ init_MUTEX(&data->update_lock);
-+
-+ /*
-+ * Tell the I2C layer a new client has arrived.
-+ */
-+
-+ if ((err = i2c_attach_client(new_client))) {
-+#ifdef DEBUG
-+ printk("max6650.o: Failed attaching client.\n");
-+#endif
-+ goto ERROR1;
-+ }
-+
-+ /*
-+ * Register a new directory entry.
-+ */
-+ if ((err = i2c_register_entry(new_client, type_name,
-+ max6650_dir_table_template)) < 0) {
-+#ifdef DEBUG
-+ printk("max6650.o: Failed registering directory entry.\n");
-+#endif
-+ goto ERROR2;
-+ }
-+ data->sysctl_id = err;
-+
-+ /*
-+ * Initialize the max6650 chip
-+ */
-+ max6650_init_client(new_client);
-+ return 0;
-+
-+ERROR2:
-+ i2c_detach_client(new_client);
-+ERROR1:
-+ kfree(data);
-+ return err;
-+}
-+
-+static void max6650_init_client(struct i2c_client *client)
-+{
-+ /* Nothing to do here - assume the BIOS has initialized the chip */
-+}
-+
-+static int max6650_detach_client(struct i2c_client *client)
-+{
-+ int err;
-+
-+ i2c_deregister_entry(((struct max6650_data *) (client->data))->sysctl_id);
-+ if ((err = i2c_detach_client(client))) {
-+ printk("max6650.o: Client deregistration failed, "
-+ "client not detached.\n");
-+ return err;
-+ }
-+
-+ kfree(client->data);
-+ return 0;
-+}
-+
-+static int max6650_read(struct i2c_client *client, u8 reg)
-+{
-+ return i2c_smbus_read_byte_data(client, reg);
-+}
-+
-+static int max6650_write(struct i2c_client *client, u8 reg, u8 value)
-+{
-+ return i2c_smbus_write_byte_data(client, reg, value);
-+}
-+
-+static void max6650_update_client(struct i2c_client *client)
-+{
-+ int i;
-+ struct max6650_data *data = client->data;
-+
-+ down(&data->update_lock);
-+
-+ if ((jiffies - data->last_updated > HZ) ||
-+ (jiffies < data->last_updated) || !data->valid) {
-+#ifdef DEBUG
-+ printk("max6650.o: Updating max6650 data.\n");
-+#endif
-+ data->speed = max6650_read (client, MAX6650_REG_SPEED);
-+ data->config = max6650_read (client, MAX6650_REG_CONFIG);
-+ for (i = 0; i < 4; i++) {
-+ data->tach[i] = max6650_read(client, tach_reg[i]);
-+ }
-+ data->count = max6650_read (client, MAX6650_REG_COUNT);
-+ data->last_updated = jiffies;
-+ data->valid = 1;
-+ }
-+ up(&data->update_lock);
-+}
-+
-+static void max6650_fan (struct i2c_client *client, int operation, int
-+ ctl_name, int *nrels_mag, long *results)
-+{
-+ int index = ctl_name - MAX6650_SYSCTL_FAN1;
-+ struct max6650_data *data = client->data;
-+ int tcount; /* Tachometer count time, 0.25 second units */
-+
-+ if (operation == SENSORS_PROC_REAL_INFO) {
-+ *nrels_mag = 0;
-+ } else if (operation == SENSORS_PROC_REAL_READ) {
-+ max6650_update_client(client);
-+
-+ /*
-+ * Calculation details:
-+ *
-+ * Each tachometer counts over an interval given by the "count"
-+ * register (0.25, 0.5, 1 or 2 seconds). This module assumes
-+ * that the fans produce two pulses per revolution (this seems
-+ * to be the most common).
-+ */
-+
-+ tcount = 1 << data->count; /* 0.25 second units */
-+ results[0] = (data->tach[index] * 240) / tcount; /* counts per min */
-+ results[0] /= 2; /* Assume two counts per rev */
-+ *nrels_mag = 1;
-+ }
-+}
-+
-+/*
-+ * Set the fan speed to the specified RPM (or read back the RPM setting).
-+ *
-+ * The MAX6650/1 will automatically control fan speed when in closed loop
-+ * mode.
-+ *
-+ * Assumptions:
-+ *
-+ * 1) The MAX6650/1 is running from its internal 254kHz clock (perhaps
-+ * this should be made a module parameter).
-+ *
-+ * 2) The prescaler (low three bits of the config register) has already
-+ * been set to an appropriate value.
-+ *
-+ * The relevant equations are given on pages 21 and 22 of the datasheet.
-+ *
-+ * From the datasheet, the relevant equation when in regulation is:
-+ *
-+ * [fCLK / (128 x (KTACH + 1))] = 2 x FanSpeed / KSCALE
-+ *
-+ * where:
-+ *
-+ * fCLK is the oscillator frequency (either the 254kHz internal
-+ * oscillator or the externally applied clock)
-+ *
-+ * KTACH is the value in the speed register
-+ *
-+ * FanSpeed is the speed of the fan in rps
-+ *
-+ * KSCALE is the prescaler value (1, 2, 4, 8, or 16)
-+ *
-+ * When reading, we need to solve for FanSpeed. When writing, we need to
-+ * solve for KTACH.
-+ *
-+ * Note: this tachometer is completely separate from the tachometers
-+ * used to measure the fan speeds. Only one fan's speed (fan1) is
-+ * controlled.
-+ */
-+
-+static void max6650_speed (struct i2c_client *client, int operation, int
-+ ctl_name, int *nrels_mag, long *results)
-+{
-+ struct max6650_data *data = client->data;
-+ int kscale, ktach, fclk, rpm;
-+
-+ if (operation == SENSORS_PROC_REAL_INFO) {
-+ *nrels_mag = 0;
-+ } else if (operation == SENSORS_PROC_REAL_READ) {
-+ /*
-+ * Use the datasheet equation:
-+ *
-+ * FanSpeed = KSCALE x fCLK / [256 x (KTACH + 1)]
-+ *
-+ * then multiply by 60 to give rpm.
-+ */
-+
-+ max6650_update_client(client);
-+
-+ kscale = 1 << (data->config & 7);
-+ ktach = data->speed;
-+ fclk = MAX6650_INT_CLK;
-+ rpm = 60 * kscale * fclk / (256 * (ktach + 1));
-+
-+ results[0] = rpm;
-+ *nrels_mag = 1;
-+ } else if (operation == SENSORS_PROC_REAL_WRITE && *nrels_mag >= 1) {
-+ /*
-+ * Divide the required speed by 60 to get from rpm to rps, then
-+ * use the datasheet equation:
-+ *
-+ * KTACH = [(fCLK x KSCALE) / (256 x FanSpeed)] - 1
-+ */
-+
-+ max6650_update_client(client);
-+
-+ rpm = results[0];
-+ kscale = 1 << (data->config & 7);
-+ fclk = MAX6650_INT_CLK;
-+ ktach = ((fclk * kscale) / (256 * rpm / 60)) - 1;
-+
-+ data->speed = ktach;
-+ data->config = (data->config & ~MAX6650_CFG_MODE_MASK) |
-+ MAX6650_CFG_MODE_CLOSED_LOOP;
-+ max6650_write (client, MAX6650_REG_CONFIG, data->config);
-+ max6650_write (client, MAX6650_REG_SPEED, data->speed);
-+ }
-+}
-+
-+/*
-+ * Debug - dump all registers except the tach counts.
-+ */
-+
-+static void max6650_xdump (struct i2c_client *client, int operation, int
-+ ctl_name, int *nrels_mag, long *results)
-+{
-+ if (operation == SENSORS_PROC_REAL_INFO) {
-+ *nrels_mag = 0;
-+ } else if (operation == SENSORS_PROC_REAL_READ) {
-+ results[0] = max6650_read (client, MAX6650_REG_SPEED);
-+ results[1] = max6650_read (client, MAX6650_REG_CONFIG);
-+ results[2] = max6650_read (client, MAX6650_REG_GPIO_DEF);
-+ results[3] = max6650_read (client, MAX6650_REG_DAC);
-+ results[4] = max6650_read (client, MAX6650_REG_ALARM_EN);
-+ results[5] = max6650_read (client, MAX6650_REG_ALARM);
-+ results[6] = max6650_read (client, MAX6650_REG_GPIO_STAT);
-+ results[7] = max6650_read (client, MAX6650_REG_COUNT);
-+ *nrels_mag = 8;
-+ }
-+}
-+
-+static int __init sm_max6650_init(void)
-+{
-+ printk(KERN_INFO "max6650.o version %s (%s)\n", LM_VERSION, LM_DATE);
-+ return i2c_add_driver(&max6650_driver);
-+}
-+
-+static void __exit sm_max6650_exit(void)
-+{
-+ i2c_del_driver(&max6650_driver);
-+}
-+
-+MODULE_AUTHOR("john.morris@spirentcom.com");
-+MODULE_DESCRIPTION("max6650 sensor driver");
-+MODULE_LICENSE("GPL");
-+
-+module_init(sm_max6650_init);
-+module_exit(sm_max6650_exit);
---- linux-old/drivers/sensors/maxilife.c Thu Jan 1 00:00:00 1970
-+++ linux/drivers/sensors/maxilife.c Mon Dec 13 20:18:50 2004
-@@ -0,0 +1,1387 @@
-+/*
-+ maxilife.c - Part of lm_sensors, Linux kernel modules for hardware
-+ monitoring
-+ Copyright (c) 1999-2000 Fons Rademakers <Fons.Rademakers@cern.ch>
-+
-+ 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., 675 Mass Ave, Cambridge, MA 02139, USA.
-+*/
-+
-+/* The is the driver for the HP MaxiLife Health monitoring system
-+ as used in the line of HP Kayak Workstation PC's.
-+
-+ The driver supports the following MaxiLife firmware versions:
-+
-+ 0) HP KAYAK XU/XAs (Dual Pentium II Slot 1, Deschutes/Klamath)
-+ 1) HP KAYAK XU (Dual Xeon [Slot 2] 400/450 Mhz)
-+ 2) HP KAYAK XA (Pentium II Slot 1, monoprocessor)
-+
-+ Currently firmware auto detection is not implemented. To use the
-+ driver load it with the correct option for you Kayak. For example:
-+
-+ insmod maxilife.o maxi_version=0 | 1 | 2
-+
-+ maxi_version=0 is the default
-+
-+ This version of MaxiLife is called MaxiLife'98 and has been
-+ succeeded by MaxiLife'99, see below.
-+
-+ The new version of the driver also supports MaxiLife NBA (New BIOS
-+ Architecture). This new MaxiLife controller provides a much cleaner
-+ machine independent abstraction layer to the MaxiLife controller.
-+ Instead of accessing directly registers (different for each revision)
-+ one now accesses the sensors via unique mailbox tokens that do not
-+ change between revisions. Also the quantities are already in physical
-+ units (degrees, rpms, voltages, etc.) and don't need special conversion
-+ formulas. This new MaxiLife is available on the new 2000 machines,
-+ like the Kayak XU800 and XM600. This hardware is also autodetected.
-+*/
-+
-+static const char *version_str = "2.00 29/2/2000 Fons Rademakers";
-+
-+
-+#include <linux/module.h>
-+#include <linux/slab.h>
-+#include <linux/i2c.h>
-+#include <linux/i2c-proc.h>
-+#include <linux/init.h>
-+#define LM_DATE "20041007"
-+#define LM_VERSION "2.8.8"
-+
-+MODULE_LICENSE("GPL");
-+
-+#undef AUTODETECT /* try to autodetect MaxiLife version */
-+/*#define AUTODETECT*/
-+#define NOWRITE /* don't allow writing to MaxiLife registers */
-+
-+#ifdef AUTODETECT
-+#include <linux/vmalloc.h>
-+#include <linux/ctype.h>
-+#endif
-+
-+/* Addresses to scan */
-+static unsigned short normal_i2c[] = { SENSORS_I2C_END };
-+static unsigned short normal_i2c_range[] = { 0x10, 0x14, SENSORS_I2C_END };
-+static unsigned int normal_isa[] = { SENSORS_ISA_END };
-+static unsigned int normal_isa_range[] = { SENSORS_ISA_END };
-+
-+/* Insmod parameters */
-+SENSORS_INSMOD_1(maxilife);
-+
-+/* Macro definitions */
-+#define LOW(MyWord) ((u8) (MyWord))
-+#define HIGH(MyWord) ((u8) (((u16)(MyWord) >> 8) & 0xFF))
-+
-+/*----------------- MaxiLife'98 registers and conversion formulas ------------*/
-+#define MAXI_REG_TEMP(nr) (0x60 + (nr))
-+
-+#define MAXI_REG_FAN(nr) (0x65 + (nr))
-+#define MAXI_REG_FAN_MIN(nr) ((nr)==0 ? 0xb3 : (nr)==1 ? 0xb3 : 0xab)
-+#define MAXI_REG_FAN_MINAS(nr) ((nr)==0 ? 0xb3 : (nr)==1 ? 0xab : 0xb3)
-+#define MAXI_REG_FAN_SPEED(nr) ((nr)==0 ? 0xe4 : (nr)==1 ? 0xe5 : 0xe9)
-+
-+#define MAXI_REG_PLL 0xb9
-+#define MAXI_REG_PLL_MIN 0xba
-+#define MAXI_REG_PLL_MAX 0xbb
-+
-+#define MAXI_REG_VID(nr) ((nr)==0 ? 0xd1 : (nr)==1 ? 0xd9 : \
-+ (nr)==2 ? 0xd4 : 0xc5)
-+#define MAXI_REG_VID_MIN(nr) MAXI_REG_VID(nr)+1
-+#define MAXI_REG_VID_MAX(nr) MAXI_REG_VID(nr)+2
-+
-+#define MAXI_REG_DIAG_RT1 0x2c
-+#define MAXI_REG_DIAG_RT2 0x2d
-+
-+#define MAXI_REG_BIOS_CTRL 0x2a
-+
-+/* Conversions. Rounding and limit checking is only done on the TO_REG
-+ variants. Note that you should be a bit careful with which arguments
-+ these macros are called: arguments may be evaluated more than once.
-+ Fixing this is just not worth it. */
-+
-+ /* 0xfe: fan off, 0xff: stopped (alarm) */
-+ /* 19531 / val * 60 == 1171860 / val */
-+#define FAN_FROM_REG(val) ((val)==0xfe ? 0 : (val)==0xff ? -1 : \
-+ (val)==0x00 ? -1 : (1171860 / (val)))
-+
-+static inline u8 FAN_TO_REG(long rpm)
-+{
-+ if (rpm == 0)
-+ return 255;
-+ rpm = SENSORS_LIMIT(rpm, 1, 1000000);
-+ return SENSORS_LIMIT((1171860 + rpm / 2) / (rpm), 1, 254);
-+}
-+
-+#define TEMP_FROM_REG(val) ((val) * 5)
-+#define TEMP_TO_REG(val) (SENSORS_LIMIT((val+2) / 5),0,0xff)
-+#define PLL_FROM_REG(val) (((val) * 1000) / 32)
-+#define PLL_TO_REG(val) (SENSORS_LIMIT((((val) * 32 + 500) / 1000),\
-+ 0,0xff))
-+#define VID_FROM_REG(val) ((val) ? (((val) * 27390) / 256) + 3208 : 0)
-+#define VID_TO_REG(val) (SENSORS_LIMIT((((val) - 3208) * 256) / 27390, \
-+ 0,255))
-+#define ALARMS_FROM_REG(val) (val)
-+
-+/*----------------- MaxiLife'99 mailbox and token definitions ----------------*/
-+/* MaxiLife mailbox data register map */
-+#define MAXI_REG_MBX_STATUS 0x5a
-+#define MAXI_REG_MBX_CMD 0x5b
-+#define MAXI_REG_MBX_TOKEN_H 0x5c
-+#define MAXI_REG_MBX_TOKEN_L 0x5d
-+#define MAXI_REG_MBX_DATA 0x60
-+
-+/* Mailbox status register definition */
-+#define MAXI_STAT_IDLE 0xff
-+#define MAXI_STAT_OK 0x00
-+#define MAXI_STAT_BUSY 0x0b
-+/* other values not used */
-+
-+/* Mailbox command register opcodes */
-+#define MAXI_CMD_READ 0x02
-+#define MAXI_CMD_WRITE 0x03
-+/* other values not used */
-+
-+/* MaxiLife NBA Hardware monitoring tokens */
-+
-+/* Alarm tokens (0x1xxx) */
-+#define MAXI_TOK_ALARM(nr) (0x1000 + (nr))
-+#define MAXI_TOK_ALARM_EVENT 0x1000
-+#define MAXI_TOK_ALARM_FAN 0x1001
-+#define MAXI_TOK_ALARM_TEMP 0x1002
-+#define MAXI_TOK_ALARM_VID 0x1003 /* voltages */
-+#define MAXI_TOK_ALARM_AVID 0x1004 /* additional voltages */
-+#define MAXI_TOK_ALARM_PWR 0x1101 /* power supply glitch */
-+
-+/* Fan status tokens (0x20xx) */
-+#define MAXI_TOK_FAN(nr) (0x2000 + (nr))
-+#define MAXI_TOK_FAN_CPU 0x2000
-+#define MAXI_TOK_FAN_PCI 0x2001
-+#define MAXI_TOK_FAN_HDD 0x2002 /* hard disk bay fan */
-+#define MAXI_TOK_FAN_SINK 0x2003 /* heatsink */
-+
-+/* Temperature status tokens (0x21xx) */
-+#define MAXI_TOK_TEMP(nr) (0x2100 + (nr))
-+#define MAXI_TOK_TEMP_CPU1 0x2100
-+#define MAXI_TOK_TEMP_CPU2 0x2101
-+#define MAXI_TOK_TEMP_PCI 0x2102 /* PCI/ambient temp */
-+#define MAXI_TOK_TEMP_HDD 0x2103 /* hard disk bay temp */
-+#define MAXI_TOK_TEMP_MEM 0x2104 /* mother board temp */
-+#define MAXI_TOK_TEMP_CPU 0x2105 /* CPU reference temp */
-+
-+/* Voltage status tokens (0x22xx) */
-+#define MAXI_TOK_VID(nr) (0x2200 + (nr))
-+#define MAXI_TOK_VID_12 0x2200 /* +12 volt */
-+#define MAXI_TOK_VID_CPU1 0x2201 /* cpu 1 voltage */
-+#define MAXI_TOK_VID_CPU2 0x2202 /* cpu 2 voltage */
-+#define MAXI_TOK_VID_L2 0x2203 /* level 2 cache voltage */
-+#define MAXI_TOK_VID_M12 0x2204 /* -12 volt */
-+
-+/* Additive voltage status tokens (0x23xx) */
-+#define MAXI_TOK_AVID(nr) (0x2300 + (nr))
-+#define MAXI_TOK_AVID_15 0x2300 /* 1.5 volt */
-+#define MAXI_TOK_AVID_18 0x2301 /* 1.8 volt */
-+#define MAXI_TOK_AVID_25 0x2302 /* 2.5 volt */
-+#define MAXI_TOK_AVID_33 0x2303 /* 3.3 volt */
-+#define MAXI_TOK_AVID_5 0x2304 /* 5 volt */
-+#define MAXI_TOK_AVID_M5 0x2305 /* -5 volt */
-+#define MAXI_TOK_AVID_BAT 0x2306 /* battery voltage */
-+
-+/* Threshold tokens (0x3xxx) */
-+#define MAXI_TOK_MIN(token) ((token) + 0x1000)
-+#define MAXI_TOK_MAX(token) ((token) + 0x1800)
-+
-+/* LCD Panel (0x4xxx) */
-+#define MAXI_TOK_LCD(nr) (0x4000 + (nr))
-+#define MAXI_TOK_LCD_LINE1 0x4000
-+#define MAXI_TOK_LCD_LINE2 0x4001
-+#define MAXI_TOK_LCD_LINE3 0x4002
-+#define MAXI_TOK_LCD_LINE4 0x4003
-+
-+ /* 0xfe: fan off, 0xff: stopped (alarm) */
-+ /* or not available */
-+#define FAN99_FROM_REG(val) ((val)==0xfe ? 0 : (val)==0xff ? -1 : ((val)*39))
-+
-+ /* when no CPU2 temp is 127 (0x7f) */
-+#define TEMP99_FROM_REG(val) ((val)==0x7f ? -1 : (val)==0xff ? -1 : (val))
-+
-+#define VID99_FROM_REG(nr,val) ((val)==0xff ? 0 : \
-+ (nr)==1 ? ((val) * 608) : \
-+ (nr)==2 ? ((val) * 160) : \
-+ (nr)==3 ? ((val) * 160) : \
-+ (nr)==4 ? (val) /* no formula spcified */ : \
-+ (nr)==5 ? ((val) * 823 - 149140) : 0)
-+
-+
-+/* The following product codenames apply:
-+ Cristal/Geronimo: HP KAYAK XU/XAs
-+ (Dual Pentium II Slot 1, Deschutes/Klamath)
-+ Cognac: HP KAYAK XU (Dual Xeon [Slot 2] 400/450 Mhz)
-+ Ashaki: HP KAYAK XA (Pentium II Slot 1, monoprocessor)
-+ NBA: New BIOS Architecture, Kayak XU800, XM600, ... */
-+
-+enum maxi_type { cristal, cognac, ashaki, nba };
-+enum sensor_type { fan, temp, vid, pll, lcd, alarm };
-+
-+/* For each registered MaxiLife controller, we need to keep some data in
-+ memory. That data is pointed to by maxi_list[NR]->data. The structure
-+ itself is dynamically allocated, at the same time when a new MaxiLife
-+ client is allocated. We assume MaxiLife will only be present on the
-+ SMBus and not on the ISA bus. */
-+struct maxi_data {
-+ struct i2c_client client;
-+ struct semaphore lock;
-+ int sysctl_id;
-+ enum maxi_type type;
-+
-+ struct semaphore update_lock;
-+ char valid; /* !=0 if following fields are valid */
-+ unsigned long last_updated; /* In jiffies */
-+
-+ u8 fan[4]; /* Register value */
-+ u8 fan_min[4]; /* Register value */
-+ u8 fan_speed[4]; /* Register value */
-+ u8 fan_div[4]; /* Static value */
-+ u8 temp[6]; /* Register value */
-+ u8 temp_max[6]; /* Static value */
-+ u8 temp_hyst[6]; /* Static value */
-+ u8 pll; /* Register value */
-+ u8 pll_min; /* Register value */
-+ u8 pll_max; /* register value */
-+ u8 vid[5]; /* Register value */
-+ u8 vid_min[5]; /* Register value */
-+ u8 vid_max[5]; /* Register value */
-+ u8 lcd[4][17]; /* Four LCD lines */
-+ u16 alarms; /* Register encoding, combined */
-+};
-+
-+
-+static int maxi_attach_adapter(struct i2c_adapter *adapter);
-+static int maxi_detect(struct i2c_adapter *adapter, int address,
-+ unsigned short flags, int kind);
-+static int maxi_detach_client(struct i2c_client *client);
-+
-+static int maxi_read_value(struct i2c_client *client, u8 register);
-+static int maxi_read_token(struct i2c_client *client, u16 token);
-+#ifndef NOWRITE
-+static int maxi_write_value(struct i2c_client *client, u8 register,
-+ u8 value);
-+#endif
-+static int maxi_write_token_loop(struct i2c_client *client, u16 token,
-+ u8 len, u8 * values);
-+
-+static void maxi_update_client(struct i2c_client *client);
-+static void maxi99_update_client(struct i2c_client *client,
-+ enum sensor_type sensor, int which);
-+static void maxi_init_client(struct i2c_client *client);
-+
-+static void maxi_fan(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void maxi99_fan(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void maxi_temp(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void maxi99_temp(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void maxi_pll(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void maxi_vid(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void maxi99_vid(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void maxi_lcd(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void maxi_alarms(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+
-+/* The driver. I choose to use type i2c_driver, as at is identical to
-+ the smbus_driver. */
-+static struct i2c_driver maxi_driver = {
-+ .owner = THIS_MODULE,
-+ .name = "HP MaxiLife driver",
-+ .id = I2C_DRIVERID_MAXILIFE,
-+ .flags = I2C_DF_NOTIFY,
-+ .attach_adapter = maxi_attach_adapter,
-+ .detach_client = maxi_detach_client,
-+};
-+
-+static int maxi_id = 0;
-+
-+/* Default firmware version. Use module option "maxi_version"
-+ to set desired version. Auto detect is not yet working */
-+static int maxi_version = cristal;
-+
-+/* The /proc/sys entries */
-+
-+/* -- SENSORS SYSCTL START -- */
-+#define MAXI_SYSCTL_FAN1 1101 /* Rotations/min */
-+#define MAXI_SYSCTL_FAN2 1102 /* Rotations/min */
-+#define MAXI_SYSCTL_FAN3 1103 /* Rotations/min */
-+#define MAXI_SYSCTL_FAN4 1104 /* Rotations/min */
-+#define MAXI_SYSCTL_TEMP1 1201 /* Degrees Celcius */
-+#define MAXI_SYSCTL_TEMP2 1202 /* Degrees Celcius */
-+#define MAXI_SYSCTL_TEMP3 1203 /* Degrees Celcius */
-+#define MAXI_SYSCTL_TEMP4 1204 /* Degrees Celcius */
-+#define MAXI_SYSCTL_TEMP5 1205 /* Degrees Celcius */
-+#define MAXI_SYSCTL_TEMP6 1206 /* Degrees Celcius */
-+#define MAXI_SYSCTL_PLL 1301 /* MHz */
-+#define MAXI_SYSCTL_VID1 1401 /* Volts / 6.337, for nba just Volts */
-+#define MAXI_SYSCTL_VID2 1402 /* Volts */
-+#define MAXI_SYSCTL_VID3 1403 /* Volts */
-+#define MAXI_SYSCTL_VID4 1404 /* Volts */
-+#define MAXI_SYSCTL_VID5 1405 /* Volts */
-+#define MAXI_SYSCTL_LCD1 1501 /* Line 1 of LCD */
-+#define MAXI_SYSCTL_LCD2 1502 /* Line 2 of LCD */
-+#define MAXI_SYSCTL_LCD3 1503 /* Line 3 of LCD */
-+#define MAXI_SYSCTL_LCD4 1504 /* Line 4 of LCD */
-+#define MAXI_SYSCTL_ALARMS 2001 /* Bitvector (see below) */
-+
-+#define MAXI_ALARM_VID4 0x0001
-+#define MAXI_ALARM_TEMP2 0x0002
-+#define MAXI_ALARM_VID1 0x0004
-+#define MAXI_ALARM_VID2 0x0008
-+#define MAXI_ALARM_VID3 0x0010
-+#define MAXI_ALARM_PLL 0x0080
-+#define MAXI_ALARM_TEMP4 0x0100
-+#define MAXI_ALARM_TEMP5 0x0200
-+#define MAXI_ALARM_FAN1 0x1000
-+#define MAXI_ALARM_FAN2 0x2000
-+#define MAXI_ALARM_FAN3 0x4000
-+
-+#define MAXI_ALARM_FAN 0x0100 /* To be used with MaxiLife'99 */
-+#define MAXI_ALARM_VID 0x0200 /* The MSB specifies which sensor */
-+#define MAXI_ALARM_TEMP 0x0400 /* in the alarm group failed, i.e.: */
-+#define MAXI_ALARM_VADD 0x0800 /* 0x0402 = TEMP2 failed = CPU2 temp */
-+
-+/* -- SENSORS SYSCTL END -- */
-+
-+/* These files are created for each detected MaxiLife processor.
-+ This is just a template; though at first sight, you might think we
-+ could use a statically allocated list, we need some way to get back
-+ to the parent - which is done through one of the 'extra' fields
-+ which are initialized when a new copy is allocated. */
-+static ctl_table maxi_dir_table_template[] = {
-+ {MAXI_SYSCTL_FAN1, "fan1", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &maxi_fan},
-+ {MAXI_SYSCTL_FAN2, "fan2", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &maxi_fan},
-+ {MAXI_SYSCTL_FAN3, "fan3", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &maxi_fan},
-+ {MAXI_SYSCTL_FAN4, "fan4", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &maxi_fan},
-+ {MAXI_SYSCTL_TEMP1, "temp1", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &maxi_temp},
-+ {MAXI_SYSCTL_TEMP2, "temp2", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &maxi_temp},
-+ {MAXI_SYSCTL_TEMP3, "temp3", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &maxi_temp},
-+ {MAXI_SYSCTL_TEMP4, "temp4", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &maxi_temp},
-+ {MAXI_SYSCTL_TEMP5, "temp5", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &maxi_temp},
-+ {MAXI_SYSCTL_TEMP6, "temp6", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &maxi_temp},
-+ {MAXI_SYSCTL_PLL, "pll", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &maxi_pll},
-+ {MAXI_SYSCTL_VID1, "vid1", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &maxi_vid},
-+ {MAXI_SYSCTL_VID2, "vid2", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &maxi_vid},
-+ {MAXI_SYSCTL_VID3, "vid3", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &maxi_vid},
-+ {MAXI_SYSCTL_VID4, "vid4", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &maxi_vid},
-+ {MAXI_SYSCTL_VID5, "vid5", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &maxi_vid},
-+ {MAXI_SYSCTL_LCD1, "lcd1", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &maxi_lcd},
-+ {MAXI_SYSCTL_LCD2, "lcd2", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &maxi_lcd},
-+ {MAXI_SYSCTL_LCD3, "lcd3", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &maxi_lcd},
-+ {MAXI_SYSCTL_LCD4, "lcd4", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &maxi_lcd},
-+ {MAXI_SYSCTL_ALARMS, "alarms", NULL, 0, 0444, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &maxi_alarms},
-+ {0}
-+};
-+
-+/* This function is called when:
-+ - maxi_driver is inserted (when this module is loaded), for each
-+ available adapter
-+ - when a new adapter is inserted (and maxi_driver is still present) */
-+static int maxi_attach_adapter(struct i2c_adapter *adapter)
-+{
-+ return i2c_detect(adapter, &addr_data, maxi_detect);
-+}
-+
-+/* This function is called by i2c_detect */
-+int maxi_detect(struct i2c_adapter *adapter, int address,
-+ unsigned short flags, int kind)
-+{
-+ struct i2c_client *new_client;
-+ struct maxi_data *data;
-+ enum maxi_type type = 0;
-+ int i, j, err = 0;
-+ const char *type_name = NULL, *client_name = NULL;
-+
-+ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
-+ goto ERROR0;
-+
-+ /* OK. For now, we presume we have a valid client. We now create the
-+ client structure, even though we cannot fill it completely yet.
-+ But it allows us to access maxi_{read,write}_value. */
-+ if (!(data = kmalloc(sizeof(struct maxi_data), GFP_KERNEL))) {
-+ err = -ENOMEM;
-+ goto ERROR0;
-+ }
-+
-+ /* Fill the new client structure with data */
-+ new_client = &data->client;
-+ new_client->addr = address;
-+ new_client->data = data;
-+ new_client->adapter = adapter;
-+ new_client->driver = &maxi_driver;
-+ new_client->flags = 0;
-+
-+ /* Now we do the remaining detection. */
-+ if (kind < 0) {
-+ if (i2c_smbus_read_byte_data
-+ (new_client, MAXI_REG_MBX_STATUS) < 0)
-+ goto ERROR2;
-+ }
-+
-+ /* Determine the chip type - only one kind supported */
-+ if (kind <= 0)
-+ kind = maxilife;
-+
-+ if (kind == maxilife) {
-+ /* Detect if the machine has a MaxiLife NBA controller.
-+ The right way to perform this check is to do a read/modify/write
-+ on register MbxStatus (5A):
-+ - Read 5A (value 0 for non-NBA firmware, FF (MbxIdle on NBA-firmware)
-+ - Write 55 on 5A, then read back 5A
-+ Non-NBA firmware: value is 55 (reg 5A is a standard writable reg)
-+ NBA firmaware: value is FF (write-protect on MbxStatus active) */
-+ int stat;
-+ i2c_smbus_write_byte_data(new_client, MAXI_REG_MBX_STATUS,
-+ 0x55);
-+ stat =
-+ i2c_smbus_read_byte_data(new_client,
-+ MAXI_REG_MBX_STATUS);
-+
-+ /*if (stat == MAXI_STAT_IDLE || stat == MAXI_STAT_OK) */
-+ if (stat != 0x55)
-+ maxi_version = nba;
-+#ifdef AUTODETECT
-+ else {
-+ /* The right way to get the platform info is to read the firmware
-+ revision from serial EEPROM (addr=0x54), at offset 0x0045.
-+ This is a string as:
-+ "CG 00.04" -> Cristal [XU] / Geronimo [XAs]
-+ "CO 00.03" -> Cognac [XU]
-+ "AS 00.01" -> Ashaki [XA] */
-+#if 0
-+ int biosctl;
-+ biosctl =
-+ i2c_smbus_read_byte_data(new_client,
-+ MAXI_REG_BIOS_CTRL);
-+ i2c_smbus_write_byte_data(new_client,
-+ MAXI_REG_BIOS_CTRL,
-+ biosctl | 4);
-+ err = eeprom_read_byte_data(adapter, 0x54, 0x45);
-+ i2c_smbus_write_byte_data(new_client,
-+ MAXI_REG_BIOS_CTRL,
-+ biosctl);
-+#endif
-+ int i;
-+ char *biosmem, *bm;
-+ bm = biosmem = ioremap(0xe0000, 0x20000);
-+ if (biosmem) {
-+ printk("begin of bios search\n");
-+ for (i = 0; i < 0x20000; i++) {
-+ if (*bm == 'C') {
-+ char *s = bm;
-+ while (s && isprint(*s)) {
-+ printk("%c", *s);
-+ s++;
-+ }
-+ printk("\n");
-+ if (!strncmp
-+ (bm, "CG 00.04", 8)) {
-+ maxi_version =
-+ cristal;
-+ printk
-+ ("maxilife: found MaxiLife Rev CG 00.04\n");
-+ break;
-+ }
-+ if (!strncmp
-+ (bm, "CO 00.03", 8)) {
-+ maxi_version =
-+ cognac;
-+ printk
-+ ("maxilife: found MaxiLife Rev CO 00.03\n");
-+ break;
-+ }
-+ }
-+ if (*bm == 'A' && *(bm + 1) == 'S') {
-+ char *s = bm;
-+ while (s && isprint(*s)) {
-+ printk("%c", *s);
-+ s++;
-+ }
-+ printk("\n");
-+ if (!strncmp
-+ (bm, "AS 00.01", 8)) {
-+ maxi_version =
-+ ashaki;
-+ printk
-+ ("maxilife: found MaxiLife Rev AS 00.01\n");
-+ break;
-+ }
-+ }
-+ bm++;
-+ }
-+ printk("end of bios search\n");
-+ } else
-+ printk("could not map bios memory\n");
-+ }
-+#endif
-+
-+ if (maxi_version == cristal) {
-+ type = cristal;
-+ type_name = "maxilife-cg";
-+ client_name = "HP MaxiLife Rev CG 00.04";
-+ printk
-+ ("maxilife: HP KAYAK XU/XAs (Dual Pentium II Slot 1)\n");
-+ } else if (maxi_version == cognac) {
-+ type = cognac;
-+ type_name = "maxilife-co";
-+ client_name = "HP MaxiLife Rev CO 00.03";
-+ printk
-+ ("maxilife: HP KAYAK XU (Dual Xeon Slot 2 400/450 Mhz)\n");
-+ } else if (maxi_version == ashaki) {
-+ type = ashaki;
-+ type_name = "maxilife-as";
-+ client_name = "HP MaxiLife Rev AS 00.01";
-+ printk
-+ ("maxilife: HP KAYAK XA (Pentium II Slot 1, monoprocessor)\n");
-+ } else if (maxi_version == nba) {
-+ type = nba;
-+ type_name = "maxilife-nba";
-+ client_name = "HP MaxiLife NBA";
-+ printk("maxilife: HP KAYAK XU800/XM600\n");
-+ } else {
-+#ifdef AUTODETECT
-+ printk
-+ ("maxilife: Warning: probed non-maxilife chip?!? (%x)\n",
-+ err);
-+#else
-+ printk
-+ ("maxilife: Error: specified wrong maxi_version (%d)\n",
-+ maxi_version);
-+#endif
-+ goto ERROR2;
-+ }
-+ }
-+
-+ /* Fill in the remaining client fields and put it into the global list */
-+ strcpy(new_client->name, client_name);
-+ ((struct maxi_data *) (new_client->data))->type = type;
-+
-+ for (i = 0; i < 4; i++)
-+ for (j = 0; j < 17; j++)
-+ ((struct maxi_data *) (new_client->data))->
-+ lcd[i][j] = (u8) 0;
-+
-+ new_client->id = maxi_id++;
-+
-+ data->valid = 0;
-+ init_MUTEX(&data->lock);
-+ init_MUTEX(&data->update_lock);
-+
-+ /* Tell i2c-core that a new client has arrived */
-+ if ((err = i2c_attach_client(new_client)))
-+ goto ERROR2;
-+
-+ /* Register a new directory entry with module sensors */
-+ if ((err = i2c_register_entry(new_client, type_name,
-+ maxi_dir_table_template)) < 0)
-+ goto ERROR4;
-+ data->sysctl_id = err;
-+
-+ /* Initialize the MaxiLife chip */
-+ maxi_init_client(new_client);
-+ return 0;
-+
-+ /* OK, this is not exactly good programming practice, usually.
-+ But it is very code-efficient in this case. */
-+ ERROR4:
-+ i2c_detach_client(new_client);
-+ ERROR2:
-+ kfree(data);
-+ ERROR0:
-+ return err;
-+}
-+
-+/* This function is called whenever a client should be removed:
-+ - maxi_driver is removed (when this module is unloaded)
-+ - when an adapter is removed which has a maxi client (and maxi_driver
-+ is still present). */
-+static int maxi_detach_client(struct i2c_client *client)
-+{
-+ int err;
-+
-+ i2c_deregister_entry(((struct maxi_data *) (client->data))->
-+ sysctl_id);
-+
-+ if ((err = i2c_detach_client(client))) {
-+ printk
-+ ("maxilife: Client deregistration failed, client not detached.\n");
-+ return err;
-+ }
-+ kfree(client->data);
-+ return 0;
-+}
-+
-+/* Read byte from specified register (-1 in case of error, value otherwise). */
-+static int maxi_read_value(struct i2c_client *client, u8 reg)
-+{
-+ return i2c_smbus_read_byte_data(client, reg);
-+}
-+
-+/* Read the byte value for a MaxiLife token (-1 in case of error, value otherwise */
-+static int maxi_read_token(struct i2c_client *client, u16 token)
-+{
-+ u8 lowToken, highToken;
-+ int error, value;
-+
-+ lowToken = LOW(token);
-+ highToken = HIGH(token);
-+
-+ /* Set mailbox status register to idle state. */
-+ error =
-+ i2c_smbus_write_byte_data(client, MAXI_REG_MBX_STATUS,
-+ MAXI_STAT_IDLE);
-+ if (error < 0)
-+ return error;
-+
-+ /* Check for mailbox idle state. */
-+ error = i2c_smbus_read_byte_data(client, MAXI_REG_MBX_STATUS);
-+ if (error != MAXI_STAT_IDLE)
-+ return -1;
-+
-+ /* Write the most significant byte of the token we want to read. */
-+ error =
-+ i2c_smbus_write_byte_data(client, MAXI_REG_MBX_TOKEN_H,
-+ highToken);
-+ if (error < 0)
-+ return error;
-+
-+ /* Write the least significant byte of the token we want to read. */
-+ error =
-+ i2c_smbus_write_byte_data(client, MAXI_REG_MBX_TOKEN_L,
-+ lowToken);
-+ if (error < 0)
-+ return error;
-+
-+ /* Write the read token opcode to the mailbox. */
-+ error =
-+ i2c_smbus_write_byte_data(client, MAXI_REG_MBX_CMD,
-+ MAXI_CMD_READ);
-+ if (error < 0)
-+ return error;
-+
-+ /* Check for transaction completion */
-+ do {
-+ error =
-+ i2c_smbus_read_byte_data(client, MAXI_REG_MBX_STATUS);
-+ } while (error == MAXI_STAT_BUSY);
-+ if (error != MAXI_STAT_OK)
-+ return -1;
-+
-+ /* Read the value of the token. */
-+ value = i2c_smbus_read_byte_data(client, MAXI_REG_MBX_DATA);
-+ if (value == -1)
-+ return -1;
-+
-+ /* set mailbox status to idle to complete transaction. */
-+ error =
-+ i2c_smbus_write_byte_data(client, MAXI_REG_MBX_STATUS,
-+ MAXI_STAT_IDLE);
-+ if (error < 0)
-+ return error;
-+
-+ return value;
-+}
-+
-+#ifndef NOWRITE
-+/* Write byte to specified register (-1 in case of error, 0 otherwise). */
-+static int maxi_write_value(struct i2c_client *client, u8 reg, u8 value)
-+{
-+ return i2c_smbus_write_byte_data(client, reg, value);
-+}
-+#endif
-+
-+/* Write a set of len byte values to MaxiLife token (-1 in case of error, 0 otherwise). */
-+int maxi_write_token_loop(struct i2c_client *client, u16 token, u8 len,
-+ u8 * values)
-+{
-+ u8 lowToken, highToken, bCounter;
-+ int error;
-+
-+ lowToken = LOW(token);
-+ highToken = HIGH(token);
-+
-+ /* Set mailbox status register to idle state. */
-+ error =
-+ i2c_smbus_write_byte_data(client, MAXI_REG_MBX_STATUS,
-+ MAXI_STAT_IDLE);
-+ if (error < 0)
-+ return error;
-+
-+ /* Check for mailbox idle state. */
-+ error = i2c_smbus_read_byte_data(client, MAXI_REG_MBX_STATUS);
-+ if (error != MAXI_STAT_IDLE)
-+ return -1;
-+
-+ for (bCounter = 0; (bCounter < len && bCounter < 32); bCounter++) {
-+ error =
-+ i2c_smbus_write_byte_data(client,
-+ (u8) (MAXI_REG_MBX_DATA +
-+ bCounter),
-+ values[bCounter]);
-+ if (error < 0)
-+ return error;
-+ }
-+
-+ /* Write the most significant byte of the token we want to read. */
-+ error =
-+ i2c_smbus_write_byte_data(client, MAXI_REG_MBX_TOKEN_H,
-+ highToken);
-+ if (error < 0)
-+ return error;
-+
-+ /* Write the least significant byte of the token we want to read. */
-+ error =
-+ i2c_smbus_write_byte_data(client, MAXI_REG_MBX_TOKEN_L,
-+ lowToken);
-+ if (error < 0)
-+ return error;
-+
-+ /* Write the write token opcode to the mailbox. */
-+ error =
-+ i2c_smbus_write_byte_data(client, MAXI_REG_MBX_CMD,
-+ MAXI_CMD_WRITE);
-+ if (error < 0)
-+ return error;
-+
-+ /* Check for transaction completion */
-+ do {
-+ error =
-+ i2c_smbus_read_byte_data(client, MAXI_REG_MBX_STATUS);
-+ } while (error == MAXI_STAT_BUSY);
-+ if (error != MAXI_STAT_OK)
-+ return -1;
-+
-+ /* set mailbox status to idle to complete transaction. */
-+ return i2c_smbus_write_byte_data(client, MAXI_REG_MBX_STATUS,
-+ MAXI_STAT_IDLE);
-+}
-+
-+/* Called when we have found a new MaxiLife. It should set limits, etc. */
-+static void maxi_init_client(struct i2c_client *client)
-+{
-+ struct maxi_data *data = client->data;
-+
-+ if (data->type == nba) {
-+ strcpy(data->lcd[2], " Linux MaxiLife");
-+ maxi_write_token_loop(client, MAXI_TOK_LCD(2),
-+ strlen(data->lcd[2]) + 1,
-+ data->lcd[2]);
-+ }
-+}
-+
-+static void maxi_update_client(struct i2c_client *client)
-+{
-+ struct maxi_data *data = client->data;
-+ int i;
-+
-+ if (data->type == nba) {
-+ printk
-+ ("maxi_update_client should never be called by nba\n");
-+ return;
-+ }
-+
-+ down(&data->update_lock);
-+
-+ if ((jiffies - data->last_updated > HZ + HZ / 2) ||
-+ (jiffies < data->last_updated) || !data->valid) {
-+
-+#ifdef DEBUG
-+ printk("maxilife: Starting MaxiLife update\n");
-+#endif
-+ for (i = 0; i < 5; i++)
-+ data->temp[i] =
-+ maxi_read_value(client, MAXI_REG_TEMP(i));
-+ switch (data->type) {
-+ case cristal:
-+ data->temp[0] = 0; /* not valid */
-+ data->temp_max[0] = 0;
-+ data->temp_hyst[0] = 0;
-+ data->temp_max[1] = 110; /* max PCI slot temp */
-+ data->temp_hyst[1] = 100;
-+ data->temp_max[2] = 120; /* max BX chipset temp */
-+ data->temp_hyst[2] = 110;
-+ data->temp_max[3] = 100; /* max HDD temp */
-+ data->temp_hyst[3] = 90;
-+ data->temp_max[4] = 120; /* max CPU temp */
-+ data->temp_hyst[4] = 110;
-+ break;
-+
-+ case cognac:
-+ data->temp_max[0] = 120; /* max CPU1 temp */
-+ data->temp_hyst[0] = 110;
-+ data->temp_max[1] = 110; /* max PCI slot temp */
-+ data->temp_hyst[1] = 100;
-+ data->temp_max[2] = 120; /* max CPU2 temp */
-+ data->temp_hyst[2] = 110;
-+ data->temp_max[3] = 100; /* max HDD temp */
-+ data->temp_hyst[3] = 90;
-+ data->temp_max[4] = 120; /* max reference CPU temp */
-+ data->temp_hyst[4] = 110;
-+ break;
-+
-+ case ashaki:
-+ data->temp[0] = 0; /* not valid */
-+ data->temp_max[0] = 0;
-+ data->temp_hyst[0] = 0;
-+ data->temp_max[1] = 110; /* max PCI slot temp */
-+ data->temp_hyst[1] = 100;
-+ data->temp[2] = 0; /* not valid */
-+ data->temp_max[2] = 0;
-+ data->temp_hyst[2] = 0;
-+ data->temp_max[3] = 100; /* max HDD temp */
-+ data->temp_hyst[3] = 90;
-+ data->temp_max[4] = 120; /* max CPU temp */
-+ data->temp_hyst[4] = 110;
-+ break;
-+
-+ default:
-+ printk("maxilife: Unknown MaxiLife chip\n");
-+ }
-+ data->temp[5] = 0; /* only used by MaxiLife'99 */
-+ data->temp_max[5] = 0;
-+ data->temp_hyst[5] = 0;
-+
-+ for (i = 0; i < 3; i++) {
-+ data->fan[i] =
-+ maxi_read_value(client, MAXI_REG_FAN(i));
-+ data->fan_speed[i] =
-+ maxi_read_value(client, MAXI_REG_FAN_SPEED(i));
-+ data->fan_div[i] = 4;
-+ if (data->type == ashaki)
-+ data->fan_min[i] =
-+ maxi_read_value(client,
-+ MAXI_REG_FAN_MINAS(i));
-+ else
-+ data->fan_min[i] =
-+ maxi_read_value(client,
-+ MAXI_REG_FAN_MIN(i));
-+ }
-+ data->fan[3] = 0xff; /* only used by MaxiLife'99 */
-+ data->fan_speed[3] = 0;
-+ data->fan_div[3] = 4; /* avoid possible /0 */
-+ data->fan_min[3] = 0;
-+
-+ data->pll = maxi_read_value(client, MAXI_REG_PLL);
-+ data->pll_min = maxi_read_value(client, MAXI_REG_PLL_MIN);
-+ data->pll_max = maxi_read_value(client, MAXI_REG_PLL_MAX);
-+
-+ for (i = 0; i < 4; i++) {
-+ data->vid[i] =
-+ maxi_read_value(client, MAXI_REG_VID(i));
-+ data->vid_min[i] =
-+ maxi_read_value(client, MAXI_REG_VID_MIN(i));
-+ data->vid_max[i] =
-+ maxi_read_value(client, MAXI_REG_VID_MAX(i));
-+ }
-+ switch (data->type) {
-+ case cristal:
-+ data->vid[3] = 0; /* no voltage cache L2 */
-+ data->vid_min[3] = 0;
-+ data->vid_max[3] = 0;
-+ break;
-+
-+ case cognac:
-+ break;
-+
-+ case ashaki:
-+ data->vid[1] = 0; /* no voltage CPU 2 */
-+ data->vid_min[1] = 0;
-+ data->vid_max[1] = 0;
-+ data->vid[3] = 0; /* no voltage cache L2 */
-+ data->vid_min[3] = 0;
-+ data->vid_max[3] = 0;
-+ break;
-+
-+ default:
-+ printk("maxilife: Unknown MaxiLife chip\n");
-+ }
-+ data->vid[4] = 0; /* only used by MaxliLife'99 */
-+ data->vid_min[4] = 0;
-+ data->vid_max[4] = 0;
-+
-+ data->alarms = maxi_read_value(client, MAXI_REG_DIAG_RT1) +
-+ (maxi_read_value(client, MAXI_REG_DIAG_RT2) << 8);
-+
-+ data->last_updated = jiffies;
-+ data->valid = 1;
-+ }
-+
-+ up(&data->update_lock);
-+}
-+
-+void maxi99_update_client(struct i2c_client *client,
-+ enum sensor_type sensor, int which)
-+{
-+ static unsigned long last_updated[6][6]; /* sensor, which */
-+ struct maxi_data *data = client->data;
-+
-+ down(&data->update_lock);
-+
-+ /*maxi_write_token_loop(client, MAXI_TOK_LCD_LINE3, 13, "Linux 2.2.13"); */
-+
-+ if ((jiffies - last_updated[sensor][which] > 2 * HZ) ||
-+ (jiffies < last_updated[sensor][which]
-+ || !last_updated[sensor][which])) {
-+
-+ int tmp, i;
-+
-+ switch (sensor) {
-+ case fan:
-+ for (i = 0; i < 4; i++) {
-+ if (i == which) {
-+ tmp =
-+ maxi_read_token(client,
-+ MAXI_TOK_FAN
-+ (i));
-+ data->fan[i] =
-+ maxi_read_token(client,
-+ MAXI_TOK_FAN
-+ (i));
-+ data->fan_speed[i] =
-+ maxi_read_token(client,
-+ MAXI_TOK_MAX
-+ (MAXI_TOK_FAN
-+ (i)));
-+ data->fan_div[i] = 1;
-+ data->fan_min[i] = 0;
-+ }
-+ }
-+ break;
-+
-+ case temp:
-+ for (i = 0; i < 6; i++) {
-+ if (i == which) {
-+ data->temp[i] =
-+ maxi_read_token(client,
-+ MAXI_TOK_TEMP
-+ (i));
-+ data->temp_max[i] =
-+ maxi_read_token(client,
-+ MAXI_TOK_MAX
-+ (MAXI_TOK_TEMP
-+ (i)));
-+ data->temp_hyst[i] =
-+ data->temp_max[i] - 5;
-+ }
-+ }
-+ break;
-+
-+ case vid:
-+ for (i = 0; i < 5; i++) {
-+ if (i == which) {
-+ data->vid[i] =
-+ maxi_read_token(client,
-+ MAXI_TOK_VID
-+ (i));
-+ data->vid_min[i] =
-+ maxi_read_token(client,
-+ MAXI_TOK_MIN
-+ (MAXI_TOK_VID
-+ (i)));
-+ data->vid_max[i] =
-+ maxi_read_token(client,
-+ MAXI_TOK_MAX
-+ (MAXI_TOK_VID
-+ (i)));
-+ }
-+ }
-+ break;
-+
-+ case pll:
-+ data->pll = 0;
-+ data->pll_min = 0;
-+ data->pll_max = 0;
-+ break;
-+
-+ case alarm:
-+ data->alarms =
-+ (maxi_read_token(client, MAXI_TOK_ALARM_EVENT)
-+ << 8);
-+ if (data->alarms)
-+ data->alarms +=
-+ data->alarms ==
-+ (1 << 8) ? maxi_read_token(client,
-+ MAXI_TOK_ALARM_FAN)
-+ : data->alarms ==
-+ (2 << 8) ? maxi_read_token(client,
-+ MAXI_TOK_ALARM_VID)
-+ : data->alarms ==
-+ (4 << 8) ? maxi_read_token(client,
-+ MAXI_TOK_ALARM_TEMP)
-+ : data->alarms ==
-+ (8 << 8) ? maxi_read_token(client,
-+ MAXI_TOK_ALARM_FAN)
-+ : 0;
-+ break;
-+
-+ default:
-+ printk("maxilife: Unknown sensor type\n");
-+ }
-+
-+ last_updated[sensor][which] = jiffies;
-+ data->valid = 1;
-+ }
-+
-+ up(&data->update_lock);
-+}
-+
-+/* The next few functions are the call-back functions of the /proc/sys and
-+ sysctl files. Which function is used is defined in the ctl_table in
-+ the extra1 field.
-+ Each function must return the magnitude (power of 10 to divide the data
-+ with) if it is called with operation==SENSORS_PROC_REAL_INFO. It must
-+ put a maximum of *nrels elements in results reflecting the data of this
-+ file, and set *nrels to the number it actually put in it, if operation==
-+ SENSORS_PROC_REAL_READ. Finally, it must get upto *nrels elements from
-+ results and write them to the chip, if operations==SENSORS_PROC_REAL_WRITE.
-+ Note that on SENSORS_PROC_REAL_READ, I do not check whether results is
-+ large enough (by checking the incoming value of *nrels). This is not very
-+ good practice, but as long as you put less than about 5 values in results,
-+ you can assume it is large enough. */
-+void maxi_fan(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct maxi_data *data = client->data;
-+ int nr;
-+
-+ if (data->type == nba) {
-+ maxi99_fan(client, operation, ctl_name, nrels_mag,
-+ results);
-+ return;
-+ }
-+
-+ nr = ctl_name - MAXI_SYSCTL_FAN1 + 1;
-+
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 0;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ maxi_update_client(client);
-+ results[0] = FAN_FROM_REG(data->fan_min[nr - 1]);
-+ results[1] = data->fan_div[nr - 1];
-+ results[2] = FAN_FROM_REG(data->fan[nr - 1]);
-+ *nrels_mag = 3;
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+#ifndef NOWRITE
-+ if (*nrels_mag >= 1) {
-+ data->fan_min[nr - 1] = FAN_TO_REG(results[0]);
-+ maxi_write_value(client, MAXI_REG_FAN_MIN(nr),
-+ data->fan_min[nr - 1]);
-+ }
-+#endif
-+ }
-+}
-+
-+void maxi99_fan(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct maxi_data *data = client->data;
-+ int nr;
-+
-+ nr = ctl_name - MAXI_SYSCTL_FAN1 + 1;
-+
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 0;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ maxi99_update_client(client, fan, nr - 1);
-+ results[0] = FAN99_FROM_REG(data->fan_min[nr - 1]); /* min rpm */
-+ results[1] = data->fan_div[nr - 1]; /* divisor */
-+ results[2] = FAN99_FROM_REG(data->fan[nr - 1]); /* rpm */
-+ *nrels_mag = 3;
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+#ifndef NOWRITE
-+ /* still to do */
-+ if (*nrels_mag >= 1) {
-+ data->fan_min[nr - 1] = FAN_TO_REG(results[0]);
-+ maxi_write_value(client, MAXI_REG_FAN_MIN(nr),
-+ data->fan_min[nr - 1]);
-+ }
-+#endif
-+ }
-+}
-+
-+void maxi_temp(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct maxi_data *data = client->data;
-+ int nr;
-+
-+ if (data->type == nba) {
-+ maxi99_temp(client, operation, ctl_name, nrels_mag,
-+ results);
-+ return;
-+ }
-+
-+ nr = ctl_name - MAXI_SYSCTL_TEMP1 + 1;
-+
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 1;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ maxi_update_client(client);
-+ results[0] = TEMP_FROM_REG(data->temp_max[nr - 1]);
-+ results[1] = TEMP_FROM_REG(data->temp_hyst[nr - 1]);
-+ results[2] = TEMP_FROM_REG(data->temp[nr - 1]);
-+ *nrels_mag = 3;
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ /* temperature range can not be changed */
-+ }
-+}
-+
-+void maxi99_temp(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct maxi_data *data = client->data;
-+ int nr;
-+
-+ nr = ctl_name - MAXI_SYSCTL_TEMP1 + 1;
-+
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 0;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ maxi99_update_client(client, temp, nr - 1);
-+ results[0] = TEMP99_FROM_REG(data->temp_max[nr - 1]);
-+ results[1] = TEMP99_FROM_REG(data->temp_hyst[nr - 1]);
-+ results[2] = TEMP99_FROM_REG(data->temp[nr - 1]);
-+ *nrels_mag = 3;
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ /* temperature range can not be changed */
-+ }
-+}
-+
-+void maxi_pll(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct maxi_data *data = client->data;
-+
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 2;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ if (data->type == nba)
-+ maxi99_update_client(client, pll, 0);
-+ else
-+ maxi_update_client(client);
-+ results[0] = PLL_FROM_REG(data->pll_min);
-+ results[1] = PLL_FROM_REG(data->pll_max);
-+ results[2] = PLL_FROM_REG(data->pll);
-+ *nrels_mag = 3;
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+#ifndef NOWRITE
-+ if (*nrels_mag >= 1) {
-+ data->pll_min = PLL_TO_REG(results[0]);
-+ maxi_write_value(client, MAXI_REG_PLL_MIN,
-+ data->pll_min);
-+ }
-+ if (*nrels_mag >= 2) {
-+ data->pll_max = PLL_TO_REG(results[1]);
-+ maxi_write_value(client, MAXI_REG_PLL_MAX,
-+ data->pll_max);
-+ }
-+#endif
-+ }
-+}
-+
-+void maxi_vid(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct maxi_data *data = client->data;
-+ int nr;
-+
-+ if (data->type == nba) {
-+ maxi99_vid(client, operation, ctl_name, nrels_mag,
-+ results);
-+ return;
-+ }
-+
-+ nr = ctl_name - MAXI_SYSCTL_VID1 + 1;
-+
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 4;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ maxi_update_client(client);
-+ results[0] = VID_FROM_REG(data->vid_min[nr - 1]);
-+ results[1] = VID_FROM_REG(data->vid_max[nr - 1]);
-+ results[2] = VID_FROM_REG(data->vid[nr - 1]);
-+ *nrels_mag = 3;
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+#ifndef NOWRITE
-+ if (*nrels_mag >= 1) {
-+ data->vid_min[nr - 1] = VID_TO_REG(results[0]);
-+ maxi_write_value(client, MAXI_REG_VID_MIN(nr),
-+ data->vid_min[nr - 1]);
-+ }
-+ if (*nrels_mag >= 2) {
-+ data->vid_max[nr - 1] = VID_TO_REG(results[1]);
-+ maxi_write_value(client, MAXI_REG_VID_MAX(nr),
-+ data->vid_max[nr - 1]);
-+ }
-+#endif
-+ }
-+}
-+
-+void maxi99_vid(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct maxi_data *data = client->data;
-+ int nr = ctl_name - MAXI_SYSCTL_VID1 + 1;
-+
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 4;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ maxi99_update_client(client, vid, nr - 1);
-+ results[0] = VID99_FROM_REG(nr, data->vid_min[nr - 1]);
-+ results[1] = VID99_FROM_REG(nr, data->vid_max[nr - 1]);
-+ results[2] = VID99_FROM_REG(nr, data->vid[nr - 1]);
-+ *nrels_mag = 3;
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+#ifndef NOWRITE
-+ /* still to do */
-+ if (*nrels_mag >= 1) {
-+ data->vid_min[nr - 1] = VID_TO_REG(results[0]);
-+ maxi_write_value(client, MAXI_REG_VID_MIN(nr),
-+ data->vid_min[nr - 1]);
-+ }
-+ if (*nrels_mag >= 2) {
-+ data->vid_max[nr - 1] = VID_TO_REG(results[1]);
-+ maxi_write_value(client, MAXI_REG_VID_MAX(nr),
-+ data->vid_max[nr - 1]);
-+ }
-+#endif
-+ }
-+}
-+
-+void maxi_lcd(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ /* Allows writing and reading from LCD display */
-+
-+ struct maxi_data *data = client->data;
-+ int nr;
-+
-+ if (data->type != nba)
-+ return;
-+
-+ nr = ctl_name - MAXI_SYSCTL_LCD1 + 1;
-+
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 0;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ results[0] = *((long *) &data->lcd[nr - 1][0]);
-+ results[1] = *((long *) &data->lcd[nr - 1][4]);
-+ results[2] = *((long *) &data->lcd[nr - 1][8]);
-+ results[3] = *((long *) &data->lcd[nr - 1][12]);
-+ *nrels_mag = 4;
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ /*
-+ Writing a string to line 3 of the LCD can be done like:
-+ echo -n "Linux MaxiLife" | od -A n -l > \
-+ /proc/sys/dev/sensors/maxilife-nba-i2c-0-14/lcd3
-+ */
-+ if (*nrels_mag >= 1)
-+ *((long *) &data->lcd[nr - 1][0]) = results[0];
-+ if (*nrels_mag >= 2)
-+ *((long *) &data->lcd[nr - 1][4]) = results[1];
-+ if (*nrels_mag >= 3)
-+ *((long *) &data->lcd[nr - 1][8]) = results[2];
-+ if (*nrels_mag >= 4)
-+ *((long *) &data->lcd[nr - 1][12]) = results[3];
-+ maxi_write_token_loop(client, MAXI_TOK_LCD(nr - 1),
-+ strlen(data->lcd[nr - 1]) + 1,
-+ data->lcd[nr - 1]);
-+#if 0
-+ if (*nrels_mag >= 1)
-+ printk("nr=%d, result[0] = %.4s\n", nr,
-+ (char *) &results[0]);
-+ if (*nrels_mag >= 2)
-+ printk("nr=%d, result[1] = %.4s\n", nr,
-+ (char *) &results[1]);
-+ if (*nrels_mag >= 3)
-+ printk("nr=%d, result[2] = %.4s\n", nr,
-+ (char *) &results[2]);
-+ if (*nrels_mag >= 4)
-+ printk("nr=%d, result[3] = %.4s\n", nr,
-+ (char *) &results[3]);
-+#endif
-+ }
-+
-+}
-+
-+void maxi_alarms(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct maxi_data *data = client->data;
-+
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 0;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ if (data->type == nba)
-+ maxi99_update_client(client, alarm, 0);
-+ else
-+ maxi_update_client(client);
-+ results[0] = ALARMS_FROM_REG(data->alarms);
-+ *nrels_mag = 1;
-+ }
-+}
-+
-+static int __init sm_maxilife_init(void)
-+{
-+ printk("maxilife: Version %s (lm_sensors %s (%s))\n", version_str,
-+ LM_VERSION, LM_DATE);
-+ return i2c_add_driver(&maxi_driver);
-+}
-+
-+static void __exit sm_maxilife_exit(void)
-+{
-+ i2c_del_driver(&maxi_driver);
-+}
-+
-+
-+
-+MODULE_AUTHOR("Fons Rademakers <Fons.Rademakers@cern.ch>");
-+MODULE_DESCRIPTION("HP MaxiLife driver");
-+MODULE_PARM(maxi_version, "i");
-+MODULE_PARM_DESC(maxi_version, "MaxiLife firmware version");
-+
-+module_init(sm_maxilife_init);
-+module_exit(sm_maxilife_exit);
---- linux-old/drivers/sensors/mtp008.c Thu Jan 1 00:00:00 1970
-+++ linux/drivers/sensors/mtp008.c Mon Dec 13 20:18:51 2004
-@@ -0,0 +1,1103 @@
-+/*
-+ mtp008.c - Part of lm_sensors, Linux kernel modules for hardware
-+ monitoring
-+ Copyright (C) 2001, 2004 Kris Van Hees <aedil@alchar.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., 675 Mass Ave, Cambridge, MA 02139, USA.
-+ */
-+
-+#include <linux/module.h>
-+#include <linux/slab.h>
-+#include <linux/i2c.h>
-+#include <linux/i2c-proc.h>
-+#include <linux/init.h>
-+#define LM_DATE "20041007"
-+#define LM_VERSION "2.8.8"
-+
-+MODULE_LICENSE("GPL");
-+
-+/* Addresses to scan */
-+static unsigned short normal_i2c[] = {SENSORS_I2C_END};
-+static unsigned short normal_i2c_range[] = {0x2c, 0x2e, SENSORS_I2C_END};
-+static unsigned int normal_isa[] = {SENSORS_ISA_END};
-+static unsigned int normal_isa_range[] = {SENSORS_ISA_END};
-+
-+/* Insmod parameters */
-+SENSORS_INSMOD_1(mtp008);
-+
-+/* The MTP008 registers */
-+/* in0 .. in6 */
-+#define MTP008_REG_IN(nr) (0x20 + (nr))
-+#define MTP008_REG_IN_MAX(nr) (0x2b + (nr) * 2)
-+#define MTP008_REG_IN_MIN(nr) (0x2c + (nr) * 2)
-+
-+/* temp1 */
-+#define MTP008_REG_TEMP 0x27
-+#define MTP008_REG_TEMP_MAX 0x39
-+#define MTP008_REG_TEMP_MIN 0x3a
-+
-+/* fan1 .. fan3 */
-+#define MTP008_REG_FAN(nr) (0x27 + (nr))
-+#define MTP008_REG_FAN_MIN(nr) (0x3a + (nr))
-+
-+#define MTP008_REG_CONFIG 0x40
-+#define MTP008_REG_INT_STAT1 0x41
-+#define MTP008_REG_INT_STAT2 0x42
-+
-+#define MTP008_REG_SMI_MASK1 0x43
-+#define MTP008_REG_SMI_MASK2 0x44
-+
-+#define MTP008_REG_NMI_MASK1 0x45
-+#define MTP008_REG_NMI_MASK2 0x46
-+
-+#define MTP008_REG_VID_FANDIV 0x47
-+
-+#define MTP008_REG_I2C_ADDR 0x48
-+
-+#define MTP008_REG_RESET_VID4 0x49
-+
-+#define MTP008_REG_OVT_PROP 0x50
-+
-+#define MTP008_REG_BEEP_CTRL1 0x51
-+#define MTP008_REG_BEEP_CTRL2 0x52
-+
-+/* pwm1 .. pwm3 nr range 1-3 */
-+#define MTP008_REG_PWM_CTRL(nr) (0x52 + (nr))
-+
-+#define MTP008_REG_PIN_CTRL1 0x56
-+#define MTP008_REG_PIN_CTRL2 0x57
-+
-+#define MTP008_REG_CHIPID 0x58
-+
-+/*
-+ * Pin control register configuration constants.
-+ */
-+#define MTP008_CFG_VT1_PII 0x08
-+#define MTP008_CFG_VT2_AIN 0x00
-+#define MTP008_CFG_VT2_VT 0x03
-+#define MTP008_CFG_VT2_PII 0x04
-+#define MTP008_CFG_VT2_MASK 0x06
-+#define MTP008_CFG_VT3_VT 0x01
-+
-+/* sensor pin types */
-+#define VOLTAGE 1
-+#define THERMISTOR 2
-+#define PIIDIODE 3
-+
-+/*
-+ * Conversion routines and macros. Limit checking is only done on
-+ * the TO_REG variants.
-+ *
-+ * Note that IN values are expressed as 100 times the actual voltage to avoid
-+ * having to use floating point values. As such, IN values are between 0 and
-+ * 409 (0V to 4.096V).
-+ */
-+#define IN_TO_REG(val) (SENSORS_LIMIT((((val) * 10 + 8) / 16), 0, 255))
-+#define IN_FROM_REG(val) (((val) * 16 + 5) / 10)
-+
-+/*
-+ * The fan cotation count (as stored in the register) is calculated using the
-+ * following formula:
-+ * count = (22.5K * 60) / (rpm * div) = 1350000 / (rpm * div)
-+ * and the rpm is therefore:
-+ * rpm = 1350000 / (count * div)
-+ */
-+static inline u8 FAN_TO_REG(long rpm, int div)
-+{
-+ if (rpm == 0)
-+ return 255;
-+
-+ rpm = SENSORS_LIMIT(rpm, 1, 1000000);
-+
-+ return SENSORS_LIMIT(
-+ (1350000 + rpm * div / 2) / (rpm * div),
-+ 1, 254
-+ );
-+}
-+
-+#define FAN_FROM_REG(val, div) ((val) == 0 ? -1 \
-+ : (val) == 255 ? 0 \
-+ : 1350000 / \
-+ ((val) * (div)) \
-+ )
-+
-+/*
-+ * Temperatures are stored as two's complement values of the Celsius value. It
-+ * actually uses 10 times the Celsius value to avoid using floating point
-+ * values.
-+ */
-+#define TEMP_TO_REG(val) ( \
-+ (val) < 0 \
-+ ? SENSORS_LIMIT(((val) - 5) / 10, 0, 255) \
-+ : SENSORS_LIMIT(((val) + 5) / 10, 0, 255) \
-+ )
-+#define TEMP_FROM_REG(val) ( \
-+ ( \
-+ (val) > 0x80 ? (val) - 0x100 \
-+ : (val) \
-+ ) * 10 \
-+ )
-+
-+/*
-+ * VCORE voltage:
-+ * 0x00 to 0x0f = 2.05 to 1.30 (0.05 per unit)
-+ * 0x10 to 0x1e = 3.50 to 2.10 (0.10 per unit)
-+ * 0x1f = No CPU
-+ */
-+#define VID_FROM_REG(val) ((val) == 0x1f \
-+ ? 0 \
-+ : (val) < 0x10 ? 205 - (val) * 5 \
-+ : 510 - (val) * 10)
-+
-+/*
-+ * Fan divider.
-+ */
-+#define DIV_FROM_REG(val) (1 << (val))
-+#define DIV_TO_REG(val) ((val) == 8 ? 3 \
-+ : (val) == 4 ? 2 \
-+ : (val) == 2 ? 1 \
-+ : 0)
-+
-+/*
-+ * Alarms (interrupt status).
-+ */
-+#define ALARMS_FROM_REG(val) (val)
-+
-+/*
-+ * Beep controls.
-+ */
-+#define BEEPS_FROM_REG(val) (val)
-+#define BEEPS_TO_REG(val) (val)
-+
-+/*
-+ * PWM control. nr range 1 to 3
-+ */
-+#define PWM_FROM_REG(val) (val)
-+#define PWM_TO_REG(val) (val)
-+#define PWMENABLE_FROM_REG(nr, val) (((val) >> ((nr) + 3)) & 1)
-+
-+/*
-+ * For each registered MTP008, we need to keep some data in memory. The
-+ * structure itself is dynamically allocated, at the same time when a new
-+ * mtp008 client is allocated.
-+ */
-+struct mtp008_data {
-+ struct i2c_client client;
-+ int sysctl_id;
-+ enum chips type;
-+
-+ struct semaphore update_lock;
-+ char valid; /* !=0 if fields are valid */
-+ unsigned long last_updated; /* In jiffies */
-+
-+ u8 in[7]; /* Register value */
-+ u8 in_max[7]; /* Register value */
-+ u8 in_min[7]; /* Register value */
-+ u8 temp; /* Register value */
-+ u8 temp_max; /* Register value */
-+ u8 temp_min; /* Register value */
-+ u8 fan[3]; /* Register value */
-+ u8 fan_min[3]; /* Register value */
-+ u8 vid; /* Register encoding */
-+ u8 fan_div[3]; /* Register encoding */
-+ u16 alarms; /* Register encoding */
-+ u16 beeps; /* Register encoding */
-+ u8 pwm[4]; /* Register value */
-+ u8 sens[3]; /* 1 = Analog input,
-+ 2 = Thermistor,
-+ 3 = PII/Celeron diode */
-+ u8 pwmenable; /* Register 0x57 value */
-+};
-+
-+static int mtp008_attach_adapter(struct i2c_adapter *adapter);
-+static int mtp008_detect(struct i2c_adapter *adapter, int address,
-+ unsigned short flags, int kind);
-+static int mtp008_detach_client(struct i2c_client *client);
-+
-+static int mtp008_read_value(struct i2c_client *client, u8 register);
-+static int mtp008_write_value(struct i2c_client *client, u8 register, u8 value);
-+static void mtp008_update_client(struct i2c_client *client);
-+static void mtp008_init_client(struct i2c_client *client);
-+
-+static void mtp008_in(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void mtp008_fan(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void mtp008_temp(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void mtp008_temp_add(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void mtp008_vid(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void mtp008_fan_div(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void mtp008_alarms(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void mtp008_beep(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void mtp008_pwm(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void mtp008_sens(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void mtp008_getsensortype(struct mtp008_data *data, u8 inp);
-+
-+static int mtp008_id = 0;
-+
-+static struct i2c_driver mtp008_driver =
-+{
-+ .owner = THIS_MODULE,
-+ .name = "MTP008 sensor driver",
-+ .id = I2C_DRIVERID_MTP008,
-+ .flags = I2C_DF_NOTIFY,
-+ .attach_adapter = mtp008_attach_adapter,
-+ .detach_client = mtp008_detach_client,
-+};
-+
-+/* -- SENSORS SYSCTL START -- */
-+#define MTP008_SYSCTL_IN0 1000 /* Volts * 100 */
-+#define MTP008_SYSCTL_IN1 1001
-+#define MTP008_SYSCTL_IN2 1002
-+#define MTP008_SYSCTL_IN3 1003
-+#define MTP008_SYSCTL_IN4 1004
-+#define MTP008_SYSCTL_IN5 1005
-+#define MTP008_SYSCTL_IN6 1006
-+#define MTP008_SYSCTL_FAN1 1101 /* Rotations/min */
-+#define MTP008_SYSCTL_FAN2 1102
-+#define MTP008_SYSCTL_FAN3 1103
-+#define MTP008_SYSCTL_TEMP1 1200 /* Degrees Celcius * 10 */
-+#define MTP008_SYSCTL_TEMP2 1201 /* Degrees Celcius * 10 */
-+#define MTP008_SYSCTL_TEMP3 1202 /* Degrees Celcius * 10 */
-+#define MTP008_SYSCTL_VID 1300 /* Volts * 100 */
-+#define MTP008_SYSCTL_PWM1 1401
-+#define MTP008_SYSCTL_PWM2 1402
-+#define MTP008_SYSCTL_PWM3 1403
-+#define MTP008_SYSCTL_SENS1 1501 /* 1, 2, or Beta (3000-5000) */
-+#define MTP008_SYSCTL_SENS2 1502
-+#define MTP008_SYSCTL_SENS3 1503
-+#define MTP008_SYSCTL_FAN_DIV 2000 /* 1, 2, 4 or 8 */
-+#define MTP008_SYSCTL_ALARMS 2001 /* bitvector */
-+#define MTP008_SYSCTL_BEEP 2002 /* bitvector */
-+
-+#define MTP008_ALARM_IN0 0x0001
-+#define MTP008_ALARM_IN1 0x0002
-+#define MTP008_ALARM_IN2 0x0004
-+#define MTP008_ALARM_IN3 0x0008
-+#define MTP008_ALARM_IN4 0x0100
-+#define MTP008_ALARM_IN5 0x0200
-+#define MTP008_ALARM_IN6 0x0400
-+#define MTP008_ALARM_FAN1 0x0040
-+#define MTP008_ALARM_FAN2 0x0080
-+#define MTP008_ALARM_FAN3 0x0800
-+#define MTP008_ALARM_TEMP1 0x0010
-+#define MTP008_ALARM_TEMP2 0x0100
-+#define MTP008_ALARM_TEMP3 0x0200
-+
-+/* -- SENSORS SYSCTL END -- */
-+
-+/* The /proc/sys entries */
-+/* These files are created for each detected chip. This is just a template;
-+ though at first sight, you might think we could use a statically
-+ allocated list, we need some way to get back to the parent - which
-+ is done through one of the 'extra' fields which are initialized
-+ when a new copy is allocated. */
-+
-+static ctl_table mtp008_dir_table_template[] =
-+{
-+ {MTP008_SYSCTL_IN0, "in0", NULL, 0, 0644, NULL,
-+ &i2c_proc_real, &i2c_sysctl_real, NULL, &mtp008_in},
-+ {MTP008_SYSCTL_IN1, "in1", NULL, 0, 0644, NULL,
-+ &i2c_proc_real, &i2c_sysctl_real, NULL, &mtp008_in},
-+ {MTP008_SYSCTL_IN2, "in2", NULL, 0, 0644, NULL,
-+ &i2c_proc_real, &i2c_sysctl_real, NULL, &mtp008_in},
-+ {MTP008_SYSCTL_IN3, "in3", NULL, 0, 0644, NULL,
-+ &i2c_proc_real, &i2c_sysctl_real, NULL, &mtp008_in},
-+ {MTP008_SYSCTL_IN4, "in4", NULL, 0, 0644, NULL,
-+ &i2c_proc_real, &i2c_sysctl_real, NULL, &mtp008_in},
-+ {MTP008_SYSCTL_IN5, "in5", NULL, 0, 0644, NULL,
-+ &i2c_proc_real, &i2c_sysctl_real, NULL, &mtp008_in},
-+ {MTP008_SYSCTL_IN6, "in6", NULL, 0, 0644, NULL,
-+ &i2c_proc_real, &i2c_sysctl_real, NULL, &mtp008_in},
-+ {MTP008_SYSCTL_FAN1, "fan1", NULL, 0, 0644, NULL,
-+ &i2c_proc_real, &i2c_sysctl_real, NULL, &mtp008_fan},
-+ {MTP008_SYSCTL_FAN2, "fan2", NULL, 0, 0644, NULL,
-+ &i2c_proc_real, &i2c_sysctl_real, NULL, &mtp008_fan},
-+ {MTP008_SYSCTL_FAN3, "fan3", NULL, 0, 0644, NULL,
-+ &i2c_proc_real, &i2c_sysctl_real, NULL, &mtp008_fan},
-+ {MTP008_SYSCTL_TEMP1, "temp1", NULL, 0, 0644, NULL,
-+ &i2c_proc_real, &i2c_sysctl_real, NULL, &mtp008_temp},
-+ {MTP008_SYSCTL_TEMP2, "temp2", NULL, 0, 0644, NULL,
-+ &i2c_proc_real, &i2c_sysctl_real, NULL, &mtp008_temp_add},
-+ {MTP008_SYSCTL_TEMP3, "temp3", NULL, 0, 0644, NULL,
-+ &i2c_proc_real, &i2c_sysctl_real, NULL, &mtp008_temp_add},
-+ {MTP008_SYSCTL_VID, "vid", NULL, 0, 0444, NULL,
-+ &i2c_proc_real, &i2c_sysctl_real, NULL, &mtp008_vid},
-+ {MTP008_SYSCTL_FAN_DIV, "fan_div", NULL, 0, 0644, NULL,
-+ &i2c_proc_real, &i2c_sysctl_real, NULL, &mtp008_fan_div},
-+ {MTP008_SYSCTL_ALARMS, "alarms", NULL, 0, 0444, NULL,
-+ &i2c_proc_real, &i2c_sysctl_real, NULL, &mtp008_alarms},
-+ {MTP008_SYSCTL_BEEP, "beep", NULL, 0, 0644, NULL,
-+ &i2c_proc_real, &i2c_sysctl_real, NULL, &mtp008_beep},
-+ {MTP008_SYSCTL_PWM1, "pwm1", NULL, 0, 0644, NULL,
-+ &i2c_proc_real, &i2c_sysctl_real, NULL, &mtp008_pwm},
-+ {MTP008_SYSCTL_PWM2, "pwm2", NULL, 0, 0644, NULL,
-+ &i2c_proc_real, &i2c_sysctl_real, NULL, &mtp008_pwm},
-+ {MTP008_SYSCTL_PWM3, "pwm3", NULL, 0, 0644, NULL,
-+ &i2c_proc_real, &i2c_sysctl_real, NULL, &mtp008_pwm},
-+ {MTP008_SYSCTL_SENS1, "sensor1", NULL, 0, 0644, NULL,
-+ &i2c_proc_real, &i2c_sysctl_real, NULL, &mtp008_sens},
-+ {MTP008_SYSCTL_SENS2, "sensor2", NULL, 0, 0644, NULL,
-+ &i2c_proc_real, &i2c_sysctl_real, NULL, &mtp008_sens},
-+ {MTP008_SYSCTL_SENS3, "sensor3", NULL, 0, 0644, NULL,
-+ &i2c_proc_real, &i2c_sysctl_real, NULL, &mtp008_sens},
-+ {0}
-+};
-+
-+/* This function is called when:
-+ * mtp008_driver is inserted (when this module is loaded), for each available
-+ * adapter when a new adapter is inserted (and mtp008_driver is still present)
-+ */
-+static int mtp008_attach_adapter(struct i2c_adapter *adapter)
-+{
-+ struct i2c_client_address_data mtp008_addr_data;
-+
-+ mtp008_addr_data.normal_i2c = addr_data.normal_i2c;
-+ mtp008_addr_data.normal_i2c_range = addr_data.normal_i2c_range;
-+ mtp008_addr_data.probe = addr_data.probe;
-+ mtp008_addr_data.probe_range = addr_data.probe_range;
-+ mtp008_addr_data.ignore = addr_data.ignore;
-+ mtp008_addr_data.ignore_range = addr_data.ignore_range;
-+ mtp008_addr_data.force = addr_data.forces->force;
-+
-+ return i2c_probe(adapter, &mtp008_addr_data, mtp008_detect);
-+}
-+
-+int mtp008_detect(struct i2c_adapter *adapter, int address,
-+ unsigned short flags, int kind)
-+{
-+ const char *type_name = "";
-+ const char *client_name = "";
-+ int is_isa, err, sysid;
-+ struct i2c_client *new_client;
-+ struct mtp008_data *data;
-+
-+ err = 0;
-+
-+ is_isa = i2c_is_isa_adapter(adapter);
-+ if (is_isa ||
-+ !i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
-+ goto ERROR0;
-+
-+ /*
-+ * We presume we have a valid client. We now create the client
-+ * structure, even though we cannot fill it completely yet. But it
-+ * allows us to use mtp008_(read|write)_value().
-+ */
-+ if (!(data = kmalloc(sizeof(struct mtp008_data), GFP_KERNEL))) {
-+ err = -ENOMEM;
-+ goto ERROR0;
-+ }
-+
-+ new_client = &data->client;
-+ new_client->addr = address;
-+ new_client->data = data;
-+ new_client->adapter = adapter;
-+ new_client->driver = &mtp008_driver;
-+ new_client->flags = 0;
-+
-+ /*
-+ * Remaining detection.
-+ */
-+ if (kind < 0) {
-+ if (mtp008_read_value(new_client, MTP008_REG_CHIPID) != 0xac)
-+ goto ERROR1;
-+ }
-+ /*
-+ * Fill in the remaining client fields and put it into the global list.
-+ */
-+ type_name = "mtp008";
-+ client_name = "MTP008 chip";
-+ strcpy(new_client->name, client_name);
-+ data->type = kind;
-+
-+ new_client->id = mtp008_id++;
-+ data->valid = 0;
-+ init_MUTEX(&data->update_lock);
-+
-+ /*
-+ * Tell the I2C layer that a new client has arrived.
-+ */
-+ if ((err = i2c_attach_client(new_client)))
-+ goto ERROR1;
-+
-+ /*
-+ * Register a new directory entry with the sensors module.
-+ */
-+ if ((sysid = i2c_register_entry(new_client, type_name,
-+ mtp008_dir_table_template)) < 0) {
-+ err = sysid;
-+ goto ERROR2;
-+ }
-+ data->sysctl_id = sysid;
-+
-+ /*
-+ * Initialize the MTP008 chip.
-+ */
-+ mtp008_init_client(new_client);
-+
-+ return 0;
-+
-+ /*
-+ * Error handling. Bad programming practise but very code efficient.
-+ */
-+ ERROR2:
-+ i2c_detach_client(new_client);
-+ ERROR1:
-+ kfree(data);
-+
-+ ERROR0:
-+ return err;
-+}
-+
-+static int mtp008_detach_client(struct i2c_client *client)
-+{
-+ int err;
-+
-+ i2c_deregister_entry(
-+ ((struct mtp008_data *) (client->data))->sysctl_id);
-+
-+ if ((err = i2c_detach_client(client))) {
-+ printk("mtp008.o: Deregistration failed, "
-+ "client not detached.\n");
-+ return err;
-+ }
-+ kfree(client->data);
-+
-+ return 0;
-+}
-+
-+
-+static int mtp008_read_value(struct i2c_client *client, u8 reg)
-+{
-+ return i2c_smbus_read_byte_data(client, reg) & 0xff;
-+}
-+
-+static int mtp008_write_value(struct i2c_client *client, u8 reg, u8 value)
-+{
-+ return i2c_smbus_write_byte_data(client, reg, value);
-+}
-+
-+/* Called when we have found a new MTP008. It should set limits, etc. */
-+static void mtp008_init_client(struct i2c_client *client)
-+{
-+ u8 save1, save2;
-+ struct mtp008_data *data;
-+
-+ data = client->data;
-+
-+ /*
-+ * Initialize the Myson MTP008 hardware monitoring chip.
-+ * Save the pin settings that the BIOS hopefully set.
-+ */
-+ save1 = mtp008_read_value(client, MTP008_REG_PIN_CTRL1);
-+ save2 = mtp008_read_value(client, MTP008_REG_PIN_CTRL2);
-+ mtp008_write_value(client, MTP008_REG_CONFIG,
-+ (mtp008_read_value(client, MTP008_REG_CONFIG) & 0x7f) | 0x80);
-+ mtp008_write_value(client, MTP008_REG_PIN_CTRL1, save1);
-+ mtp008_write_value(client, MTP008_REG_PIN_CTRL2, save2);
-+
-+ mtp008_getsensortype(data, save2);
-+
-+
-+ /*
-+ * Start monitoring.
-+ */
-+ mtp008_write_value(
-+ client, MTP008_REG_CONFIG,
-+ (mtp008_read_value(client, MTP008_REG_CONFIG) & 0xf7) | 0x01
-+ );
-+}
-+
-+static void mtp008_update_client(struct i2c_client *client)
-+{
-+ int i;
-+ u8 inp;
-+ struct mtp008_data *data;
-+
-+ data = client->data;
-+
-+ down(&data->update_lock);
-+
-+ if ((jiffies - data->last_updated > HZ + HZ / 2) ||
-+ (jiffies < data->last_updated) || !data->valid) {
-+#ifdef DEBUG
-+ printk("Starting MTP008 update\n");
-+#endif
-+
-+ /*
-+ * Read in the analog inputs. We're reading AIN4 and AIN5 as
-+ * regular analog inputs, even though they may have been
-+ * configured as temperature readings instead. Interpretation
-+ * of these values is done elsewhere.
-+ */
-+ for (i = 0; i < 7; i++) {
-+ data->in[i] =
-+ mtp008_read_value(client, MTP008_REG_IN(i));
-+ data->in_max[i] =
-+ mtp008_read_value(client, MTP008_REG_IN_MAX(i));
-+ data->in_min[i] =
-+ mtp008_read_value(client, MTP008_REG_IN_MIN(i));
-+ }
-+
-+ /*
-+ * Read the temperature sensor.
-+ */
-+ data->temp = mtp008_read_value(client, MTP008_REG_TEMP);
-+ data->temp_max = mtp008_read_value(client, MTP008_REG_TEMP_MAX);
-+ data->temp_min = mtp008_read_value(client, MTP008_REG_TEMP_MIN);
-+
-+ /*
-+ * Read the first 2 fan dividers and the VID setting. Read the
-+ * third fan divider from a different register.
-+ */
-+ inp = mtp008_read_value(client, MTP008_REG_VID_FANDIV);
-+ data->vid = inp & 0x0f;
-+ data->vid |= (mtp008_read_value(client,
-+ MTP008_REG_RESET_VID4) & 0x01) << 4;
-+
-+ data->fan_div[0] = (inp >> 4) & 0x03;
-+ data->fan_div[1] = inp >> 6;
-+ data->fan_div[2] =
-+ mtp008_read_value(client, MTP008_REG_PIN_CTRL1) >> 6;
-+
-+ /*
-+ * Read the interrupt status registers.
-+ */
-+ data->alarms =
-+ (mtp008_read_value(client,
-+ MTP008_REG_INT_STAT1) & 0xdf) |
-+ (mtp008_read_value(client,
-+ MTP008_REG_INT_STAT2) & 0x0f) << 8;
-+
-+ /*
-+ * Read the beep control registers.
-+ */
-+ data->beeps =
-+ (mtp008_read_value(client,
-+ MTP008_REG_BEEP_CTRL1) & 0xdf) |
-+ (mtp008_read_value(client,
-+ MTP008_REG_BEEP_CTRL2) & 0x8f) << 8;
-+
-+ /*
-+ * Read the sensor configuration.
-+ */
-+ inp = mtp008_read_value(client, MTP008_REG_PIN_CTRL2);
-+ mtp008_getsensortype(data, inp);
-+ data->pwmenable = inp;
-+
-+ /*
-+ * Read the PWM registers if enabled.
-+ */
-+ for (i = 1; i <= 3; i++)
-+ {
-+ if(PWMENABLE_FROM_REG(i, inp))
-+ data->pwm[i-1] = mtp008_read_value(client,
-+ MTP008_REG_PWM_CTRL(i));
-+ else
-+ data->pwm[i-1] = 255;
-+ }
-+
-+ /*
-+ * Read the fan sensors. Skip 3 if PWM1 enabled.
-+ */
-+ for (i = 1; i <= 3; i++) {
-+ if(i == 3 && PWMENABLE_FROM_REG(1, inp)) {
-+ data->fan[2] = 0;
-+ data->fan_min[2] = 0;
-+ } else {
-+ data->fan[i-1] = mtp008_read_value(client,
-+ MTP008_REG_FAN(i));
-+ data->fan_min[i-1] = mtp008_read_value(client,
-+ MTP008_REG_FAN_MIN(i));
-+ }
-+ }
-+
-+ data->last_updated = jiffies;
-+ data->valid = 1;
-+ }
-+ up(&data->update_lock);
-+}
-+
-+static void mtp008_getsensortype(struct mtp008_data *data, u8 inp)
-+{
-+ inp &= 0x0f;
-+ data->sens[0] = (inp >> 3) + 2; /* 2 or 3 */
-+ data->sens[1] = ((inp >> 1) & 0x03) + 1; /* 1, 2 or 3 */
-+ data->sens[2] = (inp & 0x01) + 1; /* 1 or 2 */
-+}
-+
-+/* The next few functions are the call-back functions of the /proc/sys and
-+ sysctl files. Which function is used is defined in the ctl_table in
-+ the extra1 field.
-+ Each function must return the magnitude (power of 10 to divide the date
-+ with) if it is called with operation==SENSORS_PROC_REAL_INFO. It must
-+ put a maximum of *nrels elements in results reflecting the data of this
-+ file, and set *nrels to the number it actually put in it, if operation==
-+ SENSORS_PROC_REAL_READ. Finally, it must get upto *nrels elements from
-+ results and write them to the chip, if operations==SENSORS_PROC_REAL_WRITE.
-+ Note that on SENSORS_PROC_REAL_READ, I do not check whether results is
-+ large enough (by checking the incoming value of *nrels). This is not very
-+ good practice, but as long as you put less than about 5 values in results,
-+ you can assume it is large enough. */
-+void mtp008_in(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ int nr;
-+ struct mtp008_data *data;
-+
-+ nr = ctl_name - MTP008_SYSCTL_IN0;
-+ data = client->data;
-+
-+ switch (operation) {
-+ case SENSORS_PROC_REAL_INFO:
-+ *nrels_mag = 2;
-+
-+ break;
-+ case SENSORS_PROC_REAL_READ:
-+ mtp008_update_client(client);
-+
-+ if((nr != 4 && nr != 5) || data->sens[nr - 3] == VOLTAGE) {
-+ results[0] = IN_FROM_REG(data->in_min[nr]);
-+ results[1] = IN_FROM_REG(data->in_max[nr]);
-+ results[2] = IN_FROM_REG(data->in[nr]);
-+ } else {
-+ results[0] = 0;
-+ results[1] = 0;
-+ results[2] = 0;
-+ }
-+
-+ *nrels_mag = 3;
-+
-+ break;
-+ case SENSORS_PROC_REAL_WRITE:
-+ if((nr != 4 && nr != 5) || data->sens[nr - 3] == VOLTAGE) {
-+ if (*nrels_mag >= 1) {
-+ data->in_min[nr] = IN_TO_REG(results[0]);
-+ mtp008_write_value(client, MTP008_REG_IN_MIN(nr),
-+ data->in_min[nr]);
-+ }
-+ if (*nrels_mag >= 2) {
-+ data->in_max[nr] = IN_TO_REG(results[1]);
-+ mtp008_write_value(client, MTP008_REG_IN_MAX(nr),
-+ data->in_max[nr]);
-+ }
-+ }
-+ }
-+}
-+
-+void mtp008_fan(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ int nr;
-+ struct mtp008_data *data;
-+
-+ nr = ctl_name - MTP008_SYSCTL_FAN1;
-+ data = client->data;
-+
-+ switch (operation) {
-+ case SENSORS_PROC_REAL_INFO:
-+ *nrels_mag = 0;
-+
-+ break;
-+ case SENSORS_PROC_REAL_READ:
-+ mtp008_update_client(client);
-+
-+ results[0] = FAN_FROM_REG(data->fan_min[nr],
-+ DIV_FROM_REG(data->fan_div[nr]));
-+ results[1] = FAN_FROM_REG(data->fan[nr],
-+ DIV_FROM_REG(data->fan_div[nr]));
-+
-+ *nrels_mag = 2;
-+
-+ break;
-+ case SENSORS_PROC_REAL_WRITE:
-+ if (*nrels_mag >= 1) {
-+ data->fan_min[nr] =
-+ FAN_TO_REG(results[0],
-+ DIV_FROM_REG(data->fan_div[nr]));
-+ mtp008_write_value(client, MTP008_REG_FAN_MIN(nr + 1),
-+ data->fan_min[nr]);
-+ }
-+ }
-+}
-+
-+void mtp008_temp(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct mtp008_data *data;
-+
-+ data = client->data;
-+
-+ switch (operation) {
-+ case SENSORS_PROC_REAL_INFO:
-+ *nrels_mag = 1;
-+
-+ break;
-+ case SENSORS_PROC_REAL_READ:
-+ mtp008_update_client(client);
-+
-+ results[0] = TEMP_FROM_REG(data->temp_max);
-+ results[1] = TEMP_FROM_REG(data->temp_min);
-+ results[2] = TEMP_FROM_REG(data->temp);
-+ *nrels_mag = 3;
-+
-+ break;
-+ case SENSORS_PROC_REAL_WRITE:
-+ if (*nrels_mag >= 1) {
-+ data->temp_max = TEMP_TO_REG(results[0]);
-+ mtp008_write_value(client, MTP008_REG_TEMP_MAX,
-+ data->temp_max);
-+ }
-+ if (*nrels_mag >= 2) {
-+ data->temp_min = TEMP_TO_REG(results[1]);
-+ mtp008_write_value(client, MTP008_REG_TEMP_MIN,
-+ data->temp_min);
-+ }
-+ }
-+}
-+
-+void mtp008_temp_add(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ int nr;
-+ struct mtp008_data *data;
-+
-+ nr = 3 + ctl_name - MTP008_SYSCTL_TEMP1; /* AIN4 or AIN5 */
-+ data = client->data;
-+
-+ switch (operation) {
-+ case SENSORS_PROC_REAL_INFO:
-+ *nrels_mag = 1;
-+
-+ break;
-+ case SENSORS_PROC_REAL_READ:
-+ mtp008_update_client(client);
-+
-+ if(data->sens[nr - 3] != VOLTAGE) {
-+ results[0] = TEMP_FROM_REG(data->in_max[nr]);
-+ results[1] = TEMP_FROM_REG(data->in_min[nr]);
-+ results[2] = TEMP_FROM_REG(data->in[nr]);
-+ } else {
-+ results[0] = 0;
-+ results[1] = 0;
-+ results[2] = 0;
-+ }
-+ *nrels_mag = 3;
-+
-+ break;
-+ case SENSORS_PROC_REAL_WRITE:
-+ if(data->sens[nr - 3] != VOLTAGE) {
-+ if (*nrels_mag >= 1) {
-+ data->in_max[nr] = TEMP_TO_REG(results[0]);
-+ mtp008_write_value(client,
-+ MTP008_REG_IN_MAX(nr),
-+ data->in_max[nr]);
-+ }
-+ if (*nrels_mag >= 2) {
-+ data->in_min[nr] = TEMP_TO_REG(results[1]);
-+ mtp008_write_value(client,
-+ MTP008_REG_IN_MIN(nr),
-+ data->in_min[nr]);
-+ }
-+ }
-+ }
-+}
-+
-+void mtp008_vid(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct mtp008_data *data;
-+
-+ data = client->data;
-+
-+ switch (operation) {
-+ case SENSORS_PROC_REAL_INFO:
-+ *nrels_mag = 2;
-+
-+ break;
-+ case SENSORS_PROC_REAL_READ:
-+ mtp008_update_client(client);
-+
-+ results[0] = VID_FROM_REG(data->vid);
-+
-+ *nrels_mag = 1;
-+ }
-+}
-+
-+void mtp008_fan_div(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results)
-+{
-+ struct mtp008_data *data;
-+ u8 val;
-+
-+ data = client->data;
-+
-+ switch (operation) {
-+ case SENSORS_PROC_REAL_INFO:
-+ *nrels_mag = 0;
-+
-+ break;
-+ case SENSORS_PROC_REAL_READ:
-+ mtp008_update_client(client);
-+
-+ results[0] = DIV_FROM_REG(data->fan_div[0]);
-+ results[1] = DIV_FROM_REG(data->fan_div[1]);
-+ results[2] = DIV_FROM_REG(data->fan_div[2]);
-+
-+ *nrels_mag = 3;
-+
-+ break;
-+ case SENSORS_PROC_REAL_WRITE:
-+ if (*nrels_mag >= 3) {
-+ data->fan_div[2] = DIV_TO_REG(results[2]);
-+ val = mtp008_read_value(client, MTP008_REG_PIN_CTRL1);
-+ val = (val & 0x3f) | (data->fan_div[2] & 0x03) << 6;
-+ mtp008_write_value(client, MTP008_REG_PIN_CTRL1, val);
-+ }
-+ if (*nrels_mag >= 1) {
-+ val = mtp008_read_value(client, MTP008_REG_VID_FANDIV);
-+ if (*nrels_mag >= 2) {
-+ data->fan_div[1] = DIV_TO_REG(results[1]);
-+ val = (val & 0x3f) |
-+ (data->fan_div[1] & 0x03) << 6;
-+ }
-+ data->fan_div[0] = DIV_TO_REG(results[0]);
-+ val = (val & 0xcf) | (data->fan_div[0] & 0x03) << 4;
-+ mtp008_write_value(client, MTP008_REG_VID_FANDIV, val);
-+ }
-+ }
-+}
-+
-+void mtp008_alarms(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct mtp008_data *data;
-+
-+ data = client->data;
-+
-+ switch (operation) {
-+ case SENSORS_PROC_REAL_INFO:
-+ *nrels_mag = 0;
-+
-+ break;
-+ case SENSORS_PROC_REAL_READ:
-+ mtp008_update_client(client);
-+
-+ results[0] = ALARMS_FROM_REG(data->alarms);
-+
-+ *nrels_mag = 1;
-+ }
-+}
-+
-+void mtp008_beep(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct mtp008_data *data;
-+
-+ data = client->data;
-+
-+ switch (operation) {
-+ case SENSORS_PROC_REAL_INFO:
-+ *nrels_mag = 0;
-+
-+ break;
-+ case SENSORS_PROC_REAL_READ:
-+ mtp008_update_client(client);
-+
-+ results[0] = BEEPS_FROM_REG(data->beeps);
-+
-+ *nrels_mag = 1;
-+
-+ break;
-+ case SENSORS_PROC_REAL_WRITE:
-+ if (*nrels_mag >= 1) {
-+ data->beeps = BEEPS_TO_REG(results[0]) & 0xdf8f;
-+
-+ mtp008_write_value(client, MTP008_REG_BEEP_CTRL1,
-+ data->beeps & 0xff);
-+ mtp008_write_value(client, MTP008_REG_BEEP_CTRL2,
-+ data->beeps >> 8);
-+ }
-+ }
-+}
-+
-+void mtp008_pwm(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ int nr;
-+ struct mtp008_data *data;
-+
-+ nr = ctl_name - MTP008_SYSCTL_PWM1;
-+ data = client->data;
-+
-+ switch (operation) {
-+ case SENSORS_PROC_REAL_INFO:
-+ *nrels_mag = 0;
-+
-+ break;
-+ case SENSORS_PROC_REAL_READ:
-+ mtp008_update_client(client);
-+
-+ results[0] = PWM_FROM_REG(data->pwm[nr]);
-+ results[1] = PWMENABLE_FROM_REG(nr + 1, data->pwmenable);
-+ *nrels_mag = 2;
-+
-+ break;
-+ case SENSORS_PROC_REAL_WRITE:
-+ if (*nrels_mag >= 1) {
-+ if (*nrels_mag >= 2) {
-+ if(results[1])
-+ data->pwmenable |= 0x10 << nr;
-+ else
-+ data->pwmenable &= ~(0x10 << nr);
-+ mtp008_write_value(client, MTP008_REG_PIN_CTRL2,
-+ data->pwmenable);
-+ }
-+ data->pwm[nr] = PWM_TO_REG(results[0]);
-+ mtp008_write_value(client, MTP008_REG_PWM_CTRL(nr),
-+ data->pwm[nr]);
-+ }
-+ }
-+}
-+
-+void mtp008_sens(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ const char *opts = "";
-+ int nr;
-+ u8 tmp;
-+ struct mtp008_data *data;
-+
-+ nr = 1 + ctl_name - MTP008_SYSCTL_SENS1;
-+ data = client->data;
-+
-+ switch (operation) {
-+ case SENSORS_PROC_REAL_INFO:
-+ *nrels_mag = 0;
-+
-+ break;
-+ case SENSORS_PROC_REAL_READ:
-+ results[0] = data->sens[nr - 1];
-+
-+ *nrels_mag = 1;
-+
-+ break;
-+ case SENSORS_PROC_REAL_WRITE:
-+ if (*nrels_mag >= 1) {
-+ tmp = mtp008_read_value(client, MTP008_REG_PIN_CTRL2);
-+
-+ switch (nr) {
-+ case 1: /* VT or PII */
-+ opts = "2 or 3";
-+
-+ switch (results[0]) {
-+ case THERMISTOR:
-+ mtp008_write_value(
-+ client, MTP008_REG_PIN_CTRL2,
-+ tmp & ~MTP008_CFG_VT1_PII);
-+ data->sens[0] = 2;
-+ return;
-+ case PIIDIODE:
-+ mtp008_write_value(
-+ client, MTP008_REG_PIN_CTRL2,
-+ tmp | MTP008_CFG_VT1_PII);
-+ data->sens[0] = 3;
-+ return;
-+ }
-+
-+ break;
-+ case 2: /* AIN, VT or PII */
-+ tmp &= ~MTP008_CFG_VT2_MASK;
-+ opts = "1, 2 or 3";
-+
-+ switch (results[0]) {
-+ case VOLTAGE:
-+ mtp008_write_value(
-+ client, MTP008_REG_PIN_CTRL2,
-+ tmp | MTP008_CFG_VT2_AIN);
-+ data->sens[1] = 1;
-+ return;
-+ case THERMISTOR:
-+ mtp008_write_value(
-+ client, MTP008_REG_PIN_CTRL2,
-+ tmp | MTP008_CFG_VT2_VT);
-+ data->sens[1] = 2;
-+ return;
-+ case PIIDIODE:
-+ mtp008_write_value(
-+ client, MTP008_REG_PIN_CTRL2,
-+ tmp | MTP008_CFG_VT2_PII);
-+ data->sens[1] = 3;
-+ return;
-+ }
-+
-+ break;
-+ case 3: /* AIN or VT */
-+ opts = "1 or 2";
-+
-+ switch (results[0]) {
-+ case VOLTAGE:
-+ mtp008_write_value(
-+ client, MTP008_REG_PIN_CTRL2,
-+ tmp & ~MTP008_CFG_VT3_VT);
-+ data->sens[2] = 1;
-+ return;
-+ case THERMISTOR:
-+ mtp008_write_value(
-+ client, MTP008_REG_PIN_CTRL2,
-+ tmp | MTP008_CFG_VT3_VT);
-+ data->sens[2] = 2;
-+ return;
-+ }
-+
-+ break;
-+ }
-+
-+ printk("mtp008.o: Invalid sensor type %ld "
-+ "for sensor %d; must be %s.\n",
-+ results[0], nr, opts);
-+ }
-+ }
-+}
-+
-+static int __init sm_mtp008_init(void)
-+{
-+ printk("mtp008.o version %s (%s)\n", LM_VERSION, LM_DATE);
-+ return i2c_add_driver(&mtp008_driver);
-+}
-+
-+static void __exit sm_mtp008_exit(void)
-+{
-+ i2c_del_driver(&mtp008_driver);
-+}
-+
-+
-+
-+MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl>, "
-+ "Philip Edelbrock <phil@netroedge.com>, "
-+ "and Kris Van Hees <aedil@alchar.org>");
-+MODULE_DESCRIPTION("MTP008 driver");
-+
-+module_init(sm_mtp008_init);
-+module_exit(sm_mtp008_exit);
---- linux-old/drivers/sensors/pc87360.c Thu Jan 1 00:00:00 1970
-+++ linux/drivers/sensors/pc87360.c Mon Dec 13 20:18:51 2004
-@@ -0,0 +1,1357 @@
-+/*
-+ * pc87360.c - Part of lm_sensors, Linux kernel modules
-+ * for hardware monitoring
-+ * Copyright (C) 2004 Jean Delvare <khali@linux-fr.org>
-+ *
-+ * Copied from smsc47m1.c:
-+ * Copyright (C) 2002 Mark D. Studebaker <mdsxyz123@yahoo.com>
-+ *
-+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
-+ *
-+ * Supports the following chips:
-+ *
-+ * Chip #vin #fan #pwm #temp devid
-+ * PC87360 - 2 2 - 0xE1
-+ * PC87363 - 2 2 - 0xE8
-+ * PC87364 - 3 3 - 0xE4
-+ * PC87365 11 3 3 2 0xE5
-+ * PC87366 11 3 3 3-4 0xE9
-+ *
-+ * This driver assumes that no more than one chip is present, and the
-+ * standard Super-I/O address is used (0x2E/0x2F).
-+ */
-+
-+#include <linux/module.h>
-+#include <linux/slab.h>
-+#include <linux/ioport.h>
-+#include <linux/i2c.h>
-+#include <linux/i2c-proc.h>
-+#include <linux/init.h>
-+#include <asm/io.h>
-+#define LM_DATE "20041007"
-+#define LM_VERSION "2.8.8"
-+#include <linux/sensors_vid.h>
-+
-+static unsigned short normal_i2c[] = { SENSORS_I2C_END };
-+static unsigned short normal_i2c_range[] = { SENSORS_I2C_END };
-+static unsigned int normal_isa[] = { 0x0000, SENSORS_ISA_END };
-+static unsigned int normal_isa_range[] = { SENSORS_ISA_END };
-+static struct i2c_force_data forces[] = {{NULL}};
-+static u8 devid;
-+static unsigned int extra_isa[] = { 0x0000, 0x0000, 0x0000 };
-+static u8 confreg[4];
-+
-+enum chips { any_chip, pc87360, pc87363, pc87364, pc87365, pc87366 };
-+static struct i2c_address_data addr_data = {
-+ .normal_i2c = normal_i2c,
-+ .normal_i2c_range = normal_i2c_range,
-+ .normal_isa = normal_isa,
-+ .normal_isa_range = normal_isa_range,
-+ .probe = normal_i2c, /* cheat */
-+ .probe_range = normal_i2c_range, /* cheat */
-+ .ignore = normal_i2c, /* cheat */
-+ .ignore_range = normal_i2c_range, /* cheat */
-+ .forces = forces,
-+};
-+
-+static int init = 1;
-+MODULE_PARM(init, "i");
-+MODULE_PARM_DESC(init,
-+ "Chip initialization level:\n"
-+ " 0: None\n"
-+ "*1: Forcibly enable internal voltage and temperature channels, except in9\n"
-+ " 2: Forcibly enable all voltage and temperature channels, except in9\n"
-+ " 3: Forcibly enable all voltage and temperature channels, including in9");
-+
-+/*
-+ * Super-I/O registers and operations
-+ */
-+
-+#define REG 0x2e /* The register to read/write */
-+#define VAL 0x2f /* The value to read/write */
-+
-+#define DEV 0x07 /* Register: Logical device select */
-+#define DEVID 0x20 /* Register: Device ID */
-+#define ACT 0x30 /* Register: Device activation */
-+#define BASE 0x60 /* Register: Base address */
-+
-+#define FSCM 0x09 /* Logical device: fans */
-+#define VLM 0x0d /* Logical device: voltages */
-+#define TMS 0x0e /* Logical device: temperatures */
-+static const u8 logdev[3] = { FSCM, VLM, TMS };
-+
-+#define LD_FAN 0
-+#define LD_IN 1
-+#define LD_TEMP 2
-+
-+static inline void superio_outb(int reg, int val)
-+{
-+ outb(reg, REG);
-+ outb(val, VAL);
-+}
-+
-+static inline int superio_inb(int reg)
-+{
-+ outb(reg, REG);
-+ return inb(VAL);
-+}
-+
-+static inline void superio_exit(void)
-+{
-+ outb(0x02, REG);
-+ outb(0x02, VAL);
-+}
-+
-+/*
-+ * Logical devices
-+ */
-+
-+#define PC87360_EXTENT 0x10
-+#define PC87365_REG_BANK 0x09
-+#define NO_BANK 0xff
-+
-+/*
-+ * Fan registers and conversions
-+ */
-+
-+/* nr has to be 0 or 1 (PC87360/87363) or 2 (PC87364/87365/87366) */
-+#define PC87360_REG_PRESCALE(nr) (0x00 + 2 * (nr))
-+#define PC87360_REG_PWM(nr) (0x01 + 2 * (nr))
-+#define PC87360_REG_FAN_MIN(nr) (0x06 + 3 * (nr))
-+#define PC87360_REG_FAN(nr) (0x07 + 3 * (nr))
-+#define PC87360_REG_FAN_STATUS(nr) (0x08 + 3 * (nr))
-+
-+#define FAN_FROM_REG(val,div) ((val)==0?0: \
-+ 480000/((val)*(div)))
-+#define FAN_TO_REG(val,div) ((val)<=100?0: \
-+ 480000/((val)*(div)))
-+#define FAN_DIV_FROM_REG(val) (1 << ((val >> 5) & 0x03))
-+#define FAN_DIV_TO_REG(val) ((val)==8?0x60:(val)==4?0x40: \
-+ (val)==1?0x00:0x20)
-+#define FAN_STATUS_FROM_REG(val) ((val) & 0x07)
-+
-+#define FAN_CONFIG_MONITOR(val,nr) (((val) >> (2 + nr * 3)) & 1)
-+#define FAN_CONFIG_CONTROL(val,nr) (((val) >> (3 + nr * 3)) & 1)
-+#define FAN_CONFIG_INVERT(val,nr) (((val) >> (4 + nr * 3)) & 1)
-+
-+#define PWM_FROM_REG(val,inv) ((inv) ? 255 - (val) : (val))
-+static inline u8 PWM_TO_REG(int val, int inv)
-+{
-+ if (inv)
-+ val = 255 - val;
-+ if (val < 0)
-+ return 0;
-+ if (val > 255)
-+ return 255;
-+ return val;
-+}
-+
-+/*
-+ * Voltage registers and conversions
-+ */
-+
-+#define PC87365_REG_IN_CONVRATE 0x07
-+#define PC87365_REG_IN_CONFIG 0x08
-+#define PC87365_REG_IN 0x0B
-+#define PC87365_REG_IN_MIN 0x0D
-+#define PC87365_REG_IN_MAX 0x0C
-+#define PC87365_REG_IN_STATUS 0x0A
-+#define PC87365_REG_IN_ALARMS1 0x00
-+#define PC87365_REG_IN_ALARMS2 0x01
-+#define PC87365_REG_VID 0x06
-+
-+#define IN_FROM_REG(val,ref) (((val) * (ref) + 128) / 256)
-+#define IN_TO_REG(val,ref) ((val)<0 ? 0 : \
-+ (val)*256>=(ref)*255 ? 255: \
-+ ((val) * 256 + (ref) / 2) / (ref))
-+
-+/*
-+ * Temperature registers and conversions
-+ */
-+
-+#define PC87365_REG_TEMP_CONFIG 0x08
-+#define PC87365_REG_TEMP 0x0B
-+#define PC87365_REG_TEMP_MIN 0x0D
-+#define PC87365_REG_TEMP_MAX 0x0C
-+#define PC87365_REG_TEMP_CRIT 0x0E
-+#define PC87365_REG_TEMP_STATUS 0x0A
-+#define PC87365_REG_TEMP_ALARMS 0x00
-+
-+#define TEMP_FROM_REG(val) ((val)&0x80 ? (val) - 0x100 : (val))
-+#define TEMP_TO_REG(val) ((val)<-55 ? 201 : (val)>127 ? 0x7F : \
-+ (val)<0 ? (val) + 0x100 : (val))
-+
-+struct pc87360_data {
-+ struct i2c_client client;
-+ struct semaphore lock;
-+ int sysctl_id;
-+ int address[3];
-+
-+ struct semaphore update_lock;
-+ char valid; /* !=0 if following fields are valid */
-+ unsigned long last_updated; /* In jiffies */
-+
-+ u8 fannr, innr, tempnr;
-+
-+ u8 fan[3]; /* Register value */
-+ u8 fan_min[3]; /* Register value */
-+ u8 fan_status[3]; /* Register value */
-+ u8 pwm[3]; /* Register value */
-+ u16 fan_conf; /* Configuration register values, combined */
-+
-+ u16 in_vref; /* 10mV/bit */
-+ u8 in[14]; /* Register value */
-+ u8 in_min[14]; /* Register value */
-+ u8 in_max[14]; /* Register value */
-+ u8 in_crit[3]; /* Register value */
-+ u8 in_status[14]; /* Register value */
-+ u16 in_alarms; /* Register values, combined, masked */
-+ u8 vid_conf; /* Configuration register value */
-+ u8 vrm;
-+ u8 vid; /* Register value */
-+
-+ u8 temp[3]; /* Register value */
-+ u8 temp_min[3]; /* Register value */
-+ u8 temp_max[3]; /* Register value */
-+ u8 temp_crit[3]; /* Register value */
-+ u8 temp_status[3]; /* Register value */
-+ u8 temp_alarms; /* Register value, masked */
-+};
-+
-+
-+static int pc87360_attach_adapter(struct i2c_adapter *adapter);
-+static int pc87360_detect(struct i2c_adapter *adapter, int address,
-+ unsigned short flags, int kind);
-+static int pc87360_detach_client(struct i2c_client *client);
-+
-+static int pc87360_read_value(struct pc87360_data *data, u8 ldi, u8 bank,
-+ u8 reg);
-+static void pc87360_write_value(struct pc87360_data *data, u8 ldi, u8 bank,
-+ u8 reg, u8 value);
-+static void pc87360_init_client(struct i2c_client *client, int use_thermistors);
-+static void pc87360_update_client(struct i2c_client *client);
-+static int pc87360_find(u8 *devid, int *address);
-+
-+
-+void pc87365_alarms(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results);
-+
-+static void pc87360_fan(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void pc87360_fan_status(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void pc87360_fan_div(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void pc87360_pwm(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+
-+void pc87365_in(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results);
-+void pc87365_in_status(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results);
-+void pc87365_vid(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results);
-+void pc87365_vrm(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results);
-+
-+void pc87365_temp(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results);
-+void pc87365_temp_status(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results);
-+
-+static int pc87360_id = 0;
-+
-+static struct i2c_driver pc87360_driver = {
-+ .owner = THIS_MODULE,
-+ .name = "PC8736x hardware monitor",
-+ .flags = I2C_DF_NOTIFY,
-+ .attach_adapter = pc87360_attach_adapter,
-+ .detach_client = pc87360_detach_client,
-+};
-+
-+/* -- SENSORS SYSCTL START -- */
-+
-+#define PC87365_SYSCTL_ALARMS 100 /* bit field */
-+
-+#define PC87360_SYSCTL_FAN1 1101 /* Rotations/min */
-+#define PC87360_SYSCTL_FAN2 1102
-+#define PC87360_SYSCTL_FAN3 1103 /* not for PC87360/PC87363 */
-+#define PC87360_SYSCTL_FAN_DIV 1201 /* 1, 2, 4 or 8 */
-+#define PC87360_SYSCTL_FAN1_STATUS 1301 /* bit field */
-+#define PC87360_SYSCTL_FAN2_STATUS 1302
-+#define PC87360_SYSCTL_FAN3_STATUS 1303 /* not for PC87360/PC87363 */
-+#define PC87360_SYSCTL_PWM1 1401 /* 0-255 */
-+#define PC87360_SYSCTL_PWM2 1402
-+#define PC87360_SYSCTL_PWM3 1403 /* not for PC87360/PC87363 */
-+
-+#define PC87360_STATUS_FAN_READY 0x01
-+#define PC87360_STATUS_FAN_LOW 0x02
-+#define PC87360_STATUS_FAN_OVERFLOW 0x04
-+
-+#define PC87365_SYSCTL_IN0 2100 /* mV */
-+#define PC87365_SYSCTL_IN1 2101
-+#define PC87365_SYSCTL_IN2 2102
-+#define PC87365_SYSCTL_IN3 2103
-+#define PC87365_SYSCTL_IN4 2104
-+#define PC87365_SYSCTL_IN5 2105
-+#define PC87365_SYSCTL_IN6 2106
-+#define PC87365_SYSCTL_IN7 2107
-+#define PC87365_SYSCTL_IN8 2108
-+#define PC87365_SYSCTL_IN9 2109
-+#define PC87365_SYSCTL_IN10 2110
-+#define PC87365_SYSCTL_TEMP4 2111 /* not for PC87365 */
-+#define PC87365_SYSCTL_TEMP5 2112 /* not for PC87365 */
-+#define PC87365_SYSCTL_TEMP6 2113 /* not for PC87365 */
-+#define PC87365_SYSCTL_IN0_STATUS 2300 /* bit field */
-+#define PC87365_SYSCTL_IN1_STATUS 2301
-+#define PC87365_SYSCTL_IN2_STATUS 2302
-+#define PC87365_SYSCTL_IN3_STATUS 2303
-+#define PC87365_SYSCTL_IN4_STATUS 2304
-+#define PC87365_SYSCTL_IN5_STATUS 2305
-+#define PC87365_SYSCTL_IN6_STATUS 2306
-+#define PC87365_SYSCTL_IN7_STATUS 2307
-+#define PC87365_SYSCTL_IN8_STATUS 2308
-+#define PC87365_SYSCTL_IN9_STATUS 2309
-+#define PC87365_SYSCTL_IN10_STATUS 2310
-+#define PC87365_SYSCTL_TEMP4_STATUS 2311 /* not for PC87365 */
-+#define PC87365_SYSCTL_TEMP5_STATUS 2312 /* not for PC87365 */
-+#define PC87365_SYSCTL_TEMP6_STATUS 2313 /* not for PC87365 */
-+
-+#define PC87365_SYSCTL_VID 2400
-+#define PC87365_SYSCTL_VRM 2401
-+
-+#define PC87365_STATUS_IN_MIN 0x02
-+#define PC87365_STATUS_IN_MAX 0x04
-+
-+#define PC87365_SYSCTL_TEMP1 3101 /* degrees Celcius */
-+#define PC87365_SYSCTL_TEMP2 3102
-+#define PC87365_SYSCTL_TEMP3 3103 /* not for PC87365 */
-+#define PC87365_SYSCTL_TEMP1_STATUS 3301 /* bit field */
-+#define PC87365_SYSCTL_TEMP2_STATUS 3302
-+#define PC87365_SYSCTL_TEMP3_STATUS 3303 /* not for PC87365 */
-+
-+#define PC87365_STATUS_TEMP_MIN 0x02
-+#define PC87365_STATUS_TEMP_MAX 0x04
-+#define PC87365_STATUS_TEMP_CRIT 0x08
-+#define PC87365_STATUS_TEMP_OPEN 0x40
-+
-+/* -- SENSORS SYSCTL END -- */
-+
-+static ctl_table pc87360_dir_table_template[] = { /* PC87363 and PC87364 too */
-+ {PC87360_SYSCTL_FAN1, "fan1", NULL, 0, 0644, NULL,
-+ &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87360_fan},
-+ {PC87360_SYSCTL_FAN2, "fan2", NULL, 0, 0644, NULL,
-+ &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87360_fan},
-+ {PC87360_SYSCTL_FAN3, "fan3", NULL, 0, 0644, NULL,
-+ &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87360_fan},
-+ {PC87360_SYSCTL_FAN_DIV, "fan_div", NULL, 0, 0644, NULL,
-+ &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87360_fan_div},
-+ {PC87360_SYSCTL_FAN1_STATUS, "fan1_status", NULL, 0, 0444, NULL,
-+ &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87360_fan_status},
-+ {PC87360_SYSCTL_FAN2_STATUS, "fan2_status", NULL, 0, 0444, NULL,
-+ &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87360_fan_status},
-+ {PC87360_SYSCTL_FAN3_STATUS, "fan3_status", NULL, 0, 0444, NULL,
-+ &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87360_fan_status},
-+ {PC87360_SYSCTL_PWM1, "pwm1", NULL, 0, 0644, NULL,
-+ &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87360_pwm},
-+ {PC87360_SYSCTL_PWM2, "pwm2", NULL, 0, 0644, NULL,
-+ &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87360_pwm},
-+ {PC87360_SYSCTL_PWM3, "pwm3", NULL, 0, 0644, NULL,
-+ &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87360_pwm},
-+ {0}
-+};
-+
-+static ctl_table pc87365_dir_table_template[] = { /* PC87366 too */
-+ {PC87365_SYSCTL_ALARMS, "alarms", NULL, 0, 0444, NULL,
-+ &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87365_alarms},
-+ {PC87360_SYSCTL_FAN1, "fan1", NULL, 0, 0644, NULL,
-+ &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87360_fan},
-+ {PC87360_SYSCTL_FAN2, "fan2", NULL, 0, 0644, NULL,
-+ &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87360_fan},
-+ {PC87360_SYSCTL_FAN3, "fan3", NULL, 0, 0644, NULL,
-+ &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87360_fan},
-+ {PC87360_SYSCTL_FAN_DIV, "fan_div", NULL, 0, 0644, NULL,
-+ &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87360_fan_div},
-+ {PC87360_SYSCTL_FAN1_STATUS, "fan1_status", NULL, 0, 0444, NULL,
-+ &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87360_fan_status},
-+ {PC87360_SYSCTL_FAN2_STATUS, "fan2_status", NULL, 0, 0444, NULL,
-+ &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87360_fan_status},
-+ {PC87360_SYSCTL_FAN3_STATUS, "fan3_status", NULL, 0, 0444, NULL,
-+ &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87360_fan_status},
-+ {PC87360_SYSCTL_PWM1, "pwm1", NULL, 0, 0644, NULL,
-+ &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87360_pwm},
-+ {PC87360_SYSCTL_PWM2, "pwm2", NULL, 0, 0644, NULL,
-+ &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87360_pwm},
-+ {PC87360_SYSCTL_PWM3, "pwm3", NULL, 0, 0644, NULL,
-+ &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87360_pwm},
-+ {PC87365_SYSCTL_IN0, "in0", NULL, 0, 0644, NULL,
-+ &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87365_in},
-+ {PC87365_SYSCTL_IN1, "in1", NULL, 0, 0644, NULL,
-+ &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87365_in},
-+ {PC87365_SYSCTL_IN2, "in2", NULL, 0, 0644, NULL,
-+ &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87365_in},
-+ {PC87365_SYSCTL_IN3, "in3", NULL, 0, 0644, NULL,
-+ &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87365_in},
-+ {PC87365_SYSCTL_IN4, "in4", NULL, 0, 0644, NULL,
-+ &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87365_in},
-+ {PC87365_SYSCTL_IN5, "in5", NULL, 0, 0644, NULL,
-+ &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87365_in},
-+ {PC87365_SYSCTL_IN6, "in6", NULL, 0, 0644, NULL,
-+ &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87365_in},
-+ {PC87365_SYSCTL_IN7, "in7", NULL, 0, 0644, NULL,
-+ &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87365_in},
-+ {PC87365_SYSCTL_IN8, "in8", NULL, 0, 0644, NULL,
-+ &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87365_in},
-+ {PC87365_SYSCTL_IN9, "in9", NULL, 0, 0644, NULL,
-+ &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87365_in},
-+ {PC87365_SYSCTL_IN10, "in10", NULL, 0, 0644, NULL,
-+ &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87365_in},
-+ {PC87365_SYSCTL_IN0_STATUS, "in0_status", NULL, 0, 0444, NULL,
-+ &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87365_in_status},
-+ {PC87365_SYSCTL_IN1_STATUS, "in1_status", NULL, 0, 0444, NULL,
-+ &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87365_in_status},
-+ {PC87365_SYSCTL_IN2_STATUS, "in2_status", NULL, 0, 0444, NULL,
-+ &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87365_in_status},
-+ {PC87365_SYSCTL_IN3_STATUS, "in3_status", NULL, 0, 0444, NULL,
-+ &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87365_in_status},
-+ {PC87365_SYSCTL_IN4_STATUS, "in4_status", NULL, 0, 0444, NULL,
-+ &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87365_in_status},
-+ {PC87365_SYSCTL_IN5_STATUS, "in5_status", NULL, 0, 0444, NULL,
-+ &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87365_in_status},
-+ {PC87365_SYSCTL_IN6_STATUS, "in6_status", NULL, 0, 0444, NULL,
-+ &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87365_in_status},
-+ {PC87365_SYSCTL_IN7_STATUS, "in7_status", NULL, 0, 0444, NULL,
-+ &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87365_in_status},
-+ {PC87365_SYSCTL_IN8_STATUS, "in8_status", NULL, 0, 0444, NULL,
-+ &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87365_in_status},
-+ {PC87365_SYSCTL_IN9_STATUS, "in9_status", NULL, 0, 0444, NULL,
-+ &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87365_in_status},
-+ {PC87365_SYSCTL_IN10_STATUS, "in10_status", NULL, 0, 0444, NULL,
-+ &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87365_in_status},
-+ {PC87365_SYSCTL_TEMP1, "temp1", NULL, 0, 0644, NULL,
-+ &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87365_temp},
-+ {PC87365_SYSCTL_TEMP2, "temp2", NULL, 0, 0644, NULL,
-+ &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87365_temp},
-+ {PC87365_SYSCTL_TEMP3, "temp3", NULL, 0, 0644, NULL,
-+ &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87365_temp},
-+ {PC87365_SYSCTL_TEMP4, "temp4", NULL, 0, 0644, NULL,
-+ &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87365_in},
-+ {PC87365_SYSCTL_TEMP5, "temp5", NULL, 0, 0644, NULL,
-+ &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87365_in},
-+ {PC87365_SYSCTL_TEMP6, "temp6", NULL, 0, 0644, NULL,
-+ &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87365_in},
-+ {PC87365_SYSCTL_TEMP1_STATUS, "temp1_status", NULL, 0, 0444, NULL,
-+ &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87365_temp_status},
-+ {PC87365_SYSCTL_TEMP2_STATUS, "temp2_status", NULL, 0, 0444, NULL,
-+ &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87365_temp_status},
-+ {PC87365_SYSCTL_TEMP3_STATUS, "temp3_status", NULL, 0, 0444, NULL,
-+ &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87365_temp_status},
-+ {PC87365_SYSCTL_TEMP4_STATUS, "temp4_status", NULL, 0, 0444, NULL,
-+ &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87365_in_status},
-+ {PC87365_SYSCTL_TEMP5_STATUS, "temp5_status", NULL, 0, 0444, NULL,
-+ &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87365_in_status},
-+ {PC87365_SYSCTL_TEMP6_STATUS, "temp6_status", NULL, 0, 0444, NULL,
-+ &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87365_in_status},
-+ {PC87365_SYSCTL_VID, "vid", NULL, 0, 0444, NULL,
-+ &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87365_vid},
-+ {PC87365_SYSCTL_VRM, "vrm", NULL, 0, 0644, NULL,
-+ &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87365_vrm},
-+ {0}
-+};
-+
-+static int pc87360_attach_adapter(struct i2c_adapter *adapter)
-+{
-+ return i2c_detect(adapter, &addr_data, pc87360_detect);
-+}
-+
-+static int pc87360_find(u8 *devid, int *address)
-+{
-+ u16 val;
-+ int i;
-+ int nrdev; /* logical device count */
-+
-+ /* No superio_enter */
-+
-+ /* Identify device */
-+ val = superio_inb(DEVID);
-+ switch (val) {
-+ case 0xE1: /* PC87360 */
-+ case 0xE8: /* PC87363 */
-+ case 0xE4: /* PC87364 */
-+ nrdev = 1;
-+ break;
-+ case 0xE5: /* PC87365 */
-+ case 0xE9: /* PC87366 */
-+ nrdev = 3;
-+ break;
-+ default:
-+ superio_exit();
-+ return -ENODEV;
-+ }
-+ /* Remember the device id */
-+ *devid = val;
-+
-+ for (i = 0; i < nrdev; i++) {
-+ /* select logical device */
-+ superio_outb(DEV, logdev[i]);
-+
-+ val = superio_inb(ACT);
-+ if (!(val & 0x01)) {
-+ printk(KERN_INFO "pc87360.o: Device 0x%02x not "
-+ "activated\n", logdev[i]);
-+ continue;
-+ }
-+
-+ val = (superio_inb(BASE) << 8)
-+ | superio_inb(BASE + 1);
-+ if (!val) {
-+ printk(KERN_INFO "pc87360.o: Base address not set for "
-+ "device 0x%02x\n", logdev[i]);
-+ continue;
-+ }
-+
-+ address[i] = val;
-+
-+ if (i==0) { /* Fans */
-+ confreg[0] = superio_inb(0xF0);
-+ confreg[1] = superio_inb(0xF1);
-+
-+#ifdef DEBUG
-+ printk(KERN_DEBUG "pc87360.o: Fan 1: mon=%d "
-+ "ctrl=%d inv=%d\n", (confreg[0]>>2)&1,
-+ (confreg[0]>>3)&1, (confreg[0]>>4)&1);
-+ printk(KERN_DEBUG "pc87360.o: Fan 2: mon=%d "
-+ "ctrl=%d inv=%d\n", (confreg[0]>>5)&1,
-+ (confreg[0]>>6)&1, (confreg[0]>>7)&1);
-+ printk(KERN_DEBUG "pc87360.o: Fan 3: mon=%d "
-+ "ctrl=%d inv=%d\n", confreg[1]&1,
-+ (confreg[1]>>1)&1, (confreg[1]>>2)&1);
-+#endif
-+ } else if (i==1) { /* Voltages */
-+ /* Are we using thermistors? */
-+ if (*devid == 0xE9) { /* PC87366 */
-+ /* These registers are not logical-device
-+ specific, just that we won't need them if
-+ we don't use the VLM device */
-+ confreg[2] = superio_inb(0x2B);
-+ confreg[3] = superio_inb(0x25);
-+
-+ if (confreg[2] & 0x40) {
-+ printk(KERN_INFO "pc87360.o: Using "
-+ "thermistors for temperature "
-+ "monitoring\n");
-+ }
-+ if (confreg[3] & 0xE0) {
-+ printk(KERN_INFO "pc87360.o: VID "
-+ "inputs routed (mode %u)\n",
-+ confreg[3] >> 5);
-+ }
-+ }
-+ }
-+ }
-+
-+ superio_exit();
-+ return 0;
-+}
-+
-+/* We don't really care about the address.
-+ Read from extra_isa instead. */
-+int pc87360_detect(struct i2c_adapter *adapter, int address,
-+ unsigned short flags, int kind)
-+{
-+ int i;
-+ struct i2c_client *new_client;
-+ struct pc87360_data *data;
-+ int err = 0;
-+ const char *type_name = "pc87360";
-+ const char *client_name = "PC8736x chip";
-+ ctl_table *template = pc87360_dir_table_template;
-+ int use_thermistors = 0;
-+
-+ if (!i2c_is_isa_adapter(adapter)) {
-+ return 0;
-+ }
-+
-+ for (i = 0; i < 3; i++) {
-+ if (extra_isa[i]
-+ && check_region(extra_isa[i], PC87360_EXTENT)) {
-+ printk(KERN_ERR "pc87360.o: Region 0x%x-0x%x already "
-+ "in use!\n", extra_isa[i],
-+ extra_isa[i]+PC87360_EXTENT-1);
-+ return -ENODEV;
-+ }
-+ }
-+
-+ if (!(data = kmalloc(sizeof(struct pc87360_data), GFP_KERNEL))) {
-+ return -ENOMEM;
-+ }
-+ memset(data, 0x00, sizeof(struct pc87360_data));
-+
-+ new_client = &data->client;
-+ new_client->addr = address;
-+ init_MUTEX(&data->lock);
-+ new_client->data = data;
-+ new_client->adapter = adapter;
-+ new_client->driver = &pc87360_driver;
-+ new_client->flags = 0;
-+
-+ data->fannr = 2;
-+ data->innr = 0;
-+ data->tempnr = 0;
-+
-+ switch (devid) {
-+ case 0xe8:
-+ type_name = "pc87363";
-+ break;
-+ case 0xe4:
-+ type_name = "pc87364";
-+ data->fannr = 3;
-+ break;
-+ case 0xe5:
-+ type_name = "pc87365";
-+ template = pc87365_dir_table_template;
-+ data->fannr = extra_isa[0] ? 3 : 0;
-+ data->innr = extra_isa[1] ? 11 : 0;
-+ data->tempnr = extra_isa[2] ? 2 : 0;
-+ break;
-+ case 0xe9:
-+ type_name = "pc87366";
-+ template = pc87365_dir_table_template;
-+ data->fannr = extra_isa[0] ? 3 : 0;
-+ data->innr = extra_isa[1] ? 14 : 0;
-+ data->tempnr = extra_isa[2] ? 3 : 0;
-+ break;
-+ }
-+
-+ /* Retrieve the fans configuration from Super-I/O space */
-+ if (data->fannr)
-+ data->fan_conf = confreg[0] | (confreg[1] << 8);
-+
-+ for (i = 0; i < 3; i++) {
-+ if ((data->address[i] = extra_isa[i])) {
-+ request_region(extra_isa[i], PC87360_EXTENT, "pc87360");
-+ }
-+ }
-+ strcpy(new_client->name, client_name);
-+
-+ new_client->id = pc87360_id++;
-+ data->valid = 0;
-+ init_MUTEX(&data->update_lock);
-+
-+ if ((err = i2c_attach_client(new_client)))
-+ goto ERROR1;
-+
-+ /* Use the correct reference voltage
-+ Unless both the VLM and the TMS logical devices agree to
-+ use an external Vref, the internal one is used. */
-+ if (data->innr) {
-+ i = pc87360_read_value(data, LD_IN, NO_BANK,
-+ PC87365_REG_IN_CONFIG);
-+ if (data->tempnr) {
-+ i &= pc87360_read_value(data, LD_TEMP, NO_BANK,
-+ PC87365_REG_TEMP_CONFIG);
-+ }
-+ data->in_vref = (i&0x02) ? 3025 : 2966;
-+#ifdef DEBUG
-+ printk(KERN_DEBUG "pc87360.o: Using %s reference voltage\n",
-+ (i&0x02) ? "external" : "internal");
-+#endif
-+
-+ data->vid_conf = confreg[3];
-+ data->vrm = 90;
-+ }
-+
-+ /* Fan clock dividers may be needed before any data is read */
-+ for (i = 0; i < data->fannr; i++) {
-+ data->fan_status[i] = pc87360_read_value(data, LD_FAN,
-+ NO_BANK, PC87360_REG_FAN_STATUS(i));
-+ }
-+
-+ if (init > 0) {
-+ if (devid == 0xe9 && data->address[1]) /* PC87366 */
-+ use_thermistors = confreg[2] & 0x40;
-+
-+ pc87360_init_client(new_client, use_thermistors);
-+ }
-+
-+ if ((i = i2c_register_entry((struct i2c_client *) new_client,
-+ type_name, template)) < 0) {
-+ err = i;
-+ goto ERROR2;
-+ }
-+ data->sysctl_id = i;
-+
-+ return 0;
-+
-+ERROR2:
-+ i2c_detach_client(new_client);
-+ERROR1:
-+ for (i = 0; i < 3; i++) {
-+ if (data->address[i]) {
-+ release_region(data->address[i], PC87360_EXTENT);
-+ }
-+ }
-+ kfree(data);
-+ return err;
-+}
-+
-+static int pc87360_detach_client(struct i2c_client *client)
-+{
-+ struct pc87360_data *data = client->data;
-+ int i, err;
-+
-+ i2c_deregister_entry(data->sysctl_id);
-+
-+ if ((err = i2c_detach_client(client))) {
-+ printk(KERN_ERR "pc87360.o: Client deregistration failed, "
-+ "client not detached.\n");
-+ return err;
-+ }
-+
-+ for (i = 0; i < 3; i++) {
-+ if (data->address[i]) {
-+ release_region(data->address[i], PC87360_EXTENT);
-+ }
-+ }
-+ kfree(client->data);
-+
-+ return 0;
-+}
-+
-+/* ldi is the logical device index
-+ bank is for voltages and temperatures only */
-+static int pc87360_read_value(struct pc87360_data *data, u8 ldi, u8 bank,
-+ u8 reg)
-+{
-+ int res;
-+
-+ down(&(data->lock));
-+ if (bank != NO_BANK) {
-+ outb_p(bank, data->address[ldi] + PC87365_REG_BANK);
-+ }
-+ res = inb_p(data->address[ldi] + reg);
-+ up(&(data->lock));
-+ return res;
-+}
-+
-+static void pc87360_write_value(struct pc87360_data *data, u8 ldi, u8 bank,
-+ u8 reg, u8 value)
-+{
-+ down(&(data->lock));
-+ if (bank != NO_BANK) {
-+ outb_p(bank, data->address[ldi] + PC87365_REG_BANK);
-+ }
-+ outb_p(value, data->address[ldi] + reg);
-+ up(&(data->lock));
-+}
-+
-+static void pc87360_init_client(struct i2c_client *client, int use_thermistors)
-+{
-+ struct pc87360_data *data = client->data;
-+ int i, nr;
-+ const u8 init_in[14] = { 2, 2, 2, 2, 2, 2, 2, 1, 1, 3, 1, 2, 2, 2 };
-+ const u8 init_temp[3] = { 2, 2, 1 };
-+ u8 reg;
-+
-+ if (init >= 2 && data->innr) {
-+ reg = pc87360_read_value(data, LD_IN, NO_BANK,
-+ PC87365_REG_IN_CONVRATE);
-+ printk(KERN_INFO "pc87360.o: VLM conversion set to"
-+ "1s period, 160us delay\n");
-+ pc87360_write_value(data, LD_IN, NO_BANK,
-+ PC87365_REG_IN_CONVRATE,
-+ (reg & 0xC0) | 0x11);
-+ }
-+
-+ nr = data->innr < 11 ? data->innr : 11;
-+ for (i=0; i<nr; i++) {
-+ if (init >= init_in[i]) {
-+ /* Forcibly enable voltage channel */
-+ reg = pc87360_read_value(data, LD_IN, i,
-+ PC87365_REG_IN_STATUS);
-+ if (!(reg & 0x01)) {
-+#ifdef DEBUG
-+ printk(KERN_DEBUG "pc87360.o: Forcibly "
-+ "enabling in%d\n", i);
-+#endif
-+ pc87360_write_value(data, LD_IN, i,
-+ PC87365_REG_IN_STATUS,
-+ (reg & 0x68) | 0x87);
-+ }
-+ }
-+ }
-+
-+ /* We can't blindly trust the Super-I/O space configuration bit,
-+ most BIOS won't set it properly */
-+ for (i=11; i<data->innr; i++) {
-+ reg = pc87360_read_value(data, LD_IN, i,
-+ PC87365_REG_TEMP_STATUS);
-+ use_thermistors = use_thermistors || (reg & 0x01);
-+ }
-+
-+ i = use_thermistors ? 2 : 0;
-+ for (; i<data->tempnr; i++) {
-+ if (init >= init_temp[i]) {
-+ /* Forcibly enable temperature channel */
-+ reg = pc87360_read_value(data, LD_TEMP, i,
-+ PC87365_REG_TEMP_STATUS);
-+ if (!(reg & 0x01)) {
-+#ifdef DEBUG
-+ printk(KERN_DEBUG "pc87360.o: Forcibly "
-+ "enabling temp%d\n", i+1);
-+#endif
-+ pc87360_write_value(data, LD_TEMP, i,
-+ PC87365_REG_TEMP_STATUS,
-+ 0xCF);
-+ }
-+ }
-+ }
-+
-+ if (use_thermistors) {
-+ for (i=11; i<data->innr; i++) {
-+ if (init >= init_in[i]) {
-+ /* The pin may already be used by thermal
-+ diodes */
-+ reg = pc87360_read_value(data, LD_TEMP, (i-11)/2,
-+ PC87365_REG_TEMP_STATUS);
-+ if (reg & 0x01) {
-+#ifdef DEBUG
-+ printk(KERN_DEBUG "pc87360.o: Skipping "
-+ "temp%d, pin already in use by ",
-+ "temp%d\n", i-7, (i-11)/2);
-+#endif
-+ continue;
-+ }
-+
-+ /* Forcibly enable thermistor channel */
-+ reg = pc87360_read_value(data, LD_IN, i,
-+ PC87365_REG_IN_STATUS);
-+ if (!(reg & 0x01)) {
-+#ifdef DEBUG
-+ printk(KERN_DEBUG "pc87360.o: Forcibly "
-+ "enabling temp%d\n", i-7);
-+#endif
-+ pc87360_write_value(data, LD_IN, i,
-+ PC87365_REG_TEMP_STATUS,
-+ (reg & 0x60) | 0x8F);
-+ }
-+ }
-+ }
-+ }
-+
-+ if (data->innr) {
-+ reg = pc87360_read_value(data, LD_IN, NO_BANK,
-+ PC87365_REG_IN_CONFIG);
-+ if (reg & 0x01) {
-+#ifdef DEBUG
-+ printk(KERN_DEBUG "pc87360.o: Forcibly "
-+ "enabling monitoring (VLM)\n");
-+#endif
-+ pc87360_write_value(data, LD_IN, NO_BANK,
-+ PC87365_REG_IN_CONFIG,
-+ reg & 0xFE);
-+ }
-+ }
-+
-+ if (data->tempnr) {
-+ reg = pc87360_read_value(data, LD_TEMP, NO_BANK,
-+ PC87365_REG_TEMP_CONFIG);
-+ if (reg & 0x01) {
-+#ifdef DEBUG
-+ printk(KERN_DEBUG "pc87360.o: Forcibly "
-+ "enabling monitoring (TMS)\n");
-+#endif
-+ pc87360_write_value(data, LD_TEMP, NO_BANK,
-+ PC87365_REG_TEMP_CONFIG,
-+ reg & 0xFE);
-+ }
-+
-+ if (init >= 2) {
-+ /* Chip config as documented by National Semi. */
-+ pc87360_write_value(data, LD_TEMP, 0xF, 0xA, 0x08);
-+ /* We voluntarily omit the bank here, in case the
-+ sequence itself matters. It shouldn't be a problem,
-+ since nobody else is supposed to access the
-+ device at that point. */
-+ pc87360_write_value(data, LD_TEMP, NO_BANK, 0xB, 0x04);
-+ pc87360_write_value(data, LD_TEMP, NO_BANK, 0xC, 0x35);
-+ pc87360_write_value(data, LD_TEMP, NO_BANK, 0xD, 0x05);
-+ pc87360_write_value(data, LD_TEMP, NO_BANK, 0xE, 0x05);
-+ }
-+ }
-+}
-+
-+static void pc87360_autodiv(struct pc87360_data *data, int nr)
-+{
-+ u8 old_min = data->fan_min[nr];
-+
-+ /* Increase clock divider if needed and possible */
-+ if ((data->fan_status[nr] & 0x04) /* overflow flag */
-+ || (data->fan[nr] >= 224)) { /* next to overflow */
-+ if ((data->fan_status[nr] & 0x60) != 0x60) {
-+ data->fan_status[nr] += 0x20;
-+ data->fan_min[nr] >>= 1;
-+ data->fan[nr] >>= 1;
-+#ifdef DEBUG
-+ printk(KERN_DEBUG "pc87360.o: Increasing "
-+ "clock divider to %d for fan %d\n",
-+ FAN_DIV_FROM_REG(data->fan_status[nr]),
-+ nr+1);
-+#endif
-+ }
-+ } else {
-+ /* Decrease clock divider if possible */
-+ while (!(data->fan_min[nr] & 0x80) /* fan min "nails" divider */
-+ && data->fan[nr] < 85 /* bad accuracy */
-+ && (data->fan_status[nr] & 0x60) != 0x00) {
-+ data->fan_status[nr] -= 0x20;
-+ data->fan_min[nr] <<= 1;
-+ data->fan[nr] <<= 1;
-+#ifdef DEBUG
-+ printk(KERN_DEBUG "pc87360.o: Decreasing "
-+ "clock divider to %d for fan %d\n",
-+ FAN_DIV_FROM_REG(data->fan_status[nr]),
-+ nr+1);
-+#endif
-+ }
-+ }
-+
-+ /* Write new fan min if it changed */
-+ if (old_min != data->fan_min[nr]) {
-+ pc87360_write_value(data, LD_FAN, NO_BANK,
-+ PC87360_REG_FAN_MIN(nr),
-+ data->fan_min[nr]);
-+ }
-+}
-+
-+static void pc87360_update_client(struct i2c_client *client)
-+{
-+ struct pc87360_data *data = client->data;
-+ u8 i;
-+
-+ down(&data->update_lock);
-+
-+ if ((jiffies - data->last_updated > HZ * 2) ||
-+ (jiffies < data->last_updated) || !data->valid) {
-+#ifdef DEBUG
-+ printk(KERN_DEBUG "pc87360.o: Data update\n");
-+#endif
-+
-+ /* Fans */
-+ for (i = 0; i < data->fannr; i++) {
-+ if (FAN_CONFIG_MONITOR(data->fan_conf, i)) {
-+ data->fan_status[i] = pc87360_read_value(data,
-+ LD_FAN, NO_BANK,
-+ PC87360_REG_FAN_STATUS(i));
-+ data->fan[i] = pc87360_read_value(data, LD_FAN,
-+ NO_BANK, PC87360_REG_FAN(i));
-+ data->fan_min[i] = pc87360_read_value(data,
-+ LD_FAN, NO_BANK,
-+ PC87360_REG_FAN_MIN(i));
-+ /* Change clock divider if needed */
-+ pc87360_autodiv(data, i);
-+ /* Clear bits and write new divider */
-+ pc87360_write_value(data, LD_FAN, NO_BANK,
-+ PC87360_REG_FAN_STATUS(i),
-+ data->fan_status[i]);
-+ }
-+ data->pwm[i] = pc87360_read_value(data, LD_FAN,
-+ NO_BANK, PC87360_REG_PWM(i));
-+ }
-+
-+ /* Voltages */
-+ for (i = 0; i < data->innr; i++) {
-+ data->in_status[i] = pc87360_read_value(data, LD_IN, i,
-+ PC87365_REG_IN_STATUS);
-+ /* Clear bits */
-+ pc87360_write_value(data, LD_IN, i,
-+ PC87365_REG_IN_STATUS,
-+ data->in_status[i]);
-+ if ((data->in_status[i] & 0x81) == 0x81) {
-+ data->in[i] = pc87360_read_value(data, LD_IN,
-+ i, PC87365_REG_IN);
-+ }
-+ if (data->in_status[i] & 0x01) {
-+ data->in_min[i] = pc87360_read_value(data,
-+ LD_IN, i,
-+ PC87365_REG_IN_MIN);
-+ data->in_max[i] = pc87360_read_value(data,
-+ LD_IN, i,
-+ PC87365_REG_IN_MAX);
-+ if (i >= 11)
-+ data->in_crit[i-11] =
-+ pc87360_read_value(data, LD_IN,
-+ i, PC87365_REG_TEMP_CRIT);
-+ }
-+ }
-+ if (data->innr) {
-+ data->in_alarms = pc87360_read_value(data, LD_IN,
-+ NO_BANK, PC87365_REG_IN_ALARMS1)
-+ | ((pc87360_read_value(data, LD_IN,
-+ NO_BANK, PC87365_REG_IN_ALARMS2)
-+ & 0x07) << 8);
-+ data->vid = (data->vid_conf & 0xE0) ?
-+ pc87360_read_value(data, LD_IN,
-+ NO_BANK, PC87365_REG_VID) : 0x1F;
-+ }
-+
-+ /* Temperatures */
-+ for (i = 0; i < data->tempnr; i++) {
-+ data->temp_status[i] = pc87360_read_value(data,
-+ LD_TEMP, i,
-+ PC87365_REG_TEMP_STATUS);
-+ /* Clear bits */
-+ pc87360_write_value(data, LD_TEMP, i,
-+ PC87365_REG_TEMP_STATUS,
-+ data->temp_status[i]);
-+ if ((data->temp_status[i] & 0x81) == 0x81) {
-+ data->temp[i] = pc87360_read_value(data,
-+ LD_TEMP, i,
-+ PC87365_REG_TEMP);
-+ }
-+ if (data->temp_status[i] & 0x01) {
-+ data->temp_min[i] = pc87360_read_value(data,
-+ LD_TEMP, i,
-+ PC87365_REG_TEMP_MIN);
-+ data->temp_max[i] = pc87360_read_value(data,
-+ LD_TEMP, i,
-+ PC87365_REG_TEMP_MAX);
-+ data->temp_crit[i] = pc87360_read_value(data,
-+ LD_TEMP, i,
-+ PC87365_REG_TEMP_CRIT);
-+ }
-+ }
-+ if (data->tempnr) {
-+ data->temp_alarms = pc87360_read_value(data, LD_TEMP,
-+ NO_BANK, PC87365_REG_TEMP_ALARMS)
-+ & 0x3F;
-+ }
-+
-+ data->last_updated = jiffies;
-+ data->valid = 1;
-+ }
-+
-+ up(&data->update_lock);
-+}
-+
-+
-+void pc87365_alarms(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct pc87360_data *data = client->data;
-+
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 0;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ pc87360_update_client(client);
-+ results[0] = data->in_alarms;
-+ results[1] = data->temp_alarms;
-+ *nrels_mag = 2;
-+ }
-+}
-+
-+void pc87360_fan(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct pc87360_data *data = client->data;
-+ int nr = ctl_name - PC87360_SYSCTL_FAN1;
-+
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 0;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ pc87360_update_client(client);
-+ results[0] = FAN_FROM_REG(data->fan_min[nr],
-+ FAN_DIV_FROM_REG(data->fan_status[nr]));
-+ results[1] = FAN_FROM_REG(data->fan[nr],
-+ FAN_DIV_FROM_REG(data->fan_status[nr]));
-+ *nrels_mag = 2;
-+ }
-+ /* We ignore National's recommendation */
-+ else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ if (nr >= data->fannr)
-+ return;
-+ if (*nrels_mag >= 1) {
-+ int fan_min = FAN_TO_REG(results[0],
-+ FAN_DIV_FROM_REG(data->fan_status[nr]));
-+ /* If it wouldn't fit, change clock divisor */
-+ while (fan_min > 255
-+ && (data->fan_status[nr] & 0x60) != 0x60) {
-+ fan_min >>= 1;
-+ data->fan[nr] >>= 1;
-+ data->fan_status[nr] += 0x20;
-+ }
-+ data->fan_min[nr] = fan_min > 255 ? 255 : fan_min;
-+ pc87360_write_value(data, LD_FAN, NO_BANK,
-+ PC87360_REG_FAN_MIN(nr),
-+ data->fan_min[nr]);
-+ /* Write new divider, preserve alarm bits */
-+ pc87360_write_value(data, LD_FAN, NO_BANK,
-+ PC87360_REG_FAN_STATUS(nr),
-+ data->fan_status[nr] & 0xF9);
-+ }
-+ }
-+}
-+
-+void pc87360_fan_div(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results)
-+{
-+ struct pc87360_data *data = client->data;
-+ int i;
-+
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 0;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ pc87360_update_client(client);
-+ for (i = 0; i < data->fannr; i++) {
-+ results[i] = FAN_DIV_FROM_REG(data->fan_status[i]);
-+ }
-+ for (; i < 3; i++) {
-+ results[i] = 0;
-+ }
-+ *nrels_mag = 3;
-+ }
-+}
-+
-+void pc87360_pwm(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct pc87360_data *data = client->data;
-+ int nr = ctl_name - PC87360_SYSCTL_PWM1;
-+
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 0;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ pc87360_update_client(client);
-+ results[0] = PWM_FROM_REG(data->pwm[nr],
-+ FAN_CONFIG_INVERT(data->fan_conf, nr));
-+ results[1] = FAN_CONFIG_CONTROL(data->fan_conf, nr);
-+ *nrels_mag = 2;
-+ }
-+ else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ if (nr >= data->fannr)
-+ return;
-+ if (*nrels_mag >= 1) {
-+ data->pwm[nr] = PWM_TO_REG(results[0],
-+ FAN_CONFIG_INVERT(data->fan_conf, nr));
-+ pc87360_write_value(data, LD_FAN, NO_BANK,
-+ PC87360_REG_PWM(nr),
-+ data->pwm[nr]);
-+ }
-+ }
-+}
-+
-+void pc87360_fan_status(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct pc87360_data *data = client->data;
-+ int nr = ctl_name - PC87360_SYSCTL_FAN1_STATUS;
-+
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 0;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ pc87360_update_client(client);
-+ results[0] = FAN_STATUS_FROM_REG(data->fan_status[nr]);
-+ *nrels_mag = 1;
-+ }
-+}
-+
-+void pc87365_in(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct pc87360_data *data = client->data;
-+ int nr = ctl_name - PC87365_SYSCTL_IN0;
-+
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 3;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ pc87360_update_client(client);
-+ results[0] = IN_FROM_REG(data->in_min[nr], data->in_vref);
-+ results[1] = IN_FROM_REG(data->in_max[nr], data->in_vref);
-+ if (nr < 11) {
-+ *nrels_mag = 3;
-+ } else {
-+ results[2] = IN_FROM_REG(data->in_crit[nr-11],
-+ data->in_vref);
-+ *nrels_mag = 4;
-+ }
-+ results[(*nrels_mag)-1] = IN_FROM_REG(data->in[nr],
-+ data->in_vref);
-+ }
-+ else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ if (*nrels_mag >= 1) {
-+ data->in_min[nr] = IN_TO_REG(results[0],
-+ data->in_vref);
-+ pc87360_write_value(data, LD_IN, nr,
-+ PC87365_REG_IN_MIN,
-+ data->in_min[nr]);
-+ }
-+ if (*nrels_mag >= 2) {
-+ data->in_max[nr] = IN_TO_REG(results[1],
-+ data->in_vref);
-+ pc87360_write_value(data, LD_IN, nr,
-+ PC87365_REG_IN_MAX,
-+ data->in_max[nr]);
-+ }
-+ if (*nrels_mag >= 3 && nr >= 11) {
-+ data->in_crit[nr-11] = IN_TO_REG(results[2],
-+ data->in_vref);
-+ pc87360_write_value(data, LD_IN, nr,
-+ PC87365_REG_TEMP_CRIT,
-+ data->in_crit[nr-11]);
-+ }
-+ }
-+}
-+
-+void pc87365_in_status(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct pc87360_data *data = client->data;
-+ int nr = ctl_name - PC87365_SYSCTL_IN0_STATUS;
-+
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 0;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ pc87360_update_client(client);
-+ results[0] = data->in_status[nr];
-+ *nrels_mag = 1;
-+ }
-+}
-+
-+void pc87365_vid(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct pc87360_data *data = client->data;
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 3;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ pc87360_update_client(client);
-+ results[0] = vid_from_reg(data->vid & 0x1f, data->vrm);
-+ *nrels_mag = 1;
-+ }
-+}
-+
-+void pc87365_vrm(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct pc87360_data *data = client->data;
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 1;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ results[0] = data->vrm;
-+ *nrels_mag = 1;
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ if (*nrels_mag >= 1)
-+ data->vrm = results[0];
-+ }
-+}
-+
-+void pc87365_temp(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct pc87360_data *data = client->data;
-+ int nr = ctl_name - PC87365_SYSCTL_TEMP1;
-+
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 0;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ pc87360_update_client(client);
-+ results[0] = TEMP_FROM_REG(data->temp_max[nr]);
-+ results[1] = TEMP_FROM_REG(data->temp_min[nr]);
-+ results[2] = TEMP_FROM_REG(data->temp_crit[nr]);
-+ results[3] = TEMP_FROM_REG(data->temp[nr]);
-+ *nrels_mag = 4;
-+ }
-+ else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ if (nr >= data->tempnr)
-+ return;
-+ if (*nrels_mag >= 1) {
-+ data->temp_max[nr] = TEMP_TO_REG(results[0]);
-+ pc87360_write_value(data, LD_TEMP, nr,
-+ PC87365_REG_TEMP_MAX,
-+ data->temp_max[nr]);
-+ }
-+ if (*nrels_mag >= 2) {
-+ data->temp_min[nr] = TEMP_TO_REG(results[1]);
-+ pc87360_write_value(data, LD_TEMP, nr,
-+ PC87365_REG_TEMP_MIN,
-+ data->temp_min[nr]);
-+ }
-+ if (*nrels_mag >= 3) {
-+ data->temp_crit[nr] = TEMP_TO_REG(results[2]);
-+ pc87360_write_value(data, LD_TEMP, nr,
-+ PC87365_REG_TEMP_CRIT,
-+ data->temp_crit[nr]);
-+ }
-+ }
-+}
-+
-+void pc87365_temp_status(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct pc87360_data *data = client->data;
-+ int nr = ctl_name - PC87365_SYSCTL_TEMP1_STATUS;
-+
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 0;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ pc87360_update_client(client);
-+ results[0] = data->temp_status[nr];
-+ *nrels_mag = 1;
-+ }
-+}
-+
-+
-+static int __init pc87360_init(void)
-+{
-+ int i;
-+
-+ printk(KERN_INFO "pc87360.o version %s (%s)\n", LM_VERSION, LM_DATE);
-+
-+ if (pc87360_find(&devid, extra_isa)) {
-+ printk(KERN_WARNING "pc87360.o: PC8736x not detected, "
-+ "module not inserted.\n");
-+ return -ENODEV;
-+ }
-+
-+ /* Arbitrarily pick one of the addresses */
-+ for (i = 0; i < 3; i++) {
-+ if (extra_isa[i] != 0x0000) {
-+ normal_isa[0] = extra_isa[i];
-+ break;
-+ }
-+ }
-+
-+ if (normal_isa[0] == 0x0000) {
-+ printk(KERN_WARNING "pc87360.o: No active logical device, "
-+ "module not inserted.\n");
-+ return -ENODEV;
-+
-+ }
-+
-+ return i2c_add_driver(&pc87360_driver);
-+}
-+
-+static void __exit pc87360_exit(void)
-+{
-+ i2c_del_driver(&pc87360_driver);
-+}
-+
-+
-+MODULE_AUTHOR("Jean Delvare <khali@linux-fr.org>");
-+MODULE_DESCRIPTION("PC8736x hardware monitor");
-+MODULE_LICENSE("GPL");
-+
-+module_init(pc87360_init);
-+module_exit(pc87360_exit);
---- linux-old/drivers/sensors/pcf8574.c Thu Jan 1 00:00:00 1970
-+++ linux/drivers/sensors/pcf8574.c Mon Dec 13 20:18:51 2004
-@@ -0,0 +1,309 @@
-+/*
-+ pcf8574.c - Part of lm_sensors, Linux kernel modules for hardware
-+ monitoring
-+ Copyright (c) 2000 Frodo Looijaard <frodol@dds.nl>,
-+ Philip Edelbrock <phil@netroedge.com>,
-+ Dan Eaton <dan.eaton@rocketlogix.com>
-+
-+ 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., 675 Mass Ave, Cambridge, MA 02139, USA.
-+*/
-+
-+/* A few notes about the PCF8574:
-+
-+* The PCF8574 is an 8-bit I/O expander for the I2C bus produced by
-+ Philips Semiconductors. It is designed to provide a byte I2C
-+ interface to up to 8 separate devices.
-+
-+* The PCF8574 appears as a very simple SMBus device which can be
-+ read from or written to with SMBUS byte read/write accesses.
-+
-+* Because of the general purpose nature of this device, it will most
-+ likely be necessary to customize the /proc interface to suit the
-+ specific application.
-+
-+ --Dan
-+
-+*/
-+
-+
-+#include <linux/module.h>
-+#include <linux/slab.h>
-+#include <linux/i2c.h>
-+#include <linux/i2c-proc.h>
-+#include <linux/init.h>
-+#define LM_DATE "20041007"
-+#define LM_VERSION "2.8.8"
-+
-+MODULE_LICENSE("GPL");
-+
-+/* Addresses to scan */
-+static unsigned short normal_i2c[] = { SENSORS_I2C_END };
-+static unsigned short normal_i2c_range[] = { 0x20, 0x27, 0x38, 0x3f, SENSORS_I2C_END };
-+static unsigned int normal_isa[] = { SENSORS_ISA_END };
-+static unsigned int normal_isa_range[] = { SENSORS_ISA_END };
-+
-+/* Insmod parameters */
-+SENSORS_INSMOD_2(pcf8574, pcf8574a);
-+
-+/* The PCF8574 registers */
-+
-+/* (No registers. [Wow! This thing is SIMPLE!] ) */
-+
-+/* Initial values */
-+#define PCF8574_INIT 255 /* All outputs on (input mode) */
-+
-+/* Each client has this additional data */
-+struct pcf8574_data {
-+ struct i2c_client client;
-+ int sysctl_id;
-+
-+ struct semaphore update_lock;
-+
-+ u8 read, write; /* Register values */
-+};
-+
-+static int pcf8574_attach_adapter(struct i2c_adapter *adapter);
-+static int pcf8574_detect(struct i2c_adapter *adapter, int address,
-+ unsigned short flags, int kind);
-+static int pcf8574_detach_client(struct i2c_client *client);
-+
-+static void pcf8574_read(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void pcf8574_write(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void pcf8574_update_client(struct i2c_client *client);
-+static void pcf8574_init_client(struct i2c_client *client);
-+
-+/* This is the driver that will be inserted */
-+static struct i2c_driver pcf8574_driver = {
-+ .owner = THIS_MODULE,
-+ .name = "PCF8574 sensor chip driver",
-+ .id = I2C_DRIVERID_PCF8574,
-+ .flags = I2C_DF_NOTIFY,
-+ .attach_adapter = pcf8574_attach_adapter,
-+ .detach_client = pcf8574_detach_client,
-+};
-+
-+
-+/* -- SENSORS SYSCTL START -- */
-+#define PCF8574_SYSCTL_READ 1000
-+#define PCF8574_SYSCTL_WRITE 1001
-+
-+/* -- SENSORS SYSCTL END -- */
-+
-+/* These files are created for each detected PCF8574. This is just a template;
-+ though at first sight, you might think we could use a statically
-+ allocated list, we need some way to get back to the parent - which
-+ is done through one of the 'extra' fields which are initialized
-+ when a new copy is allocated. */
-+static ctl_table pcf8574_dir_table_template[] = {
-+ {PCF8574_SYSCTL_READ, "read", NULL, 0, 0444, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &pcf8574_read},
-+ {PCF8574_SYSCTL_WRITE, "write", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &pcf8574_write},
-+ {0}
-+};
-+
-+static int pcf8574_id = 0;
-+
-+static int pcf8574_attach_adapter(struct i2c_adapter *adapter)
-+{
-+ return i2c_detect(adapter, &addr_data, pcf8574_detect);
-+}
-+
-+/* This function is called by i2c_detect */
-+int pcf8574_detect(struct i2c_adapter *adapter, int address,
-+ unsigned short flags, int kind)
-+{
-+ int i;
-+ struct i2c_client *new_client;
-+ struct pcf8574_data *data;
-+ int err = 0;
-+ const char *type_name, *client_name;
-+
-+ /* Make sure we aren't probing the ISA bus!! This is just a safety check
-+ at this moment; i2c_detect really won't call us. */
-+#ifdef DEBUG
-+ if (i2c_is_isa_adapter(adapter)) {
-+ printk
-+ ("pcf8574.o: pcf8574_detect called for an ISA bus adapter?!?\n");
-+ return 0;
-+ }
-+#endif
-+
-+ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE))
-+ goto ERROR0;
-+
-+ /* OK. For now, we presume we have a valid client. We now create the
-+ client structure, even though we cannot fill it completely yet. */
-+ if (!(data = kmalloc(sizeof(struct pcf8574_data), GFP_KERNEL))) {
-+ err = -ENOMEM;
-+ goto ERROR0;
-+ }
-+
-+ new_client = &data->client;
-+ new_client->addr = address;
-+ new_client->data = data;
-+ new_client->adapter = adapter;
-+ new_client->driver = &pcf8574_driver;
-+ new_client->flags = 0;
-+
-+ /* Now, we would do the remaining detection. But the PCF8574 is plainly
-+ impossible to detect! Stupid chip. */
-+
-+ /* Determine the chip type */
-+ if (kind <= 0) {
-+ if (address >= 0x38 && address <= 0x3f)
-+ kind = pcf8574a;
-+ else
-+ kind = pcf8574;
-+ }
-+
-+ if (kind == pcf8574a) {
-+ type_name = "pcf8574a";
-+ client_name = "PCF8574A chip";
-+ } else {
-+ type_name = "pcf8574a";
-+ client_name = "PCF8574A chip";
-+ }
-+
-+ /* Fill in the remaining client fields and put it into the global list */
-+ strcpy(new_client->name, client_name);
-+
-+ new_client->id = pcf8574_id++;
-+ init_MUTEX(&data->update_lock);
-+
-+ /* Tell the I2C layer a new client has arrived */
-+ if ((err = i2c_attach_client(new_client)))
-+ goto ERROR1;
-+
-+ /* Register a new directory entry with module sensors */
-+ if ((i = i2c_register_entry(new_client, type_name,
-+ pcf8574_dir_table_template)) < 0) {
-+ err = i;
-+ goto ERROR2;
-+ }
-+ data->sysctl_id = i;
-+
-+ /* Initialize the PCF8574 chip */
-+ pcf8574_init_client(new_client);
-+ return 0;
-+
-+/* OK, this is not exactly good programming practice, usually. But it is
-+ very code-efficient in this case. */
-+
-+ ERROR2:
-+ i2c_detach_client(new_client);
-+ ERROR1:
-+ kfree(data);
-+ ERROR0:
-+ return err;
-+}
-+
-+static int pcf8574_detach_client(struct i2c_client *client)
-+{
-+ int err;
-+
-+ i2c_deregister_entry(((struct pcf8574_data *) (client->data))->
-+ sysctl_id);
-+
-+ if ((err = i2c_detach_client(client))) {
-+ printk("pcf8574.o: Client deregistration failed, "
-+ "client not detached.\n");
-+ return err;
-+ }
-+
-+ kfree(client->data);
-+
-+ return 0;
-+}
-+
-+/* Called when we have found a new PCF8574. */
-+static void pcf8574_init_client(struct i2c_client *client)
-+{
-+ struct pcf8574_data *data = client->data;
-+ data->write = PCF8574_INIT;
-+ i2c_smbus_write_byte(client, data->write);
-+}
-+
-+
-+static void pcf8574_update_client(struct i2c_client *client)
-+{
-+ struct pcf8574_data *data = client->data;
-+
-+ down(&data->update_lock);
-+
-+#ifdef DEBUG
-+ printk("Starting pcf8574 update\n");
-+#endif
-+
-+ data->read = i2c_smbus_read_byte(client);
-+
-+ up(&data->update_lock);
-+}
-+
-+
-+void pcf8574_read(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results)
-+{
-+ struct pcf8574_data *data = client->data;
-+
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 0;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ pcf8574_update_client(client);
-+ results[0] = data->read;
-+ *nrels_mag = 1;
-+ }
-+}
-+void pcf8574_write(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results)
-+{
-+ struct pcf8574_data *data = client->data;
-+
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 0;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ results[0] = data->write;
-+ *nrels_mag = 1;
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ if (*nrels_mag >= 1) {
-+ data->write = results[0];
-+ i2c_smbus_write_byte(client, data->write);
-+ }
-+ }
-+}
-+
-+
-+static int __init sm_pcf8574_init(void)
-+{
-+ printk("pcf8574.o version %s (%s)\n", LM_VERSION, LM_DATE);
-+ return i2c_add_driver(&pcf8574_driver);
-+}
-+
-+static void __exit sm_pcf8574_exit(void)
-+{
-+ i2c_del_driver(&pcf8574_driver);
-+}
-+
-+
-+MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl>, "
-+ "Philip Edelbrock <phil@netroedge.com>, "
-+ "Dan Eaton <dan.eaton@rocketlogix.com> and "
-+ "Aurelien Jarno <aurelien@aurel32.net>");
-+MODULE_DESCRIPTION("PCF8574 driver");
-+
-+module_init(sm_pcf8574_init);
-+module_exit(sm_pcf8574_exit);
---- linux-old/drivers/sensors/pcf8591.c Thu Jan 1 00:00:00 1970
-+++ linux/drivers/sensors/pcf8591.c Mon Dec 13 20:18:51 2004
-@@ -0,0 +1,448 @@
-+/*
-+ pcf8591.c - Part of lm_sensors, Linux kernel modules for hardware
-+ monitoring
-+ Copyright (c) 2001 Aurelien Jarno <aurelien@aurel32.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.
-+
-+ 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., 675 Mass Ave, Cambridge, MA 02139, USA.
-+*/
-+
-+#include <linux/module.h>
-+#include <linux/slab.h>
-+#include <linux/i2c.h>
-+#include <linux/i2c-proc.h>
-+#include <linux/init.h>
-+#define LM_DATE "20041007"
-+#define LM_VERSION "2.8.8"
-+
-+/* Addresses to scan */
-+static unsigned short normal_i2c[] = { SENSORS_I2C_END };
-+static unsigned short normal_i2c_range[] = { 0x48, 0x4f, SENSORS_I2C_END };
-+static unsigned int normal_isa[] = { SENSORS_ISA_END };
-+static unsigned int normal_isa_range[] = { SENSORS_ISA_END };
-+
-+/* Insmod parameters */
-+SENSORS_INSMOD_1(pcf8591);
-+
-+/* The PCF8591 control byte */
-+/* 7 6 5 4 3 2 1 0 */
-+/* | 0 |AOEF| AIP | 0 |AINC| AICH | */
-+
-+#define PCF8591_CONTROL_BYTE_AOEF 0x40 /* Analog Output Enable Flag */
-+ /* (analog output active if 1) */
-+
-+#define PCF8591_CONTROL_BYTE_AIP 0x30 /* Analog Input Programming */
-+ /* 0x00 = four single ended inputs */
-+ /* 0x10 = three differential inputs */
-+ /* 0x20 = single ended and differential mixed */
-+ /* 0x30 = two differential inputs */
-+
-+#define PCF8591_CONTROL_BYTE_AINC 0x04 /* Autoincrement Flag */
-+ /* (switch on if 1) */
-+
-+#define PCF8591_CONTROL_BYTE_AICH 0x03 /* Analog Output Enable Flag */
-+ /* 0x00 = channel 0 */
-+ /* 0x01 = channel 1 */
-+ /* 0x02 = channel 2 */
-+ /* 0x03 = channel 3 */
-+
-+
-+/* Initial values */
-+#define PCF8591_INIT_CONTROL_BYTE (PCF8591_CONTROL_BYTE_AOEF | PCF8591_CONTROL_BYTE_AINC)
-+ /* DAC out enabled, four single ended inputs, autoincrement */
-+
-+#define PCF8591_INIT_AOUT 0 /* DAC out = 0 */
-+
-+
-+/* Conversions. */
-+#define REG_TO_SIGNED(reg) (reg & 0x80)?(reg - 256):(reg)
-+ /* Convert signed 8 bit value to signed value */
-+
-+
-+struct pcf8591_data {
-+ struct i2c_client client;
-+ int sysctl_id;
-+
-+ struct semaphore update_lock;
-+ char valid; /* !=0 if following fields are valid */
-+ unsigned long last_updated; /* In jiffies */
-+
-+ u8 control_byte;
-+ u8 ch[4];
-+ u8 aout;
-+};
-+
-+static int pcf8591_attach_adapter(struct i2c_adapter *adapter);
-+static int pcf8591_detect(struct i2c_adapter *adapter, int address,
-+ unsigned short flags, int kind);
-+static int pcf8591_detach_client(struct i2c_client *client);
-+
-+static void pcf8591_update_client(struct i2c_client *client);
-+static void pcf8591_init_client(struct i2c_client *client);
-+
-+static void pcf8591_ain_conf(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void pcf8591_ain(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void pcf8591_aout_enable(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void pcf8591_aout(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+
-+
-+/* This is the driver that will be inserted */
-+static struct i2c_driver pcf8591_driver = {
-+ .owner = THIS_MODULE,
-+ .name = "PCF8591 sensor chip driver",
-+ .id = I2C_DRIVERID_PCF8591,
-+ .flags = I2C_DF_NOTIFY,
-+ .attach_adapter = pcf8591_attach_adapter,
-+ .detach_client = pcf8591_detach_client,
-+};
-+
-+static int pcf8591_id = 0;
-+
-+/* The /proc/sys entries */
-+
-+/* -- SENSORS SYSCTL START -- */
-+#define PCF8591_SYSCTL_AIN_CONF 1000 /* Analog input configuration */
-+#define PCF8591_SYSCTL_CH0 1001 /* Input channel 1 */
-+#define PCF8591_SYSCTL_CH1 1002 /* Input channel 2 */
-+#define PCF8591_SYSCTL_CH2 1003 /* Input channel 3 */
-+#define PCF8591_SYSCTL_CH3 1004 /* Input channel 4 */
-+#define PCF8591_SYSCTL_AOUT_ENABLE 1005 /* Analog output enable flag */
-+#define PCF8591_SYSCTL_AOUT 1006 /* Analog output */
-+/* -- SENSORS SYSCTL END -- */
-+
-+/* These files are created for each detected PCF8591. This is just a template;
-+ though at first sight, you might think we could use a statically
-+ allocated list, we need some way to get back to the parent - which
-+ is done through one of the 'extra' fields which are initialized
-+ when a new copy is allocated. */
-+static ctl_table pcf8591_dir_table_template[] = {
-+ {PCF8591_SYSCTL_AIN_CONF, "ain_conf", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &pcf8591_ain_conf},
-+ {PCF8591_SYSCTL_CH0, "ch0", NULL, 0, 0444, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &pcf8591_ain},
-+ {PCF8591_SYSCTL_CH1, "ch1", NULL, 0, 0444, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &pcf8591_ain},
-+ {PCF8591_SYSCTL_CH2, "ch2", NULL, 0, 0444, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &pcf8591_ain},
-+ {PCF8591_SYSCTL_CH3, "ch3", NULL, 0, 0444, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &pcf8591_ain},
-+ {PCF8591_SYSCTL_AOUT_ENABLE, "aout_enable", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &pcf8591_aout_enable},
-+ {PCF8591_SYSCTL_AOUT, "aout", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &pcf8591_aout},
-+ {0}
-+};
-+
-+
-+/* This function is called when:
-+ * pcf8591_driver is inserted (when this module is loaded), for each
-+ available adapter
-+ * when a new adapter is inserted (and pcf8591_driver is still present) */
-+static int pcf8591_attach_adapter(struct i2c_adapter *adapter)
-+{
-+ return i2c_detect(adapter, &addr_data, pcf8591_detect);
-+}
-+
-+/* This function is called by i2c_detect */
-+int pcf8591_detect(struct i2c_adapter *adapter, int address,
-+ unsigned short flags, int kind)
-+{
-+ int i;
-+ struct i2c_client *new_client;
-+ struct pcf8591_data *data;
-+ int err = 0;
-+
-+ const char *type_name = "";
-+ const char *client_name = "";
-+
-+ /* Make sure we aren't probing the ISA bus!! This is just a safety check at this moment; i2c_detect really won't call us. */
-+#ifdef DEBUG
-+ if (i2c_is_isa_adapter(adapter)) {
-+ printk
-+ (KERN_ERR "pcf8591.o: pcf8591_detect called for an ISA bus adapter?!?\n");
-+ return 0;
-+ }
-+#endif
-+
-+ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE
-+ | I2C_FUNC_SMBUS_WRITE_BYTE_DATA))
-+ goto ERROR0;
-+
-+ /* OK. For now, we presume we have a valid client. We now create the
-+ client structure, even though we cannot fill it completely yet. */
-+ if (!(data = kmalloc(sizeof(struct pcf8591_data), GFP_KERNEL))) {
-+ err = -ENOMEM;
-+ goto ERROR0;
-+ }
-+
-+ new_client = &data->client;
-+ new_client->addr = address;
-+ new_client->data = data;
-+ new_client->adapter = adapter;
-+ new_client->driver = &pcf8591_driver;
-+ new_client->flags = 0;
-+
-+ /* Now, we would do the remaining detection. But the PCF8591 is plainly
-+ impossible to detect! Stupid chip. */
-+
-+ /* Determine the chip type - only one kind supported! */
-+ if (kind <= 0)
-+ kind = pcf8591;
-+
-+ type_name = "pcf8591";
-+ client_name = "PCF8591 chip";
-+
-+ /* Fill in the remaining client fields and put it into the global list */
-+ strcpy(new_client->name, client_name);
-+
-+ new_client->id = pcf8591_id++;
-+ data->valid = 0;
-+ init_MUTEX(&data->update_lock);
-+
-+ /* Tell the I2C layer a new client has arrived */
-+ if ((err = i2c_attach_client(new_client)))
-+ goto ERROR3;
-+
-+ /* Register a new directory entry with module sensors */
-+ if ((i = i2c_register_entry(new_client,
-+ type_name,
-+ pcf8591_dir_table_template)) < 0) {
-+ err = i;
-+ goto ERROR4;
-+ }
-+ data->sysctl_id = i;
-+
-+ /* Initialize the PCF8591 chip */
-+ pcf8591_init_client(new_client);
-+ return 0;
-+
-+/* OK, this is not exactly good programming practice, usually. But it is
-+ very code-efficient in this case. */
-+
-+ ERROR4:
-+ i2c_detach_client(new_client);
-+ ERROR3:
-+ kfree(data);
-+ ERROR0:
-+ return err;
-+}
-+
-+static int pcf8591_detach_client(struct i2c_client *client)
-+{
-+ int err;
-+
-+ i2c_deregister_entry(((struct pcf8591_data *) (client->data))->
-+ sysctl_id);
-+
-+ if ((err = i2c_detach_client(client))) {
-+ printk
-+ (KERN_ERR "pcf8591.o: Client deregistration failed, client not detached.\n");
-+ return err;
-+ }
-+
-+ kfree(client->data);
-+
-+ return 0;
-+}
-+
-+/* Called when we have found a new PCF8591. */
-+static void pcf8591_init_client(struct i2c_client *client)
-+{
-+ struct pcf8591_data *data = client->data;
-+ data->control_byte = PCF8591_INIT_CONTROL_BYTE;
-+ data->aout = PCF8591_INIT_AOUT;
-+
-+ i2c_smbus_write_byte_data(client, data->control_byte, data->aout);
-+}
-+
-+static void pcf8591_update_client(struct i2c_client *client)
-+{
-+ struct pcf8591_data *data = client->data;
-+
-+ down(&data->update_lock);
-+
-+ if ((jiffies - data->last_updated > HZ + HZ / 2) ||
-+ (jiffies < data->last_updated) || !data->valid) {
-+
-+#ifdef DEBUG
-+ printk(KERN_DEBUG "Starting pcf8591 update\n");
-+#endif
-+
-+ i2c_smbus_write_byte(client, data->control_byte);
-+ i2c_smbus_read_byte(client); /* The first byte transmitted contains the */
-+ /* conversion code of the previous read cycled */
-+ /* FLUSH IT ! */
-+
-+
-+ /* Number of byte to read to signed depend on the analog input mode */
-+ data->ch[0] = i2c_smbus_read_byte(client);
-+ data->ch[1] = i2c_smbus_read_byte(client);
-+ /* In all case, read at least two values */
-+
-+ if ((data->control_byte & PCF8591_CONTROL_BYTE_AIP) != 0x30)
-+ data->ch[2] = i2c_smbus_read_byte(client);
-+ /* Read the third value if not in "two differential inputs" mode */
-+
-+ if ((data->control_byte & PCF8591_CONTROL_BYTE_AIP) == 0x00)
-+ data->ch[3] = i2c_smbus_read_byte(client);
-+ /* Read the fourth value only in "four single ended inputs" mode */
-+
-+ data->last_updated = jiffies;
-+ data->valid = 1;
-+ }
-+
-+ up(&data->update_lock);
-+}
-+
-+/* The next few functions are the call-back functions of the /proc/sys and
-+ sysctl files. Which function is used is defined in the ctl_table in
-+ the extra1 field. */
-+void pcf8591_ain_conf(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct pcf8591_data *data = client->data;
-+
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 0;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ results[0] = (data->control_byte & PCF8591_CONTROL_BYTE_AIP) >> 4;
-+ *nrels_mag = 1;
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ if (*nrels_mag >= 1) {
-+ if (results[0] >= 0 && results[0] <= 3)
-+ {
-+ data->control_byte &= ~PCF8591_CONTROL_BYTE_AIP;
-+ data->control_byte |= (results[0] << 4);
-+ i2c_smbus_write_byte(client, data->control_byte);
-+ data->valid = 0;
-+ }
-+ }
-+ }
-+}
-+
-+void pcf8591_ain(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct pcf8591_data *data = client->data;
-+ int nr = ctl_name - PCF8591_SYSCTL_CH0;
-+
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 0;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ pcf8591_update_client(client);
-+
-+ /* Number of data to show and conversion to signed depend on */
-+ /* the analog input mode */
-+
-+ switch(nr) {
-+ case 0:
-+ if (((data->control_byte & PCF8591_CONTROL_BYTE_AIP) == 0)
-+ | ((data->control_byte & PCF8591_CONTROL_BYTE_AIP) == 2))
-+ results[0] = data->ch[0]; /* single ended */
-+ else
-+ results[0] = REG_TO_SIGNED(data->ch[0]);/* differential */
-+ break;
-+ case 1:
-+ if (((data->control_byte & PCF8591_CONTROL_BYTE_AIP) == 0)
-+ | ((data->control_byte & PCF8591_CONTROL_BYTE_AIP) == 2))
-+ results[0] = data->ch[1]; /* single ended */
-+ else
-+ results[0] = REG_TO_SIGNED(data->ch[1]);/* differential */
-+ break;
-+ case 2:
-+ if ((data->control_byte & PCF8591_CONTROL_BYTE_AIP) == 3)
-+ results[0] = 0; /* channel not used */
-+ else if ((data->control_byte & PCF8591_CONTROL_BYTE_AIP) == 0)
-+ results[0] = data->ch[2]; /* single ended */
-+ else
-+ results[0] = REG_TO_SIGNED(data->ch[2]);/* differential */
-+ break;
-+ case 3:
-+ if (((data->control_byte & PCF8591_CONTROL_BYTE_AIP) == 0)
-+ | ((data->control_byte & PCF8591_CONTROL_BYTE_AIP) == 2))
-+ results[0] = data->ch[3]; /* single ended */
-+ else
-+ results[0] = 0; /* channel not used */
-+ break;
-+ }
-+ *nrels_mag = 1;
-+ }
-+}
-+
-+void pcf8591_aout_enable(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct pcf8591_data *data = client->data;
-+
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 0;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ results[0] = !(!(data->control_byte & PCF8591_CONTROL_BYTE_AOEF));
-+ *nrels_mag = 1;
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ if (*nrels_mag >= 1) {
-+ if (results[0])
-+ data->control_byte |= PCF8591_CONTROL_BYTE_AOEF;
-+ else
-+ data->control_byte &= ~PCF8591_CONTROL_BYTE_AOEF;
-+
-+ i2c_smbus_write_byte(client, data->control_byte);
-+ }
-+ }
-+}
-+
-+void pcf8591_aout(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct pcf8591_data *data = client->data;
-+
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 0;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ results[0] = data->aout;
-+ *nrels_mag = 1;
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ if (*nrels_mag >= 1) {
-+ if (results[0] >= 0 && results[0] <= 255) /* ignore values outside DAC range */
-+ {
-+ data->aout = results[0];
-+ i2c_smbus_write_byte_data(client, data->control_byte, data->aout);
-+ }
-+ }
-+ }
-+}
-+
-+static int __init sm_pcf8591_init(void)
-+{
-+ printk(KERN_INFO "pcf8591.o version %s (%s)\n", LM_VERSION, LM_DATE);
-+ return i2c_add_driver(&pcf8591_driver);
-+}
-+
-+static void __exit sm_pcf8591_exit(void)
-+{
-+ i2c_del_driver(&pcf8591_driver);
-+}
-+
-+
-+
-+MODULE_AUTHOR("Aurelien Jarno <aurelien@aurel32.net>");
-+MODULE_DESCRIPTION("PCF8591 driver");
-+MODULE_LICENSE("GPL");
-+
-+module_init(sm_pcf8591_init);
-+module_exit(sm_pcf8591_exit);
---- linux-old/drivers/sensors/sis5595.c Thu Jan 1 00:00:00 1970
-+++ linux/drivers/sensors/sis5595.c Mon Dec 13 20:18:52 2004
-@@ -0,0 +1,735 @@
-+/*
-+ sis5595.c - Part of lm_sensors, Linux kernel modules
-+ for hardware monitoring
-+
-+ Copyright (c) 1998 - 2001 Frodo Looijaard <frodol@dds.nl>,
-+ Kyösti Mälkki <kmalkki@cc.hut.fi>, and
-+ Mark D. Studebaker <mdsxyz123@yahoo.com>
-+
-+ 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., 675 Mass Ave, Cambridge, MA 02139, USA.
-+*/
-+
-+/*
-+ Supports following revisions:
-+ Version PCI ID PCI Revision
-+ 1 1039/0008 AF or less
-+ 2 1039/0008 B0 or greater
-+
-+ Note: these chips contain a 0008 device which is incompatible with the
-+ 5595. We recognize these by the presence of the listed
-+ "blacklist" PCI ID and refuse to load.
-+
-+ NOT SUPPORTED PCI ID BLACKLIST PCI ID
-+ 540 0008 0540
-+ 550 0008 0550
-+ 5513 0008 5511
-+ 5581 0008 5597
-+ 5582 0008 5597
-+ 5597 0008 5597
-+ 5598 0008 5597/5598
-+ 630 0008 0630
-+ 645 0008 0645
-+ 730 0008 0730
-+ 735 0008 0735
-+*/
-+
-+#include <linux/module.h>
-+#include <linux/slab.h>
-+#include <linux/ioport.h>
-+#include <linux/pci.h>
-+#include <linux/i2c.h>
-+#include <linux/i2c-proc.h>
-+#include <linux/init.h>
-+#include <asm/io.h>
-+#define LM_DATE "20041007"
-+#define LM_VERSION "2.8.8"
-+
-+MODULE_LICENSE("GPL");
-+
-+/* If force_addr is set to anything different from 0, we forcibly enable
-+ the device at the given address. */
-+static int force_addr = 0;
-+MODULE_PARM(force_addr, "i");
-+MODULE_PARM_DESC(force_addr,
-+ "Initialize the base address of the sensors");
-+
-+/* Addresses to scan.
-+ Note that we can't determine the ISA address until we have initialized
-+ our module */
-+static unsigned short normal_i2c[] = { SENSORS_I2C_END };
-+static unsigned short normal_i2c_range[] = { SENSORS_I2C_END };
-+static unsigned int normal_isa[] = { 0x0000, SENSORS_ISA_END };
-+static unsigned int normal_isa_range[] = { SENSORS_ISA_END };
-+
-+/* Insmod parameters */
-+SENSORS_INSMOD_1(sis5595);
-+
-+static int blacklist[] = {
-+ PCI_DEVICE_ID_SI_540,
-+ PCI_DEVICE_ID_SI_550,
-+ PCI_DEVICE_ID_SI_630,
-+ PCI_DEVICE_ID_SI_730,
-+ PCI_DEVICE_ID_SI_5511, /* 5513 chip has the 0008 device but
-+ that ID shows up in other chips so we
-+ use the 5511 ID for recognition */
-+ PCI_DEVICE_ID_SI_5597,
-+ PCI_DEVICE_ID_SI_5598,
-+ 0x645,
-+ 0x735,
-+ 0 };
-+/*
-+ SiS southbridge has a LM78-like chip integrated on the same IC.
-+ This driver is a customized copy of lm78.c
-+*/
-+
-+/* Many SIS5595 constants specified below */
-+
-+/* Length of ISA address segment */
-+#define SIS5595_EXTENT 8
-+/* PCI Config Registers */
-+#define SIS5595_REVISION_REG 0x08
-+#define SIS5595_BASE_REG 0x68
-+#define SIS5595_PIN_REG 0x7A
-+#define SIS5595_ENABLE_REG 0x7B
-+
-+/* Where are the ISA address/data registers relative to the base address */
-+#define SIS5595_ADDR_REG_OFFSET 5
-+#define SIS5595_DATA_REG_OFFSET 6
-+
-+/* The SIS5595 registers */
-+#define SIS5595_REG_IN_MAX(nr) (0x2b + (nr) * 2)
-+#define SIS5595_REG_IN_MIN(nr) (0x2c + (nr) * 2)
-+#define SIS5595_REG_IN(nr) (0x20 + (nr))
-+
-+#define SIS5595_REG_FAN_MIN(nr) (0x3a + (nr))
-+#define SIS5595_REG_FAN(nr) (0x27 + (nr))
-+
-+/* On the first version of the chip, the temp registers are separate.
-+ On the second version,
-+ TEMP pin is shared with IN4, configured in PCI register 0x7A.
-+ The registers are the same as well.
-+ OVER and HYST are really MAX and MIN. */
-+
-+#define REV2MIN 0xb0
-+#define SIS5595_REG_TEMP (( data->revision) >= REV2MIN) ? \
-+ SIS5595_REG_IN(4) : 0x27
-+#define SIS5595_REG_TEMP_OVER (( data->revision) >= REV2MIN) ? \
-+ SIS5595_REG_IN_MAX(4) : 0x39
-+#define SIS5595_REG_TEMP_HYST (( data->revision) >= REV2MIN) ? \
-+ SIS5595_REG_IN_MIN(4) : 0x3a
-+
-+#define SIS5595_REG_CONFIG 0x40
-+#define SIS5595_REG_ALARM1 0x41
-+#define SIS5595_REG_ALARM2 0x42
-+#define SIS5595_REG_FANDIV 0x47
-+
-+/* Conversions. Limit checking is only done on the TO_REG
-+ variants. Note that you should be a bit careful with which arguments
-+ these macros are called: arguments may be evaluated more than once.
-+ Fixing this is just not worth it. */
-+
-+#define IN_TO_REG(val) (SENSORS_LIMIT((((val) * 10 + 8)/16),0,255))
-+#define IN_FROM_REG(val) (((val) * 16 + 5) / 10)
-+
-+static inline u8 FAN_TO_REG(long rpm, int div)
-+{
-+ if (rpm == 0)
-+ return 255;
-+ rpm = SENSORS_LIMIT(rpm, 1, 1000000);
-+ return SENSORS_LIMIT((1350000 + rpm * div / 2) / (rpm * div), 1,
-+ 254);
-+}
-+
-+#define FAN_FROM_REG(val,div) ((val)==0?-1:(val)==255?0:1350000/((val)*(div)))
-+
-+/* Version 1 datasheet temp=.83*reg + 52.12 */
-+#define TEMP_FROM_REG(val) (((((val)>=0x80?(val)-0x100:(val))*83)+5212)/10)
-+/* inverse 1.20*val - 62.77 */
-+#define TEMP_TO_REG(val) (SENSORS_LIMIT(((val)<0?\
-+ ((((val)*12)-6327)/100):\
-+ ((((val)*12)-6227)/100)),0,255))
-+
-+#define ALARMS_FROM_REG(val) (val)
-+
-+#define DIV_FROM_REG(val) (1 << (val))
-+#define DIV_TO_REG(val) ((val)==8?3:(val)==4?2:(val)==1?0:1)
-+
-+/* For the SIS5595, we need to keep some data in memory. That
-+ data is pointed to by sis5595_list[NR]->data. The structure itself is
-+ dynamically allocated, at the time when the new sis5595 client is
-+ allocated. */
-+struct sis5595_data {
-+ struct i2c_client client;
-+ struct semaphore lock;
-+ int sysctl_id;
-+
-+ struct semaphore update_lock;
-+ char valid; /* !=0 if following fields are valid */
-+ unsigned long last_updated; /* In jiffies */
-+ char maxins; /* == 3 if temp enabled, otherwise == 4 */
-+ u8 revision; /* Reg. value */
-+
-+ u8 in[5]; /* Register value */
-+ u8 in_max[5]; /* Register value */
-+ u8 in_min[5]; /* Register value */
-+ u8 fan[2]; /* Register value */
-+ u8 fan_min[2]; /* Register value */
-+ u8 temp; /* Register value */
-+ u8 temp_over; /* Register value - really max */
-+ u8 temp_hyst; /* Register value - really min */
-+ u8 fan_div[2]; /* Register encoding, shifted right */
-+ u16 alarms; /* Register encoding, combined */
-+};
-+
-+static struct pci_dev *s_bridge; /* pointer to the (only) sis5595 */
-+
-+static int sis5595_attach_adapter(struct i2c_adapter *adapter);
-+static int sis5595_detect(struct i2c_adapter *adapter, int address,
-+ unsigned short flags, int kind);
-+static int sis5595_detach_client(struct i2c_client *client);
-+
-+static int sis5595_read_value(struct i2c_client *client, u8 register);
-+static int sis5595_write_value(struct i2c_client *client, u8 register,
-+ u8 value);
-+static void sis5595_update_client(struct i2c_client *client);
-+static void sis5595_init_client(struct i2c_client *client);
-+static int sis5595_find_sis(int *address);
-+
-+
-+static void sis5595_in(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void sis5595_fan(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void sis5595_temp(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void sis5595_alarms(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void sis5595_fan_div(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+
-+static int sis5595_id = 0;
-+
-+/* The driver. I choose to use type i2c_driver, as at is identical to both
-+ smbus_driver and isa_driver, and clients could be of either kind */
-+static struct i2c_driver sis5595_driver = {
-+ .owner = THIS_MODULE,
-+ .name = "SiS 5595",
-+ .id = I2C_DRIVERID_SIS5595,
-+ .flags = I2C_DF_NOTIFY,
-+ .attach_adapter = sis5595_attach_adapter,
-+ .detach_client = sis5595_detach_client,
-+};
-+
-+/* The /proc/sys entries */
-+
-+/* -- SENSORS SYSCTL START -- */
-+#define SIS5595_SYSCTL_IN0 1000 /* Volts * 100 */
-+#define SIS5595_SYSCTL_IN1 1001
-+#define SIS5595_SYSCTL_IN2 1002
-+#define SIS5595_SYSCTL_IN3 1003
-+#define SIS5595_SYSCTL_IN4 1004
-+#define SIS5595_SYSCTL_FAN1 1101 /* Rotations/min */
-+#define SIS5595_SYSCTL_FAN2 1102
-+#define SIS5595_SYSCTL_TEMP 1200 /* Degrees Celcius * 10 */
-+#define SIS5595_SYSCTL_FAN_DIV 2000 /* 1, 2, 4 or 8 */
-+#define SIS5595_SYSCTL_ALARMS 2001 /* bitvector */
-+
-+#define SIS5595_ALARM_IN0 0x01
-+#define SIS5595_ALARM_IN1 0x02
-+#define SIS5595_ALARM_IN2 0x04
-+#define SIS5595_ALARM_IN3 0x08
-+#define SIS5595_ALARM_BTI 0x20
-+#define SIS5595_ALARM_FAN1 0x40
-+#define SIS5595_ALARM_FAN2 0x80
-+#define SIS5595_ALARM_IN4 0x8000
-+#define SIS5595_ALARM_TEMP 0x8000
-+
-+/* -- SENSORS SYSCTL END -- */
-+
-+/* These files are created for each detected SIS5595. This is just a template;
-+ though at first sight, you might think we could use a statically
-+ allocated list, we need some way to get back to the parent - which
-+ is done through one of the 'extra' fields which are initialized
-+ when a new copy is allocated. */
-+static ctl_table sis5595_dir_table_template[] = {
-+ {SIS5595_SYSCTL_IN0, "in0", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &sis5595_in},
-+ {SIS5595_SYSCTL_IN1, "in1", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &sis5595_in},
-+ {SIS5595_SYSCTL_IN2, "in2", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &sis5595_in},
-+ {SIS5595_SYSCTL_IN3, "in3", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &sis5595_in},
-+ {SIS5595_SYSCTL_IN4, "in4", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &sis5595_in},
-+ {SIS5595_SYSCTL_FAN1, "fan1", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &sis5595_fan},
-+ {SIS5595_SYSCTL_FAN2, "fan2", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &sis5595_fan},
-+ {SIS5595_SYSCTL_TEMP, "temp", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &sis5595_temp},
-+ {SIS5595_SYSCTL_FAN_DIV, "fan_div", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &sis5595_fan_div},
-+ {SIS5595_SYSCTL_ALARMS, "alarms", NULL, 0, 0444, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &sis5595_alarms},
-+ {0}
-+};
-+
-+/* This is called when the module is loaded */
-+static int sis5595_attach_adapter(struct i2c_adapter *adapter)
-+{
-+ return i2c_detect(adapter, &addr_data, sis5595_detect);
-+}
-+
-+/* Locate SiS bridge and correct base address for SIS5595 */
-+static int sis5595_find_sis(int *address)
-+{
-+ u16 val;
-+ int *i;
-+
-+ if (!pci_present())
-+ return -ENODEV;
-+
-+ if (!(s_bridge =
-+ pci_find_device(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_503,
-+ NULL)))
-+ return -ENODEV;
-+
-+ /* Look for imposters */
-+ for(i = blacklist; *i != 0; i++) {
-+ if (pci_find_device(PCI_VENDOR_ID_SI, *i, NULL)) {
-+ printk("sis5595.o: Error: Looked for SIS5595 but found unsupported device %.4X\n", *i);
-+ return -ENODEV;
-+ }
-+ }
-+
-+ if (PCIBIOS_SUCCESSFUL !=
-+ pci_read_config_word(s_bridge, SIS5595_BASE_REG, &val))
-+ return -ENODEV;
-+
-+ *address = val & ~(SIS5595_EXTENT - 1);
-+ if (*address == 0 && force_addr == 0) {
-+ printk("sis5595.o: base address not set - upgrade BIOS or use force_addr=0xaddr\n");
-+ return -ENODEV;
-+ }
-+ if (force_addr)
-+ *address = force_addr; /* so detect will get called */
-+
-+ return 0;
-+}
-+
-+int sis5595_detect(struct i2c_adapter *adapter, int address,
-+ unsigned short flags, int kind)
-+{
-+ int i;
-+ struct i2c_client *new_client;
-+ struct sis5595_data *data;
-+ int err = 0;
-+ const char *type_name = "sis5595";
-+ const char *client_name = "SIS5595 chip";
-+ char val;
-+ u16 a;
-+
-+ /* Make sure we are probing the ISA bus!! */
-+ if (!i2c_is_isa_adapter(adapter)) {
-+ printk
-+ ("sis5595.o: sis5595_detect called for an I2C bus adapter?!?\n");
-+ return 0;
-+ }
-+
-+ if(force_addr)
-+ address = force_addr & ~(SIS5595_EXTENT - 1);
-+ if (check_region(address, SIS5595_EXTENT)) {
-+ printk("sis5595.o: region 0x%x already in use!\n", address);
-+ return -ENODEV;
-+ }
-+ if(force_addr) {
-+ printk("sis5595.o: forcing ISA address 0x%04X\n", address);
-+ if (PCIBIOS_SUCCESSFUL !=
-+ pci_write_config_word(s_bridge, SIS5595_BASE_REG, address))
-+ return -ENODEV;
-+ if (PCIBIOS_SUCCESSFUL !=
-+ pci_read_config_word(s_bridge, SIS5595_BASE_REG, &a))
-+ return -ENODEV;
-+ if ((a & ~(SIS5595_EXTENT - 1)) != address) {
-+ /* doesn't work for some chips? */
-+ printk("sis5595.o: force address failed\n");
-+ return -ENODEV;
-+ }
-+ }
-+
-+ if (PCIBIOS_SUCCESSFUL !=
-+ pci_read_config_byte(s_bridge, SIS5595_ENABLE_REG, &val))
-+ return -ENODEV;
-+ if((val & 0x80) == 0) {
-+ printk("sis5595.o: enabling sensors\n");
-+ if (PCIBIOS_SUCCESSFUL !=
-+ pci_write_config_byte(s_bridge, SIS5595_ENABLE_REG,
-+ val | 0x80))
-+ return -ENODEV;
-+ if (PCIBIOS_SUCCESSFUL !=
-+ pci_read_config_byte(s_bridge, SIS5595_ENABLE_REG, &val))
-+ return -ENODEV;
-+ if((val & 0x80) == 0) { /* doesn't work for some chips! */
-+ printk("sis5595.o: sensors enable failed - not supported?\n");
-+ return -ENODEV;
-+ }
-+ }
-+
-+ if (!(data = kmalloc(sizeof(struct sis5595_data), GFP_KERNEL))) {
-+ return -ENOMEM;
-+ }
-+
-+ new_client = &data->client;
-+ new_client->addr = address;
-+ init_MUTEX(&data->lock);
-+ new_client->data = data;
-+ new_client->adapter = adapter;
-+ new_client->driver = &sis5595_driver;
-+ new_client->flags = 0;
-+
-+ /* Reserve the ISA region */
-+ request_region(address, SIS5595_EXTENT, type_name);
-+
-+ /* Check revision and pin registers to determine whether 3 or 4 voltages */
-+ pci_read_config_byte(s_bridge, SIS5595_REVISION_REG, &(data->revision));
-+ if(data->revision < REV2MIN) {
-+ data->maxins = 3;
-+ } else {
-+ pci_read_config_byte(s_bridge, SIS5595_PIN_REG, &val);
-+ if(val & 0x80)
-+ /* 3 voltages, 1 temp */
-+ data->maxins = 3;
-+ else
-+ /* 4 voltages, no temps */
-+ data->maxins = 4;
-+ }
-+
-+ /* Fill in the remaining client fields and put it into the global list */
-+ strcpy(new_client->name, client_name);
-+
-+ new_client->id = sis5595_id++;
-+ data->valid = 0;
-+ init_MUTEX(&data->update_lock);
-+
-+ /* Tell the I2C layer a new client has arrived */
-+ if ((err = i2c_attach_client(new_client)))
-+ goto ERROR3;
-+
-+ /* Register a new directory entry with module sensors */
-+ if ((i = i2c_register_entry((struct i2c_client *) new_client,
-+ type_name,
-+ sis5595_dir_table_template)) < 0) {
-+ err = i;
-+ goto ERROR4;
-+ }
-+ data->sysctl_id = i;
-+
-+ /* Initialize the SIS5595 chip */
-+ sis5595_init_client(new_client);
-+ return 0;
-+
-+ ERROR4:
-+ i2c_detach_client(new_client);
-+ ERROR3:
-+ release_region(address, SIS5595_EXTENT);
-+ kfree(data);
-+ return err;
-+}
-+
-+static int sis5595_detach_client(struct i2c_client *client)
-+{
-+ int err;
-+
-+ i2c_deregister_entry(((struct sis5595_data *) (client->data))->
-+ sysctl_id);
-+
-+ if ((err = i2c_detach_client(client))) {
-+ printk
-+ ("sis5595.o: Client deregistration failed, client not detached.\n");
-+ return err;
-+ }
-+
-+ release_region(client->addr, SIS5595_EXTENT);
-+ kfree(client->data);
-+
-+ return 0;
-+}
-+
-+
-+/* ISA access must be locked explicitly.
-+ There are some ugly typecasts here, but the good news is - they should
-+ nowhere else be necessary! */
-+static int sis5595_read_value(struct i2c_client *client, u8 reg)
-+{
-+ int res;
-+
-+ down(&(((struct sis5595_data *) (client->data))->lock));
-+ outb_p(reg, client->addr + SIS5595_ADDR_REG_OFFSET);
-+ res = inb_p(client->addr + SIS5595_DATA_REG_OFFSET);
-+ up(&(((struct sis5595_data *) (client->data))->lock));
-+ return res;
-+}
-+
-+static int sis5595_write_value(struct i2c_client *client, u8 reg, u8 value)
-+{
-+ down(&(((struct sis5595_data *) (client->data))->lock));
-+ outb_p(reg, client->addr + SIS5595_ADDR_REG_OFFSET);
-+ outb_p(value, client->addr + SIS5595_DATA_REG_OFFSET);
-+ up(&(((struct sis5595_data *) (client->data))->lock));
-+ return 0;
-+}
-+
-+/* Called when we have found a new SIS5595. */
-+static void sis5595_init_client(struct i2c_client *client)
-+{
-+ u8 reg;
-+
-+ /* Start monitoring */
-+ reg = i2c_smbus_read_byte_data(client, SIS5595_REG_CONFIG);
-+ sis5595_write_value(client, SIS5595_REG_CONFIG, (reg|0x01)&0x7F);
-+}
-+
-+static void sis5595_update_client(struct i2c_client *client)
-+{
-+ struct sis5595_data *data = client->data;
-+ int i;
-+
-+ down(&data->update_lock);
-+
-+ if ((jiffies - data->last_updated > HZ + HZ / 2) ||
-+ (jiffies < data->last_updated) || !data->valid) {
-+
-+ for (i = 0; i <= data->maxins; i++) {
-+ data->in[i] =
-+ sis5595_read_value(client, SIS5595_REG_IN(i));
-+ data->in_min[i] =
-+ sis5595_read_value(client,
-+ SIS5595_REG_IN_MIN(i));
-+ data->in_max[i] =
-+ sis5595_read_value(client,
-+ SIS5595_REG_IN_MAX(i));
-+ }
-+ for (i = 1; i <= 2; i++) {
-+ data->fan[i - 1] =
-+ sis5595_read_value(client, SIS5595_REG_FAN(i));
-+ data->fan_min[i - 1] =
-+ sis5595_read_value(client,
-+ SIS5595_REG_FAN_MIN(i));
-+ }
-+ if(data->maxins == 3) {
-+ data->temp =
-+ sis5595_read_value(client, SIS5595_REG_TEMP);
-+ data->temp_over =
-+ sis5595_read_value(client, SIS5595_REG_TEMP_OVER);
-+ data->temp_hyst =
-+ sis5595_read_value(client, SIS5595_REG_TEMP_HYST);
-+ }
-+ i = sis5595_read_value(client, SIS5595_REG_FANDIV);
-+ data->fan_div[0] = (i >> 4) & 0x03;
-+ data->fan_div[1] = i >> 6;
-+ data->alarms =
-+ sis5595_read_value(client, SIS5595_REG_ALARM1) |
-+ (sis5595_read_value(client, SIS5595_REG_ALARM2) << 8);
-+ data->last_updated = jiffies;
-+ data->valid = 1;
-+ }
-+
-+ up(&data->update_lock);
-+}
-+
-+
-+/* The next few functions are the call-back functions of the /proc/sys and
-+ sysctl files. Which function is used is defined in the ctl_table in
-+ the extra1 field.
-+ Each function must return the magnitude (power of 10 to divide the date
-+ with) if it is called with operation==SENSORS_PROC_REAL_INFO. It must
-+ put a maximum of *nrels elements in results reflecting the data of this
-+ file, and set *nrels to the number it actually put in it, if operation==
-+ SENSORS_PROC_REAL_READ. Finally, it must get upto *nrels elements from
-+ results and write them to the chip, if operations==SENSORS_PROC_REAL_WRITE.
-+ Note that on SENSORS_PROC_REAL_READ, I do not check whether results is
-+ large enough (by checking the incoming value of *nrels). This is not very
-+ good practice, but as long as you put less than about 5 values in results,
-+ you can assume it is large enough. */
-+
-+/* Return 0 for in4 and disallow writes if pin used for temp */
-+void sis5595_in(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct sis5595_data *data = client->data;
-+ int nr = ctl_name - SIS5595_SYSCTL_IN0;
-+
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 2;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ if(nr <= 3 || data->maxins == 4) {
-+ sis5595_update_client(client);
-+ results[0] = IN_FROM_REG(data->in_min[nr]);
-+ results[1] = IN_FROM_REG(data->in_max[nr]);
-+ results[2] = IN_FROM_REG(data->in[nr]);
-+ } else {
-+ results[0] = 0;
-+ results[1] = 0;
-+ results[2] = 0;
-+ }
-+ *nrels_mag = 3;
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ if(nr <= 3 || data->maxins == 4) {
-+ if (*nrels_mag >= 1) {
-+ data->in_min[nr] = IN_TO_REG(results[0]);
-+ sis5595_write_value(client,
-+ SIS5595_REG_IN_MIN(nr), data->in_min[nr]);
-+ }
-+ if (*nrels_mag >= 2) {
-+ data->in_max[nr] = IN_TO_REG(results[1]);
-+ sis5595_write_value(client,
-+ SIS5595_REG_IN_MAX(nr), data->in_max[nr]);
-+ }
-+ }
-+ }
-+}
-+
-+void sis5595_fan(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct sis5595_data *data = client->data;
-+ int nr = ctl_name - SIS5595_SYSCTL_FAN1 + 1;
-+
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 0;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ sis5595_update_client(client);
-+ results[0] = FAN_FROM_REG(data->fan_min[nr - 1],
-+ DIV_FROM_REG(data->fan_div[nr - 1]));
-+ results[1] = FAN_FROM_REG(data->fan[nr - 1],
-+ DIV_FROM_REG(data->fan_div[nr - 1]));
-+ *nrels_mag = 2;
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ if (*nrels_mag >= 1) {
-+ data->fan_min[nr - 1] = FAN_TO_REG(results[0],
-+ DIV_FROM_REG
-+ (data->
-+ fan_div[nr-1]));
-+ sis5595_write_value(client,
-+ SIS5595_REG_FAN_MIN(nr),
-+ data->fan_min[nr - 1]);
-+ }
-+ }
-+}
-+
-+
-+/* Return 0 for temp and disallow writes if pin used for in4 */
-+void sis5595_temp(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct sis5595_data *data = client->data;
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 1;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ if(data->maxins == 3) {
-+ sis5595_update_client(client);
-+ results[0] = TEMP_FROM_REG(data->temp_over);
-+ results[1] = TEMP_FROM_REG(data->temp_hyst);
-+ results[2] = TEMP_FROM_REG(data->temp);
-+ } else {
-+ results[0] = 0;
-+ results[1] = 0;
-+ results[2] = 0;
-+ }
-+ *nrels_mag = 3;
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ if(data->maxins == 3) {
-+ if (*nrels_mag >= 1) {
-+ data->temp_over = TEMP_TO_REG(results[0]);
-+ sis5595_write_value(client,
-+ SIS5595_REG_TEMP_OVER, data->temp_over);
-+ }
-+ if (*nrels_mag >= 2) {
-+ data->temp_hyst = TEMP_TO_REG(results[1]);
-+ sis5595_write_value(client,
-+ SIS5595_REG_TEMP_HYST, data->temp_hyst);
-+ }
-+ }
-+ }
-+}
-+
-+void sis5595_alarms(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct sis5595_data *data = client->data;
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 0;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ sis5595_update_client(client);
-+ results[0] = ALARMS_FROM_REG(data->alarms);
-+ *nrels_mag = 1;
-+ }
-+}
-+
-+void sis5595_fan_div(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results)
-+{
-+ struct sis5595_data *data = client->data;
-+ int old;
-+
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 0;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ sis5595_update_client(client);
-+ results[0] = DIV_FROM_REG(data->fan_div[0]);
-+ results[1] = DIV_FROM_REG(data->fan_div[1]);
-+ *nrels_mag = 2;
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ old = sis5595_read_value(client, SIS5595_REG_FANDIV);
-+ if (*nrels_mag >= 2) {
-+ data->fan_div[1] = DIV_TO_REG(results[1]);
-+ old = (old & 0x3f) | (data->fan_div[1] << 6);
-+ }
-+ if (*nrels_mag >= 1) {
-+ data->fan_div[0] = DIV_TO_REG(results[0]);
-+ old = (old & 0xcf) | (data->fan_div[0] << 4);
-+ sis5595_write_value(client, SIS5595_REG_FANDIV, old);
-+ }
-+ }
-+}
-+
-+static int __init sm_sis5595_init(void)
-+{
-+ int addr;
-+
-+ printk("sis5595.o version %s (%s)\n", LM_VERSION, LM_DATE);
-+
-+ if (sis5595_find_sis(&addr)) {
-+ printk("sis5595.o: SIS5595 not detected, module not inserted.\n");
-+ return -ENODEV;
-+ }
-+ normal_isa[0] = addr;
-+
-+ return i2c_add_driver(&sis5595_driver);
-+}
-+
-+static void __exit sm_sis5595_exit(void)
-+{
-+ i2c_del_driver(&sis5595_driver);
-+}
-+
-+
-+
-+MODULE_AUTHOR("Kyösti Mälkki <kmalkki@cc.hut.fi>");
-+MODULE_DESCRIPTION("SiS 5595 Sensor device");
-+
-+module_init(sm_sis5595_init);
-+module_exit(sm_sis5595_exit);
---- linux-old/drivers/sensors/smsc47m1.c Thu Jan 1 00:00:00 1970
-+++ linux/drivers/sensors/smsc47m1.c Mon Dec 13 20:18:52 2004
-@@ -0,0 +1,515 @@
-+/*
-+ smsc47m1.c - Part of lm_sensors, Linux kernel modules
-+ for hardware monitoring
-+
-+ Copyright (c) 2002 Mark D. Studebaker <mdsxyz123@yahoo.com>
-+
-+ 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., 675 Mass Ave, Cambridge, MA 02139, USA.
-+*/
-+
-+#include <linux/module.h>
-+#include <linux/slab.h>
-+#include <linux/ioport.h>
-+#include <linux/i2c.h>
-+#include <linux/i2c-proc.h>
-+#include <linux/init.h>
-+#include <asm/io.h>
-+#define LM_DATE "20041007"
-+#define LM_VERSION "2.8.8"
-+
-+static int force_addr = 0;
-+MODULE_PARM(force_addr, "i");
-+MODULE_PARM_DESC(force_addr,
-+ "Initialize the base address of the sensors");
-+
-+static unsigned short normal_i2c[] = { SENSORS_I2C_END };
-+static unsigned short normal_i2c_range[] = { SENSORS_I2C_END };
-+static unsigned int normal_isa[] = { 0x0000, SENSORS_ISA_END };
-+static unsigned int normal_isa_range[] = { SENSORS_ISA_END };
-+
-+SENSORS_INSMOD_1(smsc47m1);
-+
-+/* modified from kernel/include/traps.c */
-+#define REG 0x2e /* The register to read/write */
-+#define DEV 0x07 /* Register: Logical device select */
-+#define VAL 0x2f /* The value to read/write */
-+#define PME 0x0a /* The device with the fan registers in it */
-+#define DEVID 0x20 /* Register: Device ID */
-+
-+static inline void
-+superio_outb(int reg, int val)
-+{
-+ outb(reg, REG);
-+ outb(val, VAL);
-+}
-+
-+static inline int
-+superio_inb(int reg)
-+{
-+ outb(reg, REG);
-+ return inb(VAL);
-+}
-+
-+static inline void
-+superio_select(void)
-+{
-+ outb(DEV, REG);
-+ outb(PME, VAL);
-+}
-+
-+static inline void
-+superio_enter(void)
-+{
-+ outb(0x55, REG);
-+}
-+
-+static inline void
-+superio_exit(void)
-+{
-+ outb(0xAA, REG);
-+}
-+
-+/*
-+ * SMSC LPC47M10x (device id 0x59), LPC47M14x (device id 0x5F) and
-+ * LPC47B27x (device id 0x51) have fan control.
-+ * The 47M15x and 47M192 chips "with hardware monitoring block"
-+ * can do much more besides (device id 0x60).
-+ */
-+#define SMSC_DEVID_MATCH(id) ((id) == 0x51 || (id) == 0x59 || (id) == 0x5F)
-+
-+#define SMSC_ACT_REG 0x30
-+#define SMSC_BASE_REG 0x60
-+
-+#define SMSC_EXTENT 0x80
-+
-+#define SMSC47M1_REG_ALARM1 0x04
-+#define SMSC47M1_REG_TPIN2 0x33
-+#define SMSC47M1_REG_TPIN1 0x34
-+#define SMSC47M1_REG_PPIN(nr) (0x37 - (nr))
-+#define SMSC47M1_REG_PWM(nr) (0x55 + (nr))
-+#define SMSC47M1_REG_FANDIV 0x58
-+#define SMSC47M1_REG_FAN(nr) (0x58 + (nr))
-+#define SMSC47M1_REG_FAN_MIN(nr) (0x5a + (nr))
-+
-+static inline u8 MIN_TO_REG(long rpm, int div)
-+{
-+ if (rpm == 0)
-+ return 0;
-+ rpm = SENSORS_LIMIT(rpm, 1, 1000000);
-+ return SENSORS_LIMIT(192 - ((983040 + rpm * div / 2) / (rpm * div)),
-+ 0, 191);
-+}
-+
-+#define MIN_FROM_REG(val,div) ((val)>=192?0: \
-+ 983040/((192-(val))*(div)))
-+#define FAN_FROM_REG(val,div,preload) ((val)==0?-1:(val)==255?0: \
-+ 983040/(((val)-preload)*(div)))
-+#define DIV_FROM_REG(val) (1 << (val))
-+#define DIV_TO_REG(val) ((val)==8?3:(val)==4?2:(val)==1?0:1)
-+/* reg is 6 middle bits; /proc is 8 bits */
-+#define PWM_FROM_REG(val) (((val) << 1) & 0xfc)
-+#define PWM_TO_REG(val) (((SENSORS_LIMIT((val), 0, 255)) >> 1) & 0x7e)
-+
-+struct smsc47m1_data {
-+ struct i2c_client client;
-+ struct semaphore lock;
-+ int sysctl_id;
-+
-+ struct semaphore update_lock;
-+ char valid; /* !=0 if following fields are valid */
-+ unsigned long last_updated; /* In jiffies */
-+
-+ u8 fan[2]; /* Register value */
-+ u8 fan_min[2]; /* Register value */
-+ u8 fan_div[2]; /* Register encoding, shifted right */
-+ u8 alarms; /* Register encoding */
-+ u8 pwm[2]; /* Register value (bit 7 is enable) */
-+};
-+
-+
-+static int smsc47m1_attach_adapter(struct i2c_adapter *adapter);
-+static int smsc47m1_detect(struct i2c_adapter *adapter, int address,
-+ unsigned short flags, int kind);
-+static int smsc47m1_detach_client(struct i2c_client *client);
-+
-+static int smsc47m1_read_value(struct i2c_client *client, u8 register);
-+static int smsc47m1_write_value(struct i2c_client *client, u8 register,
-+ u8 value);
-+static void smsc47m1_update_client(struct i2c_client *client);
-+static void smsc47m1_init_client(struct i2c_client *client);
-+static int smsc47m1_find(int *address);
-+
-+
-+static void smsc47m1_fan(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void smsc47m1_alarms(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void smsc47m1_fan_div(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void smsc47m1_pwm(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+
-+static int smsc47m1_id = 0;
-+
-+static struct i2c_driver smsc47m1_driver = {
-+ .owner = THIS_MODULE,
-+ .name = "SMSC 47M1xx fan monitor",
-+ .id = I2C_DRIVERID_SMSC47M1,
-+ .flags = I2C_DF_NOTIFY,
-+ .attach_adapter = smsc47m1_attach_adapter,
-+ .detach_client = smsc47m1_detach_client,
-+};
-+
-+/* -- SENSORS SYSCTL START -- */
-+#define SMSC47M1_SYSCTL_FAN1 1101 /* Rotations/min */
-+#define SMSC47M1_SYSCTL_FAN2 1102
-+#define SMSC47M1_SYSCTL_PWM1 1401
-+#define SMSC47M1_SYSCTL_PWM2 1402
-+#define SMSC47M1_SYSCTL_FAN_DIV 2000 /* 1, 2, 4 or 8 */
-+#define SMSC47M1_SYSCTL_ALARMS 2004 /* bitvector */
-+
-+#define SMSC47M1_ALARM_FAN1 0x0001
-+#define SMSC47M1_ALARM_FAN2 0x0002
-+
-+/* -- SENSORS SYSCTL END -- */
-+
-+static ctl_table smsc47m1_dir_table_template[] = {
-+ {SMSC47M1_SYSCTL_FAN1, "fan1", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &smsc47m1_fan},
-+ {SMSC47M1_SYSCTL_FAN2, "fan2", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &smsc47m1_fan},
-+ {SMSC47M1_SYSCTL_FAN_DIV, "fan_div", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &smsc47m1_fan_div},
-+ {SMSC47M1_SYSCTL_ALARMS, "alarms", NULL, 0, 0444, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &smsc47m1_alarms},
-+ {SMSC47M1_SYSCTL_PWM1, "pwm1", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &smsc47m1_pwm},
-+ {SMSC47M1_SYSCTL_PWM2, "pwm2", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &smsc47m1_pwm},
-+ {0}
-+};
-+
-+static int smsc47m1_attach_adapter(struct i2c_adapter *adapter)
-+{
-+ return i2c_detect(adapter, &addr_data, smsc47m1_detect);
-+}
-+
-+static int smsc47m1_find(int *address)
-+{
-+ u16 val;
-+
-+ superio_enter();
-+ val= superio_inb(DEVID);
-+ if (!SMSC_DEVID_MATCH(val)) {
-+ superio_exit();
-+ return -ENODEV;
-+ }
-+
-+ superio_select();
-+ val = (superio_inb(SMSC_BASE_REG) << 8) |
-+ superio_inb(SMSC_BASE_REG + 1);
-+ *address = val & ~(SMSC_EXTENT - 1);
-+ if (*address == 0 && force_addr == 0) {
-+ printk("smsc47m1.o: base address not set - use force_addr=0xaddr\n");
-+ superio_exit();
-+ return -ENODEV;
-+ }
-+ if (force_addr)
-+ *address = force_addr; /* so detect will get called */
-+
-+ superio_exit();
-+ return 0;
-+}
-+
-+int smsc47m1_detect(struct i2c_adapter *adapter, int address,
-+ unsigned short flags, int kind)
-+{
-+ int i;
-+ struct i2c_client *new_client;
-+ struct smsc47m1_data *data;
-+ int err = 0;
-+ const char *type_name = "smsc47m1";
-+ const char *client_name = "47M1xx chip";
-+
-+ if (!i2c_is_isa_adapter(adapter)) {
-+ return 0;
-+ }
-+
-+ if(force_addr)
-+ address = force_addr & ~(SMSC_EXTENT - 1);
-+ if (check_region(address, SMSC_EXTENT)) {
-+ printk("smsc47m1.o: region 0x%x already in use!\n", address);
-+ return -ENODEV;
-+ }
-+ if(force_addr) {
-+ printk("smsc47m1.o: forcing ISA address 0x%04X\n", address);
-+ superio_enter();
-+ superio_select();
-+ superio_outb(SMSC_BASE_REG, address >> 8);
-+ superio_outb(SMSC_BASE_REG+1, address & 0xff);
-+ superio_exit();
-+ }
-+
-+ if (!(data = kmalloc(sizeof(struct smsc47m1_data), GFP_KERNEL))) {
-+ return -ENOMEM;
-+ }
-+
-+ new_client = &data->client;
-+ new_client->addr = address;
-+ init_MUTEX(&data->lock);
-+ new_client->data = data;
-+ new_client->adapter = adapter;
-+ new_client->driver = &smsc47m1_driver;
-+ new_client->flags = 0;
-+
-+ request_region(address, SMSC_EXTENT, "smsc47m1-fans");
-+ strcpy(new_client->name, client_name);
-+
-+ new_client->id = smsc47m1_id++;
-+ data->valid = 0;
-+ init_MUTEX(&data->update_lock);
-+
-+ if ((err = i2c_attach_client(new_client)))
-+ goto ERROR3;
-+
-+ if ((i = i2c_register_entry((struct i2c_client *) new_client,
-+ type_name,
-+ smsc47m1_dir_table_template)) < 0) {
-+ err = i;
-+ goto ERROR4;
-+ }
-+ data->sysctl_id = i;
-+
-+ smsc47m1_init_client(new_client);
-+ return 0;
-+
-+ ERROR4:
-+ i2c_detach_client(new_client);
-+ ERROR3:
-+ release_region(address, SMSC_EXTENT);
-+ kfree(data);
-+ return err;
-+}
-+
-+static int smsc47m1_detach_client(struct i2c_client *client)
-+{
-+ int err;
-+
-+ i2c_deregister_entry(((struct smsc47m1_data *) (client->data))->
-+ sysctl_id);
-+
-+ if ((err = i2c_detach_client(client))) {
-+ printk
-+ ("smsc47m1.o: Client deregistration failed, client not detached.\n");
-+ return err;
-+ }
-+
-+ release_region(client->addr, SMSC_EXTENT);
-+ kfree(client->data);
-+
-+ return 0;
-+}
-+
-+static int smsc47m1_read_value(struct i2c_client *client, u8 reg)
-+{
-+ int res;
-+
-+ down(&(((struct smsc47m1_data *) (client->data))->lock));
-+ res = inb_p(client->addr + reg);
-+ up(&(((struct smsc47m1_data *) (client->data))->lock));
-+ return res;
-+}
-+
-+static int smsc47m1_write_value(struct i2c_client *client, u8 reg, u8 value)
-+{
-+ down(&(((struct smsc47m1_data *) (client->data))->lock));
-+ outb_p(value, client->addr + reg);
-+ up(&(((struct smsc47m1_data *) (client->data))->lock));
-+ return 0;
-+}
-+
-+static void smsc47m1_init_client(struct i2c_client *client)
-+{
-+ /* configure pins for tach function */
-+ smsc47m1_write_value(client, SMSC47M1_REG_TPIN1, 0x05);
-+ smsc47m1_write_value(client, SMSC47M1_REG_TPIN2, 0x05);
-+}
-+
-+static void smsc47m1_update_client(struct i2c_client *client)
-+{
-+ struct smsc47m1_data *data = client->data;
-+ int i;
-+
-+ down(&data->update_lock);
-+
-+ if ((jiffies - data->last_updated > HZ + HZ / 2) ||
-+ (jiffies < data->last_updated) || !data->valid) {
-+ for (i = 1; i <= 2; i++) {
-+ data->fan[i - 1] =
-+ smsc47m1_read_value(client, SMSC47M1_REG_FAN(i));
-+ data->fan_min[i - 1] =
-+ smsc47m1_read_value(client, SMSC47M1_REG_FAN_MIN(i));
-+ data->pwm[i - 1] =
-+ smsc47m1_read_value(client, SMSC47M1_REG_PWM(i));
-+ }
-+
-+ i = smsc47m1_read_value(client, SMSC47M1_REG_FANDIV);
-+ data->fan_div[0] = (i >> 4) & 0x03;
-+ data->fan_div[1] = i >> 6;
-+ data->alarms =
-+ smsc47m1_read_value(client, SMSC47M1_REG_ALARM1) >> 6;
-+ if(data->alarms)
-+ smsc47m1_write_value(client, SMSC47M1_REG_ALARM1, 0xc0);
-+ data->last_updated = jiffies;
-+ data->valid = 1;
-+ }
-+
-+ up(&data->update_lock);
-+}
-+
-+
-+void smsc47m1_fan(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct smsc47m1_data *data = client->data;
-+ int nr = ctl_name - SMSC47M1_SYSCTL_FAN1 + 1;
-+
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 0;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ smsc47m1_update_client(client);
-+ results[0] = MIN_FROM_REG(data->fan_min[nr - 1],
-+ DIV_FROM_REG(data->fan_div[nr - 1]));
-+ results[1] = FAN_FROM_REG(data->fan[nr - 1],
-+ DIV_FROM_REG(data->fan_div[nr - 1]),
-+ data->fan_min[nr - 1]);
-+ *nrels_mag = 2;
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ if (*nrels_mag >= 1) {
-+ data->fan_min[nr - 1] = MIN_TO_REG(results[0],
-+ DIV_FROM_REG
-+ (data->
-+ fan_div[nr-1]));
-+ smsc47m1_write_value(client, SMSC47M1_REG_FAN_MIN(nr),
-+ data->fan_min[nr - 1]);
-+ }
-+ }
-+}
-+
-+
-+void smsc47m1_alarms(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct smsc47m1_data *data = client->data;
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 0;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ smsc47m1_update_client(client);
-+ results[0] = data->alarms;
-+ *nrels_mag = 1;
-+ }
-+}
-+
-+void smsc47m1_fan_div(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results)
-+{
-+ struct smsc47m1_data *data = client->data;
-+ int old;
-+
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 0;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ smsc47m1_update_client(client);
-+ results[0] = DIV_FROM_REG(data->fan_div[0]);
-+ results[1] = DIV_FROM_REG(data->fan_div[1]);
-+ *nrels_mag = 2;
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ old = smsc47m1_read_value(client, SMSC47M1_REG_FANDIV);
-+ if (*nrels_mag >= 2) {
-+ data->fan_div[1] = DIV_TO_REG(results[1]);
-+ old = (old & 0x3f) | (data->fan_div[1] << 6);
-+ }
-+ if (*nrels_mag >= 1) {
-+ data->fan_div[0] = DIV_TO_REG(results[0]);
-+ old = (old & 0xcf) | (data->fan_div[0] << 4);
-+ smsc47m1_write_value(client, SMSC47M1_REG_FANDIV, old);
-+ }
-+ }
-+}
-+
-+void smsc47m1_pwm(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct smsc47m1_data *data = client->data;
-+ int nr = 1 + ctl_name - SMSC47M1_SYSCTL_PWM1;
-+
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 0;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ smsc47m1_update_client(client);
-+ results[0] = PWM_FROM_REG(data->pwm[nr - 1]);
-+ results[1] = data->pwm[nr - 1] & 0x01;
-+ *nrels_mag = 2;
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ if (*nrels_mag >= 1) {
-+ data->pwm[nr - 1] &= 0x81;
-+ data->pwm[nr - 1] |= PWM_TO_REG(results[0]);
-+ if (*nrels_mag >= 2) {
-+ if(results[1] && (data->pwm[nr-1] & 0x01)) {
-+ /* enable PWM */
-+/* hope BIOS did it already
-+ smsc47m1_write_value(client,
-+ SMSC47M1_REG_PPIN(nr), 0x04);
-+*/
-+ data->pwm[nr - 1] &= 0xfe;
-+ } else if((!results[1]) && (!(data->pwm[nr-1] & 0x01))) {
-+ /* disable PWM */
-+ data->pwm[nr - 1] |= 0x01;
-+ }
-+ }
-+ smsc47m1_write_value(client, SMSC47M1_REG_PWM(nr),
-+ data->pwm[nr - 1]);
-+ }
-+ }
-+}
-+
-+static int __init sm_smsc47m1_init(void)
-+{
-+ int addr;
-+
-+ printk("smsc47m1.o version %s (%s)\n", LM_VERSION, LM_DATE);
-+
-+ if (smsc47m1_find(&addr)) {
-+ printk("smsc47m1.o: SMSC 47M1xx not detected, module not inserted.\n");
-+ return -ENODEV;
-+ }
-+ normal_isa[0] = addr;
-+
-+ return i2c_add_driver(&smsc47m1_driver);
-+}
-+
-+static void __exit sm_smsc47m1_exit(void)
-+{
-+ i2c_del_driver(&smsc47m1_driver);
-+}
-+
-+
-+
-+MODULE_AUTHOR("Mark D. Studebaker <mdsxyz123@yahoo.com>");
-+MODULE_DESCRIPTION("SMSC 47M1xx Fan sensors");
-+MODULE_LICENSE("GPL");
-+
-+module_init(sm_smsc47m1_init);
-+module_exit(sm_smsc47m1_exit);
---- linux-old/drivers/sensors/thmc50.c Thu Jan 1 00:00:00 1970
-+++ linux/drivers/sensors/thmc50.c Mon Dec 13 20:18:52 2004
-@@ -0,0 +1,496 @@
-+/*
-+ thmc50.c - Part of lm_sensors, Linux kernel modules for hardware
-+ monitoring
-+ Copyright (c) 1998, 1999 Frodo Looijaard <frodol@dds.nl> and
-+ Philip Edelbrock <phil@netroedge.com>
-+
-+ 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., 675 Mass Ave, Cambridge, MA 02139, USA.
-+*/
-+
-+#define DEBUG 1
-+
-+#include <linux/module.h>
-+#include <linux/slab.h>
-+#include <linux/i2c.h>
-+#include <linux/i2c-proc.h>
-+#include <linux/init.h>
-+#define LM_DATE "20041007"
-+#define LM_VERSION "2.8.8"
-+
-+MODULE_LICENSE("GPL");
-+
-+/* Addresses to scan */
-+static unsigned short normal_i2c[] = { SENSORS_I2C_END };
-+static unsigned short normal_i2c_range[] = { 0x2D, 0x2E, SENSORS_I2C_END };
-+static unsigned int normal_isa[] = { SENSORS_ISA_END };
-+static unsigned int normal_isa_range[] = { SENSORS_ISA_END };
-+
-+/* Insmod parameters */
-+SENSORS_INSMOD_1(thmc50);
-+
-+/* Many THMC50 constants specified below */
-+
-+/* The THMC50 registers */
-+#define THMC50_REG_TEMP 0x27
-+#define THMC50_REG_CONF 0x40
-+#define THMC50_REG_TEMP_HYST 0x3A
-+#define THMC50_REG_TEMP_OS 0x39
-+
-+#define THMC50_REG_TEMP_TRIP 0x13
-+#define THMC50_REG_TEMP_REMOTE_TRIP 0x14
-+#define THMC50_REG_TEMP_DEFAULT_TRIP 0x17
-+#define THMC50_REG_TEMP_REMOTE_DEFAULT_TRIP 0x18
-+#define THMC50_REG_ANALOG_OUT 0x19
-+#define THMC50_REG_REMOTE_TEMP 0x26
-+#define THMC50_REG_REMOTE_TEMP_HYST 0x38
-+#define THMC50_REG_REMOTE_TEMP_OS 0x37
-+
-+#define THMC50_REG_INTER 0x41
-+#define THMC50_REG_INTER_MIRROR 0x4C
-+#define THMC50_REG_INTER_MASK 0x43
-+
-+#define THMC50_REG_COMPANY_ID 0x3E
-+#define THMC50_REG_DIE_CODE 0x3F
-+
-+
-+/* Conversions. Rounding and limit checking is only done on the TO_REG
-+ variants. Note that you should be a bit careful with which arguments
-+ these macros are called: arguments may be evaluated more than once.
-+ Fixing this is just not worth it. */
-+#define TEMP_FROM_REG(val) ((val>127)?val - 0x0100:val)
-+#define TEMP_TO_REG(val) ((val<0)?0x0100+val:val)
-+
-+/* Each client has this additional data */
-+struct thmc50_data {
-+ struct i2c_client client;
-+ int sysctl_id;
-+
-+ struct semaphore update_lock;
-+ char valid; /* !=0 if following fields are valid */
-+ unsigned long last_updated; /* In jiffies */
-+
-+ u16 temp, temp_os, temp_hyst,
-+ remote_temp, remote_temp_os, remote_temp_hyst,
-+ inter, inter_mask, die_code, analog_out; /* Register values */
-+};
-+
-+static int thmc50_attach_adapter(struct i2c_adapter *adapter);
-+static int thmc50_detect(struct i2c_adapter *adapter, int address,
-+ unsigned short flags, int kind);
-+static void thmc50_init_client(struct i2c_client *client);
-+static int thmc50_detach_client(struct i2c_client *client);
-+
-+static int thmc50_read_value(struct i2c_client *client, u8 reg);
-+static int thmc50_write_value(struct i2c_client *client, u8 reg,
-+ u16 value);
-+static void thmc50_temp(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void thmc50_remote_temp(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag,
-+ long *results);
-+static void thmc50_inter(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void thmc50_inter_mask(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void thmc50_die_code(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void thmc50_analog_out(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void thmc50_update_client(struct i2c_client *client);
-+
-+
-+/* This is the driver that will be inserted */
-+static struct i2c_driver thmc50_driver = {
-+ .owner = THIS_MODULE,
-+ .name = "THMC50 sensor chip driver",
-+ .id = I2C_DRIVERID_THMC50,
-+ .flags = I2C_DF_NOTIFY,
-+ .attach_adapter = thmc50_attach_adapter,
-+ .detach_client = thmc50_detach_client,
-+};
-+
-+/* -- SENSORS SYSCTL START -- */
-+
-+#define THMC50_SYSCTL_TEMP 1200 /* Degrees Celcius */
-+#define THMC50_SYSCTL_REMOTE_TEMP 1201 /* Degrees Celcius */
-+#define THMC50_SYSCTL_INTER 1202
-+#define THMC50_SYSCTL_INTER_MASK 1203
-+#define THMC50_SYSCTL_DIE_CODE 1204
-+#define THMC50_SYSCTL_ANALOG_OUT 1205
-+
-+/* -- SENSORS SYSCTL END -- */
-+
-+/* These files are created for each detected THMC50. This is just a template;
-+ though at first sight, you might think we could use a statically
-+ allocated list, we need some way to get back to the parent - which
-+ is done through one of the 'extra' fields which are initialized
-+ when a new copy is allocated. */
-+static ctl_table thmc50_dir_table_template[] = {
-+ {THMC50_SYSCTL_TEMP, "temp1", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &thmc50_temp},
-+ {THMC50_SYSCTL_REMOTE_TEMP, "temp2", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &thmc50_remote_temp},
-+ {THMC50_SYSCTL_INTER, "inter", NULL, 0, 0444, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &thmc50_inter},
-+ {THMC50_SYSCTL_INTER_MASK, "inter_mask", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &thmc50_inter_mask},
-+ {THMC50_SYSCTL_DIE_CODE, "die_code", NULL, 0, 0444, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &thmc50_die_code},
-+ {THMC50_SYSCTL_ANALOG_OUT, "analog_out", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &thmc50_analog_out},
-+ {0}
-+};
-+
-+
-+static int thmc50_id = 0;
-+
-+static int thmc50_attach_adapter(struct i2c_adapter *adapter)
-+{
-+ return i2c_detect(adapter, &addr_data, thmc50_detect);
-+}
-+
-+/* This function is called by i2c_detect */
-+int thmc50_detect(struct i2c_adapter *adapter, int address,
-+ unsigned short flags, int kind)
-+{
-+ int company, i;
-+ struct i2c_client *new_client;
-+ struct thmc50_data *data;
-+ int err = 0;
-+ const char *type_name, *client_name;
-+
-+#ifdef DEBUG
-+ printk("thmc50.o: Probing for THMC50 at 0x%2X on bus %d\n",
-+ address, adapter->id);
-+#endif
-+
-+ /* Make sure we aren't probing the ISA bus!! This is just a safety check
-+ at this moment; i2c_detect really won't call us. */
-+#ifdef DEBUG
-+ if (i2c_is_isa_adapter(adapter)) {
-+ printk
-+ ("thmc50.o: thmc50_detect called for an ISA bus adapter?!?\n");
-+ return 0;
-+ }
-+#endif
-+
-+ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
-+ goto ERROR0;
-+
-+ /* OK. For now, we presume we have a valid client. We now create the
-+ client structure, even though we cannot fill it completely yet.
-+ But it allows us to access thmc50_{read,write}_value. */
-+ if (!(data = kmalloc(sizeof(struct thmc50_data), GFP_KERNEL))) {
-+ err = -ENOMEM;
-+ goto ERROR0;
-+ }
-+
-+ new_client = &data->client;
-+ new_client->addr = address;
-+ new_client->data = data;
-+ new_client->adapter = adapter;
-+ new_client->driver = &thmc50_driver;
-+ new_client->flags = 0;
-+
-+ /* Now, we do the remaining detection. */
-+ company =
-+ i2c_smbus_read_byte_data(new_client, THMC50_REG_COMPANY_ID);
-+
-+ if (company != 0x49) {
-+#ifdef DEBUG
-+ printk
-+ ("thmc50.o: Detect of THMC50 failed (reg 3E: 0x%X)\n",
-+ company);
-+#endif
-+ goto ERROR1;
-+ }
-+
-+ /* Determine the chip type - only one kind supported! */
-+ kind = thmc50;
-+
-+ if (kind == thmc50) {
-+ type_name = "thmc50";
-+ client_name = "THMC50 chip";
-+ } else {
-+#ifdef DEBUG
-+ printk("thmc50.o: Internal error: unknown kind (%d)?!?",
-+ kind);
-+#endif
-+ goto ERROR1;
-+ }
-+
-+ /* Fill in the remaining client fields and put it into the global list */
-+ strcpy(new_client->name, client_name);
-+
-+ new_client->id = thmc50_id++;
-+ data->valid = 0;
-+ init_MUTEX(&data->update_lock);
-+
-+ /* Tell the I2C layer a new client has arrived */
-+ if ((err = i2c_attach_client(new_client)))
-+ goto ERROR3;
-+
-+ /* Register a new directory entry with module sensors */
-+ if ((i = i2c_register_entry(new_client, type_name,
-+ thmc50_dir_table_template)) < 0) {
-+ err = i;
-+ goto ERROR4;
-+ }
-+ data->sysctl_id = i;
-+
-+ thmc50_init_client(new_client);
-+ return 0;
-+
-+/* OK, this is not exactly good programming practice, usually. But it is
-+ very code-efficient in this case. */
-+
-+ ERROR4:
-+ i2c_detach_client(new_client);
-+ ERROR3:
-+ ERROR1:
-+ kfree(data);
-+ ERROR0:
-+ return err;
-+}
-+
-+static int thmc50_detach_client(struct i2c_client *client)
-+{
-+ int err;
-+
-+ i2c_deregister_entry(((struct thmc50_data *) (client->data))->
-+ sysctl_id);
-+
-+ if ((err = i2c_detach_client(client))) {
-+ printk
-+ ("thmc50.o: Client deregistration failed, client not detached.\n");
-+ return err;
-+ }
-+
-+ kfree(client->data);
-+
-+ return 0;
-+}
-+
-+
-+/* All registers are word-sized, except for the configuration register.
-+ THMC50 uses a high-byte first convention, which is exactly opposite to
-+ the usual practice. */
-+static int thmc50_read_value(struct i2c_client *client, u8 reg)
-+{
-+ return i2c_smbus_read_byte_data(client, reg);
-+}
-+
-+/* All registers are word-sized, except for the configuration register.
-+ THMC50 uses a high-byte first convention, which is exactly opposite to
-+ the usual practice. */
-+static int thmc50_write_value(struct i2c_client *client, u8 reg, u16 value)
-+{
-+ return i2c_smbus_write_byte_data(client, reg, value);
-+}
-+
-+static void thmc50_init_client(struct i2c_client *client)
-+{
-+ thmc50_write_value(client, THMC50_REG_CONF, 1);
-+}
-+
-+static void thmc50_update_client(struct i2c_client *client)
-+{
-+ struct thmc50_data *data = client->data;
-+
-+ down(&data->update_lock);
-+
-+ if ((jiffies - data->last_updated > HZ + HZ / 2) ||
-+ (jiffies < data->last_updated) || !data->valid) {
-+
-+#ifdef DEBUG
-+ printk("Starting thmc50 update\n");
-+#endif
-+
-+ data->temp = thmc50_read_value(client, THMC50_REG_TEMP);
-+ data->temp_os =
-+ thmc50_read_value(client, THMC50_REG_TEMP_OS);
-+ data->temp_hyst =
-+ thmc50_read_value(client, THMC50_REG_TEMP_HYST);
-+ data->remote_temp =
-+ thmc50_read_value(client, THMC50_REG_REMOTE_TEMP);
-+ data->remote_temp_os =
-+ thmc50_read_value(client, THMC50_REG_REMOTE_TEMP_OS);
-+ data->remote_temp_hyst =
-+ thmc50_read_value(client, THMC50_REG_REMOTE_TEMP_HYST);
-+ data->inter = thmc50_read_value(client, THMC50_REG_INTER);
-+ data->inter_mask =
-+ thmc50_read_value(client, THMC50_REG_INTER_MASK);
-+ data->die_code =
-+ thmc50_read_value(client, THMC50_REG_DIE_CODE);
-+ data->analog_out =
-+ thmc50_read_value(client, THMC50_REG_ANALOG_OUT);
-+ data->last_updated = jiffies;
-+ data->valid = 1;
-+ }
-+
-+ up(&data->update_lock);
-+}
-+
-+
-+void thmc50_temp(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct thmc50_data *data = client->data;
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 0;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ thmc50_update_client(client);
-+ results[0] = TEMP_FROM_REG(data->temp_os);
-+ results[1] = TEMP_FROM_REG(data->temp_hyst);
-+ results[2] = TEMP_FROM_REG(data->temp);
-+ *nrels_mag = 3;
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ if (*nrels_mag >= 1) {
-+ data->temp_os = TEMP_TO_REG(results[0]);
-+ thmc50_write_value(client, THMC50_REG_TEMP_OS,
-+ data->temp_os);
-+ }
-+ if (*nrels_mag >= 2) {
-+ data->temp_hyst = TEMP_TO_REG(results[1]);
-+ thmc50_write_value(client, THMC50_REG_TEMP_HYST,
-+ data->temp_hyst);
-+ }
-+ }
-+}
-+
-+
-+void thmc50_remote_temp(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results)
-+{
-+ struct thmc50_data *data = client->data;
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 0;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ thmc50_update_client(client);
-+ results[0] = TEMP_FROM_REG(data->remote_temp_os);
-+ results[1] = TEMP_FROM_REG(data->remote_temp_hyst);
-+ results[2] = TEMP_FROM_REG(data->remote_temp);
-+ *nrels_mag = 3;
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ if (*nrels_mag >= 1) {
-+ data->remote_temp_os = TEMP_TO_REG(results[0]);
-+ thmc50_write_value(client,
-+ THMC50_REG_REMOTE_TEMP_OS,
-+ data->remote_temp_os);
-+ }
-+ if (*nrels_mag >= 2) {
-+ data->remote_temp_hyst = TEMP_TO_REG(results[1]);
-+ thmc50_write_value(client,
-+ THMC50_REG_REMOTE_TEMP_HYST,
-+ data->remote_temp_hyst);
-+ }
-+ }
-+}
-+
-+
-+void thmc50_inter(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct thmc50_data *data = client->data;
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 0;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ thmc50_update_client(client);
-+ results[0] = data->inter;
-+ *nrels_mag = 1;
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ printk("thmc50.o: No writes to Interrupt register!\n");
-+ }
-+}
-+
-+
-+void thmc50_inter_mask(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results)
-+{
-+ struct thmc50_data *data = client->data;
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 0;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ thmc50_update_client(client);
-+ results[0] = data->inter_mask;
-+ *nrels_mag = 1;
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ if (*nrels_mag >= 1) {
-+ data->inter_mask = results[0];
-+ thmc50_write_value(client, THMC50_REG_INTER_MASK,
-+ data->inter_mask);
-+ }
-+ }
-+}
-+
-+
-+void thmc50_die_code(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results)
-+{
-+ struct thmc50_data *data = client->data;
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 0;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ thmc50_update_client(client);
-+ results[0] = data->die_code;
-+ *nrels_mag = 1;
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ printk("thmc50.o: No writes to Die-Code register!\n");
-+ }
-+}
-+
-+
-+void thmc50_analog_out(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results)
-+{
-+ struct thmc50_data *data = client->data;
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 0;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ thmc50_update_client(client);
-+ results[0] = data->analog_out;
-+ *nrels_mag = 1;
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ if (*nrels_mag >= 1) {
-+ data->analog_out = results[0];
-+ thmc50_write_value(client, THMC50_REG_ANALOG_OUT,
-+ data->analog_out);
-+ }
-+ }
-+}
-+
-+
-+
-+
-+static int __init sm_thmc50_init(void)
-+{
-+ printk("thmc50.o version %s (%s)\n", LM_VERSION, LM_DATE);
-+
-+ return i2c_add_driver(&thmc50_driver);
-+}
-+
-+static void __exit sm_thmc50_exit(void)
-+{
-+ i2c_del_driver(&thmc50_driver);
-+}
-+
-+
-+
-+MODULE_AUTHOR
-+ ("Frodo Looijaard <frodol@dds.nl> and Philip Edelbrock <phil@netroedge.com>");
-+MODULE_DESCRIPTION("THMC50 driver");
-+
-+module_init(sm_thmc50_init);
-+module_exit(sm_thmc50_exit);
---- linux-old/drivers/sensors/via686a.c Thu Jan 1 00:00:00 1970
-+++ linux/drivers/sensors/via686a.c Mon Dec 13 20:18:52 2004
-@@ -0,0 +1,849 @@
-+/*
-+ via686a.c - Part of lm_sensors, Linux kernel modules
-+ for hardware monitoring
-+
-+ Copyright (c) 1998 - 2002 Frodo Looijaard <frodol@dds.nl>,
-+ Kyösti Mälkki <kmalkki@cc.hut.fi>,
-+ Mark Studebaker <mdsxyz123@yahoo.com>,
-+ and Bob Dougherty <bobd@stanford.edu>
-+ (Some conversion-factor data were contributed by Jonathan Teh Soon Yew
-+ <j.teh@iname.com> and Alex van Kaam <darkside@chello.nl>.)
-+
-+ 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., 675 Mass Ave, Cambridge, MA 02139, USA.
-+*/
-+
-+/*
-+ Supports the Via VT82C686A, VT82C686B south bridges.
-+ Reports all as a 686A.
-+ See doc/chips/via686a for details.
-+ Warning - only supports a single device.
-+*/
-+
-+#include <linux/module.h>
-+#include <linux/slab.h>
-+#include <linux/pci.h>
-+#include <linux/delay.h>
-+#include <linux/i2c.h>
-+#include <linux/i2c-proc.h>
-+#include <linux/init.h>
-+#include <asm/io.h>
-+#define LM_DATE "20041007"
-+#define LM_VERSION "2.8.8"
-+
-+
-+/* If force_addr is set to anything different from 0, we forcibly enable
-+ the device at the given address. */
-+static int force_addr = 0;
-+MODULE_PARM(force_addr, "i");
-+MODULE_PARM_DESC(force_addr,
-+ "Initialize the base address of the sensors");
-+
-+/* Addresses to scan.
-+ Note that we can't determine the ISA address until we have initialized
-+ our module */
-+static unsigned short normal_i2c[] = { SENSORS_I2C_END };
-+static unsigned short normal_i2c_range[] = { SENSORS_I2C_END };
-+static unsigned int normal_isa[] = { 0x0000, SENSORS_ISA_END };
-+static unsigned int normal_isa_range[] = { SENSORS_ISA_END };
-+
-+/* Insmod parameters */
-+SENSORS_INSMOD_1(via686a);
-+
-+/*
-+ The Via 686a southbridge has a LM78-like chip integrated on the same IC.
-+ This driver is a customized copy of lm78.c
-+*/
-+
-+/* Many VIA686A constants specified below */
-+
-+/* Length of ISA address segment */
-+#define VIA686A_EXTENT 0x80
-+#define VIA686A_BASE_REG 0x70
-+#define VIA686A_ENABLE_REG 0x74
-+
-+/* The VIA686A registers */
-+/* ins numbered 0-4 */
-+#define VIA686A_REG_IN_MAX(nr) (0x2b + ((nr) * 2))
-+#define VIA686A_REG_IN_MIN(nr) (0x2c + ((nr) * 2))
-+#define VIA686A_REG_IN(nr) (0x22 + (nr))
-+
-+/* fans numbered 1-2 */
-+#define VIA686A_REG_FAN_MIN(nr) (0x3a + (nr))
-+#define VIA686A_REG_FAN(nr) (0x28 + (nr))
-+
-+// the following values are as speced by VIA:
-+static const u8 regtemp[] = { 0x20, 0x21, 0x1f };
-+static const u8 regover[] = { 0x39, 0x3d, 0x1d };
-+static const u8 reghyst[] = { 0x3a, 0x3e, 0x1e };
-+
-+/* temps numbered 1-3 */
-+#define VIA686A_REG_TEMP(nr) (regtemp[(nr) - 1])
-+#define VIA686A_REG_TEMP_OVER(nr) (regover[(nr) - 1])
-+#define VIA686A_REG_TEMP_HYST(nr) (reghyst[(nr) - 1])
-+#define VIA686A_REG_TEMP_LOW1 0x4b // bits 7-6
-+#define VIA686A_REG_TEMP_LOW23 0x49 // 2 = bits 5-4, 3 = bits 7-6
-+
-+#define VIA686A_REG_ALARM1 0x41
-+#define VIA686A_REG_ALARM2 0x42
-+#define VIA686A_REG_FANDIV 0x47
-+#define VIA686A_REG_CONFIG 0x40
-+// The following register sets temp interrupt mode (bits 1-0 for temp1,
-+// 3-2 for temp2, 5-4 for temp3). Modes are:
-+// 00 interrupt stays as long as value is out-of-range
-+// 01 interrupt is cleared once register is read (default)
-+// 10 comparator mode- like 00, but ignores hysteresis
-+// 11 same as 00
-+#define VIA686A_REG_TEMP_MODE 0x4b
-+// We'll just assume that you want to set all 3 simultaneously:
-+#define VIA686A_TEMP_MODE_MASK 0x3F
-+#define VIA686A_TEMP_MODE_CONTINUOUS (0x00)
-+
-+/* Conversions. Limit checking is only done on the TO_REG
-+ variants. */
-+
-+/********* VOLTAGE CONVERSIONS (Bob Dougherty) ********/
-+// From HWMon.cpp (Copyright 1998-2000 Jonathan Teh Soon Yew):
-+// voltagefactor[0]=1.25/2628; (2628/1.25=2102.4) // Vccp
-+// voltagefactor[1]=1.25/2628; (2628/1.25=2102.4) // +2.5V
-+// voltagefactor[2]=1.67/2628; (2628/1.67=1573.7) // +3.3V
-+// voltagefactor[3]=2.6/2628; (2628/2.60=1010.8) // +5V
-+// voltagefactor[4]=6.3/2628; (2628/6.30=417.14) // +12V
-+// in[i]=(data[i+2]*25.0+133)*voltagefactor[i];
-+// That is:
-+// volts = (25*regVal+133)*factor
-+// regVal = (volts/factor-133)/25
-+// (These conversions were contributed by Jonathan Teh Soon Yew
-+// <j.teh@iname.com>)
-+static inline u8 IN_TO_REG(long val, int inNum)
-+{
-+ /* To avoid floating point, we multiply constants by 10 (100 for +12V).
-+ Rounding is done (120500 is actually 133000 - 12500).
-+ Remember that val is expressed in 0.01V/bit, which is why we divide
-+ by an additional 1000 (10000 for +12V): 100 for val and 10 (100)
-+ for the constants. */
-+ if (inNum <= 1)
-+ return (u8)
-+ SENSORS_LIMIT((val * 21024 - 120500) / 25000, 0, 255);
-+ else if (inNum == 2)
-+ return (u8)
-+ SENSORS_LIMIT((val * 15737 - 120500) / 25000, 0, 255);
-+ else if (inNum == 3)
-+ return (u8)
-+ SENSORS_LIMIT((val * 10108 - 120500) / 25000, 0, 255);
-+ else
-+ return (u8)
-+ SENSORS_LIMIT((val * 41714 - 1205000) / 250000, 0, 255);
-+}
-+
-+static inline long IN_FROM_REG(u8 val, int inNum)
-+{
-+ /* To avoid floating point, we multiply constants by 10 (100 for +12V).
-+ We also multiply them by 100 because we want 0.01V/bit for the
-+ output value. Rounding is done. */
-+ if (inNum <= 1)
-+ return (long) ((25000 * val + 133000 + 21024 / 2) / 21024);
-+ else if (inNum == 2)
-+ return (long) ((25000 * val + 133000 + 15737 / 2) / 15737);
-+ else if (inNum == 3)
-+ return (long) ((25000 * val + 133000 + 10108 / 2) / 10108);
-+ else
-+ return (long) ((250000 * val + 1330000 + 41714 / 2) / 41714);
-+}
-+
-+/********* FAN RPM CONVERSIONS ********/
-+// Higher register values = slower fans (the fan's strobe gates a counter).
-+// But this chip saturates back at 0, not at 255 like all the other chips.
-+// So, 0 means 0 RPM
-+static inline u8 FAN_TO_REG(long rpm, int div)
-+{
-+ if (rpm == 0)
-+ return 0;
-+ rpm = SENSORS_LIMIT(rpm, 1, 1000000);
-+ return SENSORS_LIMIT((1350000 + rpm * div / 2) / (rpm * div), 1, 255);
-+}
-+
-+#define FAN_FROM_REG(val,div) ((val)==0?0:(val)==255?0:1350000/((val)*(div)))
-+
-+/******** TEMP CONVERSIONS (Bob Dougherty) *********/
-+// linear fits from HWMon.cpp (Copyright 1998-2000 Jonathan Teh Soon Yew)
-+// if(temp<169)
-+// return double(temp)*0.427-32.08;
-+// else if(temp>=169 && temp<=202)
-+// return double(temp)*0.582-58.16;
-+// else
-+// return double(temp)*0.924-127.33;
-+//
-+// A fifth-order polynomial fits the unofficial data (provided by Alex van
-+// Kaam <darkside@chello.nl>) a bit better. It also give more reasonable
-+// numbers on my machine (ie. they agree with what my BIOS tells me).
-+// Here's the fifth-order fit to the 8-bit data:
-+// temp = 1.625093e-10*val^5 - 1.001632e-07*val^4 + 2.457653e-05*val^3 -
-+// 2.967619e-03*val^2 + 2.175144e-01*val - 7.090067e+0.
-+//
-+// (2000-10-25- RFD: thanks to Uwe Andersen <uandersen@mayah.com> for
-+// finding my typos in this formula!)
-+//
-+// Alas, none of the elegant function-fit solutions will work because we
-+// aren't allowed to use floating point in the kernel and doing it with
-+// integers doesn't rpovide enough precision. So we'll do boring old
-+// look-up table stuff. The unofficial data (see below) have effectively
-+// 7-bit resolution (they are rounded to the nearest degree). I'm assuming
-+// that the transfer function of the device is monotonic and smooth, so a
-+// smooth function fit to the data will allow us to get better precision.
-+// I used the 5th-order poly fit described above and solved for
-+// VIA register values 0-255. I *10 before rounding, so we get tenth-degree
-+// precision. (I could have done all 1024 values for our 10-bit readings,
-+// but the function is very linear in the useful range (0-80 deg C), so
-+// we'll just use linear interpolation for 10-bit readings.) So, tempLUT
-+// is the temp at via register values 0-255:
-+static const long tempLUT[] =
-+ { -709, -688, -667, -646, -627, -607, -589, -570, -553, -536, -519,
-+ -503, -487, -471, -456, -442, -428, -414, -400, -387, -375,
-+ -362, -350, -339, -327, -316, -305, -295, -285, -275, -265,
-+ -255, -246, -237, -229, -220, -212, -204, -196, -188, -180,
-+ -173, -166, -159, -152, -145, -139, -132, -126, -120, -114,
-+ -108, -102, -96, -91, -85, -80, -74, -69, -64, -59, -54, -49,
-+ -44, -39, -34, -29, -25, -20, -15, -11, -6, -2, 3, 7, 12, 16,
-+ 20, 25, 29, 33, 37, 42, 46, 50, 54, 59, 63, 67, 71, 75, 79, 84,
-+ 88, 92, 96, 100, 104, 109, 113, 117, 121, 125, 130, 134, 138,
-+ 142, 146, 151, 155, 159, 163, 168, 172, 176, 181, 185, 189,
-+ 193, 198, 202, 206, 211, 215, 219, 224, 228, 232, 237, 241,
-+ 245, 250, 254, 259, 263, 267, 272, 276, 281, 285, 290, 294,
-+ 299, 303, 307, 312, 316, 321, 325, 330, 334, 339, 344, 348,
-+ 353, 357, 362, 366, 371, 376, 380, 385, 390, 395, 399, 404,
-+ 409, 414, 419, 423, 428, 433, 438, 443, 449, 454, 459, 464,
-+ 469, 475, 480, 486, 491, 497, 502, 508, 514, 520, 526, 532,
-+ 538, 544, 551, 557, 564, 571, 578, 584, 592, 599, 606, 614,
-+ 621, 629, 637, 645, 654, 662, 671, 680, 689, 698, 708, 718,
-+ 728, 738, 749, 759, 770, 782, 793, 805, 818, 830, 843, 856,
-+ 870, 883, 898, 912, 927, 943, 958, 975, 991, 1008, 1026, 1044,
-+ 1062, 1081, 1101, 1121, 1141, 1162, 1184, 1206, 1229, 1252,
-+ 1276, 1301, 1326, 1352, 1378, 1406, 1434, 1462
-+};
-+
-+/* the original LUT values from Alex van Kaam <darkside@chello.nl>
-+ (for via register values 12-240):
-+{-50,-49,-47,-45,-43,-41,-39,-38,-37,-35,-34,-33,-32,-31,
-+-30,-29,-28,-27,-26,-25,-24,-24,-23,-22,-21,-20,-20,-19,-18,-17,-17,-16,-15,
-+-15,-14,-14,-13,-12,-12,-11,-11,-10,-9,-9,-8,-8,-7,-7,-6,-6,-5,-5,-4,-4,-3,
-+-3,-2,-2,-1,-1,0,0,1,1,1,3,3,3,4,4,4,5,5,5,6,6,7,7,8,8,9,9,9,10,10,11,11,12,
-+12,12,13,13,13,14,14,15,15,16,16,16,17,17,18,18,19,19,20,20,21,21,21,22,22,
-+22,23,23,24,24,25,25,26,26,26,27,27,27,28,28,29,29,30,30,30,31,31,32,32,33,
-+33,34,34,35,35,35,36,36,37,37,38,38,39,39,40,40,41,41,42,42,43,43,44,44,45,
-+45,46,46,47,48,48,49,49,50,51,51,52,52,53,53,54,55,55,56,57,57,58,59,59,60,
-+61,62,62,63,64,65,66,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,83,84,
-+85,86,88,89,91,92,94,96,97,99,101,103,105,107,109,110};
-+*/
-+
-+// Here's the reverse LUT. I got it by doing a 6-th order poly fit (needed
-+// an extra term for a good fit to these inverse data!) and then
-+// solving for each temp value from -50 to 110 (the useable range for
-+// this chip). Here's the fit:
-+// viaRegVal = -1.160370e-10*val^6 +3.193693e-08*val^5 - 1.464447e-06*val^4
-+// - 2.525453e-04*val^3 + 1.424593e-02*val^2 + 2.148941e+00*val +7.275808e+01)
-+// Note that n=161:
-+static const u8 viaLUT[] =
-+ { 12, 12, 13, 14, 14, 15, 16, 16, 17, 18, 18, 19, 20, 20, 21, 22, 23,
-+ 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 35, 36, 37, 39, 40,
-+ 41, 43, 45, 46, 48, 49, 51, 53, 55, 57, 59, 60, 62, 64, 66,
-+ 69, 71, 73, 75, 77, 79, 82, 84, 86, 88, 91, 93, 95, 98, 100,
-+ 103, 105, 107, 110, 112, 115, 117, 119, 122, 124, 126, 129,
-+ 131, 134, 136, 138, 140, 143, 145, 147, 150, 152, 154, 156,
-+ 158, 160, 162, 164, 166, 168, 170, 172, 174, 176, 178, 180,
-+ 182, 183, 185, 187, 188, 190, 192, 193, 195, 196, 198, 199,
-+ 200, 202, 203, 205, 206, 207, 208, 209, 210, 211, 212, 213,
-+ 214, 215, 216, 217, 218, 219, 220, 221, 222, 222, 223, 224,
-+ 225, 226, 226, 227, 228, 228, 229, 230, 230, 231, 232, 232,
-+ 233, 233, 234, 235, 235, 236, 236, 237, 237, 238, 238, 239,
-+ 239, 240
-+};
-+
-+/* Converting temps to (8-bit) hyst and over registers
-+ No interpolation here.
-+ The +50 is because the temps start at -50 */
-+static inline u8 TEMP_TO_REG(long val)
-+{
-+ return viaLUT[val <= -500 ? 0 : val >= 1100 ? 160 :
-+ (val < 0 ? val - 5 : val + 5) / 10 + 50];
-+}
-+
-+/* for 8-bit temperature hyst and over registers */
-+#define TEMP_FROM_REG(val) (tempLUT[(val)])
-+
-+/* for 10-bit temperature readings */
-+// You might _think_ this is too long to inline, but's it's really only
-+// called once...
-+static inline long TEMP_FROM_REG10(u16 val)
-+{
-+ // the temp values are already *10, so we don't need to do that.
-+ long temp;
-+ u16 eightBits = val >> 2;
-+ u16 twoBits = val & 3;
-+
-+ /* no interpolation for these */
-+ if (twoBits == 0 || eightBits == 255)
-+ return (long) tempLUT[eightBits];
-+
-+ /* do some linear interpolation */
-+ temp = (4 - twoBits) * tempLUT[eightBits]
-+ + twoBits * tempLUT[eightBits + 1];
-+ /* achieve rounding */
-+ return (temp < 0 ? temp - 2 : temp + 2) / 4;
-+}
-+
-+#define ALARMS_FROM_REG(val) (val)
-+
-+#define DIV_FROM_REG(val) (1 << (val))
-+#define DIV_TO_REG(val) ((val)==8?3:(val)==4?2:(val)==1?0:1)
-+
-+/* For the VIA686A, we need to keep some data in memory.
-+ The structure is dynamically allocated, at the same time when a new
-+ via686a client is allocated. */
-+struct via686a_data {
-+ struct i2c_client client;
-+ struct semaphore lock;
-+ int sysctl_id;
-+
-+ struct semaphore update_lock;
-+ char valid; /* !=0 if following fields are valid */
-+ unsigned long last_updated; /* In jiffies */
-+
-+ u8 in[5]; /* Register value */
-+ u8 in_max[5]; /* Register value */
-+ u8 in_min[5]; /* Register value */
-+ u8 fan[2]; /* Register value */
-+ u8 fan_min[2]; /* Register value */
-+ u16 temp[3]; /* Register value 10 bit */
-+ u8 temp_over[3]; /* Register value */
-+ u8 temp_hyst[3]; /* Register value */
-+ u8 fan_div[2]; /* Register encoding, shifted right */
-+ u16 alarms; /* Register encoding, combined */
-+};
-+
-+static struct pci_dev *s_bridge; /* pointer to the (only) via686a */
-+
-+static int via686a_attach_adapter(struct i2c_adapter *adapter);
-+static int via686a_detect(struct i2c_adapter *adapter, int address,
-+ unsigned short flags, int kind);
-+static int via686a_detach_client(struct i2c_client *client);
-+
-+static int via686a_read_value(struct i2c_client *client, u8 register);
-+static void via686a_write_value(struct i2c_client *client, u8 register,
-+ u8 value);
-+static void via686a_update_client(struct i2c_client *client);
-+static void via686a_init_client(struct i2c_client *client);
-+
-+
-+static void via686a_in(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void via686a_fan(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void via686a_temp(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void via686a_alarms(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void via686a_fan_div(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+
-+static int via686a_id = 0;
-+
-+/* The driver. I choose to use type i2c_driver, as at is identical to both
-+ smbus_driver and isa_driver, and clients could be of either kind */
-+static struct i2c_driver via686a_driver = {
-+ .owner = THIS_MODULE,
-+ .name = "VIA 686A",
-+ .id = I2C_DRIVERID_VIA686A,
-+ .flags = I2C_DF_NOTIFY,
-+ .attach_adapter = via686a_attach_adapter,
-+ .detach_client = via686a_detach_client,
-+};
-+
-+
-+
-+/* The /proc/sys entries */
-+
-+/* -- SENSORS SYSCTL START -- */
-+#define VIA686A_SYSCTL_IN0 1000
-+#define VIA686A_SYSCTL_IN1 1001
-+#define VIA686A_SYSCTL_IN2 1002
-+#define VIA686A_SYSCTL_IN3 1003
-+#define VIA686A_SYSCTL_IN4 1004
-+#define VIA686A_SYSCTL_FAN1 1101
-+#define VIA686A_SYSCTL_FAN2 1102
-+#define VIA686A_SYSCTL_TEMP 1200
-+#define VIA686A_SYSCTL_TEMP2 1201
-+#define VIA686A_SYSCTL_TEMP3 1202
-+#define VIA686A_SYSCTL_FAN_DIV 2000
-+#define VIA686A_SYSCTL_ALARMS 2001
-+
-+#define VIA686A_ALARM_IN0 0x01
-+#define VIA686A_ALARM_IN1 0x02
-+#define VIA686A_ALARM_IN2 0x04
-+#define VIA686A_ALARM_IN3 0x08
-+#define VIA686A_ALARM_TEMP 0x10
-+#define VIA686A_ALARM_FAN1 0x40
-+#define VIA686A_ALARM_FAN2 0x80
-+#define VIA686A_ALARM_IN4 0x100
-+#define VIA686A_ALARM_TEMP2 0x800
-+#define VIA686A_ALARM_CHAS 0x1000
-+#define VIA686A_ALARM_TEMP3 0x8000
-+
-+/* -- SENSORS SYSCTL END -- */
-+
-+/* These files are created for each detected VIA686A. This is just a template;
-+ though at first sight, you might think we could use a statically
-+ allocated list, we need some way to get back to the parent - which
-+ is done through one of the 'extra' fields which are initialized
-+ when a new copy is allocated. */
-+static ctl_table via686a_dir_table_template[] = {
-+ {VIA686A_SYSCTL_IN0, "in0", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &via686a_in},
-+ {VIA686A_SYSCTL_IN1, "in1", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &via686a_in},
-+ {VIA686A_SYSCTL_IN2, "in2", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &via686a_in},
-+ {VIA686A_SYSCTL_IN3, "in3", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &via686a_in},
-+ {VIA686A_SYSCTL_IN4, "in4", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &via686a_in},
-+ {VIA686A_SYSCTL_FAN1, "fan1", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &via686a_fan},
-+ {VIA686A_SYSCTL_FAN2, "fan2", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &via686a_fan},
-+ {VIA686A_SYSCTL_TEMP, "temp1", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &via686a_temp},
-+ {VIA686A_SYSCTL_TEMP2, "temp2", NULL, 0, 0644, NULL,
-+ &i2c_proc_real, &i2c_sysctl_real, NULL, &via686a_temp},
-+ {VIA686A_SYSCTL_TEMP3, "temp3", NULL, 0, 0644, NULL,
-+ &i2c_proc_real, &i2c_sysctl_real, NULL, &via686a_temp},
-+ {VIA686A_SYSCTL_FAN_DIV, "fan_div", NULL, 0, 0644, NULL,
-+ &i2c_proc_real, &i2c_sysctl_real, NULL, &via686a_fan_div},
-+ {VIA686A_SYSCTL_ALARMS, "alarms", NULL, 0, 0444, NULL,
-+ &i2c_proc_real, &i2c_sysctl_real, NULL, &via686a_alarms},
-+ {0}
-+};
-+
-+static inline int via686a_read_value(struct i2c_client *client, u8 reg)
-+{
-+ return (inb_p(client->addr + reg));
-+}
-+
-+static inline void via686a_write_value(struct i2c_client *client, u8 reg,
-+ u8 value)
-+{
-+ outb_p(value, client->addr + reg);
-+}
-+
-+/* This is called when the module is loaded */
-+static int via686a_attach_adapter(struct i2c_adapter *adapter)
-+{
-+ return i2c_detect(adapter, &addr_data, via686a_detect);
-+}
-+
-+int via686a_detect(struct i2c_adapter *adapter, int address,
-+ unsigned short flags, int kind)
-+{
-+ int i;
-+ struct i2c_client *new_client;
-+ struct via686a_data *data;
-+ int err = 0;
-+ const char *type_name = "via686a";
-+ u16 val;
-+
-+ /* Make sure we are probing the ISA bus!! */
-+ if (!i2c_is_isa_adapter(adapter)) {
-+ printk
-+ ("via686a.o: via686a_detect called for an I2C bus adapter?!?\n");
-+ return 0;
-+ }
-+
-+ /* 8231 requires multiple of 256, we enforce that on 686 as well */
-+ if(force_addr)
-+ address = force_addr & 0xFF00;
-+ if (check_region(address, VIA686A_EXTENT)) {
-+ printk("via686a.o: region 0x%x already in use!\n",
-+ address);
-+ return -ENODEV;
-+ }
-+
-+ if(force_addr) {
-+ printk("via686a.o: forcing ISA address 0x%04X\n", address);
-+ if (PCIBIOS_SUCCESSFUL !=
-+ pci_write_config_word(s_bridge, VIA686A_BASE_REG, address))
-+ return -ENODEV;
-+ }
-+ if (PCIBIOS_SUCCESSFUL !=
-+ pci_read_config_word(s_bridge, VIA686A_ENABLE_REG, &val))
-+ return -ENODEV;
-+ if (!(val & 0x0001)) {
-+ printk("via686a.o: enabling sensors\n");
-+ if (PCIBIOS_SUCCESSFUL !=
-+ pci_write_config_word(s_bridge, VIA686A_ENABLE_REG,
-+ val | 0x0001))
-+ return -ENODEV;
-+ }
-+
-+ if (!(data = kmalloc(sizeof(struct via686a_data), GFP_KERNEL))) {
-+ err = -ENOMEM;
-+ goto ERROR0;
-+ }
-+
-+ new_client = &data->client;
-+ new_client->addr = address;
-+ init_MUTEX(&data->lock);
-+ new_client->data = data;
-+ new_client->adapter = adapter;
-+ new_client->driver = &via686a_driver;
-+ new_client->flags = 0;
-+
-+ /* Reserve the ISA region */
-+ request_region(address, VIA686A_EXTENT, "via686a-sensors");
-+
-+ /* Fill in the remaining client fields and put into the global list */
-+ strcpy(new_client->name, "Via 686A Integrated Sensors");
-+
-+ new_client->id = via686a_id++;
-+ data->valid = 0;
-+ init_MUTEX(&data->update_lock);
-+
-+ /* Tell the I2C layer a new client has arrived */
-+ if ((err = i2c_attach_client(new_client)))
-+ goto ERROR3;
-+
-+ /* Register a new directory entry with module sensors */
-+ if ((i = i2c_register_entry((struct i2c_client *) new_client,
-+ type_name,
-+ via686a_dir_table_template)) < 0) {
-+ err = i;
-+ goto ERROR4;
-+ }
-+ data->sysctl_id = i;
-+
-+ /* Initialize the VIA686A chip */
-+ via686a_init_client(new_client);
-+ return 0;
-+
-+ ERROR4:
-+ i2c_detach_client(new_client);
-+ ERROR3:
-+ release_region(address, VIA686A_EXTENT);
-+ kfree(data);
-+ ERROR0:
-+ return err;
-+}
-+
-+static int via686a_detach_client(struct i2c_client *client)
-+{
-+ int err;
-+
-+ i2c_deregister_entry(((struct via686a_data *)
-+ (client->data))->sysctl_id);
-+
-+ if ((err = i2c_detach_client(client))) {
-+ printk
-+ ("via686a.o: Client deregistration failed, client not detached.\n");
-+ return err;
-+ }
-+
-+ release_region(client->addr, VIA686A_EXTENT);
-+ kfree(client->data);
-+
-+ return 0;
-+}
-+
-+/* Called when we have found a new VIA686A. */
-+static void via686a_init_client(struct i2c_client *client)
-+{
-+ u8 reg;
-+
-+ /* Start monitoring */
-+ reg = via686a_read_value(client, VIA686A_REG_CONFIG);
-+ via686a_write_value(client, VIA686A_REG_CONFIG, (reg|0x01)&0x7F);
-+
-+ /* Configure temp interrupt mode for continuous-interrupt operation */
-+ via686a_write_value(client, VIA686A_REG_TEMP_MODE,
-+ via686a_read_value(client, VIA686A_REG_TEMP_MODE) &
-+ !(VIA686A_TEMP_MODE_MASK | VIA686A_TEMP_MODE_CONTINUOUS));
-+}
-+
-+static void via686a_update_client(struct i2c_client *client)
-+{
-+ struct via686a_data *data = client->data;
-+ int i;
-+
-+ down(&data->update_lock);
-+
-+ if (time_after(jiffies - data->last_updated, HZ + HZ / 2) ||
-+ time_before(jiffies, data->last_updated) || !data->valid) {
-+
-+ for (i = 0; i <= 4; i++) {
-+ data->in[i] =
-+ via686a_read_value(client, VIA686A_REG_IN(i));
-+ data->in_min[i] = via686a_read_value(client,
-+ VIA686A_REG_IN_MIN
-+ (i));
-+ data->in_max[i] =
-+ via686a_read_value(client, VIA686A_REG_IN_MAX(i));
-+ }
-+ for (i = 1; i <= 2; i++) {
-+ data->fan[i - 1] =
-+ via686a_read_value(client, VIA686A_REG_FAN(i));
-+ data->fan_min[i - 1] = via686a_read_value(client,
-+ VIA686A_REG_FAN_MIN(i));
-+ }
-+ for (i = 1; i <= 3; i++) {
-+ data->temp[i - 1] = via686a_read_value(client,
-+ VIA686A_REG_TEMP(i)) << 2;
-+ data->temp_over[i - 1] =
-+ via686a_read_value(client,
-+ VIA686A_REG_TEMP_OVER(i));
-+ data->temp_hyst[i - 1] =
-+ via686a_read_value(client,
-+ VIA686A_REG_TEMP_HYST(i));
-+ }
-+ /* add in lower 2 bits
-+ temp1 uses bits 7-6 of VIA686A_REG_TEMP_LOW1
-+ temp2 uses bits 5-4 of VIA686A_REG_TEMP_LOW23
-+ temp3 uses bits 7-6 of VIA686A_REG_TEMP_LOW23
-+ */
-+ data->temp[0] |= (via686a_read_value(client,
-+ VIA686A_REG_TEMP_LOW1)
-+ & 0xc0) >> 6;
-+ data->temp[1] |=
-+ (via686a_read_value(client, VIA686A_REG_TEMP_LOW23) &
-+ 0x30) >> 4;
-+ data->temp[2] |=
-+ (via686a_read_value(client, VIA686A_REG_TEMP_LOW23) &
-+ 0xc0) >> 6;
-+
-+ i = via686a_read_value(client, VIA686A_REG_FANDIV);
-+ data->fan_div[0] = (i >> 4) & 0x03;
-+ data->fan_div[1] = i >> 6;
-+ data->alarms =
-+ via686a_read_value(client,
-+ VIA686A_REG_ALARM1) |
-+ (via686a_read_value(client, VIA686A_REG_ALARM2) << 8);
-+ data->last_updated = jiffies;
-+ data->valid = 1;
-+ }
-+
-+ up(&data->update_lock);
-+}
-+
-+
-+/* The next few functions are the call-back functions of the /proc/sys and
-+ sysctl files. Which function is used is defined in the ctl_table in
-+ the extra1 field.
-+ Each function must return the magnitude (power of 10 to divide the date
-+ with) if it is called with operation==SENSORS_PROC_REAL_INFO. It must
-+ put a maximum of *nrels elements in results reflecting the data of this
-+ file, and set *nrels to the number it actually put in it, if operation==
-+ SENSORS_PROC_REAL_READ. Finally, it must get upto *nrels elements from
-+ results and write them to the chip, if operations==SENSORS_PROC_REAL_WRITE.
-+ Note that on SENSORS_PROC_REAL_READ, I do not check whether results is
-+ large enough (by checking the incoming value of *nrels). This is not very
-+ good practice, but as long as you put less than about 5 values in results,
-+ you can assume it is large enough. */
-+static void via686a_in(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct via686a_data *data = client->data;
-+ int nr = ctl_name - VIA686A_SYSCTL_IN0;
-+
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 2;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ via686a_update_client(client);
-+ results[0] = IN_FROM_REG(data->in_min[nr], nr);
-+ results[1] = IN_FROM_REG(data->in_max[nr], nr);
-+ results[2] = IN_FROM_REG(data->in[nr], nr);
-+ *nrels_mag = 3;
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ if (*nrels_mag >= 1) {
-+ data->in_min[nr] = IN_TO_REG(results[0], nr);
-+ via686a_write_value(client, VIA686A_REG_IN_MIN(nr),
-+ data->in_min[nr]);
-+ }
-+ if (*nrels_mag >= 2) {
-+ data->in_max[nr] = IN_TO_REG(results[1], nr);
-+ via686a_write_value(client, VIA686A_REG_IN_MAX(nr),
-+ data->in_max[nr]);
-+ }
-+ }
-+}
-+
-+void via686a_fan(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct via686a_data *data = client->data;
-+ int nr = ctl_name - VIA686A_SYSCTL_FAN1 + 1;
-+
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 0;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ via686a_update_client(client);
-+ results[0] = FAN_FROM_REG(data->fan_min[nr - 1],
-+ DIV_FROM_REG(data->fan_div
-+ [nr - 1]));
-+ results[1] = FAN_FROM_REG(data->fan[nr - 1],
-+ DIV_FROM_REG(data->fan_div[nr - 1]));
-+ *nrels_mag = 2;
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ if (*nrels_mag >= 1) {
-+ data->fan_min[nr - 1] = FAN_TO_REG(results[0],
-+ DIV_FROM_REG(data->
-+ fan_div[nr -1]));
-+ via686a_write_value(client,
-+ VIA686A_REG_FAN_MIN(nr),
-+ data->fan_min[nr - 1]);
-+ }
-+ }
-+}
-+
-+void via686a_temp(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct via686a_data *data = client->data;
-+ int nr = ctl_name - VIA686A_SYSCTL_TEMP;
-+
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 1;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ via686a_update_client(client);
-+ results[0] = TEMP_FROM_REG(data->temp_over[nr]);
-+ results[1] = TEMP_FROM_REG(data->temp_hyst[nr]);
-+ results[2] = TEMP_FROM_REG10(data->temp[nr]);
-+ *nrels_mag = 3;
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ if (*nrels_mag >= 1) {
-+ data->temp_over[nr] = TEMP_TO_REG(results[0]);
-+ via686a_write_value(client,
-+ VIA686A_REG_TEMP_OVER(nr + 1),
-+ data->temp_over[nr]);
-+ }
-+ if (*nrels_mag >= 2) {
-+ data->temp_hyst[nr] = TEMP_TO_REG(results[1]);
-+ via686a_write_value(client,
-+ VIA686A_REG_TEMP_HYST(nr + 1),
-+ data->temp_hyst[nr]);
-+ }
-+ }
-+}
-+
-+void via686a_alarms(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct via686a_data *data = client->data;
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 0;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ via686a_update_client(client);
-+ results[0] = ALARMS_FROM_REG(data->alarms);
-+ *nrels_mag = 1;
-+ }
-+}
-+
-+void via686a_fan_div(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results)
-+{
-+ struct via686a_data *data = client->data;
-+ int old;
-+
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 0;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ via686a_update_client(client);
-+ results[0] = DIV_FROM_REG(data->fan_div[0]);
-+ results[1] = DIV_FROM_REG(data->fan_div[1]);
-+ *nrels_mag = 2;
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ old = via686a_read_value(client, VIA686A_REG_FANDIV);
-+ if (*nrels_mag >= 2) {
-+ data->fan_div[1] = DIV_TO_REG(results[1]);
-+ old = (old & 0x3f) | (data->fan_div[1] << 6);
-+ }
-+ if (*nrels_mag >= 1) {
-+ data->fan_div[0] = DIV_TO_REG(results[0]);
-+ old = (old & 0xcf) | (data->fan_div[0] << 4);
-+ via686a_write_value(client, VIA686A_REG_FANDIV,
-+ old);
-+ }
-+ }
-+}
-+
-+
-+static struct pci_device_id via686a_pci_ids[] __devinitdata = {
-+ {PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686_4, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
-+ { 0, }
-+};
-+
-+static int __devinit via686a_pci_probe(struct pci_dev *dev,
-+ const struct pci_device_id *id)
-+{
-+ u16 val;
-+ int addr = 0;
-+
-+ if (PCIBIOS_SUCCESSFUL !=
-+ pci_read_config_word(dev, VIA686A_BASE_REG, &val))
-+ return -ENODEV;
-+
-+ addr = val & ~(VIA686A_EXTENT - 1);
-+ if (addr == 0 && force_addr == 0) {
-+ printk("via686a.o: base address not set - upgrade BIOS or use force_addr=0xaddr\n");
-+ return -ENODEV;
-+ }
-+ if (force_addr)
-+ addr = force_addr; /* so detect will get called */
-+
-+ if (!addr) {
-+ printk("via686a.o: No Via 686A sensors found.\n");
-+ return -ENODEV;
-+ }
-+ normal_isa[0] = addr;
-+ s_bridge = dev;
-+ return i2c_add_driver(&via686a_driver);
-+}
-+
-+static void __devexit via686a_pci_remove(struct pci_dev *dev)
-+{
-+ i2c_del_driver(&via686a_driver);
-+}
-+
-+static struct pci_driver via686a_pci_driver = {
-+ .name = "via686a",
-+ .id_table = via686a_pci_ids,
-+ .probe = via686a_pci_probe,
-+ .remove = __devexit_p(via686a_pci_remove),
-+};
-+
-+static int __init sm_via686a_init(void)
-+{
-+ printk("via686a.o version %s (%s)\n", LM_VERSION, LM_DATE);
-+ return pci_module_init(&via686a_pci_driver);
-+}
-+
-+static void __exit sm_via686a_exit(void)
-+{
-+ pci_unregister_driver(&via686a_pci_driver);
-+}
-+
-+MODULE_AUTHOR("Kyösti Mälkki <kmalkki@cc.hut.fi>, "
-+ "Mark Studebaker <mdsxyz123@yahoo.com> "
-+ "and Bob Dougherty <bobd@stanford.edu>");
-+MODULE_DESCRIPTION("VIA 686A Sensor device");
-+MODULE_LICENSE("GPL");
-+
-+module_init(sm_via686a_init);
-+module_exit(sm_via686a_exit);
---- linux-old/drivers/sensors/vt1211.c Thu Jan 1 00:00:00 1970
-+++ linux/drivers/sensors/vt1211.c Mon Dec 13 20:18:53 2004
-@@ -0,0 +1,823 @@
-+/*
-+ vt1211.c - Part of lm_sensors, Linux kernel modules
-+ for hardware monitoring
-+
-+ Copyright (c) 2002 Mark D. Studebaker <mdsxyz123@yahoo.com>
-+
-+ 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., 675 Mass Ave, Cambridge, MA 02139, USA.
-+*/
-+
-+/* Supports VIA VT1211 Super I/O sensors via ISA (LPC) accesses only. */
-+
-+#include <linux/module.h>
-+#include <linux/slab.h>
-+#include <linux/ioport.h>
-+#include <linux/i2c.h>
-+#include <linux/i2c-proc.h>
-+#include <linux/init.h>
-+#include <asm/io.h>
-+#define LM_DATE "20041007"
-+#define LM_VERSION "2.8.8"
-+#include <linux/sensors_vid.h>
-+
-+static int force_addr = 0;
-+MODULE_PARM(force_addr, "i");
-+MODULE_PARM_DESC(force_addr,
-+ "Initialize the base address of the sensors");
-+
-+static unsigned short normal_i2c[] = { SENSORS_I2C_END };
-+static unsigned short normal_i2c_range[] = { SENSORS_I2C_END };
-+static unsigned int normal_isa[] = { 0x0000, SENSORS_ISA_END };
-+static unsigned int normal_isa_range[] = { SENSORS_ISA_END };
-+
-+SENSORS_INSMOD_1(vt1211);
-+
-+/* modified from kernel/include/traps.c */
-+#define REG 0x2e /* The register to read/write */
-+#define DEV 0x07 /* Register: Logical device select */
-+#define VAL 0x2f /* The value to read/write */
-+#define PME 0x0b /* The device with the hardware monitor */
-+#define DEVID 0x20 /* Register: Device ID */
-+
-+static inline void
-+superio_outb(int reg, int val)
-+{
-+ outb(reg, REG);
-+ outb(val, VAL);
-+}
-+
-+static inline int
-+superio_inb(int reg)
-+{
-+ outb(reg, REG);
-+ return inb(VAL);
-+}
-+
-+static inline void
-+superio_select(void)
-+{
-+ outb(DEV, REG);
-+ outb(PME, VAL);
-+}
-+
-+static inline void
-+superio_enter(void)
-+{
-+ outb(0x87, REG);
-+ outb(0x87, REG);
-+}
-+
-+static inline void
-+superio_exit(void)
-+{
-+ outb(0xAA, REG);
-+}
-+
-+#define VT1211_DEVID 0x3c
-+#define VT1211_ACT_REG 0x30
-+#define VT1211_BASE_REG 0x60
-+
-+#define VT1211_EXTENT 0x80
-+
-+/* pwm numbered 1-2 */
-+#define VT1211_REG_PWM(nr) (0x5f + (nr))
-+#define VT1211_REG_PWM_CTL 0x51
-+
-+/* The VT1211 registers */
-+/* We define the sensors as follows. Somewhat convoluted to minimize
-+ changes from via686a.
-+ Sensor Voltage Mode Temp Mode
-+ -------- ------------ ---------
-+ Reading 1 temp3
-+ Reading 3 temp1 not in vt1211
-+ UCH1/Reading2 in0 temp2
-+ UCH2 in1 temp4
-+ UCH3 in2 temp5
-+ UCH4 in3 temp6
-+ UCH5 in4 temp7
-+ 3.3V in5
-+ -12V in6 not in vt1211
-+*/
-+
-+/* ins numbered 0-6 */
-+#define VT1211_REG_IN_MAX(nr) ((nr)==0 ? 0x3d : 0x29 + ((nr) * 2))
-+#define VT1211_REG_IN_MIN(nr) ((nr)==0 ? 0x3e : 0x2a + ((nr) * 2))
-+#define VT1211_REG_IN(nr) (0x21 + (nr))
-+
-+/* fans numbered 1-2 */
-+#define VT1211_REG_FAN_MIN(nr) (0x3a + (nr))
-+#define VT1211_REG_FAN(nr) (0x28 + (nr))
-+
-+static const u8 regtemp[] = { 0x20, 0x21, 0x1f, 0x22, 0x23, 0x24, 0x25 };
-+static const u8 regover[] = { 0x39, 0x3d, 0x1d, 0x2b, 0x2d, 0x2f, 0x31 };
-+static const u8 reghyst[] = { 0x3a, 0x3e, 0x1e, 0x2c, 0x2e, 0x30, 0x32 };
-+
-+/* temps numbered 1-7 */
-+#define VT1211_REG_TEMP(nr) (regtemp[(nr) - 1])
-+#define VT1211_REG_TEMP_OVER(nr) (regover[(nr) - 1])
-+#define VT1211_REG_TEMP_HYST(nr) (reghyst[(nr) - 1])
-+#define VT1211_REG_TEMP_LOW3 0x4b /* bits 7-6 */
-+#define VT1211_REG_TEMP_LOW2 0x49 /* bits 5-4 */
-+#define VT1211_REG_TEMP_LOW47 0x4d
-+
-+#define VT1211_REG_CONFIG 0x40
-+#define VT1211_REG_ALARM1 0x41
-+#define VT1211_REG_ALARM2 0x42
-+#define VT1211_REG_VID 0x45
-+#define VT1211_REG_FANDIV 0x47
-+#define VT1211_REG_UCH_CONFIG 0x4a
-+#define VT1211_REG_TEMP1_CONFIG 0x4b
-+#define VT1211_REG_TEMP2_CONFIG 0x4c
-+
-+/* temps 1-7; voltages 0-6 */
-+#define ISTEMP(i, ch_config) ((i) == 1 ? 1 : \
-+ (i) == 3 ? 1 : \
-+ (i) == 2 ? ((ch_config) >> 1) & 0x01 : \
-+ ((ch_config) >> ((i)-1)) & 0x01)
-+#define ISVOLT(i, ch_config) ((i) > 4 ? 1 : !(((ch_config) >> ((i)+2)) & 0x01))
-+
-+#define DIV_FROM_REG(val) (1 << (val))
-+#define DIV_TO_REG(val) ((val)==8?3:(val)==4?2:(val)==1?0:1)
-+#define PWM_FROM_REG(val) (val)
-+#define PWM_TO_REG(val) SENSORS_LIMIT((val), 0, 255)
-+
-+#define TEMP_FROM_REG(val) ((val)*10)
-+#define TEMP_FROM_REG10(val) (((val)*10)/4)
-+#define TEMP_TO_REG(val) (SENSORS_LIMIT(((val)<0?(((val)-5)/10):\
-+ ((val)+5)/10),0,255))
-+#define IN_FROM_REG(val) /*(((val)*10+5)/10)*/ (val)
-+#define IN_TO_REG(val) (SENSORS_LIMIT((((val) * 10 + 5)/10),0,255))
-+
-+
-+/********* FAN RPM CONVERSIONS ********/
-+/* But this chip saturates back at 0, not at 255 like all the other chips.
-+ So, 0 means 0 RPM */
-+static inline u8 FAN_TO_REG(long rpm, int div)
-+{
-+ if (rpm == 0)
-+ return 0;
-+ rpm = SENSORS_LIMIT(rpm, 1, 1000000);
-+ return SENSORS_LIMIT((1310720 + rpm * div / 2) / (rpm * div), 1, 255);
-+}
-+
-+#define MIN_TO_REG(a,b) FAN_TO_REG(a,b)
-+#define FAN_FROM_REG(val,div) ((val)==0?0:(val)==255?0:1310720/((val)*(div)))
-+
-+struct vt1211_data {
-+ struct i2c_client client;
-+ struct semaphore lock;
-+ int sysctl_id;
-+
-+ struct semaphore update_lock;
-+ char valid; /* !=0 if following fields are valid */
-+ unsigned long last_updated; /* In jiffies */
-+
-+ u8 in[7]; /* Register value */
-+ u8 in_max[7]; /* Register value */
-+ u8 in_min[7]; /* Register value */
-+ u16 temp[7]; /* Register value 10 bit */
-+ u8 temp_over[7]; /* Register value */
-+ u8 temp_hyst[7]; /* Register value */
-+ u8 fan[2]; /* Register value */
-+ u8 fan_min[2]; /* Register value */
-+ u8 fan_div[2]; /* Register encoding, shifted right */
-+ u16 alarms; /* Register encoding */
-+ u8 pwm[2]; /* Register value */
-+ u8 pwm_ctl; /* Register value */
-+ u8 vid; /* Register encoding */
-+ u8 vrm;
-+ u8 uch_config;
-+};
-+
-+static int vt1211_attach_adapter(struct i2c_adapter *adapter);
-+static int vt1211_detect(struct i2c_adapter *adapter, int address,
-+ unsigned short flags, int kind);
-+static int vt1211_detach_client(struct i2c_client *client);
-+
-+static inline int vt_rdval(struct i2c_client *client, u8 register);
-+static inline void vt1211_write_value(struct i2c_client *client, u8 register,
-+ u8 value);
-+static void vt1211_update_client(struct i2c_client *client);
-+static void vt1211_init_client(struct i2c_client *client);
-+static int vt1211_find(int *address);
-+
-+
-+static void vt1211_fan(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void vt1211_alarms(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void vt1211_fan_div(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void vt1211_in(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void vt1211_pwm(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void vt1211_vid(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void vt1211_vrm(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void vt1211_uch(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void vt1211_temp(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+
-+static int vt1211_id = 0;
-+
-+static struct i2c_driver vt1211_driver = {
-+ .owner = THIS_MODULE,
-+ .name = "VT1211 sensors driver",
-+ .id = I2C_DRIVERID_VT1211,
-+ .flags = I2C_DF_NOTIFY,
-+ .attach_adapter = vt1211_attach_adapter,
-+ .detach_client = vt1211_detach_client,
-+};
-+
-+/* -- SENSORS SYSCTL START -- */
-+#define VT1211_SYSCTL_IN0 1000
-+#define VT1211_SYSCTL_IN1 1001
-+#define VT1211_SYSCTL_IN2 1002
-+#define VT1211_SYSCTL_IN3 1003
-+#define VT1211_SYSCTL_IN4 1004
-+#define VT1211_SYSCTL_IN5 1005
-+#define VT1211_SYSCTL_IN6 1006
-+#define VT1211_SYSCTL_FAN1 1101
-+#define VT1211_SYSCTL_FAN2 1102
-+#define VT1211_SYSCTL_TEMP 1200
-+#define VT1211_SYSCTL_TEMP2 1201
-+#define VT1211_SYSCTL_TEMP3 1202
-+#define VT1211_SYSCTL_TEMP4 1203
-+#define VT1211_SYSCTL_TEMP5 1204
-+#define VT1211_SYSCTL_TEMP6 1205
-+#define VT1211_SYSCTL_TEMP7 1206
-+#define VT1211_SYSCTL_VID 1300
-+#define VT1211_SYSCTL_PWM1 1401
-+#define VT1211_SYSCTL_PWM2 1402
-+#define VT1211_SYSCTL_VRM 1600
-+#define VT1211_SYSCTL_UCH 1700
-+#define VT1211_SYSCTL_FAN_DIV 2000
-+#define VT1211_SYSCTL_ALARMS 2001
-+
-+#define VT1211_ALARM_IN1 0x01
-+#define VT1211_ALARM_IN2 0x02
-+#define VT1211_ALARM_IN5 0x04
-+#define VT1211_ALARM_IN3 0x08
-+#define VT1211_ALARM_TEMP 0x10
-+#define VT1211_ALARM_FAN1 0x40
-+#define VT1211_ALARM_FAN2 0x80
-+#define VT1211_ALARM_IN4 0x100
-+#define VT1211_ALARM_IN6 0x200
-+#define VT1211_ALARM_TEMP2 0x800
-+#define VT1211_ALARM_CHAS 0x1000
-+#define VT1211_ALARM_TEMP3 0x8000
-+/* duplicates */
-+#define VT1211_ALARM_IN0 VT1211_ALARM_TEMP
-+#define VT1211_ALARM_TEMP4 VT1211_ALARM_IN1
-+#define VT1211_ALARM_TEMP5 VT1211_ALARM_IN2
-+#define VT1211_ALARM_TEMP6 VT1211_ALARM_IN3
-+#define VT1211_ALARM_TEMP7 VT1211_ALARM_IN4
-+
-+/* -- SENSORS SYSCTL END -- */
-+
-+static ctl_table vt1211_dir_table_template[] = {
-+ {VT1211_SYSCTL_IN0, "in0", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &vt1211_in},
-+ {VT1211_SYSCTL_IN1, "in1", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &vt1211_in},
-+ {VT1211_SYSCTL_IN2, "in2", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &vt1211_in},
-+ {VT1211_SYSCTL_IN3, "in3", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &vt1211_in},
-+ {VT1211_SYSCTL_IN4, "in4", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &vt1211_in},
-+ {VT1211_SYSCTL_IN5, "in5", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &vt1211_in},
-+/*
-+ datasheet says these are reserved
-+ {VT1211_SYSCTL_IN6, "in6", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &vt1211_in},
-+ {VT1211_SYSCTL_TEMP, "temp1", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &vt1211_temp},
-+*/
-+ {VT1211_SYSCTL_TEMP2, "temp2", NULL, 0, 0644, NULL,
-+ &i2c_proc_real, &i2c_sysctl_real, NULL, &vt1211_temp},
-+ {VT1211_SYSCTL_TEMP3, "temp3", NULL, 0, 0644, NULL,
-+ &i2c_proc_real, &i2c_sysctl_real, NULL, &vt1211_temp},
-+ {VT1211_SYSCTL_TEMP4, "temp4", NULL, 0, 0644, NULL,
-+ &i2c_proc_real, &i2c_sysctl_real, NULL, &vt1211_temp},
-+ {VT1211_SYSCTL_TEMP5, "temp5", NULL, 0, 0644, NULL,
-+ &i2c_proc_real, &i2c_sysctl_real, NULL, &vt1211_temp},
-+ {VT1211_SYSCTL_TEMP6, "temp6", NULL, 0, 0644, NULL,
-+ &i2c_proc_real, &i2c_sysctl_real, NULL, &vt1211_temp},
-+ {VT1211_SYSCTL_TEMP7, "temp7", NULL, 0, 0644, NULL,
-+ &i2c_proc_real, &i2c_sysctl_real, NULL, &vt1211_temp},
-+ {VT1211_SYSCTL_FAN1, "fan1", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &vt1211_fan},
-+ {VT1211_SYSCTL_FAN2, "fan2", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &vt1211_fan},
-+ {VT1211_SYSCTL_FAN_DIV, "fan_div", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &vt1211_fan_div},
-+ {VT1211_SYSCTL_ALARMS, "alarms", NULL, 0, 0444, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &vt1211_alarms},
-+ {VT1211_SYSCTL_PWM1, "pwm1", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &vt1211_pwm},
-+ {VT1211_SYSCTL_PWM2, "pwm2", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &vt1211_pwm},
-+ {VT1211_SYSCTL_VID, "vid", NULL, 0, 0444, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &vt1211_vid},
-+ {VT1211_SYSCTL_VRM, "vrm", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &vt1211_vrm},
-+ {VT1211_SYSCTL_UCH, "uch_config", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &vt1211_uch},
-+ {0}
-+};
-+
-+static int vt1211_attach_adapter(struct i2c_adapter *adapter)
-+{
-+ return i2c_detect(adapter, &addr_data, vt1211_detect);
-+}
-+
-+static int vt1211_find(int *address)
-+{
-+ u16 val;
-+
-+ superio_enter();
-+ val= superio_inb(DEVID);
-+ if(VT1211_DEVID != val) {
-+ superio_exit();
-+ return -ENODEV;
-+ }
-+
-+ superio_select();
-+ val = (superio_inb(VT1211_BASE_REG) << 8) |
-+ superio_inb(VT1211_BASE_REG + 1);
-+ *address = val & ~(VT1211_EXTENT - 1);
-+ if (*address == 0 && force_addr == 0) {
-+ printk("vt1211.o: base address not set - use force_addr=0xaddr\n");
-+ superio_exit();
-+ return -ENODEV;
-+ }
-+ if (force_addr)
-+ *address = force_addr; /* so detect will get called */
-+
-+ superio_exit();
-+ return 0;
-+}
-+
-+int vt1211_detect(struct i2c_adapter *adapter, int address,
-+ unsigned short flags, int kind)
-+{
-+ int i;
-+ struct i2c_client *new_client;
-+ struct vt1211_data *data;
-+ int err = 0;
-+ u8 val;
-+ const char *type_name = "vt1211";
-+ const char *client_name = "VT1211 chip";
-+
-+ if (!i2c_is_isa_adapter(adapter)) {
-+ return 0;
-+ }
-+
-+ if(force_addr)
-+ address = force_addr & ~(VT1211_EXTENT - 1);
-+ if (check_region(address, VT1211_EXTENT)) {
-+ printk("vt1211.o: region 0x%x already in use!\n", address);
-+ return -ENODEV;
-+ }
-+ if(force_addr) {
-+ printk("vt1211.o: forcing ISA address 0x%04X\n", address);
-+ superio_enter();
-+ superio_select();
-+ superio_outb(VT1211_BASE_REG, address >> 8);
-+ superio_outb(VT1211_BASE_REG+1, address & 0xff);
-+ superio_exit();
-+ }
-+
-+ superio_enter();
-+ superio_select();
-+ if((val = 0x01 & superio_inb(VT1211_ACT_REG)) == 0)
-+ superio_outb(VT1211_ACT_REG, 1);
-+ superio_exit();
-+
-+ if (!(data = kmalloc(sizeof(struct vt1211_data), GFP_KERNEL))) {
-+ return -ENOMEM;
-+ }
-+
-+ new_client = &data->client;
-+ new_client->addr = address;
-+ init_MUTEX(&data->lock);
-+ new_client->data = data;
-+ new_client->adapter = adapter;
-+ new_client->driver = &vt1211_driver;
-+ new_client->flags = 0;
-+
-+ request_region(address, VT1211_EXTENT, "vt1211-sensors");
-+ strcpy(new_client->name, client_name);
-+
-+ new_client->id = vt1211_id++;
-+ data->valid = 0;
-+ init_MUTEX(&data->update_lock);
-+
-+ if ((err = i2c_attach_client(new_client)))
-+ goto ERROR3;
-+
-+ if ((i = i2c_register_entry((struct i2c_client *) new_client,
-+ type_name,
-+ vt1211_dir_table_template)) < 0) {
-+ err = i;
-+ goto ERROR4;
-+ }
-+ data->sysctl_id = i;
-+
-+ vt1211_init_client(new_client);
-+ return 0;
-+
-+ ERROR4:
-+ i2c_detach_client(new_client);
-+ ERROR3:
-+ release_region(address, VT1211_EXTENT);
-+ kfree(data);
-+ return err;
-+}
-+
-+static int vt1211_detach_client(struct i2c_client *client)
-+{
-+ int err;
-+
-+ i2c_deregister_entry(((struct vt1211_data *) (client->data))->
-+ sysctl_id);
-+
-+ if ((err = i2c_detach_client(client))) {
-+ printk
-+ ("vt1211.o: Client deregistration failed, client not detached.\n");
-+ return err;
-+ }
-+
-+ release_region(client->addr, VT1211_EXTENT);
-+ kfree(client->data);
-+
-+ return 0;
-+}
-+
-+static inline int vt_rdval(struct i2c_client *client, u8 reg)
-+{
-+ return (inb_p(client->addr + reg));
-+}
-+
-+static inline void vt1211_write_value(struct i2c_client *client, u8 reg, u8 value)
-+{
-+ outb_p(value, client->addr + reg);
-+}
-+
-+static void vt1211_init_client(struct i2c_client *client)
-+{
-+ struct vt1211_data *data = client->data;
-+
-+ data->vrm = DEFAULT_VRM;
-+ /* set "default" interrupt mode for alarms, which isn't the default */
-+ vt1211_write_value(client, VT1211_REG_TEMP1_CONFIG, 0);
-+ vt1211_write_value(client, VT1211_REG_TEMP2_CONFIG, 0);
-+}
-+
-+static void vt1211_update_client(struct i2c_client *client)
-+{
-+ struct vt1211_data *data = client->data;
-+ int i, j;
-+
-+ down(&data->update_lock);
-+
-+ if ((jiffies - data->last_updated > HZ + HZ / 2) ||
-+ (jiffies < data->last_updated) || !data->valid) {
-+ data->uch_config = vt_rdval(client, VT1211_REG_UCH_CONFIG);
-+ for (i = 0; i <= 5; i++) {
-+ if(ISVOLT(i, data->uch_config)) {
-+ data->in[i] = vt_rdval(client, VT1211_REG_IN(i));
-+ data->in_min[i] = vt_rdval(client,
-+ VT1211_REG_IN_MIN(i));
-+ data->in_max[i] = vt_rdval(client,
-+ VT1211_REG_IN_MAX(i));
-+ } else {
-+ data->in[i] = 0;
-+ data->in_min[i] = 0;
-+ data->in_max[i] = 0;
-+ }
-+ }
-+ for (i = 1; i <= 2; i++) {
-+ data->fan[i - 1] = vt_rdval(client, VT1211_REG_FAN(i));
-+ data->fan_min[i - 1] = vt_rdval(client,
-+ VT1211_REG_FAN_MIN(i));
-+ }
-+ for (i = 2; i <= 7; i++) {
-+ if(ISTEMP(i, data->uch_config)) {
-+ data->temp[i - 1] = vt_rdval(client,
-+ VT1211_REG_TEMP(i)) << 2;
-+ switch(i) {
-+ case 1:
-+ /* ? */
-+ j = 0;
-+ break;
-+ case 2:
-+ j = (vt_rdval(client,
-+ VT1211_REG_TEMP_LOW2) &
-+ 0x30) >> 4;
-+ break;
-+ case 3:
-+ j = (vt_rdval(client,
-+ VT1211_REG_TEMP_LOW3) &
-+ 0xc0) >> 6;
-+ break;
-+ case 4:
-+ case 5:
-+ case 6:
-+ case 7:
-+ default:
-+ j = (vt_rdval(client,
-+ VT1211_REG_TEMP_LOW47) >>
-+ ((i-4)*2)) & 0x03;
-+ break;
-+
-+ }
-+ data->temp[i - 1] |= j;
-+ data->temp_over[i - 1] = vt_rdval(client,
-+ VT1211_REG_TEMP_OVER(i));
-+ data->temp_hyst[i - 1] = vt_rdval(client,
-+ VT1211_REG_TEMP_HYST(i));
-+ } else {
-+ data->temp[i - 1] = 0;
-+ data->temp_over[i - 1] = 0;
-+ data->temp_hyst[i - 1] = 0;
-+ }
-+ }
-+
-+ for (i = 1; i <= 2; i++) {
-+ data->fan[i - 1] = vt_rdval(client, VT1211_REG_FAN(i));
-+ data->fan_min[i - 1] = vt_rdval(client,
-+ VT1211_REG_FAN_MIN(i));
-+ data->pwm[i - 1] = vt_rdval(client, VT1211_REG_PWM(i));
-+ }
-+
-+ data->pwm_ctl = vt_rdval(client, VT1211_REG_PWM_CTL);
-+ i = vt_rdval(client, VT1211_REG_FANDIV);
-+ data->fan_div[0] = (i >> 4) & 0x03;
-+ data->fan_div[1] = i >> 6;
-+ data->alarms = vt_rdval(client, VT1211_REG_ALARM1) |
-+ (vt_rdval(client, VT1211_REG_ALARM2) << 8);
-+ data->vid= vt_rdval(client, VT1211_REG_VID) & 0x1f;
-+ data->last_updated = jiffies;
-+ data->valid = 1;
-+ }
-+
-+ up(&data->update_lock);
-+}
-+
-+
-+void vt1211_in(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct vt1211_data *data = client->data;
-+ int nr = ctl_name - VT1211_SYSCTL_IN0;
-+
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 2;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ vt1211_update_client(client);
-+ results[0] = IN_FROM_REG(data->in_min[nr]);
-+ results[1] = IN_FROM_REG(data->in_max[nr]);
-+ results[2] = IN_FROM_REG(data->in[nr]);
-+ *nrels_mag = 3;
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ if (*nrels_mag >= 1) {
-+ data->in_min[nr] = IN_TO_REG(results[0]);
-+ vt1211_write_value(client, VT1211_REG_IN_MIN(nr),
-+ data->in_min[nr]);
-+ }
-+ if (*nrels_mag >= 2) {
-+ data->in_max[nr] = IN_TO_REG(results[1]);
-+ vt1211_write_value(client, VT1211_REG_IN_MAX(nr),
-+ data->in_max[nr]);
-+ }
-+ }
-+}
-+
-+void vt1211_fan(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct vt1211_data *data = client->data;
-+ int nr = ctl_name - VT1211_SYSCTL_FAN1 + 1;
-+
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 0;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ vt1211_update_client(client);
-+ results[0] = FAN_FROM_REG(data->fan_min[nr - 1],
-+ DIV_FROM_REG(data->fan_div
-+ [nr - 1]));
-+ results[1] = FAN_FROM_REG(data->fan[nr - 1],
-+ DIV_FROM_REG(data->fan_div[nr - 1]));
-+ *nrels_mag = 2;
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ if (*nrels_mag >= 1) {
-+ data->fan_min[nr - 1] = MIN_TO_REG(results[0],
-+ DIV_FROM_REG
-+ (data->
-+ fan_div[nr-1]));
-+ vt1211_write_value(client, VT1211_REG_FAN_MIN(nr),
-+ data->fan_min[nr - 1]);
-+ }
-+ }
-+}
-+
-+
-+void vt1211_temp(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct vt1211_data *data = client->data;
-+ int nr = ctl_name - VT1211_SYSCTL_TEMP;
-+
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 1;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ vt1211_update_client(client);
-+ results[0] = TEMP_FROM_REG(data->temp_over[nr]);
-+ results[1] = TEMP_FROM_REG(data->temp_hyst[nr]);
-+ results[2] = TEMP_FROM_REG10(data->temp[nr]);
-+ *nrels_mag = 3;
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ if (*nrels_mag >= 1) {
-+ data->temp_over[nr] = TEMP_TO_REG(results[0]);
-+ vt1211_write_value(client,
-+ VT1211_REG_TEMP_OVER(nr + 1),
-+ data->temp_over[nr]);
-+ }
-+ if (*nrels_mag >= 2) {
-+ data->temp_hyst[nr] = TEMP_TO_REG(results[1]);
-+ vt1211_write_value(client,
-+ VT1211_REG_TEMP_HYST(nr + 1),
-+ data->temp_hyst[nr]);
-+ }
-+ }
-+}
-+
-+void vt1211_alarms(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct vt1211_data *data = client->data;
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 0;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ vt1211_update_client(client);
-+ results[0] = data->alarms;
-+ *nrels_mag = 1;
-+ }
-+}
-+
-+void vt1211_fan_div(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results)
-+{
-+ struct vt1211_data *data = client->data;
-+ int old;
-+
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 0;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ vt1211_update_client(client);
-+ results[0] = DIV_FROM_REG(data->fan_div[0]);
-+ results[1] = DIV_FROM_REG(data->fan_div[1]);
-+ *nrels_mag = 2;
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ old = vt_rdval(client, VT1211_REG_FANDIV);
-+ if (*nrels_mag >= 2) {
-+ data->fan_div[1] = DIV_TO_REG(results[1]);
-+ old = (old & 0x3f) | (data->fan_div[1] << 6);
-+ }
-+ if (*nrels_mag >= 1) {
-+ data->fan_div[0] = DIV_TO_REG(results[0]);
-+ old = (old & 0xcf) | (data->fan_div[0] << 4);
-+ vt1211_write_value(client, VT1211_REG_FANDIV, old);
-+ }
-+ }
-+}
-+
-+void vt1211_pwm(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct vt1211_data *data = client->data;
-+ int nr = 1 + ctl_name - VT1211_SYSCTL_PWM1;
-+
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 0;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ vt1211_update_client(client);
-+ results[0] = PWM_FROM_REG(data->pwm[nr - 1]);
-+ results[1] = (data->pwm_ctl >> (3 + (4 * (nr - 1)))) & 1;
-+ *nrels_mag = 2;
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ if (*nrels_mag >= 1) {
-+ data->pwm[nr - 1] = PWM_TO_REG(results[0]);
-+ if (*nrels_mag >= 2) {
-+ if(results[1]) {
-+ data->pwm_ctl |=
-+ (0x08 << (4 * (nr - 1)));
-+ vt1211_write_value(client,
-+ VT1211_REG_PWM_CTL,
-+ data->pwm_ctl);
-+ } else {
-+ data->pwm_ctl &=
-+ ~ (0x08 << (4 * (nr - 1)));
-+ vt1211_write_value(client,
-+ VT1211_REG_PWM_CTL,
-+ data->pwm_ctl);
-+ }
-+ }
-+ vt1211_write_value(client, VT1211_REG_PWM(nr),
-+ data->pwm[nr - 1]);
-+ }
-+ }
-+}
-+
-+void vt1211_vid(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct vt1211_data *data = client->data;
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 3;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ vt1211_update_client(client);
-+ results[0] = vid_from_reg(data->vid, data->vrm);
-+ *nrels_mag = 1;
-+ }
-+}
-+
-+void vt1211_vrm(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct vt1211_data *data = client->data;
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 1;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ results[0] = data->vrm;
-+ *nrels_mag = 1;
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ if (*nrels_mag >= 1)
-+ data->vrm = results[0];
-+ }
-+}
-+
-+void vt1211_uch(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct vt1211_data *data = client->data;
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 0;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ results[0] = data->uch_config & 0x7c;
-+ *nrels_mag = 1;
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ if (*nrels_mag >= 1) {
-+ data->uch_config = (data->uch_config & 0x83)|(results[0] & 0x7c);
-+ vt1211_write_value(client, VT1211_REG_UCH_CONFIG,
-+ data->uch_config);
-+ }
-+ }
-+}
-+
-+static int __init sm_vt1211_init(void)
-+{
-+ int addr;
-+
-+ printk("vt1211.o version %s (%s)\n", LM_VERSION, LM_DATE);
-+
-+ if (vt1211_find(&addr)) {
-+ printk("vt1211.o: VT1211 not detected, module not inserted.\n");
-+ return -ENODEV;
-+ }
-+ normal_isa[0] = addr;
-+
-+ return i2c_add_driver(&vt1211_driver);
-+}
-+
-+static void __exit sm_vt1211_exit(void)
-+{
-+ i2c_del_driver(&vt1211_driver);
-+}
-+
-+
-+
-+MODULE_AUTHOR("Mark D. Studebaker <mdsxyz123@yahoo.com>");
-+MODULE_DESCRIPTION("VT1211 sensors");
-+MODULE_LICENSE("GPL");
-+
-+module_init(sm_vt1211_init);
-+module_exit(sm_vt1211_exit);
---- linux-old/drivers/sensors/vt8231.c Thu Jan 1 00:00:00 1970
-+++ linux/drivers/sensors/vt8231.c Mon Dec 13 20:18:53 2004
-@@ -0,0 +1,794 @@
-+/*
-+ vt8231.c - Part of lm_sensors, Linux kernel modules
-+ for hardware monitoring
-+
-+ Copyright (c) 2002 Mark D. Studebaker <mdsxyz123@yahoo.com>
-+
-+ 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., 675 Mass Ave, Cambridge, MA 02139, USA.
-+*/
-+
-+/* Supports VIA VT8231 South Bridge embedded sensors */
-+
-+#include <linux/module.h>
-+#include <linux/slab.h>
-+#include <linux/ioport.h>
-+#include <linux/pci.h>
-+#include <linux/i2c.h>
-+#include <linux/i2c-proc.h>
-+#include <linux/init.h>
-+#include <asm/io.h>
-+#define LM_DATE "20041007"
-+#define LM_VERSION "2.8.8"
-+#include <linux/sensors_vid.h>
-+
-+
-+static int force_addr = 0;
-+MODULE_PARM(force_addr, "i");
-+MODULE_PARM_DESC(force_addr,
-+ "Initialize the base address of the sensors");
-+
-+static unsigned short normal_i2c[] = { SENSORS_I2C_END };
-+static unsigned short normal_i2c_range[] = { SENSORS_I2C_END };
-+static unsigned int normal_isa[] = { 0x0000, SENSORS_ISA_END };
-+static unsigned int normal_isa_range[] = { SENSORS_ISA_END };
-+
-+SENSORS_INSMOD_1(vt8231);
-+
-+#define VIA686A_EXTENT 0x80
-+#define VIA686A_BASE_REG 0x70
-+#define VIA686A_ENABLE_REG 0x74
-+
-+/* pwm numbered 1-2 */
-+#define VT8231_REG_PWM(nr) (0x5f + (nr))
-+#define VT8231_REG_PWM_CTL 0x51
-+
-+/* The VT8231 registers */
-+/* We define the sensors as follows. Somewhat convoluted to minimize
-+ changes from via686a.
-+ Sensor Voltage Mode Temp Mode
-+ -------- ------------ ---------
-+ Reading 1 temp3
-+ Reading 3 temp1 not in vt8231
-+ UCH1/Reading2 in0 temp2
-+ UCH2 in1 temp4
-+ UCH3 in2 temp5
-+ UCH4 in3 temp6
-+ UCH5 in4 temp7
-+ 3.3V in5
-+ -12V in6 not in vt8231
-+*/
-+
-+/* ins numbered 0-6 */
-+#define VT8231_REG_IN_MAX(nr) ((nr)==0 ? 0x3d : 0x29 + ((nr) * 2))
-+#define VT8231_REG_IN_MIN(nr) ((nr)==0 ? 0x3e : 0x2a + ((nr) * 2))
-+#define VT8231_REG_IN(nr) (0x21 + (nr))
-+
-+/* fans numbered 1-2 */
-+#define VT8231_REG_FAN_MIN(nr) (0x3a + (nr))
-+#define VT8231_REG_FAN(nr) (0x28 + (nr))
-+
-+static const u8 regtemp[] = { 0x20, 0x21, 0x1f, 0x22, 0x23, 0x24, 0x25 };
-+static const u8 regover[] = { 0x39, 0x3d, 0x1d, 0x2b, 0x2d, 0x2f, 0x31 };
-+static const u8 reghyst[] = { 0x3a, 0x3e, 0x1e, 0x2c, 0x2e, 0x30, 0x32 };
-+
-+/* temps numbered 1-7 */
-+#define VT8231_REG_TEMP(nr) (regtemp[(nr) - 1])
-+#define VT8231_REG_TEMP_OVER(nr) (regover[(nr) - 1])
-+#define VT8231_REG_TEMP_HYST(nr) (reghyst[(nr) - 1])
-+#define VT8231_REG_TEMP_LOW3 0x4b /* bits 7-6 */
-+#define VT8231_REG_TEMP_LOW2 0x49 /* bits 5-4 */
-+#define VT8231_REG_TEMP_LOW47 0x4d
-+
-+#define VT8231_REG_CONFIG 0x40
-+#define VT8231_REG_ALARM1 0x41
-+#define VT8231_REG_ALARM2 0x42
-+#define VT8231_REG_VID 0x45
-+#define VT8231_REG_FANDIV 0x47
-+#define VT8231_REG_UCH_CONFIG 0x4a
-+#define VT8231_REG_TEMP1_CONFIG 0x4b
-+#define VT8231_REG_TEMP2_CONFIG 0x4c
-+
-+/* temps 1-7; voltages 0-6 */
-+#define ISTEMP(i, ch_config) ((i) == 1 ? 1 : \
-+ (i) == 3 ? 1 : \
-+ (i) == 2 ? ((ch_config) >> 1) & 0x01 : \
-+ ((ch_config) >> ((i)-1)) & 0x01)
-+#define ISVOLT(i, ch_config) ((i) > 4 ? 1 : !(((ch_config) >> ((i)+2)) & 0x01))
-+
-+#define DIV_FROM_REG(val) (1 << (val))
-+#define DIV_TO_REG(val) ((val)==8?3:(val)==4?2:(val)==1?0:1)
-+#define PWM_FROM_REG(val) (val)
-+#define PWM_TO_REG(val) SENSORS_LIMIT((val), 0, 255)
-+
-+#define TEMP_FROM_REG(val) ((val)*10)
-+#define TEMP_FROM_REG10(val) (((val)*10)/4)
-+#define TEMP_TO_REG(val) (SENSORS_LIMIT(((val)<0?(((val)-5)/10):\
-+ ((val)+5)/10),0,255))
-+#define IN_FROM_REG(val) /*(((val)*10+5)/10)*/ (val)
-+#define IN_TO_REG(val) (SENSORS_LIMIT((((val) * 10 + 5)/10),0,255))
-+
-+
-+/********* FAN RPM CONVERSIONS ********/
-+/* But this chip saturates back at 0, not at 255 like all the other chips.
-+ So, 0 means 0 RPM */
-+static inline u8 FAN_TO_REG(long rpm, int div)
-+{
-+ if (rpm == 0)
-+ return 0;
-+ rpm = SENSORS_LIMIT(rpm, 1, 1000000);
-+ return SENSORS_LIMIT((1310720 + rpm * div / 2) / (rpm * div), 1, 255);
-+}
-+
-+#define MIN_TO_REG(a,b) FAN_TO_REG(a,b)
-+#define FAN_FROM_REG(val,div) ((val)==0?0:(val)==255?0:1310720/((val)*(div)))
-+
-+struct vt8231_data {
-+ struct i2c_client client;
-+ struct semaphore lock;
-+ int sysctl_id;
-+
-+ struct semaphore update_lock;
-+ char valid; /* !=0 if following fields are valid */
-+ unsigned long last_updated; /* In jiffies */
-+
-+ u8 in[7]; /* Register value */
-+ u8 in_max[7]; /* Register value */
-+ u8 in_min[7]; /* Register value */
-+ u16 temp[7]; /* Register value 10 bit */
-+ u8 temp_over[7]; /* Register value */
-+ u8 temp_hyst[7]; /* Register value */
-+ u8 fan[2]; /* Register value */
-+ u8 fan_min[2]; /* Register value */
-+ u8 fan_div[2]; /* Register encoding, shifted right */
-+ u16 alarms; /* Register encoding */
-+ u8 pwm[2]; /* Register value */
-+ u8 pwm_ctl; /* Register value */
-+ u8 vid; /* Register encoding */
-+ u8 vrm;
-+ u8 uch_config;
-+};
-+
-+static int vt8231_attach_adapter(struct i2c_adapter *adapter);
-+static int vt8231_detect(struct i2c_adapter *adapter, int address,
-+ unsigned short flags, int kind);
-+static int vt8231_detach_client(struct i2c_client *client);
-+
-+static inline int vt_rdval(struct i2c_client *client, u8 register);
-+static inline void vt8231_write_value(struct i2c_client *client, u8 register,
-+ u8 value);
-+static void vt8231_update_client(struct i2c_client *client);
-+static void vt8231_init_client(struct i2c_client *client);
-+static int vt8231_find(int *address);
-+
-+
-+static void vt8231_fan(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void vt8231_alarms(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void vt8231_fan_div(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void vt8231_in(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void vt8231_pwm(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void vt8231_vid(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void vt8231_vrm(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void vt8231_uch(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void vt8231_temp(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+
-+static int vt8231_id = 0;
-+
-+static struct i2c_driver vt8231_driver = {
-+ .owner = THIS_MODULE,
-+ .name = "VT8231 sensors driver",
-+ .id = I2C_DRIVERID_VT8231,
-+ .flags = I2C_DF_NOTIFY,
-+ .attach_adapter = vt8231_attach_adapter,
-+ .detach_client = vt8231_detach_client,
-+};
-+
-+/* -- SENSORS SYSCTL START -- */
-+#define VT8231_SYSCTL_IN0 1000
-+#define VT8231_SYSCTL_IN1 1001
-+#define VT8231_SYSCTL_IN2 1002
-+#define VT8231_SYSCTL_IN3 1003
-+#define VT8231_SYSCTL_IN4 1004
-+#define VT8231_SYSCTL_IN5 1005
-+#define VT8231_SYSCTL_IN6 1006
-+#define VT8231_SYSCTL_FAN1 1101
-+#define VT8231_SYSCTL_FAN2 1102
-+#define VT8231_SYSCTL_TEMP 1200
-+#define VT8231_SYSCTL_TEMP2 1201
-+#define VT8231_SYSCTL_TEMP3 1202
-+#define VT8231_SYSCTL_TEMP4 1203
-+#define VT8231_SYSCTL_TEMP5 1204
-+#define VT8231_SYSCTL_TEMP6 1205
-+#define VT8231_SYSCTL_TEMP7 1206
-+#define VT8231_SYSCTL_VID 1300
-+#define VT8231_SYSCTL_PWM1 1401
-+#define VT8231_SYSCTL_PWM2 1402
-+#define VT8231_SYSCTL_VRM 1600
-+#define VT8231_SYSCTL_UCH 1700
-+#define VT8231_SYSCTL_FAN_DIV 2000
-+#define VT8231_SYSCTL_ALARMS 2001
-+
-+#define VT8231_ALARM_IN1 0x01
-+#define VT8231_ALARM_IN2 0x02
-+#define VT8231_ALARM_IN5 0x04
-+#define VT8231_ALARM_IN3 0x08
-+#define VT8231_ALARM_TEMP 0x10
-+#define VT8231_ALARM_FAN1 0x40
-+#define VT8231_ALARM_FAN2 0x80
-+#define VT8231_ALARM_IN4 0x100
-+#define VT8231_ALARM_IN6 0x200
-+#define VT8231_ALARM_TEMP2 0x800
-+#define VT8231_ALARM_CHAS 0x1000
-+#define VT8231_ALARM_TEMP3 0x8000
-+/* duplicates */
-+#define VT8231_ALARM_IN0 VT8231_ALARM_TEMP
-+#define VT8231_ALARM_TEMP4 VT8231_ALARM_IN1
-+#define VT8231_ALARM_TEMP5 VT8231_ALARM_IN2
-+#define VT8231_ALARM_TEMP6 VT8231_ALARM_IN3
-+#define VT8231_ALARM_TEMP7 VT8231_ALARM_IN4
-+
-+/* -- SENSORS SYSCTL END -- */
-+
-+static ctl_table vt8231_dir_table_template[] = {
-+ {VT8231_SYSCTL_IN0, "in0", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &vt8231_in},
-+ {VT8231_SYSCTL_IN1, "in1", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &vt8231_in},
-+ {VT8231_SYSCTL_IN2, "in2", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &vt8231_in},
-+ {VT8231_SYSCTL_IN3, "in3", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &vt8231_in},
-+ {VT8231_SYSCTL_IN4, "in4", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &vt8231_in},
-+ {VT8231_SYSCTL_IN5, "in5", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &vt8231_in},
-+/*
-+ not in 8231
-+ {VT8231_SYSCTL_IN6, "in6", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &vt8231_in},
-+ {VT8231_SYSCTL_TEMP, "temp1", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &vt8231_temp},
-+*/
-+ {VT8231_SYSCTL_TEMP2, "temp2", NULL, 0, 0644, NULL,
-+ &i2c_proc_real, &i2c_sysctl_real, NULL, &vt8231_temp},
-+ {VT8231_SYSCTL_TEMP3, "temp3", NULL, 0, 0644, NULL,
-+ &i2c_proc_real, &i2c_sysctl_real, NULL, &vt8231_temp},
-+ {VT8231_SYSCTL_TEMP4, "temp4", NULL, 0, 0644, NULL,
-+ &i2c_proc_real, &i2c_sysctl_real, NULL, &vt8231_temp},
-+ {VT8231_SYSCTL_TEMP5, "temp5", NULL, 0, 0644, NULL,
-+ &i2c_proc_real, &i2c_sysctl_real, NULL, &vt8231_temp},
-+ {VT8231_SYSCTL_TEMP6, "temp6", NULL, 0, 0644, NULL,
-+ &i2c_proc_real, &i2c_sysctl_real, NULL, &vt8231_temp},
-+ {VT8231_SYSCTL_TEMP7, "temp7", NULL, 0, 0644, NULL,
-+ &i2c_proc_real, &i2c_sysctl_real, NULL, &vt8231_temp},
-+ {VT8231_SYSCTL_FAN1, "fan1", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &vt8231_fan},
-+ {VT8231_SYSCTL_FAN2, "fan2", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &vt8231_fan},
-+ {VT8231_SYSCTL_FAN_DIV, "fan_div", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &vt8231_fan_div},
-+ {VT8231_SYSCTL_ALARMS, "alarms", NULL, 0, 0444, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &vt8231_alarms},
-+ {VT8231_SYSCTL_PWM1, "pwm1", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &vt8231_pwm},
-+ {VT8231_SYSCTL_PWM2, "pwm2", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &vt8231_pwm},
-+ {VT8231_SYSCTL_VID, "vid", NULL, 0, 0444, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &vt8231_vid},
-+ {VT8231_SYSCTL_VRM, "vrm", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &vt8231_vrm},
-+ {VT8231_SYSCTL_UCH, "uch_config", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &vt8231_uch},
-+ {0}
-+};
-+
-+static struct pci_dev *s_bridge;
-+
-+static int vt8231_attach_adapter(struct i2c_adapter *adapter)
-+{
-+ return i2c_detect(adapter, &addr_data, vt8231_detect);
-+}
-+
-+/* Locate chip and get correct base address */
-+static int vt8231_find(int *address)
-+{
-+ u16 val;
-+
-+ if (!pci_present())
-+ return -ENODEV;
-+
-+ if (!(s_bridge = pci_find_device(PCI_VENDOR_ID_VIA,
-+ 0x8235, NULL)))
-+ return -ENODEV;
-+
-+ if (PCIBIOS_SUCCESSFUL !=
-+ pci_read_config_word(s_bridge, VIA686A_BASE_REG, &val))
-+ return -ENODEV;
-+ *address = val & ~(VIA686A_EXTENT - 1);
-+ if (*address == 0 && force_addr == 0) {
-+ printk("vt8231.o: base address not set - upgrade BIOS or use force_addr=0xaddr\n");
-+ return -ENODEV;
-+ }
-+ if (force_addr)
-+ *address = force_addr; /* so detect will get called */
-+
-+ return 0;
-+}
-+
-+int vt8231_detect(struct i2c_adapter *adapter, int address,
-+ unsigned short flags, int kind)
-+{
-+ int i;
-+ struct i2c_client *new_client;
-+ struct vt8231_data *data;
-+ int err = 0;
-+ const char *type_name = "vt8231";
-+ u16 val;
-+
-+ if (!i2c_is_isa_adapter(adapter)) {
-+ return 0;
-+ }
-+
-+ /* 8231 requires multiple of 256 */
-+ if(force_addr)
-+ address = force_addr & 0xFF00;
-+ if (check_region(address, VIA686A_EXTENT)) {
-+ printk("vt8231.o: region 0x%x already in use!\n",
-+ address);
-+ return -ENODEV;
-+ }
-+
-+ if(force_addr) {
-+ printk("vt8231.o: forcing ISA address 0x%04X\n", address);
-+ if (PCIBIOS_SUCCESSFUL !=
-+ pci_write_config_word(s_bridge, VIA686A_BASE_REG, address))
-+ return -ENODEV;
-+ }
-+ if (PCIBIOS_SUCCESSFUL !=
-+ pci_read_config_word(s_bridge, VIA686A_ENABLE_REG, &val))
-+ return -ENODEV;
-+ if (!(val & 0x0001)) {
-+ printk("vt8231.o: enabling sensors\n");
-+ if (PCIBIOS_SUCCESSFUL !=
-+ pci_write_config_word(s_bridge, VIA686A_ENABLE_REG,
-+ val | 0x0001))
-+ return -ENODEV;
-+ }
-+
-+ if (!(data = kmalloc(sizeof(struct vt8231_data), GFP_KERNEL))) {
-+ err = -ENOMEM;
-+ goto ERROR0;
-+ }
-+
-+ new_client = &data->client;
-+ new_client->addr = address;
-+ init_MUTEX(&data->lock);
-+ new_client->data = data;
-+ new_client->adapter = adapter;
-+ new_client->driver = &vt8231_driver;
-+ new_client->flags = 0;
-+
-+ /* Reserve the ISA region */
-+ request_region(address, VIA686A_EXTENT, "vt8231-sensors");
-+
-+ /* Fill in the remaining client fields and put into the global list */
-+ strcpy(new_client->name, "Via 8231 Integrated Sensors");
-+
-+ new_client->id = vt8231_id++;
-+ data->valid = 0;
-+ init_MUTEX(&data->update_lock);
-+
-+ /* Tell the I2C layer a new client has arrived */
-+ if ((err = i2c_attach_client(new_client)))
-+ goto ERROR3;
-+
-+ /* Register a new directory entry with module sensors */
-+ if ((i = i2c_register_entry((struct i2c_client *) new_client,
-+ type_name,
-+ vt8231_dir_table_template)) < 0) {
-+ err = i;
-+ goto ERROR4;
-+ }
-+ data->sysctl_id = i;
-+
-+ vt8231_init_client(new_client);
-+ return 0;
-+
-+ ERROR4:
-+ i2c_detach_client(new_client);
-+ ERROR3:
-+ release_region(address, VIA686A_EXTENT);
-+ kfree(data);
-+ ERROR0:
-+ return err;
-+}
-+
-+static int vt8231_detach_client(struct i2c_client *client)
-+{
-+ int err;
-+
-+ i2c_deregister_entry(((struct vt8231_data *) (client->data))->
-+ sysctl_id);
-+
-+ if ((err = i2c_detach_client(client))) {
-+ printk
-+ ("vt8231.o: Client deregistration failed, client not detached.\n");
-+ return err;
-+ }
-+
-+ release_region(client->addr, VIA686A_EXTENT);
-+ kfree(client->data);
-+
-+ return 0;
-+}
-+
-+
-+static inline int vt_rdval(struct i2c_client *client, u8 reg)
-+{
-+ return (inb_p(client->addr + reg));
-+}
-+
-+static inline void vt8231_write_value(struct i2c_client *client, u8 reg, u8 value)
-+{
-+ outb_p(value, client->addr + reg);
-+}
-+
-+static void vt8231_init_client(struct i2c_client *client)
-+{
-+ struct vt8231_data *data = client->data;
-+
-+ data->vrm = DEFAULT_VRM;
-+ /* set "default" interrupt mode for alarms, which isn't the default */
-+ vt8231_write_value(client, VT8231_REG_TEMP1_CONFIG, 0);
-+ vt8231_write_value(client, VT8231_REG_TEMP2_CONFIG, 0);
-+}
-+
-+static void vt8231_update_client(struct i2c_client *client)
-+{
-+ struct vt8231_data *data = client->data;
-+ int i, j;
-+
-+ down(&data->update_lock);
-+
-+ if ((jiffies - data->last_updated > HZ + HZ / 2) ||
-+ (jiffies < data->last_updated) || !data->valid) {
-+ data->uch_config = vt_rdval(client, VT8231_REG_UCH_CONFIG);
-+ for (i = 0; i <= 5; i++) {
-+ if(ISVOLT(i, data->uch_config)) {
-+ data->in[i] = vt_rdval(client, VT8231_REG_IN(i));
-+ data->in_min[i] = vt_rdval(client,
-+ VT8231_REG_IN_MIN(i));
-+ data->in_max[i] = vt_rdval(client,
-+ VT8231_REG_IN_MAX(i));
-+ } else {
-+ data->in[i] = 0;
-+ data->in_min[i] = 0;
-+ data->in_max[i] = 0;
-+ }
-+ }
-+ for (i = 1; i <= 2; i++) {
-+ data->fan[i - 1] = vt_rdval(client, VT8231_REG_FAN(i));
-+ data->fan_min[i - 1] = vt_rdval(client,
-+ VT8231_REG_FAN_MIN(i));
-+ }
-+ for (i = 2; i <= 7; i++) {
-+ if(ISTEMP(i, data->uch_config)) {
-+ data->temp[i - 1] = vt_rdval(client,
-+ VT8231_REG_TEMP(i)) << 2;
-+ switch(i) {
-+ case 1:
-+ /* ? */
-+ j = 0;
-+ break;
-+ case 2:
-+ j = (vt_rdval(client,
-+ VT8231_REG_TEMP_LOW2) &
-+ 0x30) >> 4;
-+ break;
-+ case 3:
-+ j = (vt_rdval(client,
-+ VT8231_REG_TEMP_LOW3) &
-+ 0xc0) >> 6;
-+ break;
-+ case 4:
-+ case 5:
-+ case 6:
-+ case 7:
-+ default:
-+ j = (vt_rdval(client,
-+ VT8231_REG_TEMP_LOW47) >>
-+ ((i-4)*2)) & 0x03;
-+ break;
-+
-+ }
-+ data->temp[i - 1] |= j;
-+ data->temp_over[i - 1] = vt_rdval(client,
-+ VT8231_REG_TEMP_OVER(i));
-+ data->temp_hyst[i - 1] = vt_rdval(client,
-+ VT8231_REG_TEMP_HYST(i));
-+ } else {
-+ data->temp[i - 1] = 0;
-+ data->temp_over[i - 1] = 0;
-+ data->temp_hyst[i - 1] = 0;
-+ }
-+ }
-+
-+ for (i = 1; i <= 2; i++) {
-+ data->fan[i - 1] = vt_rdval(client, VT8231_REG_FAN(i));
-+ data->fan_min[i - 1] = vt_rdval(client,
-+ VT8231_REG_FAN_MIN(i));
-+ data->pwm[i - 1] = vt_rdval(client, VT8231_REG_PWM(i));
-+ }
-+
-+ data->pwm_ctl = vt_rdval(client, VT8231_REG_PWM_CTL);
-+ i = vt_rdval(client, VT8231_REG_FANDIV);
-+ data->fan_div[0] = (i >> 4) & 0x03;
-+ data->fan_div[1] = i >> 6;
-+ data->alarms = vt_rdval(client, VT8231_REG_ALARM1) |
-+ (vt_rdval(client, VT8231_REG_ALARM2) << 8);
-+ data->vid= vt_rdval(client, VT8231_REG_VID) & 0x1f;
-+ data->last_updated = jiffies;
-+ data->valid = 1;
-+ }
-+
-+ up(&data->update_lock);
-+}
-+
-+
-+void vt8231_in(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct vt8231_data *data = client->data;
-+ int nr = ctl_name - VT8231_SYSCTL_IN0;
-+
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 2;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ vt8231_update_client(client);
-+ results[0] = IN_FROM_REG(data->in_min[nr]);
-+ results[1] = IN_FROM_REG(data->in_max[nr]);
-+ results[2] = IN_FROM_REG(data->in[nr]);
-+ *nrels_mag = 3;
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ if (*nrels_mag >= 1) {
-+ data->in_min[nr] = IN_TO_REG(results[0]);
-+ vt8231_write_value(client, VT8231_REG_IN_MIN(nr),
-+ data->in_min[nr]);
-+ }
-+ if (*nrels_mag >= 2) {
-+ data->in_max[nr] = IN_TO_REG(results[1]);
-+ vt8231_write_value(client, VT8231_REG_IN_MAX(nr),
-+ data->in_max[nr]);
-+ }
-+ }
-+}
-+
-+void vt8231_fan(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct vt8231_data *data = client->data;
-+ int nr = ctl_name - VT8231_SYSCTL_FAN1 + 1;
-+
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 0;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ vt8231_update_client(client);
-+ results[0] = FAN_FROM_REG(data->fan_min[nr - 1],
-+ DIV_FROM_REG(data->fan_div
-+ [nr - 1]));
-+ results[1] = FAN_FROM_REG(data->fan[nr - 1],
-+ DIV_FROM_REG(data->fan_div[nr - 1]));
-+ *nrels_mag = 2;
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ if (*nrels_mag >= 1) {
-+ data->fan_min[nr - 1] = MIN_TO_REG(results[0],
-+ DIV_FROM_REG
-+ (data->
-+ fan_div[nr-1]));
-+ vt8231_write_value(client, VT8231_REG_FAN_MIN(nr),
-+ data->fan_min[nr - 1]);
-+ }
-+ }
-+}
-+
-+
-+void vt8231_temp(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct vt8231_data *data = client->data;
-+ int nr = ctl_name - VT8231_SYSCTL_TEMP;
-+
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 1;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ vt8231_update_client(client);
-+ results[0] = TEMP_FROM_REG(data->temp_over[nr]);
-+ results[1] = TEMP_FROM_REG(data->temp_hyst[nr]);
-+ results[2] = TEMP_FROM_REG10(data->temp[nr]);
-+ *nrels_mag = 3;
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ if (*nrels_mag >= 1) {
-+ data->temp_over[nr] = TEMP_TO_REG(results[0]);
-+ vt8231_write_value(client,
-+ VT8231_REG_TEMP_OVER(nr + 1),
-+ data->temp_over[nr]);
-+ }
-+ if (*nrels_mag >= 2) {
-+ data->temp_hyst[nr] = TEMP_TO_REG(results[1]);
-+ vt8231_write_value(client,
-+ VT8231_REG_TEMP_HYST(nr + 1),
-+ data->temp_hyst[nr]);
-+ }
-+ }
-+}
-+
-+void vt8231_alarms(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct vt8231_data *data = client->data;
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 0;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ vt8231_update_client(client);
-+ results[0] = data->alarms;
-+ *nrels_mag = 1;
-+ }
-+}
-+
-+void vt8231_fan_div(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results)
-+{
-+ struct vt8231_data *data = client->data;
-+ int old;
-+
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 0;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ vt8231_update_client(client);
-+ results[0] = DIV_FROM_REG(data->fan_div[0]);
-+ results[1] = DIV_FROM_REG(data->fan_div[1]);
-+ *nrels_mag = 2;
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ old = vt_rdval(client, VT8231_REG_FANDIV);
-+ if (*nrels_mag >= 2) {
-+ data->fan_div[1] = DIV_TO_REG(results[1]);
-+ old = (old & 0x3f) | (data->fan_div[1] << 6);
-+ }
-+ if (*nrels_mag >= 1) {
-+ data->fan_div[0] = DIV_TO_REG(results[0]);
-+ old = (old & 0xcf) | (data->fan_div[0] << 4);
-+ vt8231_write_value(client, VT8231_REG_FANDIV, old);
-+ }
-+ }
-+}
-+
-+void vt8231_pwm(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct vt8231_data *data = client->data;
-+ int nr = 1 + ctl_name - VT8231_SYSCTL_PWM1;
-+
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 0;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ vt8231_update_client(client);
-+ results[0] = PWM_FROM_REG(data->pwm[nr - 1]);
-+ results[1] = (data->pwm_ctl >> (3 + (4 * (nr - 1)))) & 1;
-+ *nrels_mag = 2;
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ if (*nrels_mag >= 1) {
-+ data->pwm[nr - 1] = PWM_TO_REG(results[0]);
-+ if (*nrels_mag >= 2) {
-+ if(results[1]) {
-+ data->pwm_ctl |=
-+ (0x08 << (4 * (nr - 1)));
-+ vt8231_write_value(client,
-+ VT8231_REG_PWM_CTL,
-+ data->pwm_ctl);
-+ } else {
-+ data->pwm_ctl &=
-+ ~ (0x08 << (4 * (nr - 1)));
-+ vt8231_write_value(client,
-+ VT8231_REG_PWM_CTL,
-+ data->pwm_ctl);
-+ }
-+ }
-+ vt8231_write_value(client, VT8231_REG_PWM(nr),
-+ data->pwm[nr - 1]);
-+ }
-+ }
-+}
-+
-+void vt8231_vid(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct vt8231_data *data = client->data;
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 3;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ vt8231_update_client(client);
-+ results[0] = vid_from_reg(data->vid, data->vrm);
-+ *nrels_mag = 1;
-+ }
-+}
-+
-+void vt8231_vrm(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct vt8231_data *data = client->data;
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 1;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ results[0] = data->vrm;
-+ *nrels_mag = 1;
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ if (*nrels_mag >= 1)
-+ data->vrm = results[0];
-+ }
-+}
-+
-+void vt8231_uch(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct vt8231_data *data = client->data;
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 0;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ results[0] = data->uch_config & 0x7c;
-+ *nrels_mag = 1;
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ if (*nrels_mag >= 1) {
-+ data->uch_config = (data->uch_config & 0x83)|(results[0] & 0x7c);
-+ vt8231_write_value(client, VT8231_REG_UCH_CONFIG,
-+ data->uch_config);
-+ }
-+ }
-+}
-+
-+static int __init sm_vt8231_init(void)
-+{
-+ int addr;
-+
-+ printk("vt8231.o version %s (%s)\n", LM_VERSION, LM_DATE);
-+
-+ if (vt8231_find(&addr)) {
-+ printk("vt8231.o: VT8231 not detected, module not inserted.\n");
-+ return -ENODEV;
-+ }
-+ normal_isa[0] = addr;
-+
-+ return i2c_add_driver(&vt8231_driver);}
-+
-+static void __exit sm_vt8231_exit(void)
-+{
-+ i2c_del_driver(&vt8231_driver);
-+}
-+
-+
-+
-+MODULE_AUTHOR("Mark D. Studebaker <mdsxyz123@yahoo.com>");
-+MODULE_DESCRIPTION("VT8231 sensors");
-+MODULE_LICENSE("GPL");
-+
-+module_init(sm_vt8231_init);
-+module_exit(sm_vt8231_exit);
---- linux-old/drivers/sensors/w83627hf.c Thu Jan 1 00:00:00 1970
-+++ linux/drivers/sensors/w83627hf.c Mon Dec 13 20:18:53 2004
-@@ -0,0 +1,1422 @@
-+/*
-+ w83627hf.c - Part of lm_sensors, Linux kernel modules for hardware
-+ monitoring
-+ Copyright (c) 1998 - 2003 Frodo Looijaard <frodol@dds.nl>,
-+ Philip Edelbrock <phil@netroedge.com>,
-+ and Mark Studebaker <mdsxyz123@yahoo.com>
-+
-+ 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., 675 Mass Ave, Cambridge, MA 02139, USA.
-+*/
-+
-+/*
-+ Supports following chips:
-+
-+ Chip #vin #fanin #pwm #temp wchipid vendid i2c ISA
-+ w83627hf 9 3 2 3 0x20 0x5ca3 no yes(LPC)
-+ w83627thf 7 3 3 3 0x90 0x5ca3 no yes(LPC)
-+ w83637hf 7 3 3 3 0x80 0x5ca3 no yes(LPC)
-+ w83697hf 8 2 2 2 0x60 0x5ca3 no yes(LPC)
-+
-+ For other winbond chips, and for i2c support in the above chips,
-+ use w83781d.c.
-+
-+ Note: automatic ("cruise") fan control for 697, 637 & 627thf not
-+ supported yet.
-+*/
-+
-+#include <linux/module.h>
-+#include <linux/slab.h>
-+#include <linux/ioport.h>
-+#include <linux/i2c.h>
-+#include <linux/i2c-proc.h>
-+#include <linux/init.h>
-+#include <asm/io.h>
-+#define LM_DATE "20041007"
-+#define LM_VERSION "2.8.8"
-+#include <linux/sensors_vid.h>
-+#include "lm75.h"
-+
-+static int force_addr;
-+MODULE_PARM(force_addr, "i");
-+MODULE_PARM_DESC(force_addr,
-+ "Initialize the base address of the sensors");
-+static int force_i2c = 0x1f;
-+MODULE_PARM(force_i2c, "i");
-+MODULE_PARM_DESC(force_i2c,
-+ "Initialize the i2c address of the sensors");
-+
-+/* Addresses to scan */
-+static unsigned short normal_i2c[] = { SENSORS_I2C_END };
-+static unsigned short normal_i2c_range[] = { SENSORS_I2C_END };
-+static unsigned int normal_isa[] = { 0, SENSORS_ISA_END };
-+static unsigned int normal_isa_range[] = { SENSORS_ISA_END };
-+
-+/* Insmod parameters */
-+SENSORS_INSMOD_4(w83627hf, w83627thf, w83697hf, w83637hf);
-+
-+static int init = 1;
-+MODULE_PARM(init, "i");
-+MODULE_PARM_DESC(init, "Set to zero to bypass chip initialization");
-+
-+/* modified from kernel/include/traps.c */
-+#define REG 0x2e /* The register to read/write */
-+#define DEV 0x07 /* Register: Logical device select */
-+#define VAL 0x2f /* The value to read/write */
-+
-+/* logical device numbers for superio_select (below) */
-+#define W83627HF_LD_FDC 0x00
-+#define W83627HF_LD_PRT 0x01
-+#define W83627HF_LD_UART1 0x02
-+#define W83627HF_LD_UART2 0x03
-+#define W83627HF_LD_KBC 0x05
-+#define W83627HF_LD_CIR 0x06 /* w83627hf only */
-+#define W83627HF_LD_GAME 0x07
-+#define W83627HF_LD_MIDI 0x07
-+#define W83627HF_LD_GPIO1 0x07
-+#define W83627HF_LD_GPIO5 0x07 /* w83627thf only */
-+#define W83627HF_LD_GPIO2 0x08
-+#define W83627HF_LD_GPIO3 0x09
-+#define W83627HF_LD_GPIO4 0x09 /* w83627thf only */
-+#define W83627HF_LD_ACPI 0x0a
-+#define W83627HF_LD_HWM 0x0b
-+
-+#define DEVID 0x20 /* Register: Device ID */
-+
-+#define W83627THF_GPIO5_IOSR 0xf3 /* w83627thf only */
-+#define W83627THF_GPIO5_DR 0xf4 /* w83627thf only */
-+#define W83627THF_GPIO5_INVR 0xf5 /* w83627thf only */
-+
-+static inline void
-+superio_outb(int reg, int val)
-+{
-+ outb(reg, REG);
-+ outb(val, VAL);
-+}
-+
-+static inline int
-+superio_inb(int reg)
-+{
-+ outb(reg, REG);
-+ return inb(VAL);
-+}
-+
-+static inline void
-+superio_select(int ld)
-+{
-+ outb(DEV, REG);
-+ outb(ld, VAL);
-+}
-+
-+static inline void
-+superio_enter(void)
-+{
-+ outb(0x87, REG);
-+ outb(0x87, REG);
-+}
-+
-+static inline void
-+superio_exit(void)
-+{
-+ outb(0xAA, REG);
-+}
-+
-+#define W627_DEVID 0x52
-+#define W627THF_DEVID 0x82
-+#define W697_DEVID 0x60
-+#define W637_DEVID 0x70
-+#define WINB_ACT_REG 0x30
-+#define WINB_BASE_REG 0x60
-+/* Constants specified below */
-+
-+/* Length of ISA address segment */
-+#define WINB_EXTENT 8
-+
-+/* Where are the ISA address/data registers relative to the base address */
-+#define W83781D_ADDR_REG_OFFSET 5
-+#define W83781D_DATA_REG_OFFSET 6
-+
-+/* The W83781D registers */
-+/* The W83782D registers for nr=7,8 are in bank 5 */
-+#define W83781D_REG_IN_MAX(nr) ((nr < 7) ? (0x2b + (nr) * 2) : \
-+ (0x554 + (((nr) - 7) * 2)))
-+#define W83781D_REG_IN_MIN(nr) ((nr < 7) ? (0x2c + (nr) * 2) : \
-+ (0x555 + (((nr) - 7) * 2)))
-+#define W83781D_REG_IN(nr) ((nr < 7) ? (0x20 + (nr)) : \
-+ (0x550 + (nr) - 7))
-+
-+#define W83781D_REG_FAN_MIN(nr) (0x3a + (nr))
-+#define W83781D_REG_FAN(nr) (0x27 + (nr))
-+
-+#define W83781D_REG_TEMP2 0x0150
-+#define W83781D_REG_TEMP3 0x0250
-+#define W83781D_REG_TEMP2_HYST 0x153
-+#define W83781D_REG_TEMP3_HYST 0x253
-+#define W83781D_REG_TEMP2_CONFIG 0x152
-+#define W83781D_REG_TEMP3_CONFIG 0x252
-+#define W83781D_REG_TEMP2_OVER 0x155
-+#define W83781D_REG_TEMP3_OVER 0x255
-+
-+#define W83781D_REG_TEMP 0x27
-+#define W83781D_REG_TEMP_OVER 0x39
-+#define W83781D_REG_TEMP_HYST 0x3A
-+#define W83781D_REG_BANK 0x4E
-+
-+#define W83781D_REG_CONFIG 0x40
-+#define W83781D_REG_ALARM1 0x41
-+#define W83781D_REG_ALARM2 0x42
-+#define W83781D_REG_ALARM3 0x450
-+
-+#define W83781D_REG_IRQ 0x4C
-+#define W83781D_REG_BEEP_CONFIG 0x4D
-+#define W83781D_REG_BEEP_INTS1 0x56
-+#define W83781D_REG_BEEP_INTS2 0x57
-+#define W83781D_REG_BEEP_INTS3 0x453
-+
-+#define W83781D_REG_VID_FANDIV 0x47
-+
-+#define W83781D_REG_CHIPID 0x49
-+#define W83781D_REG_WCHIPID 0x58
-+#define W83781D_REG_CHIPMAN 0x4F
-+#define W83781D_REG_PIN 0x4B
-+
-+#define W83781D_REG_VBAT 0x5D
-+
-+#define W83627HF_REG_PWM1 0x5A
-+#define W83627HF_REG_PWM2 0x5B
-+#define W83627HF_REG_PWMCLK12 0x5C
-+
-+#define W83627THF_REG_PWM1 0x01 /* 697HF and 637HF too */
-+#define W83627THF_REG_PWM2 0x03 /* 697HF and 637HF too */
-+#define W83627THF_REG_PWM3 0x11 /* 637HF too */
-+
-+#define W83627THF_REG_VRM_OVT_CFG 0x18 /* 637HF too */
-+
-+static const u8 regpwm_627hf[] = { W83627HF_REG_PWM1, W83627HF_REG_PWM2 };
-+static const u8 regpwm[] = { W83627THF_REG_PWM1, W83627THF_REG_PWM2,
-+ W83627THF_REG_PWM3 };
-+#define W836X7HF_REG_PWM(type, nr) (((type) == w83627hf) ? \
-+ regpwm_627hf[(nr) - 1] : regpwm[(nr) - 1])
-+
-+#define W83781D_REG_I2C_ADDR 0x48
-+#define W83781D_REG_I2C_SUBADDR 0x4A
-+
-+/* Sensor selection */
-+#define W83781D_REG_SCFG1 0x5D
-+static const u8 BIT_SCFG1[] = { 0x02, 0x04, 0x08 };
-+#define W83781D_REG_SCFG2 0x59
-+static const u8 BIT_SCFG2[] = { 0x10, 0x20, 0x40 };
-+#define W83781D_DEFAULT_BETA 3435
-+
-+/* Conversions. Limit checking is only done on the TO_REG
-+ variants. Note that you should be a bit careful with which arguments
-+ these macros are called: arguments may be evaluated more than once.
-+ Fixing this is just not worth it. */
-+#define IN_TO_REG(val) (SENSORS_LIMIT((((val) * 10 + 8)/16),0,255))
-+#define IN_FROM_REG(val) (((val) * 16 + 5) / 10)
-+
-+#define IN_TO_REG_VRM9(val) \
-+ (SENSORS_LIMIT((((val) * 1000 - 70000 + 244) / 488), 0, 255))
-+#define IN_FROM_REG_VRM9(reg) (((reg) * 488 + 70000 + 500) / 1000)
-+
-+static inline u8 FAN_TO_REG(long rpm, int div)
-+{
-+ if (rpm == 0)
-+ return 255;
-+ rpm = SENSORS_LIMIT(rpm, 1, 1000000);
-+ return SENSORS_LIMIT((1350000 + rpm * div / 2) / (rpm * div), 1,
-+ 254);
-+}
-+
-+#define TEMP_MIN (-1280)
-+#define TEMP_MAX ( 1270)
-+
-+/* TEMP: 1/10 degrees C (-128C to +127C)
-+ REG: 1C/bit, two's complement */
-+static u8 TEMP_TO_REG(int temp)
-+{
-+ int ntemp = SENSORS_LIMIT(temp, TEMP_MIN, TEMP_MAX);
-+ ntemp += (ntemp<0 ? -5 : 5);
-+ return (u8)(ntemp / 10);
-+}
-+
-+static int TEMP_FROM_REG(u8 reg)
-+{
-+ return (s8)reg * 10;
-+}
-+
-+#define FAN_FROM_REG(val,div) ((val)==0?-1:(val)==255?0:1350000/((val)*(div)))
-+
-+#define PWM_TO_REG(val) (SENSORS_LIMIT((val),0,255))
-+#define BEEPS_TO_REG(val) ((val) & 0xffffff)
-+
-+#define BEEP_ENABLE_TO_REG(val) ((val)?1:0)
-+#define BEEP_ENABLE_FROM_REG(val) ((val)?1:0)
-+
-+#define DIV_FROM_REG(val) (1 << (val))
-+
-+static inline u8 DIV_TO_REG(long val)
-+{
-+ int i;
-+ val = SENSORS_LIMIT(val, 1, 128) >> 1;
-+ for (i = 0; i < 6; i++) {
-+ if (val == 0)
-+ break;
-+ val >>= 1;
-+ }
-+ return ((u8) i);
-+}
-+
-+/* For each registered chip, we need to keep some data in memory. That
-+ data is pointed to by w83627hf_list[NR]->data. The structure itself is
-+ dynamically allocated, at the same time when a new client is allocated. */
-+struct w83627hf_data {
-+ struct i2c_client client;
-+ struct semaphore lock;
-+ int sysctl_id;
-+ enum chips type;
-+
-+ struct semaphore update_lock;
-+ char valid; /* !=0 if following fields are valid */
-+ unsigned long last_updated; /* In jiffies */
-+
-+ struct i2c_client *lm75; /* for secondary I2C addresses */
-+ /* pointer to array of 2 subclients */
-+
-+ u8 in[9]; /* Register value */
-+ u8 in_max[9]; /* Register value */
-+ u8 in_min[9]; /* Register value */
-+ u8 fan[3]; /* Register value */
-+ u8 fan_min[3]; /* Register value */
-+ u8 temp;
-+ u8 temp_over; /* Register value */
-+ u8 temp_hyst; /* Register value */
-+ u16 temp_add[2]; /* Register value */
-+ u16 temp_add_over[2]; /* Register value */
-+ u16 temp_add_hyst[2]; /* Register value */
-+ u8 fan_div[3]; /* Register encoding, shifted right */
-+ u8 vid; /* Register encoding, combined */
-+ u32 alarms; /* Register encoding, combined */
-+ u32 beeps; /* Register encoding, combined */
-+ u8 beep_enable; /* Boolean */
-+ u8 pwm[3]; /* Register value */
-+ u8 pwmenable[3]; /* bool */
-+ u16 sens[3]; /* 782D/783S only.
-+ 1 = pentium diode; 2 = 3904 diode;
-+ 3000-5000 = thermistor beta.
-+ Default = 3435.
-+ Other Betas unimplemented */
-+ u8 vrm;
-+ u8 vrm_ovt; /* Register value, 627thf & 637hf only */
-+};
-+
-+
-+static int w83627hf_attach_adapter(struct i2c_adapter *adapter);
-+static int w83627hf_detect(struct i2c_adapter *adapter, int address,
-+ unsigned short flags, int kind);
-+static int w83627hf_detach_client(struct i2c_client *client);
-+
-+static int w83627hf_read_value(struct i2c_client *client, u16 register);
-+static int w83627hf_write_value(struct i2c_client *client, u16 register,
-+ u16 value);
-+static void w83627hf_update_client(struct i2c_client *client);
-+static void w83627hf_init_client(struct i2c_client *client);
-+
-+
-+static void w83627hf_in(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void w83627hf_fan(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void w83627hf_temp(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void w83627hf_temp_add(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void w83627hf_vid(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void w83627hf_vrm(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void w83627hf_alarms(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void w83627hf_beep(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void w83627hf_fan_div(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void w83627hf_pwm(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void w83627hf_sens(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+
-+static int w83627hf_id = 0;
-+
-+static struct i2c_driver w83627hf_driver = {
-+ .owner = THIS_MODULE,
-+ .name = "W83627HF sensor driver",
-+ .id = I2C_DRIVERID_W83627HF,
-+ .flags = I2C_DF_NOTIFY,
-+ .attach_adapter = w83627hf_attach_adapter,
-+ .detach_client = w83627hf_detach_client,
-+};
-+
-+/* The /proc/sys entries */
-+/* WARNING these are copied from w83781d.c and have not been renamed.
-+ Note that the 627hf and 697hf are supported by both drivers.
-+ Do not make incompatible changes here or we will have errors
-+ in the generated file ../include/sensors.h !!!
-+*/
-+/* -- SENSORS SYSCTL START -- */
-+
-+#define W83781D_SYSCTL_IN0 1000 /* Volts * 100 */
-+#define W83781D_SYSCTL_IN1 1001
-+#define W83781D_SYSCTL_IN2 1002
-+#define W83781D_SYSCTL_IN3 1003
-+#define W83781D_SYSCTL_IN4 1004
-+#define W83781D_SYSCTL_IN5 1005
-+#define W83781D_SYSCTL_IN6 1006
-+#define W83781D_SYSCTL_IN7 1007
-+#define W83781D_SYSCTL_IN8 1008
-+#define W83781D_SYSCTL_FAN1 1101 /* Rotations/min */
-+#define W83781D_SYSCTL_FAN2 1102
-+#define W83781D_SYSCTL_FAN3 1103
-+#define W83781D_SYSCTL_TEMP1 1200 /* Degrees Celcius * 10 */
-+#define W83781D_SYSCTL_TEMP2 1201 /* Degrees Celcius * 10 */
-+#define W83781D_SYSCTL_TEMP3 1202 /* Degrees Celcius * 10 */
-+#define W83781D_SYSCTL_VID 1300 /* Volts * 1000 */
-+#define W83781D_SYSCTL_VRM 1301
-+#define W83781D_SYSCTL_PWM1 1401
-+#define W83781D_SYSCTL_PWM2 1402
-+#define W83781D_SYSCTL_PWM3 1403
-+#define W83781D_SYSCTL_SENS1 1501 /* 1, 2, or Beta (3000-5000) */
-+#define W83781D_SYSCTL_SENS2 1502
-+#define W83781D_SYSCTL_SENS3 1503
-+#define W83781D_SYSCTL_FAN_DIV 2000 /* 1, 2, 4 or 8 */
-+#define W83781D_SYSCTL_ALARMS 2001 /* bitvector */
-+#define W83781D_SYSCTL_BEEP 2002 /* bitvector */
-+
-+#define W83781D_ALARM_IN0 0x0001
-+#define W83781D_ALARM_IN1 0x0002
-+#define W83781D_ALARM_IN2 0x0004
-+#define W83781D_ALARM_IN3 0x0008
-+#define W83781D_ALARM_IN4 0x0100
-+#define W83781D_ALARM_IN5 0x0200
-+#define W83781D_ALARM_IN6 0x0400
-+#define W83782D_ALARM_IN7 0x10000
-+#define W83782D_ALARM_IN8 0x20000
-+#define W83781D_ALARM_FAN1 0x0040
-+#define W83781D_ALARM_FAN2 0x0080
-+#define W83781D_ALARM_FAN3 0x0800
-+#define W83781D_ALARM_TEMP1 0x0010
-+#define W83781D_ALARM_TEMP23 0x0020 /* 781D only */
-+#define W83781D_ALARM_TEMP2 0x0020 /* 782D/783S */
-+#define W83781D_ALARM_TEMP3 0x2000 /* 782D only */
-+#define W83781D_ALARM_CHAS 0x1000
-+
-+/* -- SENSORS SYSCTL END -- */
-+
-+/* These files are created for each detected chip. This is just a template;
-+ though at first sight, you might think we could use a statically
-+ allocated list, we need some way to get back to the parent - which
-+ is done through one of the 'extra' fields which are initialized
-+ when a new copy is allocated. */
-+
-+/* without pwm3-4 */
-+static ctl_table w83627hf_dir_table_template[] = {
-+ {W83781D_SYSCTL_IN0, "in0", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83627hf_in},
-+ {W83781D_SYSCTL_IN1, "in1", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83627hf_in},
-+ {W83781D_SYSCTL_IN2, "in2", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83627hf_in},
-+ {W83781D_SYSCTL_IN3, "in3", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83627hf_in},
-+ {W83781D_SYSCTL_IN4, "in4", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83627hf_in},
-+ {W83781D_SYSCTL_IN5, "in5", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83627hf_in},
-+ {W83781D_SYSCTL_IN6, "in6", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83627hf_in},
-+ {W83781D_SYSCTL_IN7, "in7", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83627hf_in},
-+ {W83781D_SYSCTL_IN8, "in8", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83627hf_in},
-+ {W83781D_SYSCTL_FAN1, "fan1", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83627hf_fan},
-+ {W83781D_SYSCTL_FAN2, "fan2", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83627hf_fan},
-+ {W83781D_SYSCTL_FAN3, "fan3", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83627hf_fan},
-+ {W83781D_SYSCTL_TEMP1, "temp1", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83627hf_temp},
-+ {W83781D_SYSCTL_TEMP2, "temp2", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83627hf_temp_add},
-+ {W83781D_SYSCTL_TEMP3, "temp3", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83627hf_temp_add},
-+ {W83781D_SYSCTL_VID, "vid", NULL, 0, 0444, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83627hf_vid},
-+ {W83781D_SYSCTL_VRM, "vrm", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83627hf_vrm},
-+ {W83781D_SYSCTL_FAN_DIV, "fan_div", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83627hf_fan_div},
-+ {W83781D_SYSCTL_ALARMS, "alarms", NULL, 0, 0444, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83627hf_alarms},
-+ {W83781D_SYSCTL_BEEP, "beep", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83627hf_beep},
-+ {W83781D_SYSCTL_PWM1, "pwm1", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83627hf_pwm},
-+ {W83781D_SYSCTL_PWM2, "pwm2", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83627hf_pwm},
-+ {W83781D_SYSCTL_SENS1, "sensor1", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83627hf_sens},
-+ {W83781D_SYSCTL_SENS2, "sensor2", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83627hf_sens},
-+ {W83781D_SYSCTL_SENS3, "sensor3", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83627hf_sens},
-+ {0}
-+};
-+
-+/* similar to w83782d but no fan3, no vid */
-+static ctl_table w83697hf_dir_table_template[] = {
-+ {W83781D_SYSCTL_IN0, "in0", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83627hf_in},
-+ /* no in1 to maintain compatibility with 781d and 782d. */
-+ {W83781D_SYSCTL_IN2, "in2", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83627hf_in},
-+ {W83781D_SYSCTL_IN3, "in3", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83627hf_in},
-+ {W83781D_SYSCTL_IN4, "in4", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83627hf_in},
-+ {W83781D_SYSCTL_IN5, "in5", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83627hf_in},
-+ {W83781D_SYSCTL_IN6, "in6", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83627hf_in},
-+ {W83781D_SYSCTL_IN7, "in7", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83627hf_in},
-+ {W83781D_SYSCTL_IN8, "in8", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83627hf_in},
-+ {W83781D_SYSCTL_FAN1, "fan1", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83627hf_fan},
-+ {W83781D_SYSCTL_FAN2, "fan2", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83627hf_fan},
-+ {W83781D_SYSCTL_TEMP1, "temp1", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83627hf_temp},
-+ {W83781D_SYSCTL_TEMP2, "temp2", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83627hf_temp_add},
-+ {W83781D_SYSCTL_FAN_DIV, "fan_div", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83627hf_fan_div},
-+ {W83781D_SYSCTL_ALARMS, "alarms", NULL, 0, 0444, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83627hf_alarms},
-+ {W83781D_SYSCTL_BEEP, "beep", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83627hf_beep},
-+ {W83781D_SYSCTL_PWM1, "pwm1", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83627hf_pwm},
-+ {W83781D_SYSCTL_PWM2, "pwm2", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83627hf_pwm},
-+ {W83781D_SYSCTL_SENS1, "sensor1", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83627hf_sens},
-+ {W83781D_SYSCTL_SENS2, "sensor2", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83627hf_sens},
-+ {0}
-+};
-+
-+/* no in5 and in6 */
-+/* We use this one for W83637HF too */
-+static ctl_table w83627thf_dir_table_template[] = {
-+ {W83781D_SYSCTL_IN0, "in0", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83627hf_in},
-+ {W83781D_SYSCTL_IN1, "in1", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83627hf_in},
-+ {W83781D_SYSCTL_IN2, "in2", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83627hf_in},
-+ {W83781D_SYSCTL_IN3, "in3", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83627hf_in},
-+ {W83781D_SYSCTL_IN4, "in4", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83627hf_in},
-+ {W83781D_SYSCTL_IN7, "in7", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83627hf_in},
-+ {W83781D_SYSCTL_IN8, "in8", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83627hf_in},
-+ {W83781D_SYSCTL_FAN1, "fan1", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83627hf_fan},
-+ {W83781D_SYSCTL_FAN2, "fan2", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83627hf_fan},
-+ {W83781D_SYSCTL_FAN3, "fan3", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83627hf_fan},
-+ {W83781D_SYSCTL_TEMP1, "temp1", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83627hf_temp},
-+ {W83781D_SYSCTL_TEMP2, "temp2", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83627hf_temp_add},
-+ {W83781D_SYSCTL_TEMP3, "temp3", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83627hf_temp_add},
-+ {W83781D_SYSCTL_VID, "vid", NULL, 0, 0444, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83627hf_vid},
-+ {W83781D_SYSCTL_VRM, "vrm", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83627hf_vrm},
-+ {W83781D_SYSCTL_FAN_DIV, "fan_div", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83627hf_fan_div},
-+ {W83781D_SYSCTL_ALARMS, "alarms", NULL, 0, 0444, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83627hf_alarms},
-+ {W83781D_SYSCTL_BEEP, "beep", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83627hf_beep},
-+ {W83781D_SYSCTL_PWM1, "pwm1", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83627hf_pwm},
-+ {W83781D_SYSCTL_PWM2, "pwm2", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83627hf_pwm},
-+ {W83781D_SYSCTL_PWM3, "pwm3", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83627hf_pwm},
-+ {W83781D_SYSCTL_SENS1, "sensor1", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83627hf_sens},
-+ {W83781D_SYSCTL_SENS2, "sensor2", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83627hf_sens},
-+ {W83781D_SYSCTL_SENS3, "sensor3", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83627hf_sens},
-+ {0}
-+};
-+
-+
-+/* This function is called when:
-+ * w83627hf_driver is inserted (when this module is loaded), for each
-+ available adapter
-+ * when a new adapter is inserted (and w83627hf_driver is still present) */
-+static int w83627hf_attach_adapter(struct i2c_adapter *adapter)
-+{
-+ return i2c_detect(adapter, &addr_data, w83627hf_detect);
-+}
-+
-+static int w83627hf_find(int *address)
-+{
-+ u16 val;
-+
-+ superio_enter();
-+ val= superio_inb(DEVID);
-+ if(val != W627_DEVID && val !=W627THF_DEVID && val != W697_DEVID && val != W637_DEVID) {
-+ superio_exit();
-+ return -ENODEV;
-+ }
-+
-+ superio_select(W83627HF_LD_HWM);
-+ val = (superio_inb(WINB_BASE_REG) << 8) |
-+ superio_inb(WINB_BASE_REG + 1);
-+ *address = val & ~(WINB_EXTENT - 1);
-+ if (*address == 0 && force_addr == 0) {
-+ printk("w83627hf.o: base address not set - use force_addr=0xaddr\n");
-+ superio_exit();
-+ return -ENODEV;
-+ }
-+ if (force_addr)
-+ *address = force_addr; /* so detect will get called */
-+
-+ superio_exit();
-+ return 0;
-+}
-+
-+int w83627hf_detect(struct i2c_adapter *adapter, int address,
-+ unsigned short flags, int kind)
-+{
-+ int i, val;
-+ struct i2c_client *new_client;
-+ struct w83627hf_data *data;
-+ int err = 0;
-+ const char *type_name = "";
-+ const char *client_name = "";
-+
-+ if (!i2c_is_isa_adapter(adapter))
-+ return 0;
-+
-+ if(force_addr)
-+ address = force_addr & ~(WINB_EXTENT - 1);
-+ if (check_region(address, WINB_EXTENT)) {
-+ printk("w83627hf.o: region 0x%x already in use!\n", address);
-+ return -ENODEV;
-+ }
-+ if(force_addr) {
-+ printk("w83627hf.o: forcing ISA address 0x%04X\n", address);
-+ superio_enter();
-+ superio_select(W83627HF_LD_HWM);
-+ superio_outb(WINB_BASE_REG, address >> 8);
-+ superio_outb(WINB_BASE_REG+1, address & 0xff);
-+ superio_exit();
-+ }
-+
-+ superio_enter();
-+ val= superio_inb(DEVID);
-+ if(val == W627_DEVID)
-+ kind = w83627hf;
-+ else if(val == W697_DEVID)
-+ kind = w83697hf;
-+ else if(val == W627THF_DEVID)
-+ kind = w83627thf;
-+ else if(val == W637_DEVID)
-+ kind = w83637hf;
-+
-+ superio_select(W83627HF_LD_HWM);
-+ if((val = 0x01 & superio_inb(WINB_ACT_REG)) == 0)
-+ superio_outb(WINB_ACT_REG, 1);
-+ superio_exit();
-+
-+ /* OK. For now, we presume we have a valid client. We now create the
-+ client structure, even though we cannot fill it completely yet.
-+ But it allows us to access w83627hf_{read,write}_value. */
-+
-+ if (!(data = kmalloc(sizeof(struct w83627hf_data), GFP_KERNEL))) {
-+ err = -ENOMEM;
-+ goto ERROR0;
-+ }
-+
-+ new_client = &data->client;
-+ new_client->addr = address;
-+ init_MUTEX(&data->lock);
-+ new_client->data = data;
-+ new_client->adapter = adapter;
-+ new_client->driver = &w83627hf_driver;
-+ new_client->flags = 0;
-+
-+
-+ if (kind == w83627hf) {
-+ type_name = "w83627hf";
-+ client_name = "W83627HF chip";
-+ } else if (kind == w83627thf) {
-+ type_name = "w83627thf";
-+ client_name = "W83627THF chip";
-+ } else if (kind == w83697hf) {
-+ type_name = "w83697hf";
-+ client_name = "W83697HF chip";
-+ } else if (kind == w83637hf) {
-+ type_name = "w83637hf";
-+ client_name = "W83637HF chip";
-+ } else {
-+ goto ERROR1;
-+ }
-+
-+ request_region(address, WINB_EXTENT, type_name);
-+
-+ /* Fill in the remaining client fields and put it into the global list */
-+ strcpy(new_client->name, client_name);
-+ data->type = kind;
-+ new_client->id = w83627hf_id++;
-+ data->valid = 0;
-+ init_MUTEX(&data->update_lock);
-+
-+ /* Tell the I2C layer a new client has arrived */
-+ if ((err = i2c_attach_client(new_client)))
-+ goto ERROR3;
-+
-+ data->lm75 = NULL;
-+
-+ /* Register a new directory entry with module sensors */
-+ if ((i = i2c_register_entry(new_client,
-+ type_name,
-+ (kind == w83697hf) ?
-+ w83697hf_dir_table_template :
-+ (kind == w83627hf) ?
-+ w83627hf_dir_table_template :
-+ /* w83627thf table also used for 637 */
-+ w83627thf_dir_table_template)) < 0) {
-+ err = i;
-+ goto ERROR7;
-+ }
-+ data->sysctl_id = i;
-+
-+ /* Initialize the chip */
-+ w83627hf_init_client(new_client);
-+ return 0;
-+
-+/* OK, this is not exactly good programming practice, usually. But it is
-+ very code-efficient in this case. */
-+
-+ ERROR7:
-+ i2c_detach_client(new_client);
-+ ERROR3:
-+ release_region(address, WINB_EXTENT);
-+ ERROR1:
-+ kfree(data);
-+ ERROR0:
-+ return err;
-+}
-+
-+static int w83627hf_detach_client(struct i2c_client *client)
-+{
-+ int err;
-+
-+ i2c_deregister_entry(((struct w83627hf_data *) (client->data))->
-+ sysctl_id);
-+
-+ if ((err = i2c_detach_client(client))) {
-+ printk
-+ (KERN_ERR "w83627hf.o: Client deregistration failed, client not detached.\n");
-+ return err;
-+ }
-+
-+ release_region(client->addr, WINB_EXTENT);
-+ kfree(client->data);
-+
-+ return 0;
-+}
-+
-+
-+/*
-+ ISA access must always be locked explicitly!
-+ We ignore the W83781D BUSY flag at this moment - it could lead to deadlocks,
-+ would slow down the W83781D access and should not be necessary.
-+ There are some ugly typecasts here, but the good news is - they should
-+ nowhere else be necessary! */
-+static int w83627hf_read_value(struct i2c_client *client, u16 reg)
-+{
-+ int res, word_sized;
-+
-+ down(&(((struct w83627hf_data *) (client->data))->lock));
-+ word_sized = (((reg & 0xff00) == 0x100)
-+ || ((reg & 0xff00) == 0x200))
-+ && (((reg & 0x00ff) == 0x50)
-+ || ((reg & 0x00ff) == 0x53)
-+ || ((reg & 0x00ff) == 0x55));
-+ if (reg & 0xff00) {
-+ outb_p(W83781D_REG_BANK,
-+ client->addr + W83781D_ADDR_REG_OFFSET);
-+ outb_p(reg >> 8,
-+ client->addr + W83781D_DATA_REG_OFFSET);
-+ }
-+ outb_p(reg & 0xff, client->addr + W83781D_ADDR_REG_OFFSET);
-+ res = inb_p(client->addr + W83781D_DATA_REG_OFFSET);
-+ if (word_sized) {
-+ outb_p((reg & 0xff) + 1,
-+ client->addr + W83781D_ADDR_REG_OFFSET);
-+ res =
-+ (res << 8) + inb_p(client->addr +
-+ W83781D_DATA_REG_OFFSET);
-+ }
-+ if (reg & 0xff00) {
-+ outb_p(W83781D_REG_BANK,
-+ client->addr + W83781D_ADDR_REG_OFFSET);
-+ outb_p(0, client->addr + W83781D_DATA_REG_OFFSET);
-+ }
-+ up(&(((struct w83627hf_data *) (client->data))->lock));
-+ return res;
-+}
-+
-+static int w83627thf_read_gpio5(struct i2c_client *client)
-+{
-+ int res, inv;
-+
-+ down(&(((struct w83627hf_data *) (client->data))->lock));
-+ superio_enter();
-+ superio_select(W83627HF_LD_GPIO5);
-+ res = superio_inb(W83627THF_GPIO5_DR);
-+ inv = superio_inb(W83627THF_GPIO5_INVR);
-+ superio_exit();
-+ up(&(((struct w83627hf_data *) (client->data))->lock));
-+ return res;
-+}
-+
-+static int w83627hf_write_value(struct i2c_client *client, u16 reg, u16 value)
-+{
-+ int word_sized;
-+
-+ down(&(((struct w83627hf_data *) (client->data))->lock));
-+ word_sized = (((reg & 0xff00) == 0x100)
-+ || ((reg & 0xff00) == 0x200))
-+ && (((reg & 0x00ff) == 0x53)
-+ || ((reg & 0x00ff) == 0x55));
-+ if (reg & 0xff00) {
-+ outb_p(W83781D_REG_BANK,
-+ client->addr + W83781D_ADDR_REG_OFFSET);
-+ outb_p(reg >> 8,
-+ client->addr + W83781D_DATA_REG_OFFSET);
-+ }
-+ outb_p(reg & 0xff, client->addr + W83781D_ADDR_REG_OFFSET);
-+ if (word_sized) {
-+ outb_p(value >> 8,
-+ client->addr + W83781D_DATA_REG_OFFSET);
-+ outb_p((reg & 0xff) + 1,
-+ client->addr + W83781D_ADDR_REG_OFFSET);
-+ }
-+ outb_p(value & 0xff,
-+ client->addr + W83781D_DATA_REG_OFFSET);
-+ if (reg & 0xff00) {
-+ outb_p(W83781D_REG_BANK,
-+ client->addr + W83781D_ADDR_REG_OFFSET);
-+ outb_p(0, client->addr + W83781D_DATA_REG_OFFSET);
-+ }
-+ up(&(((struct w83627hf_data *) (client->data))->lock));
-+ return 0;
-+}
-+
-+/* Called when we have found a new W83781D. It should set limits, etc. */
-+static void w83627hf_init_client(struct i2c_client *client)
-+{
-+ struct w83627hf_data *data = client->data;
-+ int i;
-+ int type = data->type;
-+ u8 tmp;
-+
-+ /* Minimize conflicts with other winbond i2c-only clients... */
-+ /* disable i2c subclients... how to disable main i2c client?? */
-+ /* force i2c address to relatively uncommon address */
-+ w83627hf_write_value(client, W83781D_REG_I2C_SUBADDR, 0x89);
-+ w83627hf_write_value(client, W83781D_REG_I2C_ADDR, force_i2c);
-+
-+ /* Read VID only once */
-+ if (w83627hf == data->type || w83637hf == data->type) {
-+ int lo = w83627hf_read_value(client, W83781D_REG_VID_FANDIV);
-+ int hi = w83627hf_read_value(client, W83781D_REG_CHIPID);
-+ data->vid = (lo & 0x0f) | ((hi & 0x01) << 4);
-+ } else if (w83627thf == data->type) {
-+ data->vid = w83627thf_read_gpio5(client) & 0x1f;
-+ }
-+
-+ /* Read VRM & OVT Config only once */
-+ if (w83627thf == data->type || w83637hf == data->type)
-+ data->vrm_ovt =
-+ w83627hf_read_value(client, W83627THF_REG_VRM_OVT_CFG);
-+ else
-+ data->vrm_ovt = 0;
-+
-+ /* Choose VRM based on "VRM & OVT" register */
-+ data->vrm = (data->vrm_ovt & 0x01) ? 90 : 82;
-+
-+ tmp = w83627hf_read_value(client, W83781D_REG_SCFG1);
-+ for (i = 1; i <= 3; i++) {
-+ if (!(tmp & BIT_SCFG1[i - 1])) {
-+ data->sens[i - 1] = W83781D_DEFAULT_BETA;
-+ } else {
-+ if (w83627hf_read_value
-+ (client,
-+ W83781D_REG_SCFG2) & BIT_SCFG2[i - 1])
-+ data->sens[i - 1] = 1;
-+ else
-+ data->sens[i - 1] = 2;
-+ }
-+ if ((type == w83697hf) && (i == 2))
-+ break;
-+ }
-+
-+ data->pwmenable[0] = 1;
-+ data->pwmenable[1] = 1;
-+ data->pwmenable[2] = 1;
-+
-+ if(init) {
-+ if (type == w83627hf) {
-+ /* enable PWM2 control (can't hurt since PWM reg
-+ should have been reset to 0xff) */
-+ w83627hf_write_value(client, W83627HF_REG_PWMCLK12, 0x19);
-+ }
-+ /* enable comparator mode for temp2 and temp3 so
-+ alarm indication will work correctly */
-+ i = w83627hf_read_value(client, W83781D_REG_IRQ);
-+ if (!(i & 0x40))
-+ w83627hf_write_value(client, W83781D_REG_IRQ,
-+ i | 0x40);
-+ }
-+
-+ /* Start monitoring */
-+ w83627hf_write_value(client, W83781D_REG_CONFIG,
-+ (w83627hf_read_value(client,
-+ W83781D_REG_CONFIG) & 0xf7)
-+ | 0x01);
-+}
-+
-+static void w83627hf_update_client(struct i2c_client *client)
-+{
-+ struct w83627hf_data *data = client->data;
-+ int i;
-+
-+ down(&data->update_lock);
-+
-+ if ((jiffies - data->last_updated > HZ + HZ / 2) ||
-+ (jiffies < data->last_updated) || !data->valid) {
-+ for (i = 0; i <= 8; i++) {
-+ /* skip missing sensors */
-+ if (((data->type == w83697hf) && (i == 1)) ||
-+ ((data->type == w83627thf || data->type == w83637hf) &&
-+ (i == 4 || i == 5)))
-+ continue;
-+ data->in[i] =
-+ w83627hf_read_value(client, W83781D_REG_IN(i));
-+ data->in_min[i] =
-+ w83627hf_read_value(client,
-+ W83781D_REG_IN_MIN(i));
-+ data->in_max[i] =
-+ w83627hf_read_value(client,
-+ W83781D_REG_IN_MAX(i));
-+ }
-+ for (i = 1; i <= 3; i++) {
-+ data->fan[i - 1] =
-+ w83627hf_read_value(client, W83781D_REG_FAN(i));
-+ data->fan_min[i - 1] =
-+ w83627hf_read_value(client,
-+ W83781D_REG_FAN_MIN(i));
-+ }
-+ for (i = 1; i <= 3; i++) {
-+ u8 tmp = w83627hf_read_value(client,
-+ W836X7HF_REG_PWM(data->type, i));
-+ if (data->type == w83627thf)
-+ tmp &= 0xf0; /* bits 0-3 are reserved in 627THF */
-+ data->pwm[i - 1] = tmp;
-+ if(i == 2 && (data->type == w83627hf || data->type == w83697hf))
-+ break;
-+ }
-+
-+ data->temp = w83627hf_read_value(client, W83781D_REG_TEMP);
-+ data->temp_over =
-+ w83627hf_read_value(client, W83781D_REG_TEMP_OVER);
-+ data->temp_hyst =
-+ w83627hf_read_value(client, W83781D_REG_TEMP_HYST);
-+ data->temp_add[0] =
-+ w83627hf_read_value(client, W83781D_REG_TEMP2);
-+ data->temp_add_over[0] =
-+ w83627hf_read_value(client, W83781D_REG_TEMP2_OVER);
-+ data->temp_add_hyst[0] =
-+ w83627hf_read_value(client, W83781D_REG_TEMP2_HYST);
-+ if (data->type != w83697hf) {
-+ data->temp_add[1] =
-+ w83627hf_read_value(client, W83781D_REG_TEMP3);
-+ data->temp_add_over[1] =
-+ w83627hf_read_value(client, W83781D_REG_TEMP3_OVER);
-+ data->temp_add_hyst[1] =
-+ w83627hf_read_value(client, W83781D_REG_TEMP3_HYST);
-+ }
-+
-+ i = w83627hf_read_value(client, W83781D_REG_VID_FANDIV);
-+ data->fan_div[0] = (i >> 4) & 0x03;
-+ data->fan_div[1] = (i >> 6) & 0x03;
-+ if (data->type != w83697hf) {
-+ data->fan_div[2] = (w83627hf_read_value(client,
-+ W83781D_REG_PIN) >> 6) & 0x03;
-+ }
-+ i = w83627hf_read_value(client, W83781D_REG_VBAT);
-+ data->fan_div[0] |= (i >> 3) & 0x04;
-+ data->fan_div[1] |= (i >> 4) & 0x04;
-+ if (data->type != w83697hf)
-+ data->fan_div[2] |= (i >> 5) & 0x04;
-+ data->alarms =
-+ w83627hf_read_value(client, W83781D_REG_ALARM1) |
-+ (w83627hf_read_value(client, W83781D_REG_ALARM2) << 8) |
-+ (w83627hf_read_value(client, W83781D_REG_ALARM3) << 16);
-+ i = w83627hf_read_value(client, W83781D_REG_BEEP_INTS2);
-+ data->beep_enable = i >> 7;
-+ data->beeps = ((i & 0x7f) << 8) |
-+ w83627hf_read_value(client, W83781D_REG_BEEP_INTS1) |
-+ w83627hf_read_value(client, W83781D_REG_BEEP_INTS3) << 16;
-+ data->last_updated = jiffies;
-+ data->valid = 1;
-+ }
-+
-+ up(&data->update_lock);
-+}
-+
-+void w83627hf_in(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct w83627hf_data *data = client->data;
-+ int nr = ctl_name - W83781D_SYSCTL_IN0;
-+
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 2;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ w83627hf_update_client(client);
-+
-+ if (nr == 0 && (data->vrm_ovt & 0x01)) {
-+ /* use VRM9 calculation */
-+ results[0] = IN_FROM_REG_VRM9(data->in_min[0]);
-+ results[1] = IN_FROM_REG_VRM9(data->in_max[0]);
-+ results[2] = IN_FROM_REG_VRM9(data->in[0]);
-+
-+ } else {
-+ /* use VRM8 (standard) calculation */
-+ results[0] = IN_FROM_REG(data->in_min[nr]);
-+ results[1] = IN_FROM_REG(data->in_max[nr]);
-+ results[2] = IN_FROM_REG(data->in[nr]);
-+ }
-+
-+ *nrels_mag = 3;
-+
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ if (*nrels_mag >= 1) {
-+ if (nr == 0 && (data->vrm_ovt & 0x01))
-+ /* use VRM9 calculation */
-+ data->in_min[0] = IN_TO_REG_VRM9(results[0]);
-+ else
-+ /* use VRM8 (standard) calculation */
-+ data->in_min[nr] = IN_TO_REG(results[0]);
-+
-+ w83627hf_write_value(client, W83781D_REG_IN_MIN(nr),
-+ data->in_min[nr]);
-+ }
-+ if (*nrels_mag >= 2) {
-+ if (nr == 0 && (data->vrm_ovt & 0x01))
-+ /* use VRM9 calculation */
-+ data->in_min[0] = IN_TO_REG_VRM9(results[1]);
-+ else
-+ /* use VRM8 (standard) calculation */
-+ data->in_max[nr] = IN_TO_REG(results[1]);
-+
-+ w83627hf_write_value(client, W83781D_REG_IN_MAX(nr),
-+ data->in_max[nr]);
-+ }
-+ }
-+}
-+
-+void w83627hf_fan(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct w83627hf_data *data = client->data;
-+ int nr = ctl_name - W83781D_SYSCTL_FAN1 + 1;
-+
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 0;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ w83627hf_update_client(client);
-+ results[0] = FAN_FROM_REG(data->fan_min[nr - 1],
-+ DIV_FROM_REG(data->fan_div[nr - 1]));
-+ results[1] = FAN_FROM_REG(data->fan[nr - 1],
-+ DIV_FROM_REG(data->fan_div[nr - 1]));
-+ *nrels_mag = 2;
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ if (*nrels_mag >= 1) {
-+ data->fan_min[nr - 1] =
-+ FAN_TO_REG(results[0],
-+ DIV_FROM_REG(data->fan_div[nr-1]));
-+ w83627hf_write_value(client,
-+ W83781D_REG_FAN_MIN(nr),
-+ data->fan_min[nr - 1]);
-+ }
-+ }
-+}
-+
-+void w83627hf_temp(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct w83627hf_data *data = client->data;
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 1;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ w83627hf_update_client(client);
-+ results[0] = TEMP_FROM_REG(data->temp_over);
-+ results[1] = TEMP_FROM_REG(data->temp_hyst);
-+ results[2] = TEMP_FROM_REG(data->temp);
-+ *nrels_mag = 3;
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ if (*nrels_mag >= 1) {
-+ data->temp_over = TEMP_TO_REG(results[0]);
-+ w83627hf_write_value(client, W83781D_REG_TEMP_OVER,
-+ data->temp_over);
-+ }
-+ if (*nrels_mag >= 2) {
-+ data->temp_hyst = TEMP_TO_REG(results[1]);
-+ w83627hf_write_value(client, W83781D_REG_TEMP_HYST,
-+ data->temp_hyst);
-+ }
-+ }
-+}
-+
-+void w83627hf_temp_add(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results)
-+{
-+ struct w83627hf_data *data = client->data;
-+ int nr = ctl_name - W83781D_SYSCTL_TEMP2;
-+
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 1;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ w83627hf_update_client(client);
-+ results[0] =
-+ LM75_TEMP_FROM_REG(data->temp_add_over[nr]);
-+ results[1] =
-+ LM75_TEMP_FROM_REG(data->temp_add_hyst[nr]);
-+ results[2] = LM75_TEMP_FROM_REG(data->temp_add[nr]);
-+ *nrels_mag = 3;
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ if (*nrels_mag >= 1) {
-+ data->temp_add_over[nr] =
-+ LM75_TEMP_TO_REG(results[0]);
-+ w83627hf_write_value(client,
-+ nr ? W83781D_REG_TEMP3_OVER :
-+ W83781D_REG_TEMP2_OVER,
-+ data->temp_add_over[nr]);
-+ }
-+ if (*nrels_mag >= 2) {
-+ data->temp_add_hyst[nr] =
-+ LM75_TEMP_TO_REG(results[1]);
-+ w83627hf_write_value(client,
-+ nr ? W83781D_REG_TEMP3_HYST :
-+ W83781D_REG_TEMP2_HYST,
-+ data->temp_add_hyst[nr]);
-+ }
-+ }
-+}
-+
-+void w83627hf_vid(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct w83627hf_data *data = client->data;
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 3;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ w83627hf_update_client(client);
-+ results[0] = vid_from_reg(data->vid, data->vrm);
-+ *nrels_mag = 1;
-+ }
-+}
-+
-+void w83627hf_vrm(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct w83627hf_data *data = client->data;
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 1;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ results[0] = data->vrm;
-+ *nrels_mag = 1;
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ if (*nrels_mag >= 1)
-+ data->vrm = results[0];
-+ }
-+}
-+
-+void w83627hf_alarms(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct w83627hf_data *data = client->data;
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 0;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ w83627hf_update_client(client);
-+ results[0] = data->alarms;
-+ *nrels_mag = 1;
-+ }
-+}
-+
-+void w83627hf_beep(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct w83627hf_data *data = client->data;
-+ int val;
-+
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 0;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ w83627hf_update_client(client);
-+ results[0] = BEEP_ENABLE_FROM_REG(data->beep_enable);
-+ results[1] = data->beeps;
-+ *nrels_mag = 2;
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ if (*nrels_mag >= 2) {
-+ data->beeps = BEEPS_TO_REG(results[1]);
-+ w83627hf_write_value(client, W83781D_REG_BEEP_INTS1,
-+ data->beeps & 0xff);
-+ w83627hf_write_value(client,
-+ W83781D_REG_BEEP_INTS3,
-+ ((data-> beeps) >> 16) &
-+ 0xff);
-+ val = (data->beeps >> 8) & 0x7f;
-+ } else if (*nrels_mag >= 1)
-+ val =
-+ w83627hf_read_value(client,
-+ W83781D_REG_BEEP_INTS2) &
-+ 0x7f;
-+ if (*nrels_mag >= 1) {
-+ data->beep_enable = BEEP_ENABLE_TO_REG(results[0]);
-+ w83627hf_write_value(client, W83781D_REG_BEEP_INTS2,
-+ val | data->beep_enable << 7);
-+ }
-+ }
-+}
-+
-+/* w83697hf only has two fans */
-+void w83627hf_fan_div(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results)
-+{
-+ struct w83627hf_data *data = client->data;
-+ int old, old2, old3 = 0;
-+
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 0;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ w83627hf_update_client(client);
-+ results[0] = DIV_FROM_REG(data->fan_div[0]);
-+ results[1] = DIV_FROM_REG(data->fan_div[1]);
-+ if (data->type == w83697hf) {
-+ *nrels_mag = 2;
-+ } else {
-+ results[2] = DIV_FROM_REG(data->fan_div[2]);
-+ *nrels_mag = 3;
-+ }
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ old = w83627hf_read_value(client, W83781D_REG_VID_FANDIV);
-+ /* w83627hf doesn't have extended divisor bits */
-+ old3 =
-+ w83627hf_read_value(client, W83781D_REG_VBAT);
-+ if (*nrels_mag >= 3 && data->type != w83697hf) {
-+ data->fan_div[2] =
-+ DIV_TO_REG(results[2]);
-+ old2 = w83627hf_read_value(client, W83781D_REG_PIN);
-+ old2 =
-+ (old2 & 0x3f) | ((data->fan_div[2] & 0x03) << 6);
-+ w83627hf_write_value(client, W83781D_REG_PIN, old2);
-+ old3 =
-+ (old3 & 0x7f) |
-+ ((data->fan_div[2] & 0x04) << 5);
-+ }
-+ if (*nrels_mag >= 2) {
-+ data->fan_div[1] =
-+ DIV_TO_REG(results[1]);
-+ old =
-+ (old & 0x3f) | ((data->fan_div[1] & 0x03) << 6);
-+ old3 =
-+ (old3 & 0xbf) |
-+ ((data->fan_div[1] & 0x04) << 4);
-+ }
-+ if (*nrels_mag >= 1) {
-+ data->fan_div[0] =
-+ DIV_TO_REG(results[0]);
-+ old =
-+ (old & 0xcf) | ((data->fan_div[0] & 0x03) << 4);
-+ w83627hf_write_value(client, W83781D_REG_VID_FANDIV,
-+ old);
-+ old3 =
-+ (old3 & 0xdf) |
-+ ((data->fan_div[0] & 0x04) << 3);
-+ w83627hf_write_value(client,
-+ W83781D_REG_VBAT,
-+ old3);
-+ }
-+ }
-+}
-+
-+/* we do not currently support disabling PWM with 2nd argument;
-+ set first argument to 255 to disable */
-+void w83627hf_pwm(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct w83627hf_data *data = client->data;
-+ int nr = 1 + ctl_name - W83781D_SYSCTL_PWM1;
-+
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 0;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ w83627hf_update_client(client);
-+ results[0] = data->pwm[nr - 1];
-+ results[1] = data->pwmenable[nr - 1];
-+ *nrels_mag = 2;
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ if (*nrels_mag >= 1) {
-+ if (data->type == w83627thf) {
-+ /* bits 0-3 are reserved in 627THF */
-+ data->pwm[nr - 1] = PWM_TO_REG(results[0]) & 0xf0;
-+ w83627hf_write_value(client,
-+ W836X7HF_REG_PWM(data->type, nr),
-+ data->pwm[nr - 1] |
-+ (w83627hf_read_value(client,
-+ W836X7HF_REG_PWM(data->type, nr)) & 0x0f));
-+ } else {
-+ data->pwm[nr - 1] = PWM_TO_REG(results[0]);
-+ w83627hf_write_value(client,
-+ W836X7HF_REG_PWM(data->type, nr),
-+ data->pwm[nr - 1]);
-+ }
-+ }
-+ }
-+}
-+
-+void w83627hf_sens(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct w83627hf_data *data = client->data;
-+ int nr = 1 + ctl_name - W83781D_SYSCTL_SENS1;
-+ u8 tmp;
-+
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 0;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ results[0] = data->sens[nr - 1];
-+ *nrels_mag = 1;
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ if (*nrels_mag >= 1) {
-+ switch (results[0]) {
-+ case 1: /* PII/Celeron diode */
-+ tmp = w83627hf_read_value(client,
-+ W83781D_REG_SCFG1);
-+ w83627hf_write_value(client,
-+ W83781D_REG_SCFG1,
-+ tmp | BIT_SCFG1[nr -
-+ 1]);
-+ tmp = w83627hf_read_value(client,
-+ W83781D_REG_SCFG2);
-+ w83627hf_write_value(client,
-+ W83781D_REG_SCFG2,
-+ tmp | BIT_SCFG2[nr -
-+ 1]);
-+ data->sens[nr - 1] = results[0];
-+ break;
-+ case 2: /* 3904 */
-+ tmp = w83627hf_read_value(client,
-+ W83781D_REG_SCFG1);
-+ w83627hf_write_value(client,
-+ W83781D_REG_SCFG1,
-+ tmp | BIT_SCFG1[nr -
-+ 1]);
-+ tmp = w83627hf_read_value(client,
-+ W83781D_REG_SCFG2);
-+ w83627hf_write_value(client,
-+ W83781D_REG_SCFG2,
-+ tmp & ~BIT_SCFG2[nr -
-+ 1]);
-+ data->sens[nr - 1] = results[0];
-+ break;
-+ case W83781D_DEFAULT_BETA: /* thermistor */
-+ tmp = w83627hf_read_value(client,
-+ W83781D_REG_SCFG1);
-+ w83627hf_write_value(client,
-+ W83781D_REG_SCFG1,
-+ tmp & ~BIT_SCFG1[nr -
-+ 1]);
-+ data->sens[nr - 1] = results[0];
-+ break;
-+ default:
-+ printk
-+ (KERN_ERR "w83627hf.o: Invalid sensor type %ld; must be 1, 2, or %d\n",
-+ results[0], W83781D_DEFAULT_BETA);
-+ break;
-+ }
-+ }
-+ }
-+}
-+
-+static int __init sm_w83627hf_init(void)
-+{
-+ int addr;
-+
-+ printk(KERN_INFO "w83627hf.o version %s (%s)\n", LM_VERSION, LM_DATE);
-+ if (w83627hf_find(&addr)) {
-+ printk("w83627hf.o: W83627/697 not detected, module not inserted.\n");
-+ return -ENODEV;
-+ }
-+ normal_isa[0] = addr;
-+
-+ return i2c_add_driver(&w83627hf_driver);
-+}
-+
-+static void __exit sm_w83627hf_exit(void)
-+{
-+ i2c_del_driver(&w83627hf_driver);
-+}
-+
-+
-+
-+MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl>, "
-+ "Philip Edelbrock <phil@netroedge.com>, "
-+ "and Mark Studebaker <mdsxyz123@yahoo.com>");
-+MODULE_DESCRIPTION("W83627HF driver");
-+MODULE_LICENSE("GPL");
-+
-+module_init(sm_w83627hf_init);
-+module_exit(sm_w83627hf_exit);
---- linux-old/drivers/sensors/w83781d.c Thu Jan 1 00:00:00 1970
-+++ linux/drivers/sensors/w83781d.c Mon Dec 13 20:18:54 2004
-@@ -0,0 +1,1957 @@
-+/*
-+ w83781d.c - Part of lm_sensors, Linux kernel modules for hardware
-+ monitoring
-+ Copyright (c) 1998 - 2003 Frodo Looijaard <frodol@dds.nl>,
-+ Philip Edelbrock <phil@netroedge.com>,
-+ and Mark Studebaker <mdsxyz123@yahoo.com>
-+
-+ 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., 675 Mass Ave, Cambridge, MA 02139, USA.
-+*/
-+
-+/*
-+ Supports following chips:
-+
-+ Chip #vin #fanin #pwm #temp wchipid vendid i2c ISA
-+ as99127f 7 3 0 3 0x31 0x12c3 yes no
-+ as99127f rev.2 (type name = as99127f) 0x31 0x5ca3 yes no
-+ w83627hf 9 3 2 3 0x21 0x5ca3 yes yes(LPC)
-+ w83697hf 8 2 2 2 0x60 0x5ca3 no yes(LPC)
-+ w83781d 7 3 0 3 0x10-1 0x5ca3 yes yes
-+ w83782d 9 3 2-4 3 0x30 0x5ca3 yes yes
-+ w83783s 5-6 3 2 1-2 0x40 0x5ca3 yes no
-+ w83791d 10 5 5 3 0x71 0x5ca3 yes no
-+
-+*/
-+
-+#include <linux/module.h>
-+#include <linux/slab.h>
-+#include <linux/ioport.h>
-+#include <linux/i2c.h>
-+#include <linux/i2c-proc.h>
-+#include <linux/init.h>
-+#include <asm/io.h>
-+#define LM_DATE "20041007"
-+#define LM_VERSION "2.8.8"
-+#include <linux/sensors_vid.h>
-+#include "lm75.h"
-+
-+/* RT Table support #defined so we can take it out if it gets bothersome */
-+#define W83781D_RT 1
-+
-+/* Addresses to scan */
-+static unsigned short normal_i2c[] = { SENSORS_I2C_END };
-+static unsigned short normal_i2c_range[] = { 0x20, 0x2f, SENSORS_I2C_END };
-+static unsigned int normal_isa[] = { 0x0290, SENSORS_ISA_END };
-+static unsigned int normal_isa_range[] = { SENSORS_ISA_END };
-+
-+/* Insmod parameters */
-+SENSORS_INSMOD_7(w83781d, w83782d, w83783s, w83627hf, as99127f, w83697hf, w83791d);
-+SENSORS_MODULE_PARM(force_subclients, "List of subclient addresses: " \
-+ "{bus, clientaddr, subclientaddr1, subclientaddr2}");
-+
-+static int init = 1;
-+MODULE_PARM(init, "i");
-+MODULE_PARM_DESC(init, "Set to zero to bypass chip initialization");
-+
-+/* Constants specified below */
-+
-+/* Length of ISA address segment */
-+#define W83781D_EXTENT 8
-+
-+/* Where are the ISA address/data registers relative to the base address */
-+#define W83781D_ADDR_REG_OFFSET 5
-+#define W83781D_DATA_REG_OFFSET 6
-+
-+/* The W83781D registers */
-+/* The W83782D registers for nr=7,8 are in bank 5 */
-+#define W83781D_REG_IN_MAX(nr) ((nr < 7) ? (0x2b + (nr) * 2) : \
-+ (0x554 + (((nr) - 7) * 2)))
-+#define W83781D_REG_IN_MIN(nr) ((nr < 7) ? (0x2c + (nr) * 2) : \
-+ (0x555 + (((nr) - 7) * 2)))
-+#define W83781D_REG_IN(nr) ((nr < 7) ? (0x20 + (nr)) : \
-+ (0x550 + (nr) - 7))
-+
-+#define W83791D_REG_IN_MAX(nr) ((nr < 7) ? (0x2b + (nr) * 2) : \
-+ (0xb4 + (((nr) - 7) * 2)))
-+#define W83791D_REG_IN_MIN(nr) ((nr < 7) ? (0x2c + (nr) * 2) : \
-+ (0xb5 + (((nr) - 7) * 2)))
-+#define W83791D_REG_IN(nr) ((nr < 7) ? (0x20 + (nr)) : \
-+ (0xb0 + (nr) - 7))
-+
-+#define W83781D_REG_FAN_MIN(nr) ((nr < 4) ? (0x3a + (nr)) : \
-+ (0xba + (nr) - 4))
-+#define W83781D_REG_FAN(nr) ((nr < 4) ? (0x27 + (nr)) : \
-+ (0xbc + (nr) - 4))
-+
-+#define W83781D_REG_TEMP2 0x0150
-+#define W83781D_REG_TEMP3 0x0250
-+#define W83781D_REG_TEMP2_HYST 0x153
-+#define W83781D_REG_TEMP3_HYST 0x253
-+#define W83781D_REG_TEMP2_CONFIG 0x152
-+#define W83781D_REG_TEMP3_CONFIG 0x252
-+#define W83781D_REG_TEMP2_OVER 0x155
-+#define W83781D_REG_TEMP3_OVER 0x255
-+
-+#define W83781D_REG_TEMP 0x27
-+#define W83781D_REG_TEMP_OVER 0x39
-+#define W83781D_REG_TEMP_HYST 0x3A
-+#define W83781D_REG_BANK 0x4E
-+
-+#define W83781D_REG_CONFIG 0x40
-+#define W83781D_REG_ALARM1 0x41
-+#define W83781D_REG_ALARM2 0x42
-+#define W83781D_REG_ALARM3 0x450 /* not on W83781D */
-+
-+#define W83781D_REG_IRQ 0x4C
-+#define W83781D_REG_BEEP_CONFIG 0x4D
-+#define W83781D_REG_BEEP_INTS1 0x56
-+#define W83781D_REG_BEEP_INTS2 0x57
-+#define W83781D_REG_BEEP_INTS3 0x453 /* not on W83781D */
-+
-+#define W83781D_REG_VID_FANDIV 0x47
-+
-+#define W83781D_REG_CHIPID 0x49
-+#define W83781D_REG_WCHIPID 0x58
-+#define W83781D_REG_CHIPMAN 0x4F
-+#define W83781D_REG_PIN 0x4B
-+
-+/* 782D/783S only */
-+#define W83781D_REG_VBAT 0x5D
-+
-+/* PWM 782D (1-4) and 783S (1-2) only */
-+#define W83781D_REG_PWM1 0x5B /* 782d and 783s/627hf datasheets disagree */
-+ /* on which is which; */
-+#define W83781D_REG_PWM2 0x5A /* We follow the 782d convention here, */
-+ /* However 782d is probably wrong. */
-+#define W83781D_REG_PWM3 0x5E
-+#define W83781D_REG_PWM4 0x5F
-+#define W83781D_REG_PWMCLK12 0x5C
-+#define W83781D_REG_PWMCLK34 0x45C
-+
-+#define W83791D_REG_PWM1 0x81
-+#define W83791D_REG_PWM2 0x83
-+#define W83791D_REG_PWM3 0x94
-+
-+#define W83627HF_REG_PWM1 0x01
-+#define W83627HF_REG_PWM2 0x03
-+#define W83627HF_REG_PWMCLK1 0x00
-+#define W83627HF_REG_PWMCLK2 0x02
-+
-+static const u8 regpwm[] = { W83781D_REG_PWM1, W83781D_REG_PWM2,
-+ W83781D_REG_PWM3, W83781D_REG_PWM4
-+};
-+
-+static const u8 regpwm_w83791d[] = { W83791D_REG_PWM1, W83791D_REG_PWM2,
-+ W83791D_REG_PWM3
-+};
-+
-+#define W83781D_REG_PWM(type, nr) (((type) == w83791d) ? \
-+ regpwm_w83791d[(nr) - 1] : \
-+ ((type) == w83697hf) ? \
-+ (((nr) * 2) - 1) : \
-+ regpwm[(nr) - 1])
-+
-+#define W83781D_REG_I2C_ADDR 0x48
-+#define W83781D_REG_I2C_SUBADDR 0x4A
-+
-+/* The following are undocumented in the data sheets however we
-+ received the information in an email from Winbond tech support */
-+/* Sensor selection - not on 781d */
-+#define W83781D_REG_SCFG1 0x5D
-+static const u8 BIT_SCFG1[] = { 0x02, 0x04, 0x08 };
-+#define W83781D_REG_SCFG2 0x59
-+static const u8 BIT_SCFG2[] = { 0x10, 0x20, 0x40 };
-+#define W83781D_DEFAULT_BETA 3435
-+
-+/* RT Table registers */
-+#define W83781D_REG_RT_IDX 0x50
-+#define W83781D_REG_RT_VAL 0x51
-+
-+/* Conversions. Rounding and limit checking is only done on the TO_REG
-+ variants. Note that you should be a bit careful with which arguments
-+ these macros are called: arguments may be evaluated more than once.
-+ Fixing this is just not worth it. */
-+#define IN_TO_REG(val) (SENSORS_LIMIT((((val) * 10 + 8)/16),0,255))
-+#define IN_FROM_REG(val) (((val) * 16 + 5) / 10)
-+
-+static inline u8 FAN_TO_REG(long rpm, int div)
-+{
-+ if (rpm == 0)
-+ return 255;
-+ rpm = SENSORS_LIMIT(rpm, 1, 1000000);
-+ return SENSORS_LIMIT((1350000 + rpm * div / 2) / (rpm * div), 1,
-+ 254);
-+}
-+
-+#define FAN_FROM_REG(val,div) ((val)==0?-1:(val)==255?0:1350000/((val)*(div)))
-+
-+#define TEMP_TO_REG(val) (SENSORS_LIMIT(((val)<0?(((val)-5)/10):\
-+ ((val)+5)/10),0,255))
-+#define TEMP_FROM_REG(val) (((val)>0x80?(val)-0x100:(val))*10)
-+
-+#define AS99127_TEMP_ADD_TO_REG(val) (SENSORS_LIMIT((((((val) + 2)*4)/10) \
-+ << 7),0,0xffff))
-+#define AS99127_TEMP_ADD_FROM_REG(val) ((((val) >> 7) * 10) / 4)
-+
-+#define ALARMS_FROM_REG(val) (val)
-+#define PWM_FROM_REG(val) (val)
-+#define PWM_TO_REG(val) (SENSORS_LIMIT((val),0,255))
-+#define BEEPS_FROM_REG(val,type) ((type)==as99127f?(val)^0x7FFF:(val))
-+#define BEEPS_TO_REG(val,type) ((type)==as99127f?(~(val))&0x7FFF:(val)&0xffffff)
-+
-+#define BEEP_ENABLE_TO_REG(val) ((val)?1:0)
-+#define BEEP_ENABLE_FROM_REG(val) ((val)?1:0)
-+
-+#define DIV_FROM_REG(val) (1 << (val))
-+
-+static inline u8 DIV_TO_REG(long val, enum chips type)
-+{
-+ int i;
-+ val = SENSORS_LIMIT(val, 1,
-+ ((type == w83781d || type == as99127f) ? 8 : 128)) >> 1;
-+ for (i = 0; i < 6; i++) {
-+ if (val == 0)
-+ break;
-+ val >>= 1;
-+ }
-+ return ((u8) i);
-+}
-+
-+/* There are some complications in a module like this. First off, W83781D chips
-+ may be both present on the SMBus and the ISA bus, and we have to handle
-+ those cases separately at some places. Second, there might be several
-+ W83781D chips available (well, actually, that is probably never done; but
-+ it is a clean illustration of how to handle a case like that). Finally,
-+ a specific chip may be attached to *both* ISA and SMBus, and we would
-+ not like to detect it double. Fortunately, in the case of the W83781D at
-+ least, a register tells us what SMBus address we are on, so that helps
-+ a bit - except if there could be more than one SMBus. Groan. No solution
-+ for this yet. */
-+
-+/* This module may seem overly long and complicated. In fact, it is not so
-+ bad. Quite a lot of bookkeeping is done. A real driver can often cut
-+ some corners. */
-+
-+/* For each registered W83781D, we need to keep some data in memory. That
-+ data is pointed to by w83781d_list[NR]->data. The structure itself is
-+ dynamically allocated, at the same time when a new w83781d client is
-+ allocated. */
-+struct w83781d_data {
-+ struct i2c_client client;
-+ struct semaphore lock;
-+ int sysctl_id;
-+ enum chips type;
-+
-+ struct semaphore update_lock;
-+ char valid; /* !=0 if following fields are valid */
-+ unsigned long last_updated; /* In jiffies */
-+
-+ struct i2c_client *lm75; /* for secondary I2C addresses */
-+ /* pointer to array of 2 subclients */
-+
-+ u8 in[10]; /* Register value - 8 & 9 for 782D and 791D only 10 for 791D */
-+ u8 in_max[10]; /* Register value - 8 & 9 for 782D and 791D only 10 for 791D */
-+ u8 in_min[10]; /* Register value - 8 & 9 for 782D and 791D only 10 for 791D */
-+ u8 fan[5]; /* Register value - 4 & 5 for 791D only */
-+ u8 fan_min[5]; /* Register value - 4 & 5 for 791D only */
-+ u8 temp;
-+ u8 temp_over; /* Register value */
-+ u8 temp_hyst; /* Register value */
-+ u16 temp_add[2]; /* Register value */
-+ u16 temp_add_over[2]; /* Register value */
-+ u16 temp_add_hyst[2]; /* Register value */
-+ u8 fan_div[3]; /* Register encoding, shifted right */
-+ u8 vid; /* Register encoding, combined */
-+ u32 alarms; /* Register encoding, combined */
-+ u32 beeps; /* Register encoding, combined */
-+ u8 beep_enable; /* Boolean */
-+ u8 pwm[4]; /* Register value */
-+ u8 pwmenable[4]; /* bool */
-+ u16 sens[3]; /* 782D/783S only.
-+ 1 = pentium diode; 2 = 3904 diode;
-+ 3000-5000 = thermistor beta.
-+ Default = 3435.
-+ Other Betas unimplemented */
-+#ifdef W83781D_RT
-+ u8 rt[3][32]; /* Register value */
-+#endif
-+ u8 vrm;
-+};
-+
-+
-+static int w83781d_attach_adapter(struct i2c_adapter *adapter);
-+static int w83781d_detect(struct i2c_adapter *adapter, int address,
-+ unsigned short flags, int kind);
-+static int w83781d_detach_client(struct i2c_client *client);
-+
-+static int w83781d_read_value(struct i2c_client *client, u16 register);
-+static int w83781d_write_value(struct i2c_client *client, u16 register,
-+ u16 value);
-+static void w83781d_update_client(struct i2c_client *client);
-+static void w83781d_init_client(struct i2c_client *client);
-+
-+
-+static void w83781d_in(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void w83781d_fan(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void w83781d_temp(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void w83781d_temp_add(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void w83781d_vid(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void w83781d_vrm(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void w83781d_alarms(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void w83781d_beep(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void w83781d_fan_div(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void w83781d_pwm(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void w83781d_sens(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+#ifdef W83781D_RT
-+static void w83781d_rt(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+#endif
-+
-+static int w83781d_id = 0;
-+
-+static struct i2c_driver w83781d_driver = {
-+ .owner = THIS_MODULE,
-+ .name = "W83781D sensor driver",
-+ .id = I2C_DRIVERID_W83781D,
-+ .flags = I2C_DF_NOTIFY,
-+ .attach_adapter = w83781d_attach_adapter,
-+ .detach_client = w83781d_detach_client,
-+};
-+
-+/* The /proc/sys entries */
-+/* -- SENSORS SYSCTL START -- */
-+
-+#define W83781D_SYSCTL_IN0 1000 /* Volts * 100 */
-+#define W83781D_SYSCTL_IN1 1001
-+#define W83781D_SYSCTL_IN2 1002
-+#define W83781D_SYSCTL_IN3 1003
-+#define W83781D_SYSCTL_IN4 1004
-+#define W83781D_SYSCTL_IN5 1005
-+#define W83781D_SYSCTL_IN6 1006
-+#define W83781D_SYSCTL_IN7 1007
-+#define W83781D_SYSCTL_IN8 1008
-+#define W83781D_SYSCTL_IN9 1009
-+#define W83781D_SYSCTL_FAN1 1101 /* Rotations/min */
-+#define W83781D_SYSCTL_FAN2 1102
-+#define W83781D_SYSCTL_FAN3 1103
-+#define W83781D_SYSCTL_FAN4 1104
-+#define W83781D_SYSCTL_FAN5 1105
-+
-+#define W83781D_SYSCTL_TEMP1 1200 /* Degrees Celcius * 10 */
-+#define W83781D_SYSCTL_TEMP2 1201 /* Degrees Celcius * 10 */
-+#define W83781D_SYSCTL_TEMP3 1202 /* Degrees Celcius * 10 */
-+#define W83781D_SYSCTL_VID 1300 /* Volts * 1000 */
-+#define W83781D_SYSCTL_VRM 1301
-+#define W83781D_SYSCTL_PWM1 1401
-+#define W83781D_SYSCTL_PWM2 1402
-+#define W83781D_SYSCTL_PWM3 1403
-+#define W83781D_SYSCTL_PWM4 1404
-+#define W83781D_SYSCTL_SENS1 1501 /* 1, 2, or Beta (3000-5000) */
-+#define W83781D_SYSCTL_SENS2 1502
-+#define W83781D_SYSCTL_SENS3 1503
-+#define W83781D_SYSCTL_RT1 1601 /* 32-entry table */
-+#define W83781D_SYSCTL_RT2 1602 /* 32-entry table */
-+#define W83781D_SYSCTL_RT3 1603 /* 32-entry table */
-+#define W83781D_SYSCTL_FAN_DIV 2000 /* 1, 2, 4 or 8 */
-+#define W83781D_SYSCTL_ALARMS 2001 /* bitvector */
-+#define W83781D_SYSCTL_BEEP 2002 /* bitvector */
-+
-+#define W83781D_ALARM_IN0 0x0001
-+#define W83781D_ALARM_IN1 0x0002
-+#define W83781D_ALARM_IN2 0x0004
-+#define W83781D_ALARM_IN3 0x0008
-+#define W83781D_ALARM_IN4 0x0100
-+#define W83781D_ALARM_IN5 0x0200
-+#define W83781D_ALARM_IN6 0x0400
-+#define W83782D_ALARM_IN7 0x10000
-+#define W83782D_ALARM_IN8 0x20000
-+#define W83781D_ALARM_FAN1 0x0040
-+#define W83781D_ALARM_FAN2 0x0080
-+#define W83781D_ALARM_FAN3 0x0800
-+#define W83781D_ALARM_TEMP1 0x0010
-+#define W83781D_ALARM_TEMP23 0x0020 /* 781D only */
-+#define W83781D_ALARM_TEMP2 0x0020 /* 782D/783S */
-+#define W83781D_ALARM_TEMP3 0x2000 /* 782D only */
-+#define W83781D_ALARM_CHAS 0x1000
-+
-+/* -- SENSORS SYSCTL END -- */
-+
-+/* These files are created for each detected chip. This is just a template;
-+ though at first sight, you might think we could use a statically
-+ allocated list, we need some way to get back to the parent - which
-+ is done through one of the 'extra' fields which are initialized
-+ when a new copy is allocated. */
-+
-+/* just a guess - no datasheet */
-+static ctl_table as99127f_dir_table_template[] = {
-+ {W83781D_SYSCTL_IN0, "in0", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83781d_in},
-+ {W83781D_SYSCTL_IN1, "in1", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83781d_in},
-+ {W83781D_SYSCTL_IN2, "in2", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83781d_in},
-+ {W83781D_SYSCTL_IN3, "in3", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83781d_in},
-+ {W83781D_SYSCTL_IN4, "in4", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83781d_in},
-+ {W83781D_SYSCTL_IN5, "in5", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83781d_in},
-+ {W83781D_SYSCTL_IN6, "in6", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83781d_in},
-+ {W83781D_SYSCTL_FAN1, "fan1", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83781d_fan},
-+ {W83781D_SYSCTL_FAN2, "fan2", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83781d_fan},
-+ {W83781D_SYSCTL_FAN3, "fan3", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83781d_fan},
-+ {W83781D_SYSCTL_TEMP1, "temp1", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83781d_temp},
-+ {W83781D_SYSCTL_TEMP2, "temp2", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83781d_temp_add},
-+ {W83781D_SYSCTL_TEMP3, "temp3", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83781d_temp_add},
-+ {W83781D_SYSCTL_VID, "vid", NULL, 0, 0444, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83781d_vid},
-+ {W83781D_SYSCTL_VRM, "vrm", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83781d_vrm},
-+ {W83781D_SYSCTL_FAN_DIV, "fan_div", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83781d_fan_div},
-+ {W83781D_SYSCTL_ALARMS, "alarms", NULL, 0, 0444, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83781d_alarms},
-+ {W83781D_SYSCTL_BEEP, "beep", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83781d_beep},
-+ {0}
-+};
-+
-+static ctl_table w83781d_dir_table_template[] = {
-+ {W83781D_SYSCTL_IN0, "in0", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83781d_in},
-+ {W83781D_SYSCTL_IN1, "in1", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83781d_in},
-+ {W83781D_SYSCTL_IN2, "in2", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83781d_in},
-+ {W83781D_SYSCTL_IN3, "in3", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83781d_in},
-+ {W83781D_SYSCTL_IN4, "in4", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83781d_in},
-+ {W83781D_SYSCTL_IN5, "in5", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83781d_in},
-+ {W83781D_SYSCTL_IN6, "in6", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83781d_in},
-+ {W83781D_SYSCTL_FAN1, "fan1", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83781d_fan},
-+ {W83781D_SYSCTL_FAN2, "fan2", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83781d_fan},
-+ {W83781D_SYSCTL_FAN3, "fan3", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83781d_fan},
-+ {W83781D_SYSCTL_TEMP1, "temp1", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83781d_temp},
-+ {W83781D_SYSCTL_TEMP2, "temp2", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83781d_temp_add},
-+ {W83781D_SYSCTL_TEMP3, "temp3", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83781d_temp_add},
-+ {W83781D_SYSCTL_VID, "vid", NULL, 0, 0444, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83781d_vid},
-+ {W83781D_SYSCTL_VRM, "vrm", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83781d_vrm},
-+ {W83781D_SYSCTL_FAN_DIV, "fan_div", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83781d_fan_div},
-+ {W83781D_SYSCTL_ALARMS, "alarms", NULL, 0, 0444, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83781d_alarms},
-+ {W83781D_SYSCTL_BEEP, "beep", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83781d_beep},
-+#ifdef W83781D_RT
-+ {W83781D_SYSCTL_RT1, "rt1", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83781d_rt},
-+ {W83781D_SYSCTL_RT2, "rt2", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83781d_rt},
-+ {W83781D_SYSCTL_RT3, "rt3", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83781d_rt},
-+#endif
-+ {0}
-+};
-+
-+/* without pwm3-4 */
-+static ctl_table w83782d_isa_dir_table_template[] = {
-+ {W83781D_SYSCTL_IN0, "in0", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83781d_in},
-+ {W83781D_SYSCTL_IN1, "in1", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83781d_in},
-+ {W83781D_SYSCTL_IN2, "in2", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83781d_in},
-+ {W83781D_SYSCTL_IN3, "in3", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83781d_in},
-+ {W83781D_SYSCTL_IN4, "in4", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83781d_in},
-+ {W83781D_SYSCTL_IN5, "in5", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83781d_in},
-+ {W83781D_SYSCTL_IN6, "in6", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83781d_in},
-+ {W83781D_SYSCTL_IN7, "in7", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83781d_in},
-+ {W83781D_SYSCTL_IN8, "in8", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83781d_in},
-+ {W83781D_SYSCTL_FAN1, "fan1", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83781d_fan},
-+ {W83781D_SYSCTL_FAN2, "fan2", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83781d_fan},
-+ {W83781D_SYSCTL_FAN3, "fan3", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83781d_fan},
-+ {W83781D_SYSCTL_TEMP1, "temp1", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83781d_temp},
-+ {W83781D_SYSCTL_TEMP2, "temp2", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83781d_temp_add},
-+ {W83781D_SYSCTL_TEMP3, "temp3", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83781d_temp_add},
-+ {W83781D_SYSCTL_VID, "vid", NULL, 0, 0444, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83781d_vid},
-+ {W83781D_SYSCTL_VRM, "vrm", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83781d_vrm},
-+ {W83781D_SYSCTL_FAN_DIV, "fan_div", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83781d_fan_div},
-+ {W83781D_SYSCTL_ALARMS, "alarms", NULL, 0, 0444, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83781d_alarms},
-+ {W83781D_SYSCTL_BEEP, "beep", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83781d_beep},
-+ {W83781D_SYSCTL_PWM1, "pwm1", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83781d_pwm},
-+ {W83781D_SYSCTL_PWM2, "pwm2", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83781d_pwm},
-+ {W83781D_SYSCTL_SENS1, "sensor1", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83781d_sens},
-+ {W83781D_SYSCTL_SENS2, "sensor2", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83781d_sens},
-+ {W83781D_SYSCTL_SENS3, "sensor3", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83781d_sens},
-+ {0}
-+};
-+
-+/* with pwm3-4 */
-+static ctl_table w83782d_i2c_dir_table_template[] = {
-+ {W83781D_SYSCTL_IN0, "in0", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83781d_in},
-+ {W83781D_SYSCTL_IN1, "in1", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83781d_in},
-+ {W83781D_SYSCTL_IN2, "in2", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83781d_in},
-+ {W83781D_SYSCTL_IN3, "in3", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83781d_in},
-+ {W83781D_SYSCTL_IN4, "in4", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83781d_in},
-+ {W83781D_SYSCTL_IN5, "in5", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83781d_in},
-+ {W83781D_SYSCTL_IN6, "in6", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83781d_in},
-+ {W83781D_SYSCTL_IN7, "in7", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83781d_in},
-+ {W83781D_SYSCTL_IN8, "in8", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83781d_in},
-+ {W83781D_SYSCTL_FAN1, "fan1", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83781d_fan},
-+ {W83781D_SYSCTL_FAN2, "fan2", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83781d_fan},
-+ {W83781D_SYSCTL_FAN3, "fan3", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83781d_fan},
-+ {W83781D_SYSCTL_TEMP1, "temp1", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83781d_temp},
-+ {W83781D_SYSCTL_TEMP2, "temp2", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83781d_temp_add},
-+ {W83781D_SYSCTL_TEMP3, "temp3", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83781d_temp_add},
-+ {W83781D_SYSCTL_VID, "vid", NULL, 0, 0444, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83781d_vid},
-+ {W83781D_SYSCTL_VRM, "vrm", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83781d_vrm},
-+ {W83781D_SYSCTL_FAN_DIV, "fan_div", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83781d_fan_div},
-+ {W83781D_SYSCTL_ALARMS, "alarms", NULL, 0, 0444, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83781d_alarms},
-+ {W83781D_SYSCTL_BEEP, "beep", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83781d_beep},
-+ {W83781D_SYSCTL_PWM1, "pwm1", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83781d_pwm},
-+ {W83781D_SYSCTL_PWM2, "pwm2", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83781d_pwm},
-+ {W83781D_SYSCTL_PWM3, "pwm3", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83781d_pwm},
-+ {W83781D_SYSCTL_PWM4, "pwm4", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83781d_pwm},
-+ {W83781D_SYSCTL_SENS1, "sensor1", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83781d_sens},
-+ {W83781D_SYSCTL_SENS2, "sensor2", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83781d_sens},
-+ {W83781D_SYSCTL_SENS3, "sensor3", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83781d_sens},
-+ {0}
-+};
-+
-+/* w83791D has 10 voltages 5 fans and 3 temps. 2 of the temps are on other
-+ devices. */
-+static ctl_table w83791d_dir_table_template[] = {
-+ {W83781D_SYSCTL_IN0, "in0", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83781d_in},
-+ {W83781D_SYSCTL_IN1, "in1", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83781d_in},
-+ {W83781D_SYSCTL_IN2, "in2", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83781d_in},
-+ {W83781D_SYSCTL_IN3, "in3", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83781d_in},
-+ {W83781D_SYSCTL_IN4, "in4", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83781d_in},
-+ {W83781D_SYSCTL_IN5, "in5", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83781d_in},
-+ {W83781D_SYSCTL_IN6, "in6", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83781d_in},
-+ {W83781D_SYSCTL_IN7, "in7", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83781d_in},
-+ {W83781D_SYSCTL_IN8, "in8", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83781d_in},
-+ {W83781D_SYSCTL_IN9, "in9", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83781d_in},
-+ {W83781D_SYSCTL_FAN1, "fan1", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83781d_fan},
-+ {W83781D_SYSCTL_FAN2, "fan2", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83781d_fan},
-+ {W83781D_SYSCTL_FAN3, "fan3", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83781d_fan},
-+ {W83781D_SYSCTL_FAN4, "fan4", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83781d_fan},
-+ {W83781D_SYSCTL_FAN5, "fan5", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83781d_fan},
-+ {W83781D_SYSCTL_TEMP1, "temp1", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83781d_temp},
-+ {W83781D_SYSCTL_TEMP2, "temp2", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83781d_temp_add},
-+ {W83781D_SYSCTL_TEMP3, "temp3", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83781d_temp_add},
-+ {W83781D_SYSCTL_VID, "vid", NULL, 0, 0444, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83781d_vid},
-+ {W83781D_SYSCTL_FAN_DIV, "fan_div", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83781d_fan_div},
-+ {W83781D_SYSCTL_ALARMS, "alarms", NULL, 0, 0444, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83781d_alarms},
-+ {W83781D_SYSCTL_BEEP, "beep", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83781d_beep},
-+ {W83781D_SYSCTL_PWM1, "pwm1", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83781d_pwm},
-+ {W83781D_SYSCTL_PWM2, "pwm2", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83781d_pwm},
-+ {W83781D_SYSCTL_PWM3, "pwm3", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83781d_pwm},
-+ {W83781D_SYSCTL_PWM4, "pwm4", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83781d_pwm},
-+ {W83781D_SYSCTL_VRM, "vrm", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83781d_vrm},
-+ {0}
-+};
-+
-+static ctl_table w83783s_dir_table_template[] = {
-+ {W83781D_SYSCTL_IN0, "in0", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83781d_in},
-+ /* no in1 to maintain compatibility with 781d and 782d. */
-+ {W83781D_SYSCTL_IN2, "in2", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83781d_in},
-+ {W83781D_SYSCTL_IN3, "in3", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83781d_in},
-+ {W83781D_SYSCTL_IN4, "in4", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83781d_in},
-+ {W83781D_SYSCTL_IN5, "in5", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83781d_in},
-+ {W83781D_SYSCTL_IN6, "in6", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83781d_in},
-+ {W83781D_SYSCTL_FAN1, "fan1", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83781d_fan},
-+ {W83781D_SYSCTL_FAN2, "fan2", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83781d_fan},
-+ {W83781D_SYSCTL_FAN3, "fan3", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83781d_fan},
-+ {W83781D_SYSCTL_TEMP1, "temp1", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83781d_temp},
-+ {W83781D_SYSCTL_TEMP2, "temp2", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83781d_temp_add},
-+ {W83781D_SYSCTL_VID, "vid", NULL, 0, 0444, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83781d_vid},
-+ {W83781D_SYSCTL_VRM, "vrm", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83781d_vrm},
-+ {W83781D_SYSCTL_FAN_DIV, "fan_div", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83781d_fan_div},
-+ {W83781D_SYSCTL_ALARMS, "alarms", NULL, 0, 0444, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83781d_alarms},
-+ {W83781D_SYSCTL_BEEP, "beep", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83781d_beep},
-+ {W83781D_SYSCTL_PWM1, "pwm1", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83781d_pwm},
-+ {W83781D_SYSCTL_PWM2, "pwm2", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83781d_pwm},
-+ {W83781D_SYSCTL_SENS1, "sensor1", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83781d_sens},
-+ {W83781D_SYSCTL_SENS2, "sensor2", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83781d_sens},
-+ {0}
-+};
-+
-+/* similar to w83782d but no fan3, no vid */
-+static ctl_table w83697hf_dir_table_template[] = {
-+ {W83781D_SYSCTL_IN0, "in0", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83781d_in},
-+ /* no in1 to maintain compatibility with 781d and 782d. */
-+ {W83781D_SYSCTL_IN2, "in2", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83781d_in},
-+ {W83781D_SYSCTL_IN3, "in3", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83781d_in},
-+ {W83781D_SYSCTL_IN4, "in4", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83781d_in},
-+ {W83781D_SYSCTL_IN5, "in5", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83781d_in},
-+ {W83781D_SYSCTL_IN6, "in6", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83781d_in},
-+ {W83781D_SYSCTL_IN7, "in7", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83781d_in},
-+ {W83781D_SYSCTL_IN8, "in8", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83781d_in},
-+ {W83781D_SYSCTL_FAN1, "fan1", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83781d_fan},
-+ {W83781D_SYSCTL_FAN2, "fan2", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83781d_fan},
-+ {W83781D_SYSCTL_TEMP1, "temp1", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83781d_temp},
-+ {W83781D_SYSCTL_TEMP2, "temp2", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83781d_temp_add},
-+ {W83781D_SYSCTL_FAN_DIV, "fan_div", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83781d_fan_div},
-+ {W83781D_SYSCTL_ALARMS, "alarms", NULL, 0, 0444, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83781d_alarms},
-+ {W83781D_SYSCTL_BEEP, "beep", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83781d_beep},
-+ {W83781D_SYSCTL_PWM1, "pwm1", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83781d_pwm},
-+ {W83781D_SYSCTL_PWM2, "pwm2", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83781d_pwm},
-+ {W83781D_SYSCTL_SENS1, "sensor1", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83781d_sens},
-+ {W83781D_SYSCTL_SENS2, "sensor2", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &w83781d_sens},
-+ {0}
-+};
-+
-+
-+/* This function is called when:
-+ * w83781d_driver is inserted (when this module is loaded), for each
-+ available adapter
-+ * when a new adapter is inserted (and w83781d_driver is still present) */
-+static int w83781d_attach_adapter(struct i2c_adapter *adapter)
-+{
-+ return i2c_detect(adapter, &addr_data, w83781d_detect);
-+}
-+
-+static int w83781d_detect(struct i2c_adapter *adapter, int address,
-+ unsigned short flags, int kind)
-+{
-+ int i, val1 = 0, val2, id;
-+ struct i2c_client *new_client;
-+ struct w83781d_data *data;
-+ int err = 0;
-+ const char *type_name = "";
-+ const char *client_name = "";
-+ int is_isa = i2c_is_isa_adapter(adapter);
-+ enum vendor { winbond, asus } vendid;
-+
-+ if (!is_isa
-+ && !i2c_check_functionality(adapter,
-+ I2C_FUNC_SMBUS_BYTE_DATA)) goto
-+ ERROR0;
-+
-+ if (is_isa) {
-+ if (!request_region(address, W83781D_EXTENT, "w83781d"))
-+ goto ERROR0;
-+ release_region(address, W83781D_EXTENT);
-+ }
-+
-+ /* Probe whether there is anything available on this address. Already
-+ done for SMBus clients */
-+ if (kind < 0) {
-+ if (is_isa) {
-+
-+#define REALLY_SLOW_IO
-+ /* We need the timeouts for at least some LM78-like chips. But only
-+ if we read 'undefined' registers. */
-+ i = inb_p(address + 1);
-+ if (inb_p(address + 2) != i)
-+ goto ERROR0;
-+ if (inb_p(address + 3) != i)
-+ goto ERROR0;
-+ if (inb_p(address + 7) != i)
-+ goto ERROR0;
-+#undef REALLY_SLOW_IO
-+
-+ /* Let's just hope nothing breaks here */
-+ i = inb_p(address + 5) & 0x7f;
-+ outb_p(~i & 0x7f, address + 5);
-+ if ((inb_p(address + 5) & 0x7f) != (~i & 0x7f)) {
-+ outb_p(i, address + 5);
-+ return 0;
-+ }
-+ }
-+ }
-+
-+ /* OK. For now, we presume we have a valid client. We now create the
-+ client structure, even though we cannot fill it completely yet.
-+ But it allows us to access w83781d_{read,write}_value. */
-+
-+ if (!(data = kmalloc(sizeof(struct w83781d_data), GFP_KERNEL))) {
-+ err = -ENOMEM;
-+ goto ERROR0;
-+ }
-+
-+ new_client = &data->client;
-+ new_client->addr = address;
-+ init_MUTEX(&data->lock);
-+ new_client->data = data;
-+ new_client->adapter = adapter;
-+ new_client->driver = &w83781d_driver;
-+ new_client->flags = 0;
-+
-+ /* Now, we do the remaining detection. */
-+
-+ /* The w8378?d may be stuck in some other bank than bank 0. This may
-+ make reading other information impossible. Specify a force=... or
-+ force_*=... parameter, and the Winbond will be reset to the right
-+ bank. */
-+ if (kind < 0) {
-+ if (w83781d_read_value(new_client, W83781D_REG_CONFIG) &
-+ 0x80) {
-+ err = -ENODEV;
-+ goto ERROR1;
-+ }
-+ val1 = w83781d_read_value(new_client, W83781D_REG_BANK);
-+ val2 = w83781d_read_value(new_client, W83781D_REG_CHIPMAN);
-+ /* Check for Winbond or Asus ID if in bank 0 */
-+ if ((!(val1 & 0x07)) &&
-+ (((!(val1 & 0x80)) && (val2 != 0xa3) && (val2 != 0xc3))
-+ || ((val1 & 0x80) && (val2 != 0x5c) && (val2 != 0x12)))) {
-+ err = -ENODEV;
-+ goto ERROR1;
-+ }
-+ /* If Winbond SMBus, check address at 0x48.
-+ Asus doesn't support, except for the as99127f rev.2 */
-+ if ((!is_isa) && (((!(val1 & 0x80)) && (val2 == 0xa3)) ||
-+ ((val1 & 0x80) && (val2 == 0x5c)))) {
-+ if (w83781d_read_value
-+ (new_client, W83781D_REG_I2C_ADDR) != address) {
-+ err = -ENODEV;
-+ goto ERROR1;
-+ }
-+ }
-+ }
-+
-+ /* We have either had a force parameter, or we have already detected the
-+ Winbond. Put it now into bank 0 and Vendor ID High Byte */
-+ w83781d_write_value(new_client, W83781D_REG_BANK,
-+ (w83781d_read_value(new_client,
-+ W83781D_REG_BANK) & 0x78) |
-+ 0x80);
-+
-+ /* Determine the chip type. */
-+ if (kind <= 0) {
-+ /* get vendor ID */
-+ val2 = w83781d_read_value(new_client, W83781D_REG_CHIPMAN);
-+ if (val2 == 0x5c)
-+ vendid = winbond;
-+ else if (val2 == 0x12)
-+ vendid = asus;
-+ else {
-+ err = -ENODEV;
-+ goto ERROR1;
-+ }
-+ val1 =
-+ w83781d_read_value(new_client, W83781D_REG_WCHIPID);
-+ if ((val1 == 0x10 || val1 == 0x11) && vendid == winbond)
-+ kind = w83781d;
-+ else if (val1 == 0x30 && vendid == winbond)
-+ kind = w83782d;
-+ else if (val1 == 0x40 && vendid == winbond && !is_isa && address == 0x2d)
-+ kind = w83783s;
-+ else if (val1 == 0x21 && vendid == winbond)
-+ kind = w83627hf;
-+ else if (val1 == 0x71 && vendid == winbond && address >= 0x2c)
-+ kind = w83791d;
-+ else if (val1 == 0x31 && !is_isa && address >= 0x28)
-+ kind = as99127f;
-+ else if (val1 == 0x60 && vendid == winbond && is_isa)
-+ kind = w83697hf;
-+ else {
-+ if (kind == 0)
-+ printk
-+ (KERN_WARNING "w83781d.o: Ignoring 'force' parameter for unknown chip at"
-+ "adapter %d, address 0x%02x\n",
-+ i2c_adapter_id(adapter), address);
-+ err = -EINVAL;
-+ goto ERROR1;
-+ }
-+ }
-+
-+ if (kind == w83781d) {
-+ type_name = "w83781d";
-+ client_name = "W83781D chip";
-+ } else if (kind == w83782d) {
-+ type_name = "w83782d";
-+ client_name = "W83782D chip";
-+ } else if (kind == w83783s) {
-+ type_name = "w83783s";
-+ client_name = "W83783S chip";
-+ } else if (kind == w83627hf) {
-+ type_name = "w83627hf";
-+ client_name = "W83627HF chip";
-+ } else if (kind == as99127f) {
-+ type_name = "as99127f";
-+ client_name = "AS99127F chip";
-+ } else if (kind == w83697hf) {
-+ type_name = "w83697hf";
-+ client_name = "W83697HF chip";
-+ } else if (kind == w83791d) {
-+ type_name = "w83791d";
-+ client_name = "W83791D chip";
-+ } else {
-+#ifdef DEBUG
-+ printk(KERN_ERR "w83781d.o: Internal error: unknown kind (%d)?!?",
-+ kind);
-+#endif
-+ err = -ENODEV;
-+ goto ERROR1;
-+ }
-+
-+ /* Reserve the ISA region */
-+ if (is_isa)
-+ request_region(address, W83781D_EXTENT, type_name);
-+
-+ /* Fill in the remaining client fields and put it into the global list */
-+ strcpy(new_client->name, client_name);
-+ data->type = kind;
-+
-+ new_client->id = w83781d_id++;
-+ data->valid = 0;
-+ init_MUTEX(&data->update_lock);
-+
-+ /* Tell the I2C layer a new client has arrived */
-+ if ((err = i2c_attach_client(new_client)))
-+ goto ERROR3;
-+
-+ /* attach secondary i2c lm75-like clients */
-+ if (!is_isa) {
-+ if (!(data->lm75 = kmalloc(2 * sizeof(struct i2c_client),
-+ GFP_KERNEL))) {
-+ err = -ENOMEM;
-+ goto ERROR4;
-+ }
-+ id = i2c_adapter_id(adapter);
-+ if(force_subclients[0] == id && force_subclients[1] == address) {
-+ for(i = 2; i <= 3; i++) {
-+ if(force_subclients[i] < 0x48 ||
-+ force_subclients[i] > 0x4f) {
-+ printk(KERN_ERR "w83781d.o: Invalid subclient address %d; must be 0x48-0x4f\n",
-+ force_subclients[i]);
-+ err = -EINVAL;
-+ goto ERROR5;
-+ }
-+ }
-+ w83781d_write_value(new_client,
-+ W83781D_REG_I2C_SUBADDR,
-+ (force_subclients[2] & 0x07) |
-+ ((force_subclients[3] & 0x07) <<4));
-+ data->lm75[0].addr = force_subclients[2];
-+ } else {
-+ val1 = w83781d_read_value(new_client,
-+ W83781D_REG_I2C_SUBADDR);
-+ data->lm75[0].addr = 0x48 + (val1 & 0x07);
-+ }
-+ if (kind != w83783s) {
-+ if(force_subclients[0] == id &&
-+ force_subclients[1] == address) {
-+ data->lm75[1].addr = force_subclients[3];
-+ } else {
-+ data->lm75[1].addr = 0x48 + ((val1 >> 4) & 0x07);
-+ }
-+ if(data->lm75[0].addr == data->lm75[1].addr) {
-+ printk(KERN_ERR "w83781d.o: Duplicate addresses 0x%x for subclients.\n",
-+ data->lm75[0].addr);
-+ err = -EBUSY;
-+ goto ERROR5;
-+ }
-+ }
-+ if (kind == w83781d)
-+ client_name = "W83781D subclient";
-+ else if (kind == w83782d)
-+ client_name = "W83782D subclient";
-+ else if (kind == w83783s)
-+ client_name = "W83783S subclient";
-+ else if (kind == w83627hf)
-+ client_name = "W83627HF subclient";
-+ else if (kind == as99127f)
-+ client_name = "AS99127F subclient";
-+ else if (kind == w83791d)
-+ client_name = "W83791D subclient";
-+
-+
-+ for (i = 0; i <= 1; i++) {
-+ data->lm75[i].data = NULL; /* store all data in w83781d */
-+ data->lm75[i].adapter = adapter;
-+ data->lm75[i].driver = &w83781d_driver;
-+ data->lm75[i].flags = 0;
-+ strcpy(data->lm75[i].name, client_name);
-+ data->lm75[i].id = w83781d_id++;
-+ if ((err = i2c_attach_client(&(data->lm75[i])))) {
-+ printk(KERN_ERR "w83781d.o: Subclient %d registration at address 0x%x failed.\n",
-+ i, data->lm75[i].addr);
-+ if (i == 1)
-+ goto ERROR6;
-+ goto ERROR5;
-+ }
-+ if (kind == w83783s)
-+ break;
-+ }
-+ } else {
-+ data->lm75 = NULL;
-+ }
-+
-+ /* Register a new directory entry with module sensors */
-+ if ((i = i2c_register_entry(new_client,
-+ type_name,
-+ (kind == as99127f) ?
-+ as99127f_dir_table_template :
-+ (kind == w83781d) ?
-+ w83781d_dir_table_template :
-+ (kind == w83783s) ?
-+ w83783s_dir_table_template :
-+ (kind == w83697hf) ?
-+ w83697hf_dir_table_template :
-+ (kind == w83791d ) ?
-+ w83791d_dir_table_template :
-+ (is_isa || kind == w83627hf) ?
-+ w83782d_isa_dir_table_template :
-+ w83782d_i2c_dir_table_template)) < 0) {
-+ err = i;
-+ goto ERROR7;
-+ }
-+ data->sysctl_id = i;
-+
-+ /* Only PWM2 can be disabled */
-+ for(i = 0; i < 4; i++)
-+ data->pwmenable[i] = 1;
-+
-+ /* Initialize the chip */
-+ w83781d_init_client(new_client);
-+ return 0;
-+
-+/* OK, this is not exactly good programming practice, usually. But it is
-+ very code-efficient in this case. */
-+
-+ ERROR7:
-+ if (!is_isa)
-+ i2c_detach_client(&
-+ (((struct
-+ w83781d_data *) (new_client->data))->
-+ lm75[1]));
-+ ERROR6:
-+ if (!is_isa)
-+ i2c_detach_client(&
-+ (((struct
-+ w83781d_data *) (new_client->data))->
-+ lm75[0]));
-+ ERROR5:
-+ if (!is_isa)
-+ kfree(((struct w83781d_data *) (new_client->data))->lm75);
-+ ERROR4:
-+ i2c_detach_client(new_client);
-+ ERROR3:
-+ if (is_isa)
-+ release_region(address, W83781D_EXTENT);
-+ ERROR1:
-+ kfree(data);
-+ ERROR0:
-+ return err;
-+}
-+
-+static int w83781d_detach_client(struct i2c_client *client)
-+{
-+ int err;
-+ struct w83781d_data *data = client->data;
-+
-+ i2c_deregister_entry(data->sysctl_id);
-+
-+ if ((err = i2c_detach_client(client))) {
-+ printk
-+ (KERN_ERR "w83781d.o: Client deregistration failed, client not detached.\n");
-+ return err;
-+ }
-+
-+ if(i2c_is_isa_client(client)) {
-+ release_region(client->addr, W83781D_EXTENT);
-+ } else {
-+ i2c_detach_client(&(data->lm75[0]));
-+ if (data->type != w83783s)
-+ i2c_detach_client(&(data->lm75[1]));
-+ kfree(data->lm75);
-+ }
-+ kfree(data);
-+
-+ return 0;
-+}
-+
-+/* The SMBus locks itself, usually, but nothing may access the Winbond between
-+ bank switches. ISA access must always be locked explicitly!
-+ We ignore the W83781D BUSY flag at this moment - it could lead to deadlocks,
-+ would slow down the W83781D access and should not be necessary.
-+ There are some ugly typecasts here, but the good news is - they should
-+ nowhere else be necessary! */
-+static int w83781d_read_value(struct i2c_client *client, u16 reg)
-+{
-+ int res, word_sized, bank;
-+ struct i2c_client *cl;
-+
-+ down(&(((struct w83781d_data *) (client->data))->lock));
-+ if (i2c_is_isa_client(client)) {
-+ word_sized = (((reg & 0xff00) == 0x100)
-+ || ((reg & 0xff00) == 0x200))
-+ && (((reg & 0x00ff) == 0x50)
-+ || ((reg & 0x00ff) == 0x53)
-+ || ((reg & 0x00ff) == 0x55));
-+ if (reg & 0xff00) {
-+ outb_p(W83781D_REG_BANK,
-+ client->addr + W83781D_ADDR_REG_OFFSET);
-+ outb_p(reg >> 8,
-+ client->addr + W83781D_DATA_REG_OFFSET);
-+ }
-+ outb_p(reg & 0xff, client->addr + W83781D_ADDR_REG_OFFSET);
-+ res = inb_p(client->addr + W83781D_DATA_REG_OFFSET);
-+ if (word_sized) {
-+ outb_p((reg & 0xff) + 1,
-+ client->addr + W83781D_ADDR_REG_OFFSET);
-+ res =
-+ (res << 8) + inb_p(client->addr +
-+ W83781D_DATA_REG_OFFSET);
-+ }
-+ if (reg & 0xff00) {
-+ outb_p(W83781D_REG_BANK,
-+ client->addr + W83781D_ADDR_REG_OFFSET);
-+ outb_p(0, client->addr + W83781D_DATA_REG_OFFSET);
-+ }
-+ } else {
-+ bank = (reg >> 8) & 0x0f;
-+ if (bank > 2)
-+ /* switch banks */
-+ i2c_smbus_write_byte_data(client, W83781D_REG_BANK,
-+ bank);
-+ if (bank == 0 || bank > 2) {
-+ res = i2c_smbus_read_byte_data(client, reg & 0xff);
-+ } else {
-+ /* switch to subclient */
-+ cl =
-+ &(((struct w83781d_data *) (client->data))->
-+ lm75[bank - 1]);
-+ /* convert from ISA to LM75 I2C addresses */
-+ switch (reg & 0xff) {
-+ case 0x50: /* TEMP */
-+ res = swab16(i2c_smbus_read_word_data(cl, 0));
-+ break;
-+ case 0x52: /* CONFIG */
-+ res = i2c_smbus_read_byte_data(cl, 1);
-+ break;
-+ case 0x53: /* HYST */
-+ res = swab16(i2c_smbus_read_word_data(cl, 2));
-+ break;
-+ case 0x55: /* OVER */
-+ default:
-+ res = swab16(i2c_smbus_read_word_data(cl, 3));
-+ break;
-+ }
-+ }
-+ if (bank > 2)
-+ i2c_smbus_write_byte_data(client, W83781D_REG_BANK,
-+ 0);
-+ }
-+ up(&(((struct w83781d_data *) (client->data))->lock));
-+ return res;
-+}
-+
-+static int w83781d_write_value(struct i2c_client *client, u16 reg, u16 value)
-+{
-+ int word_sized, bank;
-+ struct i2c_client *cl;
-+
-+ down(&(((struct w83781d_data *) (client->data))->lock));
-+ if (i2c_is_isa_client(client)) {
-+ word_sized = (((reg & 0xff00) == 0x100)
-+ || ((reg & 0xff00) == 0x200))
-+ && (((reg & 0x00ff) == 0x53)
-+ || ((reg & 0x00ff) == 0x55));
-+ if (reg & 0xff00) {
-+ outb_p(W83781D_REG_BANK,
-+ client->addr + W83781D_ADDR_REG_OFFSET);
-+ outb_p(reg >> 8,
-+ client->addr + W83781D_DATA_REG_OFFSET);
-+ }
-+ outb_p(reg & 0xff, client->addr + W83781D_ADDR_REG_OFFSET);
-+ if (word_sized) {
-+ outb_p(value >> 8,
-+ client->addr + W83781D_DATA_REG_OFFSET);
-+ outb_p((reg & 0xff) + 1,
-+ client->addr + W83781D_ADDR_REG_OFFSET);
-+ }
-+ outb_p(value & 0xff,
-+ client->addr + W83781D_DATA_REG_OFFSET);
-+ if (reg & 0xff00) {
-+ outb_p(W83781D_REG_BANK,
-+ client->addr + W83781D_ADDR_REG_OFFSET);
-+ outb_p(0, client->addr + W83781D_DATA_REG_OFFSET);
-+ }
-+ } else {
-+ bank = (reg >> 8) & 0x0f;
-+ if (bank > 2)
-+ /* switch banks */
-+ i2c_smbus_write_byte_data(client, W83781D_REG_BANK,
-+ bank);
-+ if (bank == 0 || bank > 2) {
-+ i2c_smbus_write_byte_data(client, reg & 0xff,
-+ value & 0xff);
-+ } else {
-+ /* switch to subclient */
-+ cl = &(((struct w83781d_data *) (client->data))->
-+ lm75[bank - 1]);
-+ /* convert from ISA to LM75 I2C addresses */
-+ switch (reg & 0xff) {
-+ case 0x52: /* CONFIG */
-+ i2c_smbus_write_byte_data(cl, 1, value & 0xff);
-+ break;
-+ case 0x53: /* HYST */
-+ i2c_smbus_write_word_data(cl, 2, swab16(value));
-+ break;
-+ case 0x55: /* OVER */
-+ i2c_smbus_write_word_data(cl, 3, swab16(value));
-+ break;
-+ }
-+ }
-+ if (bank > 2)
-+ i2c_smbus_write_byte_data(client, W83781D_REG_BANK,
-+ 0);
-+ }
-+ up(&(((struct w83781d_data *) (client->data))->lock));
-+ return 0;
-+}
-+
-+/* Called when we have found a new W83781D. It should set limits, etc. */
-+static void w83781d_init_client(struct i2c_client *client)
-+{
-+ struct w83781d_data *data = client->data;
-+ int i, p;
-+ int type = data->type;
-+ u8 tmp;
-+
-+ if(init && type != as99127f) { /* this resets registers we don't have
-+ documentation for on the as99127f */
-+ /* save these registers */
-+ i = w83781d_read_value(client, W83781D_REG_BEEP_CONFIG);
-+ p = w83781d_read_value(client, W83781D_REG_PWMCLK12);
-+ /* Reset all except Watchdog values and last conversion values
-+ This sets fan-divs to 2, among others */
-+ w83781d_write_value(client, W83781D_REG_CONFIG, 0x80);
-+ /* Restore the registers and disable power-on abnormal beep.
-+ This saves FAN 1/2/3 input/output values set by BIOS. */
-+ w83781d_write_value(client, W83781D_REG_BEEP_CONFIG, i | 0x80);
-+ w83781d_write_value(client, W83781D_REG_PWMCLK12, p);
-+ /* Disable master beep-enable (reset turns it on).
-+ Individual beeps should be reset to off but for some reason
-+ disabling this bit helps some people not get beeped */
-+ w83781d_write_value(client, W83781D_REG_BEEP_INTS2, 0);
-+ }
-+
-+ data->vrm = (type == w83791d) ? 90 : 82;
-+
-+ if ((type != w83781d) && (type != as99127f)) {
-+ tmp = w83781d_read_value(client, W83781D_REG_SCFG1);
-+ for (i = 1; i <= 3; i++) {
-+ if (!(tmp & BIT_SCFG1[i - 1])) {
-+ data->sens[i - 1] = W83781D_DEFAULT_BETA;
-+ } else {
-+ if (w83781d_read_value
-+ (client,
-+ W83781D_REG_SCFG2) & BIT_SCFG2[i - 1])
-+ data->sens[i - 1] = 1;
-+ else
-+ data->sens[i - 1] = 2;
-+ }
-+ if ((type == w83783s || type == w83697hf) && (i == 2))
-+ break;
-+ }
-+ }
-+#ifdef W83781D_RT
-+/*
-+ Fill up the RT Tables.
-+ We assume that they are 32 bytes long, in order for temp 1-3.
-+ Data sheet documentation is sparse.
-+ We also assume that it is only for the 781D although I suspect
-+ that the others support it as well....
-+*/
-+
-+ if (init && type == w83781d) {
-+ u16 k = 0;
-+/*
-+ Auto-indexing doesn't seem to work...
-+ w83781d_write_value(client,W83781D_REG_RT_IDX,0);
-+*/
-+ for (i = 0; i < 3; i++) {
-+ int j;
-+ for (j = 0; j < 32; j++) {
-+ w83781d_write_value(client,
-+ W83781D_REG_RT_IDX,
-+ k++);
-+ data->rt[i][j] =
-+ w83781d_read_value(client,
-+ W83781D_REG_RT_VAL);
-+ }
-+ }
-+ }
-+#endif /* W83781D_RT */
-+
-+ if(init) {
-+ w83781d_write_value(client, W83781D_REG_TEMP2_CONFIG, 0x00);
-+ if (type != w83783s && type != w83697hf) {
-+ w83781d_write_value(client, W83781D_REG_TEMP3_CONFIG,
-+ 0x00);
-+ }
-+ if (type != w83781d) {
-+ /* enable comparator mode for temp2 and temp3 so
-+ alarm indication will work correctly */
-+ i = w83781d_read_value(client, W83781D_REG_IRQ);
-+ if (!(i & 0x40))
-+ w83781d_write_value(client, W83781D_REG_IRQ,
-+ i | 0x40);
-+ }
-+ }
-+
-+ /* Start monitoring */
-+ w83781d_write_value(client, W83781D_REG_CONFIG,
-+ (w83781d_read_value(client,
-+ W83781D_REG_CONFIG) & 0xf7)
-+ | 0x01);
-+}
-+
-+static void w83781d_update_client(struct i2c_client *client)
-+{
-+ struct w83781d_data *data = client->data;
-+ int i;
-+
-+ down(&data->update_lock);
-+
-+ if (time_after(jiffies - data->last_updated, HZ + HZ / 2) ||
-+ time_before(jiffies, data->last_updated) || !data->valid) {
-+ pr_debug(KERN_DEBUG "Starting device update\n");
-+
-+ for (i = 0; i <= 9; i++) {
-+ if ((data->type == w83783s || data->type == w83697hf)
-+ && (i == 1))
-+ continue; /* 783S has no in1 */
-+ if (data->type == w83791d) {
-+ data->in[i] =
-+ w83781d_read_value(client, W83791D_REG_IN(i));
-+ data->in_min[i] =
-+ w83781d_read_value(client,
-+ W83791D_REG_IN_MIN(i));
-+ data->in_max[i] =
-+ w83781d_read_value(client,
-+ W83791D_REG_IN_MAX(i));
-+ } else {
-+ data->in[i] =
-+ w83781d_read_value(client, W83781D_REG_IN(i));
-+ data->in_min[i] =
-+ w83781d_read_value(client,
-+ W83781D_REG_IN_MIN(i));
-+ data->in_max[i] =
-+ w83781d_read_value(client,
-+ W83781D_REG_IN_MAX(i));
-+ }
-+ if ((data->type != w83782d) && (data->type != w83697hf)
-+ && (data->type != w83627hf) && (i == 6)
-+ && (data->type != w83791d))
-+ break;
-+
-+ if (data->type != w83791d && i == 8)
-+ break;
-+ }
-+ for (i = 1; i <= 5; i++) {
-+ data->fan[i - 1] =
-+ w83781d_read_value(client, W83781D_REG_FAN(i));
-+ data->fan_min[i - 1] =
-+ w83781d_read_value(client,
-+ W83781D_REG_FAN_MIN(i));
-+ if (data->type != w83791d && i == 3) break;
-+ }
-+ if (data->type != w83781d && data->type != as99127f) {
-+ for (i = 1; i <= 4; i++) {
-+ data->pwm[i - 1] =
-+ w83781d_read_value(client,
-+ W83781D_REG_PWM(data->type, i));
-+ if (((data->type == w83783s)
-+ || (data->type == w83627hf)
-+ || (data->type == w83697hf)
-+ || ((data->type == w83782d)
-+ && i2c_is_isa_client(client)))
-+ && i == 2)
-+ break;
-+ }
-+ /* Only PWM2 can be disabled */
-+ data->pwmenable[1] = (w83781d_read_value(client,
-+ W83781D_REG_PWMCLK12) & 0x08) >> 3;
-+ }
-+
-+ data->temp = w83781d_read_value(client, W83781D_REG_TEMP);
-+ data->temp_over =
-+ w83781d_read_value(client, W83781D_REG_TEMP_OVER);
-+ data->temp_hyst =
-+ w83781d_read_value(client, W83781D_REG_TEMP_HYST);
-+ data->temp_add[0] =
-+ w83781d_read_value(client, W83781D_REG_TEMP2);
-+ data->temp_add_over[0] =
-+ w83781d_read_value(client, W83781D_REG_TEMP2_OVER);
-+ data->temp_add_hyst[0] =
-+ w83781d_read_value(client, W83781D_REG_TEMP2_HYST);
-+ if (data->type != w83783s && data->type != w83697hf) {
-+ data->temp_add[1] =
-+ w83781d_read_value(client, W83781D_REG_TEMP3);
-+ data->temp_add_over[1] =
-+ w83781d_read_value(client, W83781D_REG_TEMP3_OVER);
-+ data->temp_add_hyst[1] =
-+ w83781d_read_value(client, W83781D_REG_TEMP3_HYST);
-+ }
-+ i = w83781d_read_value(client, W83781D_REG_VID_FANDIV);
-+ if (data->type != w83697hf) {
-+ data->vid = i & 0x0f;
-+ data->vid |=
-+ (w83781d_read_value(client, W83781D_REG_CHIPID) & 0x01)
-+ << 4;
-+ }
-+ data->fan_div[0] = (i >> 4) & 0x03;
-+ data->fan_div[1] = (i >> 6) & 0x03;
-+ if (data->type != w83697hf) {
-+ data->fan_div[2] = (w83781d_read_value(client,
-+ W83781D_REG_PIN) >> 6) & 0x03;
-+ }
-+ if ((data->type != w83781d) && (data->type != as99127f)) {
-+ i = w83781d_read_value(client, W83781D_REG_VBAT);
-+ data->fan_div[0] |= (i >> 3) & 0x04;
-+ data->fan_div[1] |= (i >> 4) & 0x04;
-+ if (data->type != w83697hf)
-+ data->fan_div[2] |= (i >> 5) & 0x04;
-+ }
-+ data->alarms =
-+ w83781d_read_value(client,
-+ W83781D_REG_ALARM1) +
-+ (w83781d_read_value(client, W83781D_REG_ALARM2) << 8);
-+ if ((data->type == w83782d) || (data->type == w83627hf) ||
-+ (data->type == w83697hf)) {
-+ data->alarms |=
-+ w83781d_read_value(client,
-+ W83781D_REG_ALARM3) << 16;
-+ }
-+ i = w83781d_read_value(client, W83781D_REG_BEEP_INTS2);
-+ data->beep_enable = i >> 7;
-+ data->beeps = ((i & 0x7f) << 8) +
-+ w83781d_read_value(client, W83781D_REG_BEEP_INTS1);
-+ if ((data->type != w83781d) && (data->type != as99127f)
-+ && (data->type != w83791d)) {
-+ data->beeps |=
-+ w83781d_read_value(client,
-+ W83781D_REG_BEEP_INTS3) << 16;
-+ }
-+ data->last_updated = jiffies;
-+ data->valid = 1;
-+ }
-+
-+ up(&data->update_lock);
-+}
-+
-+
-+/* The next few functions are the call-back functions of the /proc/sys and
-+ sysctl files. Which function is used is defined in the ctl_table in
-+ the extra1 field.
-+ Each function must return the magnitude (power of 10 to divide the date
-+ with) if it is called with operation==SENSORS_PROC_REAL_INFO. It must
-+ put a maximum of *nrels elements in results reflecting the data of this
-+ file, and set *nrels to the number it actually put in it, if operation==
-+ SENSORS_PROC_REAL_READ. Finally, it must get upto *nrels elements from
-+ results and write them to the chip, if operations==SENSORS_PROC_REAL_WRITE.
-+ Note that on SENSORS_PROC_REAL_READ, I do not check whether results is
-+ large enough (by checking the incoming value of *nrels). This is not very
-+ good practice, but as long as you put less than about 5 values in results,
-+ you can assume it is large enough. */
-+static void w83781d_in(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct w83781d_data *data = client->data;
-+ int nr = ctl_name - W83781D_SYSCTL_IN0;
-+
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 2;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ w83781d_update_client(client);
-+ results[0] = IN_FROM_REG(data->in_min[nr]);
-+ results[1] = IN_FROM_REG(data->in_max[nr]);
-+ results[2] = IN_FROM_REG(data->in[nr]);
-+ *nrels_mag = 3;
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ if (*nrels_mag >= 1) {
-+ data->in_min[nr] = IN_TO_REG(results[0]);
-+ w83781d_write_value(client, W83781D_REG_IN_MIN(nr),
-+ data->in_min[nr]);
-+ }
-+ if (*nrels_mag >= 2) {
-+ data->in_max[nr] = IN_TO_REG(results[1]);
-+ w83781d_write_value(client, W83781D_REG_IN_MAX(nr),
-+ data->in_max[nr]);
-+ }
-+ }
-+}
-+
-+void w83781d_fan(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct w83781d_data *data = client->data;
-+ int nr = ctl_name - W83781D_SYSCTL_FAN1 + 1;
-+
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 0;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ w83781d_update_client(client);
-+ results[0] = FAN_FROM_REG(data->fan_min[nr - 1],
-+ DIV_FROM_REG(data->fan_div[nr - 1]));
-+ results[1] = FAN_FROM_REG(data->fan[nr - 1],
-+ DIV_FROM_REG(data->fan_div[nr - 1]));
-+ *nrels_mag = 2;
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ if (*nrels_mag >= 1) {
-+ data->fan_min[nr - 1] =
-+ FAN_TO_REG(results[0],
-+ DIV_FROM_REG(data->fan_div[nr-1]));
-+ w83781d_write_value(client,
-+ W83781D_REG_FAN_MIN(nr),
-+ data->fan_min[nr - 1]);
-+ }
-+ }
-+}
-+
-+void w83781d_temp(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct w83781d_data *data = client->data;
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 1;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ w83781d_update_client(client);
-+ results[0] = TEMP_FROM_REG(data->temp_over);
-+ results[1] = TEMP_FROM_REG(data->temp_hyst);
-+ results[2] = TEMP_FROM_REG(data->temp);
-+ *nrels_mag = 3;
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ if (*nrels_mag >= 1) {
-+ data->temp_over = TEMP_TO_REG(results[0]);
-+ w83781d_write_value(client, W83781D_REG_TEMP_OVER,
-+ data->temp_over);
-+ }
-+ if (*nrels_mag >= 2) {
-+ data->temp_hyst = TEMP_TO_REG(results[1]);
-+ w83781d_write_value(client, W83781D_REG_TEMP_HYST,
-+ data->temp_hyst);
-+ }
-+ }
-+}
-+
-+void w83781d_temp_add(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results)
-+{
-+ struct w83781d_data *data = client->data;
-+ int nr = ctl_name - W83781D_SYSCTL_TEMP2;
-+
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 1;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ w83781d_update_client(client);
-+ if (data->type == as99127f) {
-+ results[0] =
-+ AS99127_TEMP_ADD_FROM_REG(data->
-+ temp_add_over[nr]);
-+ results[1] =
-+ AS99127_TEMP_ADD_FROM_REG(data->
-+ temp_add_hyst[nr]);
-+ results[2] =
-+ AS99127_TEMP_ADD_FROM_REG(data->temp_add[nr]);
-+ } else {
-+ results[0] =
-+ LM75_TEMP_FROM_REG(data->temp_add_over[nr]);
-+ results[1] =
-+ LM75_TEMP_FROM_REG(data->temp_add_hyst[nr]);
-+ results[2] = LM75_TEMP_FROM_REG(data->temp_add[nr]);
-+ }
-+ *nrels_mag = 3;
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ if (*nrels_mag >= 1) {
-+ if (data->type == as99127f)
-+ data->temp_add_over[nr] =
-+ AS99127_TEMP_ADD_TO_REG(results[0]);
-+ else
-+ data->temp_add_over[nr] =
-+ LM75_TEMP_TO_REG(results[0]);
-+ w83781d_write_value(client,
-+ nr ? W83781D_REG_TEMP3_OVER :
-+ W83781D_REG_TEMP2_OVER,
-+ data->temp_add_over[nr]);
-+ }
-+ if (*nrels_mag >= 2) {
-+ if (data->type == as99127f)
-+ data->temp_add_hyst[nr] =
-+ AS99127_TEMP_ADD_TO_REG(results[1]);
-+ else
-+ data->temp_add_hyst[nr] =
-+ LM75_TEMP_TO_REG(results[1]);
-+ w83781d_write_value(client,
-+ nr ? W83781D_REG_TEMP3_HYST :
-+ W83781D_REG_TEMP2_HYST,
-+ data->temp_add_hyst[nr]);
-+ }
-+ }
-+}
-+
-+
-+void w83781d_vid(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct w83781d_data *data = client->data;
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 3;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ w83781d_update_client(client);
-+ results[0] = vid_from_reg(data->vid, data->vrm);
-+ *nrels_mag = 1;
-+ }
-+}
-+
-+void w83781d_vrm(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct w83781d_data *data = client->data;
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 1;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ results[0] = data->vrm;
-+ *nrels_mag = 1;
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ if (*nrels_mag >= 1)
-+ data->vrm = results[0];
-+ }
-+}
-+
-+void w83781d_alarms(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct w83781d_data *data = client->data;
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 0;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ w83781d_update_client(client);
-+ results[0] = ALARMS_FROM_REG(data->alarms);
-+ *nrels_mag = 1;
-+ }
-+}
-+
-+void w83781d_beep(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct w83781d_data *data = client->data;
-+ int val;
-+
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 0;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ w83781d_update_client(client);
-+ results[0] = BEEP_ENABLE_FROM_REG(data->beep_enable);
-+ results[1] = BEEPS_FROM_REG(data->beeps, data->type);
-+ *nrels_mag = 2;
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ if (*nrels_mag >= 2) {
-+ data->beeps = BEEPS_TO_REG(results[1], data->type);
-+ w83781d_write_value(client, W83781D_REG_BEEP_INTS1,
-+ data->beeps & 0xff);
-+ if ((data->type != w83781d) &&
-+ (data->type != as99127f)) {
-+ w83781d_write_value(client,
-+ W83781D_REG_BEEP_INTS3,
-+ ((data-> beeps) >> 16) &
-+ 0xff);
-+ }
-+ val = (data->beeps >> 8) & 0x7f;
-+ } else if (*nrels_mag >= 1)
-+ val =
-+ w83781d_read_value(client,
-+ W83781D_REG_BEEP_INTS2) &
-+ 0x7f;
-+ if (*nrels_mag >= 1) {
-+ data->beep_enable = BEEP_ENABLE_TO_REG(results[0]);
-+ w83781d_write_value(client, W83781D_REG_BEEP_INTS2,
-+ val | data->beep_enable << 7);
-+ }
-+ }
-+}
-+
-+/* w83697hf only has two fans */
-+void w83781d_fan_div(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results)
-+{
-+ struct w83781d_data *data = client->data;
-+ int old, old2, old3 = 0;
-+
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 0;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ w83781d_update_client(client);
-+ results[0] = DIV_FROM_REG(data->fan_div[0]);
-+ results[1] = DIV_FROM_REG(data->fan_div[1]);
-+ if (data->type == w83697hf) {
-+ *nrels_mag = 2;
-+ } else {
-+ results[2] = DIV_FROM_REG(data->fan_div[2]);
-+ *nrels_mag = 3;
-+ }
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ old = w83781d_read_value(client, W83781D_REG_VID_FANDIV);
-+ /* w83781d and as99127f don't have extended divisor bits */
-+ if ((data->type != w83781d) && data->type != as99127f) {
-+ old3 =
-+ w83781d_read_value(client, W83781D_REG_VBAT);
-+ }
-+ if (*nrels_mag >= 3 && data->type != w83697hf) {
-+ data->fan_div[2] =
-+ DIV_TO_REG(results[2], data->type);
-+ old2 = w83781d_read_value(client, W83781D_REG_PIN);
-+ old2 =
-+ (old2 & 0x3f) | ((data->fan_div[2] & 0x03) << 6);
-+ w83781d_write_value(client, W83781D_REG_PIN, old2);
-+ if ((data->type != w83781d) &&
-+ (data->type != as99127f)) {
-+ old3 =
-+ (old3 & 0x7f) |
-+ ((data->fan_div[2] & 0x04) << 5);
-+ }
-+ }
-+ if (*nrels_mag >= 2) {
-+ data->fan_div[1] =
-+ DIV_TO_REG(results[1], data->type);
-+ old =
-+ (old & 0x3f) | ((data->fan_div[1] & 0x03) << 6);
-+ if ((data->type != w83781d) &&
-+ (data->type != as99127f)) {
-+ old3 =
-+ (old3 & 0xbf) |
-+ ((data->fan_div[1] & 0x04) << 4);
-+ }
-+ }
-+ if (*nrels_mag >= 1) {
-+ data->fan_div[0] =
-+ DIV_TO_REG(results[0], data->type);
-+ old =
-+ (old & 0xcf) | ((data->fan_div[0] & 0x03) << 4);
-+ w83781d_write_value(client, W83781D_REG_VID_FANDIV,
-+ old);
-+ if ((data->type != w83781d) &&
-+ (data->type != as99127f)) {
-+ old3 =
-+ (old3 & 0xdf) |
-+ ((data->fan_div[0] & 0x04) << 3);
-+ w83781d_write_value(client,
-+ W83781D_REG_VBAT,
-+ old3);
-+ }
-+ }
-+ }
-+}
-+
-+void w83781d_pwm(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct w83781d_data *data = client->data;
-+ int nr = 1 + ctl_name - W83781D_SYSCTL_PWM1;
-+ int j, k;
-+
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 0;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ w83781d_update_client(client);
-+ results[0] = PWM_FROM_REG(data->pwm[nr - 1]);
-+ results[1] = data->pwmenable[nr - 1];
-+ *nrels_mag = 2;
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ if (*nrels_mag >= 1) {
-+ data->pwm[nr - 1] = PWM_TO_REG(results[0]);
-+ w83781d_write_value(client,
-+ W83781D_REG_PWM(data->type, nr),
-+ data->pwm[nr - 1]);
-+ }
-+ /* only PWM2 can be enabled/disabled */
-+ if (*nrels_mag >= 2 && nr == 2) {
-+ j = w83781d_read_value(client, W83781D_REG_PWMCLK12);
-+ k = w83781d_read_value(client, W83781D_REG_BEEP_CONFIG);
-+ if(results[1]) {
-+ if(!(j & 0x08))
-+ w83781d_write_value(client,
-+ W83781D_REG_PWMCLK12, j | 0x08);
-+ if(k & 0x10)
-+ w83781d_write_value(client,
-+ W83781D_REG_BEEP_CONFIG, k & 0xef);
-+ data->pwmenable[1] = 1;
-+ } else {
-+ if(j & 0x08)
-+ w83781d_write_value(client,
-+ W83781D_REG_PWMCLK12, j & 0xf7);
-+ if(!(k & 0x10))
-+ w83781d_write_value(client,
-+ W83781D_REG_BEEP_CONFIG, j | 0x10);
-+ data->pwmenable[1] = 0;
-+ }
-+ }
-+ }
-+}
-+
-+void w83781d_sens(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct w83781d_data *data = client->data;
-+ int nr = 1 + ctl_name - W83781D_SYSCTL_SENS1;
-+ u8 tmp;
-+
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 0;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ results[0] = data->sens[nr - 1];
-+ *nrels_mag = 1;
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ if (*nrels_mag >= 1) {
-+ switch (results[0]) {
-+ case 1: /* PII/Celeron diode */
-+ tmp = w83781d_read_value(client,
-+ W83781D_REG_SCFG1);
-+ w83781d_write_value(client,
-+ W83781D_REG_SCFG1,
-+ tmp | BIT_SCFG1[nr -
-+ 1]);
-+ tmp = w83781d_read_value(client,
-+ W83781D_REG_SCFG2);
-+ w83781d_write_value(client,
-+ W83781D_REG_SCFG2,
-+ tmp | BIT_SCFG2[nr -
-+ 1]);
-+ data->sens[nr - 1] = results[0];
-+ break;
-+ case 2: /* 3904 */
-+ tmp = w83781d_read_value(client,
-+ W83781D_REG_SCFG1);
-+ w83781d_write_value(client,
-+ W83781D_REG_SCFG1,
-+ tmp | BIT_SCFG1[nr -
-+ 1]);
-+ tmp = w83781d_read_value(client,
-+ W83781D_REG_SCFG2);
-+ w83781d_write_value(client,
-+ W83781D_REG_SCFG2,
-+ tmp & ~BIT_SCFG2[nr -
-+ 1]);
-+ data->sens[nr - 1] = results[0];
-+ break;
-+ case W83781D_DEFAULT_BETA: /* thermistor */
-+ tmp = w83781d_read_value(client,
-+ W83781D_REG_SCFG1);
-+ w83781d_write_value(client,
-+ W83781D_REG_SCFG1,
-+ tmp & ~BIT_SCFG1[nr -
-+ 1]);
-+ data->sens[nr - 1] = results[0];
-+ break;
-+ default:
-+ printk
-+ (KERN_ERR "w83781d.o: Invalid sensor type %ld; must be 1, 2, or %d\n",
-+ results[0], W83781D_DEFAULT_BETA);
-+ break;
-+ }
-+ }
-+ }
-+}
-+
-+#ifdef W83781D_RT
-+static void w83781d_rt(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct w83781d_data *data = client->data;
-+ int nr = 1 + ctl_name - W83781D_SYSCTL_RT1;
-+ int i;
-+
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 0;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ for (i = 0; i < 32; i++) {
-+ results[i] = data->rt[nr - 1][i];
-+ }
-+ *nrels_mag = 32;
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ if (*nrels_mag > 32)
-+ *nrels_mag = 32;
-+ for (i = 0; i < *nrels_mag; i++) {
-+ /* fixme: no bounds checking 0-255 */
-+ data->rt[nr - 1][i] = results[i];
-+ w83781d_write_value(client, W83781D_REG_RT_IDX, i);
-+ w83781d_write_value(client, W83781D_REG_RT_VAL,
-+ data->rt[nr - 1][i]);
-+ }
-+ }
-+}
-+#endif
-+
-+static int __init sm_w83781d_init(void)
-+{
-+ printk(KERN_INFO "w83781d.o version %s (%s)\n", LM_VERSION, LM_DATE);
-+ return i2c_add_driver(&w83781d_driver);
-+}
-+
-+static void __exit sm_w83781d_exit(void)
-+{
-+ i2c_del_driver(&w83781d_driver);
-+}
-+
-+
-+
-+MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl>, "
-+ "Philip Edelbrock <phil@netroedge.com>, "
-+ "and Mark Studebaker <mdsxyz123@yahoo.com>");
-+MODULE_DESCRIPTION("W83781D driver");
-+MODULE_LICENSE("GPL");
-+
-+module_init(sm_w83781d_init);
-+module_exit(sm_w83781d_exit);
---- linux-old/drivers/sensors/w83l785ts.c Thu Jan 1 00:00:00 1970
-+++ linux/drivers/sensors/w83l785ts.c Mon Dec 13 20:18:54 2004
-@@ -0,0 +1,388 @@
-+/*
-+ * w83l785ts.c - Part of lm_sensors, Linux kernel modules for hardware
-+ * monitoring
-+ * Copyright (C) 2003-2004 Jean Delvare <khali@linux-fr.org>
-+ *
-+ * Inspired from the lm83 driver. The W83L785TS-S is a sensor chip made
-+ * by Winbond. It reports a single external temperature with a 1 deg
-+ * resolution and a 3 deg accuracy. Data sheet can be obtained from
-+ * Winbond's website at:
-+ * http://www.winbond-usa.com/products/winbond_products/pdfs/PCIC/W83L785TS-S.pdf
-+ *
-+ * Thanks to James Bolt <james@evilpenguin.com> for benchmarking the read
-+ * error handling mechanism.
-+ *
-+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
-+ */
-+
-+#include <linux/module.h>
-+#include <linux/slab.h>
-+#include <linux/i2c.h>
-+#include <linux/i2c-proc.h>
-+#include <linux/init.h>
-+#include <linux/delay.h>
-+#define LM_DATE "20041007"
-+#define LM_VERSION "2.8.8"
-+
-+#ifndef I2C_DRIVERID_W83L785TS
-+#define I2C_DRIVERID_W83L785TS 1047
-+#endif
-+
-+/* How many retries on register read error */
-+#define MAX_RETRIES 5
-+
-+/*
-+ * Address to scan
-+ * Address is fully defined internally and cannot be changed.
-+ */
-+
-+static unsigned short normal_i2c[] = { 0x2e, SENSORS_I2C_END };
-+static unsigned short normal_i2c_range[] = { SENSORS_I2C_END };
-+static unsigned int normal_isa[] = { SENSORS_ISA_END };
-+static unsigned int normal_isa_range[] = { SENSORS_ISA_END };
-+
-+/*
-+ * Insmod parameters
-+ */
-+
-+SENSORS_INSMOD_1(w83l785ts);
-+
-+/*
-+ * The W83L785TS-S registers
-+ * Manufacturer ID is 0x5CA3 for Winbond.
-+ */
-+
-+#define W83L785TS_REG_MAN_ID1 0x4D
-+#define W83L785TS_REG_MAN_ID2 0x4C
-+#define W83L785TS_REG_CHIP_ID 0x4E
-+#define W83L785TS_REG_CONFIG 0x40
-+#define W83L785TS_REG_TYPE 0x52
-+#define W83L785TS_REG_TEMP 0x27
-+#define W83L785TS_REG_TEMP_OVER 0x53 /* not sure about this one */
-+
-+/*
-+ * Conversions
-+ * The W83L785TS-S uses signed 8-bit values.
-+ */
-+
-+#define TEMP_FROM_REG(val) (val & 0x80 ? val-0x100 : val)
-+
-+/*
-+ * Functions declaration
-+ */
-+
-+static int w83l785ts_attach_adapter(struct i2c_adapter *adapter);
-+static int w83l785ts_detect(struct i2c_adapter *adapter, int address, unsigned
-+ short flags, int kind);
-+static int w83l785ts_detach_client(struct i2c_client *client);
-+static u8 w83l785ts_read_value(struct i2c_client *client, u8 reg, u8 defval);
-+static void w83l785ts_update_client(struct i2c_client *client);
-+static void w83l785ts_temp(struct i2c_client *client, int operation, int
-+ ctl_name, int *nrels_mag, long *results);
-+
-+/*
-+ * Driver data (common to all clients)
-+ */
-+
-+static struct i2c_driver w83l785ts_driver = {
-+ .owner = THIS_MODULE,
-+ .name = "W83L785S-S sensor driver",
-+ .id = I2C_DRIVERID_W83L785TS,
-+ .flags = I2C_DF_NOTIFY,
-+ .attach_adapter = w83l785ts_attach_adapter,
-+ .detach_client = w83l785ts_detach_client,
-+};
-+
-+/*
-+ * Client data (each client gets its own)
-+ */
-+
-+struct w83l785ts_data {
-+ struct i2c_client client;
-+ int sysctl_id;
-+
-+ struct semaphore update_lock;
-+ char valid; /* zero until following fields are valid */
-+ unsigned long last_updated; /* in jiffies */
-+
-+ /* registers values */
-+ u8 temp, temp_over;
-+};
-+
-+/*
-+ * Proc entries
-+ * These files are created for each detected W83L785TS-S.
-+ */
-+
-+/* -- SENSORS SYSCTL START -- */
-+
-+#define W83L785TS_SYSCTL_TEMP 1200
-+
-+/* -- SENSORS SYSCTL END -- */
-+
-+
-+static ctl_table w83l785ts_dir_table_template[] =
-+{
-+ {W83L785TS_SYSCTL_TEMP, "temp", NULL, 0, 0444, NULL,
-+ &i2c_proc_real, &i2c_sysctl_real, NULL, &w83l785ts_temp},
-+ {0}
-+};
-+
-+/*
-+ * Internal variables
-+ */
-+
-+static int w83l785ts_id = 0;
-+
-+/*
-+ * Real code
-+ */
-+
-+static int w83l785ts_attach_adapter(struct i2c_adapter *adapter)
-+{
-+ return i2c_detect(adapter, &addr_data, w83l785ts_detect);
-+}
-+
-+/*
-+ * The following function does more than just detection. If detection
-+ * succeeds, it also registers the new chip.
-+ */
-+static int w83l785ts_detect(struct i2c_adapter *adapter, int address,
-+ unsigned short flags, int kind)
-+{
-+ struct i2c_client *new_client;
-+ struct w83l785ts_data *data;
-+ int err = 0;
-+ const char *type_name = "";
-+ const char *client_name = "";
-+
-+ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
-+#ifdef DEBUG
-+ printk(KERN_DEBUG "w83l785ts.o: I2C bus doesn't support "
-+ "byte read mode, skipping.\n");
-+#endif
-+ return 0;
-+ }
-+
-+ if (!(data = kmalloc(sizeof(struct w83l785ts_data), GFP_KERNEL))) {
-+ printk(KERN_ERR "w83l785ts.o: Out of memory in w83l785ts_detect "
-+ "(new_client).\n");
-+ return -ENOMEM;
-+ }
-+
-+ /*
-+ * The common I2C client data is placed right after the
-+ * W83L785TS-specific. The W83L785TS-specific data is pointed to by the
-+ * data field from the I2C client data.
-+ */
-+
-+ new_client = &data->client;
-+ new_client->addr = address;
-+ new_client->data = data;
-+ new_client->adapter = adapter;
-+ new_client->driver = &w83l785ts_driver;
-+ new_client->flags = 0;
-+
-+ /*
-+ * Now we do the remaining detection. A negative kind means that
-+ * the driver was loaded with no force parameter (default), so we
-+ * must both detect and identify the chip (actually there is only
-+ * one possible kind of chip for now, W83L785TS-S). A zero kind means
-+ * that the driver was loaded with the force parameter, the detection
-+ * step shall be skipped. A positive kind means that the driver
-+ * was loaded with the force parameter and a given kind of chip is
-+ * requested, so both the detection and the identification steps
-+ * are skipped.
-+ */
-+
-+ if (kind < 0) { /* detection */
-+ if (((w83l785ts_read_value(new_client, W83L785TS_REG_CONFIG, 0)
-+ & 0x80) != 0x00)
-+ || ((w83l785ts_read_value(new_client, W83L785TS_REG_TYPE, 0)
-+ & 0xFC) != 0x00)) {
-+#ifdef DEBUG
-+ printk(KERN_DEBUG "w83l785ts.o: Detection failed at "
-+ "0x%02x.\n", address);
-+#endif
-+ goto ERROR1;
-+ }
-+ }
-+
-+ if (kind <= 0) { /* identification */
-+ u16 man_id;
-+ u8 chip_id;
-+
-+ man_id = (w83l785ts_read_value(new_client, W83L785TS_REG_MAN_ID1, 0) << 8)
-+ + w83l785ts_read_value(new_client, W83L785TS_REG_MAN_ID2, 0);
-+ chip_id = w83l785ts_read_value(new_client, W83L785TS_REG_CHIP_ID, 0);
-+ if (man_id == 0x5CA3) { /* Winbond */
-+ if (chip_id == 0x70)
-+ kind = w83l785ts;
-+ }
-+ }
-+
-+ if (kind <= 0) { /* identification failed */
-+ printk(KERN_INFO "w83l785ts.o: Unsupported chip.\n");
-+ goto ERROR1;
-+ }
-+
-+ if (kind == w83l785ts) {
-+ type_name = "w83l785ts";
-+ client_name = "W83L785TS-S chip";
-+ } else {
-+ printk(KERN_ERR "w83l785ts.o: Unknown kind %d.\n", kind);
-+ goto ERROR1;
-+ }
-+
-+ /*
-+ * OK, we got a valid chip so we can fill in the remaining client
-+ * fields.
-+ */
-+
-+ strcpy(new_client->name, client_name);
-+ new_client->id = w83l785ts_id++;
-+ data->valid = 0;
-+ init_MUTEX(&data->update_lock);
-+
-+ /*
-+ * Tell the I2C layer a new client has arrived.
-+ */
-+
-+ if ((err = i2c_attach_client(new_client))) {
-+#ifdef DEBUG
-+ printk(KERN_ERR "w83l785ts.o: Failed attaching client.\n");
-+#endif
-+ goto ERROR1;
-+ }
-+
-+ /*
-+ * Register a new directory entry.
-+ */
-+
-+ if ((err = i2c_register_entry(new_client, type_name,
-+ w83l785ts_dir_table_template)) < 0) {
-+#ifdef DEBUG
-+ printk(KERN_ERR "w83l785ts.o: Failed registering directory "
-+ "entry.\n");
-+#endif
-+ goto ERROR2;
-+ }
-+ data->sysctl_id = err;
-+
-+ /*
-+ * Initialize the W83L785TS chip
-+ * Nothing yet, assume it is already started.
-+ */
-+
-+ return 0;
-+
-+ ERROR2:
-+ i2c_detach_client(new_client);
-+ ERROR1:
-+ kfree(data);
-+ return err;
-+}
-+
-+static int w83l785ts_detach_client(struct i2c_client *client)
-+{
-+ int err;
-+
-+ i2c_deregister_entry(((struct w83l785ts_data *) (client->data))->sysctl_id);
-+ if ((err = i2c_detach_client(client))) {
-+ printk(KERN_ERR "w83l785ts.o: Client deregistration failed, "
-+ "client not detached.\n");
-+ return err;
-+ }
-+
-+ kfree(client->data);
-+ return 0;
-+}
-+
-+static u8 w83l785ts_read_value(struct i2c_client *client, u8 reg, u8 defval)
-+{
-+ int value, i;
-+
-+ /* Frequent read errors have been reported on Asus boards, so we
-+ * retry on read errors. If it still fails (unlikely), return the
-+ * default value requested by the caller. */
-+ for (i = 1; i <= MAX_RETRIES; i++) {
-+ value = i2c_smbus_read_byte_data(client, reg);
-+ if (value >= 0)
-+ return value;
-+ printk(KERN_WARNING "w83l785ts.o: Read failed, will retry "
-+ "in %d.\n", i);
-+ mdelay(i);
-+ }
-+
-+ printk(KERN_ERR "w83l785ts.o: Couldn't read value from register. "
-+ "Please report.\n");
-+ return defval;
-+}
-+
-+static void w83l785ts_update_client(struct i2c_client *client)
-+{
-+ struct w83l785ts_data *data = client->data;
-+
-+ down(&data->update_lock);
-+
-+ if ((jiffies - data->last_updated > HZ * 2)
-+ || (jiffies < data->last_updated)
-+ || !data->valid) {
-+#ifdef DEBUG
-+ printk(KERN_DEBUG "w83l785ts.o: Updating data.\n");
-+#endif
-+ data->temp = w83l785ts_read_value(client, W83L785TS_REG_TEMP,
-+ data->temp);
-+ data->temp_over = w83l785ts_read_value(client,
-+ W83L785TS_REG_TEMP_OVER, data->temp_over);
-+ data->last_updated = jiffies;
-+ data->valid = 1;
-+ }
-+
-+ up(&data->update_lock);
-+}
-+
-+static void w83l785ts_temp(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results)
-+{
-+ struct w83l785ts_data *data = client->data;
-+
-+ if (operation == SENSORS_PROC_REAL_INFO) {
-+ *nrels_mag = 0; /* magnitude */
-+ } else if (operation == SENSORS_PROC_REAL_READ) {
-+ w83l785ts_update_client(client);
-+ results[0] = TEMP_FROM_REG(data->temp_over);
-+ results[1] = TEMP_FROM_REG(data->temp);
-+ *nrels_mag = 2;
-+ }
-+}
-+
-+static int __init sm_w83l785ts_init(void)
-+{
-+ printk(KERN_INFO "w83l785ts.o version %s (%s)\n", LM_VERSION, LM_DATE);
-+ return i2c_add_driver(&w83l785ts_driver);
-+}
-+
-+static void __exit sm_w83l785ts_exit(void)
-+{
-+ i2c_del_driver(&w83l785ts_driver);
-+}
-+
-+MODULE_AUTHOR("Jean Delvare <khali@linux-fr.org>");
-+MODULE_DESCRIPTION("W83L785TS-S sensor driver");
-+MODULE_LICENSE("GPL");
-+
-+module_init(sm_w83l785ts_init);
-+module_exit(sm_w83l785ts_exit);
---- linux-old/drivers/sensors/xeontemp.c Thu Jan 1 00:00:00 1970
-+++ linux/drivers/sensors/xeontemp.c Mon Dec 13 20:18:54 2004
-@@ -0,0 +1,388 @@
-+/*
-+ xeontemp.c - Part of lm_sensors, Linux kernel modules for hardware
-+ monitoring
-+ Copyright (c) 1998, 1999,2003 Frodo Looijaard <frodol@dds.nl>,
-+ Philip Edelbrock <phil@netroedge.com>, and
-+ Mark D. Studebaker <mdsxyz123@yahoo.com>
-+
-+ 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., 675 Mass Ave, Cambridge, MA 02139, USA.
-+*/
-+
-+/* The Xeon temperature sensor looks just like an ADM1021 with the remote
-+ sensor only. There is are no ID registers so detection is difficult. */
-+
-+#include <linux/module.h>
-+#include <linux/slab.h>
-+#include <linux/i2c.h>
-+#include <linux/i2c-proc.h>
-+#include <linux/init.h>
-+#define LM_DATE "20041007"
-+#define LM_VERSION "2.8.8"
-+
-+#ifndef I2C_DRIVERID_XEONTEMP
-+#define I2C_DRIVERID_XEONTEMP 1045
-+#endif
-+
-+/* Addresses to scan */
-+static unsigned short normal_i2c[] = { 0x18, 0x1a, 0x29, 0x2b,
-+ 0x4c, 0x4e, SENSORS_I2C_END
-+};
-+static unsigned short normal_i2c_range[] = { SENSORS_I2C_END };
-+static unsigned int normal_isa[] = { SENSORS_ISA_END };
-+static unsigned int normal_isa_range[] = { SENSORS_ISA_END };
-+
-+/* Insmod parameters */
-+SENSORS_INSMOD_1(xeontemp);
-+
-+/* xeontemp constants specified below */
-+
-+/* The registers */
-+/* Read-only */
-+#define XEONTEMP_REG_REMOTE_TEMP 0x01
-+#define XEONTEMP_REG_STATUS 0x02
-+/* These use different addresses for reading/writing */
-+#define XEONTEMP_REG_CONFIG_R 0x03
-+#define XEONTEMP_REG_CONFIG_W 0x09
-+#define XEONTEMP_REG_CONV_RATE_R 0x04
-+#define XEONTEMP_REG_CONV_RATE_W 0x0A
-+/* limits */
-+#define XEONTEMP_REG_REMOTE_TOS_R 0x07
-+#define XEONTEMP_REG_REMOTE_TOS_W 0x0D
-+#define XEONTEMP_REG_REMOTE_THYST_R 0x08
-+#define XEONTEMP_REG_REMOTE_THYST_W 0x0E
-+/* write-only */
-+#define XEONTEMP_REG_ONESHOT 0x0F
-+
-+#define XEONTEMP_ALARM_RTEMP (XEONTEMP_ALARM_RTEMP_HIGH | XEONTEMP_ALARM_RTEMP_LOW\
-+ | XEONTEMP_ALARM_RTEMP_NA)
-+#define XEONTEMP_ALARM_ALL XEONTEMP_ALARM_RTEMP
-+
-+/* Conversions. Rounding and limit checking is only done on the TO_REG
-+ variants. Note that you should be a bit careful with which arguments
-+ these macros are called: arguments may be evaluated more than once.
-+ Fixing this is just not worth it. */
-+/* Conversions note: 1021 uses normal integer signed-byte format*/
-+#define TEMP_FROM_REG(val) (val > 127 ? val-256 : val)
-+#define TEMP_TO_REG(val) (SENSORS_LIMIT((val < 0 ? val+256 : val),0,255))
-+
-+/* Each client has this additional data */
-+struct xeontemp_data {
-+ struct i2c_client client;
-+ int sysctl_id;
-+ enum chips type;
-+
-+ struct semaphore update_lock;
-+ char valid; /* !=0 if following fields are valid */
-+ unsigned long last_updated; /* In jiffies */
-+
-+ u8 remote_temp, remote_temp_os, remote_temp_hyst, alarms;
-+ u8 fail;
-+};
-+
-+static int xeontemp_attach_adapter(struct i2c_adapter *adapter);
-+static int xeontemp_detect(struct i2c_adapter *adapter, int address,
-+ unsigned short flags, int kind);
-+static void xeontemp_init_client(struct i2c_client *client);
-+static int xeontemp_detach_client(struct i2c_client *client);
-+static int xeontemp_read_value(struct i2c_client *client, u8 reg);
-+static int xeontemp_rd_good(u8 *val, struct i2c_client *client, u8 reg, u8 mask);
-+static int xeontemp_write_value(struct i2c_client *client, u8 reg,
-+ u16 value);
-+static void xeontemp_remote_temp(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag,
-+ long *results);
-+static void xeontemp_alarms(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results);
-+static void xeontemp_update_client(struct i2c_client *client);
-+
-+/* (amalysh) read only mode, otherwise any limit's writing confuse BIOS */
-+static int read_only = 0;
-+
-+
-+/* This is the driver that will be inserted */
-+static struct i2c_driver xeontemp_driver = {
-+ .owner = THIS_MODULE,
-+ .name = "Xeon temp sensor driver",
-+ .id = I2C_DRIVERID_XEONTEMP,
-+ .flags = I2C_DF_NOTIFY,
-+ .attach_adapter = xeontemp_attach_adapter,
-+ .detach_client = xeontemp_detach_client,
-+};
-+
-+/* -- SENSORS SYSCTL START -- */
-+
-+#define XEONTEMP_SYSCTL_REMOTE_TEMP 1201
-+#define XEONTEMP_SYSCTL_ALARMS 1203
-+
-+#define XEONTEMP_ALARM_RTEMP_HIGH 0x10
-+#define XEONTEMP_ALARM_RTEMP_LOW 0x08
-+#define XEONTEMP_ALARM_RTEMP_NA 0x04
-+
-+/* -- SENSORS SYSCTL END -- */
-+
-+/* These files are created for each detected xeontemp. This is just a template;
-+ though at first sight, you might think we could use a statically
-+ allocated list, we need some way to get back to the parent - which
-+ is done through one of the 'extra' fields which are initialized
-+ when a new copy is allocated. */
-+static ctl_table xeontemp_dir_table_template[] = {
-+ {XEONTEMP_SYSCTL_REMOTE_TEMP, "temp", NULL, 0, 0644, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &xeontemp_remote_temp},
-+ {XEONTEMP_SYSCTL_ALARMS, "alarms", NULL, 0, 0444, NULL, &i2c_proc_real,
-+ &i2c_sysctl_real, NULL, &xeontemp_alarms},
-+ {0}
-+};
-+
-+static int xeontemp_id = 0;
-+
-+static int xeontemp_attach_adapter(struct i2c_adapter *adapter)
-+{
-+ return i2c_detect(adapter, &addr_data, xeontemp_detect);
-+}
-+
-+static int xeontemp_detect(struct i2c_adapter *adapter, int address,
-+ unsigned short flags, int kind)
-+{
-+ int i;
-+ struct i2c_client *new_client;
-+ struct xeontemp_data *data;
-+ int err = 0;
-+ const char *type_name = "";
-+ const char *client_name = "";
-+
-+ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
-+ goto error0;
-+
-+ /* OK. For now, we presume we have a valid client. We now create the
-+ client structure, even though we cannot fill it completely yet.
-+ But it allows us to access xeontemp_{read,write}_value. */
-+
-+ if (!(data = kmalloc(sizeof(struct xeontemp_data), GFP_KERNEL))) {
-+ err = -ENOMEM;
-+ goto error0;
-+ }
-+
-+ new_client = &data->client;
-+ new_client->addr = address;
-+ new_client->data = data;
-+ new_client->adapter = adapter;
-+ new_client->driver = &xeontemp_driver;
-+ new_client->flags = 0;
-+
-+ /* Now, we do the remaining detection. */
-+
-+ if (kind < 0) {
-+ if (
-+ (xeontemp_read_value(new_client, XEONTEMP_REG_STATUS) &
-+ 0x03) != 0x00)
-+ goto error1;
-+ }
-+
-+ /* Determine the chip type. */
-+
-+ if (kind <= 0) {
-+ kind = xeontemp;
-+ }
-+
-+ type_name = "xeontemp";
-+ client_name = "xeon sensors";
-+
-+ /* Fill in the remaining client fields and put it into the global list */
-+ strcpy(new_client->name, client_name);
-+ data->type = kind;
-+
-+ new_client->id = xeontemp_id++;
-+ data->valid = 0;
-+ init_MUTEX(&data->update_lock);
-+
-+ /* Tell the I2C layer a new client has arrived */
-+ if ((err = i2c_attach_client(new_client)))
-+ goto error3;
-+
-+ /* Register a new directory entry with module sensors */
-+ if ((i = i2c_register_entry(new_client, type_name,
-+ xeontemp_dir_table_template)) < 0) {
-+ err = i;
-+ goto error4;
-+ }
-+ data->sysctl_id = i;
-+
-+ xeontemp_init_client(new_client);
-+ return 0;
-+
-+ error4:
-+ i2c_detach_client(new_client);
-+ error3:
-+ error1:
-+ kfree(data);
-+ error0:
-+ return err;
-+}
-+
-+static void xeontemp_init_client(struct i2c_client *client)
-+{
-+ /* Enable ADC and disable suspend mode */
-+ xeontemp_write_value(client, XEONTEMP_REG_CONFIG_W, 0);
-+ /* Set Conversion rate to 1/sec (this can be tinkered with) */
-+ xeontemp_write_value(client, XEONTEMP_REG_CONV_RATE_W, 0x04);
-+}
-+
-+static int xeontemp_detach_client(struct i2c_client *client)
-+{
-+
-+ int err;
-+
-+ i2c_deregister_entry(((struct xeontemp_data *) (client->data))->
-+ sysctl_id);
-+
-+ if ((err = i2c_detach_client(client))) {
-+ printk
-+ ("xeontemp.o: Client deregistration failed, client not detached.\n");
-+ return err;
-+ }
-+
-+ kfree(client->data);
-+
-+ return 0;
-+
-+}
-+
-+
-+/* All registers are byte-sized */
-+static int xeontemp_read_value(struct i2c_client *client, u8 reg)
-+{
-+ return i2c_smbus_read_byte_data(client, reg);
-+}
-+
-+/* only update value if read succeeded; set fail bit if failed */
-+static int xeontemp_rd_good(u8 *val, struct i2c_client *client, u8 reg, u8 mask)
-+{
-+ int i;
-+ struct xeontemp_data *data = client->data;
-+
-+ i = i2c_smbus_read_byte_data(client, reg);
-+ if (i < 0) {
-+ data->fail |= mask;
-+ return i;
-+ }
-+ *val = i;
-+ return 0;
-+}
-+
-+static int xeontemp_write_value(struct i2c_client *client, u8 reg, u16 value)
-+{
-+ if (read_only > 0)
-+ return 0;
-+
-+ return i2c_smbus_write_byte_data(client, reg, value);
-+}
-+
-+static void xeontemp_update_client(struct i2c_client *client)
-+{
-+ struct xeontemp_data *data = client->data;
-+
-+ down(&data->update_lock);
-+
-+ if ((jiffies - data->last_updated > HZ + HZ / 2) ||
-+ (jiffies < data->last_updated) || !data->valid) {
-+
-+#ifdef DEBUG
-+ printk("Starting xeontemp update\n");
-+#endif
-+
-+ data->fail = 0;
-+ xeontemp_rd_good(&(data->remote_temp), client,
-+ XEONTEMP_REG_REMOTE_TEMP, XEONTEMP_ALARM_RTEMP);
-+ xeontemp_rd_good(&(data->remote_temp_os), client,
-+ XEONTEMP_REG_REMOTE_TOS_R, XEONTEMP_ALARM_RTEMP);
-+ xeontemp_rd_good(&(data->remote_temp_hyst), client,
-+ XEONTEMP_REG_REMOTE_THYST_R,
-+ XEONTEMP_ALARM_RTEMP);
-+ data->alarms = XEONTEMP_ALARM_ALL;
-+ if (!xeontemp_rd_good(&(data->alarms), client,
-+ XEONTEMP_REG_STATUS, 0))
-+ data->alarms &= XEONTEMP_ALARM_ALL;
-+ data->last_updated = jiffies;
-+ data->valid = 1;
-+ }
-+
-+ up(&data->update_lock);
-+}
-+
-+void xeontemp_remote_temp(struct i2c_client *client, int operation,
-+ int ctl_name, int *nrels_mag, long *results)
-+{
-+ struct xeontemp_data *data = client->data;
-+
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 0;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ xeontemp_update_client(client);
-+ results[0] = TEMP_FROM_REG(data->remote_temp_os);
-+ results[1] = TEMP_FROM_REG(data->remote_temp_hyst);
-+ results[2] = TEMP_FROM_REG(data->remote_temp);
-+ *nrels_mag = 3;
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ if (*nrels_mag >= 1) {
-+ data->remote_temp_os = TEMP_TO_REG(results[0]);
-+ xeontemp_write_value(client,
-+ XEONTEMP_REG_REMOTE_TOS_W,
-+ data->remote_temp_os);
-+ }
-+ if (*nrels_mag >= 2) {
-+ data->remote_temp_hyst = TEMP_TO_REG(results[1]);
-+ xeontemp_write_value(client,
-+ XEONTEMP_REG_REMOTE_THYST_W,
-+ data->remote_temp_hyst);
-+ }
-+ }
-+}
-+
-+void xeontemp_alarms(struct i2c_client *client, int operation, int ctl_name,
-+ int *nrels_mag, long *results)
-+{
-+ struct xeontemp_data *data = client->data;
-+ if (operation == SENSORS_PROC_REAL_INFO)
-+ *nrels_mag = 0;
-+ else if (operation == SENSORS_PROC_REAL_READ) {
-+ xeontemp_update_client(client);
-+ results[0] = data->alarms | data->fail;
-+ *nrels_mag = 1;
-+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
-+ /* Can't write to it */
-+ }
-+}
-+
-+static int __init sm_xeontemp_init(void)
-+{
-+ printk(KERN_INFO "xeontemp.o version %s (%s)\n", LM_VERSION, LM_DATE);
-+ return i2c_add_driver(&xeontemp_driver);
-+}
-+
-+static void __exit sm_xeontemp_exit(void)
-+{
-+ i2c_del_driver(&xeontemp_driver);
-+}
-+
-+MODULE_AUTHOR
-+ ("Frodo Looijaard <frodol@dds.nl> and Philip Edelbrock <phil@netroedge.com>");
-+MODULE_DESCRIPTION("xeontemp driver");
-+MODULE_LICENSE("GPL");
-+
-+MODULE_PARM(read_only, "i");
-+MODULE_PARM_DESC(read_only, "Don't set any values, read only mode");
-+
-+module_init(sm_xeontemp_init)
-+module_exit(sm_xeontemp_exit)
---- linux-old/include/linux/sensors_compat.h Thu Jan 1 00:00:00 1970
-+++ linux/include/linux/sensors_compat.h Mon Dec 13 20:18:54 2004
-@@ -0,0 +1,31 @@
-+/*
-+ * Stolen from kernel 2.5.69
-+ * device.h - generic, centralized driver model
-+ * To make it easier to backport from 2.5
-+ *
-+ * Copyright (c) 2001-2003 Patrick Mochel <mochel@osdl.org>
-+ *
-+ */
-+
-+#ifndef _SENSORS_COMPAT_H_
-+#define _SENSORS_COMPAT_H_
-+
-+/* debugging and troubleshooting/diagnostic helpers. */
-+#define dev_printk(level, dev, format, arg...) \
-+ printk(level "%s: " format , (dev)->name , ## arg)
-+
-+#ifdef DEBUG
-+#define dev_dbg(dev, format, arg...) \
-+ dev_printk(KERN_DEBUG , dev , format , ## arg)
-+#else
-+#define dev_dbg(dev, format, arg...) do {} while (0)
-+#endif
-+
-+#define dev_err(dev, format, arg...) \
-+ dev_printk(KERN_ERR , dev , format , ## arg)
-+#define dev_info(dev, format, arg...) \
-+ dev_printk(KERN_INFO , dev , format , ## arg)
-+#define dev_warn(dev, format, arg...) \
-+ dev_printk(KERN_WARNING , dev , format , ## arg)
-+
-+#endif /* _SENSORS_COMPAT_H_ */
---- linux-old/include/linux/sensors_vid.h Thu Jan 1 00:00:00 1970
-+++ linux/include/linux/sensors_vid.h Mon Dec 13 20:18:54 2004
-@@ -0,0 +1,95 @@
-+/*
-+ sensors_vid.h - Part of lm_sensors, Linux kernel modules for hardware
-+ monitoring
-+ Copyright (c) 2002-2004 Mark D. Studebaker <mdsxyz123@yahoo.com>
-+ With assistance from Trent Piepho <xyzzy@speakeasy.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., 675 Mass Ave, Cambridge, MA 02139, USA.
-+*/
-+
-+/*
-+ This file contains common code for decoding VID pins.
-+ This file is #included in various sensor chip drivers.
-+ As the user is unlikely to load more than one driver which
-+ includes this code we don't worry about the wasted space.
-+ References: VRM x.y DC-DC Converter Design Guidelines,
-+ VRD 10.0 Design Guide,
-+ available at http://developer.intel.com
-+*/
-+
-+/*
-+ AMD Opteron processors don't follow the Intel VRM spec.
-+ I'm going to "make up" 2.4 as the VRM spec for the Opterons.
-+ No good reason just a mnemonic for the 24x Opteron processor
-+ series
-+
-+ Opteron VID encoding is:
-+
-+ 00000 = 1.550 V
-+ 00001 = 1.525 V
-+ . . . .
-+ 11110 = 0.800 V
-+ 11111 = 0.000 V (off)
-+ */
-+
-+/*
-+ Legal val values 00 - 1F except for VRD 10.0, 0x00-0x3f.
-+ vrm is the Intel VRM document version.
-+ Note: vrm version is scaled by 10 and the return value is scaled by 1000
-+ to avoid floating point in the kernel.
-+*/
-+
-+#define DEFAULT_VRM 82
-+
-+static inline int vid_from_reg(int val, int vrm)
-+{
-+ int vid;
-+
-+ switch(vrm) {
-+
-+ case 100: /* VRD 10.0 */
-+ if((val & 0x1f) == 0x1f)
-+ return 0;
-+ if((val & 0x1f) <= 0x09 || val == 0x0a)
-+ vid = 10875 - (val & 0x1f) * 250;
-+ else
-+ vid = 18625 - (val & 0x1f) * 250;
-+ if(val & 0x20)
-+ vid -= 125;
-+ vid /= 10; /* only return 3 dec. places for now */
-+ return vid;
-+
-+ case 24: /* Opteron processor */
-+ return(val == 0x1f ? 0 : 1550 - val * 25);
-+
-+ case 91: /* VRM 9.1 */
-+ case 90: /* VRM 9.0 */
-+ return(val == 0x1f ? 0 :
-+ 1850 - val * 25);
-+
-+ case 85: /* VRM 8.5 */
-+ return((val & 0x10 ? 25 : 0) +
-+ ((val & 0x0f) > 0x04 ? 2050 : 1250) -
-+ ((val & 0x0f) * 50));
-+
-+ case 84: /* VRM 8.4 */
-+ val &= 0x0f;
-+ /* fall through */
-+ default: /* VRM 8.2 */
-+ return(val == 0x1f ? 0 :
-+ val & 0x10 ? 5100 - (val) * 100 :
-+ 2050 - (val) * 50);
-+ }
-+}
---- linux-old/drivers/sensors/Config.in Thu Jan 1 00:00:00 1970
-+++ linux/drivers/sensors/Config.in Mon Dec 13 20:18:54 2004
-@@ -0,0 +1,62 @@
-+#
-+# Sensor device configuration
-+# All depend on CONFIG_I2C_PROC.
-+# ISA-only devices depend on CONFIG_I2C_ISA also.
-+#
-+
-+if [ "$CONFIG_I2C" = "m" -o "$CONFIG_I2C" = "y" ] ; then
-+if [ "$CONFIG_I2C_PROC" = "m" -o "$CONFIG_I2C_PROC" = "y" ] ; then
-+ mainmenu_option next_comment
-+ comment 'Hardware sensors support'
-+
-+ dep_mbool 'Hardware sensors support' CONFIG_SENSORS $CONFIG_I2C $CONFIG_I2C_PROC
-+
-+ if [ "$CONFIG_SENSORS" != "n" ]; then
-+ dep_tristate ' Analog Devices ADM1021 and compatibles' CONFIG_SENSORS_ADM1021 $CONFIG_I2C $CONFIG_I2C_PROC
-+ dep_tristate ' Analog Devices ADM1024' CONFIG_SENSORS_ADM1024 $CONFIG_I2C $CONFIG_I2C_PROC
-+ dep_tristate ' Analog Devices ADM1025' CONFIG_SENSORS_ADM1025 $CONFIG_I2C $CONFIG_I2C_PROC
-+ dep_tristate ' Analog Devices ADM1026' CONFIG_SENSORS_ADM1026 $CONFIG_I2C $CONFIG_I2C_PROC
-+ dep_tristate ' Analog Devices ADM9240 and compatibles' CONFIG_SENSORS_ADM9240 $CONFIG_I2C $CONFIG_I2C_PROC
-+ dep_tristate ' Asus ASB100' CONFIG_SENSORS_ASB100 $CONFIG_I2C $CONFIG_I2C_PROC
-+ dep_tristate ' Dallas DS1621 and DS1625' CONFIG_SENSORS_DS1621 $CONFIG_I2C $CONFIG_I2C_PROC
-+ dep_tristate ' Fujitsu-Siemens Poseidon' CONFIG_SENSORS_FSCPOS $CONFIG_I2C $CONFIG_I2C_PROC
-+ dep_tristate ' Fujitsu-Siemens Scylla' CONFIG_SENSORS_FSCSCY $CONFIG_I2C $CONFIG_I2C_PROC
-+ dep_tristate ' Genesys Logic GL518SM' CONFIG_SENSORS_GL518SM $CONFIG_I2C $CONFIG_I2C_PROC
-+ dep_tristate ' Genesys Logic GL520SM' CONFIG_SENSORS_GL520SM $CONFIG_I2C $CONFIG_I2C_PROC
-+ dep_tristate ' HP Maxilife' CONFIG_SENSORS_MAXILIFE $CONFIG_I2C $CONFIG_I2C_PROC
-+ dep_tristate ' Intel Xeon Thermal Sensor' CONFIG_SENSORS_XEONTEMP $CONFIG_I2C $CONFIG_I2C_PROC
-+ dep_tristate ' ITE 8705/8712, SiS950' CONFIG_SENSORS_IT87 $CONFIG_I2C $CONFIG_I2C_PROC
-+ dep_tristate ' Maxim MAX6650, MAX6651' CONFIG_SENSORS_MAX6650 $CONFIG_I2C $CONFIG_I2C_PROC
-+ dep_tristate ' Myson MTP008' CONFIG_SENSORS_MTP008 $CONFIG_I2C $CONFIG_I2C_PROC
-+ dep_tristate ' National Semiconductor LM75 and compatibles' CONFIG_SENSORS_LM75 $CONFIG_I2C $CONFIG_I2C_PROC
-+ dep_tristate ' National Semiconductor LM78' CONFIG_SENSORS_LM78 $CONFIG_I2C $CONFIG_I2C_PROC
-+ dep_tristate ' National Semiconductor LM80' CONFIG_SENSORS_LM80 $CONFIG_I2C $CONFIG_I2C_PROC
-+ dep_tristate ' National Semiconductor LM83' CONFIG_SENSORS_LM83 $CONFIG_I2C $CONFIG_I2C_PROC
-+ dep_tristate ' National Semiconductor LM85, Analog Devices ADM1027' CONFIG_SENSORS_LM85 $CONFIG_I2C $CONFIG_I2C_PROC
-+ dep_tristate ' National Semiconductor LM87' CONFIG_SENSORS_LM87 $CONFIG_I2C $CONFIG_I2C_PROC
-+ dep_tristate ' National Semiconductor LM90 and compatibles' CONFIG_SENSORS_LM90 $CONFIG_I2C $CONFIG_I2C_PROC
-+ dep_tristate ' National Semiconductor LM92' CONFIG_SENSORS_LM92 $CONFIG_I2C $CONFIG_I2C_PROC
-+ dep_tristate ' National Semiconductor PC8736x Sensors' CONFIG_SENSORS_PC87360 $CONFIG_I2C $CONFIG_I2C_PROC
-+ dep_tristate ' Silicon Integrated Systems Corp. SiS5595' CONFIG_SENSORS_SIS5595 $CONFIG_I2C $CONFIG_I2C_PROC $CONFIG_I2C_ISA
-+ dep_tristate ' SMSC47M1xx Integrated Sensors' CONFIG_SENSORS_SMSC47M1 $CONFIG_I2C $CONFIG_I2C_PROC $CONFIG_I2C_ISA
-+ dep_tristate ' Texas Instruments THMC50 and compatibles' CONFIG_SENSORS_THMC50 $CONFIG_I2C $CONFIG_I2C_PROC
-+ dep_tristate ' VIA 686a Integrated Hardware Monitor' CONFIG_SENSORS_VIA686A $CONFIG_I2C $CONFIG_I2C_PROC $CONFIG_I2C_ISA
-+ dep_tristate ' VIA VT1211 Integrated Sensors' CONFIG_SENSORS_VT1211 $CONFIG_I2C $CONFIG_I2C_PROC $CONFIG_I2C_ISA
-+ dep_tristate ' VIA VT8231 Integrated Sensors' CONFIG_SENSORS_VT8231 $CONFIG_I2C $CONFIG_I2C_PROC $CONFIG_I2C_ISA
-+ dep_tristate ' Winbond W83781D, W83782D, W83783S, W83627HF, Asus AS99127F' CONFIG_SENSORS_W83781D $CONFIG_I2C $CONFIG_I2C_PROC
-+ dep_tristate ' Winbond W83627HF, W83627THF, W83697HF' CONFIG_SENSORS_W83627HF $CONFIG_I2C $CONFIG_I2C_PROC $CONFIG_I2C_ISA
-+ dep_tristate ' Winbond W83L785TS-S' CONFIG_SENSORS_W83L785TS $CONFIG_I2C $CONFIG_I2C_PROC
-+ bool 'Other I2C devices' CONFIG_SENSORS_OTHER
-+ if [ "$CONFIG_SENSORS_OTHER" = "y" ] ; then
-+ dep_tristate ' Brooktree BT869 Video Modulator' CONFIG_SENSORS_BT869 $CONFIG_I2C $CONFIG_I2C_PROC
-+ dep_tristate ' DDC Monitor EDID EEPROM' CONFIG_SENSORS_DDCMON $CONFIG_I2C $CONFIG_I2C_PROC
-+ dep_tristate ' EEprom (DIMM) reader ' CONFIG_SENSORS_EEPROM $CONFIG_I2C $CONFIG_I2C_PROC
-+ dep_tristate ' Matrix-Orbital LCD Displays' CONFIG_SENSORS_MATORB $CONFIG_I2C $CONFIG_I2C_PROC
-+ dep_tristate ' Philips PCF8574 Parallel I/O' CONFIG_SENSORS_PCF8574 $CONFIG_I2C $CONFIG_I2C_PROC
-+ dep_tristate ' Philips PCF8591 D/A and A/D' CONFIG_SENSORS_PCF8591 $CONFIG_I2C $CONFIG_I2C_PROC
-+ fi
-+ fi
-+ endmenu
-+fi
-+fi
-+
---- linux-old/Makefile Sat Aug 14 18:38:44 2004
-+++ linux/Makefile Mon Dec 13 20:18:54 2004
-@@ -195,6 +195,7 @@
- DRIVERS-$(CONFIG_ISDN_BOOL) += drivers/isdn/vmlinux-obj.o
- DRIVERS-$(CONFIG_CRYPTO) += crypto/crypto.o
-
-+DRIVERS-$(CONFIG_SENSORS) += drivers/sensors/sensor.o
- DRIVERS := $(DRIVERS-y)
-
-
---- linux-old/drivers/Makefile Mon Nov 17 01:07:35 2003
-+++ linux/drivers/Makefile Mon Dec 13 20:18:54 2004
-@@ -8,7 +8,7 @@
-
- mod-subdirs := dio hil mtd sbus video macintosh usb input telephony ide \
- message/i2o message/fusion scsi md ieee1394 pnp isdn atm \
-- fc4 net/hamradio i2c acpi bluetooth usb/gadget
-+ fc4 net/hamradio i2c acpi bluetooth usb/gadget sensors
-
- subdir-y := parport char block net sound misc media cdrom hotplug
- subdir-m := $(subdir-y)
-@@ -45,6 +45,7 @@
- # CONFIG_HAMRADIO can be set without CONFIG_NETDEVICE being set -- ch
- subdir-$(CONFIG_HAMRADIO) += net/hamradio
- subdir-$(CONFIG_I2C) += i2c
-+subdir-$(CONFIG_SENSORS) += sensors
- subdir-$(CONFIG_ACPI_BOOT) += acpi
-
- subdir-$(CONFIG_BLUEZ) += bluetooth
---- linux-old/drivers/sensors/Makefile Thu Jan 1 00:00:00 1970
-+++ linux/drivers/sensors/Makefile Mon Dec 13 20:18:54 2004
-@@ -0,0 +1,49 @@
-+#
-+# Makefile for the kernel hardware sensors drivers.
-+#
-+
-+MOD_LIST_NAME := SENSORS_MODULES
-+O_TARGET := sensor.o
-+
-+obj-$(CONFIG_SENSORS_ADM1021) += adm1021.o
-+obj-$(CONFIG_SENSORS_ADM1024) += adm1024.o
-+obj-$(CONFIG_SENSORS_ADM1025) += adm1025.o
-+obj-$(CONFIG_SENSORS_ADM1026) += adm1026.o
-+obj-$(CONFIG_SENSORS_ADM9240) += adm9240.o
-+obj-$(CONFIG_SENSORS_ASB100) += asb100.o
-+obj-$(CONFIG_SENSORS_BT869) += bt869.o
-+obj-$(CONFIG_SENSORS_DDCMON) += ddcmon.o
-+obj-$(CONFIG_SENSORS_DS1621) += ds1621.o
-+obj-$(CONFIG_SENSORS_EEPROM) += eeprom.o
-+obj-$(CONFIG_SENSORS_FSCPOS) += fscpos.o
-+obj-$(CONFIG_SENSORS_FSCSCY) += fscscy.o
-+obj-$(CONFIG_SENSORS_GL518SM) += gl518sm.o
-+obj-$(CONFIG_SENSORS_GL520SM) += gl520sm.o
-+obj-$(CONFIG_SENSORS_IT87) += it87.o
-+obj-$(CONFIG_SENSORS_LM75) += lm75.o
-+obj-$(CONFIG_SENSORS_LM78) += lm78.o
-+obj-$(CONFIG_SENSORS_LM80) += lm80.o
-+obj-$(CONFIG_SENSORS_LM83) += lm83.o
-+obj-$(CONFIG_SENSORS_LM85) += lm85.o
-+obj-$(CONFIG_SENSORS_LM87) += lm87.o
-+obj-$(CONFIG_SENSORS_LM90) += lm90.o
-+obj-$(CONFIG_SENSORS_LM92) += lm92.o
-+obj-$(CONFIG_SENSORS_MAX6650) += max6650.o
-+obj-$(CONFIG_SENSORS_MAXILIFE) += maxilife.o
-+obj-$(CONFIG_SENSORS_MTP008) += mtp008.o
-+obj-$(CONFIG_SENSORS_PC87360) += pc87360.o
-+obj-$(CONFIG_SENSORS_PCF8574) += pcf8574.o
-+obj-$(CONFIG_SENSORS_PCF8591) += pcf8591.o
-+obj-$(CONFIG_SENSORS_SIS5595) += sis5595.o
-+obj-$(CONFIG_SENSORS_SMSC47M1) += smsc47m1.o
-+obj-$(CONFIG_SENSORS_THMC50) += thmc50.o
-+obj-$(CONFIG_SENSORS_VIA686A) += via686a.o
-+obj-$(CONFIG_SENSORS_VT1211) += vt1211.o
-+obj-$(CONFIG_SENSORS_VT8231) += vt8231.o
-+obj-$(CONFIG_SENSORS_W83781D) += w83781d.o
-+obj-$(CONFIG_SENSORS_W83627HF) += w83627hf.o
-+obj-$(CONFIG_SENSORS_W83L785TS) += w83l785ts.o
-+obj-$(CONFIG_SENSORS_XEONTEMP) += xeontemp.o
-+
-+include $(TOPDIR)/Rules.make
-+
---- linux-old/drivers/char/Config.in Sat Aug 14 18:38:49 2004
-+++ linux/drivers/char/Config.in Mon Dec 13 20:18:54 2004
-@@ -191,6 +191,8 @@
-
- source drivers/i2c/Config.in
-
-+source drivers/sensors/Config.in
-+
- mainmenu_option next_comment
- comment 'Mice'
- tristate 'Bus Mouse Support' CONFIG_BUSMOUSE
---- linux-old/drivers/i2c/Config.in Wed Jul 7 00:38:02 2004
-+++ linux/drivers/i2c/Config.in Mon Dec 13 20:18:54 2004
-@@ -63,6 +63,30 @@
- fi
-
- # This is needed for automatic patch generation: sensors code starts here
-+ bool 'I2C mainboard interfaces' CONFIG_I2C_MAINBOARD
-+ if [ "$CONFIG_I2C_MAINBOARD" = "y" ]; then
-+ dep_tristate ' Acer Labs ALI 1535' CONFIG_I2C_ALI1535 $CONFIG_I2C
-+ dep_tristate ' Acer Labs ALI 1533 and 1543C' CONFIG_I2C_ALI15X3 $CONFIG_I2C
-+ dep_tristate ' Apple Hydra Mac I/O' CONFIG_I2C_HYDRA $CONFIG_I2C_ALGOBIT
-+ dep_tristate ' AMD 756/766/768/8111' CONFIG_I2C_AMD756 $CONFIG_I2C
-+ dep_tristate ' AMD 8111 SMBus 2.0' CONFIG_I2C_AMD8111 $CONFIG_I2C
-+ if [ "$CONFIG_ALPHA" = "y" ]; then
-+ dep_tristate ' DEC Tsunami I2C interface' CONFIG_I2C_TSUNAMI $CONFIG_I2C_ALGOBIT
-+ fi
-+ dep_tristate ' Intel 82801AA, AB, BA, DB' CONFIG_I2C_I801 $CONFIG_I2C
-+ dep_tristate ' Intel i810AA/AB/E and i815' CONFIG_I2C_I810 $CONFIG_I2C_ALGOBIT
-+ dep_tristate ' Intel 82371AB PIIX4(E), 443MX, ServerWorks OSB4/CSB5, SMSC Victory66' CONFIG_I2C_PIIX4 $CONFIG_I2C
-+ dep_tristate ' Nvidia Nforce2' CONFIG_I2C_NFORCE2 $CONFIG_I2C
-+ dep_tristate ' SiS 5595' CONFIG_I2C_SIS5595 $CONFIG_I2C
-+ dep_tristate ' SiS 630/730' CONFIG_I2C_SIS630 $CONFIG_I2C
-+ dep_tristate ' SiS 645/961,645DX/961,735' CONFIG_I2C_SIS645 $CONFIG_I2C $CONFIG_HOTPLUG
-+ dep_tristate ' Savage 4' CONFIG_I2C_SAVAGE4 $CONFIG_I2C_ALGOBIT
-+ dep_tristate ' VIA Technologies, Inc. VT82C586B' CONFIG_I2C_VIA $CONFIG_I2C_ALGOBIT
-+ dep_tristate ' VIA Technologies, Inc. VT596A/B, 686A/B, 8231, 8233, 8233A, 8235' CONFIG_I2C_VIAPRO $CONFIG_I2C
-+ dep_tristate ' Voodoo3 I2C interface' CONFIG_I2C_VOODOO3 $CONFIG_I2C_ALGOBIT
-+ dep_tristate ' Pseudo ISA adapter (for some hardware sensors)' CONFIG_I2C_ISA $CONFIG_I2C
-+ fi
-+
- # This is needed for automatic patch generation: sensors code ends here
-
- dep_tristate 'I2C device interface' CONFIG_I2C_CHARDEV $CONFIG_I2C
---- linux-old/drivers/i2c/Makefile Wed Jul 7 00:38:02 2004
-+++ linux/drivers/i2c/Makefile Mon Dec 13 20:18:54 2004
-@@ -28,6 +28,24 @@
- obj-$(CONFIG_I2C_ALGO_AU1550) += i2c-algo-au1550.o i2c-au1550.o
-
- # This is needed for automatic patch generation: sensors code starts here
-+obj-$(CONFIG_I2C_ALI1535) += i2c-ali1535.o
-+obj-$(CONFIG_I2C_ALI15X3) += i2c-ali15x3.o
-+obj-$(CONFIG_I2C_AMD756) += i2c-amd756.o
-+obj-$(CONFIG_I2C_AMD8111) += i2c-amd8111.o
-+obj-$(CONFIG_I2C_HYDRA) += i2c-hydra.o
-+obj-$(CONFIG_I2C_I801) += i2c-i801.o
-+obj-$(CONFIG_I2C_I810) += i2c-i810.o
-+obj-$(CONFIG_I2C_ISA) += i2c-isa.o
-+obj-$(CONFIG_I2C_NFORCE2) += i2c-nforce2.o
-+obj-$(CONFIG_I2C_PIIX4) += i2c-piix4.o
-+obj-$(CONFIG_I2C_SIS5595) += i2c-sis5595.o
-+obj-$(CONFIG_I2C_SIS630) += i2c-sis630.o
-+obj-$(CONFIG_I2C_SIS645) += i2c-sis645.o
-+obj-$(CONFIG_I2C_SAVAGE4) += i2c-savage4.o
-+obj-$(CONFIG_I2C_TSUNAMI) += i2c-tsunami.o
-+obj-$(CONFIG_I2C_VIA) += i2c-via.o
-+obj-$(CONFIG_I2C_VIAPRO) += i2c-viapro.o
-+obj-$(CONFIG_I2C_VOODOO3) += i2c-voodoo3.o
- # This is needed for automatic patch generation: sensors code ends here
-
- include $(TOPDIR)/Rules.make
---- linux-old/Documentation/Configure.help Mon Dec 13 20:09:52 2004
-+++ linux/Documentation/Configure.help Mon Dec 13 20:18:56 2004
-@@ -29449,4 +29449,527 @@
- # fill-prefix:" "
- # adaptive-fill:nil
- # fill-column:70
-+I2C mainboard interfaces
-+CONFIG_I2C_MAINBOARD
-+ Many modern mainboards have some kind of I2C interface integrated. This
-+ is often in the form of a SMBus, or System Management Bus, which is
-+ basically the same as I2C but which uses only a subset of the I2C
-+ protocol.
-+
-+ You will also want the latest user-space utilties: you can find them
-+ in the lm_sensors package, which you can download at
-+ http://www.lm-sensors.nu
-+
-+Acer Labs ALI 1535
-+CONFIG_I2C_ALI1535
-+ If you say yes to this option, support will be included for the Acer
-+ Labs ALI 1535 mainboard I2C interface. This can also be
-+ built as a module.
-+
-+Acer Labs ALI 1533 and 1543C
-+CONFIG_I2C_ALI15X3
-+ If you say yes to this option, support will be included for the Acer
-+ Labs ALI 1533 and 1543C mainboard I2C interfaces. This can also be
-+ built as a module which can be inserted and removed while the kernel
-+ is running.
-+
-+AMD 756/766/768/8111
-+CONFIG_I2C_AMD756
-+ If you say yes to this option, support will be included for the AMD
-+ 756/766/768/8111 mainboard I2C interfaces. This can also be
-+ built as a module which can be inserted and removed while the kernel
-+ is running.
-+
-+AMD 8111 SMBus 2.0
-+CONFIG_I2C_AMD8111
-+ If you say yes to this option, support will be included for the AMD
-+ 8111 mainboard SMBus 2.0 interface. This can also be
-+ built as a module which can be inserted and removed while the kernel
-+ is running.
-+
-+Apple Hydra Mac I/O
-+CONFIG_I2C_HYDRA
-+ If you say yes to this option, support will be included for the
-+ Hydra mainboard I2C interface. This can also be built as a module
-+ which can be inserted and removed while the kernel is running.
-+
-+Intel I801
-+CONFIG_I2C_I801
-+ If you say yes to this option, support will be included for the
-+ Intel I801 mainboard I2C interfaces. "I810" mainboard sensor chips are
-+ generally located on the I801's I2C bus. This can also be
-+ built as a module which can be inserted and removed while the kernel
-+ is running.
-+
-+Intel I810/I815 based Mainboard
-+CONFIG_I2C_I810
-+ If you say yes to this option, support will be included for the
-+ Intel I810/I815 mainboard I2C interfaces. The I2C busses these chips
-+ are generally used only for video devices. For "810" mainboard sensor
-+ chips, use the I801 I2C driver instead. This can also be
-+ built as a module which can be inserted and removed while the kernel
-+ is running.
-+
-+Intel 82371AB PIIX4(E) / ServerWorks OSB4 and CSB5
-+CONFIG_I2C_PIIX4
-+ If you say yes to this option, support will be included for the
-+ Intel PIIX4, PIIX4E, and 443MX, Serverworks OSB4/CSB5,
-+ and SMSC Victory66 mainboard
-+ I2C interfaces. This can also be
-+ built as a module which can be inserted and removed while the kernel
-+ is running.
-+
-+Nvidia Nforce2 based Mainboard
-+CONFIG_I2C_NFORCE2
-+ If you say yes to this option, support will be included for the
-+ Nvidia Nforce2 family of mainboard I2C interfaces. This can also be
-+ built as a module which can be inserted and removed while the kernel
-+ is running.
-+
-+Silicon Integrated Systems Corp. SiS5595 based Mainboard
-+CONFIG_I2C_SIS5595
-+ If you say yes to this option, support will be included for the
-+ SiS5595 mainboard I2C interfaces. For integrated sensors on the
-+ Sis5595, use CONFIG_SENSORS_SIS5595. This can also be
-+ built as a module which can be inserted and removed while the kernel
-+ is running.
-+
-+Silicon Integrated Systems Corp. SiS630/730 based Mainboard
-+CONFIG_I2C_SIS630
-+ If you say yes to this option, support will be included for the SiS 630
-+ and 730 mainboard I2C interfaces. This can also be built as a module
-+ which can be inserted and removed while the kernel is running.
-+
-+Silicon Integrated Systems Corp. SiS645/961,645DX/961,735 based Mainboard
-+CONFIG_I2C_SIS645
-+ If you say yes to this option, support will be included for the SiS 645/961,
-+ 645DX/961 and 735 mainboard I2C interfaces. This can also be built as a module
-+ which can be inserted and removed while the kernel is running.
-+
-+VIA Technologies, Inc. VT82C586B
-+CONFIG_I2C_VIA
-+ If you say yes to this option, support will be included for the VIA
-+ Technologies I2C adapter found on some motherboards. This can also
-+ be built as a module which can be inserted and removed while the
-+ kernel is running.
-+
-+VIA Technologies, Inc. VT82C596, 596B, 686A/B, 8233, 8235
-+CONFIG_I2C_VIAPRO
-+ If you say yes to this option, support will be included for the VIA
-+ Technologies I2C adapter on these chips. For integrated sensors on the
-+ Via 686A/B, use CONFIG_SENSORS_VIA686A. This can also be
-+ be built as a module which can be inserted and removed while the
-+ kernel is running.
-+
-+3DFX Banshee / Voodoo3
-+CONFIG_I2C_VOODOO3
-+ If you say yes to this option, support will be included for the
-+ 3DFX Banshee and Voodoo3 I2C interfaces. The I2C busses on the these
-+ chips are generally used only for video devices.
-+ This can also be
-+ built as a module which can be inserted and removed while the kernel
-+ is running.
-+
-+DEC Tsunami 21272
-+CONFIG_I2C_TSUNAMI
-+ If you say yes to this option, support will be included for the DEC
-+ Tsunami chipset I2C adapter. Requires the Alpha architecture;
-+ do not enable otherwise. This can also be built as a module which
-+ can be inserted and removed while the kernel is running.
-+
-+Pseudo ISA adapter (for hardware sensors modules)
-+CONFIG_I2C_ISA
-+ This provides support for accessing some hardware sensor chips over
-+ the ISA bus rather than the I2C or SMBus. If you want to do this,
-+ say yes here. This feature can also be built as a module which can
-+ be inserted and removed while the kernel is running.
-+
-+ You will also need the latest user-space utilties: you can find them
-+ in the lm_sensors package, which you can download at
-+ http://www.lm-sensors.nu
-+
-+Analog Devices ADM1021 and compatibles
-+CONFIG_SENSORS_ADM1021
-+ If you say yes here you get support for Analog Devices ADM1021
-+ and ADM1023 sensor chips and clones: Maxim MAX1617 and MAX1617A,
-+ Genesys Logic GL523SM, National Semi LM84, TI THMC10 and Onsemi
-+ MC1066. This can also be built as a module which can be inserted
-+ and removed while the kernel is running.
-+
-+ You will also need the latest user-space utilties: you can find them
-+ in the lm_sensors package, which you can download at
-+ http://www.lm-sensors.nu
-+
-+Analog Devices ADM1024
-+CONFIG_SENSORS_ADM1024
-+ If you say yes here you get support for Analog Devices ADM1024 sensor
-+ chips. This can also be built as a module.
-+
-+ You will also need the latest user-space utilties: you can find them
-+ in the lm_sensors package, which you can download at
-+ http://www.lm-sensors.nu
-+
-+Analog Devices ADM1025
-+CONFIG_SENSORS_ADM1025
-+ If you say yes here you get support for Analog Devices ADM1025 sensor
-+ chips. This can also be built as a module which can be inserted and
-+ removed while the kernel is running.
-+
-+ You will also need the latest user-space utilties: you can find them
-+ in the lm_sensors package, which you can download at
-+ http://www.lm-sensors.nu
-+
-+Analog Devices ADM1026
-+CONFIG_SENSORS_ADM1026
-+ If you say yes here you get support for Analog Devices ADM1026 sensor
-+ chips. This can also be built as a module which can be inserted and
-+ removed while the kernel is running.
-+
-+ You will also need the latest user-space utilties: you can find them
-+ in the lm_sensors package, which you can download at
-+ http://www.lm-sensors.nu
-+
-+Analog Devices ADM9240 and compatibles
-+CONFIG_SENSORS_ADM9240
-+ If you say yes here you get support for Analog Devices ADM9240
-+ sensor chips and clones: the Dallas Semiconductor DS1780 and
-+ the National Semiconductor LM81. This can also be built as a
-+ module which can be inserted and removed while the kernel is
-+ running.
-+
-+ You will also need the latest user-space utilties: you can find them
-+ in the lm_sensors package, which you can download at
-+ http://www.lm-sensors.nu
-+
-+Asus ASB100
-+CONFIG_SENSORS_ASB100
-+ If you say yes here you get support for the Asus ASB100 (aka
-+ "Bach") sensor chip. This can also be built as a module.
-+
-+ You will also need the latest user-space utilities: you can find
-+ them in the lm_sensors package, which you can download at
-+ http://www.lm-sensors.nu/
-+
-+Dallas DS1621 and DS1625
-+CONFIG_SENSORS_DS1621
-+ If you say yes here you get support for the Dallas DS1621 and DS1625x
-+ sensor chips. This can also be built as a module.
-+
-+ You will also need the latest user-space utilties: you can find them
-+ in the lm_sensors package, which you can download at
-+ http://www.lm-sensors.nu
-+
-+Fujitsu-Siemens Poseidon
-+CONFIG_SENSORS_FSCPOS
-+ If you say yes here you get support for the Fujitsu-Siemens Poseidon
-+ sensor chip. This can also be built as a module.
-+
-+ You will also need the latest user-space utilties: you can find them
-+ in the lm_sensors package, which you can download at
-+ http://www.lm-sensors.nu
-+
-+Fujitsu-Siemens Scylla
-+CONFIG_SENSORS_FSCSCY
-+ If you say yes here you get support for the Fujitsu-Siemens Scylla
-+ sensor chip. This can also be built as a module. This driver may/should
-+ also work with the following Fujitsu-Siemens chips: "Poseidon",
-+ "Poseidon II" and "Hydra". You may have to force loading of the module
-+ for motherboards in these cases. Be careful - those motherboards have
-+ not been tested with this driver.
-+
-+ You will also need the latest user-space utilties: you can find them
-+ in the lm_sensors package, which you can download at
-+ http://www.lm-sensors.nu
-+
-+Genesys Logic GL518SM
-+CONFIG_SENSORS_GL518SM
-+ If you say yes here you get support for Genesys Logic GL518SM sensor
-+ chips. This can also be built as a module which can be inserted and
-+ removed while the kernel is running.
-+
-+ You will also need the latest user-space utilties: you can find them
-+ in the lm_sensors package, which you can download at
-+ http://www.lm-sensors.nu
-+
-+Genesys Logic GL520SM
-+CONFIG_SENSORS_GL520SM
-+ If you say yes here you get support for Genesys Logic GL518SM sensor
-+ chips. This can also be built as a module which can be inserted and
-+ removed while the kernel is running.
-+
-+ You will also need the latest user-space utilties: you can find them
-+ in the lm_sensors package, which you can download at
-+ http://www.lm-sensors.nu
-+
-+HP Maxilife
-+CONFIG_SENSORS_MAXILIFE
-+ If you say yes here you get support for the HP Maxilife
-+ sensor chip. This can also be built as a module.
-+
-+ You will also need the latest user-space utilties: you can find them
-+ in the lm_sensors package, which you can download at
-+ http://www.lm-sensors.nu
-+
-+Intel Xeon Thermal Sensor
-+CONFIG_SENSORS_XEONTEMP
-+ If you say yes here you get support for the Intel Xeon processor
-+ built-in thermal sensor. This can also be built as a module which
-+ can be inserted and removed while the kernel is running.
-+
-+ You will also need the latest user-space utilities: you can find them
-+ in the lm_sensors package, which you can download at
-+ http://www.lm-sensors.nu/
-+
-+ITE 8705, 8712, Sis950
-+CONFIG_SENSORS_IT87
-+ If you say yes here you get support for the ITE 8705 and 8712 and
-+ SiS950 sensor chips. This can also be built as a module.
-+
-+ You will also need the latest user-space utilties: you can find them
-+ in the lm_sensors package, which you can download at
-+ http://www.lm-sensors.nu
-+
-+Maxim MAX6650, MAX6651
-+CONFIG_SENSORS_MAX6650
-+ If you say yes here you get support for the Maxim MAX6650 and
-+ MAX6651 sensor chips. This can also be built as a module.
-+
-+ You will also need the latest user-space utilties: you can find them
-+ in the lm_sensors package, which you can download at
-+ http://www.lm-sensors.nu
-+
-+Myson MTP008
-+CONFIG_SENSORS_MTP008
-+ If you say yes here you get support for the Myson MTP008
-+ sensor chip. This can also be built as a module.
-+
-+ You will also need the latest user-space utilties: you can find them
-+ in the lm_sensors package, which you can download at
-+ http://www.lm-sensors.nu
-+
-+National Semiconductor LM75 and compatibles
-+CONFIG_SENSORS_LM75
-+ If you say yes here you get support for National Semiconductor LM75
-+ sensor chips and clones: Dallas Semiconductor DS75 and DS1775 (in
-+ 9-bit precision mode), and TelCom (now Microchip) TCN75. This can
-+ also be built as a module which can be inserted and removed while
-+ the kernel is running.
-+
-+ You will also need the latest user-space utilties: you can find them
-+ in the lm_sensors package, which you can download at
-+ http://www.lm-sensors.nu
-+
-+National Semiconductor LM78
-+CONFIG_SENSORS_LM78
-+ If you say yes here you get support for National Semiconductor LM78
-+ sensor chips family: the LM78-J and LM79. Many clone chips will
-+ also work at least somewhat with this driver. This can also be built
-+ as a module which can be inserted and removed while the kernel is
-+ running.
-+
-+ You will also need the latest user-space utilties: you can find them
-+ in the lm_sensors package, which you can download at
-+ http://www.lm-sensors.nu
-+
-+National Semiconductor LM80
-+CONFIG_SENSORS_LM80
-+ If you say yes here you get support for National Semiconductor LM80
-+ sensor chips. This can also be built as a module which can be
-+ inserted and removed while the kernel is running.
-+
-+ You will also need the latest user-space utilties: you can find them
-+ in the lm_sensors package, which you can download at
-+ http://www.lm-sensors.nu
-+
-+National Semiconductor LM83
-+CONFIG_SENSORS_LM83
-+ If you say yes here you get support for the National Semiconductor
-+ LM83 sensor chip. This can also be built as a module.
-+
-+ You will also need the latest user-space utilities: you can find
-+ them in the lm_sensors package, which you can download at
-+ http://www.lm-sensors.nu/
-+
-+National Semiconductor LM85
-+CONFIG_SENSORS_LM85
-+ If you say yes here you get support for National Semiconductor LM85
-+ sensor chips and compatibles. Compatible chips include the Analog
-+ Devices ADM1027 and ADT7463 and SMSC EMC6D100 and EMC6D101. This
-+ can also be built as a module which can be inserted and removed
-+ while the kernel is running.
-+
-+ You will also need the latest user-space utilties: you can find them
-+ in the lm_sensors package, which you can download at
-+ http://www.lm-sensors.nu
-+
-+National Semiconductor LM87
-+CONFIG_SENSORS_LM87
-+ If you say yes here you get support for National Semiconductor LM87
-+ sensor chips. This can also be built as a module which can be
-+ inserted and removed while the kernel is running.
-+
-+ You will also need the latest user-space utilties: you can find them
-+ in the lm_sensors package, which you can download at
-+ http://www.lm-sensors.nu
-+
-+National Semiconductor LM90
-+CONFIG_SENSORS_LM90
-+ If you say yes here you get support for the National Semiconductor
-+ LM90, LM89 and LM99, and Analog Devices ADM1032 sensor chips. This
-+ can also be built as a module.
-+
-+ You will also need the latest user-space utilities: you can find
-+ them in the lm_sensors package, which you can download at
-+ http://www.lm-sensors.nu/
-+
-+National Semiconductor LM92
-+CONFIG_SENSORS_LM92
-+ If you say yes here you get support for National Semiconductor LM92
-+ sensor chips. This can also be built as a module which can be
-+ inserted and removed while the kernel is running.
-+
-+ You will also need the latest user-space utilties: you can find them
-+ in the lm_sensors package, which you can download at
-+ http://www.lm-sensors.nu
-+
-+National Semiconductor PC8736x Sensors
-+CONFIG_SENSORS_PC87360
-+ If you say yes here you get support for the integrated hardware
-+ monitoring in the National Semicoductor PC87360, PC87363, PC87364,
-+ PC87365 and PC87366 Super I/O chips. This can also be built as a
-+ module which can be inserted and removed while the kernel is
-+ running.
-+
-+ You will also need the latest user-space utilities: you can find them
-+ in the lm_sensors package, which you can download at
-+ http://www.lm-sensors.nu/
-+
-+Philips PCF8574
-+CONFIG_SENSORS_PCF8574
-+ If you say yes here you get support for the Philips PCF8574
-+ I2C 8-bit Parallel I/O device.
-+ This can also be built as a module which can be
-+ inserted and removed while the kernel is running.
-+
-+ You will also need the latest user-space utilties: you can find them
-+ in the lm_sensors package, which you can download at
-+ http://www.lm-sensors.nu
-+
-+Philips PCF8591
-+CONFIG_SENSORS_PCF8591
-+ If you say yes here you get support for the Philips PCF8591
-+ I2C Quad D/A + Single A/D I/O device.
-+ This can also be built as a module which can be
-+ inserted and removed while the kernel is running.
-+
-+ You will also need the latest user-space utilties: you can find them
-+ in the lm_sensors package, which you can download at
-+ http://www.lm-sensors.nu
-+
-+Silicon Integrated Systems Corp. SiS5595 Sensor
-+CONFIG_SENSORS_SIS5595
-+ If you say yes here you get support for the integrated sensors in
-+ SiS5595 South Bridges. This can also be built as a module
-+ which can be inserted and removed while the kernel is running.
-+
-+ You will also need the latest user-space utilties: you can find them
-+ in the lm_sensors package, which you can download at
-+ http://www.lm-sensors.nu
-+
-+SMSC47M1xx Super I/O Fan Support
-+CONFIG_SENSORS_SMSC47M1
-+ If you say yes here you get support for the integrated fan
-+ monitoring and control in the SMSC 47M1xx Super I/O chips.
-+ This can also be built as a module
-+ which can be inserted and removed while the kernel is running.
-+
-+ You will also need the latest user-space utilties: you can find them
-+ in the lm_sensors package, which you can download at
-+ http://www.lm-sensors.nu
-+
-+Texas Instruments THMC50 / Analog Devices ADM1022
-+CONFIG_SENSORS_THMC50
-+ If you say yes here you get support for Texas Instruments THMC50
-+ sensor chips and clones: the Analog Devices ADM1022.
-+ This can also be built as a module which
-+ can be inserted and removed while the kernel is running.
-+
-+ You will also need the latest user-space utilties: you can find them
-+ in the lm_sensors package, which you can download at
-+ http://www.lm-sensors.nu
-+
-+Via VT82C686A/B
-+CONFIG_SENSORS_VIA686A
-+ If you say yes here you get support for the integrated sensors in
-+ Via 686A/B South Bridges. This can also be built as a module
-+ which can be inserted and removed while the kernel is running.
-+
-+ You will also need the latest user-space utilties: you can find them
-+ in the lm_sensors package, which you can download at
-+ http://www.lm-sensors.nu
-+
-+Via VT1211 Sensors
-+CONFIG_SENSORS_VT1211
-+ If you say yes here you get support for the integrated sensors in
-+ the Via VT1211 Super I/O device. This can also be built as a module
-+ which can be inserted and removed while the kernel is running.
-+
-+ You will also need the latest user-space utilties: you can find them
-+ in the lm_sensors package, which you can download at
-+ http://www.lm-sensors.nu
-+
-+Via VT8231 Sensors
-+CONFIG_SENSORS_VT8231
-+ If you say yes here you get support for the integrated sensors in
-+ the Via VT8231 device. This can also be built as a module
-+ which can be inserted and removed while the kernel is running.
-+
-+ You will also need the latest user-space utilties: you can find them
-+ in the lm_sensors package, which you can download at
-+ http://www.lm-sensors.nu
-+
-+Winbond W83781D, W83782D, W83783S, W83627HF, AS99127F
-+CONFIG_SENSORS_W83781D
-+ If you say yes here you get support for the Winbond W8378x series
-+ of sensor chips: the W83781D, W83782D, W83783S and W83682HF,
-+ and the similar Asus AS99127F. This
-+ can also be built as a module which can be inserted and removed
-+ while the kernel is running.
-+
-+ You will also need the latest user-space utilties: you can find them
-+ in the lm_sensors package, which you can download at
-+ http://www.lm-sensors.nu
-+
-+Winbond W83627HF, W83627THF, W83697HF
-+CONFIG_SENSORS_W83627HF
-+ If you say yes here you get support for the Winbond W836x7 series
-+ of sensor chips: the Winbond W83627HF, W83627THF and W83697HF. This
-+ can also be built as a module which can be inserted and removed
-+ while the kernel is running.
-+
-+ You will also need the latest user-space utilities: you can find
-+ them in the lm_sensors package, which you can download at
-+ http://www.lm-sensors.nu/
-+
-+Winbond W83L785TS-S
-+CONFIG_SENSORS_W83L785TS
-+ If you say yes here you get support for the Winbond W83L785TS-S
-+ sensor chip. This can also be built as a module.
-+
-+ You will also need the latest user-space utilities: you can find
-+ them in the lm_sensors package, which you can download at
-+ http://www.lm-sensors.nu/
-+
-+EEprom (DIMM) reader
-+CONFIG_SENSORS_EEPROM
-+ If you say yes here you get read-only access to the EEPROM data
-+ available on modern memory DIMMs, and which could theoretically
-+ also be available on other devices. This can also be built as a
-+ module which can be inserted and removed while the kernel is
-+ running.
-+
-+ You will also need the latest user-space utilties: you can find them
-+ in the lm_sensors package, which you can download at
-+ http://www.lm-sensors.nu
-+
- # End:
---- linux-old/MAINTAINERS Sun Oct 3 01:33:28 2004
-+++ linux/MAINTAINERS Mon Dec 13 20:18:56 2004
-@@ -1659,6 +1659,15 @@
- L: linux-ide@vger.kernel.org
- S: Supported
-
-+SENSORS DRIVERS
-+P: Frodo Looijaard
-+M: frodol@dds.nl
-+P: Philip Edelbrock
-+M: phil@netroedge.com
-+L: sensors@stimpy.netroedge.com
-+W: http://www.lm-sensors.nu/
-+S: Maintained
-+
- SGI VISUAL WORKSTATION 320 AND 540
- P: Bent Hagemark
- M: bh@sgi.com
---- linux-old/arch/i386/kernel/dmi_scan.c Fri Apr 16 03:14:11 2004
-+++ linux/arch/i386/kernel/dmi_scan.c Mon Dec 13 20:18:56 2004
-@@ -15,6 +15,7 @@
- #include "pci-i386.h"
-
- unsigned long dmi_broken;
-+int is_unsafe_smbus;
- int is_sony_vaio_laptop;
-
- struct dmi_header
-@@ -371,6 +372,19 @@
- }
-
- /*
-+ * Don't access SMBus on IBM systems which get corrupted eeproms
-+ */
-+
-+static __init int disable_smbus(struct dmi_blacklist *d)
-+{
-+ if (is_unsafe_smbus == 0) {
-+ is_unsafe_smbus = 1;
-+ printk(KERN_INFO "%s machine detected. Disabling SMBus accesses.\n", d->ident);
-+ }
-+ return 0;
-+}
-+
-+/*
- * Check for a Sony Vaio system
- *
- * On a Sony system we want to enable the use of the sonypi
-@@ -675,6 +689,10 @@
- NO_MATCH, NO_MATCH,
- } },
-
-+ { disable_smbus, "IBM", {
-+ MATCH(DMI_SYS_VENDOR, "IBM"),
-+ NO_MATCH, NO_MATCH, NO_MATCH
-+ } },
- { sony_vaio_laptop, "Sony Vaio", { /* This is a Sony Vaio laptop */
- MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
- MATCH(DMI_PRODUCT_NAME, "PCG-"),
---- linux-old/arch/i386/kernel/i386_ksyms.c Fri Apr 16 03:14:11 2004
-+++ linux/arch/i386/kernel/i386_ksyms.c Mon Dec 13 20:18:56 2004
-@@ -179,6 +179,9 @@
- EXPORT_SYMBOL(atomic_dec_and_lock);
- #endif
-
-+extern int is_unsafe_smbus;
-+EXPORT_SYMBOL(is_unsafe_smbus);
-+
- extern int is_sony_vaio_laptop;
- EXPORT_SYMBOL(is_sony_vaio_laptop);
-
diff --git a/recipes/linux/linux-mtx-1-2.4.27/18-i2c-au1x00gpio.patch b/recipes/linux/linux-mtx-1-2.4.27/18-i2c-au1x00gpio.patch
deleted file mode 100644
index 2dccf681eb..0000000000
--- a/recipes/linux/linux-mtx-1-2.4.27/18-i2c-au1x00gpio.patch
+++ /dev/null
@@ -1,466 +0,0 @@
-diff -urN linux-2.4.27-mtx1-lm_sensors-2.8.8/drivers/i2c/Config.in linux-2.4.27-mtx1-lm_sensors-2.8.8-i2cau1x00gpio/drivers/i2c/Config.in
---- linux-2.4.27-mtx1-lm_sensors-2.8.8/drivers/i2c/Config.in 2004-12-13 18:03:18.000000000 +0100
-+++ linux-2.4.27-mtx1-lm_sensors-2.8.8-i2cau1x00gpio/drivers/i2c/Config.in 2004-12-13 18:11:02.000000000 +0100
-@@ -17,6 +17,11 @@
- int ' GPIO pin used for SCL' CONFIG_SCx200_I2C_SCL 12
- int ' GPIO pin used for SDA' CONFIG_SCx200_I2C_SDA 13
- fi
-+ dep_tristate ' I2C using Au1x00 GPIO pins' CONFIG_I2C_AU1X00GPIO $CONFIG_I2C_ALGOBIT
-+ if [ "$CONFIG_I2C_AU1X00GPIO" != "n" ]; then
-+ int ' GPIO pin used for SCL' CONFIG_I2C_AU1X00GPIO_SCL 206
-+ int ' GPIO pin used for SDA' CONFIG_I2C_AU1X00GPIO_SDA 207
-+ fi
- fi
-
- dep_tristate 'NatSemi SCx200 ACCESS.bus' CONFIG_SCx200_ACB $CONFIG_I2C
-diff -urN linux-2.4.27-mtx1-lm_sensors-2.8.8/drivers/i2c/i2c-au1x00gpio.c linux-2.4.27-mtx1-lm_sensors-2.8.8-i2cau1x00gpio/drivers/i2c/i2c-au1x00gpio.c
---- linux-2.4.27-mtx1-lm_sensors-2.8.8/drivers/i2c/i2c-au1x00gpio.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.4.27-mtx1-lm_sensors-2.8.8-i2cau1x00gpio/drivers/i2c/i2c-au1x00gpio.c 2004-12-13 18:12:50.000000000 +0100
-@@ -0,0 +1,426 @@
-+/* ------------------------------------------------------------------------- */
-+/* i2c-au1x00gpio.c i2c-hw access for Au1x00 GPIO pins. */
-+/* ------------------------------------------------------------------------- */
-+/* Copyright (C) 1995-2000 Michael Stickel
-+
-+ 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., 675 Mass Ave, Cambridge, MA 02139, USA. */
-+/* ------------------------------------------------------------------------- */
-+
-+/* With some changes from Kyösti Mälkki <kmalkki@cc.hut.fi> and even
-+ Frodo Looijaard <frodol@dds.nl>
-+ Simon G. Vogl
-+*/
-+
-+/* $Id: i2c-au1x00gpio.c,v 1.1.1.2 2004/01/22 15:35:47 br1 Exp $ */
-+
-+#include <linux/module.h>
-+#include <linux/config.h>
-+#include <linux/types.h>
-+#include <linux/kernel.h>
-+#include <linux/init.h>
-+#include <linux/stddef.h>
-+#include <linux/ioport.h>
-+#include <asm/uaccess.h>
-+#include <asm/io.h>
-+#include <asm/au1000.h>
-+#include <asm/au1000_gpio.h>
-+
-+#include <linux/slab.h>
-+#include <linux/mm.h>
-+
-+#include <linux/i2c.h>
-+#include <linux/i2c-algo-bit.h>
-+
-+#ifndef __exit
-+#define __exit __init
-+#endif
-+
-+
-+struct i2c_au1x00gpio
-+{
-+ struct i2c_au1x00gpio *next;
-+
-+ short scl_gpio;
-+ short sda_gpio;
-+
-+ unsigned long scl_mask;
-+ unsigned long sda_mask;
-+
-+ struct i2c_adapter adapter;
-+ struct i2c_algo_bit_data bit_au1x00gpio_data;
-+};
-+
-+static struct i2c_au1x00gpio *adapter_list;
-+
-+
-+
-+/* ----- global defines ----------------------------------------------- */
-+#define DEB(x) /* should be reasonable open, close &c. */
-+#define DEB2(x) /* low level debugging - very slow */
-+#define DEBE(x) x /* error messages */
-+
-+/* ----- printer port defines ------------------------------------------*/
-+
-+/* ----- local functions ---------------------------------------------- */
-+
-+
-+//-- Primary GPIO
-+static void bit_au1x00gpio_setscl(void *data, int state)
-+{
-+ struct i2c_au1x00gpio * adapter = (struct i2c_au1x00gpio *)data;
-+ if (state)
-+ au_writel(adapter->scl_mask, SYS_TRIOUTCLR); // Disable Driver: Switch off Transistor => 1
-+ else
-+ au_writel(adapter->scl_mask, SYS_OUTPUTCLR); // Clear Output and switch on Transistor => 0
-+}
-+
-+
-+static void bit_au1x00gpio_setsda(void *data, int state)
-+{
-+ struct i2c_au1x00gpio * adapter = (struct i2c_au1x00gpio *)data;
-+ if (state)
-+ au_writel(adapter->sda_mask, SYS_TRIOUTCLR);
-+ else
-+ au_writel(adapter->sda_mask, SYS_OUTPUTCLR);
-+}
-+
-+
-+static int bit_au1x00gpio_getscl(void *data)
-+{
-+ struct i2c_au1x00gpio * adapter = (struct i2c_au1x00gpio *)data;
-+ return (au_readl(SYS_PINSTATERD) & adapter->scl_mask) ? 1 : 0;
-+}
-+
-+
-+static int bit_au1x00gpio_getsda(void *data)
-+{
-+ struct i2c_au1x00gpio * adapter = (struct i2c_au1x00gpio *)data;
-+ return (au_readl(SYS_PINSTATERD) & adapter->sda_mask) ? 1 : 0;
-+}
-+
-+
-+
-+
-+/*--
-+ *-- Functions for accessing GPIO-2
-+ *--
-+ */
-+static void bit_au1x00gpio2_setscl(void *data, int state)
-+{
-+ struct i2c_au1x00gpio * adapter = (struct i2c_au1x00gpio *)data;
-+ if (state)
-+ {
-+ au_writel(au_readl(GPIO2_DIR) & ~adapter->scl_mask, GPIO2_DIR);
-+ }
-+ else
-+ {
-+ au_writel(au_readl(GPIO2_OUTPUT) & ~adapter->scl_mask, GPIO2_OUTPUT);
-+ au_writel(au_readl(GPIO2_DIR) | adapter->scl_mask, GPIO2_DIR);
-+ }
-+}
-+
-+static void bit_au1x00gpio2_setsda(void *data, int state)
-+{
-+ struct i2c_au1x00gpio * adapter = (struct i2c_au1x00gpio *)data;
-+ if (state)
-+ {
-+ au_writel(au_readl(GPIO2_DIR) & ~adapter->sda_mask, GPIO2_DIR);
-+ }
-+ else
-+ {
-+ au_writel(au_readl(GPIO2_OUTPUT) & ~adapter->sda_mask, GPIO2_OUTPUT);
-+ au_writel(au_readl(GPIO2_DIR) | adapter->sda_mask, GPIO2_DIR);
-+ }
-+}
-+
-+static int bit_au1x00gpio2_getscl(void *data)
-+{
-+ struct i2c_au1x00gpio * adapter = (struct i2c_au1x00gpio *)data;
-+ return (au_readl(GPIO2_PINSTATE) & adapter->scl_mask) ? 1 : 0;
-+}
-+
-+static int bit_au1x00gpio2_getsda(void *data)
-+{
-+ struct i2c_au1x00gpio * adapter = (struct i2c_au1x00gpio *)data;
-+ return (au_readl(GPIO2_PINSTATE) & adapter->sda_mask) ? 1 : 0;
-+}
-+
-+
-+
-+static int check_i2c_au1x00gpio_adapter(struct i2c_au1x00gpio *adapter)
-+{
-+ int state = 0;
-+
-+ adapter->bit_au1x00gpio_data.setsda (adapter, 1);
-+ adapter->bit_au1x00gpio_data.setscl (adapter, 1);
-+
-+ if (adapter->bit_au1x00gpio_data.getsda(adapter)==0)
-+ {
-+ printk ("i2c-au1x00gpio: sda line should read 1 but reads 0\n");
-+ state = -1;
-+ }
-+ if (adapter->bit_au1x00gpio_data.getscl(adapter)==0)
-+ {
-+ printk ("i2c-au1x00gpio: scl line should read 1 but reads 0\n");
-+ state = -1;
-+ }
-+
-+
-+ adapter->bit_au1x00gpio_data.setsda (adapter, 0);
-+ adapter->bit_au1x00gpio_data.setscl (adapter, 0);
-+
-+ if (adapter->bit_au1x00gpio_data.getsda(adapter)==1)
-+ {
-+ printk ("i2c-au1x00gpio: sda line should read 0 but reads 1\n");
-+ state = -1;
-+ }
-+ if (adapter->bit_au1x00gpio_data.getscl(adapter)==1)
-+ {
-+ printk ("i2c-au1x00gpio: scl line should read 0 but reads 1\n");
-+ state = -1;
-+ }
-+
-+ if (state==0)
-+ printk ("i2c-au1x00gpio: adapter with scl=GPIO%d,sda=GPIO%d is working\n",
-+ adapter->scl_gpio, adapter->sda_gpio
-+ );
-+ return state;
-+}
-+
-+
-+
-+#if 0
-+static int bit_au1x00gpio_reg(struct i2c_client *client)
-+{
-+ return 0;
-+}
-+
-+static int bit_au1x00gpio_unreg(struct i2c_client *client)
-+{
-+ return 0;
-+}
-+
-+static void bit_au1x00gpio_inc_use(struct i2c_adapter *adap)
-+{
-+ MOD_INC_USE_COUNT;
-+}
-+
-+static void bit_au1x00gpio_dec_use(struct i2c_adapter *adap)
-+{
-+ MOD_DEC_USE_COUNT;
-+}
-+#endif
-+
-+
-+
-+static struct i2c_algo_bit_data bit_au1x00gpio_data = {
-+ .setsda = bit_au1x00gpio_setsda,
-+ .setscl = bit_au1x00gpio_setscl,
-+ .getsda = bit_au1x00gpio_getsda,
-+ .getscl = bit_au1x00gpio_getscl,
-+ .udelay = 80,
-+ .mdelay = 80,
-+ .timeout = HZ
-+};
-+
-+
-+static struct i2c_adapter bit_au1x00gpio_ops = {
-+ .owner = THIS_MODULE,
-+ .name = "Au1x00 GPIO I2C adapter",
-+ .id = I2C_HW_B_AU1x00GPIO,
-+};
-+
-+
-+
-+/*
-+ * scl_gpio:
-+ * 0..31 for primary GPIO's
-+ * 200..215 for secondary GPIO's
-+ *
-+ * sda_gpio:
-+ * 0..31 for primary GPIO's
-+ * 200..215 for secondary GPIO's
-+ *
-+ * You can even mix primary and secondary GPIO's.
-+ * E.g.: i2c_au1x00gpio_create(4,206);
-+ */
-+
-+static int i2c_au1x00gpio_create (int scl_gpio, int sda_gpio)
-+{
-+ if ((scl_gpio < 32 || (scl_gpio >= 200 && scl_gpio <= 215)) &&
-+ (scl_gpio < 32 || (scl_gpio >= 200 && scl_gpio <= 215)))
-+ {
-+ struct i2c_au1x00gpio *adapter = kmalloc(sizeof(struct i2c_au1x00gpio),
-+ GFP_KERNEL);
-+ if (!adapter) {
-+ printk(KERN_ERR "i2c-au1x00-gpio: Unable to malloc.\n");
-+ return -1;
-+ }
-+
-+ printk(KERN_DEBUG "i2c-au1x00-gpio.o: attaching to SCL=GPIO%d, SDA=GPIO%d\n",
-+ scl_gpio, sda_gpio);
-+
-+ memset (adapter, 0, sizeof(struct i2c_au1x00gpio));
-+
-+ adapter->adapter = bit_au1x00gpio_ops;
-+
-+ adapter->adapter.algo_data = &adapter->bit_au1x00gpio_data;
-+ adapter->bit_au1x00gpio_data = bit_au1x00gpio_data;
-+ adapter->bit_au1x00gpio_data.data = adapter;
-+
-+ adapter->bit_au1x00gpio_data.data = adapter;
-+
-+ adapter->scl_gpio = scl_gpio;
-+ adapter->sda_gpio = sda_gpio;
-+
-+ if (sda_gpio < 32)
-+ {
-+ adapter->bit_au1x00gpio_data.setsda = bit_au1x00gpio_setsda;
-+ adapter->bit_au1x00gpio_data.getsda = bit_au1x00gpio_getsda;
-+ adapter->sda_mask = 1<<sda_gpio;
-+ }
-+ else if (sda_gpio >= 200 && sda_gpio <= 215)
-+ {
-+ adapter->bit_au1x00gpio_data.setsda = bit_au1x00gpio2_setsda;
-+ adapter->bit_au1x00gpio_data.getsda = bit_au1x00gpio2_getsda;
-+ adapter->sda_mask = 1<<(sda_gpio-200);
-+ }
-+
-+
-+ if (scl_gpio < 32)
-+ {
-+ adapter->bit_au1x00gpio_data.setscl = bit_au1x00gpio_setscl;
-+ adapter->bit_au1x00gpio_data.getscl = bit_au1x00gpio_getscl;
-+ adapter->scl_mask = 1<<scl_gpio;
-+ }
-+ else if (scl_gpio >= 200 && scl_gpio <= 215)
-+ {
-+ adapter->bit_au1x00gpio_data.setscl = bit_au1x00gpio2_setscl;
-+ adapter->bit_au1x00gpio_data.getscl = bit_au1x00gpio2_getscl;
-+ adapter->scl_mask = 1<<(scl_gpio-200);
-+ }
-+
-+ au_writel(0L, SYS_PININPUTEN);
-+ if (check_i2c_au1x00gpio_adapter(adapter)==0)
-+ {
-+ adapter->bit_au1x00gpio_data.setsda (adapter, 1);
-+ adapter->bit_au1x00gpio_data.setscl (adapter, 1);
-+
-+ if (i2c_bit_add_bus(&adapter->adapter) < 0)
-+ {
-+ printk(KERN_ERR "i2c-au1x00-gpio: Unable to register with I2C.\n");
-+ kfree(adapter);
-+ return -1; /* No good */
-+ }
-+
-+ adapter->next = adapter_list;
-+ adapter_list = adapter;
-+ return 0;
-+ }
-+ }
-+ else
-+ printk(KERN_ERR "i2c-au1x00-gpio: Invalid argument scl_gpio=%d, sda_gpio=%d.\n", scl_gpio, sda_gpio);
-+ return -1;
-+}
-+
-+
-+
-+static void i2c_au1x00gpio_delete (int scl_gpio, int sda_gpio)
-+{
-+ struct i2c_au1x00gpio *adapter, *prev = NULL;
-+
-+ for (adapter = adapter_list; adapter; adapter = adapter->next)
-+ {
-+ if (adapter->scl_gpio == scl_gpio &&
-+ adapter->sda_gpio == sda_gpio)
-+ {
-+ i2c_bit_del_bus(&adapter->adapter);
-+ if (prev)
-+ prev->next = adapter->next;
-+ else
-+ adapter_list = adapter->next;
-+ kfree(adapter);
-+ return;
-+ }
-+ prev = adapter;
-+ }
-+}
-+
-+
-+
-+
-+
-+#ifndef CONFIG_I2C_AU1X00GPIO_SCL
-+#define CONFIG_I2C_AU1X00GPIO_SCL (216)
-+#endif
-+
-+#ifndef CONFIG_I2C_AU1X00GPIO_SDA
-+#define CONFIG_I2C_AU1X00GPIO_SDA (217)
-+#endif
-+
-+static int au1x00gpiopin_scl = CONFIG_I2C_AU1X00GPIO_SCL;
-+static int au1x00gpiopin_sda = CONFIG_I2C_AU1X00GPIO_SDA;
-+
-+
-+
-+int __init i2c_bit_au1x00gpio_init(void)
-+{
-+ printk(KERN_INFO "i2c-au1x00gpio.o: i2c Au1x00 GPIO adapter module version %s (%s)\n", I2C_VERSION, I2C_DATE);
-+
-+ if (i2c_au1x00gpio_create (au1x00gpiopin_scl, au1x00gpiopin_sda) == 0)
-+ {
-+ printk(KERN_INFO "i2c-au1x00gpio.o: registered I2C-Bus for GPIO%d,GPIO%d\n",
-+ au1x00gpiopin_scl, au1x00gpiopin_sda
-+ );
-+ return 0;
-+ }
-+ printk(KERN_INFO "i2c-au1x00gpio.o: failed to register I2C-Bus for GPIO%d,GPIO%d\n",
-+ au1x00gpiopin_scl, au1x00gpiopin_sda
-+ );
-+ return -1;
-+}
-+
-+
-+void __exit i2c_bit_au1x00gpio_exit(void)
-+{
-+ i2c_au1x00gpio_delete (au1x00gpiopin_scl, au1x00gpiopin_sda);
-+}
-+
-+
-+
-+EXPORT_NO_SYMBOLS;
-+
-+MODULE_PARM(au1x00gpiopin_scl, "i");
-+MODULE_PARM_DESC(au1x00gpiopin_scl, "GPIO pin number used for SCL pin.");
-+
-+MODULE_PARM(au1x00gpiopin_sda, "i");
-+MODULE_PARM_DESC(au1x00gpiopin_sda, "GPIO pin number used for SDA pin.");
-+
-+MODULE_AUTHOR("Michael Stickel <michael@cubic.org>");
-+MODULE_DESCRIPTION("I2C-Bus adapter routines for Au1x00 GPIO adapter.");
-+MODULE_LICENSE("GPL");
-+
-+
-+#ifdef MODULE
-+int init_module(void)
-+{
-+ return i2c_bit_au1x00gpio_init();
-+}
-+
-+void cleanup_module(void)
-+{
-+ i2c_bit_au1x00gpio_exit();
-+}
-+#endif
-diff -urN linux-2.4.27-mtx1-lm_sensors-2.8.8/drivers/i2c/Makefile linux-2.4.27-mtx1-lm_sensors-2.8.8-i2cau1x00gpio/drivers/i2c/Makefile
---- linux-2.4.27-mtx1-lm_sensors-2.8.8/drivers/i2c/Makefile 2004-12-13 18:03:18.000000000 +0100
-+++ linux-2.4.27-mtx1-lm_sensors-2.8.8-i2cau1x00gpio/drivers/i2c/Makefile 2004-12-13 18:11:59.000000000 +0100
-@@ -25,6 +25,7 @@
- obj-$(CONFIG_I2C_ALGO_SIBYTE) += i2c-algo-sibyte.o i2c-sibyte.o
- obj-$(CONFIG_I2C_MAX1617) += i2c-max1617.o
- obj-$(CONFIG_I2C_ALGO_SGI) += i2c-algo-sgi.o
-+obj-$(CONFIG_I2C_AU1X00GPIO) += i2c-au1x00gpio.o
- obj-$(CONFIG_I2C_ALGO_AU1550) += i2c-algo-au1550.o i2c-au1550.o
-
- # This is needed for automatic patch generation: sensors code starts here
---- linux-2.4.27-mtx1-lm_sensors-2.8.8/include/linux/i2c-id.h 2004-12-13 21:09:52.000000000 +0100
-+++ linux-2.4.27-mtx1-lm_sensors-2.8.8-i2cau1x00gpio/include/linux/i2c-id.h 2004-12-13 21:36:14.000000000 +0100
-@@ -242,6 +242,7 @@
- #define I2C_HW_B_S3VIA 0x18 /* S3Via ProSavage adapter */
- #define I2C_HW_B_ZR36067 0x19 /* Zoran-36057/36067 based boards */
- #define I2C_HW_B_PCILYNX 0x1a /* TI PCILynx I2C adapter */
-+#define I2C_HW_B_AU1x00GPIO 0x1b /* Au1x00 GPIO adapter */
-
- /* --- PCF 8584 based algorithms */
- #define I2C_HW_P_LP 0x00 /* Parallel port interface */
diff --git a/recipes/linux/linux-mtx-1-2.4.27/19-kernel-make-depend.diff b/recipes/linux/linux-mtx-1-2.4.27/19-kernel-make-depend.diff
deleted file mode 100644
index 6fdfe423e8..0000000000
--- a/recipes/linux/linux-mtx-1-2.4.27/19-kernel-make-depend.diff
+++ /dev/null
@@ -1,11 +0,0 @@
---- linux/Makefile~ 2004-02-09 10:35:08.000000000 -0500
-+++ linux/Makefile 2004-02-12 20:38:04.000000000 -0500
-@@ -538,7 +538,7 @@
- ifdef CONFIG_MODVERSIONS
- $(MAKE) update-modverfile
- endif
-- scripts/mkdep -- `find $(FINDHPATH) \( -name SCCS -o -name .svn \) -prune -o -follow -name \*.h ! -name modversions.h -print` > .hdepend
-+ (find $(FINDHPATH) \( -name SCCS -o -name .svn \) -prune -o -follow -name \*.h ! -name modversions.h -print | xargs -r scripts/mkdep -- ) > .hdepend
- scripts/mkdep -- init/*.c > .depend
- (find $(TOPDIR) \( -name .depend -o -name .hdepend \) -print | xargs $(AWK) -f scripts/include_deps) > tmp_include_depends
- sed -ne 's/^\([^ ].*\):.*/ \1 \\/p' tmp_include_depends > tmp_include_depends_1
diff --git a/recipes/linux/linux-mtx-1-2.4.27/20-au1x00_ethernet_tx_stats.diff b/recipes/linux/linux-mtx-1-2.4.27/20-au1x00_ethernet_tx_stats.diff
deleted file mode 100644
index 5fefd991da..0000000000
--- a/recipes/linux/linux-mtx-1-2.4.27/20-au1x00_ethernet_tx_stats.diff
+++ /dev/null
@@ -1,64 +0,0 @@
-diff -p -u -r1.5.2.33 linux/drivers/net/au1000_eth.c
---- linux/drivers/net/au1000_eth.c 26 Nov 2004 08:40:13 -0000 1.5.2.33
-+++ linux/drivers/net/au1000_eth.c 21 Jan 2005 14:33:47 -0000
-@@ -83,7 +83,7 @@ static void au1000_tx_timeout(struct net
- static int au1000_set_config(struct net_device *dev, struct ifmap *map);
- static void set_rx_mode(struct net_device *);
- static struct net_device_stats *au1000_get_stats(struct net_device *);
--static inline void update_tx_stats(struct net_device *, u32, u32);
-+static inline void update_tx_stats(struct net_device *, u32);
- static inline void update_rx_stats(struct net_device *, u32);
- static void au1000_timer(unsigned long);
- static int au1000_ioctl(struct net_device *, struct ifreq *, int);
-@@ -1542,14 +1542,11 @@ static void __exit au1000_cleanup_module
-
-
- static inline void
--update_tx_stats(struct net_device *dev, u32 status, u32 pkt_len)
-+update_tx_stats(struct net_device *dev, u32 status)
- {
- struct au1000_private *aup = (struct au1000_private *) dev->priv;
- struct net_device_stats *ps = &aup->stats;
-
-- ps->tx_packets++;
-- ps->tx_bytes += pkt_len;
--
- if (status & TX_FRAME_ABORTED) {
- if (dev->if_port == IF_PORT_100BASEFX) {
- if (status & (TX_JAB_TIMEOUT | TX_UNDERRUN)) {
-@@ -1582,7 +1579,7 @@ static void au1000_tx_ack(struct net_dev
- ptxd = aup->tx_dma_ring[aup->tx_tail];
-
- while (ptxd->buff_stat & TX_T_DONE) {
-- update_tx_stats(dev, ptxd->status, ptxd->len & 0x3ff);
-+ update_tx_stats(dev, ptxd->status);
- ptxd->buff_stat &= ~TX_T_DONE;
- ptxd->len = 0;
- au_sync();
-@@ -1604,6 +1601,7 @@ static void au1000_tx_ack(struct net_dev
- static int au1000_tx(struct sk_buff *skb, struct net_device *dev)
- {
- struct au1000_private *aup = (struct au1000_private *) dev->priv;
-+ struct net_device_stats *ps = &aup->stats;
- volatile tx_dma_t *ptxd;
- u32 buff_stat;
- db_dest_t *pDB;
-@@ -1623,7 +1621,7 @@ static int au1000_tx(struct sk_buff *skb
- return 1;
- }
- else if (buff_stat & TX_T_DONE) {
-- update_tx_stats(dev, ptxd->status, ptxd->len & 0x3ff);
-+ update_tx_stats(dev, ptxd->status);
- ptxd->len = 0;
- }
-
-@@ -1643,6 +1641,9 @@ static int au1000_tx(struct sk_buff *skb
- else
- ptxd->len = skb->len;
-
-+ ps->tx_packets++;
-+ ps->tx_bytes += ptxd->len;
-+
- ptxd->buff_stat = pDB->dma_addr | TX_DMA_ENABLE;
- au_sync();
- dev_kfree_skb(skb);
diff --git a/recipes/linux/linux-mtx-1-2.4.27/21-mtx-1-watchdog.diff b/recipes/linux/linux-mtx-1-2.4.27/21-mtx-1-watchdog.diff
deleted file mode 100644
index b58f2cdd6b..0000000000
--- a/recipes/linux/linux-mtx-1-2.4.27/21-mtx-1-watchdog.diff
+++ /dev/null
@@ -1,231 +0,0 @@
-diff -Nurb linux/arch/mips/au1000/mtx-1/Makefile linux.wd/arch/mips/au1000/mtx-1/Makefile
---- linux/arch/mips/au1000/mtx-1/Makefile 2004-11-24 12:11:54.000000000 +0100
-+++ linux.wd/arch/mips/au1000/mtx-1/Makefile 2005-03-09 17:58:40.000000000 +0100
-@@ -15,6 +15,6 @@
-
- O_TARGET := mtx-1.o
-
--obj-y := init.o board_setup.o irqmap.o
-+obj-y := init.o board_setup.o irqmap.o mtx-1_watchdog.o
-
- include $(TOPDIR)/Rules.make
-diff -Nurb linux/arch/mips/au1000/mtx-1/mtx-1_watchdog.c linux.wd/arch/mips/au1000/mtx-1/mtx-1_watchdog.c
---- linux/arch/mips/au1000/mtx-1/mtx-1_watchdog.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux.wd/arch/mips/au1000/mtx-1/mtx-1_watchdog.c 2005-03-09 18:28:06.000000000 +0100
-@@ -0,0 +1,216 @@
-+/*
-+ * Driver for the MTX-1 Watchdog.
-+ *
-+ * (c) Copyright 2005 4G Systems <info@4g-systems.biz>, All Rights Reserved.
-+ * http://www.4g-systems.biz
-+ *
-+ * 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.
-+ *
-+ * Neither Michael Stickel nor 4G Systems admit liability nor provide
-+ * warranty for any of this software. This material is provided
-+ * "AS-IS" and at no charge.
-+ *
-+ * (c) Copyright 2005 4G Systems <info@4g-systems.biz>
-+ *
-+ * Release 0.01.
-+ *
-+ * Author: Michael Stickel michael.stickel@4g-systems.biz
-+ *
-+ *
-+ * The Watchdog is configured to reset the MTX-1
-+ * if it is not triggered for 100 seconds.
-+ * It should not be triggered more often than 1.6 seconds.
-+ *
-+ * A timer triggers the watchdog every 5 seconds, until
-+ * it is opened for the first time. After the first open
-+ * it MUST be triggered every 2..95 seconds.
-+ */
-+#include <linux/config.h>
-+#include <linux/module.h>
-+#include <linux/version.h>
-+#include <linux/types.h>
-+#include <linux/errno.h>
-+#include <linux/kernel.h>
-+#include <linux/sched.h>
-+#include <linux/miscdevice.h>
-+#include <linux/watchdog.h>
-+#include <linux/slab.h>
-+#include <linux/init.h>
-+
-+#include <asm/au1000.h>
-+
-+
-+#ifndef FALSE
-+# define FALSE (0)
-+#endif
-+
-+#ifndef TRUE
-+# define TRUE (!FALSE)
-+#endif
-+
-+
-+//---------[ Hardware Functions ]-----------------
-+
-+static void mtx1_trigger_wd (void)
-+{
-+ /*
-+ * toggle GPIO2_15
-+ */
-+
-+ u32 tmp = au_readl(GPIO2_DIR);
-+ tmp = (tmp & ~(1<<15)) | ((~tmp) & (1<<15));
-+ au_writel (tmp, GPIO2_DIR);
-+}
-+
-+static void mtx1_enable_wd (void)
-+{
-+ au_writel (au_readl(GPIO2_DIR) | (u32)(1<<15), GPIO2_DIR);
-+}
-+
-+static void mtx1_disable_wd (void)
-+{
-+ au_writel (au_readl(GPIO2_DIR) & ~((u32)(1<<15)), GPIO2_DIR);
-+}
-+
-+
-+//---------[ Timer Functions ]-----------------
-+
-+static struct timer_list wd_trigger_timer;
-+static char timer_is_running = FALSE;
-+
-+static void wd_timer_callback (unsigned long data)
-+{
-+ if (timer_is_running)
-+ mod_timer (&wd_trigger_timer, jiffies + 5 * HZ);
-+ mtx1_trigger_wd ();
-+}
-+
-+static void start_wd_timer (void)
-+{
-+ if (!timer_is_running) {
-+ struct timer_list *t = &wd_trigger_timer;
-+
-+ init_timer (t);
-+ t->function = wd_timer_callback;
-+ t->data = (unsigned long)0L;
-+ t->expires = jiffies + 5 * HZ; // 5 seconds.
-+ add_timer (t);
-+ timer_is_running = TRUE;
-+ }
-+}
-+
-+
-+
-+static void stop_wd_timer (void)
-+{
-+ if (timer_is_running) {
-+ del_timer(&wd_trigger_timer);
-+ timer_is_running = FALSE;
-+ }
-+}
-+
-+
-+//---------[ File Functions ]-----------------
-+
-+static int mtx1wd_open (struct inode *inode, struct file *file)
-+{
-+ if (MINOR(inode->i_rdev)!=WATCHDOG_MINOR) return -ENODEV;
-+ MOD_INC_USE_COUNT;
-+
-+ // stop the timer, if it is running. It will not be
-+ // started again, until the module is loaded again.
-+ stop_wd_timer();
-+
-+ // sleep for 2 seconds, to ensure, that the wd is
-+ // not triggered more often than every 2 seconds.
-+ schedule_timeout (2 * HZ);
-+
-+ return 0;
-+}
-+
-+
-+static int mtx1wd_release (struct inode *inode, struct file *file) {
-+ if (MINOR(inode->i_rdev)==WATCHDOG_MINOR) {
-+ }
-+ MOD_DEC_USE_COUNT;
-+ return 0;
-+}
-+
-+
-+static ssize_t mtx1wd_write (struct file *file, const char *buf, size_t count, loff_t *ppos) {
-+ if (ppos!=&file->f_pos)
-+ return -ESPIPE;
-+
-+ if (count) {
-+ mtx1_trigger_wd ();
-+ return 1;
-+ }
-+ return 0;
-+}
-+
-+
-+
-+static struct file_operations mtx1wd_fops = {
-+ .owner = THIS_MODULE,
-+ .llseek = NULL,
-+ .read = NULL,
-+ .write = mtx1wd_write,
-+ .readdir = NULL,
-+ .poll = NULL,
-+ .ioctl = NULL,
-+ .mmap = NULL,
-+ .open = mtx1wd_open,
-+ .flush = NULL,
-+ .release = mtx1wd_release
-+};
-+
-+
-+static struct miscdevice mtx1wd_miscdev = {
-+ WATCHDOG_MINOR,
-+ "watchdog",
-+ &mtx1wd_fops
-+};
-+
-+
-+
-+//---------[ Module Functions ]-----------------
-+
-+
-+void cleanup_module (void)
-+{
-+ // stop the timer, if it is running.
-+ stop_wd_timer();
-+
-+ misc_deregister(&mtx1wd_miscdev);
-+
-+ mtx1_disable_wd ();
-+}
-+
-+
-+int __init init_mtx1_watchdog (void)
-+{
-+ printk("MTX-1 watchdog driver\n");
-+
-+ mtx1_enable_wd ();
-+
-+ //-- trigger it for the first time.
-+ //-- We do not exactly know how long it has not been triggered.
-+ mtx1_trigger_wd ();
-+
-+ misc_register (&mtx1wd_miscdev);
-+
-+ // start a timer, that calls mtx1_trigger_wd every 5 seconds.
-+ start_wd_timer();
-+
-+ return 0;
-+}
-+
-+__initcall(init_mtx1_watchdog);
-+
-+MODULE_AUTHOR("Michael Stickel");
-+MODULE_DESCRIPTION("Driver for the MTX-1 watchdog");
-+MODULE_LICENSE("GPL");
-+EXPORT_NO_SYMBOLS;
diff --git a/recipes/linux/linux-mtx-1-2.4.27/22-umts.diff b/recipes/linux/linux-mtx-1-2.4.27/22-umts.diff
deleted file mode 100644
index 8bf2f80236..0000000000
--- a/recipes/linux/linux-mtx-1-2.4.27/22-umts.diff
+++ /dev/null
@@ -1,28 +0,0 @@
-diff -Nurb linux-2.4.27-mtx1/drivers/usb/serial/usbserial.c linux-2.4.27-mtx1-umts/drivers/usb/serial/usbserial.c
---- linux-2.4.27-mtx1/drivers/usb/serial/usbserial.c 2004-08-14 20:38:57.000000000 +0200
-+++ linux-2.4.27-mtx1-umts/drivers/usb/serial/usbserial.c 2005-06-07 10:53:03.000000000 +0200
-@@ -332,7 +332,7 @@
- static __u16 vendor = 0x05f9;
- static __u16 product = 0xffff;
-
--static struct usb_device_id generic_device_ids[2]; /* Initially all zeroes. */
-+static struct usb_device_id generic_device_ids[5]; /* Initially all zeroes. */
-
- /* All of the device info needed for the Generic Serial Converter */
- static struct usb_serial_device_type generic_device = {
-@@ -1773,6 +1773,15 @@
- generic_device_ids[0].idVendor = vendor;
- generic_device_ids[0].idProduct = product;
- generic_device_ids[0].match_flags = USB_DEVICE_ID_MATCH_VENDOR | USB_DEVICE_ID_MATCH_PRODUCT;
-+ generic_device_ids[1].idVendor = 0xaf0;
-+ generic_device_ids[1].idProduct = 0x5000;
-+ generic_device_ids[1].match_flags = USB_DEVICE_ID_MATCH_VENDOR | USB_DEVICE_ID_MATCH_PRODUCT;
-+ generic_device_ids[2].idVendor = 0xaf0;
-+ generic_device_ids[2].idProduct = 0x6000;
-+ generic_device_ids[2].match_flags = USB_DEVICE_ID_MATCH_VENDOR | USB_DEVICE_ID_MATCH_PRODUCT;
-+ generic_device_ids[3].idVendor = 0xaf0;
-+ generic_device_ids[3].idProduct = 0x6300;
-+ generic_device_ids[3].match_flags = USB_DEVICE_ID_MATCH_VENDOR | USB_DEVICE_ID_MATCH_PRODUCT;
- /* register our generic driver with ourselves */
- usb_serial_register (&generic_device);
- #endif
diff --git a/recipes/linux/linux-mtx-1-2.4.27/23-mtx-1_watchdog_autotrigger.patch b/recipes/linux/linux-mtx-1-2.4.27/23-mtx-1_watchdog_autotrigger.patch
deleted file mode 100644
index c6bb0aae68..0000000000
--- a/recipes/linux/linux-mtx-1-2.4.27/23-mtx-1_watchdog_autotrigger.patch
+++ /dev/null
@@ -1,98 +0,0 @@
---- linux/arch/mips/au1000/mtx-1/mtx-1_watchdog.c.orig 2005-03-22 17:18:01.000000000 +0100
-+++ linux/arch/mips/au1000/mtx-1/mtx-1_watchdog.c 2005-07-06 12:10:06.000000000 +0200
-@@ -39,6 +39,7 @@
- #include <linux/watchdog.h>
- #include <linux/slab.h>
- #include <linux/init.h>
-+#include <asm/uaccess.h>
-
- #include <asm/au1000.h>
-
-@@ -115,6 +116,8 @@
-
- //---------[ File Functions ]-----------------
-
-+static char restart_after_close;
-+
- static int mtx1wd_open (struct inode *inode, struct file *file)
- {
- if (MINOR(inode->i_rdev)!=WATCHDOG_MINOR) return -ENODEV;
-@@ -134,6 +137,10 @@
-
- static int mtx1wd_release (struct inode *inode, struct file *file) {
- if (MINOR(inode->i_rdev)==WATCHDOG_MINOR) {
-+
-+ if (restart_after_close)
-+ start_wd_timer ();
-+
- }
- MOD_DEC_USE_COUNT;
- return 0;
-@@ -141,22 +148,53 @@
-
-
- static ssize_t mtx1wd_write (struct file *file, const char *buf, size_t count, loff_t *ppos) {
-- if (ppos!=&file->f_pos)
-- return -ESPIPE;
-
-- if (count) {
- mtx1_trigger_wd ();
-- return 1;
-+
-+ if (count > 0) {
-+ char buffer[10];
-+ int n = (count>9)?9:count;
-+
-+ if (copy_from_user (&buffer, buf, n))
-+ return -EFAULT;
-+ buffer[n]=0;
-+
-+ if (count >= 4 && strncmp("auto", buffer, 4)==0)
-+ restart_after_close = 1;
-+
-+ else if (count >= 6 && strncmp("manual", buffer, 6)==0)
-+ restart_after_close = 0;
-+
-+ return n;
- }
- return 0;
- }
-
-
-+static ssize_t mtx1wd_read (struct file *file, char *buf, size_t count, loff_t *ppos)
-+{
-+ char * state = restart_after_close ? "auto\n" : "manual\n";
-+ int n = strlen(state)+1;
-+
-+ if (file->f_pos >= n)
-+ return 0;
-+
-+ if (count < n)
-+ return -EINVAL;
-+
-+ if(copy_to_user(buf, state, n))
-+ return -EFAULT;
-+
-+ file->f_pos += n;
-+
-+ return n;
-+}
-+
-
- static struct file_operations mtx1wd_fops = {
- .owner = THIS_MODULE,
- .llseek = NULL,
-- .read = NULL,
-+ .read = mtx1wd_read,
- .write = mtx1wd_write,
- .readdir = NULL,
- .poll = NULL,
-@@ -194,6 +232,8 @@
- {
- printk("MTX-1 watchdog driver\n");
-
-+ restart_after_close = 0;
-+
- mtx1_enable_wd ();
-
- //-- trigger it for the first time.
diff --git a/recipes/linux/linux-mtx-1-2.4.27/24-mtx-1_sysbtn.patch b/recipes/linux/linux-mtx-1-2.4.27/24-mtx-1_sysbtn.patch
deleted file mode 100644
index 9c0808942a..0000000000
--- a/recipes/linux/linux-mtx-1-2.4.27/24-mtx-1_sysbtn.patch
+++ /dev/null
@@ -1,257 +0,0 @@
-diff -Nru linux-old/arch/mips/au1000/mtx-1/Makefile linux/arch/mips/au1000/mtx-1/Makefile
---- linux-old/arch/mips/au1000/mtx-1/Makefile 2005-07-19 18:59:27.000000000 +0200
-+++ linux/arch/mips/au1000/mtx-1/Makefile 2005-07-07 10:15:01.000000000 +0200
-@@ -15,6 +15,6 @@
-
- O_TARGET := mtx-1.o
-
--obj-y := init.o board_setup.o irqmap.o mtx-1_watchdog.o
-+obj-y := init.o board_setup.o irqmap.o mtx-1_watchdog.o mtx-1_sysbtn.o
-
- include $(TOPDIR)/Rules.make
-diff -Nru linux-old/arch/mips/au1000/mtx-1/irqmap.c linux/arch/mips/au1000/mtx-1/irqmap.c
---- linux-old/arch/mips/au1000/mtx-1/irqmap.c 2005-07-19 17:42:05.000000000 +0200
-+++ linux/arch/mips/au1000/mtx-1/irqmap.c 2005-07-06 13:37:25.000000000 +0200
-@@ -50,10 +50,11 @@
- /* Need to define this.
- */
- au1xxx_irq_map_t au1xxx_irq_map[] = {
-+ { AU1500_GPIO_207, INTC_INT_RISE_AND_FALL_EDGE, 0 },
- { 0, 0, 0}
- };
-
--int au1xxx_nr_irqs = 0;
-+int au1xxx_nr_irqs = 1;
-
- #ifdef CONFIG_PCI
-
-diff -Nru linux-old/arch/mips/au1000/mtx-1/mtx-1_sysbtn.c linux/arch/mips/au1000/mtx-1/mtx-1_sysbtn.c
---- linux-old/arch/mips/au1000/mtx-1/mtx-1_sysbtn.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux/arch/mips/au1000/mtx-1/mtx-1_sysbtn.c 2005-07-07 10:29:24.000000000 +0200
-@@ -0,0 +1,226 @@
-+/*
-+ * Driver for the MTX-1 System Button.
-+ *
-+ * (c) Copyright 2005 4G Systems <info@4g-systems.biz>, All Rights Reserved.
-+ * http://www.4g-systems.biz
-+ *
-+ * 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.
-+ *
-+ * Neither Michael Stickel nor 4G Systeme GmbH admit liability nor provide
-+ * warranty for any of this software. This material is provided
-+ * "AS-IS" and at no charge.
-+ *
-+ * (c) Copyright 2005 4G Systems <info@4g-systems.biz>
-+ *
-+ * Release 0.01.
-+ *
-+ * Author: Michael Stickel michael.stickel@4g-systems.biz
-+ *
-+ *
-+ * After the module is loaded there is a device /dev/misc/btn
-+ * that can be read. It returns one char '1' if the button
-+ * has been pressed an '0' if it has been released.
-+ */
-+#include <linux/config.h>
-+#include <linux/module.h>
-+#include <linux/version.h>
-+#include <linux/types.h>
-+#include <linux/errno.h>
-+#include <linux/kernel.h>
-+#include <linux/poll.h>
-+#include <linux/sched.h>
-+#include <linux/miscdevice.h>
-+#include <linux/slab.h>
-+#include <linux/init.h>
-+#include <linux/irq.h>
-+
-+#include <asm/uaccess.h>
-+
-+#include <asm/au1000.h>
-+
-+
-+#ifndef FALSE
-+# define FALSE (0)
-+#endif
-+
-+#ifndef TRUE
-+# define TRUE (!FALSE)
-+#endif
-+
-+
-+//---------[ declarations ]-----------------
-+
-+
-+static DECLARE_WAIT_QUEUE_HEAD(mtx1btn_wait_queue);
-+static char state_changed;
-+static char last_value;
-+static char is_inuse;
-+
-+
-+//---------[ Hardware Functions ]-----------------
-+
-+// The MTX-1 Button is attached to GPIO207.
-+#define MTX1_GPIO2_SYSBTN (7)
-+#define MTX1_SYSBTN_IRQ (AU1500_GPIO_207)
-+
-+
-+static char mtx1_getbtn (int btnno)
-+{
-+ if (btnno==0) {
-+ return (au_readl(GPIO2_PINSTATE) & (1<<MTX1_GPIO2_SYSBTN)) ? 0 : 1;
-+ }
-+ return 0;
-+}
-+
-+static void mtx1_initbuttons (void)
-+{
-+ au_writel (au_readl(GPIO2_DIR) & ~(1<<MTX1_GPIO2_SYSBTN), GPIO2_DIR);
-+}
-+
-+
-+//---------[ Interrupt handling ]-----------------
-+
-+
-+static void mtx1_btn_interrupt (int irq, void *private, struct pt_regs *regs)
-+{
-+ char value = mtx1_getbtn(0);
-+ if (last_value != value)
-+ {
-+ last_value = value;
-+ state_changed = 1;
-+ wake_up (&mtx1btn_wait_queue);
-+ }
-+// kill_fasync(&async_queue, SIGIO, POLL_OUT);
-+}
-+
-+
-+static int mtx1_btn_startirq (void)
-+{
-+ if (!request_irq (MTX1_SYSBTN_IRQ, mtx1_btn_interrupt, 0 /* | SA_INTERRUPT */, "mtx1btn", (void *)&state_changed)) {
-+ return 0;
-+ }
-+ return -1;
-+}
-+
-+static int mtx1_btn_stopirq (void)
-+{
-+ free_irq(MTX1_SYSBTN_IRQ, (void *)&state_changed);
-+ return 0;
-+}
-+
-+
-+
-+//---------[ File Functions ]-----------------
-+
-+
-+static int mtx1sysbtn_minor = -1;
-+
-+
-+static int mtx1sysbtn_open (struct inode *inode, struct file *file)
-+{
-+ if (MINOR(inode->i_rdev)!=mtx1sysbtn_minor) return -ENODEV;
-+ if (is_inuse) return -EBUSY;
-+ is_inuse=1;
-+ last_value = mtx1_getbtn(0);
-+ state_changed = 0;
-+ MOD_INC_USE_COUNT;
-+ return 0;
-+}
-+
-+
-+static int mtx1sysbtn_release (struct inode *inode, struct file *file) {
-+ if (MINOR(inode->i_rdev)==mtx1sysbtn_minor) {
-+ is_inuse=0;
-+ }
-+ MOD_DEC_USE_COUNT;
-+ return 0;
-+}
-+
-+
-+static ssize_t mtx1sysbtn_read (struct file *file, char *buf, size_t count, loff_t *ppos)
-+{
-+ if (count < 1)
-+ return -EINVAL;
-+ if (!state_changed)
-+ interruptible_sleep_on (&mtx1btn_wait_queue);
-+ state_changed = 0;
-+ char c = last_value ? '1' : '0'; /* mtx1_getbtn(0) */
-+ if(copy_to_user(buf, &c, 1))
-+ return -EFAULT;
-+ return 1;
-+}
-+
-+
-+static unsigned int mtx1sysbtn_poll (struct file *file, poll_table * wait)
-+{
-+ unsigned int mask = 0;
-+
-+ poll_wait (file, &mtx1btn_wait_queue, wait);
-+
-+ if (state_changed) // state changed since last time.
-+ mask |= POLLIN | POLLRDNORM;
-+
-+ return mask;
-+}
-+
-+
-+static struct file_operations mtx1sysbtn_fops = {
-+ .owner = THIS_MODULE,
-+ .llseek = NULL,
-+ .read = mtx1sysbtn_read,
-+ .write = NULL,
-+ .readdir = NULL,
-+ .poll = mtx1sysbtn_poll,
-+ .ioctl = NULL,
-+ .mmap = NULL,
-+ .open = mtx1sysbtn_open,
-+ .flush = NULL,
-+ .release = mtx1sysbtn_release
-+};
-+
-+
-+static struct miscdevice mtx1sysbtn_miscdev = {
-+ MISC_DYNAMIC_MINOR /* SYSBTN_MINOR */ ,
-+ "btn",
-+ &mtx1sysbtn_fops
-+};
-+
-+
-+
-+//---------[ Module Functions ]-----------------
-+
-+
-+void __exit cleanup_mtx1_sysbtn (void)
-+{
-+ is_inuse = 1;
-+ mtx1_btn_stopirq ();
-+ misc_deregister(&mtx1sysbtn_miscdev);
-+}
-+
-+
-+int __init init_mtx1_sysbtn (void)
-+{
-+ printk("MTX-1 System Button driver\n");
-+ is_inuse = 1;
-+ mtx1_initbuttons ();
-+ if (misc_register (&mtx1sysbtn_miscdev) >= 0) {
-+ mtx1sysbtn_minor = mtx1sysbtn_miscdev.minor;
-+ if (mtx1_btn_startirq () == 0) {
-+ is_inuse=0;
-+ return 0;
-+ }
-+ misc_deregister(&mtx1sysbtn_miscdev);
-+ }
-+ return 1;
-+}
-+
-+__initcall(init_mtx1_sysbtn);
-+__exitcall(cleanup_mtx1_sysbtn);
-+
-+MODULE_AUTHOR("Michael Stickel");
-+MODULE_DESCRIPTION("Driver for the MTX-1 system button");
-+MODULE_LICENSE("GPL");
-+EXPORT_NO_SYMBOLS;
diff --git a/recipes/linux/linux-mtx-1-2.4.27/25-mtx-sio2.diff b/recipes/linux/linux-mtx-1-2.4.27/25-mtx-sio2.diff
deleted file mode 100644
index 4f4775a960..0000000000
--- a/recipes/linux/linux-mtx-1-2.4.27/25-mtx-sio2.diff
+++ /dev/null
@@ -1,12 +0,0 @@
---- linux.old/arch/mips/au1000/mtx-1/board_setup.c 2005-08-10 15:22:14.014147000 +0200
-+++ linux/arch/mips/au1000/mtx-1/board_setup.c 2005-08-10 15:26:34.346571264 +0200
-@@ -78,8 +78,7 @@
-
- // initialize sys_pinfunc:
- // disable second ethernet port (SYS_PF_NI2)
-- // set U3/GPIO23 to GPIO23 (SYS_PF_U3)
-- au_writel( SYS_PF_NI2 | SYS_PF_U3, SYS_PINFUNC );
-+ au_writel( SYS_PF_NI2, SYS_PINFUNC );
-
- // initialize GPIO
- au_writel( 0xFFFFFFFF, SYS_TRIOUTCLR );
diff --git a/recipes/linux/linux-mtx-1-2.4.27/26-usbd-amd-pb1x00-kit-23may2003-update.diff b/recipes/linux/linux-mtx-1-2.4.27/26-usbd-amd-pb1x00-kit-23may2003-update.diff
deleted file mode 100644
index feaf08c563..0000000000
--- a/recipes/linux/linux-mtx-1-2.4.27/26-usbd-amd-pb1x00-kit-23may2003-update.diff
+++ /dev/null
@@ -1,130 +0,0 @@
-diff -Nru a/arch/mips/au1000/common/irq.c b/arch/mips/au1000/common/irq.c
---- a/arch/mips/au1000/common/irq.c Fri Feb 27 14:22:51 2004
-+++ b/arch/mips/au1000/common/irq.c Fri Feb 27 14:22:51 2004
-@@ -458,7 +458,14 @@
- intc0_req0 |= au_readl(IC0_REQ0INT);
-
- if (!intc0_req0) return;
--
-+#if 0
-+ /*
-+ * This is no longer required. The find first bit operation
-+ * is almost as fast at finding the correct interrupt, whereas
-+ * leaving this in adds a small amount of overhead to all other
-+ * interrupts and therefore induces more latency which may
-+ * actually cause USB problems.
-+ */
- /*
- * Because of the tight timing of SETUP token to reply
- * transactions, the USB devices-side packet complete
-@@ -469,7 +476,7 @@
- do_IRQ(AU1000_USB_DEV_REQ_INT, regs);
- return;
- }
--
-+#endif
- irq = au_ffs(intc0_req0) - 1;
- intc0_req0 &= ~(1<<irq);
- do_IRQ(irq, regs);
-diff -Nru a/arch/mips/defconfig-bosporus b/arch/mips/defconfig-bosporus
---- a/arch/mips/defconfig-bosporus Fri Feb 27 14:22:51 2004
-+++ b/arch/mips/defconfig-bosporus Fri Feb 27 14:22:51 2004
-@@ -606,8 +606,6 @@
- # CONFIG_SERIAL_TXX9_CONSOLE is not set
- CONFIG_AU1X00_UART=y
- CONFIG_AU1X00_SERIAL_CONSOLE=y
--# CONFIG_AU1X00_USB_TTY is not set
--# CONFIG_AU1X00_USB_RAW is not set
- # CONFIG_TXX927_SERIAL is not set
- CONFIG_UNIX98_PTYS=y
- CONFIG_UNIX98_PTY_COUNT=256
-diff -Nru a/arch/mips/defconfig-db1000 b/arch/mips/defconfig-db1000
---- a/arch/mips/defconfig-db1000 Fri Feb 27 14:22:51 2004
-+++ b/arch/mips/defconfig-db1000 Fri Feb 27 14:22:51 2004
-@@ -509,8 +509,6 @@
- # CONFIG_SERIAL_TXX9_CONSOLE is not set
- CONFIG_AU1X00_UART=y
- CONFIG_AU1X00_SERIAL_CONSOLE=y
--# CONFIG_AU1X00_USB_TTY is not set
--# CONFIG_AU1X00_USB_RAW is not set
- # CONFIG_TXX927_SERIAL is not set
- CONFIG_UNIX98_PTYS=y
- CONFIG_UNIX98_PTY_COUNT=256
-diff -Nru a/arch/mips/defconfig-db1100 b/arch/mips/defconfig-db1100
---- a/arch/mips/defconfig-db1100 Fri Feb 27 14:22:51 2004
-+++ b/arch/mips/defconfig-db1100 Fri Feb 27 14:22:51 2004
-@@ -516,8 +516,6 @@
- # CONFIG_SERIAL_TXX9_CONSOLE is not set
- CONFIG_AU1X00_UART=y
- CONFIG_AU1X00_SERIAL_CONSOLE=y
--# CONFIG_AU1X00_USB_TTY is not set
--# CONFIG_AU1X00_USB_RAW is not set
- # CONFIG_TXX927_SERIAL is not set
- CONFIG_UNIX98_PTYS=y
- CONFIG_UNIX98_PTY_COUNT=256
-diff -Nru a/arch/mips/defconfig-db1500 b/arch/mips/defconfig-db1500
---- a/arch/mips/defconfig-db1500 Fri Feb 27 14:22:51 2004
-+++ b/arch/mips/defconfig-db1500 Fri Feb 27 14:22:51 2004
-@@ -506,8 +506,6 @@
- # CONFIG_SERIAL_TXX9_CONSOLE is not set
- CONFIG_AU1X00_UART=y
- CONFIG_AU1X00_SERIAL_CONSOLE=y
--# CONFIG_AU1X00_USB_TTY is not set
--# CONFIG_AU1X00_USB_RAW is not set
- # CONFIG_TXX927_SERIAL is not set
- CONFIG_UNIX98_PTYS=y
- CONFIG_UNIX98_PTY_COUNT=256
-diff -Nru a/arch/mips/defconfig-pb1000 b/arch/mips/defconfig-pb1000
---- a/arch/mips/defconfig-pb1000 Fri Feb 27 14:22:51 2004
-+++ b/arch/mips/defconfig-pb1000 Fri Feb 27 14:22:51 2004
-@@ -569,8 +569,6 @@
- # CONFIG_SERIAL_TXX9_CONSOLE is not set
- CONFIG_AU1X00_UART=y
- CONFIG_AU1X00_SERIAL_CONSOLE=y
--# CONFIG_AU1X00_USB_TTY is not set
--# CONFIG_AU1X00_USB_RAW is not set
- # CONFIG_TXX927_SERIAL is not set
- CONFIG_UNIX98_PTYS=y
- CONFIG_UNIX98_PTY_COUNT=256
-diff -Nru a/arch/mips/defconfig-pb1100 b/arch/mips/defconfig-pb1100
---- a/arch/mips/defconfig-pb1100 Fri Feb 27 14:22:51 2004
-+++ b/arch/mips/defconfig-pb1100 Fri Feb 27 14:22:51 2004
-@@ -515,8 +515,6 @@
- # CONFIG_SERIAL_TXX9_CONSOLE is not set
- CONFIG_AU1X00_UART=y
- CONFIG_AU1X00_SERIAL_CONSOLE=y
--# CONFIG_AU1X00_USB_TTY is not set
--# CONFIG_AU1X00_USB_RAW is not set
- # CONFIG_TXX927_SERIAL is not set
- CONFIG_UNIX98_PTYS=y
- CONFIG_UNIX98_PTY_COUNT=256
-diff -Nru a/arch/mips/defconfig-pb1500 b/arch/mips/defconfig-pb1500
---- a/arch/mips/defconfig-pb1500 Fri Feb 27 14:22:51 2004
-+++ b/arch/mips/defconfig-pb1500 Fri Feb 27 14:22:51 2004
-@@ -619,8 +619,6 @@
- # CONFIG_SERIAL_TXX9_CONSOLE is not set
- CONFIG_AU1X00_UART=y
- CONFIG_AU1X00_SERIAL_CONSOLE=y
--# CONFIG_AU1X00_USB_TTY is not set
--# CONFIG_AU1X00_USB_RAW is not set
- # CONFIG_TXX927_SERIAL is not set
- CONFIG_UNIX98_PTYS=y
- CONFIG_UNIX98_PTY_COUNT=256
-diff -Nru a/drivers/char/Config.in b/drivers/char/Config.in
---- a/drivers/char/Config.in Fri Feb 27 14:22:51 2004
-+++ b/drivers/char/Config.in Fri Feb 27 14:22:51 2004
-@@ -91,14 +91,6 @@
- if [ "$CONFIG_AU1X00_UART" = "y" ]; then
- bool ' Enable Au1x00 serial console' CONFIG_AU1X00_SERIAL_CONSOLE
- fi
-- dep_tristate ' Au1x00 USB TTY Device support' CONFIG_AU1X00_USB_TTY $CONFIG_SOC_AU1X00
-- if [ "$CONFIG_AU1000_USB_TTY" != "y" ]; then
-- dep_tristate ' Au1x00 USB Raw Device support' CONFIG_AU1X00_USB_RAW $CONFIG_SOC_AU1X00
-- fi
-- if [ "$CONFIG_AU1X00_USB_TTY" != "n" -o \
-- "$CONFIG_AU1X00_USB_RAW" != "n" ]; then
-- define_bool CONFIG_AU1X00_USB_DEVICE y
-- fi
- fi
- bool ' TXx927 SIO support' CONFIG_TXX927_SERIAL
- if [ "$CONFIG_TXX927_SERIAL" = "y" ]; then
diff --git a/recipes/linux/linux-mtx-1-2.4.27/27-usbd-amd-pb1x00-kit-23may2003-usbd.diff b/recipes/linux/linux-mtx-1-2.4.27/27-usbd-amd-pb1x00-kit-23may2003-usbd.diff
deleted file mode 100644
index 7766f71846..0000000000
--- a/recipes/linux/linux-mtx-1-2.4.27/27-usbd-amd-pb1x00-kit-23may2003-usbd.diff
+++ /dev/null
@@ -1,15816 +0,0 @@
-/home/sl/USB/PB1500/work/usbd-gpl/kits/amd-pb1x00-kit/amd-pb1x00-linux-2.4.21
-diff -Nru a/arch/mips/config-shared.in b/arch/mips/config-shared.in
---- a/arch/mips/config-shared.in Fri Feb 27 14:22:51 2004
-+++ b/arch/mips/config-shared.in Fri Feb 27 14:22:51 2004
-@@ -985,6 +985,7 @@
- endmenu
-
- source drivers/usb/Config.in
-+source drivers/usbd/Config.in
-
- source net/bluetooth/Config.in
-
---- a/drivers/Makefile 2005-08-15 18:51:50.332030952 +0200
-+++ b/drivers/Makefile 2005-08-15 18:53:08.938081016 +0200
-@@ -41,6 +41,7 @@
- subdir-$(CONFIG_ISDN_BOOL) += isdn
- subdir-$(CONFIG_ATM) += atm
- subdir-$(CONFIG_FC4) += fc4
-+subdir-$(CONFIG_USBD) += usbd
-
- # CONFIG_HAMRADIO can be set without CONFIG_NETDEVICE being set -- ch
- subdir-$(CONFIG_HAMRADIO) += net/hamradio
-diff -Nru a/drivers/usbd/Config.in b/drivers/usbd/Config.in
---- /dev/null Wed Dec 31 16:00:00 1969
-+++ b/drivers/usbd/Config.in Fri Feb 27 14:22:51 2004
-@@ -0,0 +1,58 @@
-+#
-+# USB device configuration from the device viewpoint (e.g. Linux running inside a USB device, not as host)
-+#
-+# Copyright (c) 2002-2003 Belcarra
-+#
-+#
-+
-+mainmenu_option next_comment
-+
-+comment 'USB clients (devices, not hosts)'
-+
-+tristate 'Support for USB Clients (USB Device, not USB Host)' CONFIG_USBD
-+
-+if [ "$CONFIG_USBD" = "y" -o "$CONFIG_USBD" = "m" ]; then
-+ comment ''
-+ bool ' Enable High Speed Descriptors' CONFIG_USBD_HIGH_SPEED
-+
-+ bool ' Do Not Use Serial Number in Device Descriptor (Default is no' CONFIG_USBD_NO_SERIAL_NUMBER
-+ if [ "$CONFIG_USBD_NO_SERIAL_NUMBER" != "y" ]; then
-+ string ' Default Serial number (string)' CONFIG_USBD_SERIAL_NUMBER_STR ""
-+ fi
-+
-+ int ' Max Power (mA) (Default is zero, whick is self powered)' CONFIG_USBD_MAXPOWER "0"
-+
-+ comment ''
-+
-+ bool ' USBD Proc FS' CONFIG_USBD_PROCFS
-+
-+ tristate ' USBD Proc FS Module' CONFIG_USBD_PROCFSM $CONFIG_USBD
-+
-+ comment 'Function Drivers'
-+
-+ source drivers/usbd/network_fd/Config.in
-+ source drivers/usbd/acm_fd/Config.in
-+
-+ source drivers/usbd/mouse_fd/Config.in
-+
-+ comment 'Bus Interface'
-+
-+ source drivers/usbd/au1x00_bi/Config.in
-+
-+ bool ' USB Device Register Tracing' CONFIG_USBD_BI_REGISTER_TRACE
-+ if [ "$CONFIG_USBD" = "y" ]; then
-+ bool ' USB Device Manual Enable' CONFIG_USBD_BI_DELAY_ENABLE
-+ fi
-+
-+
-+ #source drivers/usbd/l7205_bi/Config.in
-+ #source drivers/usbd/sl11_bi/Config.in
-+
-+ #source drivers/usbd/cdc_fd/Config.in
-+ #source drivers/usbd/serialnumber/Config.in
-+ #source drivers/usbd/audio_fd/Config.in
-+ #source drivers/usbd/eg_fd/Config.in
-+ #source drivers/usbd/keyboard_fd/Config.in
-+fi
-+
-+endmenu
-diff -Nru a/drivers/usbd/Makefile b/drivers/usbd/Makefile
---- /dev/null Wed Dec 31 16:00:00 1969
-+++ b/drivers/usbd/Makefile Fri Feb 27 14:22:51 2004
-@@ -0,0 +1,157 @@
-+#
-+# Makefile for the kernel USBD (device not host) drivers.
-+#
-+# Copyright (c) 2002 Belcarra
-+# Copyright (C) 2001 Lineo, Inc.
-+# Copyright (C) 2001 Hewlett-Packard Co.
-+
-+# Subdirs.
-+# This is a bit complex, because some subdirs are for
-+# proprietary code, and are simply not present in a
-+# general distribution.
-+
-+TOPDIR ?= ../../..
-+
-+# The all-CAPS *_DIRS get nuked in the new versions
-+# of Rules.make, so use only the subdir-* methods.
-+subdir-y :=
-+subdir-m :=
-+subdir-n :=
-+subdir- :=
-+
-+# Function Drivers
-+subdir-$(CONFIG_USBD_ACM) += acm_fd
-+subdir-$(CONFIG_USBD_MOUSE) += mouse_fd
-+subdir-$(CONFIG_USBD_NETWORK) += network_fd
-+
-+#subdir-$(CONFIG_USBD_AUDIO) += audio_fd
-+#subdir-$(CONFIG_USBD_EG) += eg_fd
-+#subdir-$(CONFIG_USBD_KEYBOARD) += keyboard_fd
-+#subdir-$(CONFIG_USBD_CDC) += cdc_fd
-+
-+# Bus Interface Drivers
-+subdir-$(CONFIG_USBD_AU1X00_BUS) += au1x00_bi
-+
-+#subdir-$(CONFIG_USBD_OMAP_BUS) += omap_bi
-+#subdir-$(CONFIG_USBD_TC86C001_BUS) += tc86c001_bi
-+
-+#subdir-$(CONFIG_USBD_SL11_BUS) += sl11_bi
-+
-+# The target object and module list name.
-+
-+O_TARGET := usbdev.o
-+
-+# Objects that export symbols.
-+
-+export-objs := usbd.o usbd-bops.o usbd-fops.o usbd-bi.o ep0.o
-+
-+# Multipart objects.
-+
-+list-multi := usbdcore.o
-+usbdcore-objs := usbd.o ep0.o usbd-fops.o usbd-bops.o
-+usbdprocfs-objs := usbd-procfs.o
-+
-+
-+# Optional parts of multipart objects.
-+
-+# Object file lists.
-+
-+obj-y :=
-+obj-m :=
-+obj-n :=
-+obj- :=
-+
-+# Each configuration option enables a list of files.
-+
-+obj-$(CONFIG_USBD) += usbdcore.o
-+obj-$(CONFIG_USBD_PROCFSM) += usbdprocfs.o
-+
-+# Object files in subdirectories
-+
-+#
-+obj-$(CONFIG_USBD_MONITOR) += monitor/monitor.o
-+
-+obj-$(CONFIG_USBD_ACM) += acm_fd/acm_fd.o
-+obj-$(CONFIG_USBD_MOUSE) += mouse_fd/mouse_fd.o
-+obj-$(CONFIG_USBD_NETWORK) += network_fd/network_fd.o
-+
-+#obj-$(CONFIG_USBD_AUDIO) += audio_fd/audio_fd.o
-+#obj-$(CONFIG_USBD_EG) += eg_fd/eg_fd.o
-+#obj-$(CONFIG_USBD_KEYBOARD) += keyboard_fd/keyboard_fd.o
-+
-+# Bus Interface Drivers
-+obj-$(CONFIG_USBD_AU1X00_BUS) += au1x00_bi/au1x00_bi.o
-+
-+#obj-$(CONFIG_USBD_OMAP_BUS) += omap_bi/omap_bi.o
-+#obj-$(CONFIG_USBD_TC86C001_BUS) += tc86c001_bi/tc86c001_bi.o
-+
-+#obj-$(CONFIG_USBD_SL11_BUS) += sl11_bi/sl11_bi.o
-+
-+
-+# Yech. This isn't the best way to do this, but there isn't a config flag
-+# common to all the possible bus interfaces
-+
-+
-+# Extract lists of the multi-part drivers.
-+# The 'int-*' lists are the intermediate files used to build the multi's.
-+
-+multi-y := $(filter $(list-multi), $(obj-y))
-+multi-m := $(filter $(list-multi), $(obj-m))
-+int-y := $(sort $(foreach m, $(multi-y), $($(basename $(m))-objs)))
-+int-m := $(sort $(foreach m, $(multi-m), $($(basename $(m))-objs)))
-+
-+# Files that are both resident and modular: remove from modular.
-+
-+obj-m := $(filter-out $(obj-y), $(obj-m))
-+int-m := $(filter-out $(int-y), $(int-m))
-+
-+# Translate to Rules.make lists.
-+
-+O_OBJS := $(filter-out $(export-objs), $(obj-y))
-+OX_OBJS := $(filter $(export-objs), $(obj-y))
-+M_OBJS := $(sort $(filter-out $(export-objs), $(obj-m)))
-+MX_OBJS := $(sort $(filter $(export-objs), $(obj-m)))
-+MI_OBJS := $(sort $(filter-out $(export-objs), $(int-m)))
-+MIX_OBJS := $(sort $(filter $(export-objs), $(int-m)))
-+
-+# The global Rules.make.
-+
-+include $(TOPDIR)/Rules.make
-+EXTRA_CFLAGS += -Wno-format -Wall
-+
-+# Link rules for multi-part drivers.
-+
-+usbdprocfs.o: $(usbdprocfs-objs)
-+ $(LD) -r -o $@ $(usbdprocfs-objs)
-+
-+usbdcore.o: $(usbdcore-objs)
-+ $(LD) -r -o $@ $(usbdcore-objs)
-+
-+# dependencies:
-+
-+usbd.o: usbd-build.h
-+
-+usbd-build.h:
-+ echo "#define USBD_BUILD \"000\"" > $@
-+
-+# local
-+
-+%.h:%.p
-+ release inc build < $< > $@
-+ cp $@ $<
-+
-+release.h: release.p
-+
-+inc-build:
-+ release inc build < release.p > release.h
-+ cp release.h release.p
-+
-+
-+menuconfig:
-+ cd $(TOPDIR); make menuconfig
-+
-+xconfig:
-+ cd $(TOPDIR); make xconfig
-+
-+
-+
-diff -Nru a/drivers/usbd/acm_fd/Config.in b/drivers/usbd/acm_fd/Config.in
---- /dev/null Wed Dec 31 16:00:00 1969
-+++ b/drivers/usbd/acm_fd/Config.in Fri Feb 27 14:22:51 2004
-@@ -0,0 +1,27 @@
-+#
-+# CDC ACM Function Driver
-+#
-+# Copyright (C) 2003,2004 Belcarra
-+#
-+
-+mainmenu_option next_comment
-+comment "CDC ACM Function"
-+
-+dep_tristate ' CDC ACM Function' CONFIG_USBD_ACM $CONFIG_USBD
-+if [ "$CONFIG_USBD_ACM" = "y" -o "$CONFIG_USBD_ACM" = "m" ]; then
-+ hex 'VendorID (hex value)' CONFIG_USBD_ACM_VENDORID "12b9"
-+ hex 'ProductID (hex value)' CONFIG_USBD_ACM_PRODUCTID "f002"
-+ hex 'bcdDevice (binary-coded decimal)' CONFIG_USBD_ACM_BCDDEVICE "0100"
-+
-+ string 'iManufacturer (string)' CONFIG_USBD_ACM_MANUFACTURER "Belcarra"
-+ string 'iProduct (string)' CONFIG_USBD_ACM_PRODUCT_NAME "Belcarra ACM Device"
-+
-+ string 'iConfiguration (string)' CONFIG_USBD_ACM_DESC "Acm Cfg"
-+ string 'Comm Interface iInterface (string)' CONFIG_USBD_ACM_COMM_INTF "Comm Intf"
-+ string 'Data Interface iInterface (string)' CONFIG_USBD_ACM_DATA_INTF "Data Intf"
-+
-+ bool ' ACM Tracing' CONFIG_USBD_ACM_TRACE
-+ comment ''
-+fi
-+
-+endmenu
-diff -Nru a/drivers/usbd/acm_fd/Makefile b/drivers/usbd/acm_fd/Makefile
---- /dev/null Wed Dec 31 16:00:00 1969
-+++ b/drivers/usbd/acm_fd/Makefile Fri Feb 27 14:22:51 2004
-@@ -0,0 +1,65 @@
-+#
-+# Function driver for a CDC ACM USB Device
-+#
-+# Copyright (c) 2003 Belcarra
-+
-+# Multipart objects.
-+
-+O_TARGET := acm_fd.o
-+list-multi := acm_fd.o
-+
-+acm_fd-objs := acm.o trace.o
-+
-+# Objects that export symbols.
-+export-objs := acm.o
-+
-+# Object file lists.
-+
-+obj-y :=
-+obj-m :=
-+obj-n :=
-+obj- :=
-+
-+# Each configuration option enables a list of files.
-+
-+obj-$(CONFIG_USBD_ACM) += acm_fd.o
-+
-+# Extract lists of the multi-part drivers.
-+# The 'int-*' lists are the intermediate files used to build the multi's.
-+
-+multi-y := $(filter $(list-multi), $(obj-y))
-+multi-m := $(filter $(list-multi), $(obj-m))
-+int-y := $(sort $(foreach m, $(multi-y), $($(basename $(m))-objs)))
-+int-m := $(sort $(foreach m, $(multi-m), $($(basename $(m))-objs)))
-+
-+# Files that are both resident and modular: remove from modular.
-+
-+obj-m := $(filter-out $(obj-y), $(obj-m))
-+int-m := $(filter-out $(int-y), $(int-m))
-+
-+# Translate to Rules.make lists.
-+
-+O_OBJS := $(filter-out $(export-objs), $(obj-y))
-+OX_OBJS := $(filter $(export-objs), $(obj-y))
-+M_OBJS := $(sort $(filter-out $(export-objs), $(obj-m)))
-+MX_OBJS := $(sort $(filter $(export-objs), $(obj-m)))
-+MI_OBJS := $(sort $(filter-out $(export-objs), $(int-m)))
-+MIX_OBJS := $(sort $(filter $(export-objs), $(int-m)))
-+
-+# The global Rules.make.
-+
-+USBD=$(TOPDIR)/drivers/usbd
-+ACMD=$(USBD)/acm_fd
-+include $(TOPDIR)/Rules.make
-+EXTRA_CFLAGS += -I$(ACMD) -I$(USBD) -Wno-unused -Wno-format
-+EXTRA_CFLAGS_nostdinc += -I$(ACMD) -I$(USBD) -Wno-unused -Wno-format
-+
-+# Link rules for multi-part drivers.
-+
-+acm_fd.o: $(acm_fd-objs)
-+ $(LD) -r -o $@ $(acm_fd-objs)
-+
-+# dependencies:
-+
-+acm.o: $(USBD)/usbd.h $(USBD)/usbd-bus.h $(USBD)/usbd-func.h
-+
-diff -Nru a/drivers/usbd/acm_fd/acm.c b/drivers/usbd/acm_fd/acm.c
---- /dev/null Wed Dec 31 16:00:00 1969
-+++ b/drivers/usbd/acm_fd/acm.c Fri Feb 27 14:22:51 2004
-@@ -0,0 +1,1662 @@
-+/*
-+ * usbd/acm_fd/acm.c
-+ *
-+ * Copyright (c) 2003, 2004 Belcarra
-+ *
-+ * By:
-+ * Stuart Lynne <sl@belcarra.com>,
-+ * Tom Rushworth <tbr@belcarra.com>,
-+ * Bruce Balden <balden@belcarra.com>
-+ *
-+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
-+ *
-+ *
-+ * Note: this function driver requires the following endpoints:
-+ *
-+ * BULK-IN
-+ * BULK-OUT
-+ * INTERRUPT-IN
-+ *
-+ * This function driver cannot be used on devices (such as the StrongArm
-+ * SA1100) that do not have and interrupt endpoint.
-+ *
-+ */
-+
-+
-+#include <linux/config.h>
-+#include <linux/module.h>
-+#include <linux/kernel.h>
-+#include <linux/version.h>
-+
-+#include <usbd-export.h>
-+#include <usbd-build.h>
-+
-+MODULE_AUTHOR ("sl@belcarra.com, tbr@belcarra.com");
-+
-+MODULE_DESCRIPTION ("Belcarra CDC-ACM Function");
-+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,17)
-+MODULE_LICENSE("GPL");
-+#endif
-+
-+#define ACM_TRACE_NAME "acm_trace"
-+
-+#undef USE_TICKER
-+#undef MCEL
-+//#define MCEL 1
-+//#define CONFIG_USBD_ACM_DATALOG 1
-+#undef CONFIG_USBD_ACM_DATALOG
-+#undef PST_FD_AVAILABLE
-+
-+#include <linux/init.h>
-+#include <asm/uaccess.h>
-+#include <linux/ctype.h>
-+#include <linux/timer.h>
-+#include <linux/interrupt.h>
-+#include <asm/atomic.h>
-+#include <linux/tty.h>
-+#include <linux/tty_driver.h>
-+#include <linux/tty_flip.h>
-+#include <linux/smp_lock.h>
-+#include <linux/slab.h>
-+
-+#include <usbd-chap9.h>
-+#include <usbd-mem.h>
-+#include <usbd.h>
-+#include <usbd-func.h>
-+
-+#include "trace.h"
-+// Define the low order 16 bits of an urb's memory address as it's ID for tracing.
-+#define urbID(urb) (0xffff & (u32) (void *) urb)
-+int acm_interrupts;
-+
-+USBD_MODULE_INFO ("acm_fd 2.1-beta");
-+
-+#define MAX_QUEUED_BYTES 256
-+#define MAX_QUEUED_URBS 10 // Max for write
-+
-+#define MAX_RECV_URBS 2 // Max for receiving data
-+#define RECV_RING_SIZE (MAX_RECV_URBS+1)
-+
-+// Endpoint indexes in acm_endpoint_requests[] and the endpoint map.
-+#define BULK_OUT 0x00
-+#define BULK_IN 0x01
-+#define INT_IN 0x02
-+#if !defined(CONFIG_USBD_ACM_DATALOG)
-+#define ENDPOINTS 0x03
-+#else
-+#define DATALOG_BULK_IN 0x03
-+#define ENDPOINTS 0x04
-+#endif
-+
-+#define COMM_INTF 0x00
-+#define DATA_INTF 0x01
-+#if defined(CONFIG_USBD_ACM_DATALOG)
-+#define DATALOG_INTF 0x02
-+#define TESTCMD_INTF 0x03
-+#endif
-+
-+#if defined(CONFIG_USBD_ACM_DATALOG) && defined(PST_FD_AVAILABLE)
-+extern int pst_dev_create(struct usb_device_instance *device);
-+extern void pst_dev_destroy(void);
-+extern void ep0_process_vendor_request( struct urb *urb );
-+extern int pst_urb_sent (struct urb *urb, int rc);
-+#endif
-+
-+/* Module Parameters ************************************************************************* */
-+
-+static u32 vendor_id;
-+static u32 product_id;
-+static u32 max_queued_urbs = MAX_QUEUED_URBS;
-+static u32 max_queued_bytes = MAX_QUEUED_BYTES;
-+
-+MODULE_PARM (vendor_id, "i");
-+MODULE_PARM (product_id, "i");
-+MODULE_PARM (max_queued_urbs, "i");
-+MODULE_PARM (max_queued_bytes, "i");
-+
-+MODULE_PARM_DESC (vendor_id, "Device Vendor ID");
-+MODULE_PARM_DESC (product_id, "Device Product ID");
-+MODULE_PARM_DESC (max_queued_urbs, "Maximum TX Queued Urbs");
-+MODULE_PARM_DESC (max_queued_bytes, "Maximum TX Queued Bytes");
-+
-+/*
-+ * CDC ACM Configuration
-+ *
-+ * Endpoint, Class, Interface, Configuration and Device descriptors/descriptions
-+ */
-+
-+/* Endpoints */
-+static __u8 acm_alt_1[] = { 0x07, USB_DT_ENDPOINT, OUT, BULK, 0, 0x00, 0x00, };
-+static __u8 acm_alt_2[] = { 0x07, USB_DT_ENDPOINT, IN, BULK, 0, 0x00, 0x00, };
-+static struct usb_endpoint_descriptor *acm_alt_endpoints[] = {
-+ (struct usb_endpoint_descriptor *) acm_alt_1,
-+ (struct usb_endpoint_descriptor *) acm_alt_2, };
-+u8 acm_alt_indexes[] = { BULK_OUT, BULK_IN, };
-+
-+static __u8 acm_comm_1[] = { 0x07, USB_DT_ENDPOINT, IN, INTERRUPT, 0, 0x00, 0x0a, };
-+static struct usb_endpoint_descriptor *acm_comm_endpoints[] = { (struct usb_endpoint_descriptor *) acm_comm_1 };
-+u8 acm_comm_indexes[] = { INT_IN, };
-+
-+static __u8 cdc_class_1[] = { 0x05, CS_INTERFACE, USB_ST_HEADER, 0x01, 0x01, /* CLASS_BDC_VERSION, CLASS_BDC_VERSION */ };
-+static __u8 cdc_class_2[] = { 0x05, CS_INTERFACE, USB_ST_CMF, 0x03, 0x01, /* bMasterInterface: 0, bSlaveInterface: 1 */ };
-+static __u8 cdc_class_3[] = { 0x05, CS_INTERFACE, USB_ST_UF, 0x00, 0x01, /* bMasterInterface: 0, bSlaveInterface: 1 */ };
-+
-+/* ACMF - c.f. Table 28
-+ * currenty set to 0x2 - Support Set_Line_Coding etc,
-+ *
-+ * XXX Should we also set 0x4 - Supports Network_Notification?
-+ */
-+static __u8 cdc_class_4[] = { 0x04, CS_INTERFACE, USB_ST_ACMF, 0x02, };
-+
-+static struct usb_generic_class_descriptor *cdc_comm_class_descriptors[] =
-+ { (struct usb_generic_class_descriptor *) cdc_class_1,
-+ (struct usb_generic_class_descriptor *) cdc_class_2,
-+ (struct usb_generic_class_descriptor *) cdc_class_3,
-+ (struct usb_generic_class_descriptor *) cdc_class_4, };
-+
-+
-+#if defined(CONFIG_USBD_ACM_DATALOG)
-+
-+#if 0
-+/* This is used to get a specific INTERFACE number, by padding the list of interfaces. */
-+static struct usb_alternate_description dummy_alternate_descriptions[] = {
-+ { iInterface:"Dummy", },
-+};
-+#endif
-+
-+/* There is no way to request a specific ENDPOINT address, since that depends on
-+ the bus interface hardware. */
-+//#define DATA_LOG_IN_ENDPOINT 11
-+
-+static __u8 datalog_endpoint[] = {
-+ 0x07, // bLength
-+ USB_DT_ENDPOINT, // bDescriptorType // 0x5
-+ /*DATA_LOG_IN_ENDPOINT |*/ IN, // bEndpointAddress
-+ BULK, // bmAttributes
-+ 0, 0x00, // wMaxPacketSize
-+ 0x00, // bInterval
-+};
-+static struct usb_endpoint_descriptor *datalog_endpoints[] = { datalog_endpoint };
-+u8 datalog_indexes[] = { DATALOG_BULK_IN, };
-+
-+
-+// No endpoints needed for TestCmd interface.
-+#endif
-+
-+/* Alternate Descriptors */
-+// First two bytes are identical in all: bLength, bDescriptorType (0x09 0x04)
-+static __u8 cdc_comm_alternate_descriptor[sizeof(struct usb_interface_descriptor)] = {
-+ 0x09, USB_DT_INTERFACE, COMM_INTF, 0x00, 0x00, // bInterfaceNumber, bAlternateSetting, bNumEndpoints
-+ COMMUNICATIONS_INTERFACE_CLASS, COMMUNICATIONS_ACM_SUBCLASS, 0x01, 0x00, };
-+
-+static __u8 cdc_data_alternate_descriptor[sizeof(struct usb_interface_descriptor)] = {
-+ 0x09, USB_DT_INTERFACE, DATA_INTF, 0x00, 0x00, // bInterfaceNumber, bAlternateSetting, bNumEndpoints
-+ DATA_INTERFACE_CLASS, COMMUNICATIONS_NO_SUBCLASS, COMMUNICATIONS_NO_PROTOCOL, 0x00, };
-+
-+
-+#if defined(CONFIG_USBD_ACM_DATALOG)
-+
-+static __u8 datalog_alternate_descriptor[sizeof(struct usb_interface_descriptor)] = {
-+ 0x09, USB_DT_INTERFACE, DATALOG_INTF, 0x00, 0x00, // bInterfaceNumber, bAlternateSetting, bNumEndpoints
-+ // bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol, iInterface
-+ 0xFF, 0x02, 0xFF, 0x00, };
-+
-+static __u8 testcmd_alternate_descriptor[sizeof(struct usb_interface_descriptor)] = {
-+ 0x09, USB_DT_INTERFACE, TESTCMD_INTF, 0x00, 0x00, // bInterfaceNumber, bAlternateSetting, bNumEndpoints
-+ // bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol, iInterface
-+ 0xFF, 0x03, 0xFF, 0x00, };
-+
-+#endif
-+
-+/* Alternate Descriptions */
-+static struct usb_alternate_description cdc_comm_alternate_descriptions[] = {
-+ { iInterface: CONFIG_USBD_ACM_COMM_INTF,
-+ interface_descriptor: (struct usb_interface_descriptor *)&cdc_comm_alternate_descriptor,
-+ classes:sizeof (cdc_comm_class_descriptors) / sizeof (struct usb_generic_class_descriptor *),
-+ class_list: cdc_comm_class_descriptors,
-+ endpoint_list: acm_comm_endpoints,
-+ endpoints:sizeof (acm_comm_endpoints) / sizeof(struct usb_endpoint_descriptor *),
-+ endpoint_indexes: acm_comm_indexes,
-+ }, };
-+
-+static struct usb_alternate_description cdc_data_alternate_descriptions[] = {
-+ { iInterface: CONFIG_USBD_ACM_DATA_INTF,
-+ interface_descriptor: (struct usb_interface_descriptor *)&cdc_data_alternate_descriptor,
-+ endpoint_list: acm_alt_endpoints,
-+ endpoints:sizeof (acm_alt_endpoints) / sizeof(struct usb_endpoint_descriptor *),
-+ endpoint_indexes: acm_alt_indexes,
-+ }, };
-+
-+#if defined(CONFIG_USBD_ACM_DATALOG)
-+
-+static struct usb_alternate_description datalog_alternate_descriptions[] = {
-+ { iInterface:"Motorola MCU Data Logger",
-+ interface_descriptor: (struct usb_interface_descriptor *)&datalog_alternate_descriptor,
-+ endpoint_list: datalog_endpoints,
-+ endpoints:sizeof (datalog_endpoints) / sizeof (struct usb_endpoint_descriptor *),
-+ endpoint_indexes: datalog_indexes,
-+ },
-+};
-+
-+static struct usb_alternate_description testcmd_alternate_descriptions[] = {
-+ { iInterface:"Motorola Test Command",
-+ interface_descriptor: (struct usb_interface_descriptor *)&testcmd_alternate_descriptor,
-+ },
-+};
-+#endif
-+
-+/* Interface Descriptions */
-+static struct usb_interface_description cdc_interfaces[] = {
-+ {
-+ alternates:sizeof (cdc_comm_alternate_descriptions) / sizeof (struct usb_alternate_description),
-+ alternate_list:cdc_comm_alternate_descriptions,
-+ },
-+
-+ {
-+ alternates:sizeof (cdc_data_alternate_descriptions) / sizeof (struct usb_alternate_description),
-+ alternate_list:cdc_data_alternate_descriptions,
-+ },
-+
-+#if defined(CONFIG_USBD_ACM_DATALOG)
-+#if 0
-+ // Space the INTERFACEs out by adding as many dummies as required (for now, none).
-+ { alternate_list: dummy_alternate_descriptions, }, /* 0xN */
-+#endif
-+
-+ { alternates:sizeof (datalog_alternate_descriptions) / sizeof (struct usb_alternate_description),
-+ alternate_list:datalog_alternate_descriptions,
-+ },
-+
-+ { alternates:sizeof (testcmd_alternate_descriptions) / sizeof (struct usb_alternate_description),
-+ alternate_list:testcmd_alternate_descriptions,
-+ },
-+
-+#endif
-+
-+};
-+
-+
-+/* Configuration Descriptor and Description */
-+static __u8 cdc_configuration_descriptor[sizeof(struct usb_configuration_descriptor)] = {
-+ 0x09, USB_DT_CONFIG, 0x00, 0x00, sizeof (cdc_interfaces) / sizeof (struct usb_interface_description),
-+ 0x01, 0x00, BMATTRIBUTE, BMAXPOWER, };
-+
-+struct usb_configuration_description acm_description[] = {
-+ { iConfiguration: CONFIG_USBD_ACM_DESC,
-+ configuration_descriptor: (struct usb_configuration_descriptor *)cdc_configuration_descriptor,
-+ bNumInterfaces:sizeof (cdc_interfaces) / sizeof (struct usb_interface_description),
-+ interface_list:cdc_interfaces,}, };
-+
-+static struct usb_device_descriptor acm_device_descriptor = {
-+ bLength: sizeof(struct usb_device_descriptor),
-+ bDescriptorType: USB_DT_DEVICE,
-+ bcdUSB: __constant_cpu_to_le16(USB_BCD_VERSION),
-+ bDeviceClass: COMMUNICATIONS_DEVICE_CLASS,
-+ bDeviceSubClass: 0x02,
-+ bDeviceProtocol: 0x00,
-+ bMaxPacketSize0: 0x00,
-+ idVendor: __constant_cpu_to_le16(CONFIG_USBD_ACM_VENDORID),
-+ idProduct: __constant_cpu_to_le16(CONFIG_USBD_ACM_PRODUCTID),
-+ bcdDevice: __constant_cpu_to_le16(CONFIG_USBD_ACM_BCDDEVICE),
-+};
-+
-+
-+static struct usb_endpoint_request acm_endpoint_requests[ENDPOINTS+1] = {
-+ { 1, 1, 0, USB_DIR_OUT | USB_ENDPOINT_BULK, 64, 512, },
-+ { 1, 1, 0, USB_DIR_IN | USB_ENDPOINT_BULK, 64 /* * 4 */, 512, },
-+ { 1, 0, 0, USB_DIR_IN | USB_ENDPOINT_INTERRUPT, 16, 64, },
-+#if defined(CONFIG_USBD_ACM_DATALOG)
-+ { 1, 1, 0, USB_DIR_IN | USB_ENDPOINT_BULK, 64, 512, },
-+#endif
-+ { 0, },
-+};
-+
-+
-+struct usb_device_description acm_device_description = {
-+ device_descriptor: &acm_device_descriptor,
-+ iManufacturer: CONFIG_USBD_ACM_MANUFACTURER,
-+ iProduct: CONFIG_USBD_ACM_PRODUCT_NAME,
-+#if !defined(CONFIG_USBD_NO_SERIAL_NUMBER) && defined(CONFIG_USBD_SERIAL_NUMBER_STR)
-+ iSerialNumber: CONFIG_USBD_SERIAL_NUMBER_STR,
-+#endif
-+ endpointsRequested: ENDPOINTS,
-+ requestedEndpoints: acm_endpoint_requests,
-+};
-+
-+/* Missing atomic functions ******************************************************************** */
-+
-+static __inline__ int atomic_post_inc(volatile atomic_t *v)
-+{
-+ unsigned long flags;
-+ int result;
-+ local_irq_save(flags);
-+ result = (v->counter)++;
-+ local_irq_restore(flags);
-+ return(result);
-+}
-+
-+static __inline__ int atomic_pre_dec(volatile atomic_t *v)
-+{
-+ unsigned long flags;
-+ int result;
-+ local_irq_save(flags);
-+ result = --(v->counter);
-+ local_irq_restore(flags);
-+ return(result);
-+}
-+
-+/* ACM ***************************************************************************************** */
-+/*
-+ * Output and Input control lines and line errors.
-+ */
-+#define LINE_OUT_DTR 0x01
-+#define LINE_OUT_RTS 0x02
-+#define LINE_IN_DCD 0x01
-+#define LINE_IN_DSR 0x02
-+#define LINE_IN_BRK 0x04
-+#define LINE_IN_RI 0x08
-+#define LINE_IN_FRAMING 0x10
-+#define LINE_IN_PARITY 0x20
-+#define LINE_IN_OVERRUN 0x40
-+
-+/* ******************************************************************************************* */
-+
-+#define ACM_TTY_MAJOR 166
-+#define ACM_TTY_MINOR 0
-+#define ACM_TTY_MINORS 1
-+
-+struct acm_private {
-+ struct usb_function_instance *function;
-+ struct tty_driver *tty_driver;
-+ int tty_driver_registered; // non-zero if tty_driver registered
-+ int usb_driver_registered; // non-zero if usb function registered
-+
-+ struct tty_struct *tty; // non-null if tty open
-+ struct tq_struct wqueue; // task queue for writer wakeup
-+ struct tq_struct hqueue; // task queue for hangup
-+ wait_queue_head_t open_wait; // wait queue for blocking open
-+ int open_wait_count; // count of (possible) blocked
-+ int exiting; // True if module exiting
-+
-+ unsigned char throttle; // non-zero if we are throttled
-+ unsigned char clocal; // non-zero if clocal set
-+ unsigned char connected; // non-zero if connected to host (configured)
-+
-+ unsigned int writesize; // packetsize * 4
-+ unsigned int ctrlin; // line state device sends to host
-+ unsigned int ctrlout; // line state device received from host
-+
-+ int exclusive;
-+ atomic_t used;
-+ atomic_t queued_bytes;
-+ atomic_t queued_urbs;
-+
-+ /*TBR debug receive flow control */
-+ unsigned long bytes_received;
-+ unsigned long bytes_forwarded;
-+ /*TBR end debug */
-+
-+ struct urb *recv_ring[RECV_RING_SIZE];
-+ unsigned int rr_in_ndx;
-+ unsigned int rr_out_ndx;
-+
-+ struct urb *int_urb; // pending interrupt urb
-+};
-+
-+static struct acm_private acm_private;
-+
-+static int acm_send_int_notification(struct usb_function_instance *, int , int );
-+static int acm_urb_sent_bulk (struct urb *urb, int rc);
-+static int acm_urb_sent_int (struct urb *urb, int rc);
-+static int acm_recv_urb (struct urb *urb, int rc);
-+
-+/* Serial Functions **************************************************************************** */
-+
-+static void acm_schedule(struct tq_struct *queue)
-+{
-+ TRACE_MSG1("task %p",queue);
-+ RETURN_IF(!queue->data || queue->sync);
-+ MOD_INC_USE_COUNT;
-+ queue_task(queue, &tq_immediate);
-+ mark_bh(IMMEDIATE_BH);
-+ TRACE_MSG1("task %p scheduled and marked",queue);
-+}
-+
-+
-+static int block_until_ready(
-+ struct tty_struct *tty,
-+ struct file *filp,
-+ struct acm_private *acm)
-+{
-+ unsigned long flags;
-+ int rc = 0;
-+
-+ // FUTURE: check tty for non-blocking open...
-+
-+ local_irq_save(flags);
-+ TRACE_MSG1("owc=%d --> at entry",acm->open_wait_count);
-+ acm->open_wait_count += 1;
-+ for (;;) {
-+ if (tty_hung_up_p(filp)) {
-+ TRACE_MSG("tty_hung_up_p()");
-+ rc = -ERESTARTSYS;
-+ break;
-+ }
-+ if (signal_pending(current)) {
-+ TRACE_MSG("signal_pending()");
-+ rc = -ERESTARTSYS;
-+ break;
-+ }
-+ if (acm->exiting) {
-+ TRACE_MSG("module exiting()");
-+ rc = -ENODEV;
-+ break;
-+ }
-+ if (acm->ctrlout & LINE_OUT_DTR) {
-+ // OK, there's somebody on the other end, let's go...
-+ TRACE_MSG("found DTR");
-+ break;
-+ }
-+ TRACE_MSG1("owc=%d sleeping...",acm->open_wait_count);
-+ interruptible_sleep_on(&acm->open_wait);
-+ TRACE_MSG1("owc=%d got WAKEUP",acm->open_wait_count);
-+ }
-+ acm->open_wait_count -= 1;
-+ TRACE_MSG1("owc=%d <-- at exit",acm->open_wait_count);
-+ local_irq_restore(flags);
-+ return(rc);
-+}
-+
-+static void acm_hangup(void *private)
-+{
-+ //struct acm_private *acm = &acm_private;
-+ struct acm_private *acm = (struct acm_private *) private;
-+ struct tty_struct *tty = acm->tty;
-+ TRACE_MSG("entered");
-+
-+ if (tty && !acm->clocal)
-+ tty_hangup(tty);
-+
-+ wake_up_interruptible(&acm->open_wait);
-+
-+ MOD_DEC_USE_COUNT;
-+ //printk (KERN_INFO"%s: MOD: %d connected: %d tty: %p clocal: %x\n",
-+ // __FUNCTION__, MOD_IN_USE, acm->connected, tty, acm->clocal);
-+ TRACE_MSG("exited");
-+}
-+
-+static int acm_tty_open(struct tty_struct *tty, struct file *filp)
-+{
-+ struct acm_private *acm = &acm_private;
-+ //struct usb_function_instance *function = acm->function;
-+ int used;
-+ int nonblocking;
-+ int rc = 0;
-+ unsigned long flags;
-+
-+ TRACE_MSG2("used=%d MOD=%d",atomic_read(&acm->used),MOD_IN_USE);
-+ //printk (KERN_INFO"%s: bus: %p used: %d MOD: %d\n",
-+ // __FUNCTION__, acm->function, atomic_read(&acm->used), MOD_IN_USE);
-+ nonblocking = filp->f_flags & O_NONBLOCK;
-+ /* Lock and increment used counter, save current value.
-+ Check for exclusive open at the same time. */
-+ local_irq_save(flags);
-+ /* The value of acm->used controls MOD_{INC/DEC}_USE_COUNT, so
-+ it has to be incremented unconditionally, and no early return
-+ made until after USE_COUNT has been adjusted to match. */
-+ used = atomic_post_inc(&acm->used);
-+#ifdef MCEL
-+ filp->f_flags |= O_EXCL; // QQQ Can we persuade MCEL to add this to their app?
-+ if (nonblocking && !(acm->connected)) {
-+ // QQQ Is MCEL actually using this "feature"? (See below for printk)
-+ rc = -EINVAL;
-+ } else
-+#endif
-+ if (filp->f_flags & O_EXCL) {
-+ /* This is intended to be an exclusive open, so
-+ make sure no one has the device open already, and
-+ set the exclusive flag so no one can open it later. */
-+ if (used > 0) {
-+ // Someone already has it.
-+ rc = -EBUSY;
-+ } else {
-+ acm->exclusive = 1;
-+ set_bit(TTY_EXCLUSIVE, &tty->flags);
-+ }
-+ } else if (acm->exclusive != 0 && !suser()) {
-+ // Only the superuser can do a normal open of an O_EXCL tty
-+ rc = -EBUSY;
-+ }
-+ local_irq_restore(flags);
-+ if (0 == used) {
-+ // The value before incrementing was 0, this is the first open.
-+ MOD_INC_USE_COUNT;
-+ }
-+ // OK, now it's safe to make an early return.
-+ if (0 != rc) {
-+#ifdef MCEL
-+ // This can dissappear when the "feature" above does.
-+ if (-EINVAL == rc)
-+ printk(KERN_INFO "\nusb cable not connected!\n");
-+#endif
-+ return(rc);
-+ }
-+ /* To truly emulate the old dual-device approach of having a non-blocking
-+ device (e.g cu0) and a blocking device (e.g. tty0) we would need to
-+ track blocking and non-blocking opens separately. We don't. This
-+ may lead to funny behavior in the multiple open case. */
-+ if (0 == used) {
-+ // First open.
-+ TRACE_MSG2("FIRST OPEN nb=%x xo=%x",nonblocking,acm->exclusive);
-+ //printk (KERN_INFO"%s: FIRST OPEN used_%sblock: s=%d, a=%d x=%d\n",
-+ // __FUNCTION__,(nonblocking?"non":""), used, atomic_read(&acm->used),
-+ // acm->exclusive);
-+ tty->driver_data = acm;
-+ acm->tty = tty;
-+ tty->low_latency = 1;
-+ acm->bytes_received = 0;
-+ acm->bytes_forwarded = 0;
-+ acm->ctrlin = LINE_IN_DCD | LINE_IN_DSR;
-+ if (NULL != acm->function) {
-+ TRACE_MSG1("sending notification ctrlin=%x",acm->ctrlin);
-+ //printk (KERN_INFO"%s: sending ctrlin notification\n",__FUNCTION__);
-+ rc = acm_send_int_notification(acm->function, CDC_NOTIFICATION_SERIAL_STATE,
-+ acm->ctrlin);
-+ }
-+ }
-+
-+ if (0 == rc && !nonblocking) {
-+ // Blocking open - all callers block until DTR shows up.
-+ rc = block_until_ready(tty,filp,acm);
-+ }
-+
-+ /* The tty layer calls acm_tty_close() even if this open fails,
-+ so any cleanup (rc != 0) will be done there. */
-+ TRACE_MSG2("used=%d rc=%d",atomic_read(&acm->used),rc);
-+ return(rc);
-+}
-+
-+static void acm_tty_close(struct tty_struct *tty, struct file *filp)
-+{
-+ struct acm_private *acm = tty->driver_data;
-+ struct usb_function_instance *function = acm->function;
-+ int used;
-+
-+ TRACE_MSG2("used=%d MOD=%d",atomic_read(&acm->used),MOD_IN_USE);
-+ //printk (KERN_INFO"%s: function: %p used: %d MOD: %d\n",
-+ // __FUNCTION__, function, atomic_read(&acm->used), MOD_IN_USE);
-+
-+ // lock and decrement used counter, save result
-+ used = atomic_pre_dec(&acm->used);
-+
-+ // finished unless this is the last close
-+ if (used <= 0) {
-+ // This is the last close, clean up
-+
-+ acm->tty = NULL;
-+ acm->ctrlin = 0x0;
-+
-+ if (acm->function) {
-+ acm_send_int_notification(function, CDC_NOTIFICATION_SERIAL_STATE, acm->ctrlin);
-+ }
-+ /* This should never happen if this is the last close,
-+ but it can't hurt to check. */
-+ if (acm->open_wait_count) {
-+ wake_up_interruptible(&acm->open_wait);
-+ }
-+ if (acm->exclusive) {
-+ acm->exclusive = 0;
-+ clear_bit(TTY_EXCLUSIVE, &tty->flags);
-+ }
-+ MOD_DEC_USE_COUNT;
-+ TRACE_MSG1("LAST CLOSE r-f=%d",(acm->bytes_received-acm->bytes_forwarded));
-+ //printk (KERN_INFO"%s: LAST CLOSE used: %d MOD: %d bytes_received: %lu forwarded: %lu\n",
-+ // __FUNCTION__, atomic_read(&acm->used), MOD_IN_USE, acm->bytes_received,
-+ // acm->bytes_forwarded);
-+ }
-+ TRACE_MSG("exited");
-+}
-+
-+/* Transmit Function - called by serproto ****************************************************** */
-+
-+static int acm_tty_write(struct tty_struct *tty, int from_user, const unsigned char *buf, int count)
-+{
-+ struct acm_private *acm = tty->driver_data;
-+ struct usb_function_instance *function = acm->function;
-+ struct urb *urb;
-+
-+ TRACE_MSG1("count=%d",count);
-+ //printk (KERN_INFO"%s: used: %d count: %d\n", __FUNCTION__, atomic_read(&acm->used), count);
-+
-+ RETURN_EINVAL_IF(!function);
-+ TRACE_MSG("function OK");
-+
-+ // sanity check and are we connect
-+ RETURN_EINVAL_IF(!atomic_read(&acm->used));
-+ TRACE_MSG("used OK");
-+ RETURN_ZERO_IF (!count || !acm->connected);
-+ TRACE_MSG("connected OK");
-+ RETURN_ZERO_IF(max_queued_urbs <= atomic_read(&acm->queued_urbs));
-+ TRACE_MSG("max_queued_urbs OK");
-+
-+ // allocate a write urb
-+ count = MIN(count, acm->writesize);
-+
-+ // XXX verify that we don't attempt to send wMaxPacketSize packets...
-+ if (!(count % usbd_endpoint_wMaxPacketSize(function, BULK_OUT, 0))) //QQSV
-+ count--;
-+
-+ //printk(KERN_INFO"%s:\n", __FUNCTION__);
-+ RETURN_ENOMEM_IF (!(urb = usbd_alloc_urb (function, BULK_IN, count, acm_urb_sent_bulk)));
-+ TRACE_MSG("alloc_urb OK");
-+
-+ if (from_user)
-+ copy_from_user(urb->buffer, buf, count);
-+ else
-+ memcpy(urb->buffer, buf, count);
-+ urb->privdata = acm;
-+ urb->actual_length = count;
-+ atomic_add(count, &acm->queued_bytes);
-+ atomic_inc(&acm->queued_urbs);
-+ usbd_send_urb(urb);
-+ TRACE_MSG2("urbID#%04x --> %d",urbID(urb),count);
-+ return count;
-+}
-+
-+static int acm_tty_write_room(struct tty_struct *tty)
-+{
-+ struct acm_private *acm = &acm_private;
-+ int rc;
-+
-+ TRACE_MSG("entered");
-+ //printk (KERN_INFO"%s: used: %d queued: %d %d room: %d\n", __FUNCTION__, atomic_read(&acm->used),
-+ // atomic_read(&acm->queued_urbs), atomic_read(&acm->queued_bytes),
-+ // (max_queued_urbs > atomic_read(&acm->queued_urbs)) &&
-+ // (max_queued_bytes > atomic_read(&acm->queued_bytes)) ? acm->writesize : 0);
-+
-+ RETURN_EINVAL_IF(!atomic_read(&acm->used));
-+ TRACE_MSG("used OK");
-+ rc = (!acm->function || max_queued_urbs <= atomic_read(&acm->queued_urbs) ||
-+ max_queued_bytes <= atomic_read(&acm->queued_bytes) ) ? 0 : acm->writesize ;
-+ TRACE_MSG1("--> %d",rc);
-+ return(rc);
-+}
-+
-+static int acm_tty_chars_in_buffer(struct tty_struct *tty)
-+{
-+ struct acm_private *acm = &acm_private;
-+ int rc;
-+ TRACE_MSG("entered");
-+ RETURN_EINVAL_IF(!atomic_read(&acm->used));
-+ TRACE_MSG("used OK");
-+ RETURN_ZERO_IF(!acm->function);
-+ TRACE_MSG("function OK");
-+ rc = atomic_read(&acm->queued_bytes);
-+ TRACE_MSG1("--> %d",rc);
-+ return(rc);
-+}
-+
-+static struct urb *acm_frwd_recv_urbs(struct tty_struct *tty, struct acm_private *acm)
-+{
-+ unsigned long flags;
-+ struct urb *urb;
-+
-+ TRACE_MSG("entered");
-+ //struct usb_function_instance *function = acm->function;
-+
-+ //if (acm->throttle)
-+ // printk(KERN_INFO"%s: THROTTLED at 0\n", __FUNCTION__);
-+
-+ while (acm->rr_in_ndx != acm->rr_out_ndx && !acm->throttle) {
-+ // Forward one URB from the receive ring
-+ local_irq_save(flags);
-+ urb = acm->recv_ring[acm->rr_out_ndx];
-+ acm->recv_ring[acm->rr_out_ndx] = NULL;
-+ acm->rr_out_ndx = (acm->rr_out_ndx + 1) % RECV_RING_SIZE;
-+ local_irq_restore(flags);
-+
-+ if (urb->status == RECV_OK && tty) {
-+ unsigned char *cp = urb->buffer;
-+ int i;
-+ int f = 0;
-+ // Future: think about throttle part way through...
-+ //printk(KERN_INFO"%s: ", __FUNCTION__);
-+#define ACM_WORD_COPY
-+#ifndef ACM_WORD_COPY
-+ for (i = 0; i < urb->actual_length; i++) {
-+ if (tty->flip.count >= TTY_FLIPBUF_SIZE) {
-+ tty_flip_buffer_push(tty);
-+ acm->bytes_forwarded += f;
-+ f = 0;
-+ }
-+
-+ //printk("%02x ", *cp);
-+ tty_insert_flip_char(tty, *cp++, 0);
-+ f += 1;
-+
-+ if (acm->throttle) {
-+ //printk(KERN_INFO"%s: throttled at %d/%d\n", __FUNCTION__,i,urb->actual_length);
-+ break;
-+ }
-+ }
-+ //printk("\n");
-+ tty_flip_buffer_push(tty);
-+ acm->bytes_forwarded += f;
-+#else
-+ for (i = urb->actual_length; i > 0; i -= f) {
-+ f = i;
-+ if (tty->flip.count + f > TTY_FLIPBUF_SIZE) {
-+ tty_flip_buffer_push(tty);
-+ f = MIN(f, TTY_FLIPBUF_SIZE - tty->flip.count);
-+ }
-+ if (f <= 0) {
-+ // Shouldn't happen...
-+ printk(KERN_ERR"%s: %d bytes dropped\n", __FUNCTION__, i);
-+ break;
-+ }
-+ memcpy(tty->flip.char_buf_ptr, cp, f); // see: arch/arm/lib/memcpy.S
-+ cp += f;
-+ tty->flip.count += f;
-+ tty->flip.flag_buf_ptr += f;
-+ tty->flip.char_buf_ptr += f; // w20146 - Jul 31
-+ tty_flip_buffer_push(tty);
-+ acm->bytes_forwarded += f;
-+ }
-+
-+#endif
-+ if (acm->throttle) {
-+ printk(KERN_INFO"%s: THROTTLED at 1\n", __FUNCTION__);
-+ }
-+ }
-+ else if (urb->status != RECV_OK)
-+ printk(KERN_INFO"%s: !RECV_OK, dumping %d bytes\n", __FUNCTION__,urb->actual_length);
-+ else
-+ printk(KERN_INFO"%s: tty NULL\n", __FUNCTION__);
-+
-+ // Put urb back in line for a refill.
-+ if (usbd_start_recv (urb)) {
-+ // Bail if it can't be queued for refill.
-+ printk(KERN_INFO"%s: usbd_start_recv() failed\n", __FUNCTION__);
-+ return(urb);
-+ }
-+ }
-+ TRACE_MSG("exited");
-+ return(NULL);
-+}
-+
-+static void acm_tty_throttle(struct tty_struct *tty)
-+{
-+ struct acm_private *acm = &acm_private;
-+ TRACE_MSG("entered");
-+ //uuu printk (KERN_INFO"%s:\n", __FUNCTION__);
-+ if (acm && atomic_read(&acm->used))
-+ acm->throttle = 1;
-+ TRACE_MSG("exited");
-+}
-+
-+static void acm_tty_unthrottle(struct tty_struct *tty)
-+{
-+ struct acm_private *acm = &acm_private;
-+ struct urb *urb;
-+ TRACE_MSG("entered");
-+ //uuu printk (KERN_INFO"%s:\n", __FUNCTION__);
-+ if (acm && atomic_read(&acm->used)) {
-+ acm->throttle = 0;
-+ // Forward any queued URBS.
-+ if (NULL != (urb = acm_frwd_recv_urbs(tty,acm))) {
-+ /* usbd_start_recv(urb) failed, so we need to dispose of this urb.
-+ Count on someone else to replace it. */
-+ usbd_dealloc_urb(urb);
-+ }
-+ }
-+ TRACE_MSG("exited");
-+}
-+
-+static int acm_tty_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg)
-+{
-+ struct acm_private *acm = &acm_private;
-+ struct usb_function_instance *function = acm->function;
-+ unsigned int mask;
-+ unsigned int newctrl;
-+
-+ TRACE_MSG("entered");
-+ //printk (KERN_INFO"%s: used: %d\n", __FUNCTION__, atomic_read(&acm->used));
-+ RETURN_EINVAL_IF(!atomic_read(&acm->used));
-+
-+#if 1 // temporary solution for IOCTL
-+ if(cmd == TIOCMGET)
-+ return put_user( acm->ctrlout & LINE_OUT_DTR ? TIOCM_DTR : 0 | TIOCM_CTS, (unsigned long *) arg);
-+#endif
-+
-+ TRACE_MSG("--> -ENOIOCTLCMD");
-+ return -ENOIOCTLCMD;
-+
-+#if 0
-+ switch(cmd) {
-+ case TCGETS:
-+ case TCFLSH:
-+ case TCSETS:
-+ printk (KERN_INFO"%s: ignored cmd: %x\n", __FUNCTION__, cmd);
-+ return 0;
-+
-+ case TCSETSW:
-+
-+ //user_termios_to_kernel_termios(&priv->termios, (struct termios *)arg);
-+ printk (KERN_INFO"%s: ignored cmd: %x\n", __FUNCTION__, cmd);
-+ return 0;
-+
-+ case TIOCMGET:
-+ printk (KERN_INFO"%s: TIOCMGET: %04x\n", __FUNCTION__, acm->ctrlin & LINE_OUT_DTR ? TIOCM_DTR : 0 | TIOCM_CTS);
-+ return put_user( acm->ctrlin & LINE_OUT_DTR ? TIOCM_DTR : 0 | TIOCM_CTS, (unsigned long *) arg);
-+
-+ case TIOCMSET:
-+ case TIOCMBIS:
-+ case TIOCMBIC:
-+
-+ printk (KERN_INFO"%s: TIOCM{SET,BIS,BIC}:\n", __FUNCTION__);
-+ RETURN_EFAULT_IF (get_user(mask, (unsigned long *) arg));
-+
-+ printk (KERN_INFO"%s: TIOCM{SET,BIS,BIC}: %04x\n", __FUNCTION__, mask);
-+
-+ newctrl = acm->ctrlin;
-+
-+ mask = (mask & TIOCM_DTR ? LINE_IN_DCD|LINE_IN_DSR : 0)/* | (mask & TIOCM_RTS ? LINE_OUT_RTS : 0)*/;
-+
-+ switch(cmd) {
-+ case TIOCMSET: newctrl = mask; break;
-+ case TIOCMBIS: newctrl |= mask; break;
-+ case TIOCMBIC: newctrl &= mask; break;
-+ }
-+ RETURN_ZERO_IF(acm->ctrlin == newctrl);
-+
-+ printk (KERN_INFO"%s: newctrl: %04x\n", __FUNCTION__, newctrl);
-+ return acm_send_int_notification(function, CDC_NOTIFICATION_SERIAL_STATE, acm->ctrlin);
-+
-+ case 3:
-+ return 0;
-+ default:
-+ printk (KERN_INFO"%s: unknown: %04x\n", __FUNCTION__, cmd);
-+ break;
-+ }
-+ return -ENOIOCTLCMD;
-+#endif
-+}
-+
-+static void acm_tty_set_termios(struct tty_struct *tty, struct termios *termios_old)
-+{
-+ struct acm_private *acm = &acm_private;
-+ struct termios *termios;
-+
-+ TRACE_MSG("entered");
-+ //printk (KERN_INFO"%s: tty: %p\n", __FUNCTION__, tty);
-+
-+ RETURN_IF(!atomic_read(&acm->used) || !tty || !tty->termios);
-+
-+ termios = tty->termios;
-+ acm->clocal = termios->c_cflag & CLOCAL;
-+
-+ //printk (KERN_INFO"%s: clocal: %d\n", __FUNCTION__, acm->clocal);
-+ TRACE_MSG("exited");
-+}
-+
-+/* ********************************************************************************************* */
-+
-+static void acm_wakeup_writers(void *private)
-+{
-+ struct acm_private *acm = &acm_private;
-+ struct tty_struct *tty = acm->tty;
-+
-+ TRACE_MSG("entered");
-+ MOD_DEC_USE_COUNT;
-+
-+ //printk (KERN_INFO"%s: MOD: %d connected: %d tty: %p\n", __FUNCTION__, MOD_IN_USE, acm->connected, tty);
-+
-+ RETURN_IF(!acm->connected || !atomic_read(&acm->used) || !tty);
-+ TRACE_MSG("connected and used OK");
-+
-+ if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup) {
-+ TRACE_MSG("ldisc wakeup");
-+ (tty->ldisc.write_wakeup)(tty);
-+ }
-+
-+ // printk (KERN_INFO"%s: write_wait wakeup\n", __FUNCTION__);
-+ wake_up_interruptible(&tty->write_wait);
-+ TRACE_MSG("exited");
-+}
-+
-+
-+/* ********************************************************************************************* */
-+
-+static int acm_tty_refcount;
-+static struct tty_struct *acm_tty_table[ACM_TTY_MINORS];
-+static struct termios *acm_tty_termios[ACM_TTY_MINORS];
-+static struct termios *acm_tty_termios_locked[ACM_TTY_MINORS];
-+
-+static struct tty_driver acm_tty_driver = {
-+ magic: TTY_DRIVER_MAGIC,
-+ type: TTY_DRIVER_TYPE_SERIAL,
-+ subtype: SERIAL_TYPE_NORMAL,
-+ flags: TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS,
-+ driver_name: "acm-CDC",
-+ name: "usb/acm/%d",
-+ major: ACM_TTY_MAJOR,
-+ num: ACM_TTY_MINORS,
-+ minor_start: 0,
-+
-+ open: acm_tty_open,
-+ close: acm_tty_close,
-+ write: acm_tty_write,
-+ write_room: acm_tty_write_room,
-+ ioctl: acm_tty_ioctl,
-+ throttle: acm_tty_throttle,
-+ unthrottle: acm_tty_unthrottle,
-+ chars_in_buffer: acm_tty_chars_in_buffer,
-+ set_termios: acm_tty_set_termios,
-+
-+ refcount: &acm_tty_refcount,
-+ table: acm_tty_table,
-+ termios: acm_tty_termios,
-+ termios_locked: acm_tty_termios_locked,
-+};
-+
-+
-+/* Transmit INTERRUPT ************************************************************************** */
-+
-+/**
-+ * Generates a response urb on the notification (INTERRUPT) endpoint.
-+ * Return a non-zero result code to STALL the transaction.
-+ * CALLED from interrupt context.
-+ */
-+static int acm_send_int_notification(struct usb_function_instance *function, int bnotification, int data)
-+{
-+ struct acm_private *acm = &acm_private;
-+ struct urb *urb = NULL;
-+ struct cdc_notification_descriptor *notification;
-+ unsigned long flags;
-+ int rc;
-+
-+ //printk(KERN_INFO"%s: function: %p connected: %d DTR: %d\n", __FUNCTION__,
-+ // function, acm->connected, acm->ctrlout & LINE_OUT_DTR);
-+
-+ local_irq_save(flags);
-+ TRACE_MSG("entered");
-+
-+ do {
-+ BREAK_IF(!function);
-+ //BREAK_IF(!acm->connected || !acm->ctrlout & LINE_OUT_DTR);
-+ BREAK_IF(!acm->connected);
-+
-+ //printk (KERN_INFO"%s: bnotification: %x data: %d int_urb: %p\n",
-+ // __FUNCTION__, bnotification, data, acm->int_urb);
-+
-+ if (acm->int_urb) {
-+ //uuu printk(KERN_INFO"%s: int_urb: %p\n", __FUNCTION__, acm->int_urb);
-+ usbd_cancel_urb_irq(acm->int_urb);
-+ acm->int_urb = NULL;
-+ }
-+
-+ //printk(KERN_INFO"%s: AAA\n", __FUNCTION__);
-+
-+ //uuu printk(KERN_INFO"%s:\n", __FUNCTION__);
-+ BREAK_IF(!(urb = usbd_alloc_urb (function, INT_IN,
-+ sizeof(struct cdc_notification_descriptor), acm_urb_sent_int)));
-+
-+ //printk(KERN_INFO"%s: BBB\n", __FUNCTION__);
-+
-+ memset(urb->buffer, 0, urb->buffer_length);
-+ urb->actual_length = sizeof(struct cdc_notification_descriptor);
-+ urb->privdata = &acm_private;
-+
-+ // fill in notification structure
-+ notification = (struct cdc_notification_descriptor *) urb->buffer;
-+
-+ notification->bmRequestType = USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE;
-+ notification->bNotification = bnotification;
-+
-+ switch (bnotification) {
-+ case CDC_NOTIFICATION_NETWORK_CONNECTION:
-+ notification->wValue = data;
-+ break;
-+ case CDC_NOTIFICATION_SERIAL_STATE:
-+ notification->wLength = cpu_to_le16(2);
-+ *((unsigned short *)notification->data) = cpu_to_le16(data);
-+ break;
-+ }
-+
-+ acm->int_urb = urb;
-+ //printk(KERN_INFO"%s: CCC\n", __FUNCTION__);
-+ BREAK_IF(!(rc = usbd_send_urb (urb)));
-+
-+ //uuu printk(KERN_ERR"%s: usbd_send_urb failed err: %x\n", __FUNCTION__, rc);
-+ acm->int_urb = urb;
-+ urb->privdata = NULL;
-+ usbd_dealloc_urb (urb);
-+
-+ } while(0);
-+
-+ TRACE_MSG1("urbID#%04x --> 0",urbID(urb));
-+ local_irq_restore(flags);
-+ //printk(KERN_INFO"%s: DDD\n", __FUNCTION__);
-+ return 0;
-+}
-+
-+/* Callback functions for TX urb completion (function chosen when urb is allocated) ***********/
-+
-+/* acm_urb_sent_bulk - called to indicate URB transmit finished
-+ * @urb: pointer to struct urb
-+ * @rc: result
-+ */
-+static int acm_urb_sent_bulk (struct urb *urb, int rc)
-+{
-+ struct acm_private *acm = &acm_private;
-+ struct usb_function_instance *function;
-+
-+ acm_interrupts++;
-+ TRACE_MSG2("entered urbID#%04x rc=%d",urbID(urb),rc);
-+
-+ if (!urb || !(function = urb->function_instance)) {
-+ TRACE_MSG1("urbID#%04x --> -EINVAL",urbID(urb));
-+ return(-EINVAL);
-+ }
-+ TRACE_MSG1("IN length=%d",urb->actual_length);
-+
-+ atomic_sub(urb->actual_length, &acm->queued_bytes);
-+ atomic_dec(&acm->queued_urbs);
-+ urb->privdata = NULL;
-+ usbd_dealloc_urb (urb);
-+ acm_schedule(&acm->wqueue);
-+ TRACE_MSG1("urbID#%04x --> 0",urbID(urb));
-+ return 0;
-+}
-+
-+/* acm_urb_sent_int - called to indicate URB transmit finished
-+ * @urb: pointer to struct urb
-+ * @rc: result
-+ */
-+static int acm_urb_sent_int (struct urb *urb, int rc)
-+{
-+ struct acm_private *acm = &acm_private;
-+ struct usb_function_instance *function;
-+
-+ acm_interrupts++;
-+ TRACE_MSG2("entered urbID#%04x rc=%d",urbID(urb),rc);
-+ //printk(KERN_INFO"%s: urb: %p function: %p rc: %d\n", __FUNCTION__, urb, urb->function_instance, rc);
-+ if (!urb || !(function = urb->function_instance)) {
-+ TRACE_MSG1("urbID#%04x --> -EINVAL",urbID(urb));
-+ return(-EINVAL);
-+ }
-+ TRACE_MSG1("INT length=%d",urb->actual_length);
-+
-+ acm->int_urb = NULL;
-+ usbd_dealloc_urb(urb);
-+ TRACE_MSG1("urbID#%04x --> 0",urbID(urb));
-+ return 0;
-+}
-+
-+#if defined(CONFIG_USBD_ACM_DATALOG)
-+/* acm_urb_sent_pst - called to indicate URB transmit finished
-+ * @urb: pointer to struct urb
-+ * @rc: result
-+ */
-+int acm_urb_sent_pst (struct urb *urb, int rc)
-+{
-+ struct acm_private *acm = &acm_private;
-+ struct usb_function_instance *function;
-+
-+ acm_interrupts++;
-+ TRACE_MSG2("entered urbID#%04x rc=%d",urbID(urb),rc);
-+ //uuu printk(KERN_INFO"urb: %p function: %p rc: %d\n", urb, urb->function_instance, rc);
-+ if (!urb || !(function = urb->function_instance)) {
-+ TRACE_MSG1("urbID#%04x --> -EINVAL",urbID(urb));
-+ return(-EINVAL);
-+ }
-+ TRACE_MSG1("PST length=%d",urb->actual_length);
-+
-+#if defined(PST_FD_AVAILABLE)
-+ pst_urb_sent(urb, rc);
-+#endif
-+ urb->privdata = NULL;
-+ usbd_dealloc_urb(urb);
-+ TRACE_MSG1("urbID#%04x --> 0",urbID(urb));
-+ return 0;
-+}
-+#endif
-+
-+/* USB Device Functions ************************************************************************ */
-+
-+/* acm_event_irq - process a device event
-+ *
-+ */
-+void acm_event_irq (struct usb_function_instance *function, usb_device_event_t event, int data)
-+{
-+ struct acm_private *acm = &acm_private;
-+ int i;
-+
-+ acm_interrupts++;
-+ TRACE_MSG1("entered ev=%d",event);
-+ switch (event) {
-+
-+#if defined(CONFIG_USBD_ACM_DATALOG)
-+ case DEVICE_CREATE:
-+#if defined(PST_FD_AVAILABLE)
-+ if (0 != (ret = pst_dev_create(device)))
-+ return;
-+#endif
-+ break;
-+
-+ case DEVICE_DESTROY:
-+#if defined(PST_FD_AVAILABLE)
-+ pst_dev_destroy();
-+#endif
-+ break;
-+#endif
-+
-+ case DEVICE_CONFIGURED:
-+ TRACE_MSG("CONFIGURED");
-+ acm->connected = 1;
-+ acm_schedule(&acm->wqueue);
-+ for (i = 0; i < MAX_RECV_URBS; i++) {
-+ struct urb *urb;
-+ // printk(KERN_INFO"%s:\n", __FUNCTION__);
-+ BREAK_IF(!(urb = usbd_alloc_urb(function, BULK_OUT,
-+ usbd_endpoint_transferSize(function, BULK_OUT,usbd_high_speed(function)),
-+ acm_recv_urb)));
-+ if (usbd_start_recv(urb))
-+ usbd_dealloc_urb(urb);
-+ }
-+ break;
-+
-+ case DEVICE_RESET:
-+ case DEVICE_DE_CONFIGURED:
-+ TRACE_MSG("RESET");
-+ BREAK_IF(!acm->connected);
-+ acm->connected = 0;
-+ acm->int_urb = NULL;
-+ acm_schedule(&acm->hqueue);
-+ // XXX flush
-+ // Release any queued urbs
-+ break;
-+
-+ default: break;
-+ }
-+ TRACE_MSG("exited");
-+}
-+
-+static int acm_recv_urb (struct urb *urb, int rc)
-+{
-+ /* Return 0 if urb has been accepted,
-+ return 1 and expect caller to deal with urb release otherwise. */
-+ struct acm_private *acm = &acm_private;
-+ struct tty_struct *tty = acm->tty;
-+ struct urb *furb;
-+
-+ acm_interrupts++;
-+ TRACE_MSG1("entered rc=%d",rc);
-+ //printk(KERN_INFO"%s: urb: %p rc=%d\n", __FUNCTION__, urb, rc);
-+ if (RECV_CANCELLED == rc) {
-+ TRACE_MSG1("cancelled URB=%p",urb);
-+ usbd_dealloc_urb(urb);
-+ return(0);
-+ }
-+ if (RECV_OK != rc) {
-+ // Shouldn't happen, but...
-+ // Reject it.
-+ TRACE_MSG1("rejected URB=%p",urb);
-+ //printk(KERN_INFO"%s: rejecting URB %p rc=%d\n", __FUNCTION__, urb, rc);
-+ return(1);
-+ }
-+ // Queue it for forwarding, then kick off forwarding routine.
-+ acm->bytes_received += urb->actual_length;
-+ acm->recv_ring[acm->rr_in_ndx] = urb;
-+ acm->rr_in_ndx = (acm->rr_in_ndx + 1) % RECV_RING_SIZE;
-+ if (urb == (furb = acm_frwd_recv_urbs(tty,acm))) {
-+ // Couldn't restart urb, tell the caller to dispose of it.
-+ TRACE_MSG1("caller to release URB=%p",urb);
-+ //printk(KERN_INFO"%s: caller to release URB %p rc=%d\n", __FUNCTION__, urb, rc);
-+ return(1);
-+ }
-+ if (NULL != furb) {
-+ /* Couldn't restart some other urb, but we can't tell the caller
-+ about it, so we need to dispose of it ourselves. This should
-+ only happen if the bi layer is shutting down, so we let someone
-+ else allocate the replacement if one is needed. */
-+ TRACE_MSG1("releasing URB=%p",urb);
-+ usbd_dealloc_urb(urb);
-+ }
-+ TRACE_MSG("--> 0");
-+ return(0);
-+}
-+
-+/* acm_line_coding_urb_received - callback for sent URB
-+ *
-+ * Handles notification that an urb has been sent (successfully or otherwise).
-+ *
-+ * Returns non-zero for failure.
-+ */
-+static int acm_line_coding_urb_received (struct urb *urb, int urb_rc)
-+{
-+ TRACE_MSG2("urbID#%04x rc=%d",urbID(urb),urb_rc);
-+
-+ RETURN_EINVAL_IF (RECV_OK != urb_rc);
-+
-+ return -EINVAL; // caller will de-allocate
-+}
-+
-+/* acm_recv_setup_irq - called to indicate urb has been received
-+ */
-+int acm_recv_setup_irq (struct usb_device_request *request)
-+{
-+ struct acm_private *acm = &acm_private;
-+ struct usb_function_instance *function = acm->function;
-+
-+ acm_interrupts++;
-+ TRACE_SETUP(request);
-+
-+ // verify that this is a usb class request per cdc-acm specification or a vendor request.
-+ if (!(request->bmRequestType & (USB_REQ_TYPE_CLASS | USB_REQ_TYPE_VENDOR))) {
-+ TRACE_MSG("--> 0");
-+ return(0);
-+ }
-+
-+ // determine the request direction and process accordingly
-+ switch (request->bmRequestType & (USB_REQ_DIRECTION_MASK | USB_REQ_TYPE_MASK)) {
-+
-+ case USB_REQ_HOST2DEVICE | USB_REQ_TYPE_CLASS:
-+ switch (request->bRequest) {
-+ case CDC_CLASS_REQUEST_SEND_ENCAPSULATED: break;
-+ case CDC_CLASS_REQUEST_SET_COMM_FEATURE: break;
-+ case CDC_CLASS_REQUEST_CLEAR_COMM_FEATURE: break;
-+ case CDC_CLASS_REQUEST_SET_LINE_CODING:
-+ {
-+ struct urb *urb;
-+ int len = le16_to_cpu(request->wLength);
-+ TRACE_MSG1("SET_LINE_CODING wLength=%d",len);
-+ if (len <= 0) {
-+ TRACE_MSG("(len<=0)--> 0");
-+ return(0);
-+ }
-+ // Set up an ep0 recv urb for the rest of it.
-+ urb = usbd_alloc_urb_ep0(function, len, acm_line_coding_urb_received);
-+ if (NULL == urb) {
-+ TRACE_MSG("no mem for ep0 recv urb");
-+ return(-EINVAL);
-+ }
-+ if (usbd_start_recv(urb)) {
-+ TRACE_MSG("usbd_start_recv() failed");
-+ usbd_dealloc_urb(urb); // de-alloc if error
-+ TRACE_MSG("--> -EINVAL");
-+ return(-EINVAL);
-+ }
-+ }
-+ break;
-+ case CDC_CLASS_REQUEST_SET_CONTROL_STATE:
-+ {
-+ struct acm_private *acm = &acm_private;
-+ unsigned int prev_ctrlout = acm->ctrlout;
-+ acm->ctrlout = le16_to_cpu(request->wValue);
-+
-+ TRACE_MSG1("set control state, tty=%p",acm->tty);
-+ //uuu printk(KERN_INFO"%s: tty: %p clocal: %x ctrlout: %02x DTR: %x\n",
-+ //uuu __FUNCTION__, acm->tty, acm->clocal, acm->ctrlout, acm->ctrlout & LINE_OUT_DTR);
-+
-+ // schedule writers or hangup IFF open
-+ BREAK_IF(!acm->tty);
-+ TRACE_MSG1("set control state, ctrlout#%04x",acm->ctrlout);
-+ // make sure there really is a state change
-+ if ((acm->ctrlout ^ prev_ctrlout) & LINE_OUT_DTR) {
-+ TRACE_MSG1("DTR state changed -> %x",(acm->ctrlout&LINE_OUT_DTR));
-+ //printk(KERN_INFO"%s: tty: %p DTR state changed -> %u\n",
-+ // __FUNCTION__, acm->tty, (acm->ctrlout&LINE_OUT_DTR));
-+ acm_schedule(((acm->ctrlout & LINE_OUT_DTR) ? &acm->wqueue : &acm->hqueue));
-+ // wake up blocked opens
-+ if (acm->open_wait_count > 0) {
-+ wake_up_interruptible(&acm->open_wait);
-+ }
-+ } // end of state change operation
-+
-+ // send notification if we have DCD
-+ TRACE_MSG1("checking DCD ctrlin#%04x",acm->ctrlin);
-+ BREAK_IF(!(acm->ctrlin & (LINE_IN_DCD | LINE_IN_DSR)));
-+ TRACE_MSG1("tty=%p sending (DCD|DSR) notification",acm->tty);
-+ acm_send_int_notification(function, CDC_NOTIFICATION_SERIAL_STATE, acm->ctrlin);
-+ }
-+ break;
-+
-+ case CDC_CLASS_REQUEST_SEND_BREAK: break;
-+ default: break;
-+ }
-+ TRACE_MSG("--> 0");
-+ return 0;
-+
-+ case USB_REQ_DEVICE2HOST | USB_REQ_TYPE_CLASS:
-+ switch (request->bRequest) {
-+ case CDC_CLASS_REQUEST_GET_ENCAPSULATED: break;
-+ case CDC_CLASS_REQUEST_GET_COMM_FEATURE: break;
-+ case CDC_CLASS_REQUEST_GET_LINE_CODING:
-+ {
-+ struct urb *urb;
-+ struct cdc_acm_line_coding *results;
-+ int len = le16_to_cpu(request->wLength);
-+ if (len != sizeof(struct cdc_acm_line_coding)) {
-+ TRACE_MSG2("(len=%d!=sz=%d--> -EINVAL",len,sizeof(struct cdc_acm_line_coding));
-+ return -EINVAL;
-+ }
-+
-+ if (!(urb = usbd_alloc_urb_ep0(function, len, NULL))) {
-+ TRACE_MSG("(nomem)--> -EINVAL");
-+ return -EINVAL;
-+ }
-+ results = (struct cdc_acm_line_coding *)urb->buffer;
-+ results->dwDTERate = cpu_to_le16(0x1c200); // 115200
-+ results ->bDataBits = 0x08;
-+ urb->actual_length = len;
-+ TRACE_MSG1("sending line coding urb=%p",(u32)(void*)urb);
-+ if (!usbd_send_urb(urb)) {
-+ TRACE_MSG("--> 0");
-+ return(0);
-+ }
-+ usbd_dealloc_urb(urb);
-+ TRACE_MSG("(send failed)--> -EINVAL");
-+ return -EINVAL;
-+ }
-+ default: break;
-+ }
-+ TRACE_MSG("--> 0");
-+ return 0;
-+
-+ case USB_REQ_HOST2DEVICE | USB_REQ_TYPE_VENDOR: break;
-+ case USB_REQ_DEVICE2HOST | USB_REQ_TYPE_VENDOR: break;
-+#if defined(PST_FD_AVAILABLE)
-+ ep0_process_vendor_request( urb );
-+ TRACE_MSG("--> 0");
-+ return 0;
-+#endif
-+
-+ default: break;
-+ }
-+ TRACE_MSG("--> 0");
-+ return 0;
-+}
-+
-+
-+static int acm_function_enable (struct usb_function_instance *function)
-+{
-+ struct acm_private *acm = &acm_private;
-+ acm_interrupts++;
-+ TRACE_MSG("entered");
-+ MOD_INC_USE_COUNT;
-+ acm->function = function;
-+ acm->writesize = usbd_endpoint_wMaxPacketSize(function, BULK_OUT, 0) * 4; // QQSV
-+ TRACE_MSG("-> 0");
-+ return 0;
-+}
-+
-+static void acm_function_disable (struct usb_function_instance *function)
-+{
-+ struct acm_private *acm = &acm_private;
-+ acm_interrupts++;
-+ TRACE_MSG("entered");
-+ acm->writesize = 0;
-+ acm->function = NULL;
-+ MOD_DEC_USE_COUNT;
-+ TRACE_MSG("exited");
-+}
-+
-+
-+static struct usb_function_operations function_ops = {
-+ event_irq: acm_event_irq,
-+ recv_setup_irq: acm_recv_setup_irq,
-+ function_enable: acm_function_enable,
-+ function_disable: acm_function_disable,
-+};
-+
-+static struct usb_function_driver function_driver = {
-+ name: "acm-CDC",
-+ fops:&function_ops,
-+ device_description:&acm_device_description,
-+ bNumConfigurations:sizeof (acm_description) / sizeof (struct usb_configuration_description),
-+ configuration_description:acm_description,
-+ idVendor: __constant_cpu_to_le16(CONFIG_USBD_ACM_VENDORID),
-+ idProduct: __constant_cpu_to_le16(CONFIG_USBD_ACM_PRODUCTID),
-+ bcdDevice: __constant_cpu_to_le16(CONFIG_USBD_ACM_BCDDEVICE),
-+};
-+
-+#if defined(USE_TICKER)
-+/* usb ticker ********************************************************************************** */
-+
-+#define retrytime 10
-+
-+int ticker_terminating;
-+int ticker_timer_set;
-+
-+static DECLARE_MUTEX_LOCKED (ticker_sem_start);
-+static DECLARE_MUTEX_LOCKED (ticker_sem_work);
-+
-+void ticker_tick (unsigned long data)
-+{
-+ ticker_timer_set = 0;
-+ up (&ticker_sem_work);
-+}
-+
-+void udc_ticker_poke (void)
-+{
-+ up (&ticker_sem_work);
-+}
-+
-+int ticker_thread (void *data)
-+{
-+ struct timer_list ticker;
-+ // detach
-+ lock_kernel ();
-+ exit_mm (current);
-+ exit_files (current);
-+ exit_fs (current);
-+
-+ // setsid equivalent, used at start of kernel thread, no error checks needed, or at least none made :).
-+ current->leader = 1;
-+ current->session = current->pgrp = current->pid;
-+ current->tty = NULL;
-+ current->tty_old_pgrp = 0;
-+ sprintf (current->comm, "acm_fd");
-+
-+ // setup signal handler
-+ current->exit_signal = SIGCHLD;
-+ spin_lock (&current->sigmask_lock);
-+ flush_signals (current);
-+ spin_unlock (&current->sigmask_lock);
-+
-+ // run at a high priority, ahead of sync and friends
-+ current->policy = SCHED_OTHER;
-+ unlock_kernel ();
-+
-+ // setup timer
-+ init_timer (&ticker);
-+ ticker.data = 0;
-+ ticker.function = ticker_tick;
-+
-+ // let startup continue
-+ up (&ticker_sem_start);
-+
-+ // process loop
-+ for (ticker_timer_set = ticker_terminating = 0; !ticker_terminating;) {
-+
-+ struct acm_private * acm = &acm_private;
-+
-+ if (!ticker_timer_set) {
-+ mod_timer (&ticker, jiffies + HZ * retrytime);
-+ }
-+
-+ // wait for someone to tell us to do something
-+ down (&ticker_sem_work);
-+
-+ // sanity checks before proceeding
-+ BREAK_IF(ticker_terminating);
-+ CONTINUE_IF(!(function = acm->function));
-+ CONTINUE_IF(USBD_OK != bus->status);
-+
-+ // do what we need to do
-+ acm_send_int_notification(function, CDC_NOTIFICATION_SERIAL_STATE, acm->ctrlin);
-+ }
-+
-+ // remove timer, let the process stopping us know we are done and return
-+ del_timer (&ticker);
-+ up (&ticker_sem_start);
-+ return 0;
-+}
-+#endif
-+
-+
-+/* USB Module init/exit ************************************************************************ */
-+/*
-+ * acm_modinit - module init
-+ *
-+ */
-+static int acm_modinit (void)
-+{
-+ int i;
-+ printk (KERN_INFO "Copyright (c) 2003-2004 sl@belcarra.com\n");
-+
-+ if (0 != acm_trace_init(ACM_TRACE_NAME)) {
-+ printk(KERN_ERR"%s: ERROR tracing configured, but init failed.\n", __FUNCTION__);
-+ return -EINVAL;
-+ }
-+ TRACE_MSG("entered");
-+
-+ if (vendor_id)
-+ function_driver.idVendor = cpu_to_le16(vendor_id);
-+ if (product_id)
-+ function_driver.idProduct = cpu_to_le16(product_id);
-+ printk (KERN_INFO "%s: %s vendor_id: %04x product_id: %04x\n", __FUNCTION__,
-+ __usbd_module_info, function_driver.idVendor, function_driver.idProduct);
-+
-+ // initialize private structure
-+ acm_private.tty_driver = &acm_tty_driver;
-+ acm_private.wqueue.routine = acm_wakeup_writers;
-+ acm_private.wqueue.data = &acm_private;
-+ acm_private.hqueue.routine = acm_hangup;
-+ acm_private.hqueue.data = &acm_private;
-+
-+ init_waitqueue_head(&acm_private.open_wait);
-+
-+ for (i = 0; i < RECV_RING_SIZE; i++) {
-+ acm_private.recv_ring[i] = NULL;
-+ }
-+ acm_private.rr_in_ndx = acm_private.rr_out_ndx = 0;
-+
-+ // register as tty driver
-+ acm_tty_driver.init_termios = tty_std_termios;
-+ acm_tty_driver.init_termios.c_cflag = B115200 | CS8 | CREAD | HUPCL | CLOCAL;
-+ acm_tty_driver.init_termios.c_lflag &= ~(ECHO | ICANON);
-+ THROW_IF(tty_register_driver(&acm_tty_driver), error);
-+
-+ tty_register_devfs(&acm_tty_driver, 0, ACM_TTY_MINOR);
-+ acm_private.tty_driver_registered++;
-+
-+ // register as usb function driver
-+ THROW_IF (usbd_register_function (&function_driver), error);
-+ acm_private.usb_driver_registered++;
-+
-+#if defined(USE_TICKER)
-+ // kickoff_thread - start management thread
-+ //ticker_terminating = 0;
-+ //kernel_thread (&ticker_thread, NULL, 0);
-+ //down (&ticker_sem_start);
-+#endif
-+
-+ CATCH(error) {
-+ printk(KERN_ERR"%s: ERROR\n", __FUNCTION__);
-+
-+ if (acm_private.tty_driver_registered) {
-+ tty_unregister_driver(&acm_tty_driver);
-+ acm_private.tty_driver_registered = 0;
-+ }
-+ if (acm_private.usb_driver_registered) {
-+ usbd_deregister_function (&function_driver);
-+ acm_private.usb_driver_registered = 0;
-+ }
-+ TRACE_MSG("--> -EINVAL");
-+ return -EINVAL;
-+ }
-+ TRACE_MSG("--> 0");
-+ return 0;
-+}
-+
-+void acm_wait_task(struct tq_struct *queue)
-+{
-+ TRACE_MSG1("entered data=%p",queue->data);
-+ RETURN_IF(!queue->data);
-+ queue->data = NULL;
-+ while (queue->sync) {
-+ //uuu printk(KERN_INFO"%s: waiting for queue: %p\n", __FUNCTION__, queue);
-+ TRACE_MSG1("waiting for queue: %p",queue);
-+ schedule_timeout(HZ);
-+ }
-+ TRACE_MSG("exited");
-+}
-+
-+/* acm_modexit - module cleanup
-+ */
-+static void acm_modexit (void)
-+{
-+ unsigned long flags;
-+ struct urb *urb;
-+ TRACE_MSG("entered");
-+
-+#if defined(USE_TICKER)
-+ // killoff_thread - stop management thread
-+ //if (!ticker_terminating) {
-+ // ticker_terminating = 1;
-+ // up (&ticker_sem_work);
-+ // down (&ticker_sem_start);
-+ //}
-+#endif
-+
-+ // Wake up any pending opens after setting the exiting flag.
-+ local_irq_save(flags);
-+ acm_private.exiting = 1;
-+ if (acm_private.open_wait_count > 0) {
-+ wake_up_interruptible(&acm_private.open_wait);
-+ }
-+ local_irq_restore(flags);
-+
-+ // verify no tasks are running
-+ acm_wait_task(&acm_private.wqueue);
-+ acm_wait_task(&acm_private.hqueue);
-+
-+ // de-register as tty and usb drivers
-+ if (acm_private.tty_driver_registered) {
-+ tty_unregister_driver(&acm_tty_driver);
-+ }
-+ if (acm_private.usb_driver_registered) {
-+ usbd_deregister_function (&function_driver);
-+ }
-+
-+ // Flush any urbs in the recv_ring.
-+ while (acm_private.rr_in_ndx != acm_private.rr_out_ndx) {
-+ // Remove and dealloc one URB from the receive ring
-+ local_irq_save(flags);
-+ urb = acm_private.recv_ring[acm_private.rr_out_ndx];
-+ acm_private.recv_ring[acm_private.rr_out_ndx] = NULL;
-+ acm_private.rr_out_ndx = (acm_private.rr_out_ndx + 1) % RECV_RING_SIZE;
-+ local_irq_restore(flags);
-+ // printk(KERN_INFO"%s: releasing URB %p\n", __FUNCTION__, urb);
-+ usbd_dealloc_urb(urb);
-+ }
-+ acm_trace_exit(ACM_TRACE_NAME);
-+}
-+
-+
-+module_init (acm_modinit);
-+module_exit (acm_modexit);
-diff -Nru a/drivers/usbd/acm_fd/trace.c b/drivers/usbd/acm_fd/trace.c
---- /dev/null Wed Dec 31 16:00:00 1969
-+++ b/drivers/usbd/acm_fd/trace.c Fri Feb 27 14:22:51 2004
-@@ -0,0 +1,530 @@
-+/*
-+ * usbd/acm_fd/trace.c
-+ *
-+ * Copyright (c) 2004 Belcarra
-+ *
-+ * Adapted from earlier work:
-+ * Copyright (c) 2002, 2003 Belcarra
-+ * Copyright (c) 2002 Lineo
-+ *
-+ * By:
-+ * Stuart Lynne <sl@belcarra.com>,
-+ * Tom Rushworth <tbr@belcarra.com>,
-+ *
-+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
-+ *
-+ */
-+
-+#include <linux/config.h>
-+#include <linux/module.h>
-+#include <linux/version.h>
-+
-+#include <linux/kernel.h>
-+#include <linux/slab.h>
-+#include <linux/interrupt.h>
-+#include <linux/pci.h>
-+#include <linux/init.h>
-+#include <linux/delay.h>
-+
-+#include <linux/proc_fs.h>
-+#include <linux/vmalloc.h>
-+
-+#include <asm/atomic.h>
-+#include <asm/io.h>
-+
-+#include <linux/proc_fs.h>
-+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,6)
-+#define USE_ADD_DEL_TIMER_FOR_USBADDR_CHECK 1
-+#include <linux/timer.h>
-+#else
-+#undef USE_ADD_DEL_TIMER_FOR_USBADDR_CHECK
-+#include <linux/tqueue.h>
-+#endif
-+
-+#include <linux/netdevice.h>
-+#include <linux/pci.h>
-+#include <linux/cache.h>
-+
-+
-+#if defined(CONFIG_ARCH_SA1100) || defined (CONFIG_ARCH_PXA)
-+#include <asm/dma.h>
-+#include <asm/mach/dma.h>
-+#include <asm/irq.h>
-+#include <asm/system.h>
-+#include <asm/hardware.h>
-+#include <asm/types.h>
-+#endif
-+
-+#if defined(CONFIG_MIPS_AU1000) || defined(CONFIG_MIPS_PB1500) || defined(CONFIG_MIPS_PB1100) || defined(CONFIG_MIPS_DB1100)
-+#include <asm/au1000.h>
-+#include <asm/au1000_dma.h>
-+#include <asm/mipsregs.h>
-+#endif
-+
-+#if defined(CONFIG_ARCH_SAMSUNG)
-+#include <asm/arch/timers.h>
-+#include <asm/arch/hardware.h>
-+#endif
-+
-+#if defined(CONFIG_ARCH_MX1ADS)
-+#include "dbmx1_bi/dbmx1.h"
-+#endif
-+
-+#include <asm/uaccess.h>
-+#include <asm/io.h>
-+#include <asm/pgtable.h>
-+#include <asm/pgalloc.h>
-+
-+#include <usbd-chap9.h>
-+#include <usbd-mem.h>
-+#include <usbd.h>
-+#include <trace.h>
-+
-+
-+int acm_trace_first;
-+int acm_trace_last_read;
-+int acm_trace_next;
-+int acm_trace_total;
-+acm_trace_t *acm_traces;
-+
-+extern int acm_interrupts;
-+
-+
-+#if defined(CONFIG_USBD_ACM_TRACE) && defined(CONFIG_PROC_FS)
-+
-+acm_trace_t *ACM_TRACE_NEXT(char *fn, acm_trace_types_t acm_trace_type)
-+{
-+ acm_trace_t *p;
-+ unsigned long flags;
-+
-+ // Get the next trace slot - this needs to be atomic.
-+ local_irq_save (flags);
-+ p = acm_traces + acm_trace_next;
-+#if defined(TRACE_MAX_IS_2N)
-+ acm_trace_next = (acm_trace_next + 1) & TRACE_MASK;
-+ if (acm_trace_next == acm_trace_first) {
-+ // We have wraparound, bump acm_trace_first
-+ if (acm_trace_first == acm_trace_last_read) {
-+ // We have to bump last read too.
-+ acm_trace_last_read = (acm_trace_last_read + 1) & TRACE_MASK;
-+ }
-+ acm_trace_first = (acm_trace_first + 1) & TRACE_MASK;
-+ }
-+#else
-+ if (TRACE_MAX <= ++acm_trace_next)
-+ acm_trace_next = 0;
-+
-+ if (acm_trace_next == acm_trace_first) {
-+ // We have wrap around, bump acm_trace_first
-+ if (acm_trace_first == acm_trace_last_read) {
-+ // We have to bump last read too.
-+ if (TRACE_MAX <= ++acm_trace_last_read)
-+ acm_trace_last_read = 0;
-+ }
-+ if (TRACE_MAX <= ++acm_trace_first)
-+ acm_trace_first = 0;
-+ }
-+#endif
-+ acm_trace_total++;
-+ // End of next trace slot.
-+ local_irq_restore (flags);
-+
-+#if defined(CONFIG_ARCH_SA1100) || defined (CONFIG_ARCH_PXA)
-+ p->oscr = OSCR;
-+#elif defined(CONFIG_MIPS_AU1000) || defined(CONFIG_MIPS_PB1500) || defined(CONFIG_MIPS_PB1100) || defined(CONFIG_MIPS_DB1100)
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,19)
-+ p->cp0_count = __read_32bit_c0_register(CP0_COUNT);
-+#else
-+ p->cp0_count = read_c0_count();
-+#endif
-+#elif defined(CONFIG_ARCH_SAMSUNG)
-+ //p->jiffies = jiffies;
-+ //p->tcnt0 = *(volatile u32 *)TCNT0;
-+ p->tcnt1 = *(volatile u32 *)TCNT1;
-+#else
-+ p->jiffies = jiffies;
-+#endif
-+#if defined(CONFIG_MIPS_AU1000) || defined(CONFIG_MIPS_PB1500) || defined(CONFIG_MIPS_PB1100) || defined(CONFIG_MIPS_DB1100)
-+ //p->sofs = au_readl(USBD_FRAMENUM);
-+#endif
-+#if defined(CONFIG_ARCH_MX1ADS)
-+ p->sofs = USBD_FRAME & 0x3ff;
-+#endif
-+
-+ p->interrupts = acm_interrupts;
-+ p->acm_trace_type = acm_trace_type;
-+ p->function = fn;
-+
-+ //printk(KERN_INFO"first: %d next: %d interrupts: %d oscr: %d\n", acm_trace_first, acm_trace_next, acm_interrupts, p->oscr);
-+
-+ return p;
-+}
-+
-+/* Proc Filesystem *************************************************************************** */
-+
-+/* *
-+ * acm_trace_proc_read - implement proc file system read.
-+ * @file
-+ * @buf
-+ * @count
-+ * @pos
-+ *
-+ * Standard proc file system read function.
-+ */
-+static ssize_t acm_trace_proc_read (struct file *file, char *buf, size_t count, loff_t * pos)
-+{
-+ unsigned long page;
-+ int len = 0;
-+ int index;
-+ int oindex;
-+ int previous;
-+ unsigned long flags;
-+
-+ acm_trace_t px;
-+ acm_trace_t ox;
-+ acm_trace_t *o, *p;
-+
-+
-+ MOD_INC_USE_COUNT;
-+
-+ /* Get the index of the entry to read and update last_read - this needs to be atomic. */
-+ p = &px;
-+ o = NULL;
-+ oindex = index = (*pos)++;
-+ local_irq_save (flags);
-+
-+#if defined(TRACE_MAX_IS_2N)
-+ index = (acm_trace_first + index) & TRACE_MASK;
-+#else
-+ index += acm_trace_first;
-+ if (index >= TRACE_MAX) {
-+ index -= TRACE_MAX;
-+ }
-+#endif
-+ // Are we at the end of the data?
-+ if (((acm_trace_first < acm_trace_next) &&
-+ (index >= acm_trace_first) && (index < acm_trace_next)) ||
-+ ((acm_trace_first > acm_trace_next) &&
-+ ((index < acm_trace_next) || (index >= acm_trace_first)))) {
-+ // Nope, there's data to show.
-+ memcpy(p,(acm_traces+index),sizeof(acm_trace_t));
-+ // Is there a previous event?
-+ previous = (index) ? (index - 1) : (TRACE_MAX - 1);
-+ if (previous != acm_trace_next && acm_trace_total > 1) {
-+ // There is a valid previous event.
-+ o = &ox;
-+ memcpy(o,(acm_traces+previous),sizeof(acm_trace_t));
-+ }
-+ acm_trace_last_read = index;
-+ } else {
-+ index = -1;
-+ }
-+ local_irq_restore (flags);
-+ if (index < 0) {
-+ // End of data.
-+ return(0);
-+ }
-+
-+ // get a page, max 4095 bytes of data...
-+ if (!(page = get_free_page (GFP_KERNEL))) {
-+ MOD_DEC_USE_COUNT;
-+ return -ENOMEM;
-+ }
-+
-+ len = 0;
-+
-+ if (oindex == 0) {
-+#if defined(CONFIG_ARCH_SAMSUNG)
-+ len += sprintf ((char *) page + len, " Index Ints Ticks [%d]\n", CONFIG_USBD_SMDK2500_BCLOCK );
-+#else
-+ len += sprintf ((char *) page + len, " Index Ints Ticks\n");
-+#endif
-+ }
-+
-+ //printk(KERN_INFO"first: %d next: %d index: %d %d prev: %d\n", acm_trace_first, acm_trace_next, oindex, index, previous);
-+
-+#if defined(CONFIG_ARCH_SA1100) || defined (CONFIG_ARCH_PXA) || defined(CONFIG_MIPS_AU1000) || defined(CONFIG_MIPS_PB1500) || defined(CONFIG_MIPS_PB1100) || defined(CONFIG_MIPS_DB1100)
-+ u32 ticks = 0;
-+#elif defined(CONFIG_ARCH_SAMSUNG)
-+ u32 ticks = 0;
-+#else
-+ u64 jifs = 0;
-+#endif
-+ unsigned char *cp;
-+ unsigned int *ip;
-+ int skip = 0;
-+
-+ /* If there is a previous trace event, we want to calculate how many
-+ ticks have elapsed siince it happened. Unfortunately, determining
-+ if there _is_ a previous event isn't obvious, since we have to watch
-+ out for startup and wraparound. */
-+ if (o != NULL) {
-+
-+#if defined(CONFIG_ARCH_SA1100) || defined (CONFIG_ARCH_PXA)
-+ /*
-+ * oscr is 3.6864 Mhz free running counter,
-+ *
-+ * 1/3.6864 = .2712
-+ * 60/221 = .2714
-+ *
-+ */
-+ if (o->oscr) {
-+ ticks = (p->oscr > o->oscr) ? (p->oscr - o->oscr) : (o->oscr - p->oscr) ;
-+ ticks = (ticks * 60) / 221;
-+ }
-+
-+#elif defined(CONFIG_MIPS_AU1000) || defined(CONFIG_MIPS_PB1500) || defined(CONFIG_MIPS_PB1100) || defined(CONFIG_MIPS_DB1100)
-+ /*
-+ * cp0_count is incrementing timer at system clock
-+ */
-+ if (o->cp0_count) {
-+ ticks = (p->cp0_count > o->cp0_count) ?
-+ (p->cp0_count - o->cp0_count) : (o->cp0_count - p->cp0_count) ;
-+ ticks = ticks / CONFIG_USBD_AU1X00_SCLOCK;
-+ }
-+
-+#elif defined(CONFIG_ARCH_SAMSUNG)
-+ /*
-+ * tcnt1 is a count-down timer running at the system bus clock
-+ * The divisor must be set as a configuration value, typically 66 or 133.
-+ */
-+ if (o->tcnt1) {
-+ ticks = (p->tcnt1 < o->tcnt1) ? (o->tcnt1 - p->tcnt1) : (p->tcnt1 - o->tcnt1) ;
-+ ticks /= CONFIG_USBD_SMDK2500_BCLOCK;
-+ }
-+#else
-+ if (o->jiffies) {
-+ jifs = p->jiffies - acm_traces[previous].jiffies;
-+ }
-+#endif
-+
-+ if (o->interrupts != p->interrupts) {
-+ skip++;
-+ }
-+ }
-+
-+ //printk(KERN_INFO"index: %d interrupts: %d\n", index, p->interrupts);
-+ len += sprintf ((char *) page + len, "%s%6d %8d ", skip?"\n":"", index, p->interrupts);
-+
-+#if defined(CONFIG_ARCH_SA1100) || defined (CONFIG_ARCH_PXA) || defined(CONFIG_MIPS_AU1000) || defined(CONFIG_MIPS_PB1500) || defined(CONFIG_MIPS_PB1100) || defined(CONFIG_MIPS_DB1100)
-+ if (ticks > 1024*1024) {
-+ len += sprintf ((char *) page + len, "%8dM ", ticks>>20);
-+ }
-+ else {
-+ len += sprintf ((char *) page + len, "%8d ", ticks);
-+ }
-+#elif defined(CONFIG_ARCH_SAMSUNG)
-+ //len += sprintf ((char *) page + len, "%8u ", p->jiffies);
-+ //len += sprintf ((char *) page + len, "%8u ", p->tcnt0);
-+ len += sprintf ((char *) page + len, "%8u ", p->tcnt1);
-+ if (ticks > 1024*1024) {
-+ len += sprintf ((char *) page + len, "%8dM ", ticks>>20);
-+ }
-+ else {
-+ len += sprintf ((char *) page + len, "%8d ", ticks);
-+ }
-+#else
-+ if (jifs > 1024) {
-+ len += sprintf ((char *) page + len, "%4dK ", (int)jifs>>10);
-+ }
-+ else {
-+ len += sprintf ((char *) page + len, "%4d ", (int)jifs);
-+ }
-+#endif
-+#if defined(CONFIG_ARCH_MX1ADS)
-+ len += sprintf ((char *) page + len, "%6d ", (int)p->sofs);
-+#endif
-+
-+ switch (p->acm_trace_type) {
-+ case acm_trace_msg_n:
-+ len += sprintf ((char *) page + len, " -- %s: ",p->function);
-+ len += sprintf ((char *) page + len, p->trace.msg.msg);
-+ break;
-+
-+ case acm_trace_msg32_n:
-+ len += sprintf ((char *) page + len, " -- %s: ",p->function);
-+ len += sprintf ((char *) page + len, p->trace.msg32.msg, p->trace.msg32.val);
-+ break;
-+
-+ case acm_trace_msg16_n:
-+ len += sprintf ((char *) page + len, " -- %s: ",p->function);
-+ len += sprintf ((char *) page + len, p->trace.msg16.msg, p->trace.msg16.val0, p->trace.msg16.val1);
-+ break;
-+
-+ case acm_trace_msg8_n:
-+ len += sprintf ((char *) page + len, " -- %s: ",p->function);
-+ len += sprintf ((char *) page + len, p->trace.msg8.msg,
-+ p->trace.msg8.val0, p->trace.msg8.val1, p->trace.msg8.val2, p->trace.msg8.val3);
-+ break;
-+
-+ case acm_trace_setup_n:
-+ cp = (unsigned char *)&p->trace.setup;
-+ len += sprintf ((char *) page + len,
-+ " -- %s: request [%02x %02x %02x %02x %02x %02x %02x %02x]",
-+ p->function, cp[0], cp[1], cp[2], cp[3], cp[4], cp[5], cp[6], cp[7]);
-+ break;
-+ }
-+ len += sprintf ((char *) page + len, "\n");
-+
-+ // len == 0 is valid, it just means we've reached the end of the data.
-+ if (len > count) {
-+ len = -EINVAL;
-+ }
-+ else if (len > 0 && copy_to_user (buf, (char *) page, len)) {
-+ len = -EFAULT;
-+ }
-+ free_page (page);
-+ MOD_DEC_USE_COUNT;
-+ return len;
-+}
-+
-+/* *
-+ * acm_trace_proc_write - implement proc file system write.
-+ * @file
-+ * @buf
-+ * @count
-+ * @pos
-+ *
-+ * Proc file system write function.
-+ */
-+static ssize_t acm_trace_proc_write (struct file *file, const char *buf, size_t count, loff_t * pos)
-+{
-+#define MAX_TRACE_CMD_LEN 64
-+ char command[MAX_TRACE_CMD_LEN+1];
-+ size_t n = count;
-+ size_t l;
-+ char c;
-+
-+ if (n > 0) {
-+ l = MIN(n,MAX_TRACE_CMD_LEN);
-+ if (copy_from_user (command, buf, l)) {
-+ count = -EFAULT;
-+ } else {
-+ // flush remainder, if any
-+ n -= l;
-+ while (n > 0) {
-+ // Not too efficient, but it shouldn't matter
-+ if (copy_from_user (&c, buf + (count - n), 1)) {
-+ count = -EFAULT;
-+ break;
-+ }
-+ n -= 1;
-+ }
-+ // Terminate command[]
-+ if (l > 0 && command[l-1] == '\n') {
-+ l -= 1;
-+ }
-+ command[l] = 0;
-+ }
-+ }
-+
-+ if (0 >= count) {
-+ printk(KERN_INFO"%s: count <= 0 %d\n", __FUNCTION__, count);
-+ return count;
-+ }
-+
-+ if (!strncmp("flush", command, 5)) {
-+ /* Move pointers so that next read continues from last read point,
-+ instead of all available messages - this needs to be atomic. */
-+ unsigned long flags;
-+
-+ local_irq_save (flags);
-+#if defined(TRACE_MAX_IS_2N)
-+ acm_trace_first = (acm_trace_last_read + 1) & TRACE_MASK;
-+#else
-+ if (TRACE_MAX <= (acm_trace_first = acm_trace_last_read + 1)) {
-+ acm_trace_first = 0;
-+ }
-+#endif
-+ local_irq_restore (flags);
-+ }
-+
-+ return count;
-+}
-+
-+static struct file_operations acm_trace_proc_operations_functions = {
-+ read:acm_trace_proc_read,
-+ write:acm_trace_proc_write,
-+};
-+
-+#if defined(CONFIG_ARCH_SAMSUNG)
-+#endif
-+
-+/**
-+ * acm_trace_init
-+ *
-+ * Return non-zero if not successful.
-+ */
-+int acm_trace_init (char *name)
-+{
-+ printk(KERN_INFO"%s: creating /proc/%s with %u entries\n", __FUNCTION__,name,TRACE_MAX);
-+ if (!(acm_traces = vmalloc(sizeof(acm_trace_t) * TRACE_MAX))) {
-+ printk(KERN_ERR"%s: malloc failed %p %d\n", __FUNCTION__, acm_traces, sizeof(acm_trace_t) * TRACE_MAX);
-+ return -EINVAL;
-+ }
-+ memset(acm_traces, 0, sizeof(acm_trace_t) * TRACE_MAX);
-+ acm_trace_last_read = TRACE_MAX - 1;
-+
-+ {
-+ struct proc_dir_entry *p;
-+
-+ // create proc filesystem entries
-+ if ((p = create_proc_entry (name, 0, 0)) == NULL) {
-+ printk(KERN_INFO"%s PROC FS failed\n",name);
-+ }
-+ else {
-+ p->proc_fops = &acm_trace_proc_operations_functions;
-+ }
-+ }
-+#if defined(CONFIG_ARCH_SAMSUNG)
-+ *(volatile u32 *)TMOD |= 0x3 << 3;
-+#endif
-+ printk(KERN_INFO"%s: OK\n", __FUNCTION__);
-+ return 0;
-+}
-+
-+/**
-+ * acm_trace_exit - remove procfs entry, free trace data space.
-+ */
-+void acm_trace_exit (char *name)
-+{
-+ {
-+ unsigned long flags;
-+ local_irq_save (flags);
-+ remove_proc_entry (name, NULL);
-+ if (acm_traces) {
-+ acm_trace_t *p = acm_traces;
-+ acm_traces = NULL;
-+ vfree(p);
-+ }
-+ local_irq_restore (flags);
-+ }
-+}
-+
-+
-+#else
-+int acm_trace_init (char *name)
-+{
-+ return 0;
-+}
-+
-+void acm_trace_exit (char *name)
-+{
-+ return;
-+}
-+#endif
-+
-+/* End of FILE */
-+
-diff -Nru a/drivers/usbd/acm_fd/trace.h b/drivers/usbd/acm_fd/trace.h
---- /dev/null Wed Dec 31 16:00:00 1969
-+++ b/drivers/usbd/acm_fd/trace.h Fri Feb 27 14:22:51 2004
-@@ -0,0 +1,268 @@
-+/*
-+ * usbd/acm_fd/trace.h
-+ *
-+ * Copyright (c) 2004 Belcarra
-+ *
-+ * Adapted from earlier work:
-+ * Copyright (c) 2002, 2003 Belcarra
-+ * Copyright (c) 2002 Lineo
-+ *
-+ * By:
-+ * Stuart Lynne <sl@belcarra.com>,
-+ * Tom Rushworth <tbr@belcarra.com>,
-+ *
-+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
-+ *
-+ */
-+
-+#if defined(CONFIG_ARCH_SAMSUNG)
-+#ifndef CONFIG_USBD_SMDK2500_BCLOCK
-+#define CONFIG_USBD_SMDK2500_BCLOCK 66
-+#endif
-+#endif
-+
-+/* Fast Trace Utility
-+ This set of definitions and code is meant to provide a _fast_ debugging facility
-+ (much faster than printk) so that time critical code can be debugged by looking
-+ at a trace of events provided by reading a file in the procfs without affecting
-+ the timing of events in the critical code.
-+
-+ The mechanism used it to allocate a (large) ring buffer of relatively small structures
-+ that include location and high-res timestamp info, and up to 8 bytes of optional
-+ data. Values are stored and timestamps are taken as the critical code runs, but
-+ data formatting and display are done during the procfs read, when more time is
-+ available :).
-+
-+ Note that there is usually some machine dependent code involved in getting the
-+ high-res timestamp, and there may be other bits used just to keep the overall
-+ time impact as low as possible.
-+
-+ varargs style macros were avoided because there seems to be no way to avoid
-+ a run-time check on the number of arguments if they are used, and the time penalty
-+ doesn't seem to be worth the gain in utility.
-+ */
-+
-+typedef enum acm_trace_types {
-+ acm_trace_setup_n, acm_trace_msg_n, acm_trace_msg32_n, acm_trace_msg16_n, acm_trace_msg8_n
-+} acm_trace_types_t;
-+
-+typedef struct acm_trace_msg {
-+ char *msg;
-+} acm_trace_msg_t;
-+
-+typedef struct acm_trace_msg32 {
-+ u32 val;
-+ char *msg;
-+} acm_trace_msg32_t;
-+
-+typedef struct acm_trace_msg16 {
-+ u16 val0;
-+ u16 val1;
-+ char *msg;
-+} acm_trace_msg16_t;
-+
-+typedef struct acm_trace_msg8 {
-+ u8 val0;
-+ u8 val1;
-+ u8 val2;
-+ u8 val3;
-+ char *msg;
-+} acm_trace_msg8_t;
-+
-+
-+typedef struct trace {
-+ acm_trace_types_t acm_trace_type;
-+ char *function;
-+ u32 interrupts;
-+#if defined(CONFIG_ARCH_SA1100) || defined (CONFIG_ARCH_PXA)
-+ u32 oscr;
-+#elif defined(CONFIG_MIPS_AU1000) || defined(CONFIG_MIPS_PB1500) || defined(CONFIG_MIPS_PB1100) || defined(CONFIG_MIPS_DB1100)
-+ u32 cp0_count;
-+#elif defined(CONFIG_ARCH_SAMSUNG)
-+ //u32 tcnt0;
-+ u32 tcnt1;
-+ //u64 jiffies;
-+#else
-+ u64 jiffies;
-+#endif
-+#if defined(CONFIG_MIPS_AU1000) || defined(CONFIG_MIPS_PB1500) || defined(CONFIG_MIPS_PB1100) || defined(CONFIG_MIPS_DB1100) || defined(CONFIG_ARCH_MX1ADS)
-+ u64 sofs;
-+#endif
-+ union {
-+ acm_trace_msg_t msg;
-+ acm_trace_msg8_t msg8;
-+ acm_trace_msg16_t msg16;
-+ acm_trace_msg32_t msg32;
-+
-+ struct usb_device_request setup;
-+
-+ } trace;
-+
-+} acm_trace_t;
-+
-+#define TRACE_MAX_IS_2N 1
-+#if defined(TRACE_MAX_IS_2N)
-+#define TRACE_MAX 0x00008000
-+#define TRACE_MASK 0x00007FFF
-+#else
-+#define TRACE_MAX 30000
-+#endif
-+
-+extern int acm_trace_first;
-+extern int acm_trace_last_read;
-+extern int acm_trace_next;
-+
-+extern acm_trace_t *acm_traces;
-+
-+#ifdef CONFIG_USBD_ACM_TRACE
-+
-+acm_trace_t *ACM_TRACE_NEXT(char *fn, acm_trace_types_t acm_trace_type);
-+
-+#if 0
-+static __inline__ acm_trace_t *ACM_TRACE_NEXT(char *fn, acm_trace_types_t acm_trace_type)
-+{
-+ acm_trace_t *p;
-+ unsigned long flags;
-+
-+ // Get the next trace slot - this needs to be atomic.
-+ local_irq_save (flags);
-+ p = acm_traces + acm_trace_next;
-+#if defined(TRACE_MAX_IS_2N)
-+ acm_trace_next = (acm_trace_next + 1) & TRACE_MASK;
-+ if (acm_trace_next == acm_trace_first) {
-+ // We have wraparound, bump acm_trace_first
-+ if (acm_trace_first == acm_trace_last_read) {
-+ // We have to bump last read too.
-+ acm_trace_last_read = (acm_trace_last_read + 1) & TRACE_MASK;
-+ }
-+ acm_trace_first = (acm_trace_first + 1) & TRACE_MASK;
-+ }
-+#else
-+ if (TRACE_MAX <= ++acm_trace_next)
-+ acm_trace_next = 0;
-+
-+ if (acm_trace_next == acm_trace_first) {
-+ // We have wrap around, bump acm_trace_first
-+ if (acm_trace_first == acm_trace_last_read) {
-+ // We have to bump last read too.
-+ if (TRACE_MAX <= ++acm_trace_last_read)
-+ acm_trace_last_read = 0;
-+ }
-+ if (TRACE_MAX <= ++acm_trace_first)
-+ acm_trace_first = 0;
-+ }
-+#endif
-+ // End of next trace slot.
-+ local_irq_restore (flags);
-+
-+#if defined(CONFIG_ARCH_SA1100) || defined (CONFIG_ARCH_PXA)
-+ p->oscr = OSCR;
-+#elif defined(CONFIG_MIPS_AU1000) || defined(CONFIG_MIPS_PB1500) || defined(CONFIG_MIPS_PB1100) || defined(CONFIG_MIPS_DB1100)
-+ //p->cp0_count = __read_32bit_c0_register(CP0_COUNT);
-+ p->cp0_count = read_c0_count();
-+#elif defined(CONFIG_ARCH_SAMSUNG)
-+ //p->jiffies = jiffies;
-+ //p->tcnt0 = *(volatile u32 *)TCNT0;
-+ p->tcnt1 = *(volatile u32 *)TCNT1;
-+#else
-+ p->jiffies = jiffies;
-+#endif
-+#if defined(CONFIG_MIPS_AU1000) || defined(CONFIG_MIPS_PB1500) || defined(CONFIG_MIPS_PB1100) || defined(CONFIG_MIPS_DB1100)
-+ //p->sofs = au_readl(USBD_FRAMENUM);
-+#endif
-+
-+ p->interrupts = udc_interrupts;
-+ p->acm_trace_type = acm_trace_type;
-+ p->function = fn;
-+
-+ acm_trace_next++;
-+ acm_trace_next = (acm_trace_next == TRACE_MAX) ? 0 : acm_trace_next;
-+
-+ if (acm_trace_next == acm_trace_first) {
-+ acm_trace_first++;
-+ acm_trace_first = (acm_trace_first == TRACE_MAX) ? 0 : acm_trace_first;
-+ }
-+ //printk(KERN_INFO"first: %d next: %d interrupts: %d\n", acm_trace_first, acm_trace_next, udc_interrupts);
-+
-+ return p;
-+}
-+#endif
-+
-+static __inline__ void acm_trace_setup(char *fn, struct usb_device_request *setup)
-+{
-+ if (acm_traces) {
-+ acm_trace_t *p = ACM_TRACE_NEXT(fn,acm_trace_setup_n);
-+ memcpy(&p->trace.setup, setup, sizeof(struct usb_device_request));
-+ }
-+}
-+#define TRACE_SETUP(setup) acm_trace_setup(__FUNCTION__,setup)
-+
-+static __inline__ void acm_trace_msg(char *fn, char *msg)
-+{
-+ if (acm_traces) {
-+ acm_trace_t *p = ACM_TRACE_NEXT(fn,acm_trace_msg_n);
-+ p->trace.msg.msg = msg;
-+ }
-+}
-+#define TRACE_MSG(msg) acm_trace_msg(__FUNCTION__,msg)
-+
-+
-+static __inline__ void acm_trace_msg_1xU32(char *fn, char *fmt, u32 val)
-+{
-+ if (acm_traces) {
-+ acm_trace_t *p = ACM_TRACE_NEXT(fn,acm_trace_msg32_n);
-+ p->trace.msg32.val = val;
-+ p->trace.msg32.msg = fmt;
-+ }
-+}
-+#define TRACE_MSG1(fmt,val) acm_trace_msg_1xU32(__FUNCTION__,fmt,(u32)val)
-+
-+static __inline__ void acm_trace_msg_2xU16(char *fn, char *fmt, u16 val0, u16 val1)
-+{
-+ if (acm_traces) {
-+ acm_trace_t *p = ACM_TRACE_NEXT(fn,acm_trace_msg16_n);
-+ p->trace.msg16.val0 = val0;
-+ p->trace.msg16.val1 = val1;
-+ p->trace.msg16.msg = fmt;
-+ }
-+}
-+#define TRACE_MSG2(fmt,val0,val1) acm_trace_msg_2xU16(__FUNCTION__,fmt,(u16)val0,(u16)val1)
-+
-+static __inline__ void acm_trace_msg_4xU8(char *fn, char *fmt, u8 val0, u8 val1, u8 val2, u8 val3)
-+{
-+ if (acm_traces) {
-+ acm_trace_t *p = ACM_TRACE_NEXT(fn,acm_trace_msg8_n);
-+ p->trace.msg8.val0 = val0;
-+ p->trace.msg8.val1 = val1;
-+ p->trace.msg8.val2 = val2;
-+ p->trace.msg8.val3 = val3;
-+ p->trace.msg8.msg = fmt;
-+ }
-+}
-+#define TRACE_MSG4(fmt,val0,val1,val2,val3) acm_trace_msg_4xU8(__FUNCTION__,fmt,(u8)val0,(u8)val1,(u8)val2,(u8)val3)
-+
-+#else
-+
-+#define TRACE_SETUP(setup)
-+#define TRACE_MSG(msg)
-+#define TRACE_MSG1(fmt,val)
-+#define TRACE_MSG2(fmt,val0,val1)
-+#define TRACE_MSG4(fmt,val0,val1,val2,val3)
-+
-+#endif
-+
-+int acm_trace_init (char *str);
-+void acm_trace_exit (char *str);
-+
-diff -Nru a/drivers/usbd/au1x00_bi/Config.in b/drivers/usbd/au1x00_bi/Config.in
---- /dev/null Wed Dec 31 16:00:00 1969
-+++ b/drivers/usbd/au1x00_bi/Config.in Fri Feb 27 14:22:51 2004
-@@ -0,0 +1,27 @@
-+
-+# USB device configuration from the device viewpoint (e.g. Linux running inside a USB device, not as host)
-+#
-+# Copyright (c) 2002-2003 Belcarra
-+#
-+
-+#
-+# CONFIG_SOC_AU1X00 and/or CONFIG_MIPS_AU1X00 are the new and preferred tags (as of 2.4.20)
-+#
-+# CONFIG_MIPS_AU1000, CONFIG_MIPS_AU1100, CONFIG_MIPS_AU1500 are deprecated (prior to 2.4.20)
-+#
-+
-+if [ "$CONFIG_SOC_AU1X00" = "y" -o "$CONFIG_MIPS_AU1X00" = "y" -o "$CONFIG_CPU_AU1X00" = "y" -o "$CONFIG_MIPS_AU1500" = "y" -o "$CONFIG_MIPS_AU1100" = "y" -o "$CONFIG_MIPS_AU1000" = "y" ]
-+then
-+ mainmenu_option next_comment
-+
-+ comment 'AMD AU1X000 Bus Interface'
-+
-+ dep_tristate ' AU1X00 (AMD/Alchemy) support' CONFIG_USBD_AU1X00_BUS $CONFIG_USBD
-+ if [ "$CONFIG_USBD_AU1X00_BUS" = "m" -o "$CONFIG_USBD_AU1X00_BUS" = "y" ]; then
-+ int ' AU1X00 System Clock' CONFIG_USBD_AU1X00_SCLOCK 400
-+ fi
-+ define_bool CONFIG_AU1000_USB_DEVICE y
-+ define_bool CONFIG_AU1X00_USB_DEVICE y
-+
-+ endmenu
-+fi
-diff -Nru a/drivers/usbd/au1x00_bi/Makefile b/drivers/usbd/au1x00_bi/Makefile
---- /dev/null Wed Dec 31 16:00:00 1969
-+++ b/drivers/usbd/au1x00_bi/Makefile Fri Feb 27 14:22:51 2004
-@@ -0,0 +1,88 @@
-+#
-+# Makefile for the kernel USBD (device not host) drivers.
-+#
-+# Copyright (c) 2002 Belcarra
-+
-+# Subdirs.
-+# This is a bit complex, because some subdirs are for
-+# proprietary code, and are simply not present in a
-+# general distribution.
-+
-+# The all-CAPS *_DIRS get nuked in the new versions
-+# of Rules.make, so use only the subdir-* methods.
-+subdir-y :=
-+subdir-m :=
-+subdir-n :=
-+subdir- :=
-+
-+# The target object and module list name.
-+
-+O_TARGET := au1x00_bi.o
-+
-+# Objects that export symbols.
-+
-+export-objs :=
-+
-+# Multipart objects.
-+
-+au1x00_bi-objs := au1x00.o usbd-bi.o trace.o
-+
-+# Optional parts of multipart objects.
-+
-+# Object file lists.
-+
-+#obj-y := usbd-bi.o
-+obj-y :=
-+obj-m :=
-+obj-n :=
-+obj- :=
-+
-+# Each configuration option enables a list of files.
-+
-+obj-$(CONFIG_USBD_AU1X00_BUS) += au1x00_bi.o
-+
-+# Object files in subdirectories
-+
-+
-+# Extract lists of the multi-part drivers.
-+# The 'int-*' lists are the intermediate files used to build the multi's.
-+
-+multi-y := $(filter $(list-multi), $(obj-y))
-+multi-m := $(filter $(list-multi), $(obj-m))
-+int-y := $(sort $(foreach m, $(multi-y), $($(basename $(m))-objs)))
-+int-m := $(sort $(foreach m, $(multi-m), $($(basename $(m))-objs)))
-+
-+# Files that are both resident and modular: remove from modular.
-+
-+obj-m := $(filter-out $(obj-y), $(obj-m))
-+int-m := $(filter-out $(int-y), $(int-m))
-+
-+# Translate to Rules.make lists.
-+
-+O_OBJS := $(filter-out $(export-objs), $(obj-y))
-+OX_OBJS := $(filter $(export-objs), $(obj-y))
-+M_OBJS := $(sort $(filter-out $(export-objs), $(obj-m)))
-+MX_OBJS := $(sort $(filter $(export-objs), $(obj-m)))
-+MI_OBJS := $(sort $(filter-out $(export-objs), $(int-m)))
-+MIX_OBJS := $(sort $(filter $(export-objs), $(int-m)))
-+
-+# The global Rules.make.
-+
-+include $(TOPDIR)/Rules.make
-+USBD=$(TOPDIR)/drivers/usbd
-+BI_DIR=$(USBD)/au1x00_bi
-+EXTRA_CFLAGS += -Wno-missing-prototypes -Wno-unused -Wno-format -I$(USBD) -I$(BI_DIR)
-+EXTRA_CFLAGS_nostdinc += -Wno-missing-prototypes -Wno-unused -Wno-format -I$(USBD) -I$(BI_DIR)
-+
-+vpath %.c $(USBD)
-+
-+# Link rules for multi-part drivers.
-+
-+au1x00_bi.o: $(au1x00_bi-objs)
-+ $(LD) -r -o $@ $(au1x00_bi-objs)
-+
-+# dependencies:
-+
-+# local
-+
-+
-diff -Nru a/drivers/usbd/au1x00_bi/au1x00.c b/drivers/usbd/au1x00_bi/au1x00.c
---- /dev/null Wed Dec 31 16:00:00 1969
-+++ b/drivers/usbd/au1x00_bi/au1x00.c Fri Feb 27 14:22:51 2004
-@@ -0,0 +1,1268 @@
-+/*
-+ * usbd/au1x00_bi/au1x00.c -- USB Device Controller driver.
-+ *
-+ * Copyright (c) 2004 Belcarra
-+ *
-+ * Adapted from earlier work:
-+ * Copyright (c) 2002, 2003 Belcarra
-+ * Copyright (c) 2002 Lineo
-+ *
-+ * By:
-+ * Stuart Lynne <sl@belcarra.com>,
-+ * Tom Rushworth <tbr@belcarra.com>,
-+ *
-+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
-+ *
-+ * Notes
-+ *
-+ * 1. EP0 - packetsize of 8 does not work, this means that PIO cannot be used for IN (transmit).
-+ * DMA must be used. Only 16, 32 and 64 are usable.
-+ *
-+ * Update: even though we couldn't program the endpoint size to 8, we just set it to 8 in the
-+ * device descriptor and things work ok. This works and we don't need or use DMA for either
-+ * direction for EP0.
-+ *
-+ * 2. For each BULK transfer the first N packets must be sent with the full packetsize and the
-+ * last must be sent as a short packet. The packetsize must be set before enabling the DMA.
-+ *
-+ * 3. For IN endpoints an interrupt will be generated for EVERY IN packet including ones that
-+ * will be NAK'd. To reduce overhead the interrupt should only be enabled when there is data
-+ * being sent and we need to know when it has been sent.
-+ *
-+ * Update: for new silicon this is not true, the UDC will interrupt less often and will NAK
-+ * until the interrupt is cleared.
-+ *
-+ * 4. The AU1x00 auto-acks many setup commands and is very sensitive to latency of the irq
-+ * handler processing the interrupt and clearing the ep0 fifo. Like the pxa we need to spool the
-+ * requests and process later when we receive a request for data. There is a special test in
-+ * the bulk data receive handler to check if there are spooled requests to process.
-+ *
-+ * Update: this has been mostly mitigated by reducing all upper layer processing in recv_setup,
-+ * event_irq etc so that they complete in less than a milli-second. This simplifies things and
-+ * we can now pass UUT tests.
-+ *
-+ * 5. There is a time sensitive problem in au_in_epn(). Without a udelay(8) sending large
-+ * packets will eventually stall interrupts.
-+ *
-+ * Update: this is not required for new silicon.
-+ *
-+ * 6. When receiving data (Bulk OUT) the UDC will not start NAKing until and unless the receive
-+ * FIFO is full. This means that there is no reliable way to determine the end of one packet and
-+ * the beginning of the next if there is any undue latency in handling the interrupt for the
-+ * first packet.
-+ *
-+ * The Belcarra Windows and Macintosh network class drivers have an option that can be used
-+ * to pad all outgoing packets to a multiple of 8 bytes. This helps eliminate this problem.
-+ *
-+ * Update: this is not a problem with new silicon, it NAK's until the interrupt is cleared.
-+ *
-+ * 8. The original AU1x00 UDC generated an interrupt for EVERY IN packet. If we do not have
-+ * any data we need to disable the interrupt for the endpoint to eliminate the overhead
-+ * for processing them. The interrupt must be re-enabled when DMA is finished and we
-+ * actually want to know that the endpoint has finished.
-+ *
-+ * Leaving the interrupt enabled also interfers with the DMA process. It is not apparant
-+ * why.
-+ *
-+ * Update: This has been fixed on the new silicon but it doesn't hurt to continue to do this.
-+ *
-+ * 9. The DMA functions replace the equivalent routines in au1100_dma.h except that they pass
-+ * the actual struct dma_chan pointer instead of the channel number. The bounds checking and
-+ * table lookup to derive this information amounts to a substantial increase in code size and
-+ * latency which can simply be avoided by using the structure address directly and/or doing the
-+ * equivalent i/o directly.
-+ */
-+
-+
-+#include <udc.h>
-+#include "au1x00.h"
-+
-+#include <asm/io.h>
-+#include <asm/au1000.h>
-+#include <asm/au1000_dma.h>
-+#include <asm/mipsregs.h>
-+
-+
-+#ifdef CONFIG_MIPS_FREEHAND
-+#include <linux/i2c.h>
-+#include <linux/sensors.h> /* for reading serial number */
-+#endif
-+
-+MODULE_AUTHOR ("sl@belcarra.com, tbr@belcarra.com");
-+MODULE_DESCRIPTION ("USB Device AU1x00 Bus Interface");
-+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,17)
-+MODULE_LICENSE("GPL");
-+#endif
-+USBD_MODULE_INFO ("au1x00_bi 2.0-beta");
-+const char *usbd_bi_module_info(void)
-+{ return __usbd_module_info; }
-+
-+#undef CHECK_LATENCY
-+#undef RECORD_LATENCY
-+#undef MAX_INTR_LOOP_STATS 10
-+#if defined(MAX_INTR_LOOP_STATS)
-+static u32 interrupt_loop_stats[MAX_INTR_LOOP_STATS+1];
-+#endif
-+#ifdef RECORD_LATENCY
-+#define CP0_COUNTS 50
-+u32 cp0_counts[CP0_COUNTS];
-+u32 cp0_record;
-+#endif
-+u32 cp0_count;
-+unsigned int udc_interrupts;
-+unsigned int udc_saw_bus_activity;
-+int au_halt_dma_expired;
-+u32 au1x00_new_silicon;
-+u32 au1x00_inten;
-+static int udc_connected_status;
-+
-+__u8 au1x00_config_bulk[25] = {
-+ 0x04, (USB_ENDPOINT_CONTROL << 4) | (EP0_PACKETSIZE & 0x380) >> 7, // 1
-+ (EP0_PACKETSIZE & 0x7F) << 1, 0x00, 0x00,
-+ 0x24, (USB_ENDPOINT_BULK << 4) | USB_DIR_IN | (MAX_EPN_PACKET_SIZE & 0x380) >> 7, // 6
-+ (MAX_EPN_PACKET_SIZE & 0x7F) << 1, 0x00, 0x02,
-+ 0x34, (USB_ENDPOINT_BULK << 4) | USB_DIR_IN | (MAX_EPN_PACKET_SIZE & 0x380) >> 7, // 11
-+ (MAX_EPN_PACKET_SIZE & 0x7F) << 1, 0x00, 0x03,
-+ 0x44, (USB_ENDPOINT_BULK << 4) | USB_DIR_OUT | (MAX_EPN_PACKET_SIZE & 0x380) >> 7, // 16
-+ (MAX_EPN_PACKET_SIZE & 0x7F) << 1, 0x00, 0x04,
-+ 0x54, (USB_ENDPOINT_BULK << 4) | USB_DIR_OUT | (MAX_EPN_PACKET_SIZE & 0x380) >> 7, // 21
-+ (MAX_EPN_PACKET_SIZE & 0x7F) << 1, 0x00, 0x05,
-+};
-+
-+/* ********************************************************************************************* */
-+/* Note - The endpoints names are confusing. To simplify mapping of the interrupt request lines
-+ * we use a numbering of the physical endpoints of 0-5, which also matches the fifo numbering
-+ * (see the config block).
-+ *
-+ * Physical FIFO Name Direction Logical
-+ * 0 0 EP0 OUT 0
-+ * 1 1 EP0 IN 0
-+ * 2 2 EP1 IN 81
-+ * 3 3 EP2 IN 82
-+ * 4 4 EP3 OUT 3
-+ * 5 5 EP4 OUT 4
-+ *
-+ * The ep_regs array maps a physical endpoint number to the registers required to access the udc
-+ * for that endpoint. Note that ep0 is always accessed via 0. The epl2p array maps the logical
-+ * addresses back to the physical number. The epp2l array maps the physical number to the
-+ * logical endpoint address
-+ */
-+struct ep_regs ep_regs[6] = {
-+ { rd: USBD_EP0RD, rds: USBD_EP0RDSTAT, /*rx_id: DMA_ID_USBDEV_EP0_RX,*/ cs: USBD_EP0CS, rx_str: "EP0 OUT RD",
-+ wr: USBD_EP0WR, wrs: USBD_EP0WRSTAT, tx_id: DMA_ID_USBDEV_EP0_TX, tx_str: "EP0 IN WR",},
-+ { rds: 0, wrs: 0, indma: -1, outdma: -1, },
-+ { wr: NUSBD_EP1WR, wrs: NUSBD_EP1WRSTAT, tx_id: NDMA_ID_USBDEV_EP1_TX, cs: NUSBD_EP1CS, tx_str: "EP1 IN WR",},
-+ { wr: NUSBD_EP2WR, wrs: NUSBD_EP2WRSTAT, tx_id: NDMA_ID_USBDEV_EP2_TX, cs: NUSBD_EP2CS, tx_str: "EP2 IN WR",},
-+
-+ { rd: NUSBD_EP3RD, rds: NUSBD_EP3RDSTAT, rx_id: NDMA_ID_USBDEV_EP3_RX, cs: NUSBD_EP3CS, rx_str: "EP3 OUT RD",},
-+ { rd: NUSBD_EP4RD, rds: NUSBD_EP4RDSTAT, rx_id: NDMA_ID_USBDEV_EP4_RX, cs: NUSBD_EP4CS, rx_str: "EP4 OUT RD",},
-+};
-+__u8 epl2p[6] = { 0x00, 0x02, 0x03, 0x04, 0x05, 0x00, }; // map logical to physical
-+__u8 epp2l[6] = { 0x00, 0x00, 0x81, 0x82, 0x03, 0x04, }; // map physical to logical
-+
-+static __inline__ void au_fifo_read(struct ep_regs *ep, unsigned char * cp, int bytes)
-+{
-+ u32 rd = ep->rd;
-+ for (; bytes--; *cp++ = au_readl(rd));
-+}
-+
-+static __inline__ void au_fifo_write(int ep, unsigned char * cp, int bytes)
-+{
-+ u32 wr = ep_regs[ep].wr;
-+ for (; bytes--; au_writel(*cp++, wr));
-+ ep_regs[ep].last = bytes;
-+}
-+
-+void __inline__ au_inten(u32 inten)
-+{
-+ au1x00_inten = inten;
-+ au_writel(au1x00_inten, USBD_INTEN);
-+}
-+
-+void __inline__ udc_epn_interrupt_enable(int epn)
-+{
-+ au_inten(au1x00_inten | (1 << epn));
-+}
-+
-+void __inline__ udc_epn_interrupt_disable(int epn)
-+{
-+ au_inten(au1x00_inten & ~(1 << epn));
-+ au_writel((1 << epn) , USBD_INTSTAT);
-+}
-+
-+static void __inline__ send_zlp(unsigned char epn)
-+{
-+ au_writel(USBDEV_FSTAT_FLUSH | USBDEV_FSTAT_UF | USBDEV_FSTAT_OF, ep_regs[epn].wrs);
-+ au_writel(0 << 1, ep_regs[epn].cs);
-+ au_writel(0, ep_regs[epn].wr);
-+}
-+/* ********************************************************************************************* */
-+#define AU_DMA_HALT_POLL 0x1000
-+static void __inline__ au_halt_dma(struct dma_chan *chan)
-+{
-+ int i;
-+ au_writel(DMA_GO, chan->io + DMA_MODE_CLEAR);
-+ for (i = 0; i < AU_DMA_HALT_POLL; i++)
-+ RETURN_IF (au_readl(chan->io + DMA_MODE_READ) & DMA_HALT);
-+ au_halt_dma_expired++;
-+}
-+
-+static int __inline__ au_get_dma_residue(struct dma_chan *chan)
-+{
-+ int curBufCntReg = (au_readl(chan->io + DMA_MODE_READ) & DMA_AB) ? DMA_BUFFER1_COUNT : DMA_BUFFER0_COUNT;
-+ return au_readl(chan->io + curBufCntReg) & DMA_COUNT_MASK;
-+}
-+
-+static void __inline__ au_start_dma(struct dma_chan *chan, __u8 *bp, int len)
-+{
-+ if (au_readl(chan->io + DMA_MODE_READ) & DMA_AB) {
-+ au_writel(DMA_D1, chan->io + DMA_MODE_CLEAR);
-+ au_writel(len & DMA_COUNT_MASK, chan->io + DMA_BUFFER1_COUNT);
-+ au_writel(0, chan->io + DMA_BUFFER0_COUNT);
-+ au_writel(virt_to_phys(bp), chan->io + DMA_BUFFER1_START);
-+ au_writel(DMA_BE1, chan->io + DMA_MODE_SET);
-+ }
-+ else {
-+ au_writel(DMA_D0, chan->io + DMA_MODE_CLEAR);
-+ au_writel(len & DMA_COUNT_MASK, chan->io + DMA_BUFFER0_COUNT);
-+ au_writel(0, chan->io + DMA_BUFFER1_COUNT);
-+ au_writel(virt_to_phys(bp), chan->io + DMA_BUFFER0_START);
-+ au_writel(DMA_BE0, chan->io + DMA_MODE_SET);
-+ }
-+ au_writel(DMA_GO, chan->io + DMA_MODE_SET);
-+}
-+
-+static void __inline__ au_start_dma_in(int indma, __u8 *bp, int len)
-+{
-+ au_start_dma(get_dma_chan(indma), bp, len);
-+}
-+
-+static void __inline__ au_start_dma_out(int outdma, __u8 *bp, int wMaxPacketSize)
-+{
-+ dma_cache_inv((unsigned long) bp, wMaxPacketSize);
-+ au_start_dma(get_dma_chan(outdma), bp, wMaxPacketSize);
-+}
-+
-+static struct urb *au_rcv_complete_irq(struct usb_endpoint_instance *endpoint, int len, int urb_bad)
-+{
-+ return bi_rcv_complete_irq(endpoint, len, urb_bad);
-+}
-+
-+/* ********************************************************************************************* */
-+/* au_start_in_ep0 - start transmit
-+ */
-+static void au_start_in_ep0 (struct usb_endpoint_instance *endpoint, struct ep_regs *ep)
-+{
-+ struct urb *urb = endpoint->tx_urb;
-+ int last = ep->last = endpoint->last = MIN (urb->actual_length - endpoint->sent, endpoint->wMaxPacketSize);
-+ TRACE_MSG16("START IN EP0 SENT: %d SENDING: %d", endpoint->sent, last);
-+ RETURN_IF ((urb->actual_length - endpoint->sent) <= 0);
-+ au_writel(last << 1, ep->cs); // XXX
-+ au_fifo_write(0, urb->buffer + endpoint->sent, last);
-+ endpoint->last = last;
-+}
-+
-+/* au_in_ep0 - called to service an endpoint zero IN interrupt, data sent
-+ */
-+static void au_in_ep0(struct usb_endpoint_instance *endpoint, struct ep_regs *ep)
-+{
-+ u32 cs;
-+ struct urb *tx_urb;
-+ int last;
-+ TRACE_MSG32("EP0 IN: tx_urb: %p", (int)endpoint->tx_urb);
-+ if ((cs = au_readl(ep->cs)) & USBDEV_CS_STALL) { // clear stall if present
-+ TRACE_MSG32("CLEAR STALL %d", 0);
-+ cs &= ~USBDEV_CS_STALL;
-+ au_writel(cs, ep->cs);
-+ return;
-+ }
-+ if (!(tx_urb = bi_tx_complete_irq(endpoint, 0))) { // wait for setup if no more data
-+ endpoint->state = WAIT_FOR_SETUP;
-+ return;
-+ }
-+ TRACE_MSG8("EP0 IN actual: %d last: %d sent: %d flags: %x", endpoint->tx_urb->actual_length,
-+ endpoint->last, endpoint->sent, endpoint->tx_urb->flags);
-+ if (bi_tx_sendzlp(endpoint)) { // check if tx_urb we have is finished
-+ TRACE_MSG("EP0 IN BULK - sending ZLP");
-+ tx_urb->flags &= ~USBD_URB_SENDZLP;
-+ send_zlp(0);
-+ bi_tx_complete_irq(endpoint, 0);
-+ return;
-+ }
-+ if (tx_urb->actual_length > endpoint->sent) {
-+ if ((tx_urb->actual_length - endpoint->sent) < endpoint->wMaxPacketSize)
-+ TRACE_MSG32("EP0 IN starting short packet %d", tx_urb->actual_length - endpoint->sent);
-+ else
-+ TRACE_MSG32("EP0 IN LEFT TO SEND %d", tx_urb->actual_length - endpoint->sent);
-+ au_start_in_ep0(endpoint, ep);
-+ }
-+}
-+
-+/* au_out_ep0 - called to service an endpoint zero OUT interrupt, data received
-+ */
-+static void au_out_ep0(struct usb_endpoint_instance *endpoint, struct ep_regs *ep)
-+{
-+ struct usb_device_request request;
-+ int i;
-+ u32 cs;
-+ u32 bytes;
-+ TRACE_MSG("EP0 OUT");
-+ cs = au_readl(ep->cs); // check if host aborted transfer and flush the write fifo
-+ bytes = au_readl(ep->rds) & USBDEV_FSTAT_FCNT_MASK;
-+ if (endpoint->state == DATA_STATE_RECV) {
-+ struct urb *rcv_urb = bi_rcv_next_irq(endpoint);
-+ TRACE_MSG32("EP0 OUT: RECV: rcv_urb: %x", (int) rcv_urb);
-+ if (rcv_urb) {
-+ au_fifo_read(ep, rcv_urb->buffer + rcv_urb->actual_length, bytes);
-+ if (au_rcv_complete_irq(endpoint, bytes, 0))
-+ return;
-+ au_writel(USBDEV_FSTAT_FLUSH | USBDEV_FSTAT_UF | USBDEV_FSTAT_OF, ep->rds);
-+ endpoint->state = WAIT_FOR_SETUP;
-+ send_zlp(0);
-+ return;
-+ }
-+ endpoint->state = WAIT_FOR_SETUP;
-+ }
-+ bi_tx_cancelled_irq(endpoint);
-+ bi_rcv_cancelled_irq(endpoint);
-+ au_fifo_read(ep, (u8 *)&request, bytes);
-+ au_writel(USBDEV_FSTAT_FLUSH | USBDEV_FSTAT_UF | USBDEV_FSTAT_OF, ep->wrs);
-+ if (bytes != 8) {
-+ TRACE_MSG32("ERROR SETUP SET not eight bytes: %d", bytes);
-+ au_writel(USBDEV_FSTAT_FLUSH | USBDEV_FSTAT_UF | USBDEV_FSTAT_OF, ep->wrs);
-+ return;
-+ }
-+ TRACE_MSG8("SETUP bmRequestType: %02x bRequest %02x state: %d status: %d", request.bmRequestType,
-+ request.bRequest, usbd_bus->device_state, usbd_bus->status);
-+ switch (request.bRequest) { // we need to simply ignore any of these
-+ case USB_REQ_SET_ADDRESS: // Fake a bus reset IFF not state default and then process normally
-+ BREAK_IF (usbd_bus->device_state == STATE_DEFAULT);
-+ udc_saw_bus_activity = 0;
-+ usbd_bus_event_irq (usbd_bus, DEVICE_RESET, 0);
-+ usbd_bus_event_irq (usbd_bus, DEVICE_ADDRESS_ASSIGNED, 0);
-+ break;
-+ case USB_REQ_GET_DESCRIPTOR: // Fake a bus reset IFF suspended and then process normally
-+ BREAK_IF (STATE_SUSPENDED != usbd_bus->device_state);
-+ udc_saw_bus_activity = 0;
-+ usbd_bus_event_irq (usbd_bus, DEVICE_RESET, 0);
-+ usbd_bus_event_irq (usbd_bus, DEVICE_ADDRESS_ASSIGNED, 0);
-+ break;
-+ }
-+ if (bi_recv_setup_irq(&request)) {
-+ TRACE_MSG32("ep0 STALL %d", cs);
-+ au_writel(USBDEV_CS_STALL, USBD_EP0CS);
-+ return;
-+ }
-+ if (((request.bmRequestType & USB_REQ_DIRECTION_MASK) == USB_REQ_HOST2DEVICE) && le16_to_cpu (request.wLength)) {
-+ TRACE_MSG32("ep0 Class H2D request %04x", le16_to_cpu(request.wLength));
-+ endpoint->state = DATA_STATE_RECV;
-+ return;
-+ }
-+ if ((request.bmRequestType & USB_REQ_DIRECTION_MASK) == USB_REQ_HOST2DEVICE) {
-+ TRACE_MSG32("ep0 Class H2D request %04x", le16_to_cpu(request.wLength));
-+ if ((request.bmRequestType & ~USB_REQ_DIRECTION_MASK)) {
-+ TRACE_MSG32("ep0 Class or Vendor, send ZLP %d", cs);
-+ send_zlp(0);
-+ return;
-+ }
-+ }
-+ TRACE_MSG32("ep0 Class D2H request %04x", le16_to_cpu(request.wLength));
-+}
-+/* ********************************************************************************************* */
-+/* au_start_in_bulk - start transmit
-+ * The au1x00 will start to send when the first byte is loaded into the FIFO, either by
-+ * DMA or PIO. The packetsize must be set first.
-+ */
-+static void au_start_in_bulk (unsigned int epn, struct usb_endpoint_instance *endpoint, struct ep_regs *ep)
-+{
-+ struct urb *urb = endpoint->tx_urb;
-+ unsigned char *bp = urb->buffer + endpoint->sent;
-+ int indma = ep->indma;
-+ int last;
-+ TRACE_MSG32("START IN BULK %d", epn);
-+ RETURN_IF (!urb || (( (urb->actual_length - endpoint->sent) == 0) && !(urb->flags & USBD_URB_SENDZLP)));
-+ last = ep->last = endpoint->last = MIN (urb->actual_length - endpoint->sent, endpoint->wMaxPacketSize);
-+ TRACE_MSG16("START IN BULK sent: %d last:%d", endpoint->sent, last);
-+ au_writel(USBDEV_FSTAT_FLUSH | USBDEV_FSTAT_UF | USBDEV_FSTAT_OF, ep->wrs); // XXX
-+ if (!last) {
-+ if (endpoint->tx_urb->flags & USBD_URB_SENDZLP) {
-+ TRACE_MSG("START IN BULK - zending ZLP");
-+ send_zlp(epn);
-+ endpoint->tx_urb->flags &= ~USBD_URB_SENDZLP;
-+ }
-+ return;
-+ }
-+ else if (au1x00_new_silicon && (8 >= last)) {
-+ au_writel(last << 1, ep->cs);
-+ au_fifo_write(epn, bp, last);
-+ return;
-+ }
-+ if (!au1x00_new_silicon)
-+ udc_epn_interrupt_disable(epn);
-+ dma_cache_wback_inv((unsigned long) bp, last);
-+ au_writel(last << 1, ep->cs);
-+ au_start_dma_in(indma, bp, last);
-+}
-+
-+static void au_in_bulk(unsigned int epn, struct ep_regs *ep, struct usb_endpoint_instance *endpoint)
-+{
-+ struct urb *tx_urb;
-+ int rc = 0;
-+ u32 cs = au_readl(ep->cs);
-+ u32 wrs = au_readl(ep->wrs);
-+ TRACE_MSG16("BULK IN EPN - cs: %x wrs: %x", cs, wrs);
-+ if (!au1x00_new_silicon)
-+ if (epn && (ep->last > 8)) {
-+ TRACE_MSG16("BULK IN EPN - DMA ACTIVE epn %d last %d", epn, ep->last);
-+ udc_epn_interrupt_disable(epn);
-+ return;
-+ }
-+ if (wrs) { // check for underflow or overflow
-+ rc = 1;
-+ if (wrs & USBDEV_FSTAT_UF) {
-+ TRACE_MSG16("BULK IN EPN - UF epn %d wrs: %x", epn, wrs);
-+ rc = 1; // set rc to indicate an error
-+ }
-+ if (wrs & USBDEV_FSTAT_OF)
-+ TRACE_MSG16("BULK IN EPN - OF epn %d wrs: %x", epn, wrs);
-+ au_writel(USBDEV_FSTAT_FLUSH | USBDEV_FSTAT_UF | USBDEV_FSTAT_OF, ep->wrs); // flush the fifo
-+ }
-+ if (cs & USBDEV_CS_NAK) {
-+ RETURN_IF (ep->last && ((wrs&0x1f) == ep->last));
-+ rc = 1;
-+ }
-+ if (cs & USBDEV_CS_STALL) { // clear stall if present
-+ TRACE_MSG32("BULK IN EPN - CLEAR STALL %d", epn);
-+ cs &= ~USBDEV_CS_STALL;
-+ au_writel(cs, ep->cs);
-+ return;
-+ }
-+ TRACE_MSG8("BULK IN EPN epn: %d rc: %d last: %d sent: %d", epn, rc, endpoint->last, endpoint->sent);
-+ if ((tx_urb = bi_tx_complete_irq(endpoint, rc))) {
-+ if ((tx_urb->actual_length > endpoint->sent) || (endpoint->tx_urb->flags & USBD_URB_SENDZLP)) {
-+ au_start_in_bulk(epl2p[endpoint->bEndpointAddress&0xf], endpoint, ep);
-+ /* XXX magic delay - without this large packets will eventually stall the transmit
-+ * XXX and all traffic in both directions will stop.
-+ */
-+ if (!au1x00_new_silicon)
-+ udelay(8);
-+ TRACE_MSG32("BULK IN EPN - LEFT TO SEND %d", tx_urb->actual_length - endpoint->sent);
-+ return;
-+ }
-+ }
-+ udc_epn_interrupt_disable(epn); // disable interrupts
-+}
-+
-+/* au_start_in_iso - start transmit
-+ * The au1x00 will start to send when the first byte is loaded into the FIFO, either by DMA or
-+ * PIO. The packetsize must be set first.
-+ */
-+static void au_start_in_iso (unsigned int epn, struct usb_endpoint_instance *endpoint, struct ep_regs *ep)
-+{
-+ struct urb *urb = endpoint->tx_urb;
-+ unsigned char *bp = urb->buffer + endpoint->sent;
-+ int last;
-+ TRACE_MSG16("START IN ISO actual: %d sent: %d", urb->actual_length, endpoint->sent);
-+ RETURN_IF ((urb->actual_length - endpoint->sent) == 0);
-+ last = ep->last = endpoint->last = MIN (urb->actual_length - endpoint->sent, endpoint->wMaxPacketSize);
-+ TRACE_MSG16("START IN ISO last: %d packetSize: %d", last, endpoint->wMaxPacketSize);
-+ au_writel(USBDEV_FSTAT_FLUSH | USBDEV_FSTAT_UF | USBDEV_FSTAT_OF, ep->wrs); // XXX
-+ au1x00_new_silicon ? udc_epn_interrupt_enable : udc_epn_interrupt_disable (epn);
-+ dma_cache_wback_inv((unsigned long) bp, last);
-+ au_writel(last << 1, ep->cs);
-+ au_start_dma_in(ep->indma, bp, last);
-+}
-+
-+static void au_in_iso(unsigned int epn, struct ep_regs *ep, struct usb_endpoint_instance *endpoint)
-+{
-+ struct urb *tx_urb = bi_tx_complete_irq(endpoint, 0);
-+ u32 cs = au_readl(ep->cs);
-+ u32 wrs = au_readl(ep->wrs);
-+ TRACE_MSG16("ISO IN EPN - cs: %x wrs: %x", cs, wrs);
-+ if (!au1x00_new_silicon)
-+ if (epn && (ep->last > 8)) {
-+ udc_epn_interrupt_disable(epn);
-+ return;
-+ }
-+ TRACE_MSG8("ISO IN EPN epn: %d last: %d sent: %d", epn, endpoint->last, endpoint->sent, 0);
-+ ep->last = 0;
-+ if ((tx_urb = endpoint->tx_urb) && (tx_urb->actual_length > endpoint->sent)) {
-+ au_start_in_iso(epl2p[endpoint->bEndpointAddress&0xf], endpoint, ep);
-+ /* XXX magic delay - without this large packets will eventually stall the transmit
-+ * XXX and all traffic in both directions will stop.
-+ */
-+ if (!au1x00_new_silicon)
-+ udelay(8);
-+ TRACE_MSG32("ISO IN EPN - LEFT TO SEND %d", tx_urb->actual_length - endpoint->sent);
-+ return;
-+ }
-+ else
-+ TRACE_MSG("ISO IN EPN - nothing to send");
-+ udc_epn_interrupt_disable(epn); // disable interrupts
-+}
-+/* ********************************************************************************************* */
-+
-+static void au_start_out_bulk(unsigned int epn, struct usb_endpoint_instance *endpoint, struct ep_regs *ep)
-+{
-+ int outdma = ep->outdma;
-+ TRACE_MSG16("START OUT BULK %d %d", epn, endpoint->wMaxPacketSize);
-+ if (!endpoint->rcv_urb) {
-+ TRACE_MSG("START OUT BULK DISABLE");
-+ udc_epn_interrupt_disable(epn);
-+ return;
-+ }
-+ if (endpoint->rcv_error) {
-+ TRACE_MSG("START OUT BULK reseting rcv_error");
-+ endpoint->rcv_error = 0;
-+ }
-+ au_start_dma_out(outdma, endpoint->rcv_urb->buffer + endpoint->rcv_urb->actual_length, endpoint->wMaxPacketSize);
-+}
-+
-+static void au_out_bulk(unsigned int epn, struct ep_regs *ep, struct usb_endpoint_instance *endpoint)
-+{
-+ int bytes = 0;
-+ int outdma = ep->outdma;
-+ struct dma_chan *chan = get_dma_chan(outdma);
-+ struct urb *urb;
-+ struct urb *completed_urb = NULL;
-+ u32 cs;
-+ u32 rds;
-+ u32 nrds;
-+ au_halt_dma(chan);
-+ cs = au_readl(ep->cs);
-+ rds = au_readl(ep->rds);
-+ TRACE_MSG16("BULK OUT CS: %04x RD: %04x", cs, rds);
-+ bytes = endpoint->wMaxPacketSize - au_get_dma_residue(chan);
-+ if (!(urb = bi_rcv_next_irq(endpoint))) {
-+ TRACE_MSG("BULK OUT EPN - no rcv_urb");
-+ udc_epn_interrupt_disable(epn);
-+ return;
-+ }
-+ /* The original AU1X00 UDC design will continue to receive data as long as there is room
-+ * in the FIFO. We cannot tell when we are at the end of a packet and/or have the start
-+ * of a new one.
-+ *
-+ * There are only two scenarios that are guaranteed (almost) to be correct:
-+ *
-+ * 64 bytes of data from DMA, empty fifo, continue Bulk OUT < 60 bytes of data and
-+ * < 4 bytes in fifo, end Bulk OUT.
-+ *
-+ * There may be a third scenario that is ok:
-+ *
-+ * 0 bytes dma, 0 bytes in fifo, NAK
-+ *
-+ * Everything else is an error. In all cases we assume that it is safer to drop data
-+ * than to accept it in error. This allows CRC or size protected encapsulations to
-+ * notice bulk transfers received with errors.
-+ *
-+ * In general none of the policies or strategies are able to cope with all errors
-+ * without missing errors and dropping good data. The intent is to minimize the amount
-+ * of potentially bad data getting to the function driver while minimizing the amount of
-+ * good data that is dropped.
-+ *
-+ * The new silicon mitigates this problem for non control endpoints because it will NAK
-+ * additional data until the interrupt service flag is reset.
-+ *
-+ * Start with generic error tests, OF, UF or NAK indicate an error we cannot recover
-+ * from, start flushing until end of current bulk transfer (wait for a short packet)
-+ *
-+ */
-+ if (rds & (USBDEV_FSTAT_OF | USBDEV_FSTAT_UF)) {
-+ TRACE_MSG16("BULK OUT FLUSHING %d length: %d", bytes, urb->actual_length);
-+ THROW(start_flushing);
-+ }
-+ rds = rds & USBDEV_FSTAT_FCNT_MASK;
-+ nrds = au_readl(ep->rds);
-+ if (64 == bytes) {
-+ TRACE_MSG16("BULK OUT 64 BYTES %d length: %d", bytes, urb->actual_length);
-+ /* full size packet received, check that we are not flushing and that the FIFO
-+ * does not have any data. If there is data in the FIFO we may not be able to
-+ * restart DMA in time, so start flushing
-+ */
-+ if (endpoint->rcv_error) {
-+ TRACE_MSG8("FULL PACKET bytes: %d rds: %d nrds: %d cp0: %d CONTINUE FLUSHING",
-+ bytes, rds, nrds, cp0_count);
-+ THROW(start_flushing);
-+ }
-+ if ((nrds > 6) && (nrds < 8) ) {
-+ TRACE_MSG8("FIFO not empty bytes: %d rds: %d nrds: %d cp0: %d START FLUSHING nrds > 6 < 8",
-+ bytes, rds, nrds, cp0_count);
-+ THROW(start_flushing);
-+ }
-+ if (!urb->actual_length)
-+ TRACE_MSG8("PACKET ok bytes: %d rds: %d nrds: %d cp0: %d ACCEPTING 64 bytes",
-+ bytes, rds, nrds, cp0_count);
-+ au_writel(USBDEV_FSTAT_FLUSH | USBDEV_FSTAT_UF | USBDEV_FSTAT_OF, ep->rds);
-+ au_rcv_complete_irq(endpoint, 64, 0);
-+ if (cs & USBDEV_CS_NAK)
-+ if (nrds && (nrds < 8) ) {
-+ TRACE_MSG8("NAK bytes: %d rds: %d nrds: %d cp0: %d START FLUSHING CS_NAK",
-+ bytes, rds, nrds, cp0_count);
-+ THROW(start_flushing);
-+ }
-+ }
-+ else if ((cs & USBDEV_CS_NAK) && (!nrds || (nrds == 8)) ) {
-+ TRACE_MSG16("BULK OUT NAK BYTES %d length: %d", bytes, urb->actual_length);
-+ /* a nak'd packet may be ok to ignore IFF the FIFO is empty(?) or completely full.
-+ */
-+ if (endpoint->rcv_error) {
-+ TRACE_MSG8("NAK bytes: %d rds: %d nrds: %d cp0: %d CONTINUE FLUSHING",
-+ bytes, rds, nrds, cp0_count);
-+ THROW(start_flushing);
-+ }
-+ au_writel(USBDEV_FSTAT_FLUSH | USBDEV_FSTAT_UF | USBDEV_FSTAT_OF, ep->rds);
-+ }
-+ else {
-+ TRACE_MSG16("BULK OUT < 64 BYTES %d length: %d", bytes, urb->actual_length);
-+ /* short packet by DMA, additional data for this packet in FIFO, more than 3
-+ * bytes is probably an error.
-+ */
-+ if ((cs & USBDEV_CS_NAK) && nrds && (nrds < 8) ) {
-+ TRACE_MSG8("BULK OUT NAK bytes: %d rds: %d nrds: %d cp0: %d START FLUSHING",
-+ bytes, rds, nrds, cp0_count);
-+ THROW(start_flushing);
-+ }
-+ if (nrds > 4) {
-+ TRACE_MSG8("BULK OUT SHORT PACKET by DMA full FIFO bytes: %d rds: %d nrds: %d cp0: %d START FLUSHING",
-+ bytes, rds, nrds, cp0_count);
-+ THROW(start_flushing);
-+ }
-+ TRACE_MSG8("BULK OUT SHORT bytes: %d rds: %d nrds: %d cp0: %d reading fifo", bytes, rds, nrds, cp0_count);
-+ au_fifo_read(ep, urb->buffer + urb->actual_length + bytes, nrds);
-+ bytes += nrds;
-+ TRACE_MSG32("BULK OUT < 64 BYTES %d", bytes);
-+ au_writel(USBDEV_FSTAT_FLUSH | USBDEV_FSTAT_UF | USBDEV_FSTAT_OF, ep->rds);
-+ if (!endpoint->rcv_error) {
-+ TRACE_MSG("BULK OUT COMPLETED URB");
-+ au_rcv_complete_irq(endpoint, bytes, 0);
-+ }
-+ else {
-+ TRACE_MSG("BULK OUT - FLUSHING URB - reseting rcv_error");
-+ endpoint->rcv_error = 0;
-+ }
-+ }
-+ CATCH(start_flushing) {
-+ TRACE_MSG("BULK OUT - START FLUSHING URB");
-+ endpoint->rcv_error = 1;
-+ endpoint->rcv_urb->actual_length = 0;
-+ au_writel(USBDEV_FSTAT_FLUSH | USBDEV_FSTAT_UF | USBDEV_FSTAT_OF, ep->rds);
-+ bytes = 0;
-+ }
-+ TRACE_MSG("BULK OUT - RESTARTING");
-+ au_start_out_bulk(epn, endpoint, ep);
-+}
-+
-+static void au_start_out_iso(unsigned int epn, struct usb_endpoint_instance *endpoint, struct ep_regs *ep)
-+{
-+ int outdma = ep->outdma;
-+ RETURN_IF(!endpoint->rcv_urb);
-+ au_start_dma_out(outdma, endpoint->rcv_urb->buffer + endpoint->rcv_urb->actual_length, endpoint->wMaxPacketSize);
-+}
-+
-+static void au_out_iso(unsigned int epn, struct ep_regs *ep, struct usb_endpoint_instance *endpoint)
-+{
-+ int bytes = 0;
-+ int outdma = ep->outdma;
-+ struct dma_chan *chan = get_dma_chan(outdma);
-+ struct urb *urb;
-+ u32 cs;
-+ u32 rds;
-+ au_halt_dma(chan);
-+ cs = au_readl(ep->cs);
-+ rds = au_readl(ep->rds);
-+ if (!endpoint) {
-+ au_writel(USBDEV_FSTAT_FLUSH | USBDEV_FSTAT_UF | USBDEV_FSTAT_OF, ep->rds);
-+ return;
-+ }
-+ if (!(urb = endpoint->rcv_urb)) {
-+ TRACE_MSG16("ISO OUT EPN - rcv_urb was NULL bytes: %d rds: %d", bytes, rds);
-+ au_rcv_complete_irq(endpoint, bytes, 1);
-+ TRACE_MSG("ISO OUT setting rcv_error");
-+ }
-+ bytes = endpoint->wMaxPacketSize - au_get_dma_residue(chan);
-+ rds = rds & USBDEV_FSTAT_FCNT_MASK;
-+ au_fifo_read(ep, urb->buffer + urb->actual_length + bytes, rds);
-+ bytes += rds;
-+ au_writel(USBDEV_FSTAT_FLUSH | USBDEV_FSTAT_UF | USBDEV_FSTAT_OF, ep->rds);
-+ au_rcv_complete_irq(endpoint, bytes, 0);
-+ au_start_out_iso(epn, endpoint, ep);
-+}
-+/* ********************************************************************************************* */
-+/* udc_tx_dma_done - TX DMA interrupt handler
-+ */
-+static void udc_tx_dma_done(int irq, void *dev_id, struct pt_regs *regs)
-+{
-+ int epn = (int) dev_id;
-+ struct usb_endpoint_instance *endpoint = usbd_bus->endpoint_array + epn;
-+ struct ep_regs *ep = &ep_regs[epn];
-+ int residue;
-+ int indma = irq - 6;
-+ struct dma_chan *chan = get_dma_chan(indma);
-+ u32 mode = au_readl(chan->io + DMA_MODE_READ);
-+ udc_interrupts++;
-+ TRACE_MSG32("TX DMA done: mode: %x", mode);
-+ if (mode & DMA_D0)
-+ au_writel(DMA_D0, chan->io + DMA_MODE_CLEAR);
-+ if (mode & DMA_D1)
-+ au_writel(DMA_D1, chan->io + DMA_MODE_CLEAR);
-+ RETURN_IF (!epn);
-+ au_halt_dma(chan);
-+ residue = au_get_dma_residue(chan);
-+ TRACE_MSG16("TX DMA IRQ - epn %d residue %d", epn, residue);
-+ if (!au1x00_new_silicon) {
-+ /* XXX magic delay - without this large packets will eventually stall the transmit
-+ * XXX and all traffic in both directions will stop.
-+ */
-+ udelay(8);
-+ bi_tx_complete_irq (endpoint, residue?1:0);
-+ udc_epn_interrupt_enable(epl2p[endpoint->bEndpointAddress&0xf]);
-+ }
-+ ep->last = 0;
-+}
-+
-+/* udc_int_req - usb interrupt handler
-+ */
-+static void udc_int_req (int irq, void *dev_id, struct pt_regs *regs)
-+{
-+ u32 intstat;
-+ struct ep_regs *ep;
-+#if defined(MAX_INTR_LOOP_STATS)
-+ u32 loopcount = 0;
-+#endif
-+#ifdef RECORD_LATENCY
-+ cp0_count = (read_c0_count(CP0_COUNT) - cp0_record) >> 9;
-+ if (cp0_count < CP0_COUNTS)
-+ cp0_counts[cp0_count]++;
-+#endif
-+#ifdef CHECK_LATENCY
-+ u32 cp0_count = read_c0_count(CP0_COUNT);
-+#endif
-+ udc_interrupts++;
-+#if 0
-+ if (udc_interrupts > 2000) {
-+ TRACE_MSG("UDC_INT call udc_disable_interrupts");
-+ au_inten(0);
-+ return;
-+ }
-+#endif
-+ while (( intstat = au_readl(USBD_INTSTAT) & au1x00_inten)) { // read and reset interrupt status register
-+
-+ int epn;
-+#if 1
-+ for (epn = 2; epn < 6; epn++) {
-+ CONTINUE_IF (!(intstat & (1 << epn)));
-+#else
-+ // NOT TESTED
-+ u32 local_intstat = intstat;
-+ TRACE_MSG16("INTSTAT: %04x %04x", intstat, au_readl(USBD_INTEN));
-+ while (local_intstat & 0x3f) {
-+ int epn = 31 - au_clz(local_intstat);
-+ local_intstat &= ~(1<<epn);
-+#endif
-+ if (udc_saw_bus_activity) {
-+ udc_saw_bus_activity = 0;
-+ usbd_bus_event_irq (usbd_bus, DEVICE_BUS_ACTIVITY, 0);
-+ }
-+ ep = &ep_regs[epn];
-+ switch(ep->eptype) {
-+ case USB_DIR_IN | USB_ENDPOINT_BULK:
-+ case USB_DIR_IN | USB_ENDPOINT_INTERRUPT:
-+ //TRACE_MSG16("BULK IN %d %02x", epn, ep->eptype);
-+ au_in_bulk(epn, ep, usbd_bus->endpoint_array + epn);
-+ break;
-+ case USB_DIR_IN | USB_ENDPOINT_ISOCHRONOUS:
-+ //TRACE_MSG16("ISO IN %d %02x", epn, ep->eptype);
-+ au_in_iso(epn, ep, usbd_bus->endpoint_array + epn);
-+ break;
-+ case USB_DIR_OUT | USB_ENDPOINT_BULK:
-+ case USB_DIR_OUT | USB_ENDPOINT_INTERRUPT:
-+ //TRACE_MSG16("BULK OUT %d %02x", epn, ep->eptype);
-+ au_out_bulk(epn, ep, usbd_bus->endpoint_array + epn);
-+ break;
-+ case USB_DIR_OUT | USB_ENDPOINT_ISOCHRONOUS:
-+ //TRACE_MSG16("ISO OUT %d %04d", epn, au_readl(NUSBD_FRAMENUM));
-+ au_out_iso(epn, ep, usbd_bus->endpoint_array + epn);
-+ break;
-+ }
-+ }
-+ au_writel(intstat, USBD_INTSTAT); // Only clear the interrupt(s) AFTER servicing OUT
-+ /* even though we disable the bulk-in interrupt (endpoint 2) prior to enabling
-+ * DMA we always see one additional interrupt that is a NAK on that endpoint.
-+ */
-+ CONTINUE_IF(!(intstat & au1x00_inten));
-+ /* handle control endpoint and suspend interrupt
-+ */
-+ if (intstat & ( ((1 << 0) | (1 << 1) | (1 << 3) | (1 << 5) | USBDEV_INT_SOF))) {
-+ if (intstat & (1 << 0))
-+ au_out_ep0(usbd_bus->endpoint_array + 0, &ep_regs[0]);
-+ if (intstat & (1 << 1))
-+ au_in_ep0(usbd_bus->endpoint_array + 0, &ep_regs[0]);
-+ if (intstat & USBDEV_INT_SOF)
-+ if (USBD_SUSPENDED == usbd_bus->status) {
-+ TRACE_MSG("SUS - ACTIVITY");
-+ udc_saw_bus_activity++;
-+ }
-+ }
-+#if defined(MAX_INTR_LOOP_STATS)
-+ loopcount += 1; // Gather stats on how many times this loop is performed.
-+#endif
-+ }
-+#if defined(MAX_INTR_LOOP_STATS)
-+ interrupt_loop_stats[MIN(loopcount, MAX_INTR_LOOP_STATS)]++;
-+#endif
-+#if defined(CHECK_LATENCY)
-+ TRACE_MSG32("USB IRQ - %d", read_c0_count(CP0_COUNT) - cp0_count);
-+#endif
-+#if defined(RECORD_LATENCY)
-+ cp0_record = read_c0_count(CP0_COUNT);
-+#endif
-+}
-+
-+/* udc_int_sus -suspend interrupt handler
-+ */
-+static void udc_int_sus (int irq, void *dev_id, struct pt_regs *regs)
-+{
-+ udc_interrupts++;
-+ TRACE_MSG16("SUS - INACTIVE device: %d status: %d", usbd_bus->device_state, usbd_bus->status);
-+ switch(usbd_bus->status) {
-+ case USBD_OPENING:
-+ case USBD_OK:
-+ usbd_bus_event_irq (usbd_bus, DEVICE_BUS_INACTIVE, 0);
-+ break;
-+ default:
-+ break;
-+ }
-+}
-+/* ********************************************************************************************* */
-+/* udc_start_endpoint_in - start transmit
-+ */
-+void udc_start_endpoint_in(struct usb_endpoint_instance *endpoint)
-+{
-+ int epn = epl2p[endpoint->bEndpointAddress&0xf];
-+ struct ep_regs *ep = &ep_regs[epn];
-+ TRACE_MSG16("UDC START IN %02x %d", endpoint->bEndpointAddress, epn);
-+ TRACE_MSG16("UDC START IN len: %d flags: %x", (unsigned int)endpoint->tx_urb->actual_length, endpoint->tx_urb->flags);
-+ switch(endpoint->bmAttributes & USB_ENDPOINT_MASK) {
-+ case USB_ENDPOINT_CONTROL:
-+ TRACE_MSG32("UDC START IN EP0 %p", (u32)endpoint->rcv_urb);
-+ au_in_ep0(endpoint, ep);
-+ break;
-+ case USB_ENDPOINT_BULK:
-+ case USB_ENDPOINT_INTERRUPT:
-+ TRACE_MSG32("UDC START IN BULK %p", (u32)endpoint->rcv_urb);
-+ au_start_in_bulk(epn, endpoint, ep);
-+ break;
-+ case USB_ENDPOINT_ISOCHRONOUS:
-+ TRACE_MSG32("UDC START IN ISO %p", (u32)endpoint->rcv_urb);
-+ au_start_in_iso(epn, endpoint, ep);
-+ break;
-+ }
-+ if (au1x00_new_silicon)
-+ udc_epn_interrupt_enable(epn);
-+}
-+
-+/* udc_start_endpoint_out - start receive
-+ */
-+void udc_start_endpoint_out(struct usb_endpoint_instance *endpoint)
-+{
-+ int epn = epl2p[endpoint->bEndpointAddress&0xf];
-+ struct ep_regs *ep = &ep_regs[epn];
-+ TRACE_MSG16("UDC START OUT %02x %d", endpoint->bEndpointAddress, epn);
-+ TRACE_MSG32("UDC START OUT len: %d", endpoint->rcv_urb->buffer_length);
-+ switch(endpoint->bmAttributes & USB_ENDPOINT_MASK) {
-+ case USB_ENDPOINT_CONTROL:
-+ TRACE_MSG32("UDC START OUT EP0 %p", (u32)endpoint->rcv_urb);
-+ break;
-+ case USB_ENDPOINT_BULK:
-+ case USB_ENDPOINT_INTERRUPT:
-+ TRACE_MSG32("UDC START OUT BULK %p", (u32)endpoint->rcv_urb);
-+ au_start_out_bulk(epn, endpoint, ep);
-+ udc_epn_interrupt_enable(epn);
-+ break;
-+ case USB_ENDPOINT_ISOCHRONOUS:
-+ TRACE_MSG32("UDC START OUT ISO %p", (u32)endpoint->rcv_urb);
-+ au_start_out_iso(epn, endpoint, ep);
-+ break;
-+ }
-+}
-+
-+void udc_cancel_in_irq(struct urb *urb)
-+{
-+ int epn = epl2p[urb->endpoint->bEndpointAddress&0xf];
-+ struct ep_regs *ep = &ep_regs[epn];
-+ TRACE_MSG("CANCEL IN URB");
-+ au_in_bulk(epn, ep, urb->endpoint);
-+}
-+
-+void udc_cancel_out_irq(struct urb *urb)
-+{
-+ int epn = epl2p[urb->endpoint->bEndpointAddress&0xf];
-+ struct ep_regs *ep = &ep_regs[epn];
-+ TRACE_MSG("CANCEL OUT URB");
-+ if (epn)
-+ au_out_bulk(epn, ep, urb->endpoint);
-+}
-+
-+/* udc_init - initialize
-+ */
-+int udc_init (void)
-+{
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,19)
-+#undef read_c0_prid
-+#define read_c0_prid() read_32bit_cp0_register(CP0_PRID)
-+#endif
-+ u32 cp0_prid = read_c0_prid();
-+ switch (cp0_prid & CP0_PRID_SOC_MASK) {
-+ case CP0_PRID_AU1000:
-+ case CP0_PRID_AU1100:
-+ au1x00_new_silicon = (cp0_prid & CP0_PRID_REV_MASK) >= 4;
-+ printk(KERN_INFO"%s: AU1100 cp0_prid: new: %d\n", __FUNCTION__, au1x00_new_silicon);
-+ break;
-+ case CP0_PRID_AU1500:
-+ au1x00_new_silicon = (cp0_prid & CP0_PRID_REV_MASK) >= 2;
-+ printk(KERN_INFO"%s: AU1500 cp0_prid: new: %d\n", __FUNCTION__, au1x00_new_silicon);
-+ break;
-+ default:
-+ printk(KERN_INFO"%s: UNKNOWN CPU cp0_prid: %08x UNKNOWN UDC\n", __FUNCTION__, cp0_prid);
-+ return -EINVAL;
-+ }
-+ return 0;
-+}
-+
-+/* udc_serial_init - set a serial number if available
-+ */
-+int udc_serial_init (void)
-+{
-+#if defined(CONFIG_MIPS_FREEHAND)
-+ int length;
-+ long data[16]; /* yeah a hack, but we KNOW it's 16 */
-+ struct i2c_client *client;
-+ char chData[16];
-+ int i;
-+
-+ if (!(client = getFreeHandEepromClient())) {
-+ printk(KERN_INFO"eeprom not ready when udc_serial_init called\n");
-+ return -EINVAL;
-+ }
-+ eeprom_contents(client, SENSORS_PROC_REAL_READ, EEPROM_SYSCTL1, &length, (long *)data);
-+
-+ /* serial number is first 9 longs. But each long is just an ASCII char
-+ * convert this to a string and then extract a 4 byte value from it
-+ */
-+ for (i = 0; i < 9; chData[i] = (char)data[i], i++); /* trunc, is ok */
-+ chData[9] = 0; /* terminate string */
-+ printk(KERN_INFO"%s: %s\n", __FUNCTION__, chData);
-+ usbd_bus->serial_number_str = lstrdup(chData);
-+ return 0;
-+#else
-+ return -EINVAL;
-+#endif
-+}
-+
-+/* udc_setup_ep - setup endpoint
-+ */
-+void udc_setup_ep (unsigned int epn, struct usb_endpoint_instance *endpoint)
-+{
-+ RETURN_IF (epn);
-+ endpoint->state = WAIT_FOR_SETUP;
-+}
-+
-+/* udc_attached - is the USB cable connected
-+ * Return non-zero if cable is connected.
-+ *
-+ * udc_connect - enable pullup resistor
-+ * Turn on the USB connection by enabling the pullup resistor.
-+ *
-+ * udc_disconnect - disable pullup resistor
-+ * Turn off the USB connection by disabling the pullup resistor.
-+ */
-+
-+#if defined(CONFIG_MIPS_PICOENGINE_MVCI)
-+int udc_attached (void)
-+{
-+ return 1;
-+}
-+
-+int udc_connected(void)
-+{
-+ return udc_connected_status;
-+}
-+
-+void udc_connect (void)
-+{
-+ extern void pico_mvci_set_usb_pullup(int);
-+ pico_mvci_set_usb_pullup(1);
-+ udc_connected_status = 1;
-+}
-+
-+void udc_disconnect (void)
-+{
-+ extern void pico_mvci_set_usb_pullup(int);
-+ pico_mvci_set_usb_pullup(0);
-+ udc_connected_status = 0;
-+}
-+
-+#elif defined(CONFIG_MIPS_FREEHAND_NATIVE)
-+/* have to do this because version A boards don't have pullups
-+ * XXX checkme
-+*/
-+int udc_attached (void)
-+{
-+ return 1;
-+}
-+
-+int udc_connected(void)
-+{
-+ return udc_connected_status;
-+}
-+
-+void udc_connect (void)
-+{
-+ au1000gpio_set(GPIO01);
-+ udc_connected_status = 1;
-+}
-+
-+void udc_disconnect (void)
-+{
-+ au1000gpio_clear(GPIO01);
-+ udc_connected_status = 0;
-+}
-+
-+#endif
-+
-+/* udc_framenum - get current framenum
-+ */
-+int udc_framenum (void)
-+{
-+ return au_readl(NUSBD_FRAMENUM);
-+}
-+
-+/* udc_all_interrupts - enable interrupts
-+ */
-+void udc_all_interrupts (void)
-+{
-+ au_inten(0x0033|USBDEV_INT_SOF); // Only enable receive interrupts.
-+}
-+
-+/* udc_suspended_interrupts - enable suspended interrupts
-+ */
-+void udc_suspended_interrupts (void)
-+{
-+ au_inten(0x0033|USBDEV_INT_SOF);
-+}
-+
-+/* udc_disable_interrupts - disable interrupts.
-+ */
-+void udc_disable_interrupts (void)
-+{
-+ au_inten(0);
-+}
-+
-+/* udc_disable - disable the UDC
-+ */
-+void udc_disable (void)
-+{
-+ au_writel(0x0000, USBD_ENABLE);
-+}
-+
-+/* udc_release_udc_irq - release UDC irq
-+ */
-+void udc_release_udc_irq (void)
-+{
-+ free_irq (AU1000_USB_DEV_REQ_INT, NULL);
-+ free_irq (AU1000_USB_DEV_SUS_INT, NULL);
-+#if defined(MAX_INTR_LOOP_STATS)
-+ {
-+ u32 lc;
-+ for (lc = 0; lc <= MAX_INTR_LOOP_STATS; lc++)
-+ if (interrupt_loop_stats[lc])
-+ printk(KERN_ERR "%s: interrupt loopcount[%02u] %9u\n", __FUNCTION__, lc,interrupt_loop_stats[lc]);
-+ printk(KERN_INFO"%s: halt_dma_expired: %d\n", __FUNCTION__, au_halt_dma_expired);
-+ }
-+#endif
-+#ifdef RECORD_LATENCY
-+ {
-+ int i;
-+ for (i = 0; i < CP0_COUNTS; i++)
-+ if (cp0_counts[i])
-+ printk(KERN_INFO"%s: cp0_counts[%d] %d\n", __FUNCTION__, i, cp0_counts[i]);
-+ }
-+#endif
-+}
-+
-+/* udc_request_udc_irq - request UDC interrupt
-+ */
-+int udc_request_udc_irq (void)
-+{
-+ RETURN_EINVAL_IF (request_irq (AU1000_USB_DEV_REQ_INT, udc_int_req, SA_INTERRUPT, UDC_NAME "UDC Req", NULL));
-+ if (request_irq (AU1000_USB_DEV_SUS_INT, udc_int_sus, SA_INTERRUPT, UDC_NAME "UDC Sus", NULL) != 0) {
-+ udc_release_udc_irq();
-+ free_irq (AU1000_USB_DEV_REQ_INT, NULL);
-+ return -EINVAL;
-+ }
-+ return 0;
-+}
-+
-+static int request_dma(int ep, int id, char *str, void dma_done(int , void *, struct pt_regs *))
-+{
-+ int dma;
-+ if ((dma = request_au1000_dma(id, str, dma_done, SA_INTERRUPT | SA_SAMPLE_RANDOM, (void *)ep)) < 0) {
-+ printk(KERN_INFO"request_io[%d] dma: %d id: %x %s FAILED\n", ep, dma, id, str);
-+ return -1;
-+ }
-+ return dma;
-+}
-+
-+/* udc_request_io - request IO region
-+ */
-+int udc_request_io (void)
-+{
-+ int i;
-+ for (i = 0; i < 6; i++) {
-+ ep_regs[i].indma = ep_regs[i].tx_id ? request_dma(i, ep_regs[i].tx_id, ep_regs[i].tx_str, udc_tx_dma_done) : -1;
-+ ep_regs[i].outdma = ep_regs[i].rx_id ? request_dma(i, ep_regs[i].rx_id, ep_regs[i].rx_str, NULL) : -1;
-+ }
-+ return 0;
-+}
-+
-+/* udc_release_io - release IO region
-+ */
-+void udc_release_io (void)
-+{
-+ int j;
-+ for (j = 0; j < 6; j++) {
-+ struct ep_regs *ep = &ep_regs[j];
-+ if (ep->indma != -1) {
-+ free_au1000_dma(ep->indma);
-+ ep->indma = -1;
-+ }
-+ if (ep->outdma != -1) {
-+ free_au1000_dma(ep->outdma);
-+ ep->outdma = -1;
-+ }
-+ }
-+}
-+
-+int udc_assign_endpoint( __u8 physicalEndpoint, int used[6], struct usb_endpoint_map *endpoint_map, __u8 bmAttributes,
-+ __u16 wMaxPacketSize, __u16 transferSize)
-+{
-+ struct ep_regs *ep = &ep_regs[physicalEndpoint];
-+ RETURN_EINVAL_IF(used[physicalEndpoint]);
-+ endpoint_map->bEndpointAddress[0] = epp2l[physicalEndpoint];
-+ endpoint_map->physicalEndpoint[0] = physicalEndpoint;
-+ endpoint_map->wMaxPacketSize[0] = wMaxPacketSize;
-+ endpoint_map->transferSize[0] = transferSize;
-+ endpoint_map->bmAttributes[0] = bmAttributes;
-+ used[physicalEndpoint]++;
-+ ep->eptype = bmAttributes & 0x83;
-+ return 0;
-+}
-+
-+int udc_request_endpoints(struct usb_endpoint_map *endpoint_map_array, int endpointsRequested,
-+ struct usb_endpoint_request *requestedEndpoints)
-+{
-+ struct usb_device_description *device_description;
-+ int i;
-+ int used[6];
-+ memset(used, 0, sizeof(used));
-+ for (i = 0; i < endpointsRequested; i++) {
-+ struct usb_endpoint_map *endpoint_map = endpoint_map_array + i;
-+ u8 bmAttributes = requestedEndpoints[i].bmAttributes;
-+ u16 transferSize = requestedEndpoints[i].fs_requestedTransferSize;
-+ endpoint_map->bmAttributes[0] = bmAttributes;
-+ endpoint_map->wMaxPacketSize[0] = 0x40;
-+ switch(bmAttributes) {
-+ case USB_DIR_OUT | USB_ENDPOINT_BULK:
-+ case USB_DIR_OUT | USB_ENDPOINT_INTERRUPT:
-+ case USB_DIR_OUT | USB_ENDPOINT_INTERRUPT | USB_ENDPOINT_OPT:
-+ CONTINUE_IF(!udc_assign_endpoint(4, used, endpoint_map, bmAttributes, 0x40, transferSize));
-+ CONTINUE_IF(!udc_assign_endpoint(5, used, endpoint_map, bmAttributes, 0x40, transferSize));
-+ break;
-+ case USB_DIR_OUT | USB_ENDPOINT_ISOCHRONOUS:
-+ CONTINUE_IF(!udc_assign_endpoint(4, used, endpoint_map, bmAttributes, transferSize, transferSize));
-+ CONTINUE_IF(!udc_assign_endpoint(5, used, endpoint_map, bmAttributes, transferSize, transferSize));
-+ break;
-+ case USB_DIR_IN | USB_ENDPOINT_BULK:
-+ case USB_DIR_IN | USB_ENDPOINT_INTERRUPT:
-+ case USB_DIR_IN | USB_ENDPOINT_INTERRUPT | USB_ENDPOINT_OPT:
-+ CONTINUE_IF(!udc_assign_endpoint(2, used, endpoint_map, bmAttributes, 0x40, transferSize));
-+ CONTINUE_IF(!udc_assign_endpoint(3, used, endpoint_map, bmAttributes, 0x40, transferSize));
-+ break;
-+ case USB_DIR_IN | USB_ENDPOINT_ISOCHRONOUS:
-+ CONTINUE_IF(!udc_assign_endpoint(2, used, endpoint_map, bmAttributes, transferSize, transferSize));
-+ CONTINUE_IF(!udc_assign_endpoint(3, used, endpoint_map, bmAttributes, transferSize, transferSize));
-+ break;
-+ }
-+ CONTINUE_IF(bmAttributes & USB_ENDPOINT_OPT);
-+ return -EINVAL;
-+ }
-+ return 0;
-+}
-+
-+int udc_set_endpoints(int endpointsRequested, struct usb_endpoint_map *endpoint_map_array)
-+{
-+ int i, j;
-+ __u8 config[25];
-+ __u8 *cp;
-+ memcpy(config, au1x00_config_bulk, sizeof(config));
-+ for (i = 0; i < endpointsRequested; i++) {
-+ struct usb_endpoint_map *endpoint_map = endpoint_map_array + i;
-+ int epreq = endpoint_map->bmAttributes[0];
-+ int eptype = epreq & USB_ENDPOINT_MASK;
-+ int epdir = epreq & USB_ENDPOINT_DIR_MASK ? 0x8 : 0;
-+ int epsize = endpoint_map->wMaxPacketSize[0];
-+ int epaddr = epp2l[endpoint_map->physicalEndpoint[0]];
-+ CONTINUE_IF(!endpoint_map->physicalEndpoint[0] || (endpoint_map->physicalEndpoint[0] > 5));
-+ cp = config + ((endpoint_map->physicalEndpoint[0] - 1) * 5);
-+ cp[0] = (epaddr & 0xf) << 4 | 0x4;
-+ cp[1] = (eptype << 4) | epdir | (epsize & 0x380) >> 7;
-+ cp[2] = (epsize & 0x7F) << 1;
-+ }
-+ au_inten(0); // disable interrupts
-+ au_writel(0x0002, USBD_ENABLE); // reset controller
-+ udelay(100);
-+ au_writel(0x0003, USBD_ENABLE); // enable controller
-+ udelay(100);
-+ for (cp = config, i = 0; i < 25; i++, au_writel(*cp++, USBD_CONFIG)); // feed the config into the UDC
-+ return 0;
-+}
-+/* ********************************************************************************************* */
-+struct udc_ops udc_ops = {
-+ max_endpoints: UDC_MAX_ENDPOINTS,
-+ ep0_packetsize: EP0_PACKETSIZE,
-+ name: UDC_NAME,
-+ start_endpoint_in: udc_start_endpoint_in,
-+ start_endpoint_out: udc_start_endpoint_out,
-+ request_endpoints: udc_request_endpoints,
-+ set_endpoints: udc_set_endpoints,
-+ cancel_in_irq: udc_cancel_in_irq,
-+ cancel_out_irq: udc_cancel_out_irq,
-+ setup_ep: udc_setup_ep,
-+#if defined(CONFIG_MIPS_PICOENGINE_MVCI) ||defined(CONFIG_MIPS_FREEHAND_NATIVE)
-+ attached: udc_attached,
-+ connected: udc_connected,
-+ connect: udc_connect,
-+ disconnect: udc_disconnect,
-+#endif
-+ framenum: udc_framenum,
-+ all_interrupts: udc_all_interrupts,
-+ suspended_interrupts: udc_suspended_interrupts,
-+ disable_interrupts: udc_disable_interrupts,
-+ disable: udc_disable,
-+ init: udc_init,
-+ request_udc_irq: udc_request_udc_irq,
-+ release_udc_irq: udc_release_udc_irq,
-+ release_io: udc_release_io,
-+ serial_init: udc_serial_init,
-+ request_io: udc_request_io,
-+};
-+
-diff -Nru a/drivers/usbd/au1x00_bi/au1x00.h b/drivers/usbd/au1x00_bi/au1x00.h
---- /dev/null Wed Dec 31 16:00:00 1969
-+++ b/drivers/usbd/au1x00_bi/au1x00.h Fri Feb 27 14:22:51 2004
-@@ -0,0 +1,112 @@
-+/*
-+ * usbd/au1x00_bi/au1100.h
-+ *
-+ * Copyright (c) 2004 Belcarra
-+ *
-+ * Adapted from earlier work:
-+ * Copyright (c) 2002, 2003 Belcarra
-+ * Copyright (c) 2000, 2001, 2002 Lineo
-+ *
-+ * By:
-+ * Stuart Lynne <sl@belcarra.com>,
-+ * Tom Rushworth <tbr@belcarra.com>,
-+ * Bruce Balden <balden@belcarra.com>
-+ *
-+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
-+ *
-+ */
-+
-+
-+/*
-+ * au1100
-+ *
-+ * The au1100 does not seem to work properly with an 8 byte
-+ * packetsize. So 16, 32 or 64 are the only valid values.
-+ *
-+ * Unfortunately this means that a DMA channel is required for
-+ * EP0 transmit.
-+ */
-+
-+#define EP0_PACKETSIZE 0x8
-+
-+#define UDC_MAX_ENDPOINTS 6
-+
-+#define UDC_NAME "AU1100"
-+
-+#define NUSBD_EP0RD 0xB0200000
-+#define NUSBD_EP0WR 0xB0200004
-+#define NUSBD_EP1WR 0xB0200008
-+#define NUSBD_EP2WR 0xB020000C
-+#define NUSBD_EP3RD 0xB0200010
-+#define NUSBD_EP4RD 0xB0200014
-+
-+#define NUSBD_EP0CS 0xB0200024
-+#define NUSBD_EP1CS 0xB0200028
-+#define NUSBD_EP2CS 0xB020002C
-+#define NUSBD_EP3CS 0xB0200030
-+#define NUSBD_EP4CS 0xB0200034
-+
-+#define NUSBD_EP0RDSTAT 0xB0200040
-+#define NUSBD_EP0WRSTAT 0xB0200044
-+#define NUSBD_EP1WRSTAT 0xB0200048
-+#define NUSBD_EP2WRSTAT 0xB020004C
-+#define NUSBD_EP3RDSTAT 0xB0200050
-+#define NUSBD_EP4RDSTAT 0xB0200054
-+
-+#define NUSBD_FRAMENUM 0xB0200038
-+
-+enum {
-+ NDMA_ID_UART0_TX = 0,
-+ NDMA_ID_UART0_RX,
-+ NDMA_ID_GP04,
-+ NDMA_ID_GP05,
-+ NDMA_ID_AC97C_TX,
-+ NDMA_ID_AC97C_RX,
-+ NDMA_ID_UART3_TX,
-+ NDMA_ID_UART3_RX,
-+ NDMA_ID_USBDEV_EP0_RX,
-+ NDMA_ID_USBDEV_EP0_TX,
-+ NDMA_ID_USBDEV_EP1_TX,
-+ NDMA_ID_USBDEV_EP2_TX,
-+ NDMA_ID_USBDEV_EP3_RX,
-+ NDMA_ID_USBDEV_EP4_RX,
-+ NDMA_ID_I2S_TX,
-+ NDMA_ID_I2S_RX,
-+ NDMA_NUM_DEV
-+};
-+
-+typedef struct ep_regs {
-+ int rd;
-+ int wr;
-+ int cs;
-+ int rds;
-+ int wrs;
-+ int rx_id;
-+ int tx_id;
-+ char * rx_str;
-+ char * tx_str;
-+ int indma;
-+ int outdma;
-+ int last;
-+ int eptype;
-+} ep_regs_t;
-+
-+#define MAX_EPN_PACKET_SIZE 64
-+#define CP0_PRID_SOC_MASK 0xff000000
-+#define CP0_PRID_AU1000 0x00000000
-+#define CP0_PRID_AU1500 0x01000000
-+#define CP0_PRID_AU1100 0x02000000
-+#define CP0_PRID_REV_MASK 0x000000ff
-+
-diff -Nru a/drivers/usbd/ep0.c b/drivers/usbd/ep0.c
---- /dev/null Wed Dec 31 16:00:00 1969
-+++ b/drivers/usbd/ep0.c Fri Feb 27 14:22:51 2004
-@@ -0,0 +1,565 @@
-+/*
-+ * usbd/ep0.c
-+ *
-+ * Copyright (c) 2004 Belcarra
-+ *
-+ * Adapted from earlier work:
-+ * Copyright (c) 2002, 2003, 2004 Belcarra
-+ * Copyright (c) 2000, 2001, 2002 Lineo
-+ * Copyright (c) 2001 Hewlett Packard
-+ *
-+ * By:
-+ * Stuart Lynne <sl@belcarra.com>,
-+ * Tom Rushworth <tbr@belcarra.com>,
-+ * Bruce Balden <balden@lineo.com>
-+ *
-+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
-+ *
-+ */
-+
-+/*
-+ * This function driver implements support for all of the USB 2.0 Chapter
-+ * nine requests.
-+ *
-+ * Any request that is not required by Chapter nine is passed to the other
-+ * function drivers recv_setup routine.
-+ *
-+ */
-+
-+#include <linux/config.h>
-+#include <linux/module.h>
-+
-+//EXPORT_NO_SYMBOLS;
-+
-+#include <linux/init.h>
-+#include <linux/kernel.h>
-+#include <linux/list.h>
-+#include <asm/uaccess.h>
-+#include <linux/slab.h>
-+#include <linux/interrupt.h>
-+
-+#include <linux/smp_lock.h>
-+#include <linux/ctype.h>
-+#include <linux/timer.h>
-+#include <linux/string.h>
-+
-+#include "usbd-chap9.h"
-+#include "usbd-mem.h"
-+#include "usbd.h"
-+#include "usbd-func.h"
-+#include "usbd-bus.h" // for usbd_recv_setup_irq() definition
-+#include "usbd-admin.h"
-+
-+struct usb_function_instance * ep0_function;
-+
-+/* C.f. 9.4 Standard Requests and table 9.3
-+ *
-+ * Encode valid requests into a bitmap for each recipient type for
-+ * both directions.
-+ *
-+ */
-+
-+#define STD(x) (1<<(x+1))
-+
-+/* h2d_standard_requests and d2h_standard_requests
-+ *
-+ * These tables list all of the valid Chapter Nine requests. Any request
-+ * not listed in these tables will NOT be processed by the EP0 function and
-+ * will instead be passed to the appropriate function driver.
-+ */
-+u32 h2d_standard_requests[4] = {
-+ // 0 - Device
-+ STD(USB_REQ_CLEAR_FEATURE) |
-+ STD(USB_REQ_SET_FEATURE) |
-+ STD(USB_REQ_SET_ADDRESS) |
-+ STD(USB_REQ_SET_DESCRIPTOR) |
-+ STD(USB_REQ_GET_CONFIGURATION) |
-+ STD(USB_REQ_SET_CONFIGURATION) ,
-+ // 1 - Interface
-+ STD(USB_REQ_CLEAR_FEATURE) |
-+ STD(USB_REQ_SET_FEATURE) |
-+ STD(USB_REQ_SET_INTERFACE) ,
-+ // 2 - Endpoint
-+ STD(USB_REQ_CLEAR_FEATURE) |
-+ STD(USB_REQ_SET_FEATURE) ,
-+ // 3 - Other
-+ 0,
-+};
-+
-+u32 d2h_standard_requests[4] = {
-+ // 0 - Device
-+ STD(USB_REQ_GET_STATUS) |
-+ STD(USB_REQ_GET_DESCRIPTOR) ,
-+ // 1 - Interface
-+ STD(USB_REQ_GET_STATUS) |
-+ STD(USB_REQ_GET_INTERFACE) ,
-+ // 2 - Endpoint
-+ STD(USB_REQ_GET_STATUS) |
-+ STD(USB_REQ_SYNCH_FRAME) ,
-+ // 3 - Other
-+ 0,
-+};
-+
-+
-+/* Endpoint ZEro Configuration *************************************************************** */
-+
-+/* ep0_event_irq - respond to USB event
-+ *
-+ * Process USB events.
-+ */
-+static void ep0_event_irq (struct usb_function_instance *function, usb_device_event_t event, int dummy )
-+{
-+ switch (event) {
-+ case DEVICE_CREATE:
-+ default:
-+ break;
-+ }
-+}
-+
-+/* copy_config - copy data into urb buffer
-+ */
-+static int copy_config (u8 *cp, void *data, int actual_length, int max_buf)
-+{
-+ int available = max_buf - actual_length;
-+ int length = MIN(*(u8 *)data, available);
-+
-+ RETURN_ZERO_IF (!length);
-+ memcpy (cp, data, length);
-+ return length;
-+}
-+
-+/* copy_config - copy data into urb buffer
-+ */
-+static int copy_endpoint (struct usb_function_instance *function, u8 *cp,
-+ struct usb_endpoint_descriptor *endpoint, int endpoint_index, int actual_length, int max_buf, int hs)
-+{
-+ int available = max_buf - actual_length;
-+ int length = MIN(endpoint->bLength, available);
-+ struct usb_endpoint_descriptor endpoint_copy;
-+
-+ RETURN_ZERO_IF (!length);
-+ memcpy (&endpoint_copy, endpoint, endpoint->bLength);
-+ usbd_endpoint_update(function, endpoint_index, &endpoint_copy, hs);
-+ memcpy (cp, &endpoint_copy, length);
-+ return length;
-+}
-+
-+/* usbd_get_descriptor - copy descriptor into urb buffer
-+ *
-+ * Return non-zero for error.
-+ */
-+int usbd_get_descriptor (struct usb_bus_instance *bus, u8 *buffer, int max, int descriptor_type, int index)
-+{
-+ struct usb_function_driver *function_driver = bus->function_instance->function_driver;
-+ int actual_length = 0;
-+
-+ switch (descriptor_type) {
-+ case USB_DESCRIPTOR_TYPE_DEVICE:
-+ {
-+ struct usb_device_descriptor *device_descriptor = function_driver->device_descriptor;
-+
-+ // copy descriptor for this device
-+ actual_length += copy_config (buffer + actual_length, device_descriptor, actual_length, max);
-+
-+ // correct the correct control endpoint 0 max packet size into the descriptor
-+ device_descriptor = (struct usb_device_descriptor *) buffer;
-+ device_descriptor->bMaxPacketSize0 = bus->driver->maxpacketsize;
-+ }
-+ break;
-+
-+#ifdef CONFIG_USBD_HIGH_SPEED
-+ case USB_DESCRIPTOR_TYPE_DEVICE_QUALIFIER: // c.f. 9.6.2 Device Qualifier
-+ {
-+ struct usb_device_qualifier_descriptor *device_qualifier_descriptor =
-+ function_driver->device_qualifier_descriptor;
-+
-+ // copy descriptor for this device
-+ actual_length += copy_config (buffer + actual_length, device_qualifier_descriptor, actual_length, max);
-+
-+ }
-+ break;
-+
-+ case USB_DESCRIPTOR_TYPE_OTHER_SPEED_CONFIGURATION:
-+ case USB_DESCRIPTOR_TYPE_CONFIGURATION:
-+ {
-+ int hs = bus->HighSpeedFlag ? descriptor_type == USB_DESCRIPTOR_TYPE_CONFIGURATION:
-+ descriptor_type == USB_DESCRIPTOR_TYPE_OTHER_SPEED_CONFIGURATION;
-+#else
-+ case USB_DESCRIPTOR_TYPE_CONFIGURATION:
-+ {
-+ int hs = 0;
-+#endif
-+ int interface;
-+
-+ struct usb_configuration_instance *configuration_instance =
-+ &function_driver->configuration_instance_array[index];
-+
-+ struct usb_configuration_descriptor *configuration_descriptor =
-+ configuration_instance->configuration_descriptor;
-+
-+ RETURN_EINVAL_IF (!configuration_descriptor);
-+ RETURN_EINVAL_IF (index > function_driver->device_descriptor->bNumConfigurations);
-+
-+ actual_length += copy_config (buffer + actual_length, configuration_descriptor, actual_length, max);
-+
-+ // iterate across bNumInterfaces for specified configuration
-+ for (interface = 0; interface < configuration_descriptor->bNumInterfaces; interface++) {
-+
-+ int alternate;
-+ struct usb_interface_instance *interface_instance =
-+ configuration_instance->interface_instance_array + interface;
-+
-+ // iterate across interface alternates
-+ for (alternate = 0; alternate < interface_instance->alternates; alternate++) {
-+
-+ int class;
-+ int endpoint;
-+
-+ struct usb_alternate_instance *alternate_instance =
-+ interface_instance->alternates_instance_array + alternate;
-+
-+ //struct usb_interface_descriptor *usb_interface_descriptor;
-+
-+ // copy descriptor for this interface
-+ actual_length += copy_config (buffer + actual_length,
-+ alternate_instance->interface_descriptor, actual_length, max);
-+
-+ // iterate across classes for this alternate interface
-+ for (class = 0; class < alternate_instance->classes; class++)
-+ actual_length += copy_config (buffer + actual_length,
-+ *(alternate_instance->class_list + class), actual_length, max);
-+
-+ // iterate across endpoints for this alternate interface
-+ //interface_descriptor = alternate_instance->interface_descriptor;
-+
-+ for (endpoint = 0; endpoint < alternate_instance->endpoints ; endpoint++) {
-+
-+ //printk(KERN_INFO"%s: endpoint: %d index: %d\n",
-+ // __FUNCTION__, endpoint,
-+ // alternate_instance->endpoint_indexes[endpoint]
-+ // );
-+ actual_length += copy_endpoint (bus->function_instance,
-+ buffer + actual_length,
-+ *(( alternate_instance->endpoint_list) + endpoint),
-+ alternate_instance->endpoint_indexes[endpoint],
-+ actual_length, max, hs);
-+ }
-+ }
-+ }
-+ }
-+ break;
-+
-+ case USB_DESCRIPTOR_TYPE_STRING:
-+ {
-+ struct usb_string_descriptor *string_descriptor;
-+ RETURN_EINVAL_IF (!(string_descriptor = usbd_get_string (index)));
-+ actual_length += copy_config (buffer + actual_length, string_descriptor, actual_length, max);
-+ }
-+ break;
-+
-+ default:
-+ return -EINVAL;
-+ }
-+ return actual_length;
-+}
-+
-+/* ep0_recv_setup_irq - process a device request
-+ *
-+ * Process a received device request. If not a Chapter nine request pass it
-+ * to the other loaded function driver recv_setup_irq() function.
-+ *
-+ * Return non-zero to indicate failure.
-+ */
-+static int ep0_recv_setup_irq (struct usb_device_request *request)
-+{
-+ struct usb_function_instance *function = ep0_function;
-+ struct usb_bus_instance *bus = ep0_function->bus;
-+
-+#if 0
-+ printk(KERN_INFO"%s: bus: %p bmRequestType:%02x bRequest:%02x wValue:%04x wIndex:%04x wLength:%04x %d\n", __FUNCTION__,
-+ function->bus, request->bmRequestType, request->bRequest,
-+ le16_to_cpu(request->wValue), le16_to_cpu(request->wIndex), le16_to_cpu(request->wLength),
-+ request->bRequest);
-+#endif
-+
-+ // handle USB Standard Request only (c.f. USB Spec table 9-2, D6..5 must be 0)
-+
-+ THROW_IF ((request->bmRequestType & USB_REQ_TYPE_MASK) != 0, non_standard);
-+
-+ THROW_IF(!( (request->bmRequestType & USB_DIR_IN ? d2h_standard_requests : h2d_standard_requests)
-+ [request->bmRequestType & 0x3] & STD(request->bRequest)), non_standard );
-+
-+ CATCH(non_standard) {
-+ return usbd_recv_setup_irq(bus->function_instance, request);
-+ }
-+
-+ switch (bus->device_state) {
-+ case STATE_CREATED:
-+ case STATE_ATTACHED:
-+ case STATE_POWERED:
-+ return -EINVAL;
-+
-+ case STATE_INIT:
-+ case STATE_DEFAULT:
-+ switch (request->bRequest) {
-+ case USB_REQ_GET_STATUS:
-+ case USB_REQ_GET_INTERFACE:
-+ case USB_REQ_SYNCH_FRAME:
-+ case USB_REQ_CLEAR_FEATURE:
-+ case USB_REQ_SET_FEATURE:
-+ case USB_REQ_SET_DESCRIPTOR:
-+ case USB_REQ_SET_INTERFACE:
-+ printk(KERN_INFO"%s: bad device_state\n", __FUNCTION__);
-+ return -EINVAL;
-+
-+ case USB_REQ_SET_CONFIGURATION:
-+ case USB_REQ_SET_ADDRESS:
-+ case USB_REQ_GET_DESCRIPTOR:
-+ case USB_REQ_GET_CONFIGURATION:
-+ break;
-+ }
-+ case STATE_ADDRESSED:
-+ case STATE_CONFIGURED:
-+ case STATE_SUSPENDED:
-+ break;
-+ case STATE_UNKNOWN:
-+ printk(KERN_INFO"%s: suspended or unknown\n", __FUNCTION__);
-+ return -EINVAL;
-+ }
-+
-+ // handle all requests that return data (direction bit set on bm RequestType)
-+ if ((request->bmRequestType & USB_REQ_DIRECTION_MASK)) {
-+
-+ struct urb *urb;
-+ int rc = 0;
-+ switch (request->bRequest) {
-+ case USB_REQ_SYNCH_FRAME:
-+ case USB_REQ_CLEAR_FEATURE:
-+ case USB_REQ_SET_FEATURE:
-+ case USB_REQ_SET_ADDRESS:
-+ case USB_REQ_SET_DESCRIPTOR:
-+ case USB_REQ_SET_CONFIGURATION:
-+ case USB_REQ_SET_INTERFACE:
-+ printk(KERN_INFO"%s: bad direction\n", __FUNCTION__);
-+ return -EINVAL;
-+ }
-+
-+ RETURN_EINVAL_IF(!le16_to_cpu(request->wLength));
-+
-+ // allocate urb, no callback, urb will be automatically de-allocated
-+ RETURN_EINVAL_IF(!(urb = usbd_alloc_urb (function, 0, le16_to_cpu(request->wLength), NULL)));
-+
-+ switch (request->bRequest) {
-+
-+ case USB_REQ_GET_STATUS:
-+ urb->actual_length = 2;
-+ urb->buffer[0] = urb->buffer[1] = 0;
-+ switch (request->bmRequestType & USB_REQ_RECIPIENT_MASK) {
-+ case USB_REQ_RECIPIENT_DEVICE:
-+ urb->buffer[0] = USB_STATUS_SELFPOWERED;
-+ break;
-+ case USB_REQ_RECIPIENT_INTERFACE:
-+ break;
-+ case USB_REQ_RECIPIENT_ENDPOINT:
-+ urb->buffer[0] = usbd_endpoint_halted (function, le16_to_cpu(request->wIndex));
-+ break;
-+ case USB_REQ_RECIPIENT_OTHER:
-+ urb->actual_length = 0;
-+ default:
-+ break;
-+ }
-+ rc = 0;
-+
-+ break;
-+
-+ case USB_REQ_GET_DESCRIPTOR:
-+ rc = usbd_get_descriptor (bus, urb->buffer,
-+ le16_to_cpu (request->wLength),
-+ le16_to_cpu (request->wValue >> 8),
-+ le16_to_cpu (request->wValue) & 0xff);
-+ if (rc != -EINVAL) {
-+ urb->actual_length = rc;
-+ rc = 0;
-+ }
-+ break;
-+
-+ case USB_REQ_GET_CONFIGURATION:
-+ urb->actual_length = 1;
-+ urb->buffer[0] = bus->ConfigurationValue;
-+ break;
-+
-+ case USB_REQ_GET_INTERFACE:
-+ RETURN_EINVAL_IF(le16_to_cpu(request->wIndex) > bus->bNumInterfaces);
-+ urb->actual_length = 1;
-+ urb->buffer[0] = bus->alternates[le16_to_cpu(request->wIndex)];
-+ break;
-+ default:
-+ rc = 1;
-+ }
-+
-+ //printk(KERN_INFO"%s: actual: %d packetsize: %d wIndex: %d rc: %d\n", __FUNCTION__,
-+ // urb->actual_length, urb->bus->driver->maxpacketsize, le16_to_cpu(request->wLength), rc);
-+
-+ if (!(urb->actual_length % urb->bus->driver->maxpacketsize) &&
-+ (urb->actual_length < le16_to_cpu(request->wLength)))
-+ {
-+ //printk(KERN_INFO"%s: NEED ZLP\n", __FUNCTION__);
-+ urb->flags |= USBD_URB_SENDZLP;
-+ }
-+ if (!rc)
-+ RETURN_ZERO_IF(!usbd_send_urb(urb));
-+ //printk(KERN_INFO"%s: failed urb: %p\n", __FUNCTION__, urb);
-+ usbd_dealloc_urb(urb);
-+ return -EINVAL;
-+ }
-+ // handle the requests that do not return data
-+ else {
-+
-+ switch (request->bRequest) {
-+
-+ case USB_REQ_CLEAR_FEATURE:
-+ case USB_REQ_SET_FEATURE:
-+ switch (request->bmRequestType & USB_REQ_RECIPIENT_MASK) {
-+ case USB_REQ_RECIPIENT_DEVICE:
-+ // XXX DEVICE_REMOTE_WAKEUP or TEST_MODE would be added here
-+ // XXX fall through for now as we do not support either
-+ case USB_REQ_RECIPIENT_INTERFACE:
-+ case USB_REQ_RECIPIENT_OTHER:
-+ default:
-+ return -EINVAL;
-+
-+ case USB_REQ_RECIPIENT_ENDPOINT:
-+ if (le16_to_cpu(request->wValue) == USB_ENDPOINT_HALT)
-+ return usbd_device_feature (function, le16_to_cpu (request->wIndex) & 0x7f,
-+ request->bRequest == USB_REQ_SET_FEATURE);
-+
-+ else
-+ return -EINVAL ;
-+ }
-+
-+ case USB_REQ_SET_ADDRESS:
-+ // check if this is a re-address, reset first if it is (this shouldn't be possible)
-+ RETURN_EINVAL_IF (bus->device_state != STATE_DEFAULT);
-+ usbd_bus_event (bus, DEVICE_ADDRESS_ASSIGNED, le16_to_cpu(request->wValue));
-+ return 0;
-+
-+ case USB_REQ_SET_DESCRIPTOR:
-+ // XXX should we support this?
-+ // This would require allocating a rcv urb and using usbd_start_recv()
-+ return -EINVAL;
-+
-+ case USB_REQ_SET_CONFIGURATION:
-+ {
-+ struct usb_function_driver *function_driver = bus->function_instance->function_driver;
-+ int bNumConfigurations = function_driver->bNumConfigurations;
-+ int bNumInterfaces;
-+ u8 ConfigurationValue;
-+
-+
-+ struct usb_configuration_instance *configuration_instance;
-+ struct usb_configuration_descriptor *configuration_descriptor;
-+
-+ // get rid of previous interface and alternates
-+ if (bus->bNumInterfaces && bus->alternates) {
-+ bus->bNumInterfaces = 0;
-+ lkfree(bus->alternates);
-+ bus->alternates = NULL;
-+ }
-+
-+ // c.f. 9.4.7 - the top half of wValue is reserved
-+ //
-+ // c.f. 9.4.7 - zero is the default or addressed state, in our case this
-+ // is the same is configuration zero, but will be fixed in usbd.c when used.
-+
-+ ConfigurationValue = le16_to_cpu (request->wValue) & 0x7f;
-+
-+ RETURN_EINVAL_IF(ConfigurationValue > bNumConfigurations);
-+
-+ ConfigurationValue = ConfigurationValue ? 0 : ConfigurationValue -1;
-+
-+ configuration_instance = &function_driver->configuration_instance_array[ConfigurationValue];
-+ configuration_descriptor = configuration_instance->configuration_descriptor;
-+
-+ RETURN_EINVAL_IF(!configuration_descriptor);
-+
-+ bNumInterfaces = configuration_instance->bNumInterfaces;
-+
-+ bus->ConfigurationValue = ConfigurationValue + 1;
-+
-+ // reset interface and alternate settings
-+
-+ RETURN_EINVAL_IF (!(bus->alternates = ckmalloc(bNumInterfaces, GFP_ATOMIC)));
-+ bus->bNumInterfaces = bNumInterfaces;
-+
-+ //usbd_bus->device_event (bus, DEVICE_CONFIGURED, 0);
-+ usbd_bus_event (bus, DEVICE_CONFIGURED, 0);
-+ return 0;
-+ }
-+
-+ case USB_REQ_SET_INTERFACE:
-+ {
-+ int interface = le16_to_cpu(request->wIndex);
-+
-+ RETURN_EINVAL_IF(interface > bus->bNumInterfaces);
-+
-+ bus->alternates[interface] = le16_to_cpu(request->wValue);
-+ usbd_bus_event (bus, DEVICE_SET_INTERFACE, 0);
-+ return 0;
-+ }
-+
-+ case USB_REQ_GET_STATUS:
-+ case USB_REQ_GET_DESCRIPTOR:
-+ case USB_REQ_GET_CONFIGURATION:
-+ case USB_REQ_GET_INTERFACE:
-+ case USB_REQ_SYNCH_FRAME: // XXX should never see this (?)
-+ printk(KERN_INFO"%s: unknown\n", __FUNCTION__);
-+ return -EINVAL;
-+ }
-+ }
-+ return -EINVAL;
-+}
-+
-+
-+/* ep0_function_enable - enable the endpoint zero function
-+ *
-+ * Return non-zero on failure.
-+ */
-+static int ep0_function_enable (struct usb_function_instance *function)
-+{
-+ ep0_function = function;
-+ return 0;
-+}
-+
-+/* ep0_function_disable - disable the endpoint zero function
-+ */
-+static void ep0_function_disable (struct usb_function_instance *function)
-+{
-+ ep0_function = NULL;
-+}
-+
-+
-+static struct usb_function_operations ep0_ops = {
-+ event_irq: ep0_event_irq,
-+ recv_setup_irq: ep0_recv_setup_irq,
-+ function_enable: ep0_function_enable,
-+ function_disable: ep0_function_disable,
-+};
-+
-+struct usb_function_driver ep0_driver = {
-+ name: "EP0",
-+ fops: &ep0_ops,
-+};
-+
-+EXPORT_SYMBOL(usbd_get_descriptor);
-diff -Nru a/drivers/usbd/mouse_fd/Config.in b/drivers/usbd/mouse_fd/Config.in
---- /dev/null Wed Dec 31 16:00:00 1969
-+++ b/drivers/usbd/mouse_fd/Config.in Fri Feb 27 14:22:51 2004
-@@ -0,0 +1,26 @@
-+#
-+# Mouse Function Driver
-+#
-+# Copyright (C) 2003 Belcarra
-+#
-+
-+
-+mainmenu_option next_comment
-+
-+comment "Random Mouse Function"
-+dep_tristate ' Mouse Function' CONFIG_USBD_MOUSE $CONFIG_USBD
-+
-+if [ "$CONFIG_USBD_MOUSE" = "y" -o "$CONFIG_USBD_MOUSE" = "m" ]; then
-+ hex 'VendorID (hex value)' CONFIG_USBD_MOUSE_VENDORID "12b9"
-+ hex 'ProductID (hex value)' CONFIG_USBD_MOUSE_PRODUCTID "f003"
-+ hex 'bcdDevice (binary-coded decimal)' CONFIG_USBD_MOUSE_BCDDEVICE "0100"
-+
-+ string 'iManufacturer (string)' CONFIG_USBD_MOUSE_MANUFACTURER "Belcarra"
-+ #string 'iProduct (string)' CONFIG_USBD_MOUSE_PRODUCT_NAME "Belcarra Mouse"
-+
-+ string 'iConfiguration (string)' CONFIG_USBD_MOUSE_DESC "Acm Cfg"
-+ string 'Comm Interface iInterface (string)' CONFIG_USBD_MOUSE_COMM_INTF "Comm Intf"
-+ bool 'Mouse BH Test' CONFIG_USBD_MOUSE_BH
-+
-+fi
-+endmenu
-diff -Nru a/drivers/usbd/mouse_fd/Makefile b/drivers/usbd/mouse_fd/Makefile
---- /dev/null Wed Dec 31 16:00:00 1969
-+++ b/drivers/usbd/mouse_fd/Makefile Fri Feb 27 14:22:51 2004
-@@ -0,0 +1,66 @@
-+#
-+# Function driver for a Mouse USB Device
-+#
-+# Copyright (c) 2003 Belcarra
-+
-+# Multipart objects.
-+
-+O_TARGET := mouse_fd.o
-+list-multi := mouse_fd.o
-+
-+mouse_fd-objs := mouse.o
-+
-+# Objects that export symbols.
-+export-objs := mouse.o
-+
-+# Object file lists.
-+
-+obj-y :=
-+obj-m :=
-+obj-n :=
-+obj- :=
-+
-+# Each configuration option enables a list of files.
-+
-+obj-$(CONFIG_USBD_MOUSE) += mouse_fd.o
-+
-+# Extract lists of the multi-part drivers.
-+# The 'int-*' lists are the intermediate files used to build the multi's.
-+
-+multi-y := $(filter $(list-multi), $(obj-y))
-+multi-m := $(filter $(list-multi), $(obj-m))
-+int-y := $(sort $(foreach m, $(multi-y), $($(basename $(m))-objs)))
-+int-m := $(sort $(foreach m, $(multi-m), $($(basename $(m))-objs)))
-+
-+# Files that are both resident and modular: remove from modular.
-+
-+obj-m := $(filter-out $(obj-y), $(obj-m))
-+int-m := $(filter-out $(int-y), $(int-m))
-+
-+# Translate to Rules.make lists.
-+
-+O_OBJS := $(filter-out $(export-objs), $(obj-y))
-+OX_OBJS := $(filter $(export-objs), $(obj-y))
-+M_OBJS := $(sort $(filter-out $(export-objs), $(obj-m)))
-+MX_OBJS := $(sort $(filter $(export-objs), $(obj-m)))
-+MI_OBJS := $(sort $(filter-out $(export-objs), $(int-m)))
-+MIX_OBJS := $(sort $(filter $(export-objs), $(int-m)))
-+
-+# The global Rules.make.
-+
-+USBD=$(TOPDIR)/drivers/usbd
-+MOUSED=$(USBD)/mouse_fd
-+include $(TOPDIR)/Rules.make
-+EXTRA_CFLAGS += -I$(MOUSED) -I$(USBD) -Wno-unused -Wno-format
-+EXTRA_CFLAGS_nostdinc += -I$(MOUSED) -I$(USBD) -Wno-unused -Wno-format
-+
-+# Link rules for multi-part drivers.
-+
-+mouse_fd.o: $(mouse_fd-objs)
-+ $(LD) -r -o $@ $(mouse_fd-objs)
-+
-+# dependencies:
-+
-+mouse.o: $(USBD)/usbd.h $(USBD)/usbd-bus.h $(USBD)/usbd-func.h
-+
-+
-diff -Nru a/drivers/usbd/mouse_fd/getmouse.c b/drivers/usbd/mouse_fd/getmouse.c
---- /dev/null Wed Dec 31 16:00:00 1969
-+++ b/drivers/usbd/mouse_fd/getmouse.c Fri Feb 27 14:22:51 2004
-@@ -0,0 +1,122 @@
-+/*******************************************************************************
-+ * File: FILE
-+ * Module: MODULE
-+ * Author: AUTHOR
-+ * Date: DATE
-+ *
-+ * Notes:
-+ *
-+ * $Id$
-+ *
-+ * History:
-+ * $Log$
-+ *
-+ ******************************************************************************/
-+
-+/*
-+ *
-+ *
-+ * 3.2. Non-Canonical Input Processing
-+ *
-+ * In non-canonical input processing mode, input is not assembled into lines and
-+ * input processing (erase, kill, delete, etc.) does not occur. Two parameters
-+ * control the behavior of this mode: c_cc[VTIME] sets the character timer, and
-+ * c_cc[VMIN] sets the minimum number of characters to receive before satisfying
-+ * the read.
-+ *
-+ * If MIN > 0 and TIME = 0, MIN sets the number of characters to receive before
-+ * the read is satisfied. As TIME is zero, the timer is not used.
-+ *
-+ * If MIN = 0 and TIME > 0, TIME serves as a timeout value. The read will be
-+ * satisfied if a single character is read, or TIME is exceeded (t = TIME *0.1
-+ * s). If TIME is exceeded, no character will be returned.
-+ *
-+ * If MIN > 0 and TIME > 0, TIME serves as an inter-character timer. The read
-+ * will be satisfied if MIN characters are received, or the time between two
-+ * characters exceeds TIME. The timer is restarted every time a character is
-+ * received and only becomes active after the first character has been received.
-+ *
-+ * If MIN = 0 and TIME = 0, read will be satisfied immediately. The number of
-+ * characters currently available, or the number of characters requested will be
-+ * returned. According to Antonino (see contributions), you could issue a fcntl
-+ * (fd, F_SETFL, FNDELAY); before reading to get the same result.
-+ *
-+ * By modifying newtio.c_cc[VTIME] and newtio.c_cc[VMIN] all modes described
-+ * above can be tested.
-+ *
-+ */
-+
-+#include <sys/types.h>
-+#include <sys/stat.h>
-+#include <fcntl.h>
-+#include <termios.h>
-+#include <stdio.h>
-+
-+#define BAUDRATE B1200
-+#define MODEMDEVICE "/dev/ttyS0"
-+#define _POSIX_SOURCE 1 /* POSIX compliant source */
-+#define FALSE 0
-+#define TRUE 1
-+
-+volatile int STOP=FALSE;
-+
-+main()
-+{
-+ int fd,c, res;
-+ struct termios oldtio,newtio;
-+ unsigned char buf[255];
-+
-+ int bytes;
-+ unsigned char mouse[3];
-+
-+ fd = open(MODEMDEVICE, O_RDWR | O_NOCTTY );
-+ if (fd <0) {perror(MODEMDEVICE); exit(-1); }
-+
-+ tcgetattr(fd,&oldtio); /* save current port settings */
-+
-+ bzero(&newtio, sizeof(newtio));
-+ newtio.c_cflag = BAUDRATE | CRTSCTS | CS8 | CLOCAL | CREAD;
-+ newtio.c_iflag = IGNPAR;
-+ newtio.c_oflag = 0;
-+
-+ /* set input mode (non-canonical, no echo,...) */
-+ newtio.c_lflag = 0;
-+
-+ newtio.c_cc[VTIME] = 0; /* inter-character timer unused */
-+ newtio.c_cc[VMIN] = 1; /* blocking read until 5 chars received */
-+
-+ tcflush(fd, TCIFLUSH);
-+ tcsetattr(fd,TCSANOW,&newtio);
-+
-+
-+ bytes = 0;
-+ while (STOP==FALSE) { /* loop for input */
-+ unsigned char c;
-+
-+ res = read(fd,buf,1); /* returns after 5 chars have been input */
-+ buf[res]=0; /* so we can printf... */
-+ //fprintf(stderr, ":%02x:%d\n", buf[0], res);
-+ //if (buf[0]=='z') STOP=TRUE;
-+
-+ c = buf[0];
-+
-+ if ( c & 0x40 ) {
-+ bytes = 1;
-+ mouse[0] = c;
-+ }
-+ else if (bytes == 1) {
-+ bytes = 2;
-+ mouse[1] = c;
-+ }
-+ else if (bytes == 2) {
-+ bytes = 0;
-+ mouse[2] = c;
-+ fprintf(stderr, "%02x %02x %02x\n", mouse[0], mouse[1], mouse[2]);
-+ //printf("%c%c%c", mouse[0], mouse[1], mouse[2]);
-+ }
-+ }
-+ tcsetattr(fd,TCSANOW,&oldtio);
-+}
-+
-+
-+/* End of FILE */
-diff -Nru a/drivers/usbd/mouse_fd/mouse.c b/drivers/usbd/mouse_fd/mouse.c
---- /dev/null Wed Dec 31 16:00:00 1969
-+++ b/drivers/usbd/mouse_fd/mouse.c Fri Feb 27 14:22:51 2004
-@@ -0,0 +1,548 @@
-+/*
-+ * usbd/mouse_fd/mouse.c
-+ *
-+ * Copyright (c) 2003, 2004 Belcarra
-+ *
-+ * By:
-+ * Stuart Lynne <sl@belcarra.com>,
-+ * Tom Rushworth <tbr@belcarra.com>,
-+ * Bruce Balden <balden@belcarra.com>
-+ *
-+ * This is a test USB HID Function Driver designed to test and
-+ * verify that INTERRUPT IN endpoints work properly.
-+ *
-+ * This emulates a simple USB mouse and generates a constant stream
-+ * of small random mouse movements.
-+ *
-+ * To use simply load with something like:
-+ *
-+ * insmod mouse_fd.o vendor_id=0xffff product_id=0xffff
-+ *
-+ * And attach to a Windows box. Windows should recognize as a mouse and
-+ * immediately start receiving a stream of data.
-+ *
-+ * To terminate simply unplug.
-+ *
-+ * The mouse driver has several other characteristics to allow testing of
-+ * other features of the bus interface driver:
-+ *
-+ * - ep0 ZLP handling
-+ *
-+ * - ep0 delayed CONTROL READ
-+ *
-+ *
-+ * Notes
-+ *
-+ * 1. The mouse driver is product name is hard coded to a string that will
-+ * generate a string descriptor that is 32 bytes long. This will test
-+ * most UDC's ep0 ZLP handling as it is a multiple of the most common
-+ * UDC endpoint zero size. (An option can be added later to allow for
-+ * 64 byte ep0 packetsize.)
-+ *
-+ * 2. The CONFIG_USBD_MOUSE_BH option can be enabled to delay the HID report
-+ * to being generated by a bottom half handler. This will verify that
-+ * the bus interface driver properly handles the case of a delayed
-+ * CONTROL READ. I.e. when the usbd_recv_setup_irq() function returns
-+ * zero for successful completion but there is no tx_urb containing the
-+ * requested data. The bus interface driver must setup the conditions for
-+ * ACK'ing the SETUP packet but then NAK the IN data for endpoint zero
-+ * until the tx_urb is started later.
-+ */
-+
-+
-+#include <linux/config.h>
-+#include <linux/module.h>
-+#include <linux/kernel.h>
-+#include <linux/version.h>
-+
-+#include <usbd-export.h>
-+#include <usbd-build.h>
-+
-+MODULE_AUTHOR ("sl@belcarra.com, tbr@belcarra.com");
-+MODULE_LICENSE("PROPRIETARY");
-+MODULE_DESCRIPTION ("Belcarra Random Walk MOUSE Function");
-+
-+#include <linux/init.h>
-+#include <asm/uaccess.h>
-+#include <linux/ctype.h>
-+#include <linux/timer.h>
-+#include <linux/interrupt.h>
-+#include <asm/atomic.h>
-+#include <linux/random.h>
-+#include <linux/slab.h>
-+
-+#include "usbd-chap9.h"
-+#include <usbd-mem.h>
-+#include <usbd.h>
-+#include <usbd-func.h>
-+
-+USBD_MODULE_INFO ("mouse_fd 2.0-beta");
-+
-+/* Module Parameters ************************************************************************* */
-+
-+static u32 vendor_id;
-+static u32 product_id;
-+
-+MODULE_PARM (vendor_id, "i");
-+MODULE_PARM (product_id, "i");
-+
-+MODULE_PARM_DESC (vendor_id, "Device Vendor ID");
-+MODULE_PARM_DESC (product_id, "Device Product ID");
-+
-+/*
-+ * ep0 testing.... ensure that this is exactly 16 bytes
-+ */
-+#undef CONFIG_USBD_MOUSE_PRODUCT_NAME
-+#define CONFIG_USBD_MOUSE_PRODUCT_NAME "Belcarra Mouse"
-+
-+/*
-+ * MOUSE Configuration
-+ *
-+ * Endpoint, Class, Interface, Configuration and Device descriptors/descriptions
-+ */
-+
-+#define BULK_INT 0x00
-+#define ENDPOINTS 0x01
-+
-+char MouseHIDReport[52] = {
-+ 0x05, 0x01, // USAGE_PAGE (Generic Desktop)
-+ 0x09, 0x02, // USAGE (Mouse)
-+ 0xa1, 0x01, // COLLECTION (Application)
-+ 0x09, 0x01, // USAGE (Pointer)
-+ 0xa1, 0x00, // COLLECTION (Physical)
-+ 0x05, 0x09, // USAGE_PAGE (Button)
-+ 0x19, 0x01, // USAGE_MINIMUM (Button 1)
-+ 0x29, 0x03, // USAGE_MAXIMUM (Button 3)
-+ 0x15, 0x00, // LOGICAL_MINIMUM (0)
-+ 0x25, 0x01, // LOGICAL_MAXIMUM (1)
-+ 0x95, 0x03, // REPORT_COUNT (3)
-+ 0x75, 0x01, // REPORT_SIZE (1)
-+ 0x81, 0x02, // INPUT (Data,Var,Abs)
-+ 0x95, 0x01, // REPORT_COUNT (1)
-+ 0x75, 0x05, // REPORT_SIZE (5)
-+ 0x81, 0x03, // INPUT (Cnst,Var,Abs)
-+ 0x05, 0x01, // USAGE_PAGE (Generic Desktop)
-+ 0x09, 0x30, // USAGE (X)
-+ 0x09, 0x31, // USAGE (Y)
-+ 0x09, 0x38, // USAGE (WHEEL)
-+ 0x15, 0x81, // LOGICAL_MINIMUM (-127)
-+ 0x25, 0x7f, // LOGICAL_MAXIMUM (127)
-+ 0x75, 0x08, // REPORT_SIZE (8)
-+ 0x95, 0x03, // REPORT_COUNT (3)
-+ 0x81, 0x06, // INPUT (Data,Var,Rel)
-+ 0xc0, // END_COLLECTION
-+ 0xc0 // END_COLLECTION
-+};
-+
-+struct usb_endpoint_descriptor mouse_data = {
-+ bLength: 0x07,
-+ bDescriptorType: USB_DT_ENDPOINT,
-+ bEndpointAddress: IN,
-+ bmAttributes: INTERRUPT,
-+ wMaxPacketSize: __constant_cpu_to_le16(0x10),
-+ bInterval: 0x01,
-+};
-+
-+struct hid_descriptor mouse_hid = {
-+ bLength: 0x09,
-+ bDescriptorType: 0x21,
-+ bcdHID: __constant_cpu_to_le16(0x110),
-+ bCountryCode: 0x00,
-+ bNumDescriptors: 0x01,
-+ bReportType: 0x22,
-+ wItemLength: __constant_cpu_to_le16(0x34),
-+};
-+
-+static struct usb_endpoint_descriptor *mouse_default[] = { &mouse_data, };
-+u8 mouse_indexes[] = { BULK_INT, };
-+static struct usb_generic_class_descriptor *mouse_hid_descriptors[] = { (struct usb_generic_class_descriptor *)&mouse_hid, };
-+
-+/* Data Interface Alternate description(s)
-+ */
-+static __u8 mouse_data_alternate_descriptor[sizeof(struct usb_interface_descriptor)] = {
-+ 0x09, USB_DT_INTERFACE, 0x00, 0x00, // bInterfaceNumber, bAlternateSetting
-+ sizeof (mouse_default) / sizeof(struct usb_endpoint_descriptor), // bNumEndpoints
-+ 0x03, 0x01, 0x02, 0x00,
-+};
-+
-+static struct usb_alternate_description mouse_data_alternate_descriptions[] = {
-+ { iInterface:"Simple Mouse Interface - Interrupt",
-+ interface_descriptor: (struct usb_interface_descriptor *)&mouse_data_alternate_descriptor,
-+ classes:sizeof (mouse_hid_descriptors) / sizeof (struct usb_generic_class_descriptor *),
-+ class_list: mouse_hid_descriptors,
-+ endpoints:sizeof (mouse_default) / sizeof(struct usb_endpoint_descriptor *),
-+ endpoint_list: mouse_default,
-+ endpoint_indexes: mouse_indexes,
-+ },
-+};
-+
-+/* Interface description(s)
-+ */
-+static struct usb_interface_description mouse_interfaces[] = {
-+ { alternates:sizeof (mouse_data_alternate_descriptions) / sizeof (struct usb_alternate_description),
-+ alternate_list:mouse_data_alternate_descriptions,},
-+};
-+
-+
-+/* Configuration description(s)
-+ */
-+static __u8 mouse_configuration_descriptor[sizeof(struct usb_configuration_descriptor)] = {
-+ 0x09, USB_DT_CONFIG, 0x00, 0x00, // wLength
-+ sizeof (mouse_interfaces) / sizeof (struct usb_interface_description),
-+ 0x01, 0x00, // bConfigurationValue, iConfiguration
-+ BMATTRIBUTE, BMAXPOWER,
-+};
-+
-+struct usb_configuration_description mouse_description[] = {
-+ { configuration_descriptor: (struct usb_configuration_descriptor *)mouse_configuration_descriptor,
-+ iConfiguration:"USB Simple Serial Configuration",
-+ bNumInterfaces:sizeof (mouse_interfaces) / sizeof (struct usb_interface_description),
-+ interface_list:mouse_interfaces,},
-+};
-+
-+/* Device Description
-+ */
-+static struct usb_device_descriptor mouse_device_descriptor = {
-+ bLength: sizeof(struct usb_device_descriptor),
-+ bDescriptorType: USB_DT_DEVICE,
-+ bcdUSB: __constant_cpu_to_le16(USB_BCD_VERSION),
-+ bDeviceClass: 0x00,
-+ bDeviceSubClass: 0x00,
-+ bDeviceProtocol: 0x00,
-+ bMaxPacketSize0: 0x00,
-+ idVendor: __constant_cpu_to_le16(CONFIG_USBD_MOUSE_VENDORID),
-+ idProduct: __constant_cpu_to_le16(CONFIG_USBD_MOUSE_PRODUCTID),
-+ bcdDevice: __constant_cpu_to_le16(CONFIG_USBD_MOUSE_BCDDEVICE),
-+};
-+
-+static struct usb_endpoint_request mouse_endpoint_requests[ENDPOINTS+1] = {
-+ { 1, 0, 0, USB_DIR_IN | USB_ENDPOINT_INTERRUPT, 16, 64, },
-+ { 0, },
-+};
-+
-+
-+struct usb_device_description mouse_device_description = {
-+ device_descriptor: &mouse_device_descriptor,
-+ iManufacturer: CONFIG_USBD_MOUSE_MANUFACTURER,
-+ iProduct: CONFIG_USBD_MOUSE_PRODUCT_NAME,
-+#if !defined(CONFIG_USBD_NO_SERIAL_NUMBER) && defined(CONFIG_USBD_SERIAL_NUMBER_STR)
-+ iSerialNumber: CONFIG_USBD_SERIAL_NUMBER_STR,
-+#endif
-+ endpointsRequested: ENDPOINTS,
-+ requestedEndpoints: mouse_endpoint_requests,
-+};
-+
-+
-+/* MOUSE ***************************************************************************************** */
-+
-+struct mouse_private {
-+ struct usb_function_instance *function;
-+ struct tq_struct notification_bh;
-+ int usb_driver_registered; // non-zero if usb function registered
-+ unsigned char connected; // non-zero if connected to host (configured)
-+ unsigned int writesize; // packetsize * 4
-+ struct urb *tx_urb;
-+ int wLength;
-+ int x;
-+ int y;
-+ int last_x;
-+ int last_y;
-+ int n;
-+};
-+
-+struct mouse_private mouse_private;
-+
-+
-+/* Transmit Function *************************************************************************** */
-+
-+int get_xy[8] = {
-+ 0, 0, 1, 1,
-+ 0, 0, -1, -1,
-+};
-+
-+void mouse_send(struct usb_function_instance *function)
-+{
-+ struct mouse_private *mouse = &mouse_private;
-+ int new_x = 0;
-+ int new_y = 0;
-+ u8 random;
-+
-+ memset(mouse->tx_urb->buffer, 0, 4);
-+ if (!mouse->n) {
-+
-+ get_random_bytes(&random, 1);
-+
-+ mouse->last_x = MAX(-4, MIN(4, mouse->last_x + get_xy[random & 0x7]));
-+ mouse->last_y = MAX(-4, MIN(4, mouse->last_y + get_xy[(random >> 3) & 0x7]));
-+ mouse->n = (random>>6) & 0x3;
-+
-+ new_x = mouse->x + mouse->last_x;
-+ new_y = mouse->y + mouse->last_y;
-+
-+ mouse->tx_urb->buffer[1] = mouse->last_x;
-+ mouse->x = new_x;
-+ mouse->tx_urb->buffer[2] = mouse->last_y;
-+ mouse->y = new_y;
-+ mouse->tx_urb->actual_length = 4;
-+#if 0
-+ printk(KERN_INFO"%s: x: %4d y: %4d rand: %02x x: %2d y: %2d new_x: %4d new_y: %4d urb: %02x %02x %02x %02x\n",
-+ __FUNCTION__,
-+ mouse->x, mouse->y, random, x, y, new_x, new_y,
-+ mouse->tx_urb->buffer[0], mouse->tx_urb->buffer[1],
-+ mouse->tx_urb->buffer[2], mouse->tx_urb->buffer[3] );
-+#endif
-+ }
-+ else if ((mouse->n)&1) {
-+ mouse->n--;
-+ }
-+ else {
-+ mouse->n--;
-+ mouse->tx_urb->buffer[1] = mouse->last_x;
-+ mouse->x = new_x;
-+ mouse->tx_urb->buffer[2] = mouse->last_y;
-+ mouse->y = new_y;
-+ }
-+ usbd_send_urb(mouse->tx_urb);
-+}
-+
-+/* mouse_urb_sent - called to indicate URB transmit finished
-+ * @urb: pointer to struct urb
-+ * @rc: result
-+ */
-+int mouse_urb_sent (struct urb *urb, int rc)
-+{
-+ struct mouse_private *mouse = &mouse_private;
-+ struct usb_function_instance *function = mouse->function;
-+
-+ RETURN_ZERO_IF(usbd_bus_status(function) == USBD_CLOSING);
-+ RETURN_ZERO_IF(usbd_bus_status(function) != USBD_OK);
-+ RETURN_ZERO_IF(usbd_device_state(function) != STATE_CONFIGURED);
-+
-+ mouse_send(function); // re-send
-+ return 0;
-+}
-+
-+/* USB Device Functions ************************************************************************ */
-+
-+/* mouse_event_irq - process a device event
-+ *
-+ */
-+void mouse_event_irq (struct usb_function_instance *function, usb_device_event_t event, int data)
-+{
-+ struct mouse_private *mouse = &mouse_private;
-+
-+ switch (event) {
-+ case DEVICE_CONFIGURED:
-+ mouse->connected = 1;
-+ if (!(mouse->tx_urb = usbd_alloc_urb (function, BULK_INT, 4, mouse_urb_sent)))
-+ printk(KERN_INFO"%s: alloc failed\n", __FUNCTION__);
-+ mouse_send(function); // start sending
-+ break;
-+
-+ case DEVICE_RESET:
-+ case DEVICE_DE_CONFIGURED:
-+ BREAK_IF(!mouse->connected);
-+ mouse->connected = 0;
-+ if (mouse->tx_urb) {
-+ usbd_dealloc_urb (mouse->tx_urb);
-+ mouse->tx_urb = NULL;
-+ }
-+ break;
-+ default:
-+ break;
-+ }
-+}
-+
-+/* copy_config
-+ * @urb: pointer to urb
-+ * @data: pointer to configuration data
-+ * @length: length of data
-+ *
-+ * Copy configuration data to urb transfer buffer if there is room for it.
-+ */
-+static int copy_report (struct urb *urb, void *data, int size, int max_buf)
-+{
-+ int available;
-+ int length;
-+
-+ RETURN_EINVAL_IF (!urb);
-+ RETURN_EINVAL_IF (!data);
-+ RETURN_EINVAL_IF (!(length = size));
-+ RETURN_EINVAL_IF ((available = max_buf - urb->actual_length) <= 0);
-+
-+ length = (length < available) ? length : available;
-+ memcpy (urb->buffer + urb->actual_length, data, length);
-+ urb->actual_length += length;
-+ return 0;
-+}
-+
-+/* mouse_send_hid - send an EP0 urb containing HID report
-+ */
-+static int mouse_send_hid (void *data)
-+{
-+ struct mouse_private *mouse = &mouse_private;
-+ struct usb_function_instance *function = mouse->function;
-+ struct urb *urb = usbd_alloc_urb_ep0(function, mouse->wLength, NULL);
-+ RETURN_EINVAL_IF (copy_report(urb, MouseHIDReport, sizeof(MouseHIDReport), mouse->wLength));
-+ RETURN_ZERO_IF(!usbd_send_urb(urb));
-+ usbd_dealloc_urb(urb);
-+ return -EINVAL;
-+}
-+
-+#ifdef CONFIG_USBD_MOUSE_BH
-+/* mouse_hid_bh - Bottom half handler to send a HID report
-+ */
-+static void mouse_hid_bh (void *data)
-+{
-+ struct usb_function_instance *function = mouse_private.function;
-+ mouse_send_hid(function);
-+ MOD_DEC_USE_COUNT;
-+}
-+
-+/* mouse_schedule_bh - schedule a call for mouse_hid_bh
-+ */
-+static int mouse_schedule_bh (void)
-+{
-+ MOD_INC_USE_COUNT;
-+ if (!schedule_task (&mouse_private.notification_bh)) {
-+ MOD_DEC_USE_COUNT;
-+ return -EINVAL;
-+ }
-+ return 0;
-+}
-+#endif /* CONFIG_USBD_MOUSE_BH */
-+
-+
-+
-+/* mouse_recv_setup_irq - called to indicate urb has been received
-+ */
-+int mouse_recv_setup_irq (struct usb_device_request *request)
-+{
-+ struct usb_function_instance *function = mouse_private.function;
-+
-+ /* verify that this is a usb class request per cdc-mouse specification or a vendor request.
-+ * determine the request direction and process accordingly
-+ */
-+ switch (request->bmRequestType & (USB_REQ_DIRECTION_MASK | USB_REQ_TYPE_MASK)) {
-+
-+ case USB_REQ_HOST2DEVICE:
-+ case USB_REQ_HOST2DEVICE | USB_REQ_TYPE_CLASS:
-+ case USB_REQ_HOST2DEVICE | USB_REQ_TYPE_VENDOR:
-+ return 0;
-+
-+ case USB_REQ_DEVICE2HOST :
-+ case USB_REQ_DEVICE2HOST | USB_REQ_TYPE_CLASS:
-+ case USB_REQ_DEVICE2HOST | USB_REQ_TYPE_VENDOR:
-+
-+ switch (request->bRequest) {
-+ case USB_REQ_GET_DESCRIPTOR:
-+ switch (le16_to_cpu(request->wValue)>>8) {
-+ case HID_REPORT:
-+ mouse_private.wLength = request->wLength;
-+#ifdef CONFIG_USBD_MOUSE_BH
-+ return mouse_schedule_bh();
-+#else
-+ return mouse_send_hid(function);
-+#endif
-+ }
-+ default: break;
-+ }
-+ break;
-+
-+ default:
-+ break;
-+ }
-+ return -EINVAL;
-+}
-+
-+
-+static int mouse_function_enable (struct usb_function_instance *function)
-+{
-+ struct mouse_private *mouse = &mouse_private;
-+
-+ MOD_INC_USE_COUNT;
-+ mouse->function = function;
-+ mouse->n = 0;
-+ mouse->x = 0;
-+ mouse->y = 0;
-+ mouse->last_x = 0;
-+ mouse->last_y = 0;
-+
-+ mouse->writesize = usbd_endpoint_wMaxPacketSize(function, BULK_INT, 0);
-+
-+ return 0;
-+}
-+
-+static void mouse_function_disable (struct usb_function_instance *function)
-+{
-+ struct mouse_private *mouse = &mouse_private;
-+ mouse->function = NULL;
-+ mouse->writesize = 0;
-+ mouse->function = NULL;
-+ MOD_DEC_USE_COUNT;
-+}
-+
-+static struct usb_function_operations function_ops = {
-+ event_irq: mouse_event_irq,
-+ recv_setup_irq: mouse_recv_setup_irq,
-+ function_enable: mouse_function_enable,
-+ function_disable: mouse_function_disable,
-+};
-+
-+static struct usb_function_driver function_driver = {
-+ name:"mouse-random",
-+ fops:&function_ops,
-+ device_description:&mouse_device_description,
-+ bNumConfigurations:sizeof (mouse_description) / sizeof (struct usb_configuration_description),
-+ configuration_description:mouse_description,
-+ idVendor: __constant_cpu_to_le16(CONFIG_USBD_MOUSE_VENDORID),
-+ idProduct: __constant_cpu_to_le16(CONFIG_USBD_MOUSE_PRODUCTID),
-+ bcdDevice: __constant_cpu_to_le16(CONFIG_USBD_MOUSE_BCDDEVICE),
-+};
-+
-+
-+/* USB Module init/exit ************************************************************************ */
-+/*
-+ * mouse_modinit - module init
-+ *
-+ */
-+static int mouse_modinit (void)
-+{
-+ printk (KERN_INFO "%s: %s vendor_id: %04x product_id: %04x\n", __FUNCTION__, __usbd_module_info, vendor_id, product_id);
-+
-+ if (vendor_id)
-+ function_driver.idVendor = cpu_to_le16(vendor_id);
-+ if (product_id)
-+ function_driver.idProduct = cpu_to_le16(product_id);
-+
-+ mouse_hid.wItemLength = cpu_to_le16(0x34); // XXX mips compiler bug.....
-+
-+ // register as usb function driver
-+ THROW_IF (usbd_register_function (&function_driver), error);
-+ mouse_private.usb_driver_registered++;
-+#ifdef CONFIG_USBD_MOUSE_BH
-+ mouse_private.notification_bh.routine = mouse_hid_bh;
-+ mouse_private.notification_bh.data = NULL;
-+#endif
-+ CATCH(error) {
-+ if (mouse_private.usb_driver_registered) {
-+ usbd_deregister_function (&function_driver);
-+ mouse_private.usb_driver_registered = 0;
-+ }
-+ return -EINVAL;
-+ }
-+ return 0;
-+}
-+
-+/* mouse_modexit - module cleanup
-+ */
-+static void mouse_modexit (void)
-+{
-+ if (mouse_private.usb_driver_registered) {
-+ usbd_deregister_function (&function_driver);
-+ }
-+}
-+
-+
-+module_init (mouse_modinit);
-+module_exit (mouse_modexit);
-diff -Nru a/drivers/usbd/network_fd/Config.in b/drivers/usbd/network_fd/Config.in
---- /dev/null Wed Dec 31 16:00:00 1969
-+++ b/drivers/usbd/network_fd/Config.in Fri Feb 27 14:22:51 2004
-@@ -0,0 +1,97 @@
-+#
-+# Network Function
-+#
-+# Copyright (C) 2002-2003 Belcarra
-+#
-+
-+mainmenu_option next_comment
-+comment "Network Function"
-+
-+dep_tristate ' Network Function Driver' CONFIG_USBD_NETWORK $CONFIG_USBD
-+
-+if [ "$CONFIG_USBD_NETWORK" = "y" -o "$CONFIG_USBD_NETWORK" = "m" ]; then
-+
-+ hex 'VendorID (hex value)' CONFIG_USBD_NETWORK_VENDORID "12b9"
-+ hex 'ProductID (hex value)' CONFIG_USBD_NETWORK_PRODUCTID "f001"
-+ hex 'bcdDevice (binary-coded decimal)' CONFIG_USBD_NETWORK_BCDDEVICE "0100"
-+
-+ string 'iManufacturer (string)' CONFIG_USBD_NETWORK_MANUFACTURER "Belcarra"
-+ string 'iProduct (string)' CONFIG_USBD_NETWORK_PRODUCT_NAME "Belcarra BLAN Device"
-+
-+
-+ comment ''
-+ bool " MDLM-BLAN Networking mode (Personal Devices)" CONFIG_USBD_NETWORK_BLAN
-+ if [ "$CONFIG_USBD_NETWORK_BLAN" = "y" ]; then
-+ string ' iConfiguration (string)' CONFIG_USBD_NETWORK_BLAN_DESC "BLAN Net Cfg"
-+ string ' iInterface (string)' CONFIG_USBD_NETWORK_BLAN_INTF "Comm/Data Intf"
-+ fi
-+
-+ if [ "$CONFIG_USBD_NETWORK_BLAN" = "y" ]; then
-+ bool " CRC" CONFIG_USBD_NETWORK_BLAN_CRC
-+
-+ if [ "$CONFIG_USBD_NETWORK_BLAN_CRC" = "y" ]; then
-+
-+ bool " Pad Before CRC (to wMaxPacketSize-1)" CONFIG_USBD_NETWORK_BLAN_PADBEFORE
-+ bool " Pad After CRC" CONFIG_USBD_NETWORK_BLAN_PADAFTER
-+ if [ "$CONFIG_USBD_NETWORK_BLAN" = "y" -a "$CONFIG_USBD_NETWORK_BLAN_PADAFTER" = "y" ]; then
-+ int ' Pad multiple' CONFIG_USBD_NETWORK_BLAN_PADBYTES "8"
-+ fi
-+ bool " Fermat Randomizer" CONFIG_USBD_NETWORK_BLAN_FERMAT
-+ fi
-+ bool " Do not Set Time" CONFIG_USBD_NETWORK_BLAN_DO_NOT_SETTIME
-+ bool " Request Hostname" CONFIG_USBD_NETWORK_BLAN_HOSTNAME
-+ bool " Infrastructure Device" CONFIG_USBD_NETWORK_BLAN_NOBRIDGE
-+ comment ''
-+ fi
-+
-+ bool " MDLM-SAFE Networking mode (Bridge/Routers)" CONFIG_USBD_NETWORK_SAFE
-+ if [ "$CONFIG_USBD_NETWORK_SAFE" = "y" ]; then
-+ string ' Data Interface iConfiguration (string)' CONFIG_USBD_NETWORK_SAFE_DESC "SAFE Net Cfg"
-+ string ' Data Interface iInterface (string)' CONFIG_USBD_NETWORK_SAFE_INTF "Data Intf"
-+ fi
-+
-+
-+ if [ "$CONFIG_USBD_NETWORK_SAFE" = "y" ]; then
-+ bool " Do not Set Time" CONFIG_USBD_NETWORK_SAFE_DO_NOT_SETTIME
-+ bool " CRC" CONFIG_USBD_NETWORK_SAFE_CRC
-+ if [ "$CONFIG_USBD_NETWORK_SAFE_CRC" = "y" ]; then
-+ bool " Pad Before CRC (to wMaxPacketSize-1)" CONFIG_USBD_NETWORK_SAFE_PADBEFORE
-+ fi
-+ bool " Infrastructure Device" CONFIG_USBD_NETWORK_SAFE_NOBRIDGE
-+ comment ''
-+ fi
-+
-+ bool " CDC Networking mode (Bridge/Routers)" CONFIG_USBD_NETWORK_CDC
-+ if [ "$CONFIG_USBD_NETWORK_CDC" = "y" ]; then
-+ string ' iConfiguration (string)' CONFIG_USBD_NETWORK_CDC_DESC "SAFE Net Cfg"
-+ string ' Data Interface iInterface (string)' CONFIG_USBD_NETWORK_CDC_COMM_INTF "Comm Intf"
-+ string ' Data (diabled) iInterface (string)' CONFIG_USBD_NETWORK_CDC_NODATA_INTF "Data (Disabled) Intf"
-+ string ' Comm Interface iInterface (string)' CONFIG_USBD_NETWORK_CDC_DATA_INTF "Dat Intf"
-+ fi
-+
-+ if [ "$CONFIG_USBD_NETWORK_SAFE" = "y" -a "$CONFIG_USBD_NETWORK_CDC" = "y" ]; then
-+ comment 'Warning: CDC and MDLM-SAFE not allowed'
-+ fi
-+
-+
-+ bool " Failsafe BASIC Networking mode" CONFIG_USBD_NETWORK_BASIC
-+ if [ "$CONFIG_USBD_NETWORK_BASIC" = "y" ]; then
-+ string ' Data Interface iConfiguration (string)' CONFIG_USBD_NETWORK_BASIC_DESC "BASIC Net Cfg"
-+ string ' Data Interface iInterface (string)' CONFIG_USBD_NETWORK_BASIC_INTF "Data Intf"
-+ fi
-+
-+ bool " Failsafe BASIC2 Networking mode" CONFIG_USBD_NETWORK_BASIC2
-+ if [ "$CONFIG_USBD_NETWORK_BASIC2" = "y" ]; then
-+ string ' Data Interface iConfiguration (string)' CONFIG_USBD_NETWORK_BASIC2_DESC "BASIC Net Cfg"
-+ string ' Comm Interface iInterface (string)' CONFIG_USBD_NETWORK_BASIC2_COMM_INTF "Comm Intf"
-+ string ' Data Interface iInterface (string)' CONFIG_USBD_NETWORK_BASIC2_DATA_INTF "Data Intf"
-+ fi
-+
-+
-+ comment ''
-+ bool ' Start Single Urb Test' CONFIG_USBD_NETWORK_START_SINGLE
-+ bool ' EP0 Test' CONFIG_USBD_NETWORK_EP0TEST
-+
-+fi
-+
-+endmenu
-diff -Nru a/drivers/usbd/network_fd/Makefile b/drivers/usbd/network_fd/Makefile
---- /dev/null Wed Dec 31 16:00:00 1969
-+++ b/drivers/usbd/network_fd/Makefile Fri Feb 27 14:22:51 2004
-@@ -0,0 +1,66 @@
-+#
-+# Network Function Driver
-+#
-+# Copyright (C) 2002-2003 Belcarra
-+
-+
-+O_TARGET := network_fd.o
-+list-multi := network_fd.o
-+
-+network_fd-objs := network.o basic.o basic2.o blan.o cdc.o safe.o fermat.o
-+
-+# Objects that export symbols.
-+export-objs := network.o
-+
-+
-+# Object file lists.
-+
-+obj-y :=
-+obj-m :=
-+obj-n :=
-+obj- :=
-+
-+# Each configuration option enables a list of files.
-+
-+obj-$(CONFIG_USBD_NETWORK) += network_fd.o
-+
-+# Extract lists of the multi-part drivers.
-+# The 'int-*' lists are the intermediate files used to build the multi's.
-+
-+multi-y := $(filter $(list-multi), $(obj-y))
-+multi-m := $(filter $(list-multi), $(obj-m))
-+int-y := $(sort $(foreach m, $(multi-y), $($(basename $(m))-objs)))
-+int-m := $(sort $(foreach m, $(multi-m), $($(basename $(m))-objs)))
-+
-+# Files that are both resident and modular: remove from modular.
-+
-+obj-m := $(filter-out $(obj-y), $(obj-m))
-+int-m := $(filter-out $(int-y), $(int-m))
-+
-+# Translate to Rules.make lists.
-+
-+O_OBJS := $(filter-out $(export-objs), $(obj-y))
-+OX_OBJS := $(filter $(export-objs), $(obj-y))
-+M_OBJS := $(sort $(filter-out $(export-objs), $(obj-m)))
-+MX_OBJS := $(sort $(filter $(export-objs), $(obj-m)))
-+MI_OBJS := $(sort $(filter-out $(export-objs), $(int-m)))
-+MIX_OBJS := $(sort $(filter $(export-objs), $(int-m)))
-+
-+# The global Rules.make.
-+
-+USBD=$(TOPDIR)/drivers/usbd
-+NETWORKD=$(USBD)/network_fd
-+include $(TOPDIR)/Rules.make
-+EXTRA_CFLAGS += -I$(NETWORKD) -I$(USBD) -Wno-unused -Wno-format
-+EXTRA_CFLAGS_nostdinc += -I$(NETWORKD) -I$(USBD) -Wno-unused -Wno-format
-+
-+# Link rules for multi-part drivers.
-+
-+network_fd.o: $(network_fd-objs)
-+ $(LD) -r -o $@ $(network_fd-objs)
-+
-+# dependencies:
-+
-+network.o: network.h $(USBD)/usbd.h $(USBD)/usbd-bus.h $(USBD)/usbd-func.h
-+
-+
-diff -Nru a/drivers/usbd/network_fd/basic.c b/drivers/usbd/network_fd/basic.c
---- /dev/null Wed Dec 31 16:00:00 1969
-+++ b/drivers/usbd/network_fd/basic.c Fri Feb 27 14:22:51 2004
-@@ -0,0 +1,157 @@
-+/*
-+ * usbd/network_fd/basic.c - Network Function Driver
-+ *
-+ * Copyright (c) 2002, 2003, 2004 Belcarra
-+ *
-+ * By:
-+ * Chris Lynne <cl@belcarra.com>
-+ * Stuart Lynne <sl@belcarra.com>
-+ * Bruce Balden <balden@belcarra.com>
-+ *
-+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
-+ *
-+ */
-+
-+
-+#include <linux/config.h>
-+#include <linux/module.h>
-+
-+#include <usbd-export.h>
-+#include <usbd-build.h>
-+
-+#include <linux/slab.h>
-+#include <linux/interrupt.h>
-+#include <linux/utsname.h>
-+#include <linux/netdevice.h>
-+
-+#include <usbd-chap9.h>
-+#include <usbd-mem.h>
-+#include <usbd.h>
-+#include <usbd-func.h>
-+
-+#include "network.h"
-+
-+
-+#ifdef CONFIG_USBD_NETWORK_BASIC
-+/* USB BASIC Configuration ******************************************************************** */
-+
-+/* BASIC Communication Interface Class descriptors
-+ */
-+static __u8 basic_data_1[] = { 0x07, USB_DT_ENDPOINT, OUT, BULK, 0, 0x00, 0x00, };
-+static __u8 basic_data_2[] = { 0x07, USB_DT_ENDPOINT, IN, BULK, 0, 0x00, 0x00, };
-+static __u8 basic_comm_1[] = { 0x07, USB_DT_ENDPOINT, IN, INTERRUPT,0, 0x00, 0x0a, };
-+
-+static struct usb_endpoint_descriptor *basic_default[] = {
-+ (struct usb_endpoint_descriptor *) &basic_data_1,
-+ (struct usb_endpoint_descriptor *) &basic_data_2,
-+ (struct usb_endpoint_descriptor *) &basic_comm_1, };
-+u8 basic_indexes[] = { BULK_OUT, BULK_IN, INT_IN, };
-+
-+/* BASIC Data Interface Alternate endpoints
-+ */
-+static __u8 basic_data_alternate_descriptor[sizeof(struct usb_interface_descriptor)] = {
-+ 0x09, USB_DT_INTERFACE, 0x00, 0x00, // bInterfaceNumber, bAlternateSetting
-+ sizeof (basic_default) / sizeof(struct usb_endpoint_descriptor), // bNumEndpoints
-+ LINEO_CLASS, LINEO_SUBCLASS_BASIC_NET, LINEO_BASIC_NET_CRC, 0x00,
-+};
-+
-+static struct usb_alternate_description basic_data_alternate_descriptions[] = {
-+ { iInterface: CONFIG_USBD_NETWORK_BASIC_INTF,
-+ interface_descriptor: (struct usb_interface_descriptor *)&basic_data_alternate_descriptor,
-+ endpoints:sizeof (basic_default) / sizeof(struct usb_endpoint_descriptor *),
-+ endpoint_list: basic_default,
-+ endpoint_indexes: basic_indexes,
-+ },
-+};
-+
-+
-+/* BASIC Data Interface Alternate descriptions and descriptors
-+ */
-+
-+/* BASIC Interface descriptions and descriptors
-+ */
-+struct usb_interface_description basic_interfaces[] = {
-+ { alternates:sizeof (basic_data_alternate_descriptions) / sizeof (struct usb_alternate_description),
-+ alternate_list:basic_data_alternate_descriptions,},
-+};
-+
-+/* BASIC Configuration descriptions and descriptors
-+ */
-+__u8 basic_configuration_descriptor[sizeof(struct usb_configuration_descriptor)] = {
-+ 0x09, USB_DT_CONFIG, 0x00, 0x00, // wLength
-+ sizeof (basic_interfaces) / sizeof (struct usb_interface_description),
-+ 0x01, 0x00, // bConfigurationValue, iConfiguration
-+ BMATTRIBUTE, BMAXPOWER,
-+};
-+
-+struct usb_configuration_description basic_description[] = {
-+ { iConfiguration: CONFIG_USBD_NETWORK_BASIC_DESC,
-+ configuration_descriptor: (struct usb_configuration_descriptor *)basic_configuration_descriptor,
-+ bNumInterfaces:sizeof (basic_interfaces) / sizeof (struct usb_interface_description),
-+ interface_list:basic_interfaces,},
-+
-+};
-+
-+/* BASIC Device Description
-+ */
-+static struct usb_device_descriptor basic_device_descriptor = {
-+ bLength: sizeof(struct usb_device_descriptor),
-+ bDescriptorType: USB_DT_DEVICE,
-+ bcdUSB: __constant_cpu_to_le16(USB_BCD_VERSION),
-+ bDeviceClass: COMMUNICATIONS_DEVICE_CLASS,
-+ bDeviceSubClass: 0x02,
-+ bDeviceProtocol: 0x00,
-+ bMaxPacketSize0: 0x00,
-+ idVendor: __constant_cpu_to_le16(CONFIG_USBD_NETWORK_VENDORID),
-+ idProduct: __constant_cpu_to_le16(CONFIG_USBD_NETWORK_PRODUCTID),
-+ bcdDevice: __constant_cpu_to_le16(CONFIG_USBD_NETWORK_BCDDEVICE),
-+};
-+
-+static struct usb_endpoint_request basic_endpoint_requests[ENDPOINTS+1] = {
-+ { 1, 0, 0, USB_DIR_OUT | USB_ENDPOINT_BULK, MAXFRAMESIZE + 48, MAXFRAMESIZE + 512, },
-+ { 1, 0, 0, USB_DIR_IN | USB_ENDPOINT_BULK, MAXFRAMESIZE + 48, MAXFRAMESIZE + 512, },
-+ { 1, 0, 0, USB_DIR_IN | USB_ENDPOINT_INTERRUPT | USB_ENDPOINT_OPT, 16, 64, },
-+ { 0, },
-+};
-+
-+struct usb_device_description basic_device_description = {
-+ device_descriptor: &basic_device_descriptor,
-+ iManufacturer: CONFIG_USBD_NETWORK_MANUFACTURER,
-+ iProduct: CONFIG_USBD_NETWORK_PRODUCT_NAME,
-+#if !defined(CONFIG_USBD_NO_SERIAL_NUMBER) && defined(CONFIG_USBD_SERIAL_NUMBER_STR)
-+ iSerialNumber:CONFIG_USBD_SERIAL_NUMBER_STR,
-+#endif
-+ endpointsRequested: ENDPOINTS,
-+ requestedEndpoints: basic_endpoint_requests,
-+};
-+
-+
-+void basic_init (struct usb_function_instance *function)
-+{
-+ basic_data_alternate_descriptions[0].endpoints = Usb_network_private.have_interrupt ? 3 : 2;
-+}
-+
-+struct usb_function_driver basic_function_driver = {
-+ name: "network-BASIC",
-+ fops: &network_fd_function_ops,
-+ device_description: &basic_device_description,
-+ bNumConfigurations: sizeof (basic_description) / sizeof (struct usb_configuration_description),
-+ configuration_description: basic_description,
-+ idVendor: __constant_cpu_to_le16(CONFIG_USBD_NETWORK_VENDORID),
-+ idProduct: __constant_cpu_to_le16(CONFIG_USBD_NETWORK_PRODUCTID),
-+ bcdDevice: __constant_cpu_to_le16(CONFIG_USBD_NETWORK_BCDDEVICE),
-+};
-+#endif /* CONFIG_USBD_NETWORK_BASIC */
-+
-diff -Nru a/drivers/usbd/network_fd/basic2.c b/drivers/usbd/network_fd/basic2.c
---- /dev/null Wed Dec 31 16:00:00 1969
-+++ b/drivers/usbd/network_fd/basic2.c Fri Feb 27 14:22:51 2004
-@@ -0,0 +1,198 @@
-+/*
-+ * usbd/network_fd/basic22.c - Network Function Driver
-+ *
-+ * Copyright (c) 2002, 2003, 2004 Belcarra
-+ *
-+ * By:
-+ * Chris Lynne <cl@belcarra.com>
-+ * Stuart Lynne <sl@belcarra.com>
-+ * Bruce Balden <balden@belcarra.com>
-+ *
-+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
-+ *
-+ */
-+
-+
-+#include <linux/config.h>
-+#include <linux/module.h>
-+
-+#include <usbd-export.h>
-+#include <usbd-build.h>
-+
-+#include <linux/slab.h>
-+#include <linux/interrupt.h>
-+#include <linux/utsname.h>
-+#include <linux/netdevice.h>
-+
-+#include <usbd-chap9.h>
-+#include <usbd-mem.h>
-+#include <usbd.h>
-+#include <usbd-func.h>
-+
-+#include "network.h"
-+
-+
-+#ifdef CONFIG_USBD_NETWORK_BASIC2
-+/* USB BASIC Configuration ******************************************************************** */
-+
-+/*
-+ * This provides a slight amplification of the basic configuration, it moves the
-+ * interrupt endpoint (if available) to a separate interface, so that it is similiar
-+ * to the cdc configuration
-+ */
-+
-+/* BASIC Communication Interface Class descriptors
-+ */
-+static __u8 basic2_data_1[] = { 0x07, USB_DT_ENDPOINT, OUT, BULK, 0, 0x00, 0x00, };
-+static __u8 basic2_data_2[] = { 0x07, USB_DT_ENDPOINT, IN, BULK, 0, 0x00, 0x00, };
-+static __u8 basic2_comm_1[] = { 0x07, USB_DT_ENDPOINT, IN, INTERRUPT,0, 0x00, 0x0a, };
-+
-+static __u8 *basic2_comm_endpoints[] = {
-+ (struct usb_endpoint_descriptor *) &basic2_comm_1, };
-+
-+static __u8 *basic2_data_endpoints[] = {
-+ (struct usb_endpoint_descriptor *) &basic2_data_1,
-+ (struct usb_endpoint_descriptor *) &basic2_data_2, };
-+
-+u8 basic2_comm_indexes[] = { INT_IN, };
-+u8 basic2_data_indexes[] = { BULK_OUT, BULK_IN, };
-+
-+
-+/* BASIC2 Data Interface Alternate endpoints
-+ */
-+
-+static __u8 basic2_comm_alternate_descriptor[sizeof(struct usb_interface_descriptor)] = {
-+ 0x09, USB_DT_INTERFACE, 0x00, 0x00, // bInterfaceNumber, bAlternateSetting
-+ sizeof (basic2_comm_endpoints) / sizeof(struct usb_endpoint_descriptor), // bNumEndpoints
-+ COMMUNICATIONS_INTERFACE_CLASS, COMMUNICATIONS_NETWORK_SUBCLASS, VENDOR, 0x00,
-+};
-+static __u8 basic2_data_alternate_descriptor[sizeof(struct usb_interface_descriptor)] = {
-+ 0x09, USB_DT_INTERFACE, 0x01, 0x00, // bInterfaceNumber, bAlternateSetting
-+ sizeof (basic2_data_endpoints) / sizeof(struct usb_endpoint_descriptor), // bNumEndpoints
-+ DATA_INTERFACE_CLASS, COMMUNICATIONS_NO_SUBCLASS, COMMUNICATIONS_NO_PROTOCOL, 0x00,
-+};
-+
-+static struct usb_alternate_description basic2_comm_alternate_descriptions[] = {
-+ { iInterface: CONFIG_USBD_NETWORK_BASIC2_COMM_INTF,
-+ interface_descriptor: (struct usb_interface_descriptor *)&basic2_comm_alternate_descriptor,
-+ endpoints:sizeof (basic2_comm_endpoints) / sizeof(struct usb_endpoint_descriptor *),
-+ endpoint_list:basic2_comm_endpoints,
-+ endpoint_indexes:basic2_comm_indexes,
-+ },
-+};
-+
-+
-+static struct usb_alternate_description basic2_data_alternate_descriptions[] = {
-+ { iInterface: CONFIG_USBD_NETWORK_BASIC2_DATA_INTF,
-+ interface_descriptor: (struct usb_interface_descriptor *)&basic2_data_alternate_descriptor,
-+ endpoints:sizeof (basic2_data_endpoints) / sizeof(struct usb_endpoint_descriptor *),
-+ endpoint_list: basic2_data_endpoints,
-+ endpoint_indexes: basic2_data_indexes,
-+ },
-+};
-+
-+
-+/* BASIC Data Interface Alternate descriptions and descriptors
-+ */
-+
-+/* BASIC Interface descriptions and descriptors
-+ */
-+static struct usb_interface_description basic2_interfaces[] = {
-+ { alternates:sizeof (basic2_comm_alternate_descriptions) / sizeof (struct usb_alternate_description),
-+ alternate_list:basic2_comm_alternate_descriptions,},
-+
-+ { alternates:sizeof (basic2_data_alternate_descriptions) / sizeof (struct usb_alternate_description),
-+ alternate_list:basic2_data_alternate_descriptions,},
-+};
-+
-+
-+/* BASIC Configuration descriptions and descriptors
-+ */
-+__u8 basic2_configuration_descriptor[sizeof(struct usb_configuration_descriptor)] = {
-+ 0x09, USB_DT_CONFIG, 0x00, 0x00, // wLength
-+ sizeof (basic2_interfaces) / sizeof (struct usb_interface_description),
-+ 0x01, 0x00, // bConfigurationValue, iConfiguration
-+ BMATTRIBUTE, BMAXPOWER,
-+};
-+
-+struct usb_configuration_description basic2_description[] = {
-+ { iConfiguration: CONFIG_USBD_NETWORK_BASIC2_DESC,
-+ configuration_descriptor: (struct usb_configuration_descriptor *)basic2_configuration_descriptor,
-+ bNumInterfaces:sizeof (basic2_interfaces) / sizeof (struct usb_interface_description),
-+ interface_list:basic2_interfaces,},
-+
-+};
-+
-+/* BASIC Device Description
-+ */
-+static struct usb_device_descriptor basic2_device_descriptor = {
-+ bLength: sizeof(struct usb_device_descriptor),
-+ bDescriptorType: USB_DT_DEVICE,
-+ bcdUSB: __constant_cpu_to_le16(USB_BCD_VERSION),
-+ bDeviceClass: COMMUNICATIONS_DEVICE_CLASS,
-+ bDeviceSubClass: 0x02,
-+ bDeviceProtocol: 0x00,
-+ bMaxPacketSize0: 0x00,
-+ idVendor: __constant_cpu_to_le16(CONFIG_USBD_BASIC2_VENDORID),
-+ idProduct: __constant_cpu_to_le16(CONFIG_USBD_BASIC2_PRODUCTID),
-+ bcdDevice: __constant_cpu_to_le16(CONFIG_USBD_BASIC2_BCDDEVICE),
-+};
-+
-+static struct usb_endpoint_request basic2_endpoint_requests[ENDPOINTS+1] = {
-+ { 1, 0, 0, USB_DIR_OUT | USB_ENDPOINT_BULK, MAXFRAMESIZE + 48, MAXFRAMESIZE + 512, },
-+ { 1, 0, 0, USB_DIR_IN | USB_ENDPOINT_BULK, MAXFRAMESIZE + 48, MAXFRAMESIZE + 512, },
-+ { 1, 0, 0, USB_DIR_IN | USB_ENDPOINT_INTERRUPT | USB_ENDPOINT_OPT, 16, 64, },
-+ { 0, },
-+};
-+
-+struct usb_device_description basic2_device_description = {
-+ device_descriptor: &basic2_device_descriptor,
-+ iManufacturer: CONFIG_USBD_NETWORK_MANUFACTURER,
-+ iProduct: CONFIG_USBD_NETWORK_PRODUCT_NAME,
-+#if !defined(CONFIG_USBD_NO_SERIAL_NUMBER) && defined(CONFIG_USBD_SERIAL_NUMBER_STR)
-+ iSerialNumber:CONFIG_USBD_SERIAL_NUMBER_STR,
-+#endif
-+ endpointsRequested: ENDPOINTS,
-+ requestedEndpoints: basic2_endpoint_requests,
-+};
-+
-+
-+void basic2_init (struct usb_function_instance *function)
-+{
-+ printk(KERN_INFO"%s:\n", __FUNCTION__);
-+
-+ basic2_comm_alternate_descriptions[0].endpoints = Usb_network_private.have_interrupt ? 1 : 0;
-+
-+ printk(KERN_INFO"%s: alternate: %p endpoints: %d\n", __FUNCTION__,
-+ basic2_data_alternate_descriptions,
-+ basic2_data_alternate_descriptions->endpoints
-+ );
-+
-+ printk(KERN_INFO"%s: finis\n", __FUNCTION__);
-+}
-+
-+
-+struct usb_function_driver basic2_function_driver = {
-+ name: "network-BASIC2",
-+ fops: &network_fd_function_ops,
-+ device_description: &basic2_device_description,
-+ bNumConfigurations: sizeof (basic2_description) / sizeof (struct usb_configuration_description),
-+ configuration_description: basic2_description,
-+ idVendor: __constant_cpu_to_le16(CONFIG_USBD_BASIC2_VENDORID),
-+ idProduct: __constant_cpu_to_le16(CONFIG_USBD_BASIC2_PRODUCTID),
-+ bcdDevice: __constant_cpu_to_le16(CONFIG_USBD_BASIC2_BCDDEVICE),
-+};
-+#endif /* CONFIG_USBD_NETWORK_BASIC2 */
-+
-diff -Nru a/drivers/usbd/network_fd/blan.c b/drivers/usbd/network_fd/blan.c
---- /dev/null Wed Dec 31 16:00:00 1969
-+++ b/drivers/usbd/network_fd/blan.c Fri Feb 27 14:22:51 2004
-@@ -0,0 +1,251 @@
-+/*
-+ * usbd/network_fd/blan.c - Network Function Driver
-+ *
-+ * Copyright (c) 2002, 2003, 2004 Belcarra
-+ *
-+ * By:
-+ * Chris Lynne <cl@belcarra.com>
-+ * Stuart Lynne <sl@belcarra.com>
-+ * Bruce Balden <balden@belcarra.com>
-+ *
-+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
-+ *
-+ */
-+
-+
-+#include <linux/config.h>
-+#include <linux/module.h>
-+#include <linux/kernel.h>
-+#include <linux/version.h>
-+
-+#include <usbd-export.h>
-+#include <usbd-build.h>
-+
-+#include <linux/slab.h>
-+#include <linux/interrupt.h>
-+#include <linux/utsname.h>
-+#include <linux/netdevice.h>
-+
-+#include <usbd-chap9.h>
-+#include <usbd-mem.h>
-+#include <usbd.h>
-+#include <usbd-func.h>
-+
-+#include "network.h"
-+
-+
-+#ifdef CONFIG_USBD_NETWORK_BLAN
-+/* USB BLAN Configuration ******************************************************************** */
-+
-+/*
-+ * BLAN Ethernet Configuration
-+ */
-+
-+/* Communication Interface Class descriptors
-+ */
-+
-+static __u8 blan_data_1[] = { 0x07, USB_DT_ENDPOINT, OUT, BULK, 0, 0x00, 0x00, };
-+static __u8 blan_data_2[] = { 0x07, USB_DT_ENDPOINT, IN, BULK, 0, 0x00, 0x00, };
-+static __u8 blan_comm_1[] = { 0x07, USB_DT_ENDPOINT, IN, INTERRUPT,0, 0x00, 0x0a, };
-+
-+static __u8 blan_class_1[] = { 0x05, CS_INTERFACE, USB_ST_HEADER, 0x10, 0x01, /* CLASS_BDC_VERSION, CLASS_BDC_VERSION */ };
-+static __u8 blan_class_2[] = { 0x15, CS_INTERFACE, USB_ST_MDLM, 0x00, 0x01, /* bcdVersion, bcdVersion */
-+ 0x74, 0xf0, 0x3d, 0xbd, 0x1e, 0xc1, 0x44, 0x70, /* bGUID */
-+ 0xa3, 0x67, 0x71, 0x34, 0xc9, 0xf5, 0x54, 0x37, /* bGUID */ };
-+
-+
-+static __u8 blan_class_3[] = { 0x07, CS_INTERFACE, USB_ST_MDLMD, 0x01, 0x00, 0x00, 0x00, };
-+
-+static __u8 blan_class_4[] = { 0x0d, CS_INTERFACE, USB_ST_ENF,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xea, 0x05, /* 1514 maximum frame size */
-+ 0x00, 0x00, 0x00 , };
-+
-+static __u8 blan_class_5[] = { 0x07, CS_INTERFACE, USB_ST_NCT, 0x00, 0x00, 0x00, 0x00, };
-+
-+
-+static struct usb_endpoint_descriptor *blan_alt_endpoints[] = {
-+ (struct usb_endpoint_descriptor *) blan_data_1,
-+ (struct usb_endpoint_descriptor *) blan_data_2,
-+ (struct usb_endpoint_descriptor *) blan_comm_1, };
-+
-+u8 blan_alt_indexes[] = { BULK_OUT, BULK_IN, INT_IN, };
-+
-+static struct usb_generic_class_descriptor *blan_comm_class_descriptors[] = {
-+ (struct usb_generic_class_descriptor *) blan_class_1,
-+ (struct usb_generic_class_descriptor *) blan_class_2,
-+ (struct usb_generic_class_descriptor *) blan_class_3,
-+ (struct usb_generic_class_descriptor *) blan_class_4,
-+ (struct usb_generic_class_descriptor *) blan_class_5, };
-+
-+
-+/* Data Interface Alternate descriptions and descriptors
-+ */
-+static __u8 blan_alternate_descriptor[sizeof(struct usb_interface_descriptor)] = {
-+ 0x09, USB_DT_INTERFACE, 0x00, 0x00, // bInterfaceNumber, bAlternateSetting
-+ sizeof (blan_alt_endpoints) / sizeof(struct usb_endpoint_descriptor), // bNumEndpoints
-+ COMMUNICATIONS_INTERFACE_CLASS, COMMUNICATIONS_MDLM_SUBCLASS, COMMUNICATIONS_NO_PROTOCOL, 0x00,
-+};
-+
-+static struct usb_alternate_description blan_alternate_descriptions[] = {
-+ { iInterface: CONFIG_USBD_NETWORK_BLAN_INTF,
-+ interface_descriptor: (struct usb_interface_descriptor *)&blan_alternate_descriptor,
-+ classes:sizeof (blan_comm_class_descriptors) / sizeof (struct usb_generic_class_descriptor *),
-+ class_list: blan_comm_class_descriptors,
-+ endpoints:sizeof (blan_alt_endpoints) / sizeof(struct usb_endpoint_descriptor *),
-+ endpoint_list: blan_alt_endpoints,
-+ endpoint_indexes: blan_alt_indexes,
-+ },
-+};
-+/* Interface descriptions and descriptors
-+ */
-+static struct usb_interface_description blan_interfaces[] = {
-+ {
-+ alternates: sizeof (blan_alternate_descriptions) / sizeof (struct usb_alternate_description),
-+ alternate_list: blan_alternate_descriptions,
-+ },
-+};
-+
-+
-+/* Configuration descriptions and descriptors
-+ */
-+
-+static __u8 blan_configuration_descriptor[sizeof(struct usb_configuration_descriptor)] = {
-+ 0x09, USB_DT_CONFIG, 0x00, 0x00, // wLength
-+ sizeof (blan_interfaces) / sizeof (struct usb_interface_description),
-+ 0x01, 0x00, // bConfigurationValue, iConfiguration
-+ BMATTRIBUTE, BMAXPOWER,
-+};
-+
-+struct usb_configuration_description blan_description[] = {
-+ { iConfiguration: CONFIG_USBD_NETWORK_BLAN_DESC,
-+ configuration_descriptor: (struct usb_configuration_descriptor *)blan_configuration_descriptor,
-+ bNumInterfaces:sizeof (blan_interfaces) / sizeof (struct usb_interface_description),
-+ interface_list:blan_interfaces, },
-+};
-+
-+/* Device Description
-+ */
-+
-+static struct usb_device_descriptor blan_device_descriptor = {
-+ bLength: sizeof(struct usb_device_descriptor),
-+ bDescriptorType: USB_DT_DEVICE,
-+ bcdUSB: __constant_cpu_to_le16(USB_BCD_VERSION),
-+ bDeviceClass: COMMUNICATIONS_DEVICE_CLASS,
-+ bDeviceSubClass: 0x02,
-+ bDeviceProtocol: 0x00,
-+ bMaxPacketSize0: 0x00,
-+ idVendor: __constant_cpu_to_le16(CONFIG_USBD_NETWORK_VENDORID),
-+ idProduct: __constant_cpu_to_le16(CONFIG_USBD_NETWORK_PRODUCTID),
-+ bcdDevice: __constant_cpu_to_le16(CONFIG_USBD_NETWORK_BCDDEVICE),
-+};
-+
-+static struct usb_endpoint_request blan_endpoint_requests[ENDPOINTS+1] = {
-+ { 1, 0, 0, USB_DIR_OUT | USB_ENDPOINT_BULK, MAXFRAMESIZE + 48, MAXFRAMESIZE + 512, },
-+ { 1, 0, 0, USB_DIR_IN | USB_ENDPOINT_BULK, MAXFRAMESIZE + 48, MAXFRAMESIZE + 512, },
-+ { 1, 0, 0, USB_DIR_IN | USB_ENDPOINT_INTERRUPT | USB_ENDPOINT_OPT, 16, 64, },
-+ { 0, },
-+};
-+
-+struct usb_device_description blan_device_description = {
-+ device_descriptor: &blan_device_descriptor,
-+ iManufacturer: CONFIG_USBD_NETWORK_MANUFACTURER,
-+ iProduct: CONFIG_USBD_NETWORK_PRODUCT_NAME,
-+#if !defined(CONFIG_USBD_NO_SERIAL_NUMBER) && defined(CONFIG_USBD_SERIAL_NUMBER_STR)
-+ iSerialNumber:CONFIG_USBD_SERIAL_NUMBER_STR,
-+#endif
-+ endpointsRequested: ENDPOINTS,
-+ requestedEndpoints: blan_endpoint_requests,
-+};
-+
-+
-+void blan_init (struct usb_function_instance *function)
-+{
-+ struct usb_class_ethernet_networking_descriptor *ethernet;
-+ struct usb_class_network_channel_descriptor *channel;
-+
-+ int len = 0;
-+ char buf[255];
-+
-+ buf[0] = 0;
-+
-+ blan_alternate_descriptions[0].endpoints = Usb_network_private.have_interrupt ? 3 : 2;
-+
-+ // Update the iMACAddress field in the ethernet descriptor
-+ {
-+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,17)
-+ char address_str[14];
-+ snprintf(address_str, 13, "%02x%02x%02x%02x%02x%02x",
-+ local_dev_addr[0], local_dev_addr[1], local_dev_addr[2],
-+ local_dev_addr[3], local_dev_addr[4], local_dev_addr[5]);
-+#else
-+ char address_str[20];
-+ sprintf(address_str, "%02x%02x%02x%02x%02x%02x",
-+ local_dev_addr[0], local_dev_addr[1], local_dev_addr[2],
-+ local_dev_addr[3], local_dev_addr[4], local_dev_addr[5]);
-+#endif
-+ //printk(KERN_INFO"%s: alloc mac string\n", __FUNCTION__);
-+ if ((ethernet = (struct usb_class_ethernet_networking_descriptor *)blan_class_4))
-+ ethernet->iMACAddress = usbd_alloc_string(address_str);
-+ //printk(KERN_INFO"%s: alloc mac string finis\n", __FUNCTION__);
-+ }
-+ //printk(KERN_INFO"%s: alloc channel string\n", __FUNCTION__);
-+ if ((channel = (struct usb_class_network_channel_descriptor *)blan_class_5))
-+ channel->iName = usbd_alloc_string(system_utsname.nodename);
-+ //printk(KERN_INFO"%s: alloc channel string finis\n", __FUNCTION__);
-+
-+#ifdef CONFIG_USBD_NETWORK_BLAN_PADBYTES
-+ blan_class_3[6] = CONFIG_USBD_NETWORK_BLAN_PADBYTES;
-+ len += sprintf(buf + len, "PADBYTES: %02x ", blan_class_3[6]);
-+#endif
-+#ifdef CONFIG_USBD_NETWORK_BLAN_PADBEFORE
-+ blan_class_3[5] |= BMDATA_PADBEFORE;
-+ len += sprintf(buf + len, "PADBEFORE: %02x ", blan_class_3[5]);
-+#endif
-+#ifdef CONFIG_USBD_NETWORK_BLAN_PADAFTER
-+ blan_class_3[5] |= BMDATA_PADAFTER;
-+ len += sprintf(buf + len, "PADAFTER: %02x ", blan_class_3[5]);
-+#endif
-+#ifdef CONFIG_USBD_NETWORK_BLAN_CRC
-+ blan_class_3[5] |= BMDATA_CRC;
-+ len += sprintf(buf + len, "CRC: %02x ", blan_class_3[5]);
-+#endif
-+#ifdef CONFIG_USBD_NETWORK_BLAN_FERMAT
-+ blan_class_3[5] |= BMDATA_FERMAT;
-+ len += sprintf(buf + len, "FERMAT: %02x ",blan_class_3[5]);
-+#endif
-+#ifdef CONFIG_USBD_NETWORK_BLAN_HOSTNAME
-+ blan_class_3[5] |= BMDATA_HOSTNAME;
-+ len += sprintf(buf + len, "HOSTNAME: %02x ",blan_class_3[5]);
-+#endif
-+#ifdef CONFIG_USBD_NETWORK_BLAN_NOBRIDGE
-+ blan_class_3[4] |= BMNETWORK_NOBRIDGE;
-+ len += sprintf(buf + len, "NOBRIDGE: %02x ",blan_class_3[4]);
-+#endif
-+ if (strlen(buf))
-+ printk(KERN_INFO"%s: %s\n", __FUNCTION__, buf);
-+}
-+
-+struct usb_function_driver blan_function_driver = {
-+ name: "network-BLAN",
-+ fops: &network_fd_function_ops,
-+ device_description: &blan_device_description,
-+ bNumConfigurations: sizeof (blan_description) / sizeof (struct usb_configuration_description),
-+ configuration_description: blan_description,
-+ idVendor: __constant_cpu_to_le16(CONFIG_USBD_NETWORK_VENDORID),
-+ idProduct: __constant_cpu_to_le16(CONFIG_USBD_NETWORK_PRODUCTID),
-+ bcdDevice: __constant_cpu_to_le16(CONFIG_USBD_NETWORK_BCDDEVICE),
-+};
-+#endif /* CONFIG_USBD_NETWORK_BLAN */
-+
-diff -Nru a/drivers/usbd/network_fd/cdc.c b/drivers/usbd/network_fd/cdc.c
---- /dev/null Wed Dec 31 16:00:00 1969
-+++ b/drivers/usbd/network_fd/cdc.c Fri Feb 27 14:22:51 2004
-@@ -0,0 +1,222 @@
-+/*
-+ * usbd/network_fd/cdc.c - Network Function Driver
-+ *
-+ * Copyright (c) 2002, 2003, 2004 Belcarra
-+ *
-+ * By:
-+ * Chris Lynne <cl@belcarra.com>
-+ * Stuart Lynne <sl@belcarra.com>
-+ * Bruce Balden <balden@belcarra.com>
-+ *
-+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
-+ *
-+ *
-+ *
-+ */
-+
-+
-+#include <linux/config.h>
-+#include <linux/module.h>
-+
-+#include <usbd-export.h>
-+#include <usbd-build.h>
-+
-+#include <linux/slab.h>
-+#include <linux/interrupt.h>
-+#include <linux/utsname.h>
-+#include <linux/netdevice.h>
-+
-+#include <usbd-chap9.h>
-+#include <usbd-mem.h>
-+#include <usbd.h>
-+#include <usbd-func.h>
-+
-+#include "network.h"
-+
-+
-+
-+#ifdef CONFIG_USBD_NETWORK_CDC
-+/* USB CDC Configuration ********************************************************************* */
-+
-+/* CDC Communication Interface Class descriptors
-+ */
-+static __u8 cdc_data_1[] = { 0x07, USB_DT_ENDPOINT, 0 | OUT, BULK, 0, 0x00, 0x00, };
-+static __u8 cdc_data_2[] = { 0x07, USB_DT_ENDPOINT, 0 | IN, BULK, 0, 0x00, 0x00, };
-+
-+static __u8 cdc_comm_1[] = { 0x07, USB_DT_ENDPOINT, 0 | IN, INTERRUPT,0, 0x00, 0x0a, };
-+
-+static __u8 cdc_class_1[] = { 0x05, CS_INTERFACE, USB_ST_HEADER, 0x10, 0x01, /* CLASS_BDC_VERSION, CLASS_BDC_VERSION */ };
-+static __u8 cdc_class_2[] = {
-+ 0x0d, CS_INTERFACE, USB_ST_ENF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xea, 0x05, /* 1514 maximum frame size */
-+ 0x00, 0x00, 0x00 , };
-+static __u8 cdc_class_3[] = { 0x05, CS_INTERFACE, USB_ST_UF, 0x00, 0x01, /* bMasterInterface, bSlaveInterface */};
-+
-+
-+static __u8 *cdc_comm_class_descriptors[] = {
-+ (struct usb_generic_class_descriptor *) &cdc_class_1,
-+ (struct usb_generic_class_descriptor *) &cdc_class_2,
-+ (struct usb_generic_class_descriptor *) &cdc_class_3, };
-+
-+static __u8 *cdc_data_endpoints[] = {
-+ (struct usb_endpoint_descriptor *) &cdc_data_1,
-+ (struct usb_endpoint_descriptor *) &cdc_data_2, };
-+static __u8 *cdc_comm_endpoints[] = {
-+ (struct usb_endpoint_descriptor *) &cdc_comm_1, };
-+
-+u8 cdc_comm_indexes[] = { INT_IN, };
-+u8 cdc_data_indexes[] = { BULK_OUT, BULK_IN, };
-+
-+
-+/* Data Interface Alternate descriptions and descriptors
-+ */
-+static __u8 cdc_comm_alternate_descriptor[sizeof(struct usb_interface_descriptor)] = {
-+ 0x09, USB_DT_INTERFACE, 0x00, 0x00, // bInterfaceNumber, bAlternateSetting
-+ sizeof (cdc_comm_endpoints) / sizeof(struct usb_endpoint_descriptor), // bNumEndpoints
-+ COMMUNICATIONS_INTERFACE_CLASS, COMMUNICATIONS_ENCM_SUBCLASS, COMMUNICATIONS_NO_PROTOCOL, 0x00,
-+};
-+static __u8 cdc_nodata_alternate_descriptor[sizeof(struct usb_interface_descriptor)] = {
-+ 0x09, USB_DT_INTERFACE, 0x01, 0x00, // bInterfaceNumber, bAlternateSetting
-+ 0x00, // bNumEndpoints
-+ DATA_INTERFACE_CLASS, COMMUNICATIONS_NO_SUBCLASS, COMMUNICATIONS_NO_PROTOCOL, 0x00,
-+};
-+static __u8 cdc_data_alternate_descriptor[sizeof(struct usb_interface_descriptor)] = {
-+ 0x09, USB_DT_INTERFACE, 0x01, 0x01, // bInterfaceNumber, bAlternateSetting
-+ sizeof (cdc_data_endpoints) / sizeof(struct usb_endpoint_descriptor), // bNumEndpoints
-+ DATA_INTERFACE_CLASS, COMMUNICATIONS_NO_SUBCLASS, COMMUNICATIONS_NO_PROTOCOL, 0x00,
-+};
-+
-+static struct usb_alternate_description cdc_comm_alternate_descriptions[] = {
-+ { iInterface: CONFIG_USBD_NETWORK_CDC_COMM_INTF,
-+ interface_descriptor: (struct usb_interface_descriptor *)&cdc_comm_alternate_descriptor,
-+ classes:sizeof (cdc_comm_class_descriptors) / sizeof (struct usb_generic_class_descriptor *),
-+ class_list: cdc_comm_class_descriptors,
-+ endpoints:sizeof (cdc_comm_endpoints) / sizeof(struct usb_endpoint_descriptor *),
-+ endpoint_list: cdc_comm_endpoints,
-+ endpoint_indexes: cdc_comm_indexes,
-+ },
-+};
-+
-+
-+static struct usb_alternate_description cdc_data_alternate_descriptions[] = {
-+ { iInterface: CONFIG_USBD_NETWORK_CDC_NODATA_INTF,
-+ interface_descriptor: (struct usb_interface_descriptor *)&cdc_nodata_alternate_descriptor, },
-+ { iInterface: CONFIG_USBD_NETWORK_CDC_DATA_INTF,
-+ interface_descriptor: (struct usb_interface_descriptor *)&cdc_data_alternate_descriptor,
-+ endpoints:sizeof (cdc_data_endpoints) / sizeof(struct usb_endpoint_descriptor *),
-+ endpoint_list: cdc_data_endpoints,
-+ endpoint_indexes: cdc_data_indexes,
-+ },
-+};
-+
-+/* Interface descriptions and descriptors
-+ */
-+struct usb_interface_description cdc_interfaces[] = {
-+ { alternates:sizeof (cdc_comm_alternate_descriptions) / sizeof (struct usb_alternate_description),
-+ alternate_list:cdc_comm_alternate_descriptions,},
-+
-+ { alternates:sizeof (cdc_data_alternate_descriptions) / sizeof (struct usb_alternate_description),
-+ alternate_list:cdc_data_alternate_descriptions,},
-+};
-+
-+/* Configuration descriptions and descriptors
-+ */
-+
-+__u8 cdc_configuration_descriptor[sizeof(struct usb_configuration_descriptor)] = {
-+ 0x09, USB_DT_CONFIG, 0x00, 0x00, // wLength
-+ sizeof (cdc_interfaces) / sizeof (struct usb_interface_description),
-+ 0x01, 0x00, // bConfigurationValue, iConfiguration
-+ BMATTRIBUTE, BMAXPOWER,
-+};
-+
-+struct usb_configuration_description cdc_description[] = {
-+ { iConfiguration: CONFIG_USBD_NETWORK_CDC_DESC,
-+ configuration_descriptor: (struct usb_configuration_descriptor *)cdc_configuration_descriptor,
-+ bNumInterfaces:sizeof (cdc_interfaces) / sizeof (struct usb_interface_description),
-+ interface_list:cdc_interfaces,},
-+};
-+
-+
-+
-+/* Device Description
-+ */
-+
-+static struct usb_device_descriptor cdc_device_descriptor = {
-+ bLength: sizeof(struct usb_device_descriptor),
-+ bDescriptorType: USB_DT_DEVICE,
-+ bcdUSB: __constant_cpu_to_le16(USB_BCD_VERSION),
-+ bDeviceClass: COMMUNICATIONS_DEVICE_CLASS,
-+ bDeviceSubClass: 0x02,
-+ bDeviceProtocol: 0x00,
-+ bMaxPacketSize0: 0x00,
-+ idVendor: __constant_cpu_to_le16(CONFIG_USBD_NETWORK_VENDORID),
-+ idProduct: __constant_cpu_to_le16(CONFIG_USBD_NETWORK_PRODUCTID),
-+ bcdDevice: __constant_cpu_to_le16(CONFIG_USBD_NETWORK_BCDDEVICE),
-+};
-+
-+static struct usb_endpoint_request cdc_endpoint_requests[ENDPOINTS+1] = {
-+ { 1, 1, 1, USB_DIR_OUT | USB_ENDPOINT_BULK, MAXFRAMESIZE + 48, MAXFRAMESIZE + 512, },
-+ { 1, 1, 1, USB_DIR_IN | USB_ENDPOINT_BULK, MAXFRAMESIZE + 48, MAXFRAMESIZE + 512, },
-+ { 1, 0, 0, USB_DIR_IN | USB_ENDPOINT_INTERRUPT | USB_ENDPOINT_OPT, 16, 64, },
-+ { 0, },
-+};
-+
-+struct usb_device_description cdc_device_description = {
-+ device_descriptor: &cdc_device_descriptor,
-+ iManufacturer: CONFIG_USBD_NETWORK_MANUFACTURER,
-+ iProduct: CONFIG_USBD_NETWORK_PRODUCT_NAME,
-+#if !defined(CONFIG_USBD_NO_SERIAL_NUMBER) && defined(CONFIG_USBD_SERIAL_NUMBER_STR)
-+ iSerialNumber:CONFIG_USBD_SERIAL_NUMBER_STR,
-+#endif
-+ endpointsRequested: ENDPOINTS,
-+ requestedEndpoints: cdc_endpoint_requests,
-+};
-+
-+
-+
-+void cdc_init (struct usb_function_instance *function)
-+{
-+ struct usb_class_ethernet_networking_descriptor *ethernet;
-+
-+ cdc_comm_alternate_descriptions[0].endpoints = Usb_network_private.have_interrupt ? 1 : 0;
-+
-+ // Update the iMACAddress field in the ethernet descriptor
-+ {
-+ char address_str[14];
-+ snprintf(address_str, 13, "%02x%02x%02x%02x%02x%02x",
-+ remote_dev_addr[0], remote_dev_addr[1], remote_dev_addr[2],
-+ remote_dev_addr[3], remote_dev_addr[4], remote_dev_addr[5]);
-+
-+ if ((ethernet = (struct usb_class_ethernet_networking_descriptor *)cdc_class_2)) {
-+ if (ethernet->iMACAddress) {
-+ usbd_dealloc_string(ethernet->iMACAddress);
-+ }
-+ ethernet->iMACAddress = usbd_alloc_string(address_str);
-+ }
-+ }
-+}
-+
-+
-+struct usb_function_driver cdc_function_driver = {
-+ name: "network-CDC",
-+ fops: &network_fd_function_ops,
-+ device_description: &cdc_device_description,
-+ bNumConfigurations: sizeof (cdc_description) / sizeof (struct usb_configuration_description),
-+ configuration_description: cdc_description,
-+ idVendor: __constant_cpu_to_le16(CONFIG_USBD_NETWORK_VENDORID),
-+ idProduct: __constant_cpu_to_le16(CONFIG_USBD_NETWORK_PRODUCTID),
-+ bcdDevice: __constant_cpu_to_le16(CONFIG_USBD_NETWORK_BCDDEVICE),
-+};
-+#endif /* CONFIG_USBD_NETWORK_CDC */
-+
-diff -Nru a/drivers/usbd/network_fd/fermat.c b/drivers/usbd/network_fd/fermat.c
---- /dev/null Wed Dec 31 16:00:00 1969
-+++ b/drivers/usbd/network_fd/fermat.c Fri Feb 27 14:22:51 2004
-@@ -0,0 +1,132 @@
-+/*
-+ * usbd/network_fd/fermat.c - Network Function Driver
-+ *
-+ * Copyright (c) 2003, 2004 Belcarra
-+ *
-+ * By:
-+ * Bruce Balden <balden@belcarra.com>
-+ *
-+ *
-+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
-+ *
-+ */
-+
-+#include <linux/config.h>
-+#include <linux/module.h>
-+#include <linux/kernel.h>
-+#include <linux/version.h>
-+
-+#ifdef CONFIG_USBD_NETWORK_BLAN_FERMAT
-+
-+#include "fermat.h"
-+
-+#ifndef FERMAT_DEFINED
-+typedef unsigned char BYTE;
-+typedef struct fermat {
-+ int length;
-+ BYTE power[256];
-+} FERMAT;
-+#endif
-+
-+
-+static int fermat_setup(FERMAT *p, int seed){
-+ int i = 0;
-+ unsigned long x,y;
-+ y = 1;
-+ do{
-+ x = y;
-+ p->power[i] = ( x == 256 ? 0 : x);
-+ y = ( seed * x ) % 257;
-+ i += 1;
-+ }while( y != 1);
-+ p->length = i;
-+ return i;
-+}
-+
-+static void fermat_xform(FERMAT *p, BYTE *data, int length){
-+ BYTE *pw = p->power;
-+ int i, j;
-+ BYTE * q ;
-+ for(i = 0, j=0, q = data; i < length; i++, j++, q++){
-+ if(j>=p->length){
-+ j = 0;
-+ }
-+ *q ^= pw[j];
-+ }
-+}
-+
-+static FERMAT default_fermat;
-+static const int primitive_root = 5;
-+void fermat_init(){
-+ (void) fermat_setup(&default_fermat, primitive_root);
-+}
-+
-+// Here are the public official versions.
-+// Change the primitive_root above to another primitive root
-+// if you need better scatter. Possible values are 3 and 7
-+
-+
-+void fermat_encode(BYTE *data, int length){
-+ fermat_xform(&default_fermat, data, length);
-+}
-+
-+void fermat_decode(BYTE *data, int length){
-+ fermat_xform(&default_fermat, data, length);
-+}
-+
-+
-+// Note: the seed must be a "primitive root" of 257. This means that
-+// the return value of the setup routine must be 256 (otherwise the
-+// seed is not a primitive root. The routine will still work fine
-+// but will be less pseudo-random.
-+
-+#undef TEST
-+#if TEST
-+#include <stdio.h>
-+#include <memory.h>
-+
-+// Use FERMAT in two ways: to encode, and to generate test data.
-+
-+main(){
-+ //Note 3, 5, and 7 are primitive roots of 257
-+ // 11 is not a primitive root
-+ FERMAT three, five, seven;
-+
-+ FERMAT three2;
-+ printf("Cycle lengths: 3,5,7 %d %d %d \n",
-+ fermat_setup(&three, 3),
-+ fermat_setup(&five, 5),
-+ fermat_setup(&seven, 7));
-+ three2=three; // Copy data from three
-+ fermat_xform(&three,three2.power,three2.length);
-+ fermat_xform(&five,three2.power,three2.length);
-+ fermat_xform(&seven,three2.power,three2.length);
-+ fermat_xform(&seven,three2.power,three2.length);
-+ fermat_xform(&five,three2.power,three2.length);
-+ fermat_xform(&three,three2.power,three2.length);
-+
-+ //At this stage, three2 and three should be identical
-+ if(memcpy(&three,&three2,sizeof(FERMAT))){
-+ printf("Decoded intact\n");
-+ }
-+
-+ fermat_init();
-+ fermat_encode(three2.power,256);
-+
-+}
-+#endif
-+
-+#endif /* CONFIG_USBD_NETWORK_BLAN_FERMAT */
-+
-diff -Nru a/drivers/usbd/network_fd/fermat.h b/drivers/usbd/network_fd/fermat.h
---- /dev/null Wed Dec 31 16:00:00 1969
-+++ b/drivers/usbd/network_fd/fermat.h Fri Feb 27 14:22:51 2004
-@@ -0,0 +1,39 @@
-+/*
-+ * usbd/network_fd/fermat.h - Network Function Driver
-+ *
-+ * Copyright (c) 2003, 2004 Belcarra
-+ *
-+ * By:
-+ * Bruce Balden <balden@belcarra.com>
-+ *
-+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
-+ *
-+ *
-+ */
-+
-+#ifndef FERMAT_DEFINED
-+#define FERMAT_DEFINED 1
-+typedef unsigned char BYTE;
-+typedef struct fermat {
-+ int length;
-+ BYTE power[256];
-+} FERMAT;
-+
-+void fermat_init(void);
-+void fermat_encode(BYTE *data, int length);
-+void fermat_decode(BYTE *data, int length);
-+#endif
-+
-+
-diff -Nru a/drivers/usbd/network_fd/network.c b/drivers/usbd/network_fd/network.c
---- /dev/null Wed Dec 31 16:00:00 1969
-+++ b/drivers/usbd/network_fd/network.c Fri Feb 27 14:22:51 2004
-@@ -0,0 +1,2112 @@
-+/*
-+ * usbd/network_fd/network.c - Network Function Driver
-+ *
-+ * Copyright (c) 2002, 2003, 2004 Belcarra
-+ *
-+ * By:
-+ * Chris Lynne <cl@belcarra.com>
-+ * Stuart Lynne <sl@belcarra.com>
-+ * Bruce Balden <balden@belcarra.com>
-+ *
-+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
-+ *
-+ *
-+ * This network function driver intended to interoperate with
-+ * Belcarra's USBLAN Class drivers.
-+ *
-+ * These are available for Windows, Linux and Mac OSX. For more
-+ * information and to download a copy for testing:
-+ *
-+ * http://www.belcarra.com/usblan/
-+ *
-+ *
-+ * Notes
-+ *
-+ * 1. If compiled into the kernel this driver can be used with NFSROOT to
-+ * provide the ROOT filesystem. Please note that the kernel NFSROOT support
-+ * (circa 2.4.20) can have problems if there are multiple interfaces. So
-+ * it is best to ensure that there are no other network interfaces compiled
-+ * in.
-+ *
-+ */
-+
-+
-+#include <linux/config.h>
-+#include <linux/module.h>
-+#include <linux/kernel.h>
-+#include <linux/version.h>
-+
-+#include <usbd-export.h>
-+#include <usbd-build.h>
-+
-+MODULE_AUTHOR ("sl@belcarra.com, balden@belcarra.com");
-+
-+
-+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,17)
-+MODULE_LICENSE("GPL");
-+#endif
-+
-+MODULE_DESCRIPTION ("USB Network Function");
-+
-+
-+#include <linux/init.h>
-+#include <linux/list.h>
-+#include <linux/netdevice.h>
-+#include <linux/skbuff.h>
-+#include <linux/etherdevice.h>
-+#include <net/arp.h>
-+#include <linux/rtnetlink.h>
-+#include <linux/smp_lock.h>
-+#include <linux/ctype.h>
-+#include <linux/time.h>
-+#include <linux/timer.h>
-+#include <linux/string.h>
-+#include <linux/atmdev.h>
-+#include <linux/pkt_sched.h>
-+#include <linux/random.h>
-+#include <linux/utsname.h>
-+
-+#include <linux/ip.h>
-+#include <linux/if_ether.h>
-+#include <linux/in.h>
-+#include <linux/inetdevice.h>
-+
-+#include <linux/kmod.h>
-+
-+#include <asm/uaccess.h>
-+#include <asm/system.h>
-+
-+#include <usbd-chap9.h>
-+#include <usbd-mem.h>
-+#include <usbd.h>
-+#include <usbd-func.h>
-+
-+USBD_MODULE_INFO ("network_fd 2.0-beta");
-+
-+#include "network.h"
-+#ifdef CONFIG_USBD_NETWORK_BLAN_FERMAT
-+#include "fermat.h"
-+#endif
-+
-+
-+#if defined(CONFIG_USBD_NETWORK_CDC)
-+
-+static u32 cdc = 0;
-+MODULE_PARM (cdc, "i");
-+MODULE_PARM_DESC (cdc, "Enable CDC mode");
-+void cdc_init(struct usb_function_instance *);
-+
-+extern struct usb_function_driver cdc_function_driver;
-+
-+#if defined(CONFIG_USBD_NETWORK_NETWORK_CDC_MYDHCPD)
-+extern u_int8_t * checkfordhcp(struct net_device *net_device, u_int8_t *, int, int* );
-+#endif
-+
-+#endif
-+
-+#ifdef CONFIG_USBD_NETWORK_BASIC
-+static u32 basic = 0;
-+MODULE_PARM (basic, "i");
-+MODULE_PARM_DESC (basic, "Enable BASIC mode");
-+void basic_init(struct usb_function_instance *);
-+extern struct usb_function_driver basic_function_driver;
-+#endif
-+
-+#ifdef CONFIG_USBD_NETWORK_BASIC2
-+static u32 basic2 = 0;
-+MODULE_PARM (basic, "i");
-+MODULE_PARM_DESC (basic2, "Enable BASIC2 mode");
-+void basic2_init(struct usb_function_instance *);
-+extern struct usb_function_driver basic2_function_driver;
-+#endif
-+
-+
-+#ifdef CONFIG_USBD_NETWORK_SAFE
-+static u32 safe = 0;
-+MODULE_PARM (safe, "i");
-+MODULE_PARM_DESC (safe, "Enable SAFE mode");
-+void safe_init(struct usb_function_instance *);
-+extern struct usb_function_driver safe_function_driver;
-+#endif
-+
-+#ifdef CONFIG_USBD_NETWORK_BLAN
-+static u32 blan = 0;
-+MODULE_PARM (blan, "i");
-+MODULE_PARM_DESC (blan, "Enable BLAN mode");
-+void blan_init(struct usb_function_instance *);
-+extern struct usb_function_driver blan_function_driver;
-+#endif
-+
-+static struct usb_function_driver *function_driver = NULL;
-+
-+
-+/* Module Parameters ************************************************************************* */
-+
-+wait_queue_head_t usb_netif_wq;
-+#ifdef CONFIG_USBD_NET_NFS_SUPPORT
-+int usb_is_configured;
-+#endif
-+
-+#define CONFIG_USBD_NETWORK_ALLOW_SETID 1
-+
-+
-+
-+#ifdef CONFIG_USBD_NETWORK_ALLOW_SETID
-+// override vendor ID
-+static u32 vendor_id;
-+MODULE_PARM (vendor_id, "i");
-+MODULE_PARM_DESC (vendor_id, "vendor id");
-+
-+// override product ID
-+static u32 product_id;
-+MODULE_PARM (product_id, "i");
-+MODULE_PARM_DESC (product_id, "product id");
-+#endif
-+
-+// override local mac address
-+#ifdef CONFIG_USBD_NETWORK_LOCAL_MACADDR
-+static char *local_mac_address_str = CONFIG_USBD_NETWORK_LOCAL_MACADDR;
-+#else
-+static char *local_mac_address_str;
-+#endif
-+MODULE_PARM (local_mac_address_str, "s");
-+MODULE_PARM_DESC (local_mac_address_str, "Local MAC");
-+
-+// override remote mac address
-+#ifdef CONFIG_USBD_NETWORK_REMOTE_MACADDR
-+static char *remote_mac_address_str = CONFIG_USBD_NETWORK_REMOTE_MACADDR;
-+#else
-+static char *remote_mac_address_str;
-+#endif
-+MODULE_PARM (remote_mac_address_str, "s");
-+MODULE_PARM_DESC (remote_mac_address_str, "Remote MAC");
-+
-+
-+#ifdef CONFIG_USBD_NETWORK_EP0TEST
-+static u32 ep0test;
-+MODULE_PARM (ep0test, "i");
-+MODULE_PARM_DESC (ep0test, "Test EP0 String Handling - set to ep0 packetsize [8,16,32,64]");
-+#endif
-+
-+
-+static u32 zeroconf = 0;
-+MODULE_PARM (zeroconf, "i");
-+MODULE_PARM_DESC (zeroconf, "Use usbz%d for network name");
-+
-+#define NETWORK_CREATED 0x01
-+#define NETWORK_REGISTERED 0x02
-+#define NETWORK_DESTROYING 0x04
-+#define NETWORK_ENABLED 0x08
-+#define NETWORK_ATTACHED 0x10
-+#define NETWORK_OPEN 0x20
-+
-+
-+#define MCCI_ENABLE_CRC 0x03
-+#define BELCARRA_GETMAC 0x04
-+
-+#define BELCARRA_SETTIME 0x04
-+#define BELCARRA_SETIP 0x05
-+#define BELCARRA_SETMSK 0x06
-+#define BELCARRA_SETROUTER 0x07
-+#define BELCARRA_SETDNS 0x08
-+#define BELCARRA_PING 0x09
-+#define BELCARRA_SETFERMAT 0x0a
-+#define BELCARRA_HOSTNAME 0x0b
-+
-+
-+#define RFC868_OFFSET_TO_EPOCH 0x83AA7E80 // RFC868 - seconds from midnight on 1 Jan 1900 GMT to Midnight 1 Jan 1970 GMT
-+
-+
-+__u8 local_dev_addr[ETH_ALEN];
-+
-+__u8 remote_dev_addr[ETH_ALEN];
-+static __u8 zeros[ETH_ALEN];
-+
-+static __u32 ip_addr;
-+static __u32 router_ip;
-+static __u32 network_mask;
-+static __u32 dns_server_ip;
-+
-+/* Prevent overlapping of bus administrative functions:
-+ *
-+ * network_function_enable
-+ * network_function_disable
-+ * network_hard_start_xmit
-+ */
-+DECLARE_MUTEX(usbd_network_sem);
-+
-+
-+struct net_device Network_net_device;
-+struct usb_network_private Usb_network_private;
-+
-+static void network_send_int_blan(struct usb_function_instance *function, int connected );
-+static void notification_schedule_bh (void);
-+static int network_urb_sent_bulk (struct urb *urb, int urb_rc);
-+static int network_urb_sent_int (struct urb *urb, int urb_rc);
-+
-+
-+//_________________________________________________________________________________________________
-+
-+/*
-+ * Synchronization
-+ *
-+ *
-+ * Notification bottom half
-+ *
-+ * This is a scheduled task that will send an interrupt notification. Because it
-+ * is called from the task scheduler context it needs to verify that the device is
-+ * still usable.
-+ *
-+ * static int network_send_int_blan(struct usb_device_instance *, int )
-+ * static void notification_bh (void *)
-+ * void notification_schedule_bh (void)
-+ *
-+ *
-+ * Netdevice functions
-+ *
-+ * These are called by the Linux network layer. They must be protected by irq locks
-+ * if necessary to prevent interruption by IRQ level events.
-+ *
-+ * int network_init (struct net_device *net_device)
-+ * void network_uninit (struct net_device *net_device)
-+ * int network_open (struct net_device *net_device)
-+ * int network_stop (struct net_device *net_device)
-+ * struct net_device_stats *network_get_stats (struct net_device *net_device)
-+ * int network_set_mac_addr (struct net_device *net_device, void *p)
-+ * void network_tx_timeout (struct net_device *net_device)
-+ * int network_set_config (struct net_device *net_device, struct ifmap *map)
-+ * int network_stop (struct net_device *net_device)
-+ * int network_hard_start_xmit (struct sk_buff *skb, struct net_device *net_device)
-+ * int network_do_ioctl (struct net_device *net_device, struct ifreq *rp, int cmd)
-+ *
-+ *
-+ * Data bottom half functions
-+ *
-+ * These are called from the bus bottom half handler.
-+ *
-+ * static int network_recv (struct usb_network_private *, struct net_device *, struct sk_buff *)
-+ * int network_recv_urb (struct urb *)
-+ * int network_urb_sent (struct urb *, int )
-+ *
-+ *
-+ * Hotplug bottom half:
-+ *
-+ * This is a scheduled task that will send do a hotplug call. Because it is
-+ * called from the task scheduler context it needs to verify that the
-+ * device is still usable.
-+ *
-+ * static int hotplug_attach (__u32 ip, __u32 mask, __u32 router, int attach)
-+ * static void hotplug_bh (void *data)
-+ * void hotplug_schedule_bh (void)
-+ *
-+ *
-+ * Irq level functions:
-+ *
-+ * These are called at interrupt time do process or respond to USB setup
-+ * commands.
-+ *
-+ * int network_recv_setup_irq (struct usb_device_request *)
-+ * void network_event_irq (struct usb_function_instance *function, usb_device_event_t event, int data)
-+ *
-+ *
-+ * Enable and disable functions:
-+ *
-+ * void network_function_enable (struct usb_function_instance *, struct usb_function_instance *)
-+ * void network_function_disable (struct usb_function_instance *function)
-+ *
-+ *
-+ * Driver initialization and exit:
-+ *
-+ * static int network_create (void)
-+ * static void network_destroy (void)
-+ *
-+ * int network_modinit (void)
-+ * void network_modexit (void)
-+ */
-+
-+//_________________________________________________________________________________________________
-+
-+/*
-+ * If the following are defined we implement the crc32_copy routine using
-+ * Duff's device. This will unroll the copy loop by either 4 or 8. Do not
-+ * use these without profiling to test if it actually helps on any specific
-+ * device.
-+ */
-+#undef CONFIG_USBD_NETWORK_CRC_DUFF4
-+#undef CONFIG_USBD_NETWORK_CRC_DUFF8
-+
-+static __u32 *network_crc32_table;
-+
-+#define CRC32_INIT 0xffffffff // Initial FCS value
-+#define CRC32_GOOD 0xdebb20e3 // Good final FCS value
-+
-+#define CRC32_POLY 0xedb88320 // Polynomial for table generation
-+
-+#define COMPUTE_FCS(val, c) (((val) >> 8) ^ network_crc32_table[((val) ^ (c)) & 0xff])
-+
-+//_________________________________________________________________________________________________
-+// crc32_copy
-+
-+/**
-+ * Generate the crc32 table
-+ *
-+ * return non-zero if malloc fails
-+ */
-+static int make_crc_table(void)
-+{
-+ u32 n;
-+ RETURN_ZERO_IF(network_crc32_table);
-+ RETURN_ENOMEM_IF(!(network_crc32_table = (u32 *)ckmalloc(256*4, GFP_KERNEL)));
-+ for (n = 0; n < 256; n++) {
-+ int k;
-+ u32 c = n;
-+ for (k = 0; k < 8; k++) {
-+ c = (c & 1) ? (CRC32_POLY ^ (c >> 1)) : (c >> 1);
-+ }
-+ network_crc32_table[n] = c;
-+ }
-+ return 0;
-+}
-+
-+#if !defined(CONFIG_USBD_NETWORK_CRC_DUFF4) && !defined(CONFIG_USBD_NETWORK_CRC_DUFF8)
-+/**
-+ * Copies a specified number of bytes, computing the 32-bit CRC FCS as it does so.
-+ *
-+ * dst Pointer to the destination memory area.
-+ * src Pointer to the source memory area.
-+ * len Number of bytes to copy.
-+ * val Starting value for the CRC FCS.
-+ *
-+ * Returns Final value of the CRC FCS.
-+ *
-+ * @sa crc32_pad
-+ */
-+static __u32 __inline__ crc32_copy (__u8 *dst, __u8 *src, int len, __u32 val)
-+{
-+ for (; len-- > 0; val = COMPUTE_FCS (val, *dst++ = *src++));
-+ return val;
-+}
-+
-+#else /* DUFFn */
-+
-+/**
-+ * Copies a specified number of bytes, computing the 32-bit CRC FCS as it does so.
-+ *
-+ * dst Pointer to the destination memory area.
-+ * src Pointer to the source memory area.
-+ * len Number of bytes to copy.
-+ * val Starting value for the CRC FCS.
-+ *
-+ * Returns Final value of the CRC FCS.
-+ *
-+ * @sa crc32_pad
-+ */
-+static __u32 crc32_copy (__u8 *dst, __u8 *src, int len, __u32 val)
-+{
-+#if defined(CONFIG_USBD_NETWORK_CRC_DUFF8)
-+ int n = (len + 7) / 8;
-+ switch (len % 8)
-+#elif defined(CONFIG_USBD_NETWORK_CRC_DUFF4)
-+ int n = (len + 3) / 4;
-+ switch (len % 4)
-+#endif
-+ {
-+ case 0: do {
-+ val = COMPUTE_FCS (val, *dst++ = *src++);
-+#if defined(CONFIG_USBD_NETWORK_CRC_DUFF8)
-+ case 7:
-+ val = COMPUTE_FCS (val, *dst++ = *src++);
-+ case 6:
-+ val = COMPUTE_FCS (val, *dst++ = *src++);
-+ case 5:
-+ val = COMPUTE_FCS (val, *dst++ = *src++);
-+ case 4:
-+ val = COMPUTE_FCS (val, *dst++ = *src++);
-+#endif
-+ case 3:
-+ val = COMPUTE_FCS (val, *dst++ = *src++);
-+ case 2:
-+ val = COMPUTE_FCS (val, *dst++ = *src++);
-+ case 1:
-+ val = COMPUTE_FCS (val, *dst++ = *src++);
-+ } while (--n > 0);
-+ }
-+ return val;
-+}
-+#endif /* DUFFn */
-+
-+
-+//_________________________________________________________________________________________________
-+// crc32_pad
-+
-+/* crc32_pad - pad and calculate crc32
-+ *
-+ * Returns - CRC FCS
-+ */
-+static __u32 __inline__ crc32_pad (__u8 *dst, int len, __u32 val)
-+{
-+ for (; len-- > 0; val = COMPUTE_FCS (val, *dst++ = '\0'));
-+ return val;
-+}
-+
-+//_________________________________________________________________________________________________
-+// network_send_int
-+//
-+
-+/* network_send_int_blan - send an interrupt notification response
-+ *
-+ * Generates a response urb on the notification (INTERRUPT) endpoint.
-+ * Return a non-zero result code to STALL the transaction.
-+ *
-+ * This is called from either a scheduled task or from the process context
-+ * that calls network_open() or network_close().
-+ *
-+ */
-+static void network_send_int_blan(struct usb_function_instance *function, int connected )
-+{
-+ struct urb *urb;
-+ struct cdc_notification_descriptor *cdc;
-+ int rc;
-+ struct usb_network_private *network_private = &Usb_network_private;
-+
-+ //printk(KERN_INFO"%s: device: %p\n", __FUNCTION__, device);
-+
-+ /*
-+ * This needs to lock out interrupts as network_event_irq can
-+ * change the NETWORK_ATTACHED status
-+ */
-+ unsigned long flags;
-+ local_irq_save(flags);
-+ do {
-+ BREAK_IF(!function);
-+
-+
-+ BREAK_IF(network_private->network_type != network_blan);
-+ BREAK_IF(!network_private->have_interrupt);
-+
-+ BREAK_IF(!(network_private->flags & NETWORK_ATTACHED));
-+
-+ //printk(KERN_INFO"%s: connected: %d network: %d %d\n", __FUNCTION__, connected,
-+ // network_private->network_type, network_blan);
-+
-+ BREAK_IF(usbd_bus_status(function) != USBD_OK);
-+
-+ if (network_private->int_urb) {
-+ printk(KERN_INFO"%s: int_urb: %p\n", __FUNCTION__, network_private->int_urb);
-+ usbd_cancel_urb_irq(network_private->int_urb);
-+ network_private->int_urb = NULL;
-+ }
-+
-+ BREAK_IF(!(urb = usbd_alloc_urb (function, INT_IN,
-+ sizeof(struct cdc_notification_descriptor), network_urb_sent_int)));
-+
-+ urb->actual_length = sizeof(struct cdc_notification_descriptor);
-+ memset(urb->buffer, 0, sizeof(struct cdc_notification_descriptor));
-+
-+ cdc = (struct cdc_notification_descriptor *)urb->buffer;
-+
-+ cdc->bmRequestType = 0xa1;
-+ cdc->bNotification = 0x00;
-+ cdc->wValue = connected ? 0x01 : 0x00;
-+ cdc->wIndex = 0x01; // XXX interface - check that this is correct
-+
-+
-+ network_private->int_urb = urb;
-+ //printk(KERN_INFO"%s: int_urb: %p\n", __FUNCTION__, urb);
-+ BREAK_IF (!(rc = usbd_send_urb (urb)));
-+
-+ printk(KERN_ERR"%s: usbd_send_urb failed err: %x\n", __FUNCTION__, rc);
-+ urb->privdata = NULL;
-+ network_private->int_urb = NULL;
-+ usbd_dealloc_urb (urb);
-+
-+ } while(0);
-+ local_irq_restore(flags);
-+}
-+
-+
-+/* notification_bh - Bottom half handler to send a notification status
-+ *
-+ * Send a notification with open/close status
-+ *
-+ * It should not be possible for this to be called more than once at a time
-+ * as it is only called via schedule_task() which protects against a second
-+ * invocation.
-+ */
-+static void notification_bh (void *data)
-+{
-+ network_send_int_blan(Usb_network_private.function, Usb_network_private.flags & NETWORK_OPEN);
-+ MOD_DEC_USE_COUNT;
-+}
-+
-+/* notification_schedule_bh - schedule a call for notification_bh
-+ */
-+static void notification_schedule_bh (void)
-+{
-+ MOD_INC_USE_COUNT;
-+ if (!schedule_task (&Usb_network_private.notification_bh))
-+ MOD_DEC_USE_COUNT;
-+}
-+
-+
-+//______________________________________Network Layer Functions____________________________________
-+
-+/*
-+ * In general because the functions are called from an independant layer it is necessary
-+ * to verify that the device is still ok and to lock interrupts out to prevent in-advertant
-+ * closures while in progress.
-+ */
-+
-+/* network_init -
-+ *
-+ * Initializes the specified network device.
-+ *
-+ * Returns non-zero for failure.
-+ */
-+static int network_init (struct net_device *net_device)
-+{
-+ //printk(KERN_INFO"%s:\n", __FUNCTION__);
-+ return 0;
-+}
-+
-+
-+/* network_uninit -
-+ *
-+ * Uninitializes the specified network device.
-+ */
-+static void network_uninit (struct net_device *net_device)
-+{
-+ //printk(KERN_INFO"%s:\n", __FUNCTION__);
-+ return;
-+}
-+
-+
-+/* network_open -
-+ *
-+ * Opens the specified network device.
-+ *
-+ * Returns non-zero for failure.
-+ */
-+static int network_open (struct net_device *net_device)
-+{
-+ struct usb_network_private *network_private = &Usb_network_private;
-+
-+ // XXX should this be before or after the preceeding netif_running() test?
-+ MOD_INC_USE_COUNT;
-+ network_private->flags |= NETWORK_OPEN;
-+ netif_wake_queue (net_device);
-+ network_send_int_blan(network_private->function, 1);
-+
-+#ifdef CONFIG_USBD_NET_NFS_SUPPORT
-+ if (!usb_is_configured) {
-+ if (!in_interrupt()) {
-+ printk(KERN_ERR"Please replug USB cable and then ifconfig host interface.\n");
-+ interruptible_sleep_on(&usb_netif_wq);
-+ }
-+ else {
-+ printk(KERN_ERR"Wanring! In interrupt\n");
-+ }
-+ }
-+#endif
-+ return 0;
-+}
-+
-+
-+/* network_stop -
-+ *
-+ * Stops the specified network device.
-+ *
-+ * Returns non-zero for failure.
-+ */
-+static int network_stop (struct net_device *net_device)
-+{
-+ struct usb_network_private *network_private = &Usb_network_private;
-+
-+ //printk(KERN_INFO"%s:\n", __FUNCTION__);
-+
-+ //netif_stop_queue (net_device);
-+
-+ network_private->flags &= ~NETWORK_OPEN;
-+ network_send_int_blan(network_private->function, 0);
-+
-+ MOD_DEC_USE_COUNT;
-+ return 0;
-+}
-+
-+
-+/* network_get_stats -
-+ *
-+ * Gets statistics from the specified network device.
-+ *
-+ * Returns pointer to net_device_stats structure with the required information.
-+ */
-+static struct net_device_stats *network_get_stats (struct net_device *net_device)
-+{
-+ struct usb_network_private *network_private = &Usb_network_private;
-+ return &network_private->stats;
-+}
-+
-+
-+/* network_set_mac_addr
-+ *
-+ * Sets the MAC address of the specified network device. Fails if the device is in use.
-+ *
-+ * Returns non-zero for failure.
-+ */
-+static int network_set_mac_addr (struct net_device *net_device, void *p)
-+{
-+ struct sockaddr *addr = p;
-+ unsigned long flags;
-+
-+ //printk(KERN_INFO"%s:\n", __FUNCTION__);
-+
-+ RETURN_EBUSY_IF(netif_running (net_device));
-+ local_irq_save(flags);
-+ memcpy (net_device->dev_addr, addr->sa_data, net_device->addr_len);
-+ local_irq_restore(flags);
-+ return 0;
-+}
-+
-+
-+/* network_tx_timeout -
-+ *
-+ * Tells the specified network device that its current transmit attempt has timed out.
-+ */
-+static void network_tx_timeout (struct net_device *net_device)
-+{
-+ struct usb_network_private *network_private = &Usb_network_private;
-+#if 0
-+ //printk(KERN_ERR"%s:\n", __FUNCTION__);
-+ network_private->stats.tx_errors++;
-+ network_private->stats.tx_dropped++;
-+ usbd_cancel_urb_irq (network_private->bus, NULL);
-+#endif
-+#if 0
-+ // XXX attempt to wakeup the host...
-+ if ((network_private->network_type == network_blan) && (network_private->flags & NETWORK_OPEN)) {
-+ notification_schedule_bh();
-+ }
-+#endif
-+}
-+
-+
-+/** network_set_config -
-+ *
-+ * Sets the specified network device's configuration. Fails if the device is in use.
-+ *
-+ * map An ifmap structure containing configuration values.
-+ * Those values which are non-zero/non-null update the corresponding fields
-+ * in net_device.
-+ *
-+ * Returns non-zero for failure.
-+ */
-+static int network_set_config (struct net_device *net_device, struct ifmap *map)
-+{
-+ RETURN_EBUSY_IF(netif_running (net_device));
-+ if (map->base_addr)
-+ net_device->base_addr = map->base_addr;
-+ if (map->mem_start)
-+ net_device->mem_start = map->mem_start;
-+ if (map->irq)
-+ net_device->irq = map->irq;
-+ return 0;
-+}
-+
-+
-+/* network_change_mtu -
-+ *
-+ * Sets the specified network device's MTU. Fails if the new value is larger and
-+ * the device is in use.
-+ *
-+ * Returns non-zero for failure.
-+ */
-+static int network_change_mtu (struct net_device *net_device, int mtu)
-+{
-+ struct usb_network_private *network_private = &Usb_network_private;
-+
-+ //printk(KERN_INFO"%s:\n", __FUNCTION__);
-+
-+ RETURN_EBUSY_IF(netif_running (net_device));
-+ RETURN_EBUSY_IF(mtu > network_private->mtu);
-+
-+ net_device->mtu = mtu;
-+ return 0;
-+}
-+
-+//_________________________________________________________________________________________________
-+// network_hard_start_xmit
-+
-+/* network_hard_start_xmit - start sending an skb
-+ *
-+ * Starts a network device's transmit function.
-+ * Called by kernel network layer to transmit a frame on this device.
-+ * Grab locks and pass to @c netproto_do_xmit().
-+ * The network layer flow control is managed to prevent more than
-+ * @c device->max_queue_entries from being outstanding.
-+ *
-+ * skb Pointer to the sk_buff structure to be sent.
-+ * net_device Specifies the device by pointing to its net_device struct.
-+ *
-+ * Return non-zero (1) if busy.
-+ */
-+static int network_hard_start_xmit (struct sk_buff *skb, struct net_device *net_device)
-+{
-+ struct usb_network_private *network_private = &Usb_network_private;
-+ struct usb_function_instance *function = network_private->function;
-+ struct urb *urb = NULL;
-+ int len = skb->len;
-+ int rc = 1;
-+ int in_pkt_sz;
-+
-+ down(&usbd_network_sem);
-+ do {
-+
-+
-+#if 0
-+ printk(KERN_INFO"%s: %s len: %d encap: %d\n", __FUNCTION__, net_device->name, skb->len, network_private->encapsulation);
-+ printk(KERN_INFO"start_xmit: len: %x head: %p data: %p tail: %p\n",
-+ skb->len, skb->head, skb->data, skb->tail);
-+ {
-+ __u8 *cp = skb->data;
-+ int i;
-+ for (i = 0; i < skb->len; i++) {
-+ if ((i%32) == 0) {
-+ printk("\ntx[%2x] ", i);
-+ }
-+ printk("%02x ", *cp++);
-+ }
-+ printk("\n");
-+ }
-+#endif
-+
-+ THROW_IF(!(network_private->flags & NETWORK_ATTACHED), not_ok);
-+ THROW_IF(!netif_carrier_ok (net_device), not_ok);
-+ THROW_IF(usbd_bus_status(function) != USBD_OK, not_ok);
-+
-+#if defined(CONFIG_USBD_NETWORK_CDC)
-+ // verify interface is enabled - non-zero altsetting means data is enabled
-+ THROW_IF(!usbd_interface_AltSetting(function, DATA_INTF), not_ok);
-+#endif
-+ in_pkt_sz = usbd_endpoint_wMaxPacketSize(function, BULK_IN, usbd_high_speed(function));
-+
-+ // stop queue, it will be restart only when we are ready for another skb
-+ netif_stop_queue (net_device);
-+
-+ // lock and update some stats
-+ network_private->stopped++;
-+ network_private->queued_entries++;
-+ network_private->queued_bytes += skb->len;
-+
-+
-+ // Set the timestamp for tx timeout
-+ net_device->trans_start = jiffies;
-+
-+ switch (network_private->encapsulation) {
-+ case simple_crc:
-+ //printk(KERN_INFO"%s: BASIC_CRC\n", __FUNCTION__);
-+ {
-+ u32 crc;
-+
-+ // allocate urb 5 bytes larger than required
-+ if (!(urb = usbd_alloc_urb (function, BULK_IN,
-+ skb->len + 5 + in_pkt_sz, network_urb_sent_bulk )))
-+ {
-+ printk(KERN_ERR"%s: urb alloc failed len: %d endpoint: %02x\n",
-+ __FUNCTION__, skb->len,
-+ usbd_endpoint_bEndpointAddress(function, BULK_IN,
-+ usbd_high_speed(function)));
-+ return -ENOMEM;
-+ }
-+
-+ // copy and crc skb->len bytes
-+ crc = crc32_copy(urb->buffer, skb->data, skb->len, CRC32_INIT);
-+ urb->actual_length = skb->len;
-+
-+ // add a pad byte if required to ensure a short packet, usbdnet driver
-+ // will correctly handle pad byte before or after CRC, but the MCCI driver
-+ // wants it before the CRC.
-+ if ((urb->actual_length % in_pkt_sz) == (in_pkt_sz - 4)) {
-+ crc = crc32_pad(urb->buffer + urb->actual_length, 1, crc);
-+ urb->actual_length++;
-+ }
-+
-+ // munge and append crc
-+ crc = ~crc;
-+ urb->buffer[urb->actual_length++] = crc & 0xff;
-+ urb->buffer[urb->actual_length++] = (crc >> 8) & 0xff;
-+ urb->buffer[urb->actual_length++] = (crc >> 16) & 0xff;
-+ urb->buffer[urb->actual_length++] = (crc >> 24) & 0xff;
-+
-+ break;
-+ }
-+ default:
-+ break;
-+
-+ }
-+ if (!urb) {
-+ printk(KERN_ERR"%s: unknown encapsulation\n", __FUNCTION__);
-+ rc = -EINVAL;
-+ break;
-+ }
-+
-+ // save skb for netproto_done
-+ urb->privdata = (void *) skb;
-+#if 0
-+ printk(KERN_INFO"start_xmit: len: %d : %d data: %p\n", skb->len, urb->actual_length, urb->buffer);
-+ {
-+ __u8 *cp = urb->buffer;
-+ int i;
-+ for (i = 0; i < urb->actual_length; i++) {
-+ if ((i%32) == 0) {
-+ printk("\ntx[%2x] ", i);
-+ }
-+ printk("%02x ", *cp++);
-+ }
-+ printk("\n");
-+ }
-+#endif
-+#if defined(CONFIG_USBD_NETWORK_BLAN_FERMAT)
-+ if (network_private->fermat) {
-+ fermat_encode(urb->buffer, urb->actual_length);
-+ }
-+#endif
-+
-+ //printk(KERN_INFO"%s: urb: %p\n", __FUNCTION__, urb);
-+ if ((rc = usbd_send_urb (urb))) {
-+
-+ printk(KERN_ERR"%s: FAILED: %d\n", __FUNCTION__, rc);
-+ urb->privdata = NULL;
-+ usbd_dealloc_urb (urb);
-+
-+ switch (rc) {
-+
-+ case -EINVAL:
-+ case -EUNATCH:
-+ printk(KERN_ERR"%s: not attached, send failed: %d\n", __FUNCTION__, rc);
-+ network_private->stats.tx_errors++;
-+ network_private->stats.tx_carrier_errors++;
-+ netif_wake_queue (net_device);
-+ break;
-+
-+ case -ENOMEM:
-+ printk(KERN_ERR"%s: no mem, send failed: %d\n", __FUNCTION__, rc);
-+ network_private->stats.tx_errors++;
-+ network_private->stats.tx_fifo_errors++;
-+ netif_wake_queue (net_device);
-+ break;
-+
-+ case -ECOMM:
-+ printk(KERN_ERR"%s: comm failure, send failed: %d %p\n", __FUNCTION__, rc, net_device);
-+ network_private->stats.tx_dropped++;
-+ break;
-+
-+ }
-+ dev_kfree_skb_any (skb);
-+ //rc = NET_XMIT_DROP; XXX this is what we should do, blows up on some 2.4.20 kernels
-+ rc = 0;
-+ break;
-+ }
-+
-+ // XXX should we restart network queue
-+ //printk(KERN_INFO"%s: OK: %d\n", __FUNCTION__, rc);
-+ network_private->stats.tx_packets++;
-+ network_private->stats.tx_bytes += len;
-+
-+ if ((network_private->queued_entries < network_private->max_queue_entries) &&
-+ (network_private->queued_bytes < network_private->max_queue_bytes))
-+ netif_wake_queue (net_device);
-+
-+ CATCH(not_ok) {
-+ dev_kfree_skb_any (skb);
-+ network_private->stats.tx_dropped++;
-+ //netif_stop_queue(net_device); // XXX
-+ //rc = NET_XMIT_DROP; XXX this is what we should do, blows up on some 2.4.20 kernels
-+ rc = 0;
-+ break;
-+ }
-+
-+ } while (0);
-+ up(&usbd_network_sem);
-+ return rc;
-+}
-+
-+
-+/* network_do_ioctl - perform an ioctl call
-+ *
-+ * Carries out IOCTL commands for the specified network device.
-+ *
-+ * rp Points to an ifreq structure containing the IOCTL parameter(s).
-+ * cmd The IOCTL command.
-+ *
-+ * Returns non-zero for failure.
-+ */
-+static int network_do_ioctl (struct net_device *net_device, struct ifreq *rp, int cmd)
-+{
-+ return -ENOIOCTLCMD;
-+}
-+
-+//_________________________________________________________________________________________________
-+
-+struct net_device Network_net_device = {
-+ get_stats: network_get_stats,
-+ tx_timeout: network_tx_timeout,
-+ do_ioctl: network_do_ioctl,
-+ set_config: network_set_config,
-+ set_mac_address: network_set_mac_addr,
-+ hard_start_xmit: network_hard_start_xmit,
-+ change_mtu: network_change_mtu,
-+ init: network_init,
-+ uninit: network_uninit,
-+ open: network_open,
-+ stop: network_stop,
-+ priv: &Usb_network_private,
-+};
-+
-+//_________________________________________________________________________________________________
-+
-+
-+/* network_recv - function to process an received data URB
-+ *
-+ * Passes received data to the network layer. Passes skb to network layer.
-+ *
-+ * Returns non-zero for failure.
-+ */
-+static __inline__ int network_recv (struct usb_network_private *network_private,
-+ struct net_device *net_device, struct sk_buff *skb)
-+{
-+ int rc;
-+#if 0
-+ printk(KERN_INFO"%s: len: %x head: %p data: %p tail: %p\n", __FUNCTION__,
-+ skb->len, skb->head, skb->data, skb->tail);
-+ {
-+ __u8 *cp = skb->data;
-+ int i;
-+ for (i = 0; i < skb->len; i++) {
-+ if ((i%32) == 0) {
-+ printk("\nrx[%2x] ", i);
-+ }
-+ printk("%02x ", *cp++);
-+ }
-+ printk("\n");
-+ }
-+#endif
-+
-+ // refuse if no device present
-+ if (!netif_device_present (net_device)) {
-+ printk(KERN_INFO"%s: device not present\n", __FUNCTION__);
-+ return -EINVAL;
-+ }
-+
-+ // refuse if no carrier
-+ if (!netif_carrier_ok (net_device)) {
-+ printk(KERN_INFO"%s: no carrier\n", __FUNCTION__);
-+ return -EINVAL;
-+ }
-+
-+ // refuse if the net device is down
-+ if (!(net_device->flags & IFF_UP)) {
-+ //printk(KERN_INFO"%s: not up net_dev->flags: %x\n", __FUNCTION__, net_device->flags);
-+ network_private->stats.rx_dropped++;
-+ return -EINVAL;
-+ }
-+
-+ skb->dev = net_device;
-+ skb->pkt_type = PACKET_HOST;
-+ skb->protocol = eth_type_trans (skb, net_device);
-+ skb->ip_summed = CHECKSUM_UNNECESSARY;
-+
-+ //printk(KERN_INFO"%s: len: %x head: %p data: %p tail: %p\n", __FUNCTION__,
-+ // skb->len, skb->head, skb->data, skb->tail);
-+
-+
-+ // pass it up to kernel networking layer
-+ if ((rc = netif_rx (skb))) {
-+ //printk(KERN_INFO"%s: netif_rx rc: %d\n", __FUNCTION__, rc);
-+ }
-+ network_private->stats.rx_bytes += skb->len;
-+ network_private->stats.rx_packets++;
-+
-+ return 0;
-+}
-+
-+//_________________________________________________________________________________________________
-+
-+/* network_recv_urb - callback to process a received URB
-+ *
-+ * Returns non-zero for failure.
-+ */
-+static int network_recv_urb (struct urb *urb, int rc)
-+{
-+ struct net_device *net_device;
-+ struct usb_network_private *network_private = &Usb_network_private;
-+ struct usb_function_instance *function = network_private->function;
-+
-+ struct sk_buff *skb = NULL;
-+ int out_pkt_sz;
-+
-+ RETURN_EINVAL_IF(!(network_private->flags & NETWORK_ATTACHED));
-+ RETURN_EINVAL_IF(!(net_device = &Network_net_device));
-+
-+ out_pkt_sz = usbd_endpoint_wMaxPacketSize(function, BULK_OUT, usbd_high_speed(function));
-+
-+#if 0
-+ printk(KERN_INFO"%s: urb: %p len: %d maxtransfer: %d encap: %d\n", __FUNCTION__,
-+ urb, urb->actual_length, network_private->maxtransfer, network_private->encapsulation);
-+
-+ {
-+ __u8 *cp = urb->buffer;
-+ int i;
-+ for (i = 0; i < urb->actual_length; i++) {
-+ if ((i%32) == 0) {
-+ printk("\n[%2x] ", i);
-+ }
-+ printk("%02x ", *cp++);
-+ }
-+ printk("\n");
-+ }
-+#endif
-+
-+ THROW_IF(urb->status != RECV_OK, error);
-+
-+ // Is CDC active (we have received CONTROL WRITE setup packets indicating real CDC host)
-+ switch (network_private->encapsulation) {
-+ int len;
-+ case simple_crc:
-+
-+ len = urb->actual_length;
-+
-+ // allocate skb of appropriate length, reserve 2 to align ip
-+ THROW_IF(!(skb = dev_alloc_skb (len + 2)), error);
-+ skb_reserve(skb, 2);
-+
-+#if defined(CONFIG_USBD_NETWORK_BLAN_PADAFTER)
-+ {
-+ /* This version simply checks for a correct CRC along the
-+ * entire packet. Some UDC's have trouble with some packet
-+ * sizes, this allows us to add pad bytes after the CRC.
-+ */
-+
-+ u8 *dst = skb_put(skb, len - 1);
-+ u8 *src = urb->buffer;
-+ int copied;
-+ u32 crc;
-+
-+ // XXX this should work, but the MIPS optimizer seems to get it wrong....
-+ //copied = (len < out_pkt_sz) ? 0 : ((len / out_pkt_sz) - 1) * out_pkt_sz;
-+
-+ if (len < out_pkt_sz*2)
-+ copied = 0;
-+ else {
-+ int pkts = ((len - out_pkt_sz) / out_pkt_sz);
-+ copied = (pkts - 1) * out_pkt_sz;
-+ }
-+
-+ len -= copied;
-+ crc = CRC32_INIT;
-+ for (; copied-- > 0 ; crc = COMPUTE_FCS (crc, *dst++ = *src++));
-+
-+ for (; (len-- > 0) && (CRC32_GOOD != crc); crc = COMPUTE_FCS (crc, *dst++ = *src++));
-+
-+ skb_trim(skb, skb->len - len - 4);
-+
-+ if (CRC32_GOOD != crc) {
-+ //printk(KERN_INFO"%s: AAA frame: %03x\n", __FUNCTION__, urb->framenum);
-+ THROW_IF(network_private->crc, crc_error);
-+ }
-+ else
-+ network_private->crc = 1;
-+ }
-+#else
-+ /*
-+ * The CRC can be sent in two ways when the size of the transfer
-+ * ends up being a multiple of the packetsize:
-+ *
-+ * |
-+ * <data> <CRC><CRC><CRC><CRC>|<???> case 1
-+ * <data> <NUL><CRC><CRC><CRC>|<CRC> case 2
-+ * <data> <NUL><CRC><CRC><CRC><CRC>| case 3
-+ * <data> <NUL><CRC><CRC><CRC>|<CRC> | case 4
-+ * |
-+ *
-+ * This complicates CRC checking, there are four scenarios:
-+ *
-+ * 1. length is 1 more than multiple of packetsize with a trailing byte
-+ * 2. length is 1 more than multiple of packetsize
-+ * 3. length is multiple of packetsize
-+ * 4. none of the above
-+ *
-+ * Finally, even though we always compute CRC, we do not actually throw
-+ * things away until and unless we have previously seen a good CRC.
-+ * This allows backwards compatibility with hosts that do not support
-+ * adding a CRC to the frame.
-+ *
-+ */
-+
-+ // test if 1 more than packetsize multiple
-+ if (1 == (len % out_pkt_sz)) {
-+
-+ // copy and CRC up to the packetsize boundary
-+ u32 crc = crc32_copy(skb_put(skb, len - 1), urb->buffer, len - 1, CRC32_INIT);
-+
-+ // if the CRC is good then this is case 1
-+ if (CRC32_GOOD != crc) {
-+
-+ crc = crc32_copy(skb_put(skb, 1), urb->buffer + len - 1, 1, crc);
-+
-+ if (CRC32_GOOD != crc) {
-+ //crc_errors[len%64]++;
-+ printk(KERN_INFO"%s: A CRC error %08x %03x\n", __FUNCTION__, crc, urb->framenum);
-+ THROW_IF(network_private->crc, crc_error);
-+ }
-+ else
-+ network_private->crc = 1;
-+ }
-+ else
-+ network_private->crc = 1;
-+ }
-+ else {
-+ u32 crc = crc32_copy(skb_put(skb, len), urb->buffer, len, CRC32_INIT);
-+
-+ if (CRC32_GOOD != crc) {
-+ //crc_errors[len%64]++;
-+ //printk(KERN_INFO"%s: CCC\n", __FUNCTION__);
-+ THROW_IF(network_private->crc, crc_error);
-+ }
-+ else
-+ network_private->crc = 1;
-+ }
-+ // trim IFF we are paying attention to crc
-+ if (network_private->crc)
-+ skb_trim(skb, skb->len - 4);
-+#endif
-+
-+ // pass it up, free skb if non zero
-+ THROW_IF(network_recv (network_private, net_device, skb), skb_error);
-+
-+ break;
-+ default:
-+ break;
-+ }
-+
-+ // catch a simple error, just increment missed error and general error
-+ CATCH(error) {
-+
-+ network_private->stats.rx_frame_errors++;
-+ network_private->stats.rx_errors++;
-+
-+ // catch error where skb may need to be released
-+ CATCH(skb_error) {
-+
-+ // catch a CRC error
-+
-+ // XXX We need to track whether we have seen a correct CRC, until then
-+ // we ignore CRC errors.
-+
-+ CATCH(crc_error) {
-+#if 0
-+ printk(KERN_INFO"%s: urb: %p status: %d len: %d maxtransfer: %d encap: %d\n", __FUNCTION__,
-+ urb, urb->status, urb->actual_length, network_private->maxtransfer,
-+ network_private->encapsulation);
-+
-+ {
-+ __u8 *cp = urb->buffer;
-+ int i;
-+ for (i = 0; i < urb->actual_length; i++) {
-+ if ((i%32) == 0) {
-+ printk("\n[%2x] ", i);
-+ }
-+ printk("%02x ", *cp++);
-+ }
-+ printk("\n");
-+ }
-+#endif
-+ network_private->stats.rx_crc_errors++;
-+ network_private->stats.rx_errors++;
-+ }
-+
-+ // catch an overrun error
-+ // (Only used if CONFIG_USBD_NETWORK_CDC is defined.)
-+ //CATCH(fifo_error) {
-+ // network_private->stats.rx_fifo_errors++;
-+ // network_private->stats.rx_errors++;
-+ //}
-+
-+ // if skb defined free it
-+ if (skb)
-+ dev_kfree_skb_any (skb);
-+ }
-+ network_private->stats.rx_dropped++;
-+ //return -EINVAL;
-+ }
-+ //printk(KERN_INFO"%s: restart: %p\n", __FUNCTION__, urb);
-+ return (usbd_start_recv (urb));
-+}
-+
-+//_________________________________________________________________________________________________
-+// network_urb_sent
-+
-+/* network_urb_sent_bulk - callback function to process a sent URB
-+ *
-+ * Handles notification that an urb has been sent (successfully or otherwise).
-+ *
-+ * urb Pointer to the urb that has been sent.
-+ * rc Result code from the send operation.
-+ *
-+ * Returns non-zero for failure.
-+ */
-+static int network_urb_sent_bulk (struct urb *urb, int urb_rc)
-+{
-+ struct sk_buff *skb;
-+ struct net_device *net_device;
-+ unsigned long flags;
-+ struct usb_network_private *network_private = &Usb_network_private;
-+ struct usb_function_instance *function = network_private->function;
-+ int rc = -EINVAL;
-+
-+ //printk(KERN_INFO"%s: urb: %p device: %p address: %x urb_rc: %d\n", __FUNCTION__,
-+ // urb, urb->device, urb->endpoint->bEndpointAddress, urb_rc);
-+
-+ local_irq_save(flags);
-+ do {
-+
-+ BREAK_IF(!urb);
-+ BREAK_IF(!(function = urb->function_instance));
-+
-+ switch (urb_rc) {
-+ case SEND_FINISHED_ERROR:
-+ network_private->stats.tx_errors++;
-+ network_private->stats.tx_dropped++;
-+ break;
-+ case SEND_FINISHED_CANCELLED:
-+ network_private->stats.tx_errors++;
-+ network_private->stats.tx_carrier_errors++;
-+ break;
-+ default:
-+ break;
-+ }
-+
-+ // XXX should we zap skb first if error?
-+ RETURN_EINVAL_IF(!(network_private->flags & NETWORK_CREATED));
-+
-+ // retrieve skb pointer and unlink from urb pointers
-+ skb = (struct sk_buff *) urb->privdata;
-+
-+ urb->privdata = NULL;
-+ usbd_dealloc_urb (urb);
-+
-+ // tell netproto we are done with the skb, it will test for NULL
-+ // netproto_done (interface, skb, urb_rc != SEND_FINISHED_OK);
-+
-+ BREAK_IF(!skb);
-+ BREAK_IF(!(net_device = &Network_net_device));
-+
-+
-+ network_private->avg_queue_entries += network_private->queued_entries;
-+ network_private->queued_entries--;
-+ network_private->samples++;
-+ network_private->jiffies += jiffies - *(time_t *) (&skb->cb);
-+ network_private->queued_bytes -= skb->len;
-+
-+ dev_kfree_skb_any (skb);
-+
-+ if (netif_queue_stopped (net_device)) {
-+ netif_wake_queue (net_device);
-+ network_private->restarts++;
-+ }
-+ rc = 0;
-+
-+ } while (0);
-+ local_irq_restore(flags);
-+ return rc;
-+}
-+
-+/* network_urb_sent_int - callback for sent URB
-+ *
-+ * Handles notification that an urb has been sent (successfully or otherwise).
-+ *
-+ * Returns non-zero for failure.
-+ */
-+static int network_urb_sent_int (struct urb *urb, int urb_rc)
-+{
-+ struct usb_function_instance *function;
-+ struct sk_buff *skb;
-+ struct net_device *net_device;
-+ unsigned long flags;
-+ int rc = -EINVAL;
-+ struct usb_network_private *network_private = &Usb_network_private;
-+
-+ //printk(KERN_INFO"%s: urb: %p device: %p address: %x urb_rc: %d\n", __FUNCTION__,
-+ // urb, urb->device, urb->endpoint->bEndpointAddress, urb_rc);
-+
-+ local_irq_save(flags);
-+ do {
-+
-+ BREAK_IF(!urb);
-+ BREAK_IF(!(function = urb->function_instance));
-+ //RETURN_EINVAL_IF(!(network_private->flags & NETWORK_ATTACHED));
-+
-+ //printk(KERN_INFO"%s: reseting int_urb: %p\n", __FUNCTION__, network_private->int_urb);
-+ usbd_dealloc_urb (urb);
-+ network_private->int_urb = NULL;
-+ rc = 0;
-+
-+ } while (0);
-+ local_irq_restore(flags);
-+ return rc;
-+}
-+
-+
-+//_________________________________________________________________________________________________
-+// network_recv_setup_irq
-+//
-+/* network_urb_received_ep0 - callback for sent URB
-+ *
-+ * Handles notification that an urb has been sent (successfully or otherwise).
-+ *
-+ * Returns non-zero for failure.
-+ */
-+static int network_urb_received_ep0 (struct urb *urb, int urb_rc)
-+{
-+ printk(KERN_INFO"%s: urb: %p status: %d\n", __FUNCTION__, urb, urb->status);
-+
-+ RETURN_EINVAL_IF (RECV_OK != urb->status);
-+
-+ printk(KERN_INFO"%s: %s\n", __FUNCTION__, urb->buffer);
-+
-+ return -EINVAL; // caller will de-allocate
-+}
-+
-+/* network_recv_setup_irq - process a received SETUP URB
-+ *
-+ * Processes a received setup packet and CONTROL WRITE data.
-+ * Results for a CONTROL READ are placed in urb->buffer.
-+ *
-+ * Returns non-zero for failure.
-+ */
-+static int network_recv_setup_irq (struct usb_device_request *request)
-+{
-+ struct usb_network_private *network_private = &Usb_network_private;
-+ struct usb_function_instance *function = network_private->function;
-+ struct urb *urb;
-+
-+
-+ // Verify that this is a USB Class request per CDC specification or a vendor request.
-+ RETURN_ZERO_IF (!(request->bmRequestType & (USB_REQ_TYPE_CLASS | USB_REQ_TYPE_VENDOR)));
-+
-+ // Determine the request direction and process accordingly
-+ switch (request->bmRequestType & (USB_REQ_DIRECTION_MASK | USB_REQ_TYPE_MASK)) {
-+
-+ case USB_REQ_HOST2DEVICE | USB_REQ_TYPE_VENDOR:
-+
-+ switch (request->bRequest) {
-+ case MCCI_ENABLE_CRC:
-+ if (make_crc_table())
-+ return -EINVAL;
-+ network_private->encapsulation = simple_crc;
-+ return 0;
-+
-+ case BELCARRA_PING:
-+ //printk(KERN_INFO"%s: H2D VENDOR IP: %08x\n", __FUNCTION__, ip_addr);
-+ if ((network_private->network_type == network_blan))
-+ notification_schedule_bh();
-+ break;
-+
-+#if !defined(CONFIG_USBD_NETWORK_BLAN_DO_NOT_SETTIME) || !defined(CONFIG_USBD_NETWORK_SAFE_DO_NOT_SETTIME)
-+ case BELCARRA_SETTIME:
-+ {
-+ struct timeval tv;
-+
-+ // wIndex and wLength contain RFC868 time - seconds since midnight 1 jan 1900
-+
-+ tv.tv_sec = ntohl( request->wValue << 16 | request->wIndex);
-+ tv.tv_usec = 0;
-+
-+ // convert to Unix time - seconds since midnight 1 jan 1970
-+
-+ tv.tv_sec -= RFC868_OFFSET_TO_EPOCH;
-+
-+ //printk(KERN_INFO"%s: H2D VENDOR TIME: %08x\n", __FUNCTION__, tv.tv_sec);
-+
-+ // set the time
-+ do_settimeofday(&tv);
-+ } break;
-+#endif
-+ case BELCARRA_SETIP:
-+ ip_addr = ntohl( request->wValue << 16 | request->wIndex);
-+ break;
-+
-+ case BELCARRA_SETMSK:
-+ network_mask = ntohl( request->wValue << 16 | request->wIndex);
-+ break;
-+
-+ case BELCARRA_SETROUTER:
-+ router_ip = ntohl( request->wValue << 16 | request->wIndex);
-+ break;
-+
-+ case BELCARRA_SETDNS:
-+ dns_server_ip = ntohl( request->wValue << 16 | request->wIndex);
-+ break;
-+#ifdef CONFIG_USBD_NETWORK_BLAN_FERMAT
-+ case BELCARRA_SETFERMAT:
-+ network_private->fermat = 1;
-+ break;
-+#endif
-+#ifdef CONFIG_USBD_NETWORK_BLAN_HOSTNAME
-+ case BELCARRA_HOSTNAME:
-+ //printk(KERN_INFO"%s: HOSTNAME\n", __FUNCTION__);
-+ RETURN_EINVAL_IF(!(urb = usbd_alloc_urb_ep0(function, le16_to_cpu(request->wLength),
-+ network_urb_received_ep0) ));
-+ RETURN_ZERO_IF(!usbd_start_recv(urb)); // return if no error
-+ usbd_dealloc_urb(urb); // de-alloc if error
-+ return -EINVAL;
-+#endif
-+ }
-+ return 0;
-+#if 0
-+ case USB_REQ_DEVICE2HOST | USB_REQ_TYPE_VENDOR:
-+ urb->actual_length = 0;
-+ switch (request->bRequest) {
-+ case BELCARRA_GETMAC:
-+ {
-+ // copy and free the original buffer
-+ memcpy(urb->buffer, Network_net_device.dev_addr, ETH_ALEN);
-+ urb->actual_length = ETH_ALEN;
-+ return 0;
-+ }
-+ }
-+#endif
-+ return 0;
-+ default:
-+ break;
-+ }
-+ return -EINVAL;
-+}
-+
-+//______________________________________ Hotplug Functions ________________________________________
-+
-+#ifdef CONFIG_HOTPLUG
-+
-+#define AGENT "network_fd"
-+
-+/* hotplug_attach - call hotplug
-+ */
-+static int hotplug_attach (__u32 ip, __u32 mask, __u32 router, int attach)
-+{
-+ static int count = 0;
-+ char *argv[3];
-+ char *envp[10];
-+ char ifname[20+12 + IFNAMSIZ];
-+ int i;
-+ char count_str[20];
-+
-+ RETURN_EINVAL_IF(!hotplug_path[0]);
-+
-+ argv[0] = hotplug_path;
-+ argv[1] = AGENT;
-+ argv[2] = 0;
-+
-+ sprintf (ifname, "INTERFACE=%s", Network_net_device.name);
-+ sprintf (count_str, "COUNT=%d", count++);
-+
-+ i = 0;
-+ envp[i++] = "HOME=/";
-+ envp[i++] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";
-+ envp[i++] = ifname;
-+
-+
-+ if (attach) {
-+ unsigned char *cp;
-+ char ip_str[20+32];
-+ char mask_str[20+32];
-+ char router_str[20+32];
-+ __u32 nh;
-+
-+ nh = htonl(ip);
-+ cp = (unsigned char*) &nh;
-+ sprintf (ip_str, "IP=%d.%d.%d.%d", cp[0], cp[1], cp[2], cp[3]);
-+
-+ nh = htonl(mask);
-+ cp = (unsigned char*) &nh;
-+ sprintf (mask_str, "MASK=%d.%d.%d.%d", cp[0], cp[1], cp[2], cp[3]);
-+
-+ nh = htonl(router);
-+ cp = (unsigned char*) &nh;
-+ sprintf (router_str, "ROUTER=%d.%d.%d.%d", cp[0], cp[1], cp[2], cp[3]);
-+
-+ //printk (KERN_INFO "%s: attach %s %s %s\n", __FUNCTION__, ifname, ip_str, count_str);
-+
-+ envp[i++] = "ACTION=attach";
-+ envp[i++] = ip_str;
-+ envp[i++] = mask_str;
-+ envp[i++] = router_str;
-+ }
-+ else {
-+ //printk (KERN_INFO "%s: detach %s %s\n", __FUNCTION__, ifname, count_str);
-+ envp[i++] = "ACTION=detach";
-+ }
-+
-+ envp[i++] = count_str;
-+ envp[i++] = 0;
-+
-+ return call_usermodehelper (argv[0], argv, envp);
-+}
-+
-+
-+/* hotplug_bh - bottom half handler to call hotplug script to signal ATTACH or DETACH
-+ *
-+ * Check connected status and load/unload as appropriate.
-+ *
-+ * It should not be possible for this to be called more than once at a time
-+ * as it is only called via schedule_task() which protects against a second
-+ * invocation.
-+ */
-+static void hotplug_bh (void *data)
-+{
-+ struct usb_network_private *network_private = &Usb_network_private;
-+ struct usb_function_instance *function = network_private->function;
-+
-+ //printk(KERN_INFO"%s: BUS state: %d status: %d\n", __FUNCTION__, usbd_device_state(function), usbd_bus_status(function));
-+
-+ if (function && (USBD_OK == usbd_bus_status(function)) && (STATE_CONFIGURED == usbd_device_state(function))) {
-+ if (hotplug_attached != network_private->hotplug_status) {
-+ //printk(KERN_INFO"%s: ATTACH\n", __FUNCTION__);
-+ network_private->hotplug_status = hotplug_attached;
-+ hotplug_attach (ip_addr, network_mask, router_ip, 1);
-+ }
-+ }
-+ else {
-+ if (hotplug_detached != network_private->hotplug_status) {
-+ //printk(KERN_INFO"%s: DETACH\n", __FUNCTION__);
-+ network_private->hotplug_status = hotplug_detached;
-+ hotplug_attach (ip_addr, network_mask, router_ip, 0);
-+ }
-+ }
-+ MOD_DEC_USE_COUNT;
-+}
-+
-+/* hotplug_schedule_bh - schedule a call to hotplug bottom half
-+ */
-+static void hotplug_schedule_bh (void)
-+{
-+ MOD_INC_USE_COUNT;
-+ if (!schedule_task (&Usb_network_private.hotplug_bh))
-+ MOD_DEC_USE_COUNT;
-+}
-+#endif /* CONFIG_HOTPLUG */
-+
-+
-+//_________________________________________________________________________________________________
-+
-+#ifdef CONFIG_USBD_NETWORK_START_SINGLE
-+#define NETWORK_START_URBS 1
-+#else
-+#define NETWORK_START_URBS 2
-+#endif
-+
-+/* network_start_recv - start recv urb(s)
-+ */
-+void network_start_recv(struct usb_function_instance *function)
-+{
-+ int i;
-+ for (i = 0; i < NETWORK_START_URBS; i++) {
-+ struct urb *urb;
-+ BREAK_IF(!(urb = usbd_alloc_urb (function, BULK_OUT,
-+ usbd_endpoint_transferSize(function, BULK_OUT, usbd_high_speed(function)),
-+ network_recv_urb)));
-+ //printk(KERN_INFO"%s: i: %d start: %p\n", __FUNCTION__, i, urb);
-+ if (usbd_start_recv(urb))
-+ usbd_dealloc_urb(urb);
-+ }
-+}
-+
-+/* network_event_irg - Processes a USB event.
-+ */
-+static void network_event_irq (struct usb_function_instance *function, usb_device_event_t event, int data)
-+{
-+ struct usb_network_private *network_private = &Usb_network_private;
-+
-+ switch (event) {
-+
-+ case DEVICE_RESET:
-+ case DEVICE_DESTROY:
-+ case DEVICE_BUS_INACTIVE:
-+ //printk(KERN_INFO"%s: RST %x\n", __FUNCTION__, ip_addr);
-+ {
-+ //printk(KERN_INFO"%s:\n", __FUNCTION__);
-+ // Return if argument is null.
-+
-+ // XXX flush
-+
-+ network_private->flags &= ~NETWORK_ATTACHED;
-+ network_private->int_urb = NULL;
-+
-+ // Disable our net-device.
-+ // Apparently it doesn't matter if we should do this more than once.
-+
-+ netif_stop_queue(&Network_net_device);
-+ netif_carrier_off(&Network_net_device);
-+
-+ // If we aren't already tearing things down, do it now.
-+ if (!(network_private->flags & NETWORK_DESTROYING)) {
-+ network_private->flags |= NETWORK_DESTROYING;
-+ //network_private->device = NULL;
-+ }
-+ }
-+ break;
-+
-+ case DEVICE_CONFIGURED:
-+ case DEVICE_BUS_ACTIVITY:
-+ //printk(KERN_INFO"%s: CFG %x\n", __FUNCTION__, ip_addr);
-+ network_private->flags |= NETWORK_ATTACHED;
-+
-+ if ((network_private->network_type == network_blan) && (network_private->flags & NETWORK_OPEN))
-+ notification_schedule_bh();
-+
-+ netif_carrier_on (&Network_net_device);
-+ netif_wake_queue (&Network_net_device);
-+
-+ network_start_recv(function);
-+
-+#ifdef CONFIG_USBD_NET_NFS_SUPPORT
-+ if (!usb_is_configured) {
-+ wake_up(&usb_netif_wq);
-+ usb_is_configured = 1;
-+ }
-+#endif
-+ break;
-+
-+ case DEVICE_SET_INTERFACE:
-+ // XXX if CDC then we can check device->alternates[1] and see if we should
-+ // enable/disable data flow.
-+ // XXX verify ep0.c SET_CONFIGURATION and SET_INTERFACE implmentation are
-+ // complete before using this
-+ break;
-+
-+ default:
-+ return;
-+ }
-+#ifdef CONFIG_HOTPLUG
-+ hotplug_schedule_bh();
-+#endif
-+}
-+
-+//_________________________________________________________________________________________________
-+
-+/* network_function_enable - enable the function driver
-+ *
-+ * Called for usbd_function_enable() from usbd_register_device()
-+ */
-+
-+static int network_function_enable (struct usb_function_instance *function)
-+{
-+ //printk(KERN_INFO"%s: DOWN\n", __FUNCTION__);
-+ down(&usbd_network_sem);
-+ MOD_INC_USE_COUNT; // QQQ Should this be _before_ the down()?
-+
-+ // set the network device address from the local device address
-+ memcpy(Network_net_device.dev_addr, local_dev_addr, ETH_ALEN);
-+
-+ //Usb_network_private.bus = function->bus;
-+ Usb_network_private.function = function;
-+ Usb_network_private.have_interrupt = usbd_endpoint_bEndpointAddress(function, INT_IN, usbd_high_speed(function)) ? 1 : 0;
-+
-+ Usb_network_private.flags |= NETWORK_ENABLED;
-+
-+#if defined(CONFIG_USBD_NETWORK_CDC)
-+ cdc_init(function);
-+#endif /* CONFIG_USBD_NETWORK_CDC */
-+
-+#ifdef CONFIG_USBD_NETWORK_BASIC
-+ basic_init(function);
-+#endif
-+
-+#ifdef CONFIG_USBD_NETWORK_BASIC2
-+ basic2_init(function);
-+#endif
-+
-+#ifdef CONFIG_USBD_NETWORK_SAFE
-+ safe_init(function);
-+#endif
-+#ifdef CONFIG_USBD_NETWORK_BLAN
-+ blan_init(function);
-+#endif
-+ up(&usbd_network_sem);
-+ //printk(KERN_INFO"%s: UP\n", __FUNCTION__);
-+ return 0;
-+}
-+
-+/* network_functino_disable - disable the function driver
-+ *
-+ */
-+static void network_function_disable (struct usb_function_instance *function)
-+{
-+ //printk(KERN_INFO"%s: DOWN\n", __FUNCTION__);
-+ down(&usbd_network_sem);
-+ Usb_network_private.flags &= ~NETWORK_ENABLED;
-+ //Usb_network_private.bus = NULL;
-+ Usb_network_private.function = NULL;
-+ MOD_DEC_USE_COUNT; // QQQ Should this be _after_ the up()?
-+ up(&usbd_network_sem);
-+ //printk(KERN_INFO"%s: UP\n", __FUNCTION__);
-+}
-+
-+struct usb_function_operations network_fd_function_ops = {
-+ recv_setup_irq: network_recv_setup_irq,
-+ event_irq: network_event_irq,
-+ function_enable: network_function_enable,
-+ function_disable: network_function_disable,
-+};
-+
-+//_________________________________________________________________________________________________
-+
-+/* network_create - create and initialize network private structure
-+ *
-+ * Returns non-zero for failure.
-+ */
-+static int network_create (void)
-+{
-+ struct usb_network_private *network_private = &Usb_network_private;
-+
-+ //printk(KERN_INFO"%s:\n", __FUNCTION__);
-+
-+ // Set some fields to generic defaults and register the network device with the kernel networking code
-+
-+ memset(&network_private->stats, 0, sizeof network_private->stats);
-+
-+ ether_setup (&Network_net_device);
-+ RETURN_EINVAL_IF (register_netdev(&Network_net_device));
-+
-+ netif_stop_queue (&Network_net_device);
-+ netif_carrier_off (&Network_net_device);
-+ Network_net_device.flags &= ~IFF_UP;
-+
-+ network_private->flags |= NETWORK_CREATED;
-+
-+ network_private->maxtransfer = MAXFRAMESIZE + 4 + 64;
-+
-+ network_private->flags |= NETWORK_REGISTERED;
-+
-+ network_private->network_type = network_unknown;
-+
-+ //printk(KERN_INFO"%s: finis\n", __FUNCTION__);
-+ return 0;
-+}
-+
-+/* network_destroy - destroy network private struture
-+ *
-+ * Destroys the network interface referenced by the global variable @c network_private.
-+ */
-+static void network_destroy (void)
-+{
-+ if (Usb_network_private.flags & NETWORK_REGISTERED) {
-+ netif_stop_queue (&Network_net_device);
-+ netif_carrier_off (&Network_net_device);
-+ unregister_netdev (&Network_net_device);
-+ }
-+ Usb_network_private.flags = 0;
-+}
-+
-+
-+//______________________________________module_init and module_exit________________________________
-+
-+/* hexdigit -
-+ *
-+ * Converts characters in [0-9A-F] to 0..15, characters in [a-f] to 42..47, and all others to 0.
-+ */
-+static __u8 hexdigit (char c)
-+{
-+ return isxdigit (c) ? (isdigit (c) ? (c - '0') : (c - 'A' + 10)) : 0;
-+}
-+
-+/* set_address -
-+ */
-+void set_address(char *mac_address_str, __u8 *dev_addr)
-+{
-+ int i;
-+ if (mac_address_str && strlen(mac_address_str)) {
-+ for (i = 0; i < ETH_ALEN; i++) {
-+ dev_addr[i] =
-+ hexdigit (mac_address_str[i * 2]) << 4 |
-+ hexdigit (mac_address_str[i * 2 + 1]);
-+ }
-+ }
-+ else {
-+ get_random_bytes(dev_addr, ETH_ALEN);
-+ dev_addr[0] = (dev_addr[0] & 0xfe) | 0x02;
-+ }
-+}
-+
-+/* macstrtest -
-+ */
-+int macstrtest(char *mac_address_str)
-+{
-+ int l = 0;
-+
-+ if (mac_address_str) {
-+ l = strlen(mac_address_str);
-+ }
-+ return ((l != 0) && (l != 12));
-+}
-+
-+/* network_modinit - driver intialization
-+ *
-+ * Returns non-zero for failure.
-+ */
-+static int network_modinit (void)
-+{
-+ network_type_t network_type = network_unknown;
-+
-+ init_waitqueue_head(&usb_netif_wq);
-+
-+
-+ printk(KERN_INFO "Copyright (c) 2002-2004 Belcarra Technologies; www.belcarra.com; sl@belcarra.com\n");
-+ printk(KERN_INFO "%s: %s vendor_id: %04x product_id: %04x\n", __FUNCTION__, __usbd_module_info, vendor_id, product_id);
-+
-+#ifdef CONFIG_USBD_NETWORK_BLAN_FERMAT
-+ //printk(KERN_INFO "%s: fermat\n", __FUNCTION__);
-+ fermat_init();
-+#endif
-+
-+#if defined(CONFIG_USBD_NETWORK_CDC)
-+ if (cdc) {
-+ //printk(KERN_INFO "%s: cdc\n", __FUNCTION__);
-+ network_type = network_cdc;
-+ }
-+#endif
-+
-+#ifdef CONFIG_USBD_NETWORK_BASIC
-+ if (basic) {
-+ THROW_IF (network_type != network_unknown, select_error);
-+ //printk(KERN_INFO "%s: basic\n", __FUNCTION__);
-+ network_type = network_basic;
-+ }
-+#endif
-+
-+#ifdef CONFIG_USBD_NETWORK_BASIC2
-+ if (basic2) {
-+ THROW_IF (network_type != network_unknown, select_error);
-+ //printk(KERN_INFO "%s: basic2\n", __FUNCTION__);
-+ network_type = network_basic2;
-+ }
-+#endif
-+
-+#ifdef CONFIG_USBD_NETWORK_BLAN
-+ if (blan) {
-+ //printk(KERN_INFO "%s: blan\n", __FUNCTION__);
-+ THROW_IF (network_type != network_unknown, select_error);
-+ network_type = network_blan;
-+ }
-+#endif
-+
-+#if defined(CONFIG_USBD_NETWORK_CDC)
-+ if (network_type == network_unknown) {
-+ //printk(KERN_INFO "%s: cdc\n", __FUNCTION__);
-+ network_type = network_cdc;
-+ }
-+#endif
-+
-+ // still unknown - check for other bNumConfigurations
-+
-+ if (network_type == network_unknown) {
-+#if defined(CONFIG_USBD_NETWORK_BASIC)
-+ //printk(KERN_INFO "%s: basic\n", __FUNCTION__);
-+ THROW_IF (network_type != network_unknown, select_error);
-+ network_type = network_basic;
-+#endif
-+#if defined(CONFIG_USBD_NETWORK_BASIC2)
-+ //printk(KERN_INFO "%s: basic2\n", __FUNCTION__);
-+ THROW_IF (network_type != network_unknown, select_error);
-+ network_type = network_basic2;
-+#endif
-+#if defined(CONFIG_USBD_NETWORK_SAFE)
-+ //printk(KERN_INFO "%s: safe\n", __FUNCTION__);
-+ THROW_IF (network_type != network_unknown, select_error);
-+ network_type = network_safe;
-+#endif
-+#if defined(CONFIG_USBD_NETWORK_BLAN)
-+ //printk(KERN_INFO "%s: blan\n", __FUNCTION__);
-+ THROW_IF (network_type != network_unknown, select_error);
-+ network_type = network_blan;
-+#endif
-+ }
-+
-+ // sanity check
-+ THROW_IF (network_type == network_unknown, select_error);
-+
-+ // select the function driver descriptors based on network_type
-+
-+ switch (network_type) {
-+
-+#if defined(CONFIG_USBD_NETWORK_BASIC)
-+ case network_basic:
-+ //printk(KERN_INFO "%s: basic\n", __FUNCTION__);
-+ function_driver = &basic_function_driver;
-+ break;
-+#endif
-+
-+#if defined(CONFIG_USBD_NETWORK_BASIC2)
-+ case network_basic2:
-+ //printk(KERN_INFO "%s: basic2\n", __FUNCTION__);
-+ function_driver = &basic2_function_driver;
-+ break;
-+#endif
-+
-+#if defined(CONFIG_USBD_NETWORK_SAFE)
-+ case network_safe:
-+ //printk(KERN_INFO "%s: blan bNumConfigurations: %d\n", __FUNCTION__, blan_function_driver.bNumConfigurations);
-+ function_driver = &safe_function_driver;
-+ break;
-+#endif
-+#if defined(CONFIG_USBD_NETWORK_BLAN)
-+ case network_blan:
-+ //printk(KERN_INFO "%s: blan bNumConfigurations: %d\n", __FUNCTION__, blan_function_driver.bNumConfigurations);
-+ function_driver = &blan_function_driver;
-+ break;
-+#endif
-+
-+#if defined(CONFIG_USBD_NETWORK_CDC)
-+ case network_cdc:
-+ function_driver = &cdc_function_driver;
-+ break;
-+#endif
-+ default:
-+ THROW(select_error);
-+ break;
-+ }
-+
-+ strncpy(Network_net_device.name, network_type == zeroconf ? "usbz0" : (network_blan ? "usbl0" : "usbb0"), 6);
-+
-+
-+ THROW_IF (!function_driver, select_error);
-+
-+ CATCH(select_error) {
-+ printk(KERN_INFO "%s: configuration selection error\n", __FUNCTION__);
-+ return -EINVAL;
-+ }
-+
-+
-+#ifdef CONFIG_USBD_NETWORK_EP0TEST
-+ /*
-+ * ep0test - test that bus interface can do ZLP on endpoint zero
-+ *
-+ * This will artificially force iProduct string descriptor to be
-+ * exactly the same as the endpoint zero packetsize. When the host
-+ * requests this string it will request it not knowing the strength
-+ * and will use a max length of 0xff. The bus interface driver must
-+ * send a ZLP to terminate the transaction.
-+ *
-+ * The iProduct descriptor is used because both the Linux and
-+ * Windows usb implmentations fetch this in a default enumeration.
-+ *
-+ */
-+ if (ep0test) {
-+ switch (ep0test) {
-+ case 8: function_driver->device_description->iProduct = "012"; break;
-+ case 16: function_driver->device_description->iProduct = "0123456"; break;
-+ case 32: function_driver->device_description->iProduct = "0123456789abcde"; break;
-+ case 64: function_driver->device_description->iProduct = "0123456789abcdef0123456789abcde"; break;
-+ default: printk(KERN_ERR"%s: ep0test: bad value: %d, must be one of 8, 16, 32 or 64\n",
-+ __FUNCTION__, ep0test); return -EINVAL;
-+ break;
-+ }
-+ printk(KERN_INFO"%s: ep0test: iProduct set to: %s\n", __FUNCTION__,
-+ function_driver->device_description->iProduct);
-+ }
-+ else
-+ printk(KERN_INFO"%s: ep0test: not set\n", __FUNCTION__);
-+#endif /* CONFIG_USBD_NETWORK_EP0TEST */
-+
-+
-+#ifdef CONFIG_USBD_NETWORK_ALLOW_SETID
-+ //printk(KERN_INFO"%s: checking idVendor: %04x idProduct: %04x\n", __FUNCTION__, vendor_id, product_id);
-+
-+ if (vendor_id)
-+ function_driver->idVendor = cpu_to_le16(vendor_id);
-+
-+ if (product_id)
-+ function_driver->idProduct = cpu_to_le16(product_id);
-+#endif
-+
-+ if ((macstrtest(local_mac_address_str) || macstrtest(remote_mac_address_str))) {
-+ printk(KERN_INFO"%s: bad size %s %s\n", __FUNCTION__, local_mac_address_str, remote_mac_address_str);
-+ return -EINVAL;
-+ }
-+
-+ set_address(local_mac_address_str, local_dev_addr);
-+ set_address(remote_mac_address_str, remote_dev_addr);
-+
-+ RETURN_EINVAL_IF(network_create());
-+
-+ Usb_network_private.network_type = network_type;
-+
-+ Usb_network_private.notification_bh.routine = notification_bh;
-+ Usb_network_private.notification_bh.data = NULL;
-+
-+#ifdef CONFIG_HOTPLUG
-+ Usb_network_private.hotplug_bh.routine = hotplug_bh;
-+ Usb_network_private.hotplug_bh.data = NULL;
-+#endif
-+
-+ memcpy(Network_net_device.dev_addr, local_dev_addr, ETH_ALEN);
-+
-+ THROW_IF(make_crc_table(), error);
-+
-+ Usb_network_private.encapsulation = simple_crc;
-+
-+ THROW_IF(usbd_register_function (function_driver), error);
-+
-+ return 0;
-+
-+ CATCH(error) {
-+ network_destroy();
-+ return -EINVAL;
-+ }
-+}
-+
-+//_________________________________________________________________________________________________
-+
-+/* network_modexit - driver exit
-+ *
-+ * Cleans up the module. Deregisters the function driver and destroys the network object.
-+ */
-+static void network_modexit (void)
-+{
-+ //printk(KERN_INFO"%s: exiting\n", __FUNCTION__);
-+
-+ while (Usb_network_private.notification_bh.sync) {
-+ printk(KERN_ERR"%s: waiting for notificationhotplug bh\n", __FUNCTION__);
-+ schedule_timeout(10 * HZ);
-+ }
-+
-+#ifdef CONFIG_HOTPLUG
-+ while (Usb_network_private.hotplug_bh.sync) {
-+ printk(KERN_ERR"%s: waiting for hotplug bh\n", __FUNCTION__);
-+ schedule_timeout(10 * HZ);
-+ }
-+#endif
-+
-+ usbd_deregister_function (function_driver);
-+ network_destroy();
-+ if (network_crc32_table) {
-+ lkfree(network_crc32_table);
-+ network_crc32_table = NULL;
-+ }
-+}
-+
-+//_________________________________________________________________________________________________
-+
-+module_init (network_modinit);
-+module_exit (network_modexit);
-+
-diff -Nru a/drivers/usbd/network_fd/network.h b/drivers/usbd/network_fd/network.h
---- /dev/null Wed Dec 31 16:00:00 1969
-+++ b/drivers/usbd/network_fd/network.h Fri Feb 27 14:22:51 2004
-@@ -0,0 +1,203 @@
-+/*
-+ * usbd/network_fd/network.h - Network Function Driver
-+ *
-+ * Copyright (c) 2002, 2003, 2004 Belcarra
-+ *
-+ * By:
-+ * Chris Lynne <cl@belcarra.com>
-+ * Stuart Lynne <sl@belcarra.com>
-+ * Bruce Balden <balden@belcarra.com>
-+ *
-+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
-+ *
-+ */
-+
-+#ifndef NETWORK_FD_H
-+#define NETWORK_FD_H 1
-+
-+typedef enum network_encapsulation {
-+ simple_net, simple_crc,
-+} network_encapsulation_t;
-+
-+typedef enum network_hotplug_status {
-+ hotplug_unkown,
-+ hotplug_attached,
-+ hotplug_detached
-+} network_hotplug_status_t;
-+
-+typedef enum network_type {
-+ network_unknown,
-+ network_blan,
-+ network_safe,
-+ network_cdc,
-+ network_basic,
-+ network_basic2,
-+} network_type_t;
-+
-+struct usb_network_private {
-+
-+ struct net_device_stats stats; /* network device statistics */
-+
-+ int flags;
-+ struct usb_function_instance *function;
-+ unsigned int maxtransfer;
-+ rwlock_t rwlock;
-+
-+ network_hotplug_status_t hotplug_status;
-+ network_type_t network_type;
-+
-+ int state;
-+
-+ int mtu;
-+ int crc;
-+#if defined(CONFIG_USBD_NETWORK_BLAN_FERMAT)
-+ int fermat;
-+#endif
-+
-+ unsigned int stopped;
-+ unsigned int restarts;
-+
-+ unsigned int max_queue_entries;
-+ unsigned int max_queue_bytes;
-+
-+ unsigned int queued_entries;
-+ unsigned int queued_bytes;
-+
-+ time_t avg_queue_entries;
-+
-+ time_t jiffies;
-+ unsigned long samples;
-+
-+ int have_interrupt;
-+
-+ struct urb *int_urb;
-+
-+ network_encapsulation_t encapsulation;
-+
-+ struct tq_struct notification_bh;
-+
-+#ifdef CONFIG_HOTPLUG
-+ struct tq_struct hotplug_bh;
-+#endif
-+};
-+
-+// XXX this needs to be co-ordinated with rndis.c maximum's
-+#define MAXFRAMESIZE 2000
-+
-+#if !defined(CONFIG_USBD_MAXPOWER)
-+ #define CONFIG_USBD_MAXPOWER 0
-+#endif
-+
-+#if !defined(CONFIG_USBD_MANUFACTURER)
-+ #define CONFIG_USBD_MANUFACTURER "Belcarra"
-+#endif
-+
-+
-+#if !defined(CONFIG_USBD_SERIAL_NUMBER_STR)
-+ #define CONFIG_USBD_SERIAL_NUMBER_STR ""
-+#endif
-+
-+/*
-+ * Lineo specific
-+ */
-+
-+#define VENDOR_SPECIFIC_CLASS 0xff
-+#define VENDOR_SPECIFIC_SUBCLASS 0xff
-+#define VENDOR_SPECIFIC_PROTOCOL 0xff
-+
-+/*
-+ * Lineo Classes
-+ */
-+#define LINEO_CLASS 0xff
-+
-+#define LINEO_SUBCLASS_BASIC_NET 0x01
-+#define LINEO_SUBCLASS_BASIC_SERIAL 0x02
-+
-+/*
-+ * Lineo Protocols
-+ */
-+#define LINEO_BASIC_NET_CRC 0x01
-+#define LINEO_BASIC_NET_CRC_PADDED 0x02
-+
-+#define LINEO_BASIC_SERIAL_CRC 0x01
-+#define LINEO_BASIC_SERIAL_CRC_PADDED 0x02
-+
-+
-+/*
-+ * endpoint and interface indexes
-+ */
-+#define BULK_OUT 0x00
-+#define BULK_IN 0x01
-+#define INT_IN 0x02
-+#define ENDPOINTS 0x03
-+
-+#define COMM_INTF 0x00
-+#define DATA_INTF 0x01
-+
-+
-+/* bmDataCapabilities */
-+#define BMDATA_CRC 0x01
-+#define BMDATA_PADBEFORE 0x02
-+#define BMDATA_PADAFTER 0x04
-+#define BMDATA_FERMAT 0x08
-+#define BMDATA_HOSTNAME 0x10
-+
-+/* bmNetworkCapabilities */
-+#define BMNETWORK_SET_PACKET_OK 0x01
-+#define BMNETWORK_NOBRIDGE 0x02
-+
-+
-+/*
-+ * BLAN Data Plane
-+ */
-+//#define CONFIG_USBD_NETWORK_PADBYTES 8
-+//#define CONFIG_USBD_NETWORK_PADAFTER 1
-+//#undef CONFIG_USBD_NETWORK_PADBEFORE
-+//#define CONFIG_USBD_NETWORK_CRC 1
-+
-+
-+extern __u8 network_requested_endpoints[ENDPOINTS+1];
-+extern __u16 network_requested_transferSizes[ENDPOINTS+1];
-+extern struct usb_network_private Usb_network_private;
-+extern __u8 local_dev_addr[ETH_ALEN];
-+extern __u8 remote_dev_addr[ETH_ALEN];
-+
-+extern struct usb_function_operations network_fd_function_ops;
-+extern struct usb_network_private Usb_network_private;
-+
-+struct usb_class_safe_networking_mdlm_descriptor {
-+ __u8 bFunctionLength; // 0x06
-+ __u8 bDescriptorType; // 0x24
-+ __u8 bDescriptorSubtype; // 0x13
-+ __u8 bGuidDescriptorType; // 0x00
-+ __u8 bmNetworkCapabilities;
-+ __u8 bmDataCapabilities;
-+} __attribute__ ((packed));
-+
-+struct usb_class_blan_networking_mdlm_descriptor {
-+ __u8 bFunctionLength; // 0x07
-+ __u8 bDescriptorType; // 0x24
-+ __u8 bDescriptorSubtype; // 0x13
-+ __u8 bGuidDescriptorType; // 0x01
-+ __u8 bmNetworkCapabilities;
-+ __u8 bmDataCapabilities;
-+ __u8 bPad;
-+} __attribute__ ((packed));
-+
-+
-+
-+
-+
-+#endif /* NETWORK_FD_H */
-diff -Nru a/drivers/usbd/network_fd/safe.c b/drivers/usbd/network_fd/safe.c
---- /dev/null Wed Dec 31 16:00:00 1969
-+++ b/drivers/usbd/network_fd/safe.c Fri Feb 27 14:22:51 2004
-@@ -0,0 +1,224 @@
-+/*
-+ * usbd/network_fd/safe.c - Network Function Driver
-+ *
-+ * Copyright (c) 2002, 2003, 2004 Belcarra
-+ *
-+ * By:
-+ * Chris Lynne <cl@belcarra.com>
-+ * Stuart Lynne <sl@belcarra.com>
-+ * Bruce Balden <balden@belcarra.com>
-+ *
-+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
-+ *
-+ *
-+ *
-+ */
-+
-+
-+#include <linux/config.h>
-+#include <linux/module.h>
-+
-+#include <usbd-export.h>
-+#include <usbd-build.h>
-+
-+#include <linux/slab.h>
-+#include <linux/interrupt.h>
-+#include <linux/utsname.h>
-+#include <linux/netdevice.h>
-+
-+#include <usbd-chap9.h>
-+#include <usbd-mem.h>
-+#include <usbd.h>
-+#include <usbd-func.h>
-+
-+#include "network.h"
-+
-+
-+#ifdef CONFIG_USBD_NETWORK_SAFE
-+/* USB SAFE Configuration ******************************************************************** */
-+
-+/*
-+ * SAFE Ethernet Configuration
-+ */
-+
-+/* Communication Interface Class descriptors
-+ */
-+
-+static __u8 safe_data_1[] = { 0x07, USB_DT_ENDPOINT, OUT, BULK, 0, 0x00, 0x00, };
-+static __u8 safe_data_2[] = { 0x07, USB_DT_ENDPOINT, IN, BULK, 0, 0x00, 0x00, };
-+static __u8 safe_comm_1[] = { 0x07, USB_DT_ENDPOINT, IN, INTERRUPT,0, 0x00, 0x0a, };
-+
-+static __u8 safe_class_1[] = { 0x05, CS_INTERFACE, USB_ST_HEADER, 0x10, 0x01, /* CLASS_BDC_VERSION, CLASS_BDC_VERSION */ };
-+static __u8 safe_class_2[] = { 0x15, CS_INTERFACE, USB_ST_MDLM, 0x00, 0x01, /* bcdVersion, bcdVersion */
-+ 0x5d, 0x34, 0xcf, 0x66, 0x11, 0x18, 0x11, 0xd6, /* bGUID */
-+ 0xa2, 0x1a, 0x00, 0x01, 0x02, 0xca, 0x9a, 0x7f, /* bGUID */ };
-+
-+static __u8 safe_class_3[] = { 0x06, CS_INTERFACE, USB_ST_MDLMD, 0x00, 0x00, 0x00, /* bDetailData */ };
-+
-+static __u8 safe_class_4[] = { 0x0d, CS_INTERFACE, USB_ST_ENF,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xea, 0x05, /* 1514 maximum frame size */
-+ 0x00, 0x00, 0x00 , };
-+
-+
-+static __u8 *safe_alt_endpoints[] = {
-+ (struct usb_endpoint_descriptor *) &safe_data_1,
-+ (struct usb_endpoint_descriptor *) &safe_data_2,
-+ (struct usb_endpoint_descriptor *) &safe_comm_1, };
-+static __u8 *safe_comm_class_descriptors[] = {
-+ (struct usb_generic_class_descriptor *) &safe_class_1,
-+ (struct usb_generic_class_descriptor *) &safe_class_2,
-+ (struct usb_generic_class_descriptor *) &safe_class_3,
-+ (struct usb_generic_class_descriptor *) &safe_class_4, };
-+
-+u8 safe_alt_indexes[] = { BULK_OUT, BULK_IN, INT_IN, };
-+
-+/* Data Interface Alternate descriptions and descriptors
-+ */
-+static __u8 safe_alternate_descriptor[sizeof(struct usb_interface_descriptor)] = {
-+ 0x09, USB_DT_INTERFACE, 0x00, 0x00, // bInterfaceNumber, bAlternateSetting
-+ sizeof (safe_alt_endpoints) / sizeof(struct usb_endpoint_descriptor), // bNumEndpoints
-+ COMMUNICATIONS_INTERFACE_CLASS, COMMUNICATIONS_MDLM_SUBCLASS, COMMUNICATIONS_NO_PROTOCOL, 0x00,
-+};
-+
-+static struct usb_alternate_description safe_alternate_descriptions[] = {
-+ { iInterface: CONFIG_USBD_NETWORK_SAFE_INTF,
-+ interface_descriptor: (struct usb_interface_descriptor *)&safe_alternate_descriptor,
-+ classes:sizeof (safe_comm_class_descriptors) / sizeof (struct usb_generic_class_descriptor *),
-+ class_list: safe_comm_class_descriptors,
-+ endpoints:sizeof (safe_alt_endpoints) / sizeof(struct usb_endpoint_descriptor *),
-+ endpoint_list: safe_alt_endpoints,
-+ endpoint_indexes: safe_alt_indexes,
-+ },
-+};
-+
-+/* Interface descriptions and descriptors
-+ */
-+static struct usb_interface_description safe_interfaces[] = {
-+ { alternates:sizeof (safe_alternate_descriptions) / sizeof (struct usb_alternate_description),
-+ alternate_list:safe_alternate_descriptions, },
-+};
-+
-+
-+/* Configuration descriptions and descriptors
-+ */
-+
-+static __u8 safe_configuration_descriptor[sizeof(struct usb_configuration_descriptor)] = {
-+ 0x09, USB_DT_CONFIG, 0x00, 0x00, // wLength
-+ sizeof (safe_interfaces) / sizeof (struct usb_interface_description),
-+ 0x01, 0x00, // bConfigurationValue, iConfiguration
-+ BMATTRIBUTE, BMAXPOWER,
-+};
-+
-+struct usb_configuration_description safe_description[] = {
-+ { iConfiguration: CONFIG_USBD_NETWORK_SAFE_DESC,
-+ configuration_descriptor: (struct usb_configuration_descriptor *)safe_configuration_descriptor,
-+ bNumInterfaces:sizeof (safe_interfaces) / sizeof (struct usb_interface_description),
-+ interface_list:safe_interfaces, },
-+};
-+
-+/* Device Description
-+ */
-+
-+//static __u8 safe_device_descriptor[sizeof(struct usb_device_descriptor)] = {
-+// 0x12, USB_DT_DEVICE,
-+// 0x00, 0x02, // bcdUSB
-+// COMMUNICATIONS_DEVICE_CLASS,
-+// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+//};
-+static struct usb_device_descriptor safe_device_descriptor = {
-+ bLength: sizeof(struct usb_device_descriptor),
-+ bDescriptorType: USB_DT_DEVICE,
-+ bcdUSB: __constant_cpu_to_le16(USB_BCD_VERSION),
-+ bDeviceClass: COMMUNICATIONS_DEVICE_CLASS,
-+ bDeviceSubClass: 0x02,
-+ bDeviceProtocol: 0x00,
-+ bMaxPacketSize0: 0x00,
-+ idVendor: __constant_cpu_to_le16(CONFIG_USBD_NETWORK_VENDORID),
-+ idProduct: __constant_cpu_to_le16(CONFIG_USBD_NETWORK_PRODUCTID),
-+ bcdDevice: __constant_cpu_to_le16(CONFIG_USBD_NETWORK_BCDDEVICE),
-+};
-+
-+static struct usb_endpoint_request safe_endpoint_requests[ENDPOINTS+1] = {
-+ { 1, 0, 0, USB_DIR_OUT | USB_ENDPOINT_BULK, MAXFRAMESIZE + 48, MAXFRAMESIZE + 512, },
-+ { 1, 0, 0, USB_DIR_IN | USB_ENDPOINT_BULK, MAXFRAMESIZE + 48, MAXFRAMESIZE + 512, },
-+ { 1, 0, 0, USB_DIR_IN | USB_ENDPOINT_INTERRUPT | USB_ENDPOINT_OPT, 16, 64, },
-+ { 0, },
-+};
-+
-+struct usb_device_description safe_device_description = {
-+ device_descriptor: &safe_device_descriptor,
-+ iManufacturer: CONFIG_USBD_NETWORK_MANUFACTURER,
-+ iProduct: CONFIG_USBD_NETWORK_PRODUCT_NAME,
-+#if !defined(CONFIG_USBD_NO_SERIAL_NUMBER) && defined(CONFIG_USBD_SERIAL_NUMBER_STR)
-+ iSerialNumber:CONFIG_USBD_SERIAL_NUMBER_STR,
-+#endif
-+ endpointsRequested: ENDPOINTS,
-+ requestedEndpoints: safe_endpoint_requests,
-+};
-+
-+void safe_init (struct usb_function_instance *function)
-+{
-+ struct usb_class_ethernet_networking_descriptor *ethernet;
-+ int len = 0;
-+ char buf[255];
-+
-+ buf[0] = 0;
-+
-+ safe_alternate_descriptions[0].endpoints = Usb_network_private.have_interrupt ? 3 : 2;
-+
-+ // Update the iMACAddress field in the ethernet descriptor
-+ {
-+ char address_str[14];
-+ snprintf(address_str, 13, "%02x%02x%02x%02x%02x%02x",
-+ remote_dev_addr[0], remote_dev_addr[1], remote_dev_addr[2],
-+ remote_dev_addr[3], remote_dev_addr[4], remote_dev_addr[5]);
-+ if ((ethernet = (struct usb_class_ethernet_networking_descriptor *)safe_class_4)) {
-+ if (ethernet->iMACAddress) {
-+ usbd_dealloc_string(ethernet->iMACAddress);
-+ }
-+ ethernet->iMACAddress = usbd_alloc_string(address_str);
-+ }
-+ }
-+
-+
-+#ifdef CONFIG_USBD_NETWORK_SAFE_PADBEFORE
-+ safe_class_3[5] |= BMDATA_PADBEFORE;
-+ len += sprintf(buf + len, "PADBEFORE: %02x ", safe_class_3[5]);
-+#endif
-+#ifdef CONFIG_USBD_NETWORK_SAFE_CRC
-+ safe_class_3[5] |= BMDATA_CRC;
-+ len += sprintf(buf + len, "CRC: %02x ", safe_class_3[5]);
-+#endif
-+#ifdef CONFIG_USBD_NETWORK_SAFE_NOBRIDGE
-+ safe_class_3[4] |= BMNETWORK_NOBRIDGE;
-+ len += sprintf(buf + len, "NOBRIDGE: %02x ",safe_class_3[4]);
-+#endif
-+ if (strlen(buf))
-+ printk(KERN_INFO"%s: %s\n", __FUNCTION__, buf);
-+
-+}
-+
-+struct usb_function_driver safe_function_driver = {
-+ name: "network-SAFE",
-+ fops: &network_fd_function_ops,
-+ device_description: &safe_device_description,
-+ bNumConfigurations: sizeof (safe_description) / sizeof (struct usb_configuration_description),
-+ configuration_description: safe_description,
-+ idVendor: __constant_cpu_to_le16(CONFIG_USBD_NETWORK_VENDORID),
-+ idProduct: __constant_cpu_to_le16(CONFIG_USBD_NETWORK_PRODUCTID),
-+ bcdDevice: __constant_cpu_to_le16(CONFIG_USBD_NETWORK_BCDDEVICE),
-+};
-+#endif /* CONFIG_USBD_NETWORK_SAFE */
-+
-diff -Nru a/drivers/usbd/trace.c b/drivers/usbd/trace.c
---- /dev/null Wed Dec 31 16:00:00 1969
-+++ b/drivers/usbd/trace.c Fri Feb 27 14:22:51 2004
-@@ -0,0 +1,509 @@
-+/*
-+ * usbd/trace.c
-+ *
-+ * Copyright (c) 2004 Belcarra
-+ *
-+ * Adapted from earlier work:
-+ * Copyright (c) 2002, 2003 Belcarra
-+ * Copyright (c) 2002 Lineo
-+ *
-+ * By:
-+ * Stuart Lynne <sl@belcarra.com>,
-+ * Tom Rushworth <tbr@belcarra.com>,
-+ *
-+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
-+ *
-+ */
-+
-+#include <linux/config.h>
-+#include <linux/module.h>
-+#include <linux/version.h>
-+
-+//EXPORT_NO_SYMBOLS;
-+
-+#include <linux/kernel.h>
-+#include <linux/slab.h>
-+#include <linux/interrupt.h>
-+#include <linux/pci.h>
-+#include <linux/init.h>
-+#include <linux/delay.h>
-+
-+#include <linux/proc_fs.h>
-+#include <linux/vmalloc.h>
-+
-+#include <asm/atomic.h>
-+#include <asm/io.h>
-+
-+#include <linux/proc_fs.h>
-+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,6)
-+#define USE_ADD_DEL_TIMER_FOR_USBADDR_CHECK 1
-+#include <linux/timer.h>
-+#else
-+#undef USE_ADD_DEL_TIMER_FOR_USBADDR_CHECK
-+#include <linux/tqueue.h>
-+#endif
-+
-+#include <linux/pci.h>
-+#include <linux/cache.h>
-+
-+
-+#if defined(CONFIG_ARCH_SA1100) || defined (CONFIG_ARCH_PXA)
-+#include <asm/dma.h>
-+#include <asm/mach/dma.h>
-+#include <asm/irq.h>
-+#include <asm/system.h>
-+#include <asm/hardware.h>
-+#include <asm/types.h>
-+#endif
-+
-+#if defined(CONFIG_SOC_AU1X00) || \
-+ defined(CONFIG_MIPS_AU1X00) || \
-+ defined(CONFIG_CPU_AU1X00) || \
-+ defined(CONFIG_MIPS_AU1000) || \
-+ defined(CONFIG_MIPS_PB1500) || \
-+ defined(CONFIG_MIPS_PB1100)
-+
-+#include <asm/au1000.h>
-+#include <asm/au1000_dma.h>
-+#include <asm/mipsregs.h>
-+
-+#endif /* defined(..) */
-+
-+#if defined(CONFIG_ARCH_SAMSUNG)
-+#include <asm/arch/timers.h>
-+#include <asm/arch/hardware.h>
-+#endif /* defined(CONFIG_ARCH_SAMSUNG) */
-+
-+#if defined(CONFIG_ARCH_MX1ADS)
-+#include "dbmx1_bi/dbmx1.h"
-+#endif /* defined(CONFIG_ARCH_MX1ADS) */
-+
-+#include <asm/uaccess.h>
-+#include <asm/io.h>
-+#include <asm/pgtable.h>
-+#include <asm/pgalloc.h>
-+
-+#include "usbd-chap9.h"
-+#include "usbd-mem.h"
-+#include "usbd.h"
-+#include "usbd-func.h"
-+#include "usbd-bus.h"
-+
-+#include "trace.h"
-+#include "usbd-bi.h"
-+
-+
-+int trace_first;
-+int trace_next;
-+trace_t *traces;
-+
-+#if defined(CONFIG_USBD_BI_REGISTER_TRACE) && defined(CONFIG_PROC_FS)
-+
-+trace_t *TRACE_NEXT(trace_types_t trace_type)
-+{
-+ trace_t *p;
-+
-+ p = traces + trace_next;
-+
-+ #if defined(CONFIG_ARCH_SA1100) || \
-+ defined (CONFIG_ARCH_PXA)
-+
-+ p->oscr = OSCR;
-+
-+ #elif defined(CONFIG_SOC_AU1X00) || \
-+ defined(CONFIG_MIPS_AU1X00) || \
-+ defined(CONFIG_CPU_AU1X00) || \
-+ defined(CONFIG_MIPS_AU1000) || \
-+ defined(CONFIG_MIPS_PB1500) || \
-+ defined(CONFIG_MIPS_PB1100)
-+
-+ #if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,19)
-+ p->cp0_count = __read_32bit_c0_register(CP0_COUNT);
-+ #else
-+ p->cp0_count = read_c0_count();
-+ #endif
-+
-+ #elif defined(CONFIG_ARCH_SAMSUNG)
-+ p->tcnt1 = *(volatile u32 *)TCNT1;
-+ #else
-+ p->jiffies = jiffies;
-+ #endif
-+
-+ #if defined(CONFIG_SOC_AU1X00) || \
-+ defined(CONFIG_MIPS_AU1X00) || \
-+ defined(CONFIG_CPU_AU1X00) || \
-+ defined(CONFIG_MIPS_AU1000) || \
-+ defined(CONFIG_MIPS_PB1500) || \
-+ defined(CONFIG_MIPS_PB1100)
-+ //p->sofs = au_readl(USBD_FRAMENUM);
-+ #endif
-+
-+ #if defined(CONFIG_ARCH_MX1ADS)
-+ p->sofs = USBD_FRAME & 0x3ff;
-+ #endif
-+
-+ p->interrupts = udc_interrupts;
-+ p->trace_type = trace_type;
-+
-+ trace_next++;
-+ trace_next = (trace_next == TRACE_MAX) ? 0 : trace_next;
-+
-+ if (trace_next == trace_first) {
-+ trace_first++;
-+ trace_first = (trace_first == TRACE_MAX) ? 0 : trace_first;
-+ }
-+
-+ return p;
-+}
-+
-+/* Proc Filesystem *************************************************************************** */
-+
-+static __inline__ char *nullchk(char *s)
-+{
-+ return s ? s : "(NULL)";
-+}
-+/* *
-+ * trace_proc_read - implement proc file system read.
-+ * @file
-+ * @buf
-+ * @count
-+ * @pos
-+ *
-+ * Standard proc file system read function.
-+ */
-+static ssize_t trace_proc_read (struct file *file, char *buf, size_t count, loff_t * pos)
-+{
-+ unsigned long page;
-+ int len = 0;
-+ int index;
-+ int oindex;
-+ int previous;
-+
-+ #ifdef MODULE
-+ MOD_INC_USE_COUNT;
-+ #endif
-+ // get a page, max 4095 bytes of data...
-+ if (!(page = get_free_page (GFP_KERNEL))) {
-+
-+ #ifdef MODULE
-+ MOD_DEC_USE_COUNT;
-+ #endif
-+ return -ENOMEM;
-+ }
-+
-+ len = 0;
-+ oindex = index = (*pos)++;
-+
-+ if (index == 0) {
-+ #if defined(CONFIG_ARCH_SAMSUNG)
-+ len += sprintf ((char *) page + len, " Index Ints Ticks [%d]\n", CONFIG_USBD_SMDK2500_BCLOCK );
-+ #else
-+ len += sprintf ((char *) page + len, " Index Ints Ticks\n");
-+ #endif
-+ }
-+
-+ index += trace_first;
-+ if (index >= TRACE_MAX) {
-+ index -= TRACE_MAX;
-+ }
-+ previous = (index) ? (index - 1) : (TRACE_MAX - 1);
-+
-+ //printk(KERN_INFO"first: %d next: %d index: %d %d prev: %d\n", trace_first, trace_next, oindex, index, previous);
-+
-+ if (
-+ ((trace_first < trace_next) && (index >= trace_first) && (index < trace_next)) ||
-+ ((trace_first > trace_next) && ((index < trace_next) || (index >= trace_first)))
-+ )
-+ {
-+
-+ #if defined(CONFIG_SOC_AU1X00) || \
-+ defined(CONFIG_MIPS_AU1X00) || \
-+ defined(CONFIG_CPU_AU1X00) || \
-+ defined(CONFIG_MIPS_AU1000) || \
-+ defined(CONFIG_MIPS_PB1500) || \
-+ defined(CONFIG_MIPS_PB1100)
-+
-+ u32 ticks = 0;
-+
-+ #elif defined(CONFIG_ARCH_SAMSUNG)
-+ u32 ticks = 0;
-+ #elif defined(CONFIG_ARCH_SA1100) || defined (CONFIG_ARCH_PXA)
-+ u32 ticks = 0;
-+ u64 jifs = 0;
-+ #else
-+ u64 jifs = 0;
-+ #endif
-+
-+ trace_t *p = traces + index;
-+ unsigned char *cp;
-+ int skip = 0;
-+
-+ if (oindex > 0) {
-+ trace_t *o = traces + previous;
-+
-+ #if defined(CONFIG_ARCH_SA1100) || defined (CONFIG_ARCH_PXA)
-+ /*
-+ * oscr is 3.6864 Mhz free running counter,
-+ *
-+ * 1/3.6864 = .2712
-+ * 60/221 = .2714
-+ *
-+ */
-+ if (o->oscr) {
-+ ticks = (p->oscr > o->oscr) ? (p->oscr - o->oscr) : (o->oscr - p->oscr) ;
-+ ticks = (ticks * 60) / 221;
-+ }
-+
-+ #elif defined(CONFIG_SOC_AU1X00) || \
-+ defined(CONFIG_MIPS_AU1X00) || \
-+ defined(CONFIG_CPU_AU1X00) || \
-+ defined(CONFIG_MIPS_AU1000) || \
-+ defined(CONFIG_MIPS_PB1500) || \
-+ defined(CONFIG_MIPS_PB1100)
-+ /*
-+ * cp0_count is incrementing timer at system clock
-+ */
-+ if (o->cp0_count) {
-+ ticks = (p->cp0_count > o->cp0_count) ?
-+ (p->cp0_count - o->cp0_count) : (o->cp0_count - p->cp0_count) ;
-+ ticks = ticks / CONFIG_USBD_AU1X00_SCLOCK;
-+ }
-+ #elif defined(CONFIG_ARCH_SAMSUNG)
-+ /*
-+ * tcnt1 is a count-down timer running at the system bus clock
-+ * The divisor must be set as a configuration value, typically 66 or 133.
-+ */
-+ if (o->tcnt1) {
-+ ticks = (p->tcnt1 < o->tcnt1) ? (o->tcnt1 - p->tcnt1) : (p->tcnt1 - o->tcnt1) ;
-+ ticks /= CONFIG_USBD_SMDK2500_BCLOCK;
-+ }
-+ #else
-+ if (o->jiffies) {
-+ jifs = p->jiffies - traces[previous].jiffies;
-+ }
-+ #endif
-+
-+ if (o->interrupts != p->interrupts) {
-+ skip++;
-+ }
-+ }
-+
-+ //printk(KERN_INFO"index: %d interrupts: %d\n", index, p->interrupts);
-+ len += sprintf ((char *) page + len, "%s%6d %8d ", skip?"\n":"", index, p->interrupts);
-+
-+ #if defined(CONFIG_SOC_AU1X00) || \
-+ defined(CONFIG_MIPS_AU1X00) || \
-+ defined(CONFIG_CPU_AU1X00) || \
-+ defined(CONFIG_MIPS_AU1000) || \
-+ defined(CONFIG_MIPS_PB1500) || \
-+ defined(CONFIG_MIPS_PB1100) || \
-+ defined(CONFIG_ARCH_SA1100) || \
-+ defined(CONFIG_ARCH_PXA)
-+
-+ if (ticks > 1024*1024) {
-+ len += sprintf ((char *) page + len, "%8dM ", ticks>>20);
-+ }
-+ else {
-+ len += sprintf ((char *) page + len, "%8d ", ticks);
-+ }
-+
-+ #elif defined(CONFIG_ARCH_SAMSUNG)
-+ //len += sprintf ((char *) page + len, "%8u ", p->jiffies);
-+ //len += sprintf ((char *) page + len, "%8u ", p->tcnt0);
-+ len += sprintf ((char *) page + len, "%8u ", p->tcnt1);
-+ if (ticks > 1024*1024) {
-+ len += sprintf ((char *) page + len, "%8dM ", ticks>>20);
-+ }
-+ else {
-+ len += sprintf ((char *) page + len, "%8d ", ticks);
-+ }
-+ #else
-+ if (jifs > 1024) {
-+ len += sprintf ((char *) page + len, "%4d ", (int)jifs>>20);
-+ }
-+ else {
-+ len += sprintf ((char *) page + len, "%4d ", (int)jifs);
-+ }
-+ #endif
-+ #if defined(CONFIG_ARCH_MX1ADS)
-+ len += sprintf ((char *) page + len, "%6d ", (int)p->sofs);
-+ #endif
-+
-+ switch (p->trace_type) {
-+ case trace_msg:
-+ len += sprintf ((char *) page + len, " -- ");
-+ len += sprintf ((char *) page + len, p->trace.msg.msg);
-+ break;
-+
-+ case trace_w:
-+ len += sprintf ((char *) page + len, " --> ");
-+ len += sprintf ((char *) page + len, "[%8x] W %s", p->trace.msg32.val, nullchk(p->trace.msg32.msg));
-+ break;
-+
-+ case trace_r:
-+ len += sprintf ((char *) page + len, "<-- ");
-+ len += sprintf ((char *) page + len, "[%8x] R %s", p->trace.msg32.val, nullchk(p->trace.msg32.msg));
-+ break;
-+
-+ case trace_msg32:
-+ len += sprintf ((char *) page + len, " -- ");
-+ len += sprintf ((char *) page + len, p->trace.msg32.msg, p->trace.msg32.val);
-+ break;
-+
-+ case trace_msg16:
-+ len += sprintf ((char *) page + len, " -- ");
-+ len += sprintf ((char *) page + len, p->trace.msg16.msg, p->trace.msg16.val0, p->trace.msg16.val1);
-+ break;
-+
-+ case trace_msg8:
-+ len += sprintf ((char *) page + len, " -- ");
-+ len += sprintf ((char *) page + len, p->trace.msg8.msg,
-+ p->trace.msg8.val0, p->trace.msg8.val1, p->trace.msg8.val2, p->trace.msg8.val3);
-+ break;
-+
-+ case trace_setup:
-+ cp = (unsigned char *)&p->trace.setup;
-+ len += sprintf ((char *) page + len,
-+ " -- request [%02x %02x %02x %02x %02x %02x %02x %02x]",
-+ cp[0], cp[1], cp[2], cp[3], cp[4], cp[5], cp[6], cp[7]);
-+ break;
-+
-+ case trace_recv:
-+ case trace_sent:
-+ cp = (unsigned char *)&p->trace.sent;
-+ len += sprintf ((char *) page + len,
-+ "%s %s [%02x %02x %02x %02x %02x %02x %02x %02x]",
-+ ( p->trace_type == trace_recv)?"<-- ":" -->",
-+ ( p->trace_type == trace_recv)?"recv":"sent",
-+ cp[0], cp[1], cp[2], cp[3], cp[4], cp[5], cp[6], cp[7]);
-+ break;
-+ }
-+ len += sprintf ((char *) page + len, "\n");
-+ }
-+
-+ if ((len > count) || (len == 0))
-+ len = -EINVAL;
-+
-+ else if (len > 0 && copy_to_user (buf, (char *) page, len))
-+ len = -EFAULT;
-+
-+ free_page (page);
-+ MOD_DEC_USE_COUNT;
-+ return len;
-+}
-+
-+/* *
-+ * trace_proc_write - implement proc file system write.
-+ * @file
-+ * @buf
-+ * @count
-+ * @pos
-+ *
-+ * Proc file system write function, used to signal monitor actions complete.
-+ * (Hotplug script (or whatever) writes to the file to signal the completion
-+ * of the script.) An ugly hack.
-+ */
-+static ssize_t trace_proc_write (struct file *file, const char *buf, size_t count, loff_t * pos)
-+{
-+ return count;
-+}
-+
-+static struct file_operations trace_proc_operations_functions = {
-+ read:trace_proc_read,
-+ write:trace_proc_write,
-+};
-+
-+int trace_reinit (void)
-+{
-+ printk(KERN_INFO"%s:\n", __FUNCTION__);
-+ //trace_first = trace_next = 0;
-+ return 0;
-+}
-+
-+/**
-+ * udc_request_udc_io - request UDC io region
-+ *
-+ * Return non-zero if not successful.
-+ */
-+int trace_init (void)
-+{
-+ struct proc_dir_entry *p;
-+ trace_first = trace_next = 0;
-+ printk(KERN_INFO"%s:\n", __FUNCTION__);
-+
-+ if (!(traces = vmalloc(sizeof(trace_t) * TRACE_MAX))) {
-+ printk(KERN_ERR"BITRACE malloc failed %p %d\n", traces, sizeof(trace_t) * TRACE_MAX);
-+ return -EINVAL;
-+ }
-+
-+ memset(traces, 0, sizeof(trace_t) * TRACE_MAX);
-+
-+ TRACE_MSG("init");
-+ TRACE_MSG("test");
-+
-+ // create proc filesystem entries
-+ if ((p = create_proc_entry ("bitrace", 0, 0)) == NULL)
-+ printk(KERN_INFO"BITRACE PROC FS failed\n");
-+ else
-+ p->proc_fops = &trace_proc_operations_functions;
-+
-+ #if defined(CONFIG_ARCH_SAMSUNG)
-+ *(volatile u32 *)TMOD |= 0x3 << 3;
-+ #endif
-+ return 0;
-+}
-+
-+/**
-+ * udc_release_io - release UDC io region
-+ */
-+void trace_exit (void)
-+{
-+ {
-+ unsigned long flags;
-+ local_irq_save (flags);
-+ remove_proc_entry ("bitrace", NULL);
-+ if (traces) {
-+ trace_t *p = traces;
-+ traces = 0;
-+ vfree(p);
-+ }
-+ local_irq_restore (flags);
-+ }
-+}
-+
-+#else
-+int trace_reinit (void)
-+{
-+ return 0;
-+}
-+
-+int trace_init (void)
-+{
-+ return 0;
-+}
-+
-+void trace_exit (void)
-+{
-+ return;
-+}
-+#endif
-+
-+/* End of FILE */
-+
-+
-+//EXPORT_SYMBOL(trace_first);
-+//EXPORT_SYMBOL(trace_next);
-+//EXPORT_SYMBOL(traces);
-+
-diff -Nru a/drivers/usbd/trace.h b/drivers/usbd/trace.h
---- /dev/null Wed Dec 31 16:00:00 1969
-+++ b/drivers/usbd/trace.h Fri Feb 27 14:22:51 2004
-@@ -0,0 +1,270 @@
-+/*
-+ * usbd/trace.h
-+ *
-+ * Copyright (c) 2004 Belcarra
-+ *
-+ * Adapted from earlier work:
-+ * Copyright (c) 2002, 2003 Belcarra
-+ * Copyright (c) 2002 Lineo
-+ *
-+ * By:
-+ * Stuart Lynne <sl@belcarra.com>,
-+ * Tom Rushworth <tbr@belcarra.com>,
-+ *
-+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
-+ *
-+ */
-+
-+#if defined(CONFIG_ARCH_SAMSUNG)
-+#ifndef CONFIG_USBD_SMDK2500_BCLOCK
-+#define CONFIG_USBD_SMDK2500_BCLOCK 66
-+#endif
-+#endif
-+
-+
-+typedef enum trace_int_types {
-+ trace_int_udc, trace_int_ep0, trace_int_in, trace_int_out, trace_int_int
-+} trace_int_types_t;
-+
-+typedef struct trace_int {
-+ u32 last;
-+ u32 total;
-+ u32 samples;
-+} trace_int_t;
-+
-+
-+typedef enum trace_types {
-+ trace_setup, trace_msg, trace_msg32, trace_msg16, trace_msg8, trace_recv, trace_sent, trace_w, trace_r
-+} trace_types_t;
-+
-+
-+typedef struct trace_regs32 {
-+ u32 reg;
-+ char * msg;
-+} trace_regs32_t;
-+
-+
-+typedef struct trace_msg {
-+ char *msg;
-+} trace_msg_t;
-+
-+typedef struct trace_msg32 {
-+ u32 val;
-+ char *msg;
-+} trace_msg32_t;
-+
-+typedef struct trace_msg16 {
-+ u16 val0;
-+ u16 val1;
-+ char *msg;
-+} trace_msg16_t;
-+
-+typedef struct trace_msg8 {
-+ u8 val0;
-+ u8 val1;
-+ u8 val2;
-+ u8 val3;
-+ char *msg;
-+} trace_msg8_t;
-+
-+
-+typedef struct trace {
-+ trace_types_t trace_type;
-+ u32 interrupts;
-+#if defined(CONFIG_ARCH_SA1100) || defined (CONFIG_ARCH_PXA)
-+ u32 oscr;
-+
-+#elif defined(CONFIG_SOC_AU1X00) || defined(CONFIG_MIPS_AU1X00) || defined(CONFIG_CPU_AU1X00) || defined(CONFIG_MIPS_AU1000) || defined(CONFIG_MIPS_PB1500) || defined(CONFIG_MIPS_PB1100)
-+
-+ u32 cp0_count;
-+#elif defined(CONFIG_ARCH_SAMSUNG)
-+ //u32 tcnt0;
-+ u32 tcnt1;
-+ //u64 jiffies;
-+#else
-+ u64 jiffies;
-+#endif
-+#if defined(CONFIG_SOC_AU1X00) || defined(CONFIG_MIPS_AU1X00) || defined(CONFIG_CPU_AU1X00) || defined(CONFIG_MIPS_AU1000) || defined(CONFIG_MIPS_PB1500) || defined(CONFIG_MIPS_PB1100) || defined(CONFIG_ARCH_MX1ADS)
-+ u64 sofs;
-+#endif
-+ union {
-+ trace_msg_t msg;
-+ trace_msg8_t msg8;
-+ trace_msg16_t msg16;
-+ trace_msg32_t msg32;
-+
-+ struct usb_device_request setup;
-+ unsigned char recv[8];
-+ unsigned char sent[8];
-+
-+ } trace;
-+
-+} trace_t;
-+
-+
-+#define TRACE_MAX 10000
-+
-+extern int trace_first;
-+extern int trace_next;
-+
-+extern trace_int_t *trace_ints;
-+extern trace_t *traces;
-+
-+#ifdef CONFIG_USBD_BI_REGISTER_TRACE
-+
-+trace_t *TRACE_NEXT(trace_types_t trace_type);
-+
-+static __inline__ void TRACE_SETUP(struct usb_device_request *setup)
-+{
-+ if (traces) {
-+ trace_t *p = TRACE_NEXT(trace_setup);
-+ p->trace_type = trace_setup;
-+ memcpy(&p->trace.setup, setup, sizeof(struct usb_device_request));
-+ }
-+}
-+
-+static __inline__ void TRACE_MSG(char *msg)
-+{
-+ if (traces) {
-+ trace_t *p = TRACE_NEXT(trace_msg);
-+ p->trace.msg.msg = msg;
-+ }
-+}
-+
-+static __inline__ void TRACE_W(char *msg, u32 val)
-+{
-+ if (traces) {
-+ trace_t *p = TRACE_NEXT(trace_w);
-+ p->trace.msg32.val = val;
-+ p->trace.msg32.msg = msg;
-+ }
-+}
-+
-+static __inline__ void TRACE_R(char *msg, u32 val)
-+{
-+ if (traces) {
-+ trace_t *p = TRACE_NEXT(trace_r);
-+ p->trace.msg32.val = val;
-+ p->trace.msg32.msg = msg;
-+ }
-+}
-+
-+static __inline__ void TRACE_MSG32(char *msg, u32 val)
-+{
-+ if (traces) {
-+ trace_t *p = TRACE_NEXT(trace_msg32);
-+ p->trace.msg32.val = val;
-+ p->trace.msg32.msg = msg;
-+ }
-+}
-+
-+static __inline__ void TRACE_MSG16(char *msg, u16 val0, u16 val1)
-+{
-+ if (traces) {
-+ trace_t *p = TRACE_NEXT(trace_msg16);
-+ p->trace.msg16.val0 = val0;
-+ p->trace.msg16.val1 = val1;
-+ p->trace.msg16.msg = msg;
-+ }
-+}
-+
-+static __inline__ void TRACE_MSG8(char *msg, u8 val0, u8 val1, u8 val2, u8 val3)
-+{
-+ if (traces) {
-+ trace_t *p = TRACE_NEXT(trace_msg8);
-+ p->trace.msg8.val0 = val0;
-+ p->trace.msg8.val1 = val1;
-+ p->trace.msg8.val2 = val2;
-+ p->trace.msg8.val3 = val3;
-+ p->trace.msg8.msg = msg;
-+ }
-+}
-+
-+static __inline__ void TRACE_RECV(unsigned char *cp)
-+{
-+ if (traces) {
-+ trace_t *p = TRACE_NEXT(trace_recv);
-+ memcpy(&p->trace.recv, cp, 8);
-+ }
-+}
-+
-+static __inline__ void TRACE_RECVN(unsigned char *cp, int bytes)
-+{
-+ if (traces) {
-+ trace_t *p = TRACE_NEXT(trace_recv);
-+ memset(&p->trace.recv, 0, 8);
-+ memcpy(&p->trace.recv, cp, bytes);
-+ }
-+}
-+
-+static __inline__ void TRACE_SENT(unsigned char *cp)
-+{
-+ if (traces) {
-+ trace_t *p = TRACE_NEXT(trace_sent);
-+ memcpy(&p->trace.sent, cp, 8);
-+ }
-+}
-+
-+#else
-+
-+static __inline__ void TRACE_SETUP(struct usb_device_request *setup)
-+{
-+}
-+
-+static __inline__ void TRACE_IRQS(u32 cr, u32 sr)
-+{
-+}
-+
-+static __inline__ void TRACE_RECV(unsigned char *cp)
-+{
-+}
-+
-+static __inline__ void TRACE_SENT(unsigned char *cp)
-+{
-+}
-+
-+static __inline__ void TRACE_W(char *msg, u32 val)
-+{
-+}
-+
-+static __inline__ void TRACE_R(char *msg, u32 val)
-+{
-+}
-+
-+static __inline__ void TRACE_MSG(char *msg)
-+{
-+}
-+
-+static __inline__ void TRACE_MSG32(char *msg, u32 val)
-+{
-+}
-+
-+static __inline__ void TRACE_MSG16(char *msg, u16 val0, u16 val1)
-+{
-+}
-+
-+static __inline__ void TRACE_MSG8(char *msg, u8 val0, u8 val1, u8 val2, u8 vale)
-+{
-+}
-+static __inline__ void TRACE_RECVN(unsigned char *cp, int bytes)
-+{
-+}
-+
-+#endif
-+
-+int trace_init (void);
-+int trace_reinit (void);
-+void trace_exit (void);
-+
-diff -Nru a/drivers/usbd/udc.h b/drivers/usbd/udc.h
---- /dev/null Wed Dec 31 16:00:00 1969
-+++ b/drivers/usbd/udc.h Fri Feb 27 14:22:51 2004
-@@ -0,0 +1,48 @@
-+/*
-+ * usbd/udc.h
-+ *
-+ * Copyright (c) 2004 Belcarra
-+ *
-+ * By:
-+ * Stuart Lynne <sl@belcarra.com>,
-+ * Tom Rushworth <tbr@belcarra.com>,
-+ * Bruce Balden <balden@belcarra.com>
-+ *
-+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
-+ *
-+ */
-+
-+#include <linux/config.h>
-+#include <linux/module.h>
-+#include <linux/kernel.h>
-+#include <linux/version.h>
-+#include <linux/kernel.h>
-+#include <linux/slab.h>
-+#include <linux/interrupt.h>
-+#include <linux/init.h>
-+#include <linux/delay.h>
-+#include <asm/atomic.h>
-+#include <asm/irq.h>
-+#include <asm/system.h>
-+#include <asm/types.h>
-+#include <asm/uaccess.h>
-+#include <asm/io.h>
-+
-+#include <usbd-export.h>
-+#include <usbd-build.h>
-+#include <usbd-chap9.h>
-+#include <usbd-mem.h>
-+#include <usbd.h>
-+#include <usbd-bus.h>
-+#include <trace.h>
-+#include <usbd-bi.h>
-+
-diff -Nru a/drivers/usbd/usbd-admin.h b/drivers/usbd/usbd-admin.h
---- /dev/null Wed Dec 31 16:00:00 1969
-+++ b/drivers/usbd/usbd-admin.h Fri Feb 27 14:22:51 2004
-@@ -0,0 +1,61 @@
-+/*
-+ * usbd/usbd-admin.h
-+ *
-+ * Copyright (c) 2004 Belcarra
-+ *
-+ * By:
-+ * Stuart Lynne <sl@belcarra.com>,
-+ * Tom Rushworth <tbr@belcarra.com>,
-+ * Bruce Balden <balden@belcarra.com>
-+ *
-+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
-+ *
-+ */
-+
-+
-+/*
-+ * This defines the public interface to administer the USB Device Software.
-+ *
-+ * Specifically it allows the USB Device software to be:
-+ *
-+ * enabled enable a specific function driver for use
-+ * disabled disable the USB Device Software
-+ *
-+ * disconnected disable the USB Pullup Resistor (also known as soft-connect)
-+ * connected enable the USB Pullup Resistor
-+ *
-+ * pm_off perform required functions for Power Management off
-+ * pm_on perform required functions for Power Management on
-+ *
-+ *
-+ */
-+
-+int usbd_enable(char *);
-+int usbd_enable_irq(char *);
-+int usbd_disable(char *);
-+int usbd_disable_irq(char *);
-+
-+int usbd_disconnect(char *);
-+int usbd_connect(char *);
-+int usbd_pm_on(char *);
-+int usbd_pm_off(char *);
-+
-+#ifdef CONFIG_USBD_DEPRECATED
-+int usbd_load(char *);
-+int usbd_unload(char *);
-+int usbd_replug(char *);
-+int usbd_unplug(char *);
-+#endif
-+
-diff -Nru a/drivers/usbd/usbd-bi.c b/drivers/usbd/usbd-bi.c
---- /dev/null Wed Dec 31 16:00:00 1969
-+++ b/drivers/usbd/usbd-bi.c Fri Feb 27 14:22:51 2004
-@@ -0,0 +1,753 @@
-+/*
-+ * usbd/usbd-bi.c - USB Bus Interface Driver
-+ *
-+ * Copyright (c) 2004 Belcarra
-+ *
-+ * By:
-+ * Stuart Lynne <sl@belcara.com>,
-+ * Tom Rushworth <tbr@belcara.com>,
-+ * Bruce Balden <balden@belcara.com>
-+ *
-+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
-+ *
-+ * Notes
-+ *
-+ * 1. The usbd-bi layer has be re-implemented to re-factor the UDC layer in a way to
-+ * simplify implementation of UDC drivers. As much of the complexity of dealing with the middle
-+ * layers and buffer (urb) handling is provided for in the common bi layer.
-+ *
-+ * 2. TODO The udc interface will be further modified to allow the UDC to export a block of
-+ * function pointers for the common bi layer to use. This will allow the common layer to
-+ * implement default operations where the UDC does not provide an function. For example many UDC
-+ * drivers do not provide full support for cable detection and usb pullup control. If these
-+ * routines are not provided the common layer will supply defaults. This eliminates a reasonably
-+ * larger amount of effectively unused code from many of the udc drivers.
-+ *
-+ */
-+
-+#include <linux/config.h>
-+#include <linux/module.h>
-+#include <linux/kernel.h>
-+#include <linux/version.h>
-+#include <linux/init.h>
-+#include <linux/ctype.h>
-+#include <linux/slab.h>
-+#include <linux/interrupt.h>
-+#include <asm/uaccess.h>
-+
-+#include "usbd-chap9.h"
-+#include "usbd-mem.h"
-+#include "usbd.h"
-+#include "usbd-bus.h"
-+#include "usbd-func.h"
-+#include "trace.h"
-+#include "usbd-bi.h"
-+#include "usbd-admin.h"
-+
-+#ifdef MODULE
-+static char *serial_number_str;
-+MODULE_PARM (serial_number_str, "s");
-+MODULE_PARM_DESC (serial_number_str, "Serial Number");
-+#else
-+static char *serial_number_str;
-+#endif
-+
-+struct usb_bus_instance *usbd_bus;
-+int have_cable_irq;
-+
-+/* ******************************************************************************************* */
-+
-+int bi_attached (struct usb_bus_instance *bus)
-+{
-+ return udc_ops.attached ? udc_ops.attached () : 1;
-+}
-+
-+int bi_connected (struct usb_bus_instance *bus)
-+{
-+ return udc_ops.connected ? udc_ops.connected () : 1;
-+}
-+
-+int bi_disconnect (struct usb_bus_instance *bus, char *arg)
-+{
-+ RETURN_EINVAL_IF (in_interrupt ());
-+ if (udc_ops.disconnect) udc_ops.disconnect ();
-+ return 0;
-+}
-+
-+int bi_connect (struct usb_bus_instance *bus, char *arg)
-+{
-+ RETURN_EINVAL_IF (in_interrupt ());
-+ if (udc_ops.connect) udc_ops.connect ();
-+ return 0;
-+}
-+
-+int bi_request_endpoints(struct usb_endpoint_map *endpoint_map_array, int endpointsRequested,
-+ struct usb_endpoint_request *requestedEndpoints)
-+{
-+ int i;
-+ RETURN_EINVAL_IF (udc_ops.request_endpoints(endpoint_map_array, endpointsRequested, requestedEndpoints));
-+ for (i = 0; i < endpointsRequested; i++) {
-+ struct usb_endpoint_map *endpoint_map = endpoint_map_array + i;
-+ TRACE_MSG8 ("address: %02x physical: %02x request: %02x size: %04x",
-+ endpoint_map->bEndpointAddress[0], endpoint_map->physicalEndpoint[0],
-+ endpoint_map->bmAttributes[0], endpoint_map->wMaxPacketSize[0]);
-+ }
-+ return 0;
-+}
-+int bi_set_endpoints(int endpointsRequested, struct usb_endpoint_map *endpoint_map_array)
-+{
-+ return udc_ops.set_endpoints ? udc_ops.set_endpoints(endpointsRequested, endpoint_map_array) : 0;
-+}
-+
-+/* ******************************************************************************************* */
-+/* bi_endpoint_halted - check if endpoint halted
-+ * Used by the USB Device Core to check endpoint halt status.
-+ */
-+int bi_endpoint_halted (struct usb_bus_instance *bus, int endpoint_index)
-+{
-+ return udc_ops.endpoint_halted ? udc_ops.endpoint_halted(endpoint_index) : 0;
-+}
-+
-+/* bi_device_feature - handle set/clear feature requests
-+ * Used by the USB Device Core to check endpoint halt status.
-+ */
-+int bi_device_feature (struct usb_bus_instance *bus, int endpoint_index, int flag)
-+{
-+ return 0;
-+}
-+
-+/* bi_disable_endpoints - disable udc and all endpoints
-+ */
-+static void bi_disable_endpoints (struct usb_bus_instance *bus)
-+{
-+ int i;
-+ RETURN_IF (!bus || !bus->endpoint_array);
-+ for (i = 1; i < udc_ops.max_endpoints; i++) {
-+ struct usb_endpoint_instance *endpoint = (bus->endpoint_array + i);
-+ CONTINUE_IF (!endpoint);
-+ usbd_flush_endpoint (endpoint);
-+ }
-+}
-+
-+
-+/* bi_device_event_irq - handle generic bus event
-+ * Called by usb core layer to inform bus of an event.
-+ */
-+int bi_device_event_irq (struct usb_bus_instance *bus, usb_device_event_t event, int data)
-+{
-+ int epn;
-+ int endpointsRequested = bus->function_instance->endpointsRequested;
-+ struct usb_endpoint_map *endpoint_map_array = bus->function_instance->endpoint_map_array;
-+
-+ TRACE_MSG32 ("EVENT %x", event);
-+ switch (event) {
-+ case DEVICE_UNKNOWN:
-+ break;
-+
-+ case DEVICE_INIT:
-+ TRACE_MSG ("EVENT INIT");
-+ break;
-+
-+ case DEVICE_CREATE:
-+ TRACE_MSG ("EVENT CREATE");
-+ bi_disable_endpoints (bus);
-+ if (udc_ops.enable) udc_ops.enable ();
-+ if (udc_ops.suspended_interrupts) udc_ops.suspended_interrupts ();
-+ break;
-+
-+ case DEVICE_HUB_CONFIGURED:
-+ TRACE_MSG ("EVENT HUB_CONFIGURED");
-+ bi_connect (usbd_bus, NULL);
-+ break;
-+
-+ case DEVICE_RESET:
-+ TRACE_MSG ("EVENT RESET");
-+ if (udc_ops.set_address) udc_ops.set_address (0);
-+ if (udc_ops.reset_ep) udc_ops.reset_ep (0);
-+ if (udc_ops.suspended_interrupts) udc_ops.suspended_interrupts ();
-+ bi_disable_endpoints (bus);
-+ break;
-+
-+ case DEVICE_ADDRESS_ASSIGNED:
-+ TRACE_MSG ("EVENT ADDRESSED");
-+ if (udc_ops.set_address) udc_ops.set_address (data);
-+ if (udc_ops.all_interrupts) udc_ops.all_interrupts ();
-+ break;
-+
-+ case DEVICE_CONFIGURED:
-+ TRACE_MSG ("EVENT CONFIGURED");
-+ // iterate across the physical endpoint instance array to enable the endpoints
-+ if (udc_ops.setup_ep)
-+ for (epn = 1; epn < bus->endpoints; epn++)
-+ udc_ops.setup_ep (epn, bus->endpoint_array + epn);
-+ return 0;
-+
-+ case DEVICE_DE_CONFIGURED:
-+ TRACE_MSG ("EVENT DE-CONFIGURED");
-+ break;
-+
-+ case DEVICE_SET_INTERFACE:
-+ TRACE_MSG ("EVENT SET INTERFACE");
-+ break;
-+
-+ case DEVICE_SET_FEATURE:
-+ TRACE_MSG ("EVENT SET FEATURE");
-+ break;
-+
-+ case DEVICE_CLEAR_FEATURE:
-+ TRACE_MSG ("EVENT CLEAR FEATURE");
-+ break;
-+
-+ case DEVICE_BUS_INACTIVE:
-+ TRACE_MSG ("EVENT INACTIVE");
-+ if (udc_ops.suspended_interrupts) udc_ops.suspended_interrupts (); // disable suspend interrupt
-+ if (bi_attached (usbd_bus))
-+ usbd_bus_event_irq (bus, DEVICE_RESET, 0);
-+ break;
-+
-+ case DEVICE_BUS_ACTIVITY:
-+ TRACE_MSG ("EVENT ACTIVITY");
-+ if (udc_ops.all_interrupts) udc_ops.all_interrupts (); // enable suspend interrupt
-+ break;
-+
-+ case DEVICE_POWER_INTERRUPTION:
-+ TRACE_MSG ("POWER INTERRUPTION");
-+ break;
-+
-+ case DEVICE_HUB_RESET:
-+ TRACE_MSG ("HUB RESET");
-+ break;
-+
-+ case DEVICE_DESTROY:
-+ TRACE_MSG ("DEVICE DESTROY");
-+ bi_disconnect (usbd_bus, NULL);
-+ bi_disable_endpoints (bus);
-+ if (udc_ops.disable_interrupts) udc_ops.disable_interrupts ();
-+ if (udc_ops.disable) udc_ops.disable ();
-+ break;
-+
-+ case DEVICE_CLOSE:
-+ break;
-+ }
-+ return 0;
-+}
-+
-+
-+/* bi_start_endpoint_in
-+ */
-+int bi_start_endpoint_in (struct usb_bus_instance *bus, struct usb_endpoint_instance *endpoint)
-+{
-+ unsigned long flags;
-+
-+ //printk (KERN_INFO"%s: bus: %p status: %d\n", __FUNCTION__, bus, bus->status);
-+
-+ RETURN_ZERO_IF (!endpoint);
-+ udc_interrupts++;
-+
-+ TRACE_MSG32 ("BI START ENDPOINT IN: tx_urb: %x", (int)endpoint->tx_urb);
-+ local_irq_save (flags);
-+ // call udc_start_endpoint_in IFF we didn't previously have a tx urb
-+ if (!endpoint->tx_urb && bi_tx_next_irq (endpoint)) {
-+ TRACE_MSG16 ("BI START ENDPOINT IN: bEndpointAddress: %x actual_length: %d",
-+ (int)endpoint->bEndpointAddress, endpoint->tx_urb->actual_length);
-+ udc_ops.start_endpoint_in (endpoint);
-+ }
-+ local_irq_restore (flags);
-+ //printk (KERN_INFO"%s: finis\n", __FUNCTION__);
-+ return 0;
-+}
-+
-+/* bi_start_endpoint_out
-+ */
-+int bi_start_endpoint_out (struct usb_bus_instance *bus, struct usb_endpoint_instance *endpoint)
-+{
-+ unsigned long flags;
-+
-+ //printk (KERN_INFO"%s: bus: %p status: %d\n", __FUNCTION__, bus, bus->status);
-+
-+ RETURN_ZERO_IF (!endpoint);
-+ udc_interrupts++;
-+ TRACE_MSG32 ("BI START ENDPOINT OUT: rcv_urb: %x", (int)endpoint->rcv_urb);
-+ local_irq_save (flags);
-+ // call udc_start_endpoint_OUT IFF we didn't previously have a rcv urb
-+ if (!endpoint->rcv_urb && bi_rcv_next_irq (endpoint)) {
-+ TRACE_MSG16 ("BI START ENDPOINT OUT: bEndpointAddress: %x request_length: %d",
-+ (int)endpoint->bEndpointAddress, endpoint->rcv_urb->request_length);
-+ udc_ops.start_endpoint_out (endpoint);
-+ }
-+ local_irq_restore (flags);
-+ //printk (KERN_INFO"%s: finis\n", __FUNCTION__);
-+ return 0;
-+}
-+
-+
-+/* bi_cancel_urb_irq - cancel sending an urb
-+ * Used by the USB Device Core to cancel an urb.
-+ */
-+int bi_cancel_urb_irq (struct urb *urb)
-+{
-+ RETURN_EINVAL_IF (!urb);
-+ switch (urb->endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK) {
-+ case USB_DIR_IN:
-+ //printk (KERN_INFO"%s: IN urb: %p\n", __FUNCTION__, urb);
-+ // is this the active urb?
-+ if (urb->endpoint->tx_urb == urb) {
-+ urb->endpoint->tx_urb = NULL;
-+ if (udc_ops.cancel_in_irq) udc_ops.cancel_in_irq (urb);
-+ }
-+ usbd_urb_sent_finished_irq (urb, SEND_FINISHED_CANCELLED);
-+ break;
-+
-+ case USB_DIR_OUT:
-+ //printk (KERN_INFO"%s: OUT urb: %p\n", __FUNCTION__, urb);
-+ // is this the active urb?
-+ if (urb->endpoint->rcv_urb == urb) {
-+ urb->endpoint->rcv_urb = NULL;
-+ if (udc_ops.cancel_out_irq) udc_ops.cancel_out_irq (urb);
-+ }
-+ TRACE_MSG ("CANCEL RECV URB");
-+ usbd_urb_recv_finished_irq (urb, RECV_CANCELLED);
-+ break;
-+ }
-+ return 0;
-+}
-+
-+struct urb * bi_rcv_complete_irq (struct usb_endpoint_instance *endpoint, int len, int urb_bad)
-+{
-+ struct urb *rcv_urb;
-+
-+ // if we had an urb then update actual_length, dispatch if neccessary
-+ if (likely ( (int) (rcv_urb = endpoint->rcv_urb))) {
-+
-+ //printk (KERN_ERR"%s: actual: %d buffer: %d\n",
-+ // __FUNCTION__, rcv_urb->actual_length, rcv_urb->buffer_length);
-+
-+ TRACE_MSG8 ("BI RCV COMPLETE: actual: %d len: %d bad: %d: status: %d",
-+ rcv_urb->actual_length, len, urb_bad, rcv_urb->status);
-+
-+ TRACE_MSG8 ("BI RCV COMPLETE: request: %d buffer: %d packet: %d transfer: %d",
-+ rcv_urb->request_length, rcv_urb->buffer_length,
-+ endpoint->wMaxPacketSize, endpoint->rcv_transferSize);
-+
-+ // check the urb is ok, are we adding data less than the packetsize
-+ if (!urb_bad && !endpoint->rcv_error && (rcv_urb->bus->status == USBD_OK) && (len <= endpoint->wMaxPacketSize)) {
-+
-+ // increment the received data size
-+ rcv_urb->actual_length += len;
-+
-+ // if the current received data is short (less than full packetsize) which
-+ // indicates the end of the bulk transfer, we have received the maximum
-+ // transfersize, or if we do not have enough room to receive another packet
-+ // then pass this data up to the function driver
-+
-+ // XXX this needs to be fixed, for example the MSC driver
-+ // has varying maximum sizes
-+
-+
-+ if (
-+ ( (len < endpoint->wMaxPacketSize) ||
-+ (rcv_urb->actual_length >= endpoint->rcv_transferSize) ||
-+ (rcv_urb->actual_length >= rcv_urb->request_length) ||
-+ (rcv_urb->actual_length + endpoint->wMaxPacketSize > rcv_urb->buffer_length)))
-+ {
-+#if 0
-+ int i;
-+ for (i = 0; i < rcv_urb->actual_length; TRACE_RECV (rcv_urb->buffer + i), i+= 8);
-+#endif
-+ endpoint->rcv_urb = NULL;
-+ rcv_urb->jiffies = jiffies;
-+ rcv_urb->framenum = udc_ops.framenum ? udc_ops.framenum () : 0;
-+ TRACE_MSG32 ("BI RCV COMPLETE: finished length: %d", rcv_urb->actual_length);
-+ TRACE_MSG32 ("BI RCV COMPLETE: framenum: %x", (int) rcv_urb->framenum);
-+ usbd_urb_recv_finished_irq (rcv_urb, RECV_OK);
-+ rcv_urb = NULL;
-+ }
-+ }
-+ else {
-+ rcv_urb->actual_length = 0;
-+ //endpoint->rcv_error = 1;
-+ }
-+ }
-+
-+ // if we don't have an urb see if we can get one
-+ return bi_rcv_next_irq (endpoint);
-+}
-+
-+struct urb * bi_tx_complete_irq (struct usb_endpoint_instance *endpoint, int restart)
-+{
-+ struct urb *tx_urb;
-+
-+ // if we have a tx_urb advance or reset, finish if complete
-+ if ( (likely ( (int)tx_urb = endpoint->tx_urb))) {
-+
-+ TRACE_MSG32 ("BI TX CURRENT TX_URB: %p", (int)endpoint->tx_urb);
-+ TRACE_MSG8 ("BI TX COMPLETE: actual: %d sent: %d last: %d: status: %d",
-+ tx_urb->actual_length, endpoint->sent, endpoint->last, tx_urb->status);
-+
-+ if (likely (!restart)) {
-+ int sent = endpoint->last;
-+ endpoint->sent += sent;
-+ endpoint->last -= sent;
-+ }
-+ else
-+ endpoint->last = 0;
-+
-+ //printk (KERN_INFO"%s: act: %d last: %d sent: %d status: %d flags: %x\n", __FUNCTION__,
-+ // endpoint->tx_urb->actual_length, endpoint->last, endpoint->sent,
-+ // tx_urb->status, tx_urb->flags);
-+
-+ // XXX is the test for bEndpointAddress still appropriate for CONTROL WRITES
-+ if ( ( (tx_urb->actual_length - endpoint->sent) <= 0) && ! (tx_urb->flags & USBD_URB_SENDZLP) ) {
-+ //if (endpoint->bEndpointAddress)
-+ tx_urb->jiffies = jiffies;
-+ tx_urb->framenum = udc_ops.framenum ? udc_ops.framenum () : 0;
-+ TRACE_MSG32 ("BI TX COMPLETE: finished tx_urb: %p", (int)tx_urb);
-+ TRACE_MSG32 ("BI TX COMPLETE: framenum: %x", (int)tx_urb->framenum);
-+ usbd_urb_sent_finished_irq (tx_urb, SEND_FINISHED_OK);
-+ endpoint->tx_urb = NULL;
-+ endpoint->last = endpoint->sent = 0;
-+ }
-+ }
-+ return bi_tx_next_irq (endpoint);
-+}
-+
-+/* ******************************************************************************************* */
-+/* bi_udc_init_irq - initialize USB Device Controller
-+ * Get ready to use the USB Device Controller.
-+ * Register the interrupt handlers and optional IO region.
-+ * Return non-zero for error.
-+ */
-+int bi_udc_init_irq (void)
-+{
-+ THROW_IF (udc_ops.request_udc_irq ? udc_ops.request_udc_irq () : 0, irq_err);
-+ THROW_IF (udc_ops.request_io ? udc_ops.request_io () : 0, io_err);
-+ THROW_IF (udc_ops.init ? udc_ops.init () : 0, init_err);
-+ CATCH (irq_err) {
-+ printk (KERN_ERR"%s: could not request USB IRQ\n", __FUNCTION__);
-+ CATCH (io_err) {
-+ CATCH (init_err) {
-+ printk (KERN_ERR"%s: could not request USB IO space\n", __FUNCTION__);
-+ if (udc_ops.release_io) udc_ops.release_io ();
-+ }
-+ if (udc_ops.release_udc_irq) udc_ops.release_udc_irq ();
-+ }
-+ printk (KERN_ERR"%s: error\n", __FUNCTION__);
-+ return -EINVAL;
-+ }
-+ return 0;
-+}
-+
-+
-+/* bi_udc_exit - Stop using the USB Device Controller
-+ * Stop using the USB Device Controller.
-+ * Shutdown and free dma channels, de-register the interrupt handler.
-+ */
-+void bi_udc_exit (struct usb_bus_instance *bus)
-+{
-+ if (udc_ops.disable_ep) udc_ops.disable_ep (0);
-+ bi_disable_endpoints (bus);
-+ bi_disconnect (usbd_bus, NULL);
-+ if (udc_ops.disable) udc_ops.disable ();
-+ if (udc_ops.release_io) udc_ops.release_io ();
-+ if (udc_ops.release_udc_irq) udc_ops.release_udc_irq ();
-+}
-+
-+
-+/* ************************************************************************************* */
-+
-+int bus_disable (struct usb_bus_instance *bus, char *arg);
-+int bus_enable (struct usb_bus_instance *bus, char *arg);
-+
-+int bi_pm_off (struct usb_bus_instance *bus, char *arg)
-+{
-+ //printk (KERN_INFO"%s:\n", __FUNCTION__);
-+ RETURN_EINVAL_IF (in_interrupt ());
-+ return bus_disable (bus, arg);
-+}
-+
-+int bi_pm_on (struct usb_bus_instance *bus, char *arg)
-+{
-+ //printk (KERN_INFO"%s:\n", __FUNCTION__);
-+ RETURN_EINVAL_IF (in_interrupt ());
-+ return bi_attached (usbd_bus) ? bus_enable (bus, arg) : 0;
-+}
-+
-+int bi_fix_serial_number_str (struct usb_bus_instance *bus)
-+{
-+ char *sp, *dp;
-+ for (sp = dp = usbd_bus->serial_number_str; sp && sp[0]; sp++) {
-+ CONTINUE_IF (!isxdigit (sp[0]));
-+ *dp++ = toupper (*sp);
-+ }
-+ if (dp)
-+ *dp = '\0';
-+ return 0;
-+}
-+
-+int bi_serial_number (struct usb_bus_instance *bus, char *arg)
-+{
-+ char *sp, *dp;
-+ RETURN_EINVAL_IF (in_interrupt ());
-+ if (usbd_bus->serial_number_str)
-+ lkfree (usbd_bus->serial_number_str);
-+ usbd_bus->serial_number_str = lstrdup (arg);
-+ bi_fix_serial_number_str (bus);
-+ return 0;
-+}
-+
-+
-+/* ******************************************************************************************* */
-+
-+struct usb_bus_operations bi_ops = {
-+ bus_enable: bus_enable,
-+ bus_disable: bus_disable,
-+ bus_pm_off: bi_pm_off,
-+ bus_pm_on: bi_pm_on,
-+ bus_serial_number: bi_serial_number,
-+ start_endpoint_in: bi_start_endpoint_in,
-+ start_endpoint_out: bi_start_endpoint_out,
-+ cancel_urb_irq: bi_cancel_urb_irq,
-+ endpoint_halted: bi_endpoint_halted,
-+ device_feature: bi_device_feature,
-+ device_event: bi_device_event_irq,
-+ bus_disconnect: bi_disconnect,
-+ bus_connect: bi_connect,
-+ bus_attached: bi_attached,
-+ bus_connected: bi_connected,
-+ request_endpoints: bi_request_endpoints,
-+ set_endpoints: bi_set_endpoints,
-+};
-+
-+
-+struct usb_bus_driver bi_driver = {
-+ bops: &bi_ops,
-+};
-+
-+void bi_cable_event_irq (void)
-+{
-+ (bi_attached (usbd_bus) ? usbd_enable_irq : usbd_disable_irq) (NULL);
-+}
-+
-+void bi_cable_event (void)
-+{
-+ unsigned long flags;
-+ local_irq_save (flags);
-+ bi_cable_event_irq ();
-+ local_irq_restore (flags);
-+}
-+
-+
-+/* Prevent overlapp of bi administrative functions mainly:
-+ * bus_enable
-+ * bus_disable
-+ * bi_modinit
-+ * bi_modexit
-+ */
-+DECLARE_MUTEX (usbd_bi_sem);
-+
-+int bus_disable_sem (struct usb_bus_instance *bus, char *arg)
-+{
-+ struct bi_data *data;
-+ unsigned long flags;
-+
-+ RETURN_ZERO_IF (usbd_bus_state_enabled != bus->bus_state);
-+ MOD_DEC_USE_COUNT;
-+
-+ bi_disconnect (usbd_bus, NULL);
-+ if (udc_ops.disable) udc_ops.disable ();
-+
-+ local_irq_save (flags);
-+ if (bus->device_state != STATE_ATTACHED) {
-+ usbd_bus_event_irq (bus, DEVICE_RESET, 0);
-+ usbd_bus_event_irq (bus, DEVICE_POWER_INTERRUPTION, 0);
-+ usbd_bus_event_irq (bus, DEVICE_HUB_RESET, 0);
-+ }
-+ usbd_bus_event_irq (bus, DEVICE_DESTROY, 0);
-+ bi_disable_endpoints (bus);
-+ bi_udc_exit (bus);
-+ local_irq_restore (flags);
-+
-+ usbd_disable_function (bus);
-+ bus->bus_state = usbd_bus_state_disabled;
-+ return 0;
-+}
-+
-+int bus_disable (struct usb_bus_instance *bus, char *arg)
-+{
-+ RETURN_EINVAL_IF (in_interrupt ());
-+ down (&usbd_bi_sem);
-+ bus_disable_sem (bus, arg);
-+ up (&usbd_bi_sem);
-+ return 0;
-+}
-+
-+void bi_startup_events(void)
-+{
-+ if (udc_ops.startup_events)
-+ udc_ops.startup_events();
-+ else {
-+ usbd_bus_event_irq (usbd_bus, DEVICE_INIT, 0);
-+ usbd_bus_event_irq (usbd_bus, DEVICE_CREATE, 0);
-+ usbd_bus_event_irq (usbd_bus, DEVICE_HUB_CONFIGURED, 0);
-+ usbd_bus_event_irq (usbd_bus, DEVICE_RESET, 0);
-+ }
-+}
-+
-+int bus_enable (struct usb_bus_instance *bus, char *arg)
-+{
-+ struct usb_endpoint_instance *endpoint;
-+ int rc = -EINVAL;
-+ unsigned long flags;
-+
-+ //printk (KERN_INFO "%s: %s bus_state: %d\n", __FUNCTION__, arg ? arg : " (NULL)", bus->bus_state);
-+ RETURN_EINVAL_IF (in_interrupt ());
-+
-+ down (&usbd_bi_sem);
-+ bus_disable_sem (bus, arg);
-+ MOD_INC_USE_COUNT;
-+
-+ local_irq_save (flags);
-+ do {
-+ // check if we can see the UDC and register, then enable the function
-+ BREAK_IF (bi_udc_init_irq ());
-+ BREAK_IF (usbd_enable_function_irq (bus, arg));
-+ rc = 0;
-+
-+ // setup endpoint zero
-+ endpoint = bus->endpoint_array + 0;
-+ endpoint->bEndpointAddress = 0;
-+
-+ //endpoint->tx_attributes = 0;
-+ endpoint->wMaxPacketSize = udc_ops.ep0_packetsize;
-+ endpoint->rcv_transferSize = 255; // XXX should this be higher
-+ endpoint->wMaxPacketSize = udc_ops.ep0_packetsize;
-+ if (udc_ops.setup_ep) udc_ops.setup_ep (0, endpoint);
-+
-+ // hopefully device enumeration will finish this process
-+ bi_startup_events ();
-+ trace_reinit ();
-+ } while (0);
-+ local_irq_restore (flags);
-+ up (&usbd_bi_sem);
-+
-+ //printk (KERN_INFO"%s: finis\n", __FUNCTION__);
-+ if (rc) {
-+ printk (KERN_INFO "%s: failed\n", __FUNCTION__);
-+ bi_udc_exit (NULL);
-+ }
-+ return rc;
-+}
-+
-+/* ************************************************************************************* */
-+
-+static int bi_modinit (void)
-+{
-+ extern const char *usbd_bi_module_info (void);
-+ //struct bi_data *data = NULL;
-+ static int first = 0;
-+
-+ printk (KERN_INFO "%s: %s serial: \"%s\"\n", __FUNCTION__, usbd_bi_module_info (),
-+ serial_number_str && strlen (serial_number_str) ? serial_number_str : "");
-+
-+ down (&usbd_bi_sem);
-+
-+ THROW_IF (trace_init (), error);
-+ THROW_IF (usbd_bus, error);
-+
-+ // Set the UDC defaults
-+ udc_ops.disable_interrupts ();
-+ bi_disconnect (usbd_bus, NULL);
-+
-+ bi_driver.name = udc_ops.name;
-+ bi_driver.max_endpoints = udc_ops.max_endpoints;
-+ bi_driver.maxpacketsize = udc_ops.ep0_packetsize;
-+
-+ // register this bus interface driver and create the device driver instance
-+ THROW_IF (! (usbd_bus = usbd_register_bus (&bi_driver)), error);
-+
-+ //THROW_IF (! (data = ckmalloc (sizeof (struct bi_data), GFP_KERNEL)), error);
-+ //memset (data, 0, sizeof (struct bi_data));
-+ //usbd_bus->privdata = data;
-+
-+ // see if we can scrounge up something to set a sort of unique device address
-+ if (udc_ops.serial_init ? udc_ops.serial_init () : -EINVAL) {
-+ if (serial_number_str && strlen (serial_number_str))
-+ bi_serial_number (usbd_bus, serial_number_str);
-+ }
-+ else
-+ bi_fix_serial_number_str (usbd_bus);
-+
-+ have_cable_irq = udc_ops.request_cable_irq ? !udc_ops.request_cable_irq () : 0;
-+ up (&usbd_bi_sem);
-+
-+#if defined (MODULE) || !defined (CONFIG_USBD_BI_DELAY_ENABLE)
-+ // if we are connected OR if we don't have a cable irq fake an attach event
-+
-+ // XXX this is not quite correct, if not attached then an enable
-+ // will be required later if attached on a system that does not have
-+ // cable event.
-+ //
-+ //if (!have_cable_irq || udc_attached ()) {
-+ // Even if we have a cable irq, we need to check the current status,
-+ // because the cable may have been attached before we installed the handler.
-+
-+ if (bi_attached (usbd_bus)) {
-+ printk (KERN_INFO"%s: cable attached\n", __FUNCTION__);
-+ bi_cable_event ();
-+ }
-+#endif
-+ return 0;
-+
-+ CATCH (error) {
-+ printk (KERN_ERR"%s: error loading module\n", __FUNCTION__);
-+ //if (data)
-+ // lkfree (data);
-+ if (usbd_bus)
-+ usbd_deregister_bus (usbd_bus);
-+ usbd_bus = NULL;
-+ trace_exit ();
-+ up (&usbd_bi_sem);
-+ printk (KERN_INFO"%s: UP\n", __FUNCTION__);
-+ return -EINVAL;
-+ }
-+}
-+
-+#ifdef MODULE
-+/* bi_modexit - This is *only* used for drivers compiled and used as a module.
-+ */
-+static void bi_modexit (void)
-+{
-+ down (&usbd_bi_sem);
-+ RETURN_IF (!usbd_bus);
-+
-+ if (have_cable_irq)
-+ udc_ops.release_cable_irq ();
-+
-+ bus_disable_sem (usbd_bus, NULL);
-+
-+ //if ( (usbd_bus->privdata))
-+ // lkfree (usbd_bus->privdata);
-+ //usbd_bus->privdata = NULL;
-+
-+ if (usbd_bus->serial_number_str)
-+ lkfree (usbd_bus->serial_number_str);
-+
-+ usbd_deregister_bus (usbd_bus);
-+ usbd_bus = NULL;
-+ trace_exit ();
-+}
-+
-+module_exit (bi_modexit);
-+#endif
-+
-+module_init (bi_modinit);
-+
-diff -Nru a/drivers/usbd/usbd-bi.h b/drivers/usbd/usbd-bi.h
---- /dev/null Wed Dec 31 16:00:00 1969
-+++ b/drivers/usbd/usbd-bi.h Fri Feb 27 14:22:51 2004
-@@ -0,0 +1,196 @@
-+/*
-+ * usbd/usbd-bi.h
-+ *
-+ * Copyright (c) 2004 Belcarra
-+ *
-+ * By:
-+ * Stuart Lynne <sl@belcarra.com>,
-+ * Tom Rushworth <tbr@belcarra.com>,
-+ * Bruce Balden <balden@belcarra.com>
-+ *
-+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
-+ *
-+ */
-+
-+struct udc_ops {
-+
-+ /* mandatory */
-+ int max_endpoints;
-+ int ep0_packetsize;
-+ char *name;
-+
-+ void (*start_endpoint_in)
-+ (struct usb_endpoint_instance *); /* start an IN urb */
-+ void (*start_endpoint_out)
-+ (struct usb_endpoint_instance *); /* start an OUT urb */
-+
-+ int (*request_endpoints)
-+ (struct usb_endpoint_map *, int, struct usb_endpoint_request *);
-+
-+ /* optional */
-+
-+ int (*set_endpoints)
-+ (int , struct usb_endpoint_map *);
-+
-+ void (*cancel_in_irq) (struct urb *urb); /* cancel active urb for IN endpoint */
-+ void (*cancel_out_irq) (struct urb *urb); /* cancel active urb for OUT endpoint */
-+
-+ void (*reset_ep) (unsigned int ep); /* reset requested endpoint */
-+ int (*endpoint_halted) (unsigned int ep); /* Return non-zero if requested endpoint is halted */
-+
-+ void (*set_address) (unsigned char address);/* set the device USB address */
-+ int (* serial_init) (void); /* get device serial number if available */
-+ void (*setup_ep) (unsigned int ep,
-+ struct usb_endpoint_instance *endpoint); /* setup specified endpoint for use */
-+ void (*disable_ep) (unsigned int ep); /* disable specified endpoint */
-+ void (*stall_ep) (u32 ); /* stall endpoint */
-+
-+ int (*attached) (void); /* return non-zero if the USB cable connected */
-+ int (*connected) (void); /* return non-zero if the USB pullup resistor is enabled */
-+ void (*connect) (void); /* enable USB pullup resistor to enable connection to host */
-+ void (*disconnect) (void); /* disable pullup resistor to disconnect from host */
-+
-+ int (*framenum) (void); /* fetch SOF framenum */
-+
-+ void (*all_interrupts) (void); /* enable all interrupts for normal operation */
-+ void (*suspended_interrupts) (void); /* enable interrupts for suspended operation */
-+ void (*disable_interrupts) (void); /* disable all interrupts */
-+
-+ void (*enable) (void); /* enable the UDC */
-+ void (*disable) (void); /* disable the UDC */
-+
-+ void (*startup_events) (void); /* perform UDC specific USB events */
-+ int (*init) (void); /* initialize USB Device Controller */
-+
-+ int (*request_udc_irq) (void); /* return non-zero if request for UDC interrupt fails */
-+ int (*request_cable_irq) (void); /* return non-zero if request for Cable interrupt fails */
-+ int (*request_io) (void); /* return non-zero if request UDC IO region fails */
-+ void (*release_udc_irq) (void); /* release USB Device Controller interrupt */
-+ void (*release_cable_irq) (void); /* release Cable interrupt */
-+ void (*release_io) (void); /* release UDC IO region */
-+};
-+
-+extern struct udc_ops udc_ops;
-+extern unsigned int udc_interrupts;
-+extern struct usb_bus_instance *usbd_bus;
-+
-+void bi_cable_event_irq (void); /* called from cradle interrupt handler */
-+void bi_cable_event (void);
-+
-+/* bi_rcv_next_irq - complete a receive
-+ * Called from rcv interrupt to complete.
-+ */
-+static __inline__ struct urb * bi_rcv_next_irq (struct usb_endpoint_instance *endpoint)
-+{
-+ if (!endpoint->rcv_urb)
-+ if ( (endpoint->rcv_urb = usbd_first_urb_detached_irq (&endpoint->rdy)))
-+ endpoint->rcv_urb->status = RECV_IN_PROGRESS;
-+ TRACE_MSG32 ("BI RCV_URB: %p", (int)endpoint->rcv_urb);
-+ return endpoint->rcv_urb;
-+}
-+
-+
-+/* bi_rcv_complete_irq - complete a receive
-+ * Called from rcv interrupt to complete.
-+ */
-+struct urb * bi_rcv_complete_irq (struct usb_endpoint_instance *endpoint, int len, int urb_bad);
-+
-+static __inline__ void bi_rcv_cancelled_irq (struct usb_endpoint_instance *endpoint)
-+{
-+ struct urb *rcv_urb;
-+
-+ TRACE_MSG32 ("BI RCV CANCELLED: %p", (int) endpoint->rcv_urb);
-+ RETURN_IF (! (rcv_urb = endpoint->rcv_urb));
-+ printk (KERN_INFO"%s: rcv_urb: %p\n", __FUNCTION__, endpoint->rcv_urb);
-+ usbd_urb_recv_finished_irq (rcv_urb, RECV_CANCELLED);
-+ endpoint->sent = endpoint->last = 0;
-+ endpoint->rcv_urb = NULL;
-+ printk (KERN_INFO"%s: rcv_urb: %p\n", __FUNCTION__, endpoint->rcv_urb);
-+}
-+
-+
-+/* bi_tx_next_irq - complete a receive
-+ * Called from tx interrupt to complete.
-+ */
-+static __inline__ struct urb * bi_tx_next_irq (struct usb_endpoint_instance *endpoint)
-+{
-+ if (!endpoint->tx_urb)
-+ if ( (endpoint->tx_urb = usbd_first_urb_detached_irq (&endpoint->tx))) {
-+#if 0
-+ int i;
-+ TRACE_MSG16 ("NEXT TX: length: %d flags: %x", endpoint->tx_urb->actual_length, endpoint->tx_urb->flags);
-+ for (i = 0; i < endpoint->tx_urb->actual_length; TRACE_SENT (endpoint->tx_urb->buffer + i), i+= 8);
-+#endif
-+ endpoint->tx_urb->status = SEND_IN_PROGRESS;
-+ }
-+ TRACE_MSG32 ("BI TX NEXT TX_URB: %p", (int)endpoint->tx_urb);
-+ return endpoint->tx_urb;
-+}
-+
-+
-+/* bi_tx_complete_irq - complete a transmit
-+ * Called from tx interrupt to complete.
-+ */
-+struct urb * bi_tx_complete_irq (struct usb_endpoint_instance *endpoint, int restart);
-+
-+static __inline__ void bi_tx_cancelled_irq (struct usb_endpoint_instance *endpoint)
-+{
-+ struct urb *tx_urb;
-+
-+ TRACE_MSG32 ("BI TX CANCELLED: %p", (int) endpoint->tx_urb);
-+ RETURN_IF (! (tx_urb = endpoint->tx_urb));
-+ usbd_urb_sent_finished_irq (tx_urb, SEND_FINISHED_CANCELLED);
-+ endpoint->sent = endpoint->last = 0;
-+ endpoint->tx_urb = NULL;
-+}
-+
-+static __inline__ int bi_tx_sendzlp (struct usb_endpoint_instance *endpoint)
-+{
-+ struct urb *tx_urb = endpoint->tx_urb;
-+ RETURN_ZERO_IF (!tx_urb || (tx_urb->actual_length != endpoint->sent) || ! (tx_urb->flags & USBD_URB_SENDZLP));
-+ tx_urb->flags &= ~USBD_URB_SENDZLP;
-+ return 1;
-+}
-+
-+/* bi_rcv_complete_irq - complete a receive
-+ * Called from rcv interrupt to complete.
-+ */
-+static __inline__ void bi_rcv_fast_complete_irq (struct usb_endpoint_instance *endpoint, struct urb *rcv_urb)
-+{
-+ TRACE_MSG32 ("BI RCV FAST COMPLETE: %d", rcv_urb->actual_length);
-+ usbd_urb_recv_finished_irq (rcv_urb, RECV_OK);
-+}
-+
-+/* bi_recv_setup - process a device request
-+ * Note that we verify if a receive urb has been queued for H2D with non-zero wLength
-+ * and return -EINVAL to stall if the upper layers have not properly tested for and
-+ * setup a receive urb in this case.
-+ */
-+static __inline__ int bi_recv_setup_irq (struct usb_device_request *request)
-+{
-+ struct usb_endpoint_instance *endpoint = usbd_bus->endpoint_array + 0;
-+ TRACE_SETUP (request);
-+ RETURN_EINVAL_IF (usbd_recv_setup_irq (usbd_bus->ep0, request)); // fail if already failed
-+ RETURN_ZERO_IF ( (request->bmRequestType & USB_REQ_DIRECTION_MASK) == USB_REQ_DEVICE2HOST);
-+ RETURN_ZERO_IF (!le16_to_cpu (request->wLength));
-+ RETURN_EINVAL_IF (!endpoint->rcv_urb);
-+ return 0;
-+}
-+
-+/* bi_ep0_reset_irq - reset ep0 endpoint
-+ */
-+static void __inline__ bi_ep0_reset_endpoint_irq (struct usb_endpoint_instance *endpoint)
-+{
-+ bi_tx_cancelled_irq (endpoint);
-+ bi_rcv_cancelled_irq (endpoint);
-+ endpoint->sent = endpoint->last = 0;
-+}
-diff -Nru a/drivers/usbd/usbd-bops.c b/drivers/usbd/usbd-bops.c
---- /dev/null Wed Dec 31 16:00:00 1969
-+++ b/drivers/usbd/usbd-bops.c Fri Feb 27 14:22:51 2004
-@@ -0,0 +1,889 @@
-+/*
-+ * usbd/usbd-bops.c - USB Device Prototype
-+ *
-+ * Copyright (c) 2004 Belcarra
-+ *
-+ * Adapted from earlier work:
-+ * Copyright (c) 2002, 2003 Belcarra
-+ * Copyright (c) 2000, 2001, 2002 Lineo
-+ * Copyright (c) 2001 Hewlett Packard
-+ *
-+ * By:
-+ * Stuart Lynne <sl@belcarra.com>,
-+ * Tom Rushworth <tbr@belcarra.com>,
-+ * Bruce Balden <balden@belcarra.com>
-+ *
-+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
-+ *
-+ */
-+
-+#include <linux/config.h>
-+#include <linux/module.h>
-+
-+#include <linux/init.h>
-+#include <linux/kernel.h>
-+#include <linux/list.h>
-+#include <asm/uaccess.h>
-+#include <linux/slab.h>
-+#include <linux/interrupt.h>
-+#include <linux/smp_lock.h>
-+#include <linux/ctype.h>
-+#include <linux/timer.h>
-+#include <linux/string.h>
-+
-+#include "usbd-chap9.h"
-+#include "usbd-mem.h"
-+#include "usbd.h"
-+#include "usbd-func.h"
-+#include "usbd-bus.h"
-+
-+/* Private defs from usbd-func.c *************************************************************** */
-+/* Function driver enable/disable
-+ *
-+ * Called by usbd_enable_function/usbd_disable_function to call the selected
-+ * function drivers function_enable or function_disable function.
-+ */
-+int usbd_function_enable (struct usb_bus_instance *, struct usb_function_instance *);
-+void usbd_function_disable(struct usb_function_instance *);
-+void usbd_func_event_irq(struct usb_bus_instance *, struct usb_function_instance *, usb_device_event_t , int );
-+int usbd_strings_init (void);
-+void usbd_strings_exit(void);
-+void usbd_urb_callback (struct urb *urb, int rc);
-+
-+/* List support functions ******************************************************************** */
-+
-+/*
-+ * Structure member address manipulation macros.
-+ * These are used by client code (code using the urb_link routines), since
-+ * the urb_link structure is embedded in the client data structures.
-+ *
-+ * Note: a macro offsetof equivalent to member_offset is defined in stddef.h
-+ * but this is kept here for the sake of portability.
-+ *
-+ * p2surround returns a pointer to the surrounding structure given
-+ * type of the surrounding structure, the name memb of the structure
-+ * member pointed at by ptr. For example, if you have:
-+ *
-+ * struct foo {
-+ * int x;
-+ * float y;
-+ * char z;
-+ * } thingy;
-+ *
-+ * char *cp = &thingy.z;
-+ *
-+ * then
-+ * &thingy == p2surround(struct foo, z, cp)
-+ */
-+
-+#define _cv_(ptr) ((char*)(void*)(ptr))
-+#define member_offset(type,memb) (_cv_(&(((type*)0)->memb))-(char*)0)
-+#define p2surround(type,memb,ptr) ((type*)(void*)(_cv_(ptr)-member_offset(type,memb)))
-+
-+static inline struct usb_function_driver *list_entry_function (const struct list_head *le)
-+{
-+ return list_entry (le, struct usb_function_driver, drivers);
-+}
-+
-+
-+/*
-+ * Append an urb_link (or a whole list of
-+ * urb_links) to the tail of another list
-+ * of urb_links.
-+ */
-+static __inline__ void urb_append_irq (urb_link * hd, struct urb *urb)
-+{
-+ if (hd && urb) {
-+ urb_link *new = &urb->link;
-+
-+#ifdef C2L_SINGLETON_ONLY
-+ // This _assumes_ the new urb is a singleton,
-+ // but allows it to have an uninitialized link.
-+ //printk(KERN_DEBUG"urb_append: hd: %p n:%p p:%p new: %p n:%p p:%p\n", hd, hd->next, hd->prev, new, new->next, new->prev);
-+
-+ new->prev = hd->prev;
-+ new->next = hd;
-+
-+ hd->prev->next = new;
-+ hd->prev = new;
-+#else
-+ // This allows the new urb to be a list of urbs,
-+ // with new pointing at the first, but the link
-+ // must be initialized.
-+ // Order is important here...
-+ urb_link *pul = hd->prev;
-+ new->prev->next = hd;
-+ hd->prev = new->prev;
-+ new->prev = pul;
-+ pul->next = new;
-+#endif
-+ }
-+}
-+
-+/*
-+ * Return the first urb_link in a list with a distinguished
-+ * head "hd", or NULL if the list is empty. This will also
-+ * work as a predicate, returning NULL if empty, and non-NULL
-+ * otherwise.
-+ *
-+ * Called from interrupt.
-+ */
-+static __inline__ urb_link *first_urb_link_irq (urb_link * hd)
-+{
-+ urb_link *nx;
-+ return (!hd || !(nx = hd->next) || (nx == hd)) ? NULL : nx;
-+}
-+
-+/*
-+ * Return the first urb in a list with a distinguished
-+ * head "hd", or NULL if the list is empty.
-+ *
-+ * Called from interrupt.
-+ */
-+static __inline__ struct urb *first_urb_irq (urb_link * hd)
-+{
-+ urb_link *nx;
-+ return (!(nx = first_urb_link_irq (hd))) ? NULL : p2surround (struct urb, link, nx);
-+}
-+
-+/*
-+ * Detach and return the first urb in a list with a distinguished
-+ * head "hd", or NULL if the list is empty.
-+ */
-+struct urb *usbd_first_urb_detached_irq (urb_link * hd)
-+{
-+ struct urb *urb;
-+ urb_link *ul;
-+ RETURN_NULL_IF (!(urb = first_urb_irq (hd)));
-+ ul = &urb->link;
-+ ul->next->prev = ul->prev;
-+ ul->prev->next = ul->next;
-+ ul->prev = ul->next = ul;
-+ return urb;
-+}
-+
-+static __inline__ void urb_append(urb_link *hd, struct urb *urb)
-+{
-+ unsigned long flags;
-+ local_irq_save (flags);
-+ urb_append_irq(hd, urb);
-+ local_irq_restore (flags);
-+}
-+
-+/* usbd_urb_sent_finished_irq - tell function that an urb has been transmitted.
-+ *
-+ * Must be called from an interrupt or with interrupts disabled.
-+ *
-+ * Used by a USB Bus driver to pass a sent urb back to the function
-+ * driver via the endpoints done queue.
-+ */
-+void usbd_urb_sent_finished_irq (struct urb *urb, int rc)
-+{
-+ //printk(KERN_INFO"%s: urb: %p\n", __FUNCTION__, urb);
-+ urb->status = rc;
-+ urb->jiffies = jiffies;
-+ if (USBD_OK != urb->bus->status)
-+ usbd_urb_callback(urb, urb->status);
-+ else {
-+ urb_append_irq (&(urb->endpoint->done), urb);
-+ RETURN_IF ( urb->bus->device_bh.sync);
-+ queue_task (&urb->bus->device_bh, &tq_immediate);
-+ mark_bh (IMMEDIATE_BH);
-+ }
-+}
-+
-+
-+/* usbd_urb_recv_finished_irq - tell function that an urb has been received.
-+ *
-+ * Must be called from an interrupt or with interrupts disabled.
-+ *
-+ * Used by a USB Bus driver to pass a sent urb back to the function
-+ * driver via the endpoints done queue.
-+ */
-+void usbd_urb_recv_finished_irq (struct urb *urb, int rc)
-+{
-+ urb->status = rc;
-+ urb->jiffies = jiffies;
-+ if (USBD_OK != urb->bus->status)
-+ usbd_urb_callback (urb, rc);
-+ else {
-+ urb_append_irq (&(urb->endpoint->rcv), urb);
-+ RETURN_IF (urb->bus->device_bh.sync);
-+ queue_task (&urb->bus->device_bh, &tq_immediate);
-+ mark_bh (IMMEDIATE_BH);
-+ }
-+}
-+
-+
-+/* first_urb_detached -
-+ *
-+ * Detach and return the first urb in a list with a distinguished
-+ * head "hd", or NULL if the list is empty.
-+ *
-+ */
-+static __inline__ struct urb *first_urb_detached (urb_link * hd)
-+{
-+ struct urb *urb;
-+ unsigned long flags;
-+ local_irq_save (flags);
-+ urb = usbd_first_urb_detached_irq (hd);
-+ local_irq_restore (flags);
-+ return urb;
-+}
-+
-+
-+/* Private defs from usbd-fops.c *************************************************************** */
-+
-+
-+extern struct usb_function_driver ep0_driver;
-+extern struct list_head usbd_function_drivers;
-+extern struct usb_bus_instance *usbd_bus_instance;
-+
-+#define LANGID_ENGLISH "\011"
-+#define LANGID_US_ENGLISH "\004"
-+#define LANGIDs LANGID_US_ENGLISH LANGID_ENGLISH
-+
-+/* usbd_flush_endpoint_irq - flush urbs from endpoint
-+ *
-+ * Iterate across the approrpiate tx or rcv list and cancel any outstanding urbs.
-+ */
-+void usbd_flush_endpoint_irq (struct usb_endpoint_instance *endpoint)
-+{
-+ struct urb *urb;
-+ //printk(KERN_INFO"%s: bEndpointAddress: %d\n", __FUNCTION__, endpoint->bEndpointAddress);
-+ if ((urb = endpoint->tx_urb))
-+ usbd_cancel_urb_irq(urb);
-+
-+ for (; (urb = usbd_first_urb_detached_irq (&endpoint->tx)); usbd_cancel_urb_irq(urb));
-+
-+ if ((urb = endpoint->rcv_urb))
-+ usbd_cancel_urb_irq(urb);
-+
-+ for (; (urb = usbd_first_urb_detached_irq (&endpoint->rdy)); usbd_cancel_urb_irq(urb));
-+}
-+
-+/* usbd_flush_endpoint - flush urbs from endpoint
-+ *
-+ * Iterate across the approrpiate tx or rcv list and cancel any outstanding urbs.
-+ */
-+void usbd_flush_endpoint (struct usb_endpoint_instance *endpoint)
-+{
-+ unsigned long flags;
-+ local_irq_save (flags);
-+ usbd_flush_endpoint_irq(endpoint);
-+ local_irq_restore (flags);
-+}
-+
-+/* usbd_endpoint_halted
-+ *
-+ * Return non-zero if endpoint is halted.
-+ */
-+int usbd_endpoint_halted (struct usb_function_instance *function, int endpoint)
-+{
-+ //printk(KERN_INFO"%s:\n", __FUNCTION__);
-+ return function->bus->driver->bops->endpoint_halted (function->bus, endpoint);
-+}
-+
-+
-+/* usbd_device_feature - set usb device feature
-+ *
-+ * Return non-zero if error
-+ */
-+int usbd_device_feature (struct usb_function_instance *function, int endpoint, int feature)
-+{
-+ //printk(KERN_INFO"%s:\n", __FUNCTION__);
-+ return function->bus->driver->bops->device_feature (function->bus, endpoint, feature);
-+}
-+
-+/* usbd_cancel_urb_irq - cancel an urb being sent
-+ *
-+ * Return non-zero if error
-+ */
-+int usbd_cancel_urb_irq (struct urb *urb)
-+{
-+ //printk(KERN_INFO"%s: urb: %p\n", __FUNCTION__, urb);
-+ // XXX should we do usbd_dealloc_urb(urb);
-+ return urb->bus->driver->bops->cancel_urb_irq (urb);
-+}
-+
-+/* usbd_send_urb - submit a urb to send
-+ *
-+ * Used by a USB Function driver to submit data to be sent in an urb to the
-+ * appropriate USB Bus driver via the endpoints transmit queue.
-+ *
-+ * Return non-zero if error
-+ */
-+int usbd_send_urb (struct urb *urb)
-+{
-+ //printk(KERN_INFO"%s: urb: %p length: %d\n", __FUNCTION__, urb, urb->actual_length);
-+ //RETURN_EINVAL_IF (USBD_OK != urb->bus->status);
-+ RETURN_EINVAL_IF (urb->endpoint->bEndpointAddress && (USBD_OK != urb->bus->status));
-+ urb->status = SEND_IN_QUEUE;
-+ urb->jiffies = jiffies;
-+ urb_append (&(urb->endpoint->tx), urb);
-+ return urb->bus->driver->bops->start_endpoint_in(urb->bus, urb->endpoint);
-+}
-+
-+/* usbd_start_recv - recycle a received urb
-+ *
-+ * Used by a USB Function interface driver to recycle an urb.
-+ *
-+ * Return non-zero if error
-+ */
-+int usbd_start_recv (struct urb *urb)
-+{
-+ //printk(KERN_INFO"%s: urb: %p\n", __FUNCTION__, urb);
-+ RETURN_EINVAL_IF (urb->endpoint->bEndpointAddress && (USBD_OK != urb->bus->status));
-+ urb->actual_length = 0;
-+ urb->status = RECV_IN_QUEUE;
-+ urb->jiffies = jiffies;
-+ urb_append (&(urb->endpoint->rdy), urb);
-+ urb->bus->driver->bops->start_endpoint_out(urb->bus, urb->endpoint);
-+ //printk(KERN_INFO"%s: finis\n", __FUNCTION__, urb);
-+ return 0;
-+}
-+
-+/* usbd_alloc_string_zero - allocate a string descriptor and return index number
-+ *
-+ * Find an empty slot in index string array, create a corresponding descriptor
-+ * and return the slot number.
-+ */
-+__u8 usbd_alloc_string_zero (char *str)
-+{
-+ __u8 bLength;
-+ __u16 *wData;
-+ struct usb_string_descriptor *string;
-+
-+ RETURN_ZERO_IF(usb_strings[0] != NULL);
-+
-+ bLength = sizeof (struct usb_string_descriptor) + strlen (str);
-+
-+ RETURN_ZERO_IF(!(string = ckmalloc (bLength, GFP_KERNEL)));
-+
-+ string->bLength = bLength;
-+ string->bDescriptorType = USB_DT_STRING;
-+
-+ for (wData = string->wData; *str; str += 2) {
-+ *wData = (__u16) ((str[0] << 8 | str[1]));
-+ wData++;
-+ }
-+ usb_strings[0] = string; // store in string index array
-+ return 0;
-+}
-+
-+
-+int usbd_strings_init (void)
-+{
-+ //printk(KERN_INFO"%s: usb_strings: %p\n", __FUNCTION__, usb_strings);
-+ RETURN_ZERO_IF(usb_strings);
-+ usbd_maxstrings = MIN(usbd_maxstrings, 254);
-+
-+ RETURN_EINVAL_IF (!(usb_strings = ckmalloc (sizeof (struct usb_string_descriptor *) * usbd_maxstrings, GFP_KERNEL)));
-+ if (usbd_alloc_string_zero (LANGIDs) != 0) {
-+ lkfree (usb_strings);
-+ return -1;
-+ }
-+ return 0;
-+}
-+
-+void usbd_strings_exit(void)
-+{
-+ int i;
-+ //printk(KERN_INFO"%s: usb_strings: %p\n", __FUNCTION__, usb_strings);
-+ RETURN_IF (!usb_strings);
-+ for (i = 0; i < usbd_maxstrings; i++)
-+ usbd_dealloc_string(i);
-+ lkfree (usb_strings);
-+ usb_strings = NULL;
-+}
-+
-+static usb_device_state_t event_states[DEVICE_CLOSE] = {
-+ STATE_UNKNOWN, STATE_INIT, STATE_ATTACHED, STATE_POWERED,
-+ STATE_DEFAULT, STATE_ADDRESSED, STATE_CONFIGURED, STATE_UNKNOWN,
-+ STATE_UNKNOWN, STATE_UNKNOWN, STATE_ADDRESSED, STATE_SUSPENDED,
-+ STATE_UNKNOWN, STATE_POWERED, STATE_ATTACHED,
-+};
-+
-+static usb_device_status_t event_status[DEVICE_CLOSE+1] = {
-+ USBD_UNKNOWN, // DEVICE_UNKNOWN
-+ USBD_OPENING, // DEVICE_INIT
-+ USBD_OPENING, // DEVICE_CREATE
-+ USBD_OPENING, // DEVICE_HUB_CONFIGURED
-+ USBD_RESETING, // DEVICE_RESET
-+ USBD_OK, // DEVICE_ADDRESS_ASSIGNED
-+ USBD_OK, // DEVICE_CONFIGURED
-+ USBD_OK, // DEVICE_SET_INTERFACE
-+ USBD_OK, // DEVICE_SET_FEATURE
-+ USBD_OK, // DEVICE_CLEAR_FEATURE
-+ USBD_OK, // DEVICE_DE_CONFIGURED
-+ USBD_SUSPENDED, // DEVICE_BUS_INACTIVE
-+ USBD_OK, // DEVICE_BUS_ACTIVITY
-+ USBD_RESETING, // DEVICE_POWER_INTERRUPTION
-+ USBD_RESETING, // DEVICE_HUB_RESET
-+ USBD_CLOSING, // DEVICE_DESTROY
-+ USBD_CLOSED, // DEVICE_CLOSE
-+};
-+
-+/* usbd_device_event_irq - called to respond to various usb events
-+ *
-+ * Used by a Bus driver to indicate an event.
-+ */
-+void usbd_bus_event_irq (struct usb_bus_instance *bus, usb_device_event_t event, int data)
-+{
-+ RETURN_IF(!bus);
-+
-+ //printk(KERN_INFO"%s:\n", __FUNCTION__);
-+ //printk(KERN_INFO"%s: --> event: %d status: %d state: %d\n", __FUNCTION__, event, bus->status, bus->device_state);
-+ switch (event) {
-+ case DEVICE_BUS_INACTIVE:
-+ bus->suspended_state = bus->device_state;
-+ //printk(KERN_INFO"%s: INACTIVE\n", __FUNCTION__);
-+ /* FALL THROUGH */
-+ default:
-+ bus->device_state = event_states[event];
-+ //printk(KERN_INFO"%s: DEFAUL\n", __FUNCTION__);
-+ break;
-+ case DEVICE_UNKNOWN:
-+ //printk(KERN_INFO"%s: UNKNOWN\n", __FUNCTION__);
-+ break;
-+ case DEVICE_BUS_ACTIVITY:
-+ bus->device_state = bus->suspended_state;
-+ //printk(KERN_INFO"%s: ACTIVITY\n", __FUNCTION__);
-+ break;
-+
-+ case DEVICE_SET_INTERFACE:
-+ case DEVICE_SET_FEATURE:
-+ case DEVICE_CLEAR_FEATURE:
-+ //printk(KERN_INFO"%s: SET\n", __FUNCTION__);
-+ break;
-+ }
-+
-+ switch (event) {
-+ case DEVICE_BUS_ACTIVITY:
-+ case DEVICE_BUS_INACTIVE:
-+ BREAK_IF(USBD_CLOSING != bus->status);
-+ /* FALL THROUGH */
-+ default:
-+ bus->status = event_status[event];
-+ //printk(KERN_INFO"%s: DEFAULT\n", __FUNCTION__);
-+ break;
-+ }
-+ //printk(KERN_INFO"%s: <-- event: %d status: %d state: %d\n", __FUNCTION__, event, bus->status, bus->device_state);
-+
-+ // if we lost configuration then get rid of alternate settings
-+ if ((bus->device_state != STATE_CONFIGURED) && bus->bNumInterfaces && bus->alternates) {
-+ bus->bNumInterfaces = 0;
-+ lkfree(bus->alternates);
-+ bus->alternates = NULL;
-+ }
-+ bus->driver->bops->device_event (bus, event, data);
-+ usbd_func_event_irq (bus, bus->ep0, event, data);
-+ usbd_func_event_irq (bus, bus->function_instance, event, data);
-+}
-+
-+
-+/* usbd_bus_event
-+ */
-+void usbd_bus_event (struct usb_bus_instance *bus, usb_device_event_t event, int data)
-+{
-+ unsigned long flags;
-+ local_irq_save (flags);
-+ usbd_bus_event_irq (bus, event, data);
-+ local_irq_restore (flags);
-+}
-+
-+
-+/* usbd_attached - return cable status
-+ *
-+ * Return non-zero if cable attached
-+ */
-+int usbd_attached (struct usb_bus_instance *bus)
-+{
-+ return bus->driver->bops->bus_attached (bus);
-+}
-+
-+/* usbd_connected - return pullup resistor control status
-+ * *
-+ * * Return non-zero if pullup enabled
-+ * */
-+int usbd_connected (struct usb_bus_instance *bus)
-+{
-+ return bus->driver->bops->bus_connected (bus);
-+}
-+
-+
-+/* usbb bus bottom half ********************************************************************** */
-+
-+/*
-+ * Note that all of the functions from here to the end of the file protect against
-+ * overlapped operation using the usbd_bus_sem
-+ *
-+ * usbd_device_bh
-+ *
-+ * usbd_register_bus
-+ * usbd_deregister_bus
-+ * usbd_enable_function_irq
-+ * usbd_disable_function
-+ */
-+DECLARE_MUTEX(usbd_bus_sem);
-+
-+
-+/* usbd_device_bh -
-+ *
-+ * Bottom half handler to process sent or received urbs.
-+ */
-+void usbd_device_bh (void *data)
-+{
-+ int i;
-+ struct usb_bus_instance *bus = data;
-+ struct usb_endpoint_instance *endpoint;
-+
-+ RETURN_IF (!bus || !(endpoint = bus->endpoint_array));
-+ down(&usbd_bus_sem);
-+ // process received and sent urbs
-+ for (i = 0; i < bus->endpoints; i++, endpoint++) {
-+ struct urb *urb;
-+ for (; (urb = first_urb_detached (&endpoint->rcv )); usbd_urb_callback (urb, urb->status));
-+ for (; (urb = first_urb_detached (&endpoint->done)); usbd_urb_callback (urb, urb->status));
-+ }
-+ if (USBD_CLOSING == bus->status)
-+ bus->device_bh.data = NULL;
-+ up(&usbd_bus_sem);
-+}
-+
-+
-+/* usb-device USB BUS INTERFACE generic functions ******************************************** */
-+
-+/*
-+ * Initialize an urb_link to be a single element list.
-+ * If the urb_link is being used as a distinguished list head
-+ * the list is empty when the head is the only link in the list.
-+ */
-+static __inline__ void urb_link_init (urb_link * ul)
-+{
-+ ul->prev = ul->next = ul;
-+}
-+
-+/* usbd_register_bus - called by a USB BUS INTERFACE driver to register a bus driver
-+ *
-+ * Used by a USB Bus interface driver to register itself with the usb device layer.
-+ *
-+ * Return non-zero if error
-+ */
-+struct usb_bus_instance *usbd_register_bus (struct usb_bus_driver *driver)
-+{
-+ int i;
-+ struct usb_bus_instance *bus = NULL;
-+
-+ //printk(KERN_INFO"%s: DOWN USBD_BUS_SEM\n", __FUNCTION__);
-+ down(&usbd_bus_sem);
-+ MOD_INC_USE_COUNT; // QQQ should this be before the down()?
-+
-+ THROW_IF(usbd_bus_instance, error);
-+ THROW_IF((bus = ckmalloc (sizeof (struct usb_bus_instance), GFP_ATOMIC)) == NULL, error);
-+
-+ bus->driver = driver;
-+ bus->endpoints = bus->driver->max_endpoints;
-+
-+ THROW_IF(!(bus->endpoint_array = ckmalloc(sizeof (struct usb_endpoint_instance) * bus->endpoints, GFP_ATOMIC)), error);
-+
-+ for (i = 0; i < bus->endpoints; i++) {
-+ struct usb_endpoint_instance *endpoint = bus->endpoint_array + i;
-+ endpoint->physical_endpoint = i;
-+ urb_link_init (&endpoint->rcv);
-+ urb_link_init (&endpoint->rdy);
-+ urb_link_init (&endpoint->tx);
-+ urb_link_init (&endpoint->done);
-+ }
-+
-+ bus->admin[usbd_admin_enable] = driver->bops->bus_enable;
-+ bus->admin[usbd_admin_disable] = driver->bops->bus_disable;
-+ bus->admin[usbd_admin_disconnect] = driver->bops->bus_disconnect;
-+ bus->admin[usbd_admin_connect] = driver->bops->bus_connect;
-+ bus->admin[usbd_admin_pm_off] = driver->bops->bus_pm_off;
-+ bus->admin[usbd_admin_pm_on] = driver->bops->bus_pm_on;
-+ bus->admin[usbd_admin_serial_number] = driver->bops->bus_serial_number;
-+
-+ THROW_IF((bus->ep0 = ckmalloc (sizeof (struct usb_function_instance), GFP_ATOMIC)) == NULL, error)
-+ bus->ep0->function_driver = &ep0_driver;
-+ bus->ep0->endpointsRequested = 1;
-+ THROW_IF(!(bus->ep0->endpoint_map_array = ckmalloc(sizeof(struct usb_endpoint_map) * 1, GFP_KERNEL)), error);
-+
-+ bus->device_state = STATE_CREATED;
-+ bus->status = USBD_OPENING;
-+
-+ usbd_bus_instance = bus;
-+
-+ CATCH(error) {
-+ if (bus) {
-+ if (bus->endpoint_array)
-+ lkfree(bus->endpoint_array);
-+ lkfree(bus);
-+ }
-+ bus->endpoints = 0;
-+ printk(KERN_INFO"%s: FAILED\n", __FUNCTION__);
-+ bus = NULL;
-+ MOD_DEC_USE_COUNT;
-+ }
-+
-+ up(&usbd_bus_sem);
-+ //printk(KERN_INFO"%s: UP USBD_BUS_SEM\n", __FUNCTION__);
-+ return bus;
-+}
-+
-+/* usbd_deregister_bus - called by a USB BUS INTERFACE driver to deregister a bus driver
-+ *
-+ * Used by a USB Bus interface driver to de-register itself with the usb device
-+ * layer.
-+ */
-+void usbd_deregister_bus (struct usb_bus_instance *bus)
-+{
-+ //printk(KERN_INFO"%s: DOWN USBD_BUS_SEM\n", __FUNCTION__);
-+ down(&usbd_bus_sem);
-+
-+ usbd_bus_instance = NULL;
-+
-+ if (bus->ep0) {
-+ if (bus->ep0->endpoint_map_array)
-+ lkfree(bus->ep0->endpoint_map_array);
-+ lkfree(bus->ep0);
-+ }
-+
-+ lkfree (bus->arg);
-+ lkfree (bus->endpoint_array);
-+ lkfree (bus);
-+ bus->endpoints = 0;
-+ MOD_DEC_USE_COUNT; // QQQ should this be after the up()?
-+ up(&usbd_bus_sem);
-+ //printk(KERN_INFO"%s: UP USBD_BUS_SEM\n", __FUNCTION__);
-+}
-+
-+
-+/* usb-device USB Device generic functions *************************************************** */
-+
-+/* usbd_enable_function_irq - called to enable the desired function
-+ *
-+ * Used by a USB Bus interface driver to create a virtual device.
-+ *
-+ * Return non-zero if error
-+ */
-+int usbd_enable_function_irq (struct usb_bus_instance *bus, char *arg)
-+{
-+ struct usb_function_instance *function = NULL;
-+ struct list_head *lhd;
-+ int len = 0;
-+ int i;
-+ int rc = -EINVAL;
-+ int epn;
-+
-+ //printk(KERN_INFO"%s: DOWN USBD_BUS_SEM\n", __FUNCTION__);
-+ down(&usbd_bus_sem);
-+
-+ if (arg && bus->arg)
-+ lkfree(bus->arg);
-+
-+ if (arg) {
-+ bus->arg = lstrdup(arg);
-+ len = strlen(arg);
-+ }
-+
-+ // initialize the strings pool
-+ THROW_IF(usbd_strings_init (), error);
-+
-+ for (i = 1; i < bus->endpoints; i++) {
-+ struct usb_endpoint_instance *endpoint = bus->endpoint_array + i;
-+ endpoint->rcv_urb = endpoint->tx_urb = NULL;
-+ }
-+
-+ list_for_each (lhd, &usbd_function_drivers) {
-+ struct usb_function_driver *function_driver;
-+ function_driver = list_entry_function (lhd);
-+
-+ printk(KERN_INFO"%s: check: [%s] %s\n", __FUNCTION__,
-+ (arg?arg:""), function_driver->name);
-+
-+ // mode - single, either the first or a named function
-+ CONTINUE_IF(arg && len && strncmp(function_driver->name, arg, len));
-+
-+ //printk(KERN_INFO"%s: found: %s\n", __FUNCTION__, function_driver->name);
-+
-+ THROW_IF (!(function = ckmalloc (sizeof (struct usb_function_instance), GFP_ATOMIC)), error);
-+ function->function_driver = function_driver; // XXX
-+
-+ THROW_IF (!(function->endpoint_map_array = ckmalloc (sizeof(struct usb_endpoint_map) *
-+ function->function_driver->device_description->endpointsRequested,
-+ GFP_KERNEL)), error);
-+
-+ THROW_IF(bus->driver->bops->request_endpoints( function->endpoint_map_array,
-+ function->function_driver->device_description->endpointsRequested,
-+ function->function_driver->device_description->requestedEndpoints), error);
-+
-+ function->endpointsRequested = function->function_driver->device_description->endpointsRequested;
-+ usbd_function_enable (bus, function);
-+ break;
-+ }
-+
-+ if (NULL == function && NULL != arg && 0 != len) {
-+ printk(KERN_INFO"Unknown function driver (len=%d) [%s], known drivers:\n",len,arg);
-+ list_for_each (lhd, &usbd_function_drivers) {
-+ struct usb_function_driver *function_driver = list_entry_function (lhd);
-+ printk(KERN_INFO" [%s]\n", function_driver->name);
-+ }
-+ }
-+
-+ THROW_IF (!(bus->function_instance = function), error);
-+
-+ THROW_IF(bus->driver->bops->set_endpoints( function->function_driver->device_description->endpointsRequested,
-+ function->endpoint_map_array), error);
-+ // device bottom half
-+ bus->device_bh.routine = usbd_device_bh;
-+ bus->device_bh.data = bus;
-+ bus->status = USBD_OK;
-+ bus->bus_state = usbd_bus_state_enabled;
-+ bus->ep0->endpoint_map_array->endpoint = bus->endpoint_array;
-+ THROW_IF (usbd_function_enable (bus, bus->ep0), error);
-+
-+ //printk(KERN_INFO"%s: %d endpoint: %p map: %p\n", __FUNCTION__, 0,
-+ // bus->ep0->endpoint_map_array->endpoint,
-+ // bus->ep0->endpoint_map_array);
-+
-+ // iterate across the logical endpoint map to copy appropriate information
-+ // into the physical endpoint instance array
-+
-+ for (epn = 0; epn < bus->function_instance->endpointsRequested; epn++) {
-+
-+ struct usb_endpoint_map *endpoint_map = bus->function_instance->endpoint_map_array + epn;
-+ int physicalEndpoint = endpoint_map->physicalEndpoint[0];
-+ struct usb_endpoint_instance *endpoint = bus->endpoint_array + physicalEndpoint;
-+
-+ //printk(KERN_INFO"%s: %d endpoint: %p map: %p bEndpointAddress: %02x\n", __FUNCTION__,
-+ // epn, endpoint, endpoint_map, endpoint_map->bEndpointAddress[0]);
-+
-+ endpoint_map->endpoint = endpoint;
-+ endpoint->bEndpointAddress = endpoint_map->bEndpointAddress[0];
-+ endpoint->bmAttributes = endpoint_map->bmAttributes[0];
-+
-+ switch(endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK) {
-+ case USB_DIR_IN:
-+ endpoint->wMaxPacketSize = endpoint_map->wMaxPacketSize[0];
-+ endpoint->last = 0;
-+ endpoint->tx_urb = NULL;
-+ break;
-+
-+ case USB_DIR_OUT:
-+ endpoint->rcv_transferSize = endpoint_map->transferSize[0];
-+ endpoint->wMaxPacketSize = endpoint_map->wMaxPacketSize[0];
-+ endpoint->rcv_urb = NULL;
-+ break;
-+ }
-+ }
-+
-+ rc = 0;
-+
-+ CATCH(error) {
-+ printk(KERN_INFO"%s: FAILED\n", __FUNCTION__);
-+ usbd_strings_exit();
-+ }
-+ up(&usbd_bus_sem);
-+ //printk(KERN_INFO"%s: UP USBD_BUS_SEM\n", __FUNCTION__);
-+ return rc;
-+}
-+
-+/* usbd_disable_function - called to disable the current function
-+ *
-+ * Used by a USB Bus interface driver to destroy a virtual device.
-+ */
-+void usbd_disable_function (struct usb_bus_instance *bus)
-+{
-+ printk(KERN_INFO"%s: DOWN USBD_BUS_SEM\n", __FUNCTION__);
-+ down(&usbd_bus_sem);
-+ // prevent any more bottom half scheduling
-+ bus->status = USBD_CLOSING;
-+ up(&usbd_bus_sem);
-+ //printk(KERN_INFO"%s: UP USBD_BUS_SEM\n", __FUNCTION__);
-+
-+ // wait for pending device bottom half to finish
-+ while (bus->device_bh.data /*|| device->function_bh.data */) {
-+
-+ //printk(KERN_INFO"%s: waiting for usbd_device_bh %ld %p interrupt: %d\n", __FUNCTION__,
-+ // bus->device_bh.sync, bus->device_bh.data, in_interrupt());
-+
-+ // This can probably be either, but for consistency's sake...
-+ queue_task(&bus->device_bh, &tq_immediate);
-+ mark_bh (IMMEDIATE_BH);
-+ // schedule_task(&device->device_bh);
-+
-+ schedule_timeout (2000 * HZ);
-+ }
-+
-+ //printk(KERN_INFO"%s: DOWN USBD_BUS_SEM\n", __FUNCTION__);
-+ down(&usbd_bus_sem);
-+
-+ // tell the function driver to close
-+ usbd_function_disable (bus->ep0);
-+ usbd_function_disable (bus->function_instance);
-+
-+ // free alternates memory
-+ if (/*bus->bNumInterfaces &&*/ bus->alternates) {
-+ bus->bNumInterfaces = 0;
-+ lkfree(bus->alternates);
-+ bus->alternates = NULL;
-+ }
-+ if (bus->function_instance) {
-+ if (bus->function_instance->endpoint_map_array)
-+ lkfree(bus->function_instance->endpoint_map_array);
-+ lkfree(bus->function_instance);
-+ bus->function_instance = NULL;
-+ }
-+ usbd_strings_exit();
-+ bus->status = USBD_CLOSED;
-+ up(&usbd_bus_sem);
-+ printk(KERN_INFO"%s: UP USBD_BUS_SEM\n", __FUNCTION__);
-+}
-+
-+usb_device_state_t usbd_device_state(struct usb_function_instance *function)
-+{
-+ //printk(KERN_INFO"%s: %d\n", __FUNCTION__, function->bus->device_state);
-+ return (function && function->bus) ? function->bus->device_state : STATE_UNKNOWN;
-+}
-+usb_device_state_t usbd_bus_state(struct usb_function_instance *function)
-+{
-+ //printk(KERN_INFO"%s: %d\n", __FUNCTION__, function->bus->bus_state);
-+ return (function && function->bus) ? function->bus->bus_state : usbd_bus_state_unknown;
-+}
-+usb_device_status_t usbd_bus_status(struct usb_function_instance *function)
-+{
-+ //printk(KERN_INFO"%s: %d\n", __FUNCTION__, function->bus->status);
-+ return (function && function->bus) ? function->bus->status : USBD_UNKNOWN;
-+}
-+
-+EXPORT_SYMBOL(usbd_register_bus);
-+EXPORT_SYMBOL(usbd_deregister_bus);
-+EXPORT_SYMBOL(usbd_enable_function_irq);
-+EXPORT_SYMBOL(usbd_disable_function);
-+EXPORT_SYMBOL(usbd_attached);
-+EXPORT_SYMBOL(usbd_send_urb);
-+EXPORT_SYMBOL(usbd_start_recv);
-+EXPORT_SYMBOL(usbd_flush_endpoint);
-+EXPORT_SYMBOL(usbd_cancel_urb_irq);
-+EXPORT_SYMBOL(usbd_bus_event_irq);
-+EXPORT_SYMBOL(usbd_bus_event);
-+EXPORT_SYMBOL(usbd_urb_sent_finished_irq);
-+EXPORT_SYMBOL(usbd_urb_recv_finished_irq);
-+EXPORT_SYMBOL(usbd_device_state);
-+EXPORT_SYMBOL(usbd_bus_state);
-+EXPORT_SYMBOL(usbd_bus_status);
-+EXPORT_SYMBOL(usbd_first_urb_detached_irq);
-+
-diff -Nru a/drivers/usbd/usbd-build.h b/drivers/usbd/usbd-build.h
---- /dev/null Wed Dec 31 16:00:00 1969
-+++ b/drivers/usbd/usbd-build.h Fri Feb 27 14:22:51 2004
-@@ -0,0 +1 @@
-+#define USBD_BUILD "000"
-diff -Nru a/drivers/usbd/usbd-bus.h b/drivers/usbd/usbd-bus.h
---- /dev/null Wed Dec 31 16:00:00 1969
-+++ b/drivers/usbd/usbd-bus.h Fri Feb 27 14:22:51 2004
-@@ -0,0 +1,316 @@
-+/*
-+ * usbd/usbd-bus.c - USB Device Bus Interface Driver Interface
-+ *
-+ * Copyright (c) 2004 Belcarra
-+ *
-+ * Adapted from earlier work:
-+ * Copyright (c) 2002, 2003 Belcarra
-+ * Copyright (c) 2000, 2001, 2002 Lineo
-+ * Copyright (c) 2001 Hewlett Packard
-+ *
-+ * By:
-+ * Stuart Lynne <sl@belcarra.com>,
-+ * Tom Rushworth <tbr@belcarra.com>,
-+ * Bruce Balden <balden@belcarra.com>
-+ *
-+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
-+ *
-+ */
-+
-+/*
-+ * This file contains the USB Bus Interface Driver Interface definitions.
-+ *
-+ * This is the interface between the bottom of the USB Core and the top of
-+ * the Bus Interace Drivers and is comprised of:
-+ *
-+ * o public functions exported by the USB Core layer
-+ *
-+ * o structures and functions passed by the Function Driver to the USB
-+ * Core layer
-+ *
-+ * USB Bus Interface Drivers are structured such that the upper edge
-+ * implements interfaces to the USB Core layer to provide low level USB
-+ * services and the lower edge interfaces to the actual USB Hardware
-+ * (typically called the USB Device Controller or UDC.)
-+ *
-+ */
-+
-+struct usb_endpoint_map;
-+
-+/* Operations that the slave layer or function driver can use to interact
-+ * with the bus interface driver.
-+ *
-+ * The send_urb() function is used by the usb-device endpoint 0 driver and
-+ * function drivers to submit data to be sent.
-+ *
-+ * The cancel_urb() function is used by the usb-device endpoint 0 driver and
-+ * function drivers to remove previously queued data to be sent.
-+ *
-+ * The endpoint_halted() function is used by the ep0 control function to
-+ * check if an endpoint is halted.
-+ *
-+ * The device_feature() function is used by the ep0 control function to
-+ * set/reset device features on an endpoint.
-+ *
-+ * The device_event() function is used by the usb device core to tell the
-+ * bus interface driver about various events.
-+ */
-+struct usb_bus_operations {
-+ int (*bus_enable) (struct usb_bus_instance *, char *);
-+ int (*bus_disable) (struct usb_bus_instance *, char *);
-+ int (*bus_disconnect) (struct usb_bus_instance *, char *);
-+ int (*bus_connect) (struct usb_bus_instance *, char *);
-+ int (*bus_pm_off) (struct usb_bus_instance *, char *);
-+ int (*bus_pm_on) (struct usb_bus_instance *, char *);
-+ int (*bus_serial_number) (struct usb_bus_instance *, char *);
-+
-+ int (*bus_attached) (struct usb_bus_instance *);
-+ int (*bus_connected) (struct usb_bus_instance *);
-+ int (*start_endpoint_in) (struct usb_bus_instance *, struct usb_endpoint_instance *);
-+ int (*start_endpoint_out) (struct usb_bus_instance *, struct usb_endpoint_instance *);
-+ int (*cancel_urb_irq) (struct urb *);
-+ int (*endpoint_halted) (struct usb_bus_instance *, int);
-+ int (*device_feature) (struct usb_bus_instance *, int, int);
-+ int (*device_event) (struct usb_bus_instance *, usb_device_event_t, int);
-+ int (*request_endpoints) (struct usb_endpoint_map *, int, struct usb_endpoint_request *);
-+ int (*set_endpoints) (int , struct usb_endpoint_map *);
-+};
-+
-+
-+/* Endpoint Map
-+ *
-+ * An array of these structures is created by the bus interface driver to
-+ * show what endpoints have been configured for the function driver.
-+ */
-+struct usb_endpoint_map {
-+ u8 configuration;
-+ u8 interface;
-+ u8 alternate;
-+ u8 bEndpointAddress[2]; // logical endpoint address
-+ u16 wMaxPacketSize[2]; // packetsSize for requested endpoint
-+ u8 bmAttributes[2]; // requested endpoint type
-+ u16 transferSize[2]; // transferSize for bulk transfers
-+ u8 physicalEndpoint[2]; // physical endpoint number
-+ struct usb_endpoint_instance *endpoint;
-+};
-+
-+
-+/* Endpoint configuration
-+ *
-+ * Per endpoint configuration data. Used to track which function driver owns
-+ * an endpoint.
-+ *
-+ */
-+struct usb_endpoint_instance {
-+ int bEndpointAddress; // logical endpoint address
-+ int physical_endpoint; // physical endpoint address - bus interface specific
-+ int bmAttributes; // endpoint type
-+ u16 wMaxPacketSize; // packet size for requested endpoint
-+
-+ // control
-+ int status; // halted
-+ int state; // available for use by bus interface driver
-+
-+ // receive side
-+ struct urb_link rcv; // received urbs
-+ struct urb_link rdy; // empty urbs ready to receive
-+ struct urb *rcv_urb; // active urb
-+ __u32 rcv_transferSize; // maximum transfer size from function driver
-+ int rcv_error; // current bulk-in has an error
-+
-+ // transmit side
-+ struct urb_link tx; // urbs ready to transmit
-+ struct urb_link done; // transmitted urbs
-+ struct urb *tx_urb; // active urb
-+
-+ __u32 sent; // data already sent
-+ __u32 last; // data sent in last packet XXX do we need this
-+};
-+
-+/* endpoint zero states
-+ */
-+#define WAIT_FOR_SETUP 0
-+#define DATA_STATE_XMIT 1
-+#define DATA_STATE_NEED_ZLP 2
-+#define WAIT_FOR_OUT_STATUS 3
-+#define DATA_STATE_RECV 4
-+#define DATA_STATE_PENDING_XMIT 5
-+
-+
-+/* Bus Interface data structure
-+ *
-+ * Keep track of specific bus interface.
-+ *
-+ * This is passed to the usb-device layer when registering. It contains all
-+ * required information about each real bus interface found such that the
-+ * usb-device layer can create and maintain a usb-device structure.
-+ *
-+ * Note that bus interface registration is incumbent on finding specific
-+ * actual real bus interfaces. There will be a registration for each such
-+ * device found.
-+ *
-+ * The max_tx_endpoints and max_rx_endpoints are the maximum number of
-+ * possible endpoints that this bus interface can support. The default
-+ * endpoint 0 is not included in these counts.
-+ *
-+ */
-+struct usb_bus_driver {
-+ char *name;
-+ u8 max_endpoints; // maximimum number of rx enpoints
-+ u8 maxpacketsize;
-+ u8 HighSpeedCapable;
-+ struct usb_device_description *device_description;
-+ struct usb_bus_operations *bops;
-+};
-+
-+
-+typedef enum usbd_admin {
-+ usbd_admin_enable = 0,
-+ usbd_admin_disable = 1,
-+ usbd_admin_connect = 2,
-+ usbd_admin_disconnect = 3,
-+ usbd_admin_pm_off = 4,
-+ usbd_admin_pm_on = 5,
-+ usbd_admin_serial_number = 6
-+} usbd_admin_t;
-+
-+typedef int (*usbd_admin_proc_t) (struct usb_bus_instance *, char *);
-+
-+
-+/* Function configuration structure
-+ *
-+ * This is allocated for each configured instance of a function driver.
-+ *
-+ * It stores pointers to the usb_function_driver for the appropriate function,
-+ * and pointers to the USB HOST requested usb_configuration_description and
-+ * usb_interface_description.
-+ *
-+ * The privdata pointer may be used by the function driver to store private
-+ * per instance state information.
-+ *
-+ */
-+struct usb_function_instance {
-+ struct usb_bus_instance *bus;
-+ struct usb_function_driver *function_driver;
-+ void *privdata; // private data for the function
-+ __u8 endpointsRequested; // number of requested endpoints
-+ struct usb_endpoint_map *endpoint_map_array; // map of endpoints requested by function driver
-+};
-+
-+
-+/* Bus Interface configuration structure
-+ *
-+ * This is allocated for each configured instance of a bus interface driver.
-+ *
-+ * It contains a pointer to the appropriate bus interface driver.
-+ *
-+ * The privdata pointer may be used by the bus interface driver to store private
-+ * per instance state information.
-+ */
-+struct usb_bus_instance {
-+
-+ struct usb_bus_driver *driver;
-+
-+ usbd_admin_proc_t admin [8];
-+
-+ int endpoints;
-+ struct usb_endpoint_instance *endpoint_array; // array of available configured endpoints
-+
-+ char *serial_number_str;
-+
-+ usb_device_status_t status; // device status
-+ usbd_bus_state_t bus_state;
-+ usb_device_state_t device_state; // current USB Device state
-+ usb_device_state_t suspended_state; // previous USB Device state
-+
-+ struct usb_function_instance *ep0; // ep0 configuration
-+ struct usb_function_instance *function_instance;
-+
-+
-+ u8 HighSpeedFlag;
-+ u8 ConfigurationValue; // current set configuration (zero is default)
-+ u8 bNumInterfaces; // number of interfaces in the current configuration
-+ u8 *alternates; // array[0..interfaces-1] of alternate settings for each interface
-+
-+ struct tq_struct device_bh; // runs as bottom half, equivalent to interrupt time
-+
-+ void *privdata; // private data for the bus interface
-+ char *arg;
-+};
-+
-+/* bus driver registration
-+ *
-+ * Called by bus interface drivers to register themselves when loaded
-+ * or de-register when unloading.
-+ */
-+struct usb_bus_instance *usbd_register_bus (struct usb_bus_driver *);
-+void usbd_deregister_bus (struct usb_bus_instance *);
-+
-+
-+
-+/* Enable/Disable Function
-+ *
-+ * Called by a bus interface driver to select and enable a specific function
-+ * driver.
-+ */
-+int usbd_enable_function_irq (struct usb_bus_instance *, char *);
-+void usbd_disable_function (struct usb_bus_instance *);
-+
-+
-+void usbd_flush_endpoint_irq (struct usb_endpoint_instance *);
-+void usbd_flush_endpoint (struct usb_endpoint_instance *);
-+
-+/*
-+ * usbd_configure_device is used by function drivers (usually the control endpoint)
-+ * to change the device configuration.
-+ *
-+ * usbd_device_event is used by bus interface drivers to tell the higher layers that
-+ * certain events have taken place.
-+ */
-+void usbd_bus_event_irq (struct usb_bus_instance *, usb_device_event_t, int);
-+void usbd_bus_event (struct usb_bus_instance *, usb_device_event_t, int);
-+
-+
-+/**
-+ * usbd_recv_setup_irq - process a received urb
-+ * @urb: pointer to an urb structure
-+ *
-+ * Used by a USB Bus interface driver to pass received data in a URB to the
-+ * appropriate USB Function driver.
-+ *
-+ * This function must return 0 for success and -EINVAL if the request
-+ * is to be stalled.
-+ *
-+ * Not that if the SETUP is Host to Device with a non-zero wLength then there
-+ * *MUST* be a valid receive urb queued OR the request must be stalled.
-+ */
-+int usbd_recv_setup_irq (struct usb_function_instance*, struct usb_device_request *);
-+
-+
-+void usbd_urb_sent_finished_irq (struct urb *, int );
-+void usbd_urb_recv_finished_irq (struct urb *, int );
-+
-+
-+/*
-+ * Detach and return the first urb in a list with a distinguished
-+ * head "hd", or NULL if the list is empty.
-+ */
-+struct urb *usbd_first_urb_detached_irq (urb_link * hd);
-+
-+/*
-+ * Get a descriptor
-+ */
-+int usbd_get_descriptor (struct usb_bus_instance *bus, u8 *buffer, int max, int descriptor_type, int index);
-+
-diff -Nru a/drivers/usbd/usbd-chap9.h b/drivers/usbd/usbd-chap9.h
---- /dev/null Wed Dec 31 16:00:00 1969
-+++ b/drivers/usbd/usbd-chap9.h Fri Feb 27 14:22:51 2004
-@@ -0,0 +1,1054 @@
-+/*
-+ * usbd/usbd-chap9.h
-+ *
-+ * Copyright (c) 2004 Belcarra
-+ *
-+ * Adapted from earlier work:
-+ * Copyright (c) 2002, 2003 Belcarra
-+ * Copyright (c) 2000, 2001, 2002 Lineo
-+ * Copyright (c) 2001 Hewlett Packard
-+ *
-+ * By:
-+ * Stuart Lynne <sl@belcarra.com>,
-+ * Tom Rushworth <tbr@belcarra.com>,
-+ * Bruce Balden <balden@belcarra.com>
-+ *
-+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
-+ *
-+ */
-+
-+
-+/*
-+ * USB Descriptors are used to build a configuration database for each USB
-+ * Function driver.
-+ *
-+ */
-+
-+
-+/*
-+ * Device and/or Interface Class codes
-+ */
-+#define USB_CLASS_PER_INTERFACE 0 /* for DeviceClass */
-+#define USB_CLASS_AUDIO 1
-+#define USB_CLASS_COMM 2
-+#define USB_CLASS_HID 3
-+#define USB_CLASS_PHYSICAL 5
-+#define USB_CLASS_PRINTER 7
-+#define USB_CLASS_MASS_STORAGE 8
-+#define USB_CLASS_HUB 9
-+#define USB_CLASS_DATA 10
-+#define USB_CLASS_APP_SPEC 0xfe
-+#define USB_CLASS_VENDOR_SPEC 0xff
-+
-+/*
-+ * USB Device Request Types (bmRequestType)
-+ * C.f. USB 2.0 Table 9-2
-+ */
-+#define USB_TYPE_STANDARD (0x00 << 5)
-+#define USB_TYPE_CLASS (0x01 << 5)
-+#define USB_TYPE_VENDOR (0x02 << 5)
-+#define USB_TYPE_RESERVED (0x03 << 5)
-+
-+#define USB_RECIP_DEVICE 0x00
-+#define USB_RECIP_INTERFACE 0x01
-+#define USB_RECIP_ENDPOINT 0x02
-+#define USB_RECIP_OTHER 0x03
-+
-+#define USB_DIR_OUT 0
-+#define USB_DIR_IN 0x80
-+#define USB_ENDPOINT_OPT 0x40
-+
-+
-+
-+/*
-+ * Descriptor types
-+ * C.f. USB Table 9-5
-+ */
-+#define USB_DT_DEVICE 0x01
-+#define USB_DT_CONFIG 0x02
-+#define USB_DT_STRING 0x03
-+#define USB_DT_INTERFACE 0x04
-+#define USB_DT_ENDPOINT 0x05
-+
-+
-+
-+#define USB_DT_HID (USB_TYPE_CLASS | 0x01)
-+#define USB_DT_REPORT (USB_TYPE_CLASS | 0x02)
-+#define USB_DT_PHYSICAL (USB_TYPE_CLASS | 0x03)
-+#define USB_DT_HUB (USB_TYPE_CLASS | 0x09)
-+
-+/*
-+ * Descriptor sizes per descriptor type
-+ */
-+#define USB_DT_DEVICE_SIZE 18
-+#define USB_DT_CONFIG_SIZE 9
-+#define USB_DT_INTERFACE_SIZE 9
-+#define USB_DT_ENDPOINT_SIZE 7
-+#define USB_DT_ENDPOINT_AUDIO_SIZE 9 /* Audio extension */
-+#define USB_DT_HUB_NONVAR_SIZE 7
-+#define USB_DT_HID_SIZE 9
-+
-+/*
-+ * Endpoints
-+ */
-+#define USB_ENDPOINT_NUMBER_MASK 0x0f /* in bEndpointAddress */
-+#define USB_ENDPOINT_DIR_MASK 0x80
-+
-+#define USB_ENDPOINT_MASK 0x03 /* in bmAttributes */
-+#define USB_ENDPOINT_CONTROL 0x00
-+#define USB_ENDPOINT_ISOCHRONOUS 0x01
-+#define USB_ENDPOINT_BULK 0x02
-+#define USB_ENDPOINT_INTERRUPT 0x03
-+
-+/*
-+ * USB Packet IDs (PIDs)
-+ */
-+#define USB_PID_UNDEF_0 0xf0
-+#define USB_PID_OUT 0xe1
-+#define USB_PID_ACK 0xd2
-+#define USB_PID_DATA0 0xc3
-+#define USB_PID_PING 0xb4 /* USB 2.0 */
-+#define USB_PID_SOF 0xa5
-+#define USB_PID_NYET 0x96 /* USB 2.0 */
-+#define USB_PID_DATA2 0x87 /* USB 2.0 */
-+#define USB_PID_SPLIT 0x78 /* USB 2.0 */
-+#define USB_PID_IN 0x69
-+#define USB_PID_NAK 0x5a
-+#define USB_PID_DATA1 0x4b
-+#define USB_PID_PREAMBLE 0x3c /* Token mode */
-+#define USB_PID_ERR 0x3c /* USB 2.0: handshake mode */
-+#define USB_PID_SETUP 0x2d
-+#define USB_PID_STALL 0x1e
-+#define USB_PID_MDATA 0x0f /* USB 2.0 */
-+
-+/*
-+ * Standard requests
-+ */
-+#define USB_REQ_GET_STATUS 0x00
-+#define USB_REQ_CLEAR_FEATURE 0x01
-+#define USB_REQ_SET_FEATURE 0x03
-+#define USB_REQ_SET_ADDRESS 0x05
-+#define USB_REQ_GET_DESCRIPTOR 0x06
-+#define USB_REQ_SET_DESCRIPTOR 0x07
-+#define USB_REQ_GET_CONFIGURATION 0x08
-+#define USB_REQ_SET_CONFIGURATION 0x09
-+#define USB_REQ_GET_INTERFACE 0x0A
-+#define USB_REQ_SET_INTERFACE 0x0B
-+#define USB_REQ_SYNCH_FRAME 0x0C
-+
-+/*
-+ * HID requests
-+ */
-+#define USB_REQ_GET_REPORT 0x01
-+#define USB_REQ_GET_IDLE 0x02
-+#define USB_REQ_GET_PROTOCOL 0x03
-+#define USB_REQ_SET_REPORT 0x09
-+#define USB_REQ_SET_IDLE 0x0A
-+#define USB_REQ_SET_PROTOCOL 0x0B
-+
-+
-+/*
-+ * USB Spec Release number
-+ */
-+
-+#define USB_BCD_VERSION 0x0200
-+
-+/*
-+ * Audio
-+ */
-+#define CS_AUDIO_UNDEFINED 0x20
-+#define CS_AUDIO_DEVICE 0x21
-+#define CS_AUDIO_CONFIGURATION 0x22
-+#define CS_AUDIO_STRING 0x23
-+#define CS_AUDIO_INTERFACE 0x24
-+#define CS_AUDIO_ENDPOINT 0x25
-+
-+#define AUDIO_HEADER 0x01
-+#define AUDIO_INPUT_TERMINAL 0x02
-+#define AUDIO_OUTPUT_TERMINAL 0x03
-+#define AUDIO_MIXER_UNIT 0x04
-+#define AUDIO_SELECTOR_UNIT 0x05
-+#define AUDIO_FEATURE_UNIT 0x06
-+#define AUDIO_PROCESSING_UNIT 0x07
-+#define AUDIO_EXTENSION_UNIT 0x08
-+
-+
-+/*
-+ * Device Requests (c.f Table 9-2)
-+ */
-+
-+#define USB_REQ_DIRECTION_MASK 0x80
-+#define USB_REQ_TYPE_MASK 0x60
-+#define USB_REQ_RECIPIENT_MASK 0x1f
-+
-+#define USB_REQ_DEVICE2HOST 0x80
-+#define USB_REQ_HOST2DEVICE 0x00
-+
-+#define USB_REQ_TYPE_STANDARD 0x00
-+#define USB_REQ_TYPE_CLASS 0x20
-+#define USB_REQ_TYPE_VENDOR 0x40
-+
-+#define USB_REQ_RECIPIENT_DEVICE 0x00
-+#define USB_REQ_RECIPIENT_INTERFACE 0x01
-+#define USB_REQ_RECIPIENT_ENDPOINT 0x02
-+#define USB_REQ_RECIPIENT_OTHER 0x03
-+
-+/*
-+ * get status bits
-+ */
-+
-+#define USB_STATUS_SELFPOWERED 0x01
-+#define USB_STATUS_REMOTEWAKEUP 0x02
-+
-+#define USB_STATUS_HALT 0x01
-+
-+/*
-+ * descriptor types
-+ */
-+
-+#define USB_DESCRIPTOR_TYPE_DEVICE 0x01
-+#define USB_DESCRIPTOR_TYPE_CONFIGURATION 0x02
-+#define USB_DESCRIPTOR_TYPE_STRING 0x03
-+#define USB_DESCRIPTOR_TYPE_INTERFACE 0x04
-+#define USB_DESCRIPTOR_TYPE_ENDPOINT 0x05
-+#define USB_DESCRIPTOR_TYPE_DEVICE_QUALIFIER 0x06
-+#define USB_DESCRIPTOR_TYPE_OTHER_SPEED_CONFIGURATION 0x07
-+#define USB_DESCRIPTOR_TYPE_INTERFACE_POWER 0x08
-+
-+/*
-+ * standard feature selectors
-+ */
-+#define USB_ENDPOINT_HALT 0x00
-+#define USB_DEVICE_REMOTE_WAKEUP 0x01
-+#define USB_TEST_MODE 0x02
-+
-+
-+/* USB Requests
-+ *
-+ */
-+
-+struct usb_device_request {
-+ __u8 bmRequestType;
-+ __u8 bRequest;
-+ __u16 wValue;
-+ __u16 wIndex;
-+ __u16 wLength;
-+} __attribute__ ((packed));
-+
-+
-+/*
-+ * Class-Specific Request Codes
-+ * C.f. CDC Table 46
-+ */
-+#define CDC_CLASS_REQUEST_SEND_ENCAPSULATED 0x00
-+#define CDC_CLASS_REQUEST_GET_ENCAPSULATED 0x01
-+
-+#define CDC_CLASS_REQUEST_SET_COMM_FEATURE 0x02
-+#define CDC_CLASS_REQUEST_GET_COMM_FEATURE 0x03
-+#define CDC_CLASS_REQUEST_CLEAR_COMM_FEATURE 0x04
-+
-+#define CDC_CLASS_REQUEST_SET_LINE_CODING 0x20
-+#define CDC_CLASS_REQUEST_GET_LINE_CODING 0x21
-+
-+#define CDC_CLASS_REQUEST_SET_CONTROL_STATE 0x22
-+#define CDC_CLASS_REQUEST_SEND_BREAK 0x23
-+
-+/*
-+ * Notification codes
-+ * c.f. CDC Table 68
-+ */
-+
-+#define CDC_NOTIFICATION_NETWORK_CONNECTION 0x00
-+#define CDC_NOTIFICATION_RESPONSE_AVAILABLE 0x01
-+#define CDC_NOTIFICATION_AUX_JACK_HOOK_STATE 0x08
-+#define CDC_NOTIFICATION_RING_DETECT 0x09
-+#define CDC_NOTIFICATION_SERIAL_STATE 0x20
-+#define CDC_NOTIFICATION_CALL_STATE_CHANGE 0x28
-+#define CDC_NOTIFICATION_LINE_STATE_CHANGE 0x29
-+#define CDC_NOTIFICATION_CONNECTION_SPEED_CHANGE 0x2a
-+
-+/*
-+ * HID - Class Descriptors
-+ * C.f. 7.1.1
-+ */
-+#define HID 0x21
-+#define HID_REPORT 0x22
-+#define HID_PHYSICAL 0x23
-+
-+/*
-+ * HID Descriptor
-+ * C.f. E.8
-+ */
-+struct hid_descriptor {
-+ u8 bLength;
-+ u8 bDescriptorType;
-+ u16 bcdHID;
-+ u8 bCountryCode;
-+ u8 bNumDescriptors;
-+ u8 bReportType;
-+ u16 wItemLength;
-+} __attribute__((packed));
-+
-+/*
-+ * ACM - Line Coding structure
-+ * C.f CDC Table 50
-+ */
-+struct cdc_acm_line_coding {
-+ __u32 dwDTERate;
-+ __u8 bCharFormat;
-+ __u8 bParityType;
-+ __u8 bDataBits;
-+} __attribute__((packed));
-+
-+/*
-+ * ACM
-+ * C.f CDC Table 50
-+ */
-+
-+
-+/*
-+ * ACM
-+ * C.f CDC Table 51
-+ */
-+
-+
-+/* USB Notification
-+ *
-+ */
-+
-+struct cdc_notification_descriptor {
-+ __u8 bmRequestType;
-+ __u8 bNotification;
-+ __u16 wValue;
-+ __u16 wIndex;
-+ __u16 wLength;
-+ __u8 data[2];
-+} __attribute__ ((packed));
-+
-+
-+
-+
-+/*
-+ * communications class types
-+ *
-+ * c.f. CDC USB Class Definitions for Communications Devices
-+ * c.f. WMCD USB CDC Subclass Specification for Wireless Mobile Communications Devices
-+ *
-+ */
-+
-+#define CLASS_BCD_VERSION 0x0110
-+
-+// c.f. CDC 4.1 Table 14
-+#define AUDIO_CLASS 0x01
-+#define COMMUNICATIONS_DEVICE_CLASS 0x02
-+
-+// c.f. CDC 4.2 Table 15
-+#define COMMUNICATIONS_INTERFACE_CLASS 0x02
-+
-+// c.f. CDC 4.3 Table 16
-+#define COMMUNICATIONS_NO_SUBCLASS 0x00
-+#define COMMUNICATIONS_DLCM_SUBCLASS 0x01
-+#define COMMUNICATIONS_ACM_SUBCLASS 0x02
-+#define COMMUNICATIONS_TCM_SUBCLASS 0x03
-+#define COMMUNICATIONS_MCCM_SUBCLASS 0x04
-+#define COMMUNICATIONS_CCM_SUBCLASS 0x05
-+#define COMMUNICATIONS_ENCM_SUBCLASS 0x06
-+#define COMMUNICATIONS_ANCM_SUBCLASS 0x07
-+
-+#define AUDIO_CONTROL_SUBCLASS 0x01
-+#define AUDIO_STREAMING_SUBCLASS 0x02
-+
-+// c.f. WMCD 5.1
-+#define COMMUNICATIONS_WHCM_SUBCLASS 0x08
-+#define COMMUNICATIONS_DMM_SUBCLASS 0x09
-+#define COMMUNICATIONS_MDLM_SUBCLASS 0x0a
-+#define COMMUNICATIONS_OBEX_SUBCLASS 0x0b
-+
-+// c.f. CDC 4.6 Table 18
-+#define DATA_INTERFACE_CLASS 0x0a
-+
-+// c.f. CDC 4.7 Table 19
-+#define COMMUNICATIONS_NO_PROTOCOL 0x00
-+
-+
-+// c.f. CDC 5.2.3 Table 24
-+// c.f. Audio Appendix A.4
-+#define CS_UNDEFINED 0x20
-+#define CS_DEVICE 0x21
-+#define CS_CONFIG 0x22
-+#define CS_STRING 0x23
-+#define CS_INTERFACE 0x24
-+#define CS_ENDPOINT 0x25
-+
-+// Audio Interface Class - c.f Appendix A.1
-+#define AUDIO_INTERFACE_CLASS 0x01
-+
-+// Audio Interface Subclass - c.f Appendix A.2
-+#define AUDIO_SUBCLASS_UNDEFINED 0x00
-+#define AUDIO_AUDIOCONTROL 0x01
-+#define AUDIO_AUDIOSTREAMING 0x02
-+#define AUDIO_MIDISTREAMING 0x03
-+
-+// Audio Interface Proctol - c.f. Appendix A.3
-+#define AUDIO_PR_PROTOCOL_UNDEFINED 0x00
-+
-+// Audio Class-Specific AC Interface Descriptor Subtypes - c.f. A.5
-+#define AUDIO_AC_DESCRIPTOR_UNDEFINED 0x00
-+#define AUDIO_AC_HEADER 0x01
-+#define AUDIO_AC_INPUT_TERMINAL 0x02
-+#define AUDIO_AC_OUTPUT_TERMINAL 0x03
-+#define AUDIO_AC_MIXER_UNIT 0x04
-+#define AUDIO_AC_SELECTOR_UNIT 0x05
-+#define AUDIO_AC_FEATURE_UNIT 0x06
-+#define AUDIO_AC_PROCESSING_UNIT 0x07
-+#define AUDIO_AC_EXTENSION_UNIT 0x08
-+
-+// Audio Class-Specific AS Interface Descriptor Subtypes - c.f. A.6
-+#define AUDIO_AS_DESCRIPTOR_UNDEFINED 0x00
-+#define AUDIO_AS_GENERAL 0x01
-+#define AUDIO_AS_FORMAT_TYPE 0x02
-+#define AUDIO_AS_FORMAT_UNSPECFIC 0x03
-+
-+// Audio Class Processing Unit Processing Types - c.f. A.7
-+#define AUDIO_PROCESS_UNDEFINED 0x00
-+#define AUDIO_UP_DOWN_MUIX_PROCESS 0x01
-+#define AUDIO_DOLBY_PROLOGIC_PROCESS 0x02
-+#define AUDIO_3D_STEREO_EXTENDER_PROCESS 0x03
-+#define AUDIO_REVERBERATION_PROCESS 0x04
-+#define AUDIO_CHORUS_PROCESS 0x05
-+#define AUDIO_DYN_RANGE_COMP_PROCESS 0x06
-+
-+// Audio Class-Specific Endpoint Descriptor Subtypes - c.f. A.8
-+#define AUDIO_DESCRIPTOR_UNDEFINED 0x00
-+#define AUDIO_EP_GENERAL 0x01
-+
-+// Audio Class-Specific Request Codes - c.f. A.9
-+#define AUDIO_REQUEST_CODE_UNDEFINED 0x00
-+#define AUDIO_SET_CUR 0x01
-+#define AUDIO_GET_CUR 0x81
-+#define AUDIO_SET_MIN 0x02
-+#define AUDIO_GET_MIN 0x82
-+#define AUDIO_SET_MAX 0x03
-+#define AUDIO_GET_MAX 0x83
-+#define AUDIO_SET_RES 0x04
-+#define AUDIO_GET_RES 0x84
-+#define AUDIO_SET_MEM 0x05
-+#define AUDIO_GET_MEM 0x85
-+#define AUDIO_GET_STAT 0xff
-+
-+
-+
-+
-+
-+
-+/*
-+ * bDescriptorSubtypes
-+ *
-+ * c.f. CDC 5.2.3 Table 25
-+ * c.f. WMCD 5.3 Table 5.3
-+ */
-+
-+#define USB_ST_HEADER 0x00
-+#define USB_ST_CMF 0x01
-+#define USB_ST_ACMF 0x02
-+#define USB_ST_DLMF 0x03
-+#define USB_ST_TRF 0x04
-+#define USB_ST_TCLF 0x05
-+#define USB_ST_UF 0x06
-+#define USB_ST_CSF 0x07
-+#define USB_ST_TOMF 0x08
-+#define USB_ST_USBTF 0x09
-+#define USB_ST_NCT 0x0a
-+#define USB_ST_PUF 0x0b
-+#define USB_ST_EUF 0x0c
-+#define USB_ST_MCMF 0x0d
-+#define USB_ST_CCMF 0x0e
-+#define USB_ST_ENF 0x0f
-+#define USB_ST_ATMNF 0x10
-+
-+#define USB_ST_WHCM 0x11
-+#define USB_ST_MDLM 0x12
-+#define USB_ST_MDLMD 0x13
-+#define USB_ST_DMM 0x14
-+#define USB_ST_OBEX 0x15
-+#define USB_ST_CS 0x16
-+#define USB_ST_CSD 0x17
-+#define USB_ST_TCM 0x18
-+
-+
-+
-+/*
-+ * commuications class description structures
-+ *
-+ * c.f. CDC 5.1
-+ * c.f. WCMC 6.7.2
-+ *
-+ * XXX add the other dozen class descriptor description structures....
-+ */
-+
-+struct usb_header_description {
-+ __u8 bDescriptorSubtype;
-+ __u16 bcdCDC;
-+};
-+
-+struct usb_call_management_description {
-+ __u8 bmCapabilities;
-+ __u8 bDataInterface;
-+};
-+
-+struct usb_abstract_control_description {
-+ __u8 bmCapabilities;
-+};
-+
-+struct usb_union_function_description {
-+ __u8 bMasterInterface;
-+ __u8 bSlaveInterface[1];
-+ //__u8 bSlaveInterface[0]; // XXX FIXME
-+};
-+
-+struct usb_ethernet_networking_description {
-+ char *iMACAddress;
-+ __u8 bmEthernetStatistics;
-+ __u16 wMaxSegmentSize;
-+ __u16 wNumberMCFilters;
-+ __u8 bNumberPowerFilters;
-+};
-+
-+struct usb_mobile_direct_line_model_description {
-+ __u16 bcdVersion;
-+ __u8 bGUID[16];
-+};
-+
-+struct usb_mobile_direct_line_model_detail_description {
-+ __u8 bGuidDescriptorType;
-+ __u8 bDetailData[2];
-+ //__u8 bDetailData[0]; // XXX FIXME
-+};
-+
-+struct usb_class_description {
-+ __u8 bDescriptorSubtype;
-+ __u8 elements;
-+ union {
-+ struct usb_header_description header;
-+ struct usb_call_management_description call_management;
-+ struct usb_abstract_control_description abstract_control;
-+ struct usb_union_function_description union_function;
-+ struct usb_ethernet_networking_description ethernet_networking;
-+ struct usb_mobile_direct_line_model_description mobile_direct;
-+ struct usb_mobile_direct_line_model_detail_description mobile_direct_detail;
-+ } description;
-+};
-+
-+/* endpoint modifiers
-+ * static struct usb_endpoint_description function_default_A_1[] = {
-+ *
-+ * {this_endpoint: 0, attributes: CONTROL, max_size: 8, polling_interval: 0 },
-+ * {this_endpoint: 1, attributes: BULK, max_size: 64, polling_interval: 0, direction: IN},
-+ * {this_endpoint: 2, attributes: BULK, max_size: 64, polling_interval: 0, direction: OUT},
-+ * {this_endpoint: 3, attributes: INTERRUPT, max_size: 8, polling_interval: 0},
-+ *
-+ *
-+ */
-+#define OUT 0x00
-+#define IN 0x80
-+
-+#define CONTROL 0x00
-+#define ISOCHRONOUS 0x01
-+#define BULK 0x02
-+#define INTERRUPT 0x03
-+
-+
-+/* configuration modifiers
-+ */
-+#define BMATTRIBUTE_RESERVED 0x80
-+#define BMATTRIBUTE_SELF_POWERED 0x40
-+
-+/*
-+ * The UUT tester specifically tests for MaxPower to be non-zero (> 0).
-+ */
-+#if !defined(CONFIG_USBD_MAXPOWER) || (CONFIG_USBD_MAXPOWER == 0)
-+ #define BMATTRIBUTE BMATTRIBUTE_RESERVED | BMATTRIBUTE_SELF_POWERED
-+ #define BMAXPOWER 1
-+#else
-+ #define BMATTRIBUTE BMATTRIBUTE_RESERVED
-+ #define BMAXPOWER CONFIG_USBD_MAXPOWER
-+#endif
-+
-+
-+
-+
-+/*
-+ * standard usb descriptor structures
-+ */
-+
-+struct usb_endpoint_descriptor {
-+ __u8 bLength;
-+ __u8 bDescriptorType; // 0x5
-+ __u8 bEndpointAddress;
-+ __u8 bmAttributes;
-+ __u16 wMaxPacketSize;
-+ __u8 bInterval;
-+} __attribute__ ((packed));
-+
-+struct usb_interface_descriptor {
-+ __u8 bLength;
-+ __u8 bDescriptorType; // 0x04
-+ __u8 bInterfaceNumber;
-+ __u8 bAlternateSetting;
-+ __u8 bNumEndpoints;
-+ __u8 bInterfaceClass;
-+ __u8 bInterfaceSubClass;
-+ __u8 bInterfaceProtocol;
-+ __u8 iInterface;
-+} __attribute__ ((packed));
-+
-+struct usb_configuration_descriptor {
-+ __u8 bLength;
-+ __u8 bDescriptorType; // 0x2
-+ __u16 wTotalLength;
-+ __u8 bNumInterfaces;
-+ __u8 bConfigurationValue;
-+ __u8 iConfiguration;
-+ __u8 bmAttributes;
-+ __u8 bMaxPower;
-+} __attribute__ ((packed));
-+
-+struct usb_device_descriptor {
-+ __u8 bLength;
-+ __u8 bDescriptorType; // 0x01
-+ __u16 bcdUSB;
-+ __u8 bDeviceClass;
-+ __u8 bDeviceSubClass;
-+ __u8 bDeviceProtocol;
-+ __u8 bMaxPacketSize0;
-+ __u16 idVendor;
-+ __u16 idProduct;
-+ __u16 bcdDevice;
-+ __u8 iManufacturer;
-+ __u8 iProduct;
-+ __u8 iSerialNumber;
-+ __u8 bNumConfigurations;
-+} __attribute__ ((packed));
-+
-+struct usb_string_descriptor {
-+ __u8 bLength;
-+ __u8 bDescriptorType; // 0x03
-+ __u16 wData[0];
-+} __attribute__ ((packed));
-+
-+struct usb_device_qualifier_descriptor {
-+ __u8 bLength;
-+ __u8 bDescriptorType;
-+ __u16 bcdUSB;
-+ __u8 bDeviceClass;
-+ __u8 bDeviceSubClass;
-+ __u8 bDeviceProtocol;
-+ __u8 bMaxPacketSize0;
-+ __u8 bNumConfigurations;
-+ __u8 bReserved;
-+} __attribute__ ((packed));
-+
-+struct usb_generic_descriptor {
-+ __u8 bLength;
-+ __u8 bDescriptorType;
-+} __attribute__ ((packed));
-+
-+struct usb_generic_class_descriptor {
-+ __u8 bLength;
-+ __u8 bDescriptorType;
-+ __u8 bDescriptorSubtype;
-+} __attribute__ ((packed));
-+
-+
-+/*
-+ * communications class descriptor structures
-+ *
-+ * c.f. CDC 5.2 Table 25c
-+ */
-+
-+struct usb_class_function_descriptor {
-+ __u8 bFunctionLength;
-+ __u8 bDescriptorType;
-+ __u8 bDescriptorSubtype;
-+} __attribute__ ((packed));
-+
-+struct usb_class_function_descriptor_generic {
-+ __u8 bFunctionLength;
-+ __u8 bDescriptorType;
-+ __u8 bDescriptorSubtype;
-+ __u8 bmCapabilities;
-+} __attribute__ ((packed));
-+
-+struct usb_class_header_function_descriptor {
-+ __u8 bFunctionLength;
-+ __u8 bDescriptorType;
-+ __u8 bDescriptorSubtype; // 0x00
-+ __u16 bcdCDC;
-+} __attribute__ ((packed));
-+
-+struct usb_class_call_management_descriptor {
-+ __u8 bFunctionLength;
-+ __u8 bDescriptorType;
-+ __u8 bDescriptorSubtype; // 0x01
-+ __u8 bmCapabilities;
-+ __u8 bDataInterface;
-+} __attribute__ ((packed));
-+
-+struct usb_class_abstract_control_descriptor {
-+ __u8 bFunctionLength;
-+ __u8 bDescriptorType;
-+ __u8 bDescriptorSubtype; // 0x02
-+ __u8 bmCapabilities;
-+} __attribute__ ((packed));
-+
-+struct usb_class_direct_line_descriptor {
-+ __u8 bFunctionLength;
-+ __u8 bDescriptorType;
-+ __u8 bDescriptorSubtype; // 0x03
-+} __attribute__ ((packed));
-+
-+struct usb_class_telephone_ringer_descriptor {
-+ __u8 bFunctionLength;
-+ __u8 bDescriptorType;
-+ __u8 bDescriptorSubtype; // 0x04
-+ __u8 bRingerVolSeps;
-+ __u8 bNumRingerPatterns;
-+} __attribute__ ((packed));
-+
-+struct usb_class_telephone_call_descriptor {
-+ __u8 bFunctionLength;
-+ __u8 bDescriptorType;
-+ __u8 bDescriptorSubtype; // 0x05
-+ __u8 bmCapabilities;
-+} __attribute__ ((packed));
-+
-+struct usb_class_union_function_descriptor {
-+ __u8 bFunctionLength;
-+ __u8 bDescriptorType;
-+ __u8 bDescriptorSubtype; // 0x06
-+ __u8 bMasterInterface;
-+ __u8 bSlaveInterface0[0];
-+} __attribute__ ((packed));
-+
-+struct usb_class_country_selection_descriptor {
-+ __u8 bFunctionLength;
-+ __u8 bDescriptorType;
-+ __u8 bDescriptorSubtype; // 0x07
-+ __u8 iCountryCodeRelDate;
-+ __u16 wCountryCode0[0];
-+} __attribute__ ((packed));
-+
-+
-+struct usb_class_telephone_operational_descriptor {
-+ __u8 bFunctionLength;
-+ __u8 bDescriptorType;
-+ __u8 bDescriptorSubtype; // 0x08
-+ __u8 bmCapabilities;
-+} __attribute__ ((packed));
-+
-+
-+struct usb_class_usb_terminal_descriptor {
-+ __u8 bFunctionLength;
-+ __u8 bDescriptorType;
-+ __u8 bDescriptorSubtype; // 0x09
-+ __u8 bEntityId;
-+ __u8 bInterfaceNo;
-+ __u8 bOutInterfaceNo;
-+ __u8 bmOptions;
-+ __u8 bChild0[0];
-+} __attribute__ ((packed));
-+
-+struct usb_class_network_channel_descriptor {
-+ __u8 bFunctionLength;
-+ __u8 bDescriptorType;
-+ __u8 bDescriptorSubtype; // 0x0a
-+ __u8 bEntityId;
-+ __u8 iName;
-+ __u8 bChannelIndex;
-+ __u8 bPhysicalInterface;
-+} __attribute__ ((packed));
-+
-+struct usb_class_protocol_unit_function_descriptor {
-+ __u8 bFunctionLength;
-+ __u8 bDescriptorType;
-+ __u8 bDescriptorSubtype; // 0x0b
-+ __u8 bEntityId;
-+ __u8 bProtocol;
-+ __u8 bChild0[0];
-+} __attribute__ ((packed));
-+
-+struct usb_class_extension_unit_descriptor {
-+ __u8 bFunctionLength;
-+ __u8 bDescriptorType;
-+ __u8 bDescriptorSubtype; // 0x0c
-+ __u8 bEntityId;
-+ __u8 bExtensionCode;
-+ __u8 iName;
-+ __u8 bChild0[0];
-+} __attribute__ ((packed));
-+
-+struct usb_class_multi_channel_descriptor {
-+ __u8 bFunctionLength;
-+ __u8 bDescriptorType;
-+ __u8 bDescriptorSubtype; // 0x0d
-+ __u8 bmCapabilities;
-+} __attribute__ ((packed));
-+
-+struct usb_class_capi_control_descriptor {
-+ __u8 bFunctionLength;
-+ __u8 bDescriptorType;
-+ __u8 bDescriptorSubtype; // 0x0e
-+ __u8 bmCapabilities;
-+} __attribute__ ((packed));
-+
-+struct usb_class_ethernet_networking_descriptor {
-+ __u8 bFunctionLength;
-+ __u8 bDescriptorType;
-+ __u8 bDescriptorSubtype; // 0x0f
-+ __u8 iMACAddress;
-+ __u32 bmEthernetStatistics;
-+ __u16 wMaxSegmentSize;
-+ __u16 wNumberMCFilters;
-+ __u8 bNumberPowerFilters;
-+} __attribute__ ((packed));
-+
-+struct usb_class_atm_networking_descriptor {
-+ __u8 bFunctionLength;
-+ __u8 bDescriptorType;
-+ __u8 bDescriptorSubtype; // 0x10
-+ __u8 iEndSystermIdentifier;
-+ __u8 bmDataCapabilities;
-+ __u8 bmATMDeviceStatistics;
-+ __u16 wType2MaxSegmentSize;
-+ __u16 wType3MaxSegmentSize;
-+ __u16 wMaxVC;
-+} __attribute__ ((packed));
-+
-+
-+struct usb_class_mdlm_descriptor {
-+ __u8 bFunctionLength;
-+ __u8 bDescriptorType;
-+ __u8 bDescriptorSubtype; // 0x12
-+ __u16 bcdVersion;
-+ __u8 bGUID[16];
-+} __attribute__ ((packed));
-+
-+struct usb_class_mdlmd_descriptor {
-+ __u8 bFunctionLength;
-+ __u8 bDescriptorType;
-+ __u8 bDescriptorSubtype; // 0x13
-+ __u8 bGuidDescriptorType;
-+ __u8 bDetailData[0];
-+
-+} __attribute__ ((packed));
-+
-+
-+/*
-+ * descriptor union structures
-+ */
-+
-+struct usb_descriptor {
-+ union {
-+ struct usb_generic_descriptor generic;
-+ struct usb_generic_class_descriptor generic_class;
-+ struct usb_endpoint_descriptor endpoint;
-+ struct usb_interface_descriptor interface;
-+ struct usb_configuration_descriptor configuration;
-+ struct usb_device_descriptor device;
-+ struct usb_string_descriptor string;
-+ } descriptor;
-+
-+} __attribute__ ((packed));
-+
-+struct usb_class_descriptor {
-+ union {
-+ struct usb_class_function_descriptor function;
-+ struct usb_class_function_descriptor_generic generic;
-+ struct usb_class_header_function_descriptor header_function;
-+ struct usb_class_call_management_descriptor call_management;
-+ struct usb_class_abstract_control_descriptor abstract_control;
-+ struct usb_class_direct_line_descriptor direct_line;
-+ struct usb_class_telephone_ringer_descriptor telephone_ringer;
-+ struct usb_class_telephone_operational_descriptor telephone_operational;
-+ struct usb_class_telephone_call_descriptor telephone_call;
-+ struct usb_class_union_function_descriptor union_function;
-+ struct usb_class_country_selection_descriptor country_selection;
-+ struct usb_class_usb_terminal_descriptor usb_terminal;
-+ struct usb_class_network_channel_descriptor network_channel;
-+ struct usb_class_extension_unit_descriptor extension_unit;
-+ struct usb_class_multi_channel_descriptor multi_channel;
-+ struct usb_class_capi_control_descriptor capi_control;
-+ struct usb_class_ethernet_networking_descriptor ethernet_networking;
-+ struct usb_class_atm_networking_descriptor atm_networking;
-+ struct usb_class_mdlm_descriptor mobile_direct;
-+ struct usb_class_mdlmd_descriptor mobile_direct_detail;
-+ } descriptor;
-+
-+} __attribute__ ((packed));
-+
-+
-+/*
-+ * Audio Status Word Format - c.f. Table 3.1
-+ */
-+#define AUDIO_STATUS_INTERRUPT_PENDING 1<<7
-+#define AUDIO_STATUS_MEMORY_CONTENT_CHANGED 1<<6
-+#define AUDIO_STATUS_ORIGINATOR_AUDIO_CONTROL_INTERFACE 0
-+#define AUDIO_STATUS_ORIGINATOR_AUDIO_STREAMING_INTERFACE 1
-+#define AUDIO_STATUS_ORIGINATOR_AUDIO_STREAMING_ENDPOINT 2
-+#define AUDIO_STATUS_ORIGINATOR_AUDIOCONTROL_INTERFACE 0
-+
-+struct usb_audio_status_word {
-+ __u8 bStatusType;
-+ __u8 bOriginator;
-+} __attribute__ ((packed));
-+
-+struct usb_audio_ac_interface_header_descriptor {
-+ __u8 bFunctionLength;
-+ __u8 bDescriptorType;
-+ __u8 bDescriptorSubtype;
-+ __u16 bcdADC;
-+ __u16 wTotalLength;
-+ __u8 binCollection;
-+ __u8 bainterfaceNr[0];
-+} __attribute__ ((packed));
-+
-+struct usb_audio_input_terminal_descriptor {
-+ __u8 bFunctionLength;
-+ __u8 bDescriptorType;
-+ __u8 bDescriptorSubtype;
-+ __u8 bTerminalID;
-+ __u16 wTerminalType;
-+ __u8 bAssocTerminal;
-+ __u8 bNrChannels;
-+ __u16 wChannelConfig;
-+ __u8 iChannelNames;
-+ __u8 iTerminal;
-+} __attribute__ ((packed));
-+
-+struct usb_audio_input_terminal_description {
-+ struct usb_audio_input_terminal_descriptor *audio_input_terminal_descriptor;
-+ __u16 wTerminalType;
-+ __u16 wChannelConfig;
-+ char * iChannelNames;
-+ char * iTerminal;
-+};
-+
-+struct usb_audio_output_terminal_descriptor {
-+ __u8 bFunctionLength;
-+ __u8 bDescriptorType;
-+ __u8 bDescriptorSubtype;
-+ __u8 bTerminalID;
-+ __u16 wTerminalType;
-+ __u8 bAssocTerminal;
-+ __u8 bSourceID;
-+ __u8 iTerminal;
-+} __attribute__ ((packed));
-+
-+struct usb_audio_output_terminal_description {
-+ struct usb_audio_output_terminal_descriptor *audio_output_terminal_descriptor;
-+ __u16 wTerminalType;
-+ char * iTerminal;
-+};
-+
-+struct usb_audio_mixer_unit_descriptor_a {
-+ __u8 bFunctionLength;
-+ __u8 bDescriptorType;
-+ __u8 bDescriptorSubtype;
-+ __u8 bUniteID;
-+ __u8 bNrinPins;
-+} __attribute__ ((packed));
-+
-+struct usb_audio_mixer_unit_descriptor_b {
-+ __u8 baSourceID;
-+ __u8 bNrChannels;
-+ __u16 wChannelConfig;
-+ __u8 iChannelNames;
-+ __u8 bmControls;
-+ __u8 iMixer;
-+} __attribute__ ((packed));
-+
-+struct usb_audio_mixer_unit_description {
-+ struct usb_audio_mixer_unit_descriptor *audio_mixer_unit_descriptor;
-+ __u16 wChannelConfig;
-+ char * iMixer;
-+};
-+
-+
-+struct usb_audio_as_general_interface_descriptor {
-+ __u8 bLength;
-+ __u8 bDescriptorType;
-+ __u8 bDescriptorSubtype;
-+ __u8 bTerminalLink;
-+ __u8 bDelay;
-+ __u16 wFormatTag;
-+} __attribute__ ((packed));
-+
-+struct usb_audio_as_general_interface_description {
-+ struct usb_audio_as_general_interface_descriptor *audio_as_general_interface_descriptor;
-+ __u16 wFormatTag;
-+};
-+
-+struct usb_audio_as_format_type_descriptor {
-+ __u8 bLength;
-+ __u8 bDescriptorType;
-+ __u8 bDescriptorSubtype;
-+ __u8 bFormatType;
-+ __u8 bNrChannels;
-+ __u8 bSubFrameSize;
-+ __u8 bBitResolution;
-+ __u8 bSamFreqType;
-+ __u8 iSamFreq[3];
-+} __attribute__ ((packed));
-+
-+struct usb_audio_as_format_type_description {
-+ struct usb_audio_as_format_type_descriptor *audio_as_format_type_descriptor;
-+ __u16 wFormatTag;
-+};
-+
-+
-+
-+
-+struct usb_audio_descriptor {
-+ union {
-+ struct usb_audio_ac_interface_header_descriptor header;
-+ struct usb_audio_input_terminal_descriptor input;
-+ struct usb_audio_output_terminal_descriptor output;
-+ } descriptor;
-+} __attribute__ ((packed));
-+
-+
-+
-+struct usb_ac_endpoint_descriptor {
-+ __u8 bLength;
-+ __u8 bDescriptorType;
-+ __u8 bEndpointAddress;
-+ __u8 bmAttributes;
-+ __u16 wMaxPacketSize;
-+ __u8 bInterval;
-+ __u8 bRefresh;
-+ __u8 bSynchAddress;
-+} __attribute__ ((packed));
-+
-+
-+struct usb_as_iso_endpoint_descriptor {
-+ __u8 bLength;
-+ __u8 bDescriptorType;
-+ __u8 bDescriptorSubtype;
-+ __u8 bmAttributes;
-+ __u8 bLockDelayUnits;
-+ __u16 wLockDelay;
-+} __attribute__ ((packed));
-+
-+
-diff -Nru a/drivers/usbd/usbd-export.h b/drivers/usbd/usbd-export.h
---- /dev/null Wed Dec 31 16:00:00 1969
-+++ b/drivers/usbd/usbd-export.h Fri Feb 27 14:22:51 2004
-@@ -0,0 +1 @@
-+#define USBD_EXPORT_TAG "usbd-gpl-20040227-1420-usbd-amd-pb1x00-kit"
-diff -Nru a/drivers/usbd/usbd-fops.c b/drivers/usbd/usbd-fops.c
---- /dev/null Wed Dec 31 16:00:00 1969
-+++ b/drivers/usbd/usbd-fops.c Fri Feb 27 14:22:51 2004
-@@ -0,0 +1,589 @@
-+/*
-+ * usbd/usbd-fops.c - USB Function support
-+ *
-+ * Copyright (c) 2004 Belcarra
-+ *
-+ * Adapted from earlier work:
-+ * Copyright (c) 2002, 2003 Belcarra
-+ * Copyright (c) 2000, 2001, 2002 Lineo
-+ * Copyright (c) 2001 Hewlett Packard
-+ *
-+ * By:
-+ * Stuart Lynne <sl@belcarra.com>,
-+ * Tom Rushworth <tbr@belcarra.com>,
-+ * Bruce Balden <balden@belcarra.com>
-+ *
-+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
-+ *
-+ */
-+
-+
-+#include <linux/config.h>
-+#include <linux/module.h>
-+
-+#include <linux/init.h>
-+#include <linux/kernel.h>
-+#include <linux/list.h>
-+#include <asm/uaccess.h>
-+#include <linux/slab.h>
-+#include <linux/interrupt.h>
-+
-+#include <linux/smp_lock.h>
-+#include <linux/ctype.h>
-+#include <linux/timer.h>
-+#include <linux/string.h>
-+
-+#include "usbd-chap9.h"
-+#include "usbd-mem.h"
-+#include "usbd.h"
-+#include "usbd-func.h"
-+#include "usbd-bus.h"
-+
-+
-+struct usb_string_descriptor **usb_strings;
-+
-+extern struct list_head usbd_function_drivers;
-+extern struct usb_bus_instance *usbd_bus_instance;
-+
-+
-+/* usbd_get_string - find and return a string descriptor
-+ *
-+ * Find an indexed string and return a pointer to a it.
-+ */
-+struct usb_string_descriptor *usbd_get_string (__u8 index)
-+{
-+ RETURN_NULL_IF (index >= usbd_maxstrings);
-+ return usb_strings[index];
-+}
-+
-+/* usbd_alloc_string - allocate a string descriptor and return index number
-+ *
-+ * Find an empty slot in index string array, create a corresponding descriptor
-+ * and return the slot number.
-+ */
-+__u8 usbd_alloc_string (char *str)
-+{
-+ int i;
-+ struct usb_string_descriptor *string;
-+ __u8 bLength;
-+ __u16 *wData;
-+
-+ RETURN_ZERO_IF(!str || !strlen (str));
-+
-+ //printk(KERN_INFO"%s: %s\n", __FUNCTION__, str);
-+
-+ // find an empty string descriptor slot
-+ for (i = 1; i < usbd_maxstrings; i++) {
-+
-+ CONTINUE_IF (usb_strings[i] != NULL);
-+
-+ bLength = sizeof (struct usb_string_descriptor) + 2 * strlen (str);
-+
-+ RETURN_ZERO_IF(!(string = ckmalloc (bLength, GFP_KERNEL)));
-+
-+ string->bLength = bLength;
-+ string->bDescriptorType = USB_DT_STRING;
-+
-+ for (wData = string->wData; *str;)
-+ *wData++ = (__u16) (*str++);
-+
-+ // store in string index array
-+ usb_strings[i] = string;
-+ return i;
-+ }
-+ return 0;
-+}
-+
-+
-+/* usbd_dealloc_string - deallocate a string descriptor
-+ *
-+ * Find and remove an allocated string.
-+ */
-+void usbd_dealloc_string (__u8 index)
-+{
-+ struct usb_string_descriptor *string;
-+
-+ if ((index < usbd_maxstrings) && (string = usb_strings[index])) {
-+ usb_strings[index] = NULL;
-+ lkfree (string);
-+ }
-+}
-+
-+/* usbd_alloc_urb - allocate an URB appropriate for specified endpoint
-+ *
-+ * Allocate an urb structure. The usb device urb structure is used to
-+ * contain all data associated with a transfer, including a setup packet for
-+ * control transfers.
-+ */
-+struct urb *usbd_alloc_urb (struct usb_function_instance *function, int endpoint_index,
-+ int length, int (*callback) (struct urb *, int))
-+{
-+ struct urb *urb = NULL;
-+ struct usb_endpoint_map *endpoint_map;
-+ struct usb_endpoint_instance *endpoint;
-+ unsigned long flags;
-+
-+ //printk(KERN_INFO"%s: %s\n", __FUNCTION__, function->function_driver->name);
-+ RETURN_NULL_IF(!function);
-+ RETURN_NULL_IF(!(endpoint_map = function->endpoint_map_array));
-+ RETURN_NULL_IF(!(endpoint = endpoint_map[endpoint_index].endpoint));
-+
-+ local_irq_save(flags);
-+ THROW_IF (!(urb = ckmalloc (sizeof (struct urb), GFP_ATOMIC)), error);
-+ urb->endpoint = endpoint;
-+ urb->bus = function->bus;
-+ urb->function_instance = function;
-+ urb->link.prev = urb->link.next = &urb->link;
-+ urb->callback = callback;
-+ urb->buffer_length = urb->actual_length = 0;
-+
-+ if (length) {
-+ urb->request_length = length;
-+
-+ /* For receive we always overallocate to ensure that receiving another
-+ * full sized packet when we are only expecting a short packet will
-+ * not overflow the buffer
-+ */
-+ if (!endpoint->bEndpointAddress || endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK) {
-+ length = ((length / endpoint->wMaxPacketSize) + 1) * endpoint->wMaxPacketSize;
-+ }
-+ urb->buffer_length = length;
-+
-+ if (urb->endpoint && urb->endpoint->bEndpointAddress && urb->function_instance &&
-+ urb->function_instance->function_driver->fops->alloc_urb_data)
-+ {
-+ THROW_IF(urb->function_instance->function_driver->fops->alloc_urb_data (urb, length), error);
-+ }
-+ else {
-+ THROW_IF(!(urb->buffer = ckmalloc (length, GFP_ATOMIC)), error);
-+ }
-+ }
-+
-+ CATCH(error) {
-+ printk(KERN_ERR"%s: dealloc %p\n", __FUNCTION__, urb);
-+ usbd_dealloc_urb(urb);
-+ urb = NULL;
-+ }
-+ local_irq_restore(flags);
-+ //printk(KERN_INFO"%s: finis %p\n", __FUNCTION__, urb);
-+ return urb;
-+}
-+
-+struct urb *usbd_alloc_urb_ep0 (struct usb_function_instance *function, int length, int (*callback) (struct urb *, int))
-+{
-+ return usbd_alloc_urb(function->bus->ep0, 0, length, callback);
-+}
-+
-+/* usbd_dealloc_urb - deallocate an URB and associated buffer
-+ *
-+ * Deallocate an urb structure and associated data.
-+ */
-+void usbd_dealloc_urb (struct urb *urb)
-+{
-+ RETURN_IF (!urb);
-+ if (urb->buffer)
-+ (urb->function_instance && urb->function_instance->function_driver->fops->dealloc_urb_data) ?
-+ urb->function_instance->function_driver->fops->dealloc_urb_data : lkfree (urb->buffer);
-+ lkfree (urb);
-+}
-+
-+/* usbd_urb_callback - tell function that an urb has been transmitted.
-+ *
-+ * Must be called from an interrupt or with interrupts disabled.
-+ *
-+ * Used by a USB Bus driver to pass a sent urb back to the function
-+ * driver via the endpoints done queue.
-+ */
-+void usbd_urb_callback (struct urb *urb, int rc)
-+{
-+ RETURN_IF (!urb);
-+ if (!urb->callback || urb->callback(urb,rc))
-+ usbd_dealloc_urb(urb);
-+}
-+
-+
-+/* usbd_recv_setup_irq - process a received urb
-+ *
-+ * Used by a USB Bus interface driver to pass received data in a URB to the
-+ * appropriate USB Function driver.
-+ */
-+int usbd_recv_setup_irq (struct usb_function_instance *function, struct usb_device_request *request)
-+{
-+ return function->function_driver->fops->recv_setup_irq(request);
-+}
-+
-+void *usbd_function_get_privdata(struct usb_function_instance *function)
-+{
-+ return(function->privdata);
-+}
-+
-+void usbd_function_set_privdata(struct usb_function_instance *function, void *privdata)
-+{
-+ function->privdata = privdata;
-+}
-+
-+int usbd_endpoint_wMaxPacketSize(struct usb_function_instance *function, int endpoint_index, int hs)
-+{
-+ struct usb_endpoint_map *endpoint_map;
-+ RETURN_ZERO_IF(!(endpoint_map = function->endpoint_map_array));
-+ return le16_to_cpu(endpoint_map[endpoint_index].wMaxPacketSize[hs]);
-+}
-+
-+int usbd_endpoint_bEndpointAddress(struct usb_function_instance *function, int endpoint_index, int hs)
-+{
-+ struct usb_endpoint_map *endpoint_map;
-+ RETURN_ZERO_IF(!(endpoint_map = function->endpoint_map_array));
-+ return endpoint_map[endpoint_index].bEndpointAddress[hs];
-+}
-+
-+int usbd_endpoint_transferSize(struct usb_function_instance *function, int endpoint_index, int hs)
-+{
-+ struct usb_endpoint_map *endpoint_map;
-+ RETURN_ZERO_IF(!(endpoint_map = function->endpoint_map_array));
-+ return endpoint_map[endpoint_index].transferSize[hs];
-+}
-+
-+void usbd_endpoint_update(struct usb_function_instance *function, int endpoint_index,
-+ struct usb_endpoint_descriptor *endpoint, int hs)
-+{
-+ endpoint->bEndpointAddress = usbd_endpoint_bEndpointAddress(function, endpoint_index, hs);
-+ endpoint->wMaxPacketSize = usbd_endpoint_wMaxPacketSize(function, endpoint_index, hs);
-+}
-+
-+int usbd_endpoint_interface(struct usb_function_instance *function, int endpoint_index)
-+{
-+ struct usb_endpoint_map *endpoint_map;
-+ RETURN_ZERO_IF(!(endpoint_map = function->endpoint_map_array));
-+ return endpoint_map[endpoint_index].interface;
-+}
-+
-+int usbd_interface_AltSetting(struct usb_function_instance *function, int interface_index)
-+{
-+ // XXX TODO - per function modifications for composite devices
-+ return function->bus->alternates[interface_index];
-+}
-+
-+int usbd_ConfigurationValue(struct usb_function_instance *function)
-+{
-+ // XXX TODO - per function modifications for composite devices
-+ return function->bus->ConfigurationValue;
-+}
-+
-+int usbd_high_speed(struct usb_function_instance *function)
-+{
-+ // XXX TODO - per function modifications for composite devices
-+ return function->bus->HighSpeedFlag;
-+}
-+
-+/* usb-device USB FUNCTION generic functions ************************************************* */
-+
-+/* alloc_function_alternates - allocate alternate instance array
-+ *
-+ * Return a pointer to an array of alternate instances. Each instance contains a pointer
-+ * to a filled in alternate descriptor and a pointer to the endpoint descriptor array.
-+ *
-+ * Returning NULL will cause the caller to cleanup all previously allocated memory.
-+ */
-+static struct usb_alternate_instance *alloc_function_alternates (int bInterfaceNumber,
-+ struct usb_interface_description *interface_description,
-+ int alternates, struct usb_alternate_description *alternate_description_array)
-+{
-+ int i;
-+ struct usb_alternate_instance *alternate_instance_array;
-+
-+ // allocate array of alternate instances
-+ RETURN_NULL_IF(!(alternate_instance_array = ckmalloc (sizeof (struct usb_alternate_instance) * alternates, GFP_KERNEL)));
-+
-+ // iterate across the alternate descriptions
-+ for (i = 0; i < alternates; i++) {
-+
-+ struct usb_alternate_description *alternate_description = alternate_description_array + i;
-+ struct usb_alternate_instance *alternate_instance = alternate_instance_array + i;
-+ struct usb_interface_descriptor *interface_descriptor;
-+
-+ interface_descriptor = alternate_description->interface_descriptor;
-+ if (interface_descriptor->bInterfaceNumber != bInterfaceNumber) {
-+ printk(KERN_INFO"%s: bInterfaceNumber mis-match: %d should be %d\n", __FUNCTION__,
-+ interface_descriptor->bInterfaceNumber, bInterfaceNumber);
-+ lkfree(alternate_instance_array);
-+ return NULL;
-+ }
-+
-+ interface_descriptor->bNumEndpoints = alternate_description->endpoints;
-+ interface_descriptor->iInterface = usbd_alloc_string (alternate_description->iInterface );
-+
-+ alternate_instance->class_list = alternate_description->class_list;
-+ alternate_instance->classes = alternate_description->classes;
-+ alternate_instance->endpoint_list = alternate_description->endpoint_list;
-+ alternate_instance->endpoint_indexes = alternate_description->endpoint_indexes;
-+
-+ // save number of alternates, classes and endpoints for this alternate
-+ alternate_instance->endpoints = alternate_description->endpoints;
-+ alternate_instance->interface_descriptor = interface_descriptor;
-+ }
-+ return alternate_instance_array;
-+}
-+
-+/* alloc_function_interfaces - allocate interface instance array
-+ *
-+ * Return a pointer to an array of interface instances. Each instance contains a pointer
-+ * to a filled in interface descriptor and a pointer to the endpoint descriptor array.
-+ *
-+ * Returning NULL will cause the caller to cleanup all previously allocated memory.
-+ */
-+static struct usb_interface_instance *alloc_function_interfaces (int bNumInterfaces,
-+ struct usb_interface_description *interface_description_array)
-+{
-+ int interface;
-+ struct usb_interface_instance *interface_instance_array;
-+
-+ // allocate array of interface instances
-+ RETURN_NULL_IF(!(interface_instance_array =
-+ ckmalloc (sizeof (struct usb_interface_instance) * bNumInterfaces, GFP_KERNEL)));
-+
-+ // iterate across the interface descriptions
-+ for (interface = 0; interface < bNumInterfaces; interface++) {
-+
-+ struct usb_interface_description *interface_description = interface_description_array + interface;
-+ struct usb_interface_instance *interface_instance = interface_instance_array + interface;
-+
-+ interface_instance->alternates_instance_array =
-+ alloc_function_alternates (interface, interface_description,
-+ interface_description->alternates, interface_description->alternate_list);
-+ interface_instance->alternates = interface_description->alternates;
-+ }
-+ return interface_instance_array;
-+}
-+
-+
-+/* alloc_function_configurations - allocate configuration instance array
-+ *
-+ * Return a pointer to an array of configuration instances. Each instance contains a pointer
-+ * to a filled in configuration descriptor and a pointer to the interface instances array.
-+ *
-+ * Returning NULL will cause the caller to cleanup all previously allocated memory.
-+ */
-+static struct usb_configuration_instance *alloc_function_configurations (int bNumConfigurations,
-+ struct usb_configuration_description *configuration_description_array)
-+{
-+ int i;
-+ struct usb_configuration_instance *configuration_instance_array;
-+
-+ // allocate array
-+ RETURN_NULL_IF(!(configuration_instance_array =
-+ ckmalloc (sizeof (struct usb_configuration_instance) * bNumConfigurations, GFP_KERNEL)));
-+ // fill in array
-+ for (i = 0; i < bNumConfigurations; i++) {
-+ int j;
-+ int length;
-+
-+ struct usb_configuration_description *configuration_description = configuration_description_array + i;
-+ struct usb_configuration_descriptor *configuration_descriptor;
-+
-+ configuration_descriptor = configuration_description->configuration_descriptor;
-+
-+ // setup fields in configuration descriptor
-+ // XXX c.f. 9.4.7 zero is default, so config MUST BE 1 to n, not 0 to n-1
-+ // XXX N.B. the configuration itself is fetched 0 to n-1.
-+
-+ configuration_descriptor->bConfigurationValue = i + 1;
-+ configuration_descriptor->wTotalLength = 0;
-+ configuration_descriptor->bNumInterfaces = configuration_description->bNumInterfaces;
-+ configuration_descriptor->iConfiguration = usbd_alloc_string (configuration_description->iConfiguration);
-+
-+ // save the configuration descriptor in the configuration instance array
-+ configuration_instance_array[i].configuration_descriptor = configuration_descriptor;
-+
-+ RETURN_NULL_IF (!(configuration_instance_array[i].interface_instance_array =
-+ alloc_function_interfaces (configuration_description->bNumInterfaces,
-+ configuration_description->interface_list)));
-+
-+ length = sizeof(struct usb_configuration_descriptor);
-+
-+ for (j = 0; j < configuration_descriptor->bNumInterfaces; j++) {
-+
-+ int alternate;
-+ struct usb_interface_instance *interface_instance =
-+ configuration_instance_array[i].interface_instance_array + j;
-+
-+ //printk(KERN_INFO"%s: len: %02x:%02d configuration\n", __FUNCTION__, length, length);
-+ for (alternate = 0; alternate < interface_instance->alternates; alternate++) {
-+ int class;
-+ int endpoint;
-+ struct usb_alternate_instance *alternate_instance =
-+ interface_instance->alternates_instance_array + alternate;
-+
-+ length += sizeof (struct usb_interface_descriptor);
-+
-+ //printk(KERN_INFO"%s: len: %02x:%02d interface\n", __FUNCTION__, length, length);
-+ for (class = 0; class < alternate_instance->classes; class++) {
-+ struct usb_generic_class_descriptor * class_descriptor =
-+ *(alternate_instance->class_list + class);
-+ length += class_descriptor->bLength;
-+ //printk(KERN_INFO"%s: len: %02x:%02d class\n", __FUNCTION__, length, length);
-+ }
-+
-+ for (endpoint = 0; endpoint < alternate_instance->endpoints; endpoint++) {
-+ struct usb_endpoint_descriptor * endpoint_descriptor =
-+ *(alternate_instance->endpoint_list + endpoint);
-+ length += endpoint_descriptor->bLength;
-+ //printk(KERN_INFO"%s: len: %02x:%02d endpoint\n", __FUNCTION__, length, length);
-+ }
-+ }
-+ }
-+ configuration_descriptor->wTotalLength = cpu_to_le16 (length);
-+ configuration_instance_array[i].bNumInterfaces = configuration_description->bNumInterfaces;
-+ //printk(KERN_INFO"%s: configuration_instance_array[%d]: %p\n", __FUNCTION__, i,
-+ // &configuration_instance_array[i]);
-+ }
-+ return configuration_instance_array;
-+}
-+
-+
-+void usbd_func_event_irq(struct usb_bus_instance *bus, struct usb_function_instance *function,
-+ usb_device_event_t event , int data)
-+{
-+ function->function_driver->fops->event_irq(function, event, data);
-+}
-+
-+
-+/* usbd_register_function - register a usb function driver
-+ *
-+ * Used by a USB Function driver to register itself with the usb device layer.
-+ *
-+ * It will create a usb_function_instance structure.
-+ *
-+ * The user friendly configuration/interface/endpoint descriptions are compiled into
-+ * the equivalent ready to use descriptor records.
-+ *
-+ * All function drivers must register before any bus interface drivers.
-+ *
-+ */
-+int usbd_register_function (struct usb_function_driver *function_driver)
-+{
-+ MOD_INC_USE_COUNT;
-+ list_add_tail (&function_driver->drivers, &usbd_function_drivers);
-+ return 0;
-+}
-+
-+
-+/* usbd_deregister_function - called by a USB FUNCTION driver to deregister itself
-+ *
-+ * Called by a USB Function driver De-register a usb function driver.
-+ */
-+void usbd_deregister_function (struct usb_function_driver *function_driver)
-+{
-+ list_del (&function_driver->drivers);
-+ MOD_DEC_USE_COUNT;
-+}
-+
-+
-+int usbd_function_enable (struct usb_bus_instance *bus, struct usb_function_instance *function)
-+{
-+ struct usb_function_driver *function_driver = function->function_driver;
-+ struct usb_device_description *device_description;
-+ struct usb_device_descriptor *device_descriptor;
-+ int rc = 0;
-+
-+ function->bus = bus;
-+
-+ RETURN_EINVAL_IF(function_driver->fops->function_enable (function));
-+ RETURN_ZERO_IF(!(device_description = function_driver->device_description));
-+ RETURN_ZERO_IF(!(device_descriptor = device_description->device_descriptor));
-+
-+ device_descriptor->bMaxPacketSize0 = bus->driver->maxpacketsize;
-+ device_descriptor->iManufacturer = usbd_alloc_string (device_description->iManufacturer);
-+ device_descriptor->iProduct = usbd_alloc_string (device_description->iProduct);
-+
-+ if (bus->serial_number_str && strlen (bus->serial_number_str))
-+ device_descriptor->iSerialNumber = usbd_alloc_string (bus->serial_number_str);
-+ else
-+ device_descriptor->iSerialNumber = usbd_alloc_string (device_description->iSerialNumber);
-+
-+ device_descriptor->bNumConfigurations = function_driver->bNumConfigurations;
-+ device_descriptor->idVendor = function_driver->idVendor;
-+ device_descriptor->idProduct = function_driver->idProduct;
-+ device_descriptor->bcdDevice = function_driver->bcdDevice;
-+
-+ /* call alloc_function_configurations() to allocate the configuration descriptor array
-+ */
-+ RETURN_EINVAL_IF (!(function_driver->configuration_instance_array =
-+ alloc_function_configurations (function_driver->bNumConfigurations,
-+ function_driver->configuration_description)));
-+ function_driver->device_descriptor = device_descriptor;
-+ function_driver->device_qualifier_descriptor = device_description->device_qualifier_descriptor;
-+ return rc;
-+}
-+
-+
-+void usbd_function_disable (struct usb_function_instance *function)
-+{
-+ int configuration;
-+ struct usb_function_driver *function_driver = function->function_driver;
-+ struct usb_configuration_instance *configuration_instance_array = function_driver->configuration_instance_array;
-+
-+ function->function_driver->fops->function_disable (function);
-+
-+ RETURN_IF(!function_driver->configuration_instance_array);
-+
-+ // iterate across the descriptors list and de-allocate all structures
-+ if (function_driver->configuration_instance_array) {
-+ for (configuration = 0; configuration < function_driver->bNumConfigurations; configuration++) {
-+ int interface;
-+ struct usb_configuration_instance *configuration_instance = configuration_instance_array + configuration;
-+
-+ for (interface = 0; interface < configuration_instance->bNumInterfaces; interface++) {
-+
-+ //int alternate;
-+ struct usb_interface_instance *interface_instance =
-+ configuration_instance->interface_instance_array + interface;
-+
-+ lkfree (interface_instance->alternates_instance_array);
-+ }
-+ lkfree (configuration_instance->interface_instance_array);
-+ //usbd_dealloc_descriptor_strings( (struct usb_descriptor *)
-+ // configuration_instance_array[configuration].configuration_descriptor);
-+ }
-+ }
-+
-+ //usbd_dealloc_descriptor_strings ((struct usb_descriptor *) function_driver->device_descriptor);
-+ lkfree (configuration_instance_array);
-+
-+ function->bus = NULL;
-+}
-+
-+EXPORT_SYMBOL(usbd_register_function );
-+EXPORT_SYMBOL(usbd_deregister_function);
-+EXPORT_SYMBOL(usbd_alloc_string);
-+EXPORT_SYMBOL(usbd_dealloc_string);
-+EXPORT_SYMBOL(usbd_get_string);
-+EXPORT_SYMBOL(usbd_alloc_urb);
-+EXPORT_SYMBOL(usbd_alloc_urb_ep0);
-+EXPORT_SYMBOL(usbd_dealloc_urb);
-+EXPORT_SYMBOL(usbd_recv_setup_irq);
-+EXPORT_SYMBOL(usbd_urb_callback);
-+EXPORT_SYMBOL(usbd_endpoint_halted);
-+EXPORT_SYMBOL(usbd_device_feature);
-+EXPORT_SYMBOL(usbd_function_get_privdata);
-+EXPORT_SYMBOL(usbd_function_set_privdata);
-+
-+EXPORT_SYMBOL(usbd_endpoint_wMaxPacketSize);
-+EXPORT_SYMBOL(usbd_endpoint_bEndpointAddress);
-+EXPORT_SYMBOL(usbd_endpoint_interface);
-+EXPORT_SYMBOL(usbd_endpoint_transferSize);
-+EXPORT_SYMBOL(usbd_interface_AltSetting);
-+EXPORT_SYMBOL(usbd_ConfigurationValue);
-+EXPORT_SYMBOL(usbd_high_speed);
-+EXPORT_SYMBOL(usbd_endpoint_update);
-diff -Nru a/drivers/usbd/usbd-func.h b/drivers/usbd/usbd-func.h
---- /dev/null Wed Dec 31 16:00:00 1969
-+++ b/drivers/usbd/usbd-func.h Fri Feb 27 14:22:51 2004
-@@ -0,0 +1,256 @@
-+/*
-+ * usbd/usbd-func.h - USB Device Function Driver Interface
-+ *
-+ * Copyright (c) 2004 Belcarra
-+ *
-+ * Adapted from earlier work:
-+ * Copyright (c) 2002, 2003 Belcarra
-+ * Copyright (c) 2000, 2001, 2002 Lineo
-+ * Copyright (c) 2001 Hewlett Packard
-+ *
-+ * By:
-+ * Stuart Lynne <sl@belcarra.com>,
-+ * Tom Rushworth <tbr@belcarra.com>,
-+ * Bruce Balden <balden@belcarra.com>
-+ *
-+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
-+ *
-+ */
-+
-+/*
-+ * This file contains the USB Function Driver Interface definitions.
-+ *
-+ * This is the interface between the bottom of the USB Function drivers and
-+ * the top of the USB Core and is comprised of:
-+ *
-+ * o public functions exported by the USB Core layer
-+ *
-+ * o structures and functions passed by the Bus Interface Driver to the
-+ * USB Core layer
-+ *
-+ *
-+ * USB Function Drivers are structured such that the upper edge implements
-+ * some specific function (network, serial, mass storage etc) and the lower
-+ * edge interfaces to the USB Device Core for USB services.
-+ *
-+ */
-+
-+/*
-+ * USB Function Driver structures
-+ *
-+ * Descriptors:
-+ * struct usb_endpoint_description
-+ * struct usb_interface_description
-+ * struct usb_configuration_description
-+ *
-+ * Driver description:
-+ * struct usb_function_driver
-+ * struct usb_function_operations
-+ *
-+ */
-+
-+struct usb_function_operations {
-+ int (*function_enable) (struct usb_function_instance *);
-+ void (*function_disable) (struct usb_function_instance *);
-+ void (*event_irq) (struct usb_function_instance *, usb_device_event_t, int);
-+ int (*recv_setup_irq) (struct usb_device_request *);
-+ int (*alloc_urb_data) (struct urb *, int);
-+ void (*dealloc_urb_data) (struct urb *);
-+};
-+
-+
-+/*
-+ * function driver definitions
-+ */
-+struct usb_alternate_instance {
-+ struct usb_interface_descriptor *interface_descriptor;
-+ int classes;
-+ struct usb_generic_class_descriptor **class_list;
-+ int endpoints;
-+ struct usb_endpoint_descriptor **endpoint_list;
-+ u8 *endpoint_indexes;
-+};
-+
-+
-+/*
-+ * usb device description structures
-+ */
-+
-+struct usb_alternate_description {
-+ struct usb_interface_descriptor *interface_descriptor;
-+ char *iInterface;
-+
-+ // list of CDC class descriptions for this alternate interface
-+ u8 classes;
-+ struct usb_generic_class_descriptor **class_list;
-+
-+ // list of endpoint descriptions for this alternate interface
-+ u8 endpoints;
-+ struct usb_endpoint_descriptor **endpoint_list;
-+
-+ // list of indexes into endpoint request map for each endpoint descriptor
-+ u8 *endpoint_indexes;
-+};
-+
-+struct usb_interface_description {
-+ // list of alternate interface descriptions for this interface
-+ u8 alternates;
-+ struct usb_alternate_description *alternate_list;
-+};
-+
-+struct usb_configuration_description {
-+ struct usb_configuration_descriptor *configuration_descriptor;
-+ char *iConfiguration;
-+ // list of interface descriptons for this configuration
-+ u8 bNumInterfaces;
-+ struct usb_interface_description *interface_list;
-+ int configuration_type;
-+};
-+
-+struct usb_device_description {
-+ struct usb_device_descriptor *device_descriptor;
-+ struct usb_device_qualifier_descriptor *device_qualifier_descriptor;
-+ char *iManufacturer;
-+ char *iProduct;
-+ char *iSerialNumber;
-+ u8 endpointsRequested;
-+ struct usb_endpoint_request *requestedEndpoints;
-+ struct usb_function_endpoint_config *endpointConfig;
-+};
-+
-+
-+struct usb_interface_instance {
-+ u8 alternates;
-+ struct usb_alternate_instance *alternates_instance_array;
-+};
-+
-+struct usb_configuration_instance {
-+ int bNumInterfaces;
-+ struct usb_configuration_descriptor *configuration_descriptor;
-+ struct usb_interface_instance *interface_instance_array;
-+ struct usb_function_driver *function_driver;
-+};
-+
-+
-+extern struct usb_string_descriptor **usb_strings;
-+__u8 usbd_alloc_string (char *);
-+void usbd_dealloc_string (__u8 );
-+void usbd_dealloc_descriptor_strings (struct usb_descriptor *);
-+struct usb_string_descriptor *usbd_get_string (__u8);
-+
-+
-+
-+
-+/* Function Driver data structure
-+ *
-+ * Function driver and its configuration descriptors.
-+ *
-+ * This is passed to the usb-device layer when registering. It contains all
-+ * required information about the function driver for the usb-device layer
-+ * to use the function drivers configuration data and to configure this
-+ * function driver an active configuration.
-+ *
-+ * Note that each function driver registers itself on a speculative basis.
-+ * Whether a function driver is actually configured will depend on the USB
-+ * HOST selecting one of the function drivers configurations.
-+ *
-+ * This may be done multiple times WRT to either a single bus interface
-+ * instance or WRT to multiple bus interface instances. In other words a
-+ * multiple configurations may be selected for a specific bus interface. Or
-+ * the same configuration may be selected for multiple bus interfaces.
-+ *
-+ */
-+struct usb_function_driver {
-+ const char *name;
-+ struct usb_function_operations *fops; // functions
-+
-+ // device & configuration descriptions
-+ struct usb_device_description *device_description;
-+ struct usb_configuration_description *configuration_description;
-+ int bNumConfigurations;
-+
-+ u16 idVendor;
-+ u16 idProduct;
-+ u16 bcdDevice;
-+
-+ // constructed descriptors
-+ struct usb_device_descriptor *device_descriptor;
-+ struct usb_device_qualifier_descriptor *device_qualifier_descriptor;
-+ struct usb_configuration_instance *configuration_instance_array;
-+
-+ struct list_head drivers; // linked list
-+};
-+
-+
-+struct usb_function_instance;
-+
-+/* function driver registration
-+ *
-+ * Called by function drivers to register themselves when loaded
-+ * or de-register when unloading.
-+ */
-+//int usbd_strings_init(void);
-+int usbd_register_function (struct usb_function_driver *);
-+void usbd_deregister_function (struct usb_function_driver *);
-+
-+/* Access to function privdata
-+ */
-+void *usbd_function_get_privdata(struct usb_function_instance *function);
-+void usbd_function_set_privdata(struct usb_function_instance *function, void *privdata);
-+/*
-+ * Called to queue urb's for send or recv
-+ */
-+int usbd_send_urb (struct urb *urb);
-+int usbd_start_recv (struct urb *);
-+
-+/*
-+ * queury endpoint astatus
-+ */
-+int usbd_endpoint_halted (struct usb_function_instance *, int);
-+int usbd_device_feature (struct usb_function_instance *, int, int);
-+
-+
-+/*
-+ * query bus state and status
-+ */
-+usb_device_state_t usbd_device_state(struct usb_function_instance *);
-+usbd_bus_state_t usbd_bus_state(struct usb_function_instance *);
-+usb_device_status_t usbd_bus_status(struct usb_function_instance *);
-+
-+
-+/* urb allocation
-+ *
-+ * Used to allocate and de-allocate urb structures.
-+ * usb_cancel_urb is used to cancel a previously submitted data urb for sending.
-+ */
-+struct urb *usbd_alloc_urb (struct usb_function_instance *, int, int length, int (*callback) (struct urb *, int));
-+struct urb *usbd_alloc_urb_ep0 (struct usb_function_instance *, int length, int (*callback) (struct urb *, int));
-+void usbd_dealloc_urb (struct urb *urb);
-+int usbd_alloc_urb_data (struct urb *, int);
-+int usbd_cancel_urb_irq (struct urb *);
-+
-+/* endpoint information
-+ *
-+ * Used by function drivers to get specific endpoint information
-+ */
-+int usbd_endpoint_wMaxPacketSize(struct usb_function_instance *, int, int);
-+int usbd_endpoint_bEndpointAddress(struct usb_function_instance *, int, int);
-+int usbd_endpoint_transferSize(struct usb_function_instance *, int, int);
-+int usbd_endpoint_interface(struct usb_function_instance *, int);
-+int usbd_interface_AltSetting(struct usb_function_instance *, int);
-+int usbd_ConfigurationValue(struct usb_function_instance *);
-+void usbd_endpoint_update(struct usb_function_instance *, int , struct usb_endpoint_descriptor *, int);
-+int usbd_high_speed(struct usb_function_instance *);
-+
-diff -Nru a/drivers/usbd/usbd-mem.h b/drivers/usbd/usbd-mem.h
---- /dev/null Wed Dec 31 16:00:00 1969
-+++ b/drivers/usbd/usbd-mem.h Fri Feb 27 14:22:51 2004
-@@ -0,0 +1,146 @@
-+/*
-+ * usbd/usbd-mem.h
-+ *
-+ * Copyright (c) 2004 Belcarra
-+ *
-+ * Adapted from earlier work:
-+ * Copyright (c) 2002, 2003 Belcarra
-+ * Copyright (c) 2000, 2001, 2002 Lineo
-+ * Copyright (c) 2001 Hewlett Packard
-+ *
-+ * By:
-+ * Stuart Lynne <sl@belcarra.com>,
-+ * Tom Rushworth <tbr@belcarra.com>,
-+ * Bruce Balden <balden@belcarra.com>
-+ *
-+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
-+ *
-+ */
-+
-+
-+#ifndef MODULE
-+#undef __init
-+#define __init
-+#undef __exit
-+#define __exit
-+#undef THIS_MODULE
-+#define THIS_MODULE 0
-+#endif
-+
-+#define USBD_MODULE_INFO(info) static const char __usbd_module_info[] = info " " USBD_BUILD " %D% %@%";
-+
-+
-+#ifndef MIN
-+#define MIN(a,b) ((a) < (b) ? (a) : (b))
-+#endif
-+#ifndef MAX
-+#define MAX(a,b) ((a) > (b) ? (a) : (b))
-+#endif
-+#define CATCH(x) while(0) x:
-+#define THROW(x) goto x
-+#define THROW_IF(e, x) if (e) goto x;
-+#define BREAK_IF(x) if (x) break;
-+#define CONTINUE_IF(x) if (x) continue;
-+#define RETURN_IF(x) if (x) return;
-+#define RETURN_ZERO_IF(x) if (x) return 0;
-+#define RETURN_EINVAL_IF(x) if (x) return -EINVAL;
-+#define RETURN_EFAULT_IF(x) if (x) return -EFAULT;
-+#define RETURN_ENOMEM_IF(x) if (x) return -ENOMEM;
-+#define RETURN_EBUSY_IF(x) if (x) return -EBUSY;
-+#define RETURN_NULL_IF(x) if (x) return NULL;
-+#define unless(x) if(!(x))
-+#define UNLESS(x) if(!(x))
-+#define RETURN_UNLESS(x) UNLESS (x) return;
-+#define RETURN_ZERO_UNLESS(x) UNLESS (x) return 0;
-+#define CONTINUE_UNLESS(x) UNLESS (x) continue;
-+
-+
-+#ifndef likely
-+#define likely(x) x
-+#endif
-+
-+#ifndef unlikely
-+#define unlikely(x) x
-+#endif
-+
-+#define ckmalloc(n,f) _ckmalloc(__FUNCTION__, __LINE__, n, f)
-+#define lstrdup(str) _lstrdup(__FUNCTION__, __LINE__, str)
-+#define lkfree(p) _lkfree(__FUNCTION__, __LINE__, p)
-+
-+#define MALLOC_TEST
-+#undef MALLOC_DEBUG
-+
-+#ifdef MALLOC_TEST
-+extern int usbd_mallocs;
-+#endif
-+
-+
-+static __inline__ void *_ckmalloc (char *func, int line, int n, int f)
-+{
-+ void *p;
-+ if ((p = kmalloc (n, f)) == NULL) {
-+ return NULL;
-+ }
-+ memset (p, 0, n);
-+#ifdef MALLOC_TEST
-+ ++usbd_mallocs;
-+#endif
-+#ifdef MALLOC_DEBUG
-+ printk(KERN_INFO"%s: %p %s %d %d\n", __FUNCTION__, p, func, line, usbd_mallocs);
-+#endif
-+ return p;
-+}
-+
-+static __inline__ char *_lstrdup (char *func, int line, char *str)
-+{
-+ int n;
-+ char *s;
-+ if (str && (n = strlen (str) + 1) && (s = kmalloc (n, GFP_ATOMIC))) {
-+#ifdef MALLOC_TEST
-+ ++usbd_mallocs;
-+#endif
-+#ifdef MALLOC_DEBUG
-+ printk(KERN_INFO"%s: %p %s %d %d\n", __FUNCTION__, s, func, line, usbd_mallocs);
-+#endif
-+ return strcpy (s, str);
-+ }
-+ return NULL;
-+}
-+
-+static __inline__ void _lkfree (char *func, int line, void *p)
-+{
-+ if (p) {
-+#ifdef MALLOC_TEST
-+ --usbd_mallocs;
-+#endif
-+#ifdef MALLOC_DEBUG
-+ printk(KERN_INFO"%s: %p %s %d %d\n", __FUNCTION__, p, func, line, usbd_mallocs);
-+#endif
-+ kfree (p);
-+#ifdef MALLOC_TEST
-+ if (usbd_mallocs < 0) {
-+ printk(KERN_INFO"%s: %p %s %d %d usbd_mallocs less zero!\n", __FUNCTION__, p, func, line, usbd_mallocs);
-+ }
-+#endif
-+ }
-+#ifdef MALLOC_DEBUG
-+ else {
-+ printk(KERN_INFO"%s: %s %d NULL\n", __FUNCTION__, func, line);
-+ }
-+#endif
-+}
-+
-+
-+
-diff -Nru a/drivers/usbd/usbd-procfs.c b/drivers/usbd/usbd-procfs.c
---- /dev/null Wed Dec 31 16:00:00 1969
-+++ b/drivers/usbd/usbd-procfs.c Fri Feb 27 14:22:51 2004
-@@ -0,0 +1,337 @@
-+/*
-+ * usbd/usbd-procfs.c - USB Device Core Layer
-+ *
-+ * Copyright (c) 2004 Belcarra
-+ *
-+ * Adapted from earlier work:
-+ * Copyright (c) 2002, 2003 Belcarra
-+ * Copyright (c) 2000, 2001, 2002 Lineo
-+ * Copyright (c) 2001 Hewlett Packard
-+ *
-+ * By:
-+ * Stuart Lynne <sl@belcarra.com>,
-+ * Tom Rushworth <tbr@belcarra.com>,
-+ * Bruce Balden <balden@belcarra.com>
-+ *
-+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
-+ *
-+ */
-+
-+
-+#include <linux/config.h>
-+#include <linux/module.h>
-+#include <linux/kernel.h>
-+#include <linux/version.h>
-+
-+EXPORT_NO_SYMBOLS;
-+
-+#include "usbd-export.h"
-+#include "usbd-build.h"
-+
-+#ifdef MODULE
-+MODULE_AUTHOR ("sl@lineo.com, tbr@lineo.com");
-+MODULE_DESCRIPTION ("USB Device Core Support Procfs");
-+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,17)
-+MODULE_LICENSE("GPL");
-+#endif
-+
-+#endif
-+
-+#include <linux/init.h>
-+#include <linux/list.h>
-+#include <linux/proc_fs.h>
-+#include <asm/uaccess.h>
-+#include <linux/slab.h>
-+#include <linux/interrupt.h>
-+
-+#include <linux/smp_lock.h>
-+#include <linux/ctype.h>
-+#include <linux/timer.h>
-+#include <linux/string.h>
-+
-+#include "usbd-chap9.h"
-+#include "usbd-mem.h"
-+#include "usbd.h"
-+#include "usbd-func.h"
-+#include "usbd-bus.h"
-+
-+USBD_MODULE_INFO ("usbdprocfs 2.0-beta");
-+
-+#define MAX_INTERFACES 2
-+
-+extern struct list_head usbd_function_drivers;
-+extern struct usb_bus_instance *usbd_bus_instance;
-+
-+
-+#ifdef CONFIG_USBD_PROCFS
-+/* Proc Filesystem *************************************************************************** */
-+
-+
-+/* *
-+ * dohex
-+ *
-+ */
-+static void dohexdigit (char *cp, unsigned char val)
-+{
-+ if (val < 0xa) {
-+ *cp = val + '0';
-+ } else if ((val >= 0x0a) && (val <= 0x0f)) {
-+ *cp = val - 0x0a + 'a';
-+ }
-+}
-+
-+/* *
-+ * dohex
-+ *
-+ */
-+static void dohexval (char *cp, unsigned char val)
-+{
-+ dohexdigit (cp++, val >> 4);
-+ dohexdigit (cp++, val & 0xf);
-+}
-+
-+/* *
-+ * dump_descriptor
-+ */
-+static int dump_descriptor (char *buf, char *sp)
-+{
-+ int num = *sp;
-+ int len = 0;
-+
-+ //printk(KERN_INFO"%s: %p %d %d %d\n", __FUNCTION__, buf, *buf, buf[0], num);
-+
-+ while (sp && num--) {
-+ dohexval (buf, *sp++);
-+ buf += 2;
-+ *buf++ = ' ';
-+ len += 3;
-+ }
-+ len++;
-+ *buf = '\n';
-+ return len;
-+}
-+
-+/* dump_descriptors
-+ */
-+static int dump_config_descriptor(char *buf, char *sp)
-+{
-+ struct usb_configuration_descriptor *config = (struct usb_configuration_descriptor *) sp;
-+
-+ int wTotalLength = le16_to_cpu(config->wTotalLength);
-+ int bConfigurationValue = config->bConfigurationValue;
-+ int interface;
-+ int class;
-+ int endpoint;
-+ int total;
-+
-+ interface = class = endpoint = 0;
-+
-+ for (total = 0; wTotalLength; ) {
-+ //printk(KERN_INFO"%s: wTotalLength: %d total: %d bLength: %d\n",
-+ // __FUNCTION__, wTotalLength, total, sp[0]);
-+ switch (sp[1]) {
-+ case USB_DESCRIPTOR_TYPE_CONFIGURATION:
-+ interface = class = endpoint = 0;
-+ total += sprintf(buf + total, "\nConfiguration descriptor [%d ] ",
-+ bConfigurationValue);
-+ break;
-+ case USB_DESCRIPTOR_TYPE_INTERFACE:
-+ class = 0;
-+ total += sprintf(buf + total, "\nInterface descriptor [%d:%d:%d ] ",
-+ bConfigurationValue, ++interface, class);
-+ break;
-+ case USB_DESCRIPTOR_TYPE_ENDPOINT:
-+ class = endpoint = 0;
-+ total += sprintf(buf + total, "Endpint descriptor [%d:%d:%d:%d] ",
-+ bConfigurationValue, interface, class, ++endpoint);
-+ break;
-+ default:
-+ endpoint = 0;
-+ total += sprintf(buf + total, "Class descriptor [%d:%d:%d ] ",
-+ bConfigurationValue, interface, ++class);
-+ break;
-+ }
-+ total += dump_descriptor(buf + total, sp);
-+ wTotalLength -= sp[0];
-+ sp += sp[0];
-+ }
-+ total += sprintf(buf + total, "\n");
-+ return total;
-+}
-+
-+/* *
-+ * usbd_device_proc_read - implement proc file system read.
-+ * @file
-+ * @buf
-+ * @count
-+ * @pos
-+ *
-+ * Standard proc file system read function.
-+ *
-+ * We let upper layers iterate for us, *pos will indicate which device to return
-+ * statistics for.
-+ */
-+static ssize_t usbd_device_proc_read_functions (struct file *file, char *buf, size_t count, loff_t * pos)
-+{
-+ unsigned long page;
-+ int len = 0;
-+ int index;
-+
-+ u8 config_descriptor[512];
-+ int config_size;
-+
-+ //struct list_head *lhd;
-+
-+ // get a page, max 4095 bytes of data...
-+ if (!(page = get_free_page (GFP_KERNEL))) {
-+ return -ENOMEM;
-+ }
-+
-+ len = 0;
-+ index = (*pos)++;
-+
-+ if (index == 0) {
-+ len += sprintf ((char *) page + len, "usb-device list\n");
-+ }
-+
-+ //printk(KERN_INFO"%s: index: %d len: %d\n", __FUNCTION__, index, len);
-+
-+ if (usbd_bus_instance && usbd_bus_instance->function_instance) {
-+ int configuration = index;
-+ struct usb_function_instance *function_instance = usbd_bus_instance->function_instance;
-+ struct usb_function_driver *function_driver = function_instance->function_driver;
-+ struct usb_configuration_instance *configuration_instance_array = function_driver->configuration_instance_array;
-+ if (configuration_instance_array) {
-+
-+ if (index == 0) {
-+ len += sprintf ((char *) page + len, "\nDevice descriptor ");
-+ len += dump_descriptor ((char *) page + len, (char *) function_driver->device_descriptor);
-+#ifdef CONFIG_USBD_HIGH_SPEED
-+ len += sprintf ((char *) page + len, "\nDevice Qualifier descriptor ");
-+ len += dump_descriptor ((char *) page + len,
-+ (char *) function_driver->device_qualifier_descriptor);
-+#endif
-+ }
-+ if (configuration < function_driver->bNumConfigurations) {
-+
-+ if ((config_size = usbd_get_descriptor(usbd_bus_instance, config_descriptor,
-+ sizeof(config_descriptor),
-+ USB_DESCRIPTOR_TYPE_CONFIGURATION, 0)) > index) {
-+ len += dump_config_descriptor((char *)page + len, config_descriptor );
-+ }
-+#ifdef CONFIG_USBD_HIGH_SPEED
-+ if ((config_size = usbd_get_descriptor(usbd_bus_instance, config_descriptor,
-+ sizeof(config_descriptor),
-+ USB_DESCRIPTOR_TYPE_OTHER_SPEED_CONFIGURATION, index)) > 0) {
-+ len += dump_config_descriptor((char *)page + len, config_descriptor );
-+ }
-+
-+#endif
-+ }
-+ else if (configuration == function_driver->bNumConfigurations) {
-+ int i;
-+ int k;
-+ struct usb_string_descriptor *string_descriptor;
-+
-+ //len += sprintf ((char *) page + len, "\n\n");
-+
-+ if ((string_descriptor = usbd_get_string (0)) != NULL) {
-+ len += sprintf ((char *) page + len, "String [%2d] ", 0);
-+
-+ for (k = 0; k < (string_descriptor->bLength / 2) - 1; k++) {
-+ len += sprintf ((char *) page + len, "%02x %02x ",
-+ string_descriptor->wData[k] >> 8,
-+ string_descriptor->wData[k] & 0xff);
-+ len++;
-+ }
-+ len += sprintf ((char *) page + len, "\n");
-+ }
-+
-+ for (i = 1; i < usbd_maxstrings; i++) {
-+
-+ if ((string_descriptor = usbd_get_string (i)) != NULL) {
-+
-+ len += sprintf((char *)page+len, "String [%2d:%2d] ",
-+ i, string_descriptor->bLength);
-+
-+ // bLength = sizeof(struct usb_string_descriptor) + 2*strlen(str)-2;
-+
-+ for (k = 0; k < (string_descriptor->bLength / 2) - 1; k++) {
-+ *(char *) (page + len) = (char) string_descriptor->wData[k];
-+ len++;
-+ }
-+ len += sprintf ((char *) page + len, "\n");
-+ }
-+ }
-+ len += sprintf((char *)page + len, "\n--\n");
-+ }
-+ }
-+ }
-+
-+ //printk(KERN_INFO"%s: len: %d count: %d\n", __FUNCTION__, len, count);
-+
-+ if (len > count) {
-+ //printk(KERN_INFO"%s: len > count\n", __FUNCTION__);
-+ //printk(KERN_INFO"%s", page);
-+ len = -EINVAL;
-+ }
-+ else if ((len > 0) && copy_to_user (buf, (char *) page, len)) {
-+ //printk(KERN_INFO"%s: EFAULT\n", __FUNCTION__);
-+ len = -EFAULT;
-+ }
-+ else {
-+ //printk(KERN_INFO"%s: OK\n", __FUNCTION__);
-+ }
-+ free_page (page);
-+ return len;
-+}
-+
-+static struct file_operations usbd_device_proc_operations_functions = {
-+read:usbd_device_proc_read_functions,
-+};
-+
-+#endif
-+
-+
-+
-+/* Module init ******************************************************************************* */
-+
-+
-+static int usbd_procfs_init (void)
-+{
-+#ifdef CONFIG_USBD_PROCFS
-+ {
-+ struct proc_dir_entry *p;
-+
-+ // create proc filesystem entries
-+ if ((p = create_proc_entry ("usb-functions", 0, 0)) == NULL)
-+ return -ENOMEM;
-+ p->proc_fops = &usbd_device_proc_operations_functions;
-+ }
-+#endif
-+ return 0;
-+}
-+
-+static void usbd_procfs_exit (void)
-+{
-+#ifdef CONFIG_USBD_PROCFS
-+ // remove proc filesystem entry
-+ remove_proc_entry ("usb-functions", NULL);
-+#endif
-+}
-+
-+module_init (usbd_procfs_init);
-+module_exit (usbd_procfs_exit);
-+
-diff -Nru a/drivers/usbd/usbd.c b/drivers/usbd/usbd.c
---- /dev/null Wed Dec 31 16:00:00 1969
-+++ b/drivers/usbd/usbd.c Fri Feb 27 14:22:51 2004
-@@ -0,0 +1,663 @@
-+/*
-+ * usbd/usbd.c - USB Device Core Layer
-+ *
-+ * Copyright (c) 2004 Belcarra
-+ *
-+ * By:
-+ * Stuart Lynne <sl@belcarra.com>,
-+ * Tom Rushworth <tbr@belcarra.com>,
-+ * Bruce Balden <balden@belcarra.com>
-+ *
-+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
-+ *
-+ */
-+
-+#include <linux/config.h>
-+#include <linux/module.h>
-+#include <linux/kernel.h>
-+#include <linux/version.h>
-+#include <linux/interrupt.h>
-+#include <linux/init.h>
-+#include <asm/uaccess.h>
-+#include <linux/slab.h>
-+#include <linux/proc_fs.h>
-+#include <linux/ctype.h>
-+#include <linux/string.h>
-+#if defined(CONFIG_PM)
-+#include <linux/pm.h>
-+#endif
-+
-+#include "usbd-export.h"
-+#include "usbd-build.h"
-+#include "usbd-chap9.h"
-+#include "usbd-mem.h"
-+#include "usbd.h"
-+#include "usbd-func.h"
-+#include "usbd-bus.h"
-+#include "usbd-admin.h"
-+
-+MODULE_AUTHOR ("sl@lineo.com, tbr@lineo.com");
-+MODULE_DESCRIPTION ("USB Device Core Support");
-+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,17)
-+MODULE_LICENSE("GPL");
-+#endif
-+USBD_MODULE_INFO ("usbdcore 2.0-beta");
-+
-+int usbd_maxstrings = 20;
-+extern int usbd_switch_init(void);
-+LIST_HEAD (usbd_function_drivers); // list of all registered function modules
-+struct usb_bus_instance *usbd_bus_instance;
-+#ifdef MALLOC_TEST
-+int usbd_mallocs;
-+#endif
-+
-+/* ******************************************************************************************* */
-+/*
-+ * USBD Switch will make direct calls to the appropriate modinit/modexit and
-+ * bus interface bi_modinit/bi_modexit functions to load and unload as appropriate.
-+ *
-+ *
-+ * The following entry points are exported:
-+ *
-+ * int usbd_enable(void)
-+ * int usbd_disable(char *name)
-+ * int usbd_disconnect(char *name)
-+ * int usbd_connect(char *name)
-+ * int usbd_pm_on(char *name)
-+ * int usbd_pm_off(char *name)
-+ *
-+ * int usbd_unload(void)
-+ * int usbd_load(char *name)
-+ * int usbd_unplug(char *name)
-+ * int usbd_replug(char *name)
-+ *
-+ *
-+ * If CONFIG_PROCFS is defined then the following commands can be given to /proc/usbd-switch:
-+ *
-+ * enable
-+ * enable name
-+ * disable
-+ * disconnect
-+ * connect
-+ *
-+ * serial_number
-+ * debug
-+ * nodebug
-+ *
-+ *
-+ * There are four different styles of operations that can be used:
-+ *
-+ * 1. switch - change or configure the device function by sending any
-+ * one of a number of commands to the switch interface [1] of
-+ * usbd-switch:
-+ *
-+ * - echo "serial_number xxxxx" > /proc/usbd-switch
-+ * - echo "enable network_fd" > /proc/usbd-switch
-+ * - echo "disconnect" > /proc/usbd-switch
-+ * - echo "connect" > /proc/usbd-switch
-+ * - echo "disable" > /proc/usbd-switch
-+ *
-+ * serial_number - set the serial number string
-+ * enable function - set current function and enable function and bus interface
-+ * enable - enable current function and bus interface
-+ * disable - disable bus interface and current function
-+ * connect - enable current function and bus interface and connect pullup resistor
-+ * disconnect - unload bus interface, current function and reset current function,
-+ * and disconnect pullup resistor
-+ *
-+ * 2. simple power management
-+ *
-+ * - EXPORT_SYMBOL(usbd_enable);
-+ * - EXPORT_SYMBOL(usbd_disable);
-+ * - EXPORT_SYMBOL(usbd_disconnect);
-+ * - EXPORT_SYMBOL(usbd_connect);
-+ * - EXPORT_SYMBOL(usbd_pm_on);
-+ * - EXPORT_SYMBOL(usbd_pm_off);
-+ *
-+ * Deprecated:
-+ *
-+ * - EXPORT_SYMBOL(usbd_load);
-+ * - EXPORT_SYMBOL(usbd_unload);
-+ * - EXPORT_SYMBOL(usbd_unplug);
-+ * - EXPORT_SYMBOL(usbd_replug);
-+ *
-+ * usbd_enable() - load function and bus interface
-+ * usbd_disable() - unload bus interface and function
-+ *
-+ * usbd_connect() - connect
-+ * usbd_disconnect() - disconnect
-+ *
-+ * usbd_pm_on() - connect
-+ * usbd_pm_off() - disconnect
-+ *
-+ * usbd_load() - load function and bus interface
-+ * usbd_unload() - unload bus interface and function
-+ * usbd_unplug() - disconnect
-+ * usbd_replug() - connect
-+ *
-+ * 3. official power management CONFIG_PM [not tested yet]
-+ *
-+ * Perform unplug and plug functions appropriate for CONFIG_PM actions.
-+ *
-+ *
-+ * N.B.
-+ *
-+ * [1] The switch interface is only available when the USB device stack
-+ * and usbd-switch are compiled into the kernel. It is not available
-+ * when the USB device stack consists of loadable modules.
-+ *
-+ * [2] Cable detection requires implementation of architecture specific
-+ * code that knows about the appropriate interrupt, GPIO pins etc.
-+ *
-+ */
-+
-+
-+extern struct list_head usbd_function_drivers;
-+
-+
-+/*
-+ * This is a table of function drivers that are compiled into the kernel.
-+ */
-+
-+#define MAX_FUNC_NAME_LEN 64
-+char current_function[MAX_FUNC_NAME_LEN+1];
-+int switch_debug = 0;
-+
-+char *usbd_load_arg;
-+
-+int switch_exiting;
-+struct tq_struct enable_bh;
-+struct tq_struct disable_bh;
-+
-+
-+
-+/* ******************************************************************************************* */
-+
-+static DECLARE_MUTEX(usbd_sem); // protect against multiple administrative actions overlapping
-+
-+extern struct usb_bus_instance *usbd_bus_instance;
-+
-+char *usbd_admin_names[] = {
-+ "enable", "disable", "connect", "disconnect", "pm_off", "pm_on", "serial_number",
-+};
-+
-+char *usbd_admin_aliases[] = {
-+ "load", "unload", "replug", "unplug", "pm_off", "pm_on", "serial_number_str",
-+};
-+
-+
-+/* usbd_admin -
-+ */
-+static int usbd_admin(usbd_admin_t usbd_admin_ndx, char *arg)
-+{
-+
-+ printk(KERN_INFO"%s: %s current: %s arg: %s\n", __FUNCTION__,
-+ usbd_admin_names[usbd_admin_ndx],
-+ current_function[0] ? current_function : "(EMPTY)",
-+ (arg && arg[0]) ? arg : "(EMPTY)");
-+
-+ RETURN_EINVAL_IF(in_interrupt() || down_interruptible(&usbd_sem));
-+
-+ /*
-+ *
-+ */
-+ if (usbd_admin_ndx == usbd_admin_enable && (NULL == arg || 0 == *arg)) {
-+ // s/enable/enable current_function/
-+ arg = current_function;
-+ }
-+
-+ THROW_IF(!usbd_bus_instance, error);
-+
-+ THROW_IF (!usbd_bus_instance->admin[usbd_admin_ndx] ||
-+ usbd_bus_instance->admin[usbd_admin_ndx](usbd_bus_instance, arg), error);
-+
-+ if (usbd_admin_ndx == usbd_admin_enable && NULL != arg && arg != current_function) {
-+ // update current_function
-+ strncpy(current_function,arg,MAX_FUNC_NAME_LEN);
-+ }
-+
-+ up(&usbd_sem);
-+ return 0;
-+
-+ CATCH(error) {
-+ printk(KERN_INFO"%s: %d error\n", __FUNCTION__, usbd_admin_ndx);
-+
-+ up(&usbd_sem);
-+ return -ENODEV;
-+ }
-+}
-+
-+
-+/* usbd_enable -
-+ */
-+int usbd_enable(char *arg)
-+{
-+ printk(KERN_INFO"%s:\n", __FUNCTION__);
-+ RETURN_ZERO_IF(switch_exiting);
-+ return usbd_admin(usbd_admin_enable, arg);
-+}
-+
-+void usbd_enable_bh(void *arg)
-+{
-+ usbd_admin(usbd_admin_enable, (char *)arg);
-+}
-+
-+int usbd_enable_irq(char *arg)
-+{
-+ RETURN_ZERO_IF(enable_bh.sync || switch_exiting);
-+ schedule_task(&enable_bh);
-+ return 0;
-+}
-+
-+
-+/* usbd_disable -
-+ */
-+int usbd_disable(char *arg)
-+{
-+ RETURN_ZERO_IF(switch_exiting);
-+ return usbd_admin(usbd_admin_disable, arg);
-+}
-+
-+void usbd_disable_bh(void *arg)
-+{
-+ usbd_admin(usbd_admin_disable, (char *)arg);
-+}
-+
-+int usbd_disable_irq(char *arg)
-+{
-+ RETURN_ZERO_IF(disable_bh.sync || switch_exiting);
-+ schedule_task(&disable_bh);
-+ return 0;
-+}
-+
-+/* usbd_load -
-+ */
-+int usbd_load(char *arg)
-+{
-+ if (arg && strlen(arg)) {
-+ if ( usbd_load_arg)
-+ lkfree(usbd_load_arg);
-+ usbd_load_arg = lstrdup(arg);
-+ }
-+ return usbd_admin(usbd_admin_enable, arg);
-+}
-+
-+/* usbd_unload -
-+ */
-+int usbd_unload(char *arg)
-+{
-+ return usbd_admin(usbd_admin_disable, arg);
-+}
-+
-+
-+/* usbd_connect -
-+ */
-+int usbd_connect(char *arg)
-+{
-+ return usbd_admin(usbd_admin_connect, arg);
-+}
-+
-+/* usbd_disconnect -
-+ */
-+int usbd_disconnect(char *arg)
-+{
-+ return usbd_admin(usbd_admin_disconnect, arg);
-+}
-+
-+
-+/* usbd_replug -
-+ */
-+int usbd_replug(char *arg)
-+{
-+ return usbd_admin(usbd_admin_connect, arg);
-+}
-+
-+/* usbd_unplug -
-+ */
-+int usbd_unplug(char *arg)
-+{
-+ return usbd_admin(usbd_admin_disconnect, arg);
-+}
-+
-+
-+
-+/* usbd_pm_off -
-+ */
-+int usbd_pm_off(char *arg)
-+{
-+ return usbd_admin(usbd_admin_pm_off, arg);
-+}
-+
-+/* usbd_pm_on -
-+ */
-+int usbd_pm_on(char *arg)
-+{
-+ return usbd_admin(usbd_admin_pm_on, arg);
-+}
-+
-+
-+
-+
-+/* ******************************************************************************************* */
-+#ifdef CONFIG_USBD_PROCFS
-+
-+static int usbd_admin_procfs(char *arg)
-+{
-+ usbd_admin_t admin;
-+ RETURN_EINVAL_IF(!arg || !strlen(arg));
-+
-+ for (admin = usbd_admin_enable; admin <= usbd_admin_serial_number; admin++) {
-+ char *cp = usbd_admin_names[admin];
-+ int len = strlen(cp);
-+ if (!strncmp(arg, cp, len)) {
-+ cp = arg + len;
-+ while (cp && ((*cp == ' ') || (*cp == '\t'))) cp++;
-+ return usbd_admin(admin, cp);
-+ }
-+ }
-+
-+ for (admin = usbd_admin_enable; admin <= usbd_admin_serial_number; admin++) {
-+ char *cp = usbd_admin_aliases[admin];
-+ int len = strlen(cp);
-+ if (!strncmp(arg, cp, len)) {
-+ cp = arg + len;
-+ while (cp && ((*cp == ' ') || (*cp == '\t'))) cp++;
-+ return usbd_admin(admin, cp);
-+ }
-+ }
-+
-+ return -EINVAL;
-+}
-+
-+/* usbd_proc_switch_write - handle a user switch request
-+ */
-+static ssize_t usbd_proc_switch_write (struct file *file, const char *buf, size_t count, loff_t * pos)
-+{
-+
-+ char command[MAX_FUNC_NAME_LEN+1];
-+ size_t n = count;
-+ size_t l;
-+ char c;
-+
-+ command[0] = 0;
-+ if (n > 0) {
-+ l = MIN(n,MAX_FUNC_NAME_LEN);
-+ if (copy_from_user (command, buf, l)) {
-+ count = -EFAULT;
-+ }
-+ else {
-+ if (l > 0 && command[l-1] == '\n') {
-+ l -= 1;
-+ }
-+ command[l] = 0;
-+ n -= l;
-+ // flush remainder, if any
-+ while (n > 0) {
-+ // Not too efficient, but it shouldn't matter
-+ if (copy_from_user (&c, buf + (count - n), 1)) {
-+ count = -EFAULT;
-+ break;
-+ }
-+ n -= 1;
-+ }
-+ }
-+ }
-+
-+ if (0 >= count) {
-+ printk(KERN_INFO"%s: count <= 0 %d\n", __FUNCTION__, count);
-+ return count;
-+ }
-+
-+ //printk(KERN_INFO"%s: %s\n", __FUNCTION__, command);
-+ if (!usbd_admin_procfs(command)) {
-+ // do nothing
-+ //printk(KERN_INFO"%s: back\n", __FUNCTION__);
-+ }
-+
-+
-+ /*
-+ * debug - increment switch_debug
-+ */
-+ else if (!strncmp("debug", command, 5)) {
-+ switch_debug++;
-+ if (switch_debug)
-+ printk(KERN_INFO"%s: debug: %d\n", __FUNCTION__, switch_debug);
-+ }
-+ /*
-+ * nodebug - reset switch_debug
-+ */
-+ else if (!strncmp("nodebug", command, 7)) {
-+ switch_debug = 0;
-+ if (switch_debug)
-+ printk(KERN_INFO"%s: no debug\n", __FUNCTION__);
-+ }
-+
-+ return count;
-+}
-+
-+/* usbd_proc_switch_read - implement proc file system read.
-+ * Standard proc file system read function.
-+ */
-+static ssize_t usbd_proc_switch_read (struct file *file, char *buf, size_t count, loff_t * pos)
-+{
-+ unsigned long page;
-+ int len;
-+ //int index;
-+ char *bp,*ep;
-+ struct list_head *lhd;
-+
-+ if ((*pos)++ > 0) {
-+ /* This is the second time, we finished on the first time,
-+ indicate we have no more data by returning 0. */
-+ return(0);
-+ }
-+
-+ // get a page, max 4095 bytes of data...
-+ if (!(page = get_free_page (GFP_KERNEL))) {
-+ return -ENOMEM;
-+ }
-+
-+ bp = (char *) page;
-+ ep = bp + 4095;
-+
-+ bp += sprintf(bp, "USB cable ");
-+ if (NULL != usbd_bus_instance &&
-+ NULL != usbd_bus_instance->driver &&
-+ NULL != usbd_bus_instance->driver->bops &&
-+ NULL != usbd_bus_instance->driver->bops->bus_attached &&
-+ usbd_bus_instance->driver->bops->bus_attached(usbd_bus_instance)) {
-+ bp += sprintf(bp, "at");
-+ } else {
-+ bp += sprintf(bp, "de");
-+ }
-+ bp += sprintf(bp, "tached");
-+ bp += sprintf(bp, ", USB pullup resistor ");
-+ if (NULL != usbd_bus_instance &&
-+ NULL != usbd_bus_instance->driver &&
-+ NULL != usbd_bus_instance->driver->bops &&
-+ NULL != usbd_bus_instance->driver->bops->bus_connected &&
-+ !usbd_bus_instance->driver->bops->bus_connected(usbd_bus_instance)) {
-+ bp += sprintf(bp, "dis");
-+ }
-+ bp += sprintf(bp, "connected");
-+ bp += sprintf(bp, "\nUSB Device function drivers:\n");
-+ list_for_each (lhd, &usbd_function_drivers) {
-+ struct usb_function_driver *fd = list_entry(lhd, struct usb_function_driver, drivers);
-+ char enabled = '-';
-+ if (usbd_bus_instance && usbd_bus_instance->function_instance &&
-+ usbd_bus_instance->function_instance->function_driver == fd) {
-+ enabled = '+';
-+ }
-+ if ((ep - bp) < 64) {
-+ printk(KERN_INFO"%s: Too many usbd functions!\n", __FUNCTION__);
-+ break;
-+ }
-+ bp += sprintf(bp," %c [%s]\n",enabled,fd->name);
-+ }
-+ len = bp - (char *) page;
-+
-+ if (len > 0 && copy_to_user (buf, (char *) page, len)) {
-+ //printk(KERN_INFO"%s: EFAULT\n", __FUNCTION__);
-+ len = -EFAULT;
-+ } else {
-+ //printk(KERN_INFO"%s: OK\n", __FUNCTION__);
-+ }
-+ free_page (page);
-+ return len;
-+}
-+
-+static struct file_operations usbd_proc_switch_functions = {
-+ write:usbd_proc_switch_write,
-+ read:usbd_proc_switch_read,
-+};
-+#endif
-+
-+
-+/* ******************************************************************************************* */
-+
-+#if defined(CONFIG_PM)
-+/* switch_pm_event
-+ *
-+ * Handle power management event
-+ */
-+static int switch_pm_event (struct pm_dev *dev, pm_request_t rqst, void *unused)
-+{
-+ switch (rqst) {
-+ case PM_SUSPEND:
-+ usbd_pm_off(usbd_load_arg);
-+ break;
-+ case PM_RESUME:
-+ usbd_pm_on(usbd_load_arg);
-+ break;
-+ }
-+ return 0;
-+}
-+#endif
-+
-+/* ******************************************************************************************* */
-+
-+
-+
-+/* ******************************************************************************************* */
-+
-+#if defined(CONFIG_PM)
-+struct pm_dev *switch_pm_info;
-+#endif
-+
-+/* usbd_switch_init
-+ *
-+ */
-+int usbd_switch_init(void)
-+{
-+
-+#ifdef CONFIG_USBD_PROCFS
-+ struct proc_dir_entry *p;
-+
-+ // create proc filesystem entries
-+ //printk(KERN_INFO"%s: creating /proc/usbd-switch\n", __FUNCTION__);
-+ if ((p = create_proc_entry ("usbd-switch", 0666, 0)) == NULL) {
-+ printk(KERN_ERR"%s: creating /proc/usbd-switch failed\n", __FUNCTION__);
-+ return -ENOMEM;
-+ }
-+ p->proc_fops = &usbd_proc_switch_functions;
-+#endif
-+#ifdef CONFIG_PM
-+ switch_pm_info = NULL;
-+
-+ if (!(switch_pm_info = pm_register (PM_USB_DEV, PM_SYS_UNKNOWN, switch_pm_event)))
-+ return -ENOMEM;
-+
-+ switch_pm_info->state = 0;
-+#endif
-+ enable_bh.routine = usbd_enable_bh;
-+ enable_bh.data = NULL;
-+ disable_bh.routine = usbd_disable_bh;
-+ disable_bh.data = NULL;
-+ return 0;
-+}
-+
-+void usbd_switch_exit (void)
-+{
-+ // This is *only* used for drivers compiled and used as a module.
-+#ifdef CONFIG_PM
-+ if (switch_pm_info)
-+ pm_unregister_all(switch_pm_event);
-+ switch_pm_info = NULL;
-+#endif
-+#ifdef CONFIG_USBD_PROCFS
-+ remove_proc_entry("usbd-switch", NULL);
-+#endif
-+ switch_exiting = 1;
-+ while (enable_bh.sync || disable_bh.sync) {
-+ printk(KERN_INFO"%s: waiting for bh\n", __FUNCTION__);
-+ schedule_timeout(10 * HZ);
-+ }
-+}
-+
-+
-+
-+/* Module init ******************************************************************************* */
-+
-+int usbd_switch_init(void);
-+void usbd_switch_exit (void);
-+
-+static int usbd_device_init (void)
-+{
-+ printk (KERN_INFO "%s: %s %s\n", __FUNCTION__, __usbd_module_info, USBD_EXPORT_TAG);
-+
-+ usbd_switch_init();
-+
-+ return 0;
-+}
-+
-+static void usbd_device_exit (void)
-+{
-+ //printk (KERN_INFO "%s: %s exiting\n", __FUNCTION__, __usbd_module_info);
-+
-+ usbd_switch_exit();
-+
-+ if ( usbd_load_arg)
-+ lkfree(usbd_load_arg);
-+
-+#ifdef MALLOC_TEST
-+ if (usbd_mallocs) printk(KERN_INFO"%s: usbd_mallocs non-zero! %d\n", __FUNCTION__, usbd_mallocs);
-+#endif
-+}
-+
-+module_init (usbd_device_init);
-+module_exit (usbd_device_exit);
-+
-+EXPORT_SYMBOL(usbd_function_drivers);
-+EXPORT_SYMBOL(usbd_maxstrings);
-+
-+EXPORT_SYMBOL(usbd_enable);
-+EXPORT_SYMBOL(usbd_disable);
-+EXPORT_SYMBOL(usbd_enable_irq);
-+EXPORT_SYMBOL(usbd_disable_irq);
-+
-+EXPORT_SYMBOL(usbd_connect);
-+EXPORT_SYMBOL(usbd_disconnect);
-+EXPORT_SYMBOL(usbd_pm_on);
-+EXPORT_SYMBOL(usbd_pm_off);
-+
-+EXPORT_SYMBOL(usbd_load);
-+EXPORT_SYMBOL(usbd_unload);
-+EXPORT_SYMBOL(usbd_unplug);
-+EXPORT_SYMBOL(usbd_replug);
-+
-+
-+EXPORT_SYMBOL(usbd_bus_instance);
-+#ifdef MALLOC_TEST
-+EXPORT_SYMBOL(usbd_mallocs);
-+#endif
-+
-+
-diff -Nru a/drivers/usbd/usbd.h b/drivers/usbd/usbd.h
---- /dev/null Wed Dec 31 16:00:00 1969
-+++ b/drivers/usbd/usbd.h Fri Feb 27 14:22:51 2004
-@@ -0,0 +1,239 @@
-+/*
-+ * usbd/usbd.h
-+ *
-+ * Copyright (c) 2004 Belcarra
-+ *
-+ * Adapted from earlier work:
-+ * Copyright (c) 2002, 2003 Belcarra
-+ * Copyright (c) 2000, 2001, 2002 Lineo
-+ * Copyright (c) 2001 Hewlett Packard
-+ *
-+ * By:
-+ * Stuart Lynne <sl@belcarra.com>,
-+ * Tom Rushworth <tbr@belcarra.com>,
-+ * Bruce Balden <balden@belcarra.com>
-+ *
-+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
-+ *
-+ */
-+
-+/*
-+ * This file contains the USB Device Core Common definitions. It also contains definitions for
-+ * functions that are commonly used by both Function Drivers and Bus Interface Drivers.
-+ *
-+ * Specifically:
-+ *
-+ * o public functions exported by the USB Core layer
-+ *
-+ * o common structures and definitions
-+ *
-+ */
-+
-+
-+/*
-+ * Device Events
-+ *
-+ * These are defined in the USB Spec (c.f USB Spec 2.0 Figure 9-1).
-+ *
-+ * There are additional events defined to handle some extra actions we need to have handled.
-+ *
-+ */
-+typedef enum usb_device_event {
-+
-+ DEVICE_UNKNOWN, // bi - unknown event
-+ DEVICE_INIT, // bi - initialize
-+ DEVICE_CREATE, // bi -
-+ DEVICE_HUB_CONFIGURED, // bi - bus has been plugged int
-+ DEVICE_RESET, // bi - hub has powered our port
-+
-+ DEVICE_ADDRESS_ASSIGNED,// ep0 - set address setup received
-+ DEVICE_CONFIGURED, // ep0 - set configure setup received
-+ DEVICE_SET_INTERFACE, // ep0 - set interface setup received
-+
-+ DEVICE_SET_FEATURE, // ep0 - set feature setup received
-+ DEVICE_CLEAR_FEATURE, // ep0 - clear feature setup received
-+
-+ DEVICE_DE_CONFIGURED, // ep0 - set configure setup received for ??
-+
-+ DEVICE_BUS_INACTIVE, // bi - bus in inactive (no SOF packets)
-+ DEVICE_BUS_ACTIVITY, // bi - bus is active again
-+
-+ DEVICE_POWER_INTERRUPTION,// bi - hub has depowered our port
-+ DEVICE_HUB_RESET, // bi - bus has been unplugged
-+ DEVICE_DESTROY, // bi - device instance should be destroyed
-+ DEVICE_CLOSE, // bi - device instance should be destroyed
-+
-+} usb_device_event_t;
-+
-+
-+
-+struct usb_bus_instance;
-+struct usb_function_instance;
-+
-+typedef struct urb_link {
-+ struct urb_link *next;
-+ struct urb_link *prev;
-+} urb_link;
-+
-+/* URB Status
-+ *
-+ */
-+typedef enum usbd_urb_status {
-+ SEND_IN_QUEUE,
-+ SEND_IN_PROGRESS,
-+ SEND_FINISHED_OK,
-+ SEND_FINISHED_ERROR,
-+ SEND_FINISHED_CANCELLED,
-+ RECV_IN_QUEUE,
-+ RECV_IN_PROGRESS,
-+ RECV_OK,
-+ RECV_ERROR,
-+ RECV_CANCELLED
-+} usbd_urb_status_t;
-+
-+
-+
-+/* USB Data structure
-+ *
-+ * This is used for both sending and receiving data.
-+ *
-+ * The callback function is used to let the function driver know when transmitted data has been
-+ * sent.
-+ *
-+ * The callback function is set by the alloc_recv function when an urb is allocated for
-+ * receiving data for an endpoint and used to call the function driver to inform it that data
-+ * has arrived.
-+ *
-+ * Note that for OUT urbs the buffer is always allocated to a multiple of the packetsize that is
-+ * 1 larger than the requested size. This prevents overflow if the host unexpectedly sends a
-+ * full sized packet when we are expecting a short one (the host is always right..)
-+ */
-+
-+struct urb {
-+
-+ struct usb_bus_instance *bus;
-+ struct usb_function_instance *function_instance;
-+ struct usb_endpoint_instance *endpoint;
-+
-+ int (*callback) (struct urb *, int);
-+
-+ u8 *buffer; // data received (OUT) or being sent (IN)
-+ u32 request_length; // maximum data expected for OUT
-+ u32 buffer_length; // allocated size of buffer
-+ u32 actual_length; // actual data received (OUT or being sent (IN)
-+ u32 flags;
-+
-+ void *privdata;
-+
-+ struct urb_link link;
-+ usbd_urb_status_t status; // what is the current status of the urb
-+ time_t jiffies; // timestamp for when urb was started or finished
-+ u16 framenum; // SOF framenum when urb was finished
-+};
-+
-+#define USBD_URB_SENDZLP 0x01
-+
-+
-+/*
-+ * Device State (c.f USB Spec 2.0 Figure 9-1)
-+ *
-+ * What state the usb device is in.
-+ *
-+ * Note the state does not change if the device is suspended, we simply set a
-+ * flag to show that it is suspended.
-+ *
-+ */
-+typedef enum usb_device_state {
-+ STATE_INIT, // just initialized
-+ STATE_CREATED, // just created
-+ STATE_ATTACHED, // we are attached
-+ STATE_POWERED, // we have seen power indication (electrical bus signal)
-+ STATE_DEFAULT, // we been reset
-+ STATE_ADDRESSED, // we have been addressed (in default configuration)
-+ STATE_CONFIGURED, // we have seen a set configuration device command
-+ STATE_SUSPENDED,
-+ STATE_UNKNOWN, // destroyed
-+} usb_device_state_t;
-+
-+/*
-+ * Device status
-+ *
-+ * Overall state
-+ */
-+typedef enum usb_device_status {
-+ USBD_OPENING, // we are currently opening
-+ USBD_RESETING, // we are currently opening
-+ USBD_OK, // ok to use
-+ USBD_SUSPENDED, // we are currently suspended
-+ USBD_CLOSING, // we are currently closing
-+ USBD_CLOSED, // we are currently closing
-+ USBD_UNKNOWN,
-+} usb_device_status_t;
-+
-+/*
-+ * Bus state
-+ *
-+ * enabled or disabled
-+ */
-+typedef enum usbd_bus_state {
-+ usbd_bus_state_unknown,
-+ usbd_bus_state_disabled,
-+ usbd_bus_state_enabled
-+} usbd_bus_state_t;
-+
-+
-+
-+/* Endpoint Request
-+ *
-+ * An array of these structures is initialized by each function driver to specify the endpoints
-+ * it requires.
-+ *
-+ * The bus interface driver will attempt to fulfill these requests with the actual endpoints it
-+ * has available.
-+ *
-+ * Note that in most cases the bEndpointAddress should be left as zero except for specialized
-+ * function drivers that both require a specific value and know ahead of time that the specified
-+ * value is legal for the bus interface driver being used.
-+ */
-+struct usb_endpoint_request {
-+ u8 configuration; // configuration endpoint will be in
-+ u8 interface; // interface endpoint will be in
-+ u8 alternate; // altsetting for this request
-+ u8 bmAttributes; // endpoint type AND direction
-+ u16 fs_requestedTransferSize; // max full speed transfer size for this endpoint
-+ u16 hs_requestedTransferSize; // max high speed transfer size for this endpoint
-+ u8 bEndpointAddress; // specific bEndpointAddress function driver requires
-+ u8 physical; // physical endpoint used
-+};
-+
-+
-+
-+struct usb_function_operations;
-+struct usb_function_driver;
-+
-+
-+
-+/*
-+ * USB Bus Interface Driver structures
-+ *
-+ * Driver description:
-+ *
-+ * struct usb_bus_operations
-+ * struct usb_bus_driver
-+ *
-+ */
-+
-+struct usb_bus_operations;
-+struct usb_bus_driver;
-+extern int usbd_maxstrings;
-+
-+
diff --git a/recipes/linux/linux-mtx-1-2.4.27/28-idsel-cardbus.diff b/recipes/linux/linux-mtx-1-2.4.27/28-idsel-cardbus.diff
deleted file mode 100644
index aff210bb54..0000000000
--- a/recipes/linux/linux-mtx-1-2.4.27/28-idsel-cardbus.diff
+++ /dev/null
@@ -1,67 +0,0 @@
-diff -Nurb linux/arch/mips/au1000/mtx-1/board_setup.c /home/br1/linux-idsel/arch/mips/au1000/mtx-1/board_setup.c
---- linux/arch/mips/au1000/mtx-1/board_setup.c 2005-08-18 18:23:59.000000000 +0200
-+++ /home/br1/linux-idsel/arch/mips/au1000/mtx-1/board_setup.c 2005-08-18 18:19:48.000000000 +0200
-@@ -48,6 +48,10 @@
-
- extern struct rtc_ops no_rtc_ops;
-
-+extern int (*board_pci_idsel)(unsigned int devsel, int assert);
-+int mtx1_pci_idsel(unsigned int devsel, int assert);
-+
-+
- void board_reset (void)
- {
- /* Hit BCSR.SYSTEM_CONTROL[SW_RST] */
-@@ -85,11 +89,39 @@
- au_writel( 0xFFFFFFFF, SYS_TRIOUTCLR );
- au_writel( 0x00000001, SYS_OUTPUTCLR ); // set M66EN (PCI 66MHz) to OFF
- au_writel( 0x00000008, SYS_OUTPUTSET ); // set PCI CLKRUN# to OFF
-+ au_writel( 0x00000002, SYS_OUTPUTSET ); // set EXT_IO3 ON
- au_writel( 0x00000020, SYS_OUTPUTCLR ); // set eth PHY TX_ER to OFF
-
- // enable LED and set it to green
- au_writel( au_readl(GPIO2_DIR) | 0x1800, GPIO2_DIR );
- au_writel( 0x18000800, GPIO2_OUTPUT );
-
-+ board_pci_idsel = mtx1_pci_idsel;
-+
- printk("4G Systems MTX-1 Board\n");
- }
-+
-+
-+/*
-+ */
-+int
-+mtx1_pci_idsel(unsigned int devsel, int assert)
-+{
-+#define MTX_IDSEL_ONLY_0_AND_3 0
-+#if MTX_IDSEL_ONLY_0_AND_3
-+ if (devsel != 0 && devsel != 3) {
-+ printk("*** not 0 or 3\n");
-+ return 0;
-+ }
-+#endif
-+
-+ if (assert && devsel != 0) {
-+ // supress signal to cardbus
-+ au_writel( 0x00000002, SYS_OUTPUTCLR ); // set EXT_IO3 OFF
-+ }
-+ else {
-+ au_writel( 0x00000002, SYS_OUTPUTSET ); // set EXT_IO3 ON
-+ }
-+ au_sync_udelay(1);
-+ return 1;
-+}
-diff -Nurb linux/arch/mips/au1000/mtx-1/irqmap.c /home/br1/linux-idsel/arch/mips/au1000/mtx-1/irqmap.c
---- linux/arch/mips/au1000/mtx-1/irqmap.c 2005-08-18 18:24:05.000000000 +0200
-+++ /home/br1/linux-idsel/arch/mips/au1000/mtx-1/irqmap.c 2005-08-16 16:37:39.000000000 +0200
-@@ -73,7 +73,7 @@
- * A B C D
- */
- {
-- {INTA, INTB, INTX, INTX}, /* IDSEL 0 */
-+ {INTA, INTA, INTX, INTX}, /* IDSEL 0 */
- {INTB, INTA, INTX, INTX}, /* IDSEL 1 */
- {INTC, INTD, INTX, INTX}, /* IDSEL 2 */
- {INTD, INTC, INTX, INTX}, /* IDSEL 3 */
-
diff --git a/recipes/linux/linux-mtx-1-2.4.27/29-au1000-pci-config-clear-errors.diff b/recipes/linux/linux-mtx-1-2.4.27/29-au1000-pci-config-clear-errors.diff
deleted file mode 100644
index 5da1cd61f8..0000000000
--- a/recipes/linux/linux-mtx-1-2.4.27/29-au1000-pci-config-clear-errors.diff
+++ /dev/null
@@ -1,15 +0,0 @@
---- linux/arch/mips/au1000/common/pci_ops.c.orig 2005-08-24 17:36:25.000000000 +0200
-+++ linux/arch/mips/au1000/common/pci_ops.c 2005-08-24 17:37:38.000000000 +0200
-@@ -259,7 +259,11 @@
- *data = 0xffffffff;
- error = -1;
- } else if ((status >> 28) & 0xf) {
-- DBG("PCI ERR detected: status %x\n", status);
-+ DBG("PCI ERR detected: device %d, status %x\n", device, ((status >> 28) & 0xf));
-+
-+ /* clear errors */
-+ au_writel(status & 0xf000ffff, Au1500_PCI_STATCMD);
-+
- *data = 0xffffffff;
- error = -1;
- }
diff --git a/recipes/linux/linux-mtx-1-2.4.27/30-mtx-1-sysled.diff b/recipes/linux/linux-mtx-1-2.4.27/30-mtx-1-sysled.diff
deleted file mode 100644
index 283b7af451..0000000000
--- a/recipes/linux/linux-mtx-1-2.4.27/30-mtx-1-sysled.diff
+++ /dev/null
@@ -1,446 +0,0 @@
---- /dev/null 1970-01-01 01:00:00.000000000 +0100
-+++ linux/arch/mips/au1000/mtx-1/mtx-1_sysled.c 2005-08-27 15:30:51.000000000 +0200
-@@ -0,0 +1,398 @@
-+/*
-+ * Driver for the MTX-1 System LEDs.
-+ *
-+ * (c) Copyright 2005 4G Systems <info@4g-systems.biz>, All Rights Reserved.
-+ * http://www.4g-systems.biz
-+ *
-+ * 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.
-+ *
-+ * Neither Alan Cox nor CymruNet Ltd. admit liability nor provide
-+ * warranty for any of this software. This material is provided
-+ * "AS-IS" and at no charge.
-+ *
-+ * (c) Copyright 2005 4G Systems <info@4g-systems.biz>
-+ *
-+ * Release 0.01.
-+ *
-+ * Author: Michael Stickel michael.stickel@4g-systems.biz
-+ *
-+ *
-+ * After the module is loaded there will be a device /dev/misc/leds
-+ * that can be written to. There are two bits, each represents one LED
-+ *
-+ *
-+ */
-+
-+static int errno;
-+#define __KERNEL_SYSCALLS__
-+
-+#include <linux/config.h>
-+#include <linux/module.h>
-+#include <linux/version.h>
-+#include <linux/types.h>
-+#include <linux/errno.h>
-+#include <linux/kernel.h>
-+#include <linux/sched.h>
-+#include <linux/miscdevice.h>
-+#include <linux/slab.h>
-+#include <linux/init.h>
-+#include <linux/smp_lock.h>
-+#include <asm/unistd.h>
-+
-+#include <asm/uaccess.h>
-+
-+#include <asm/au1000.h>
-+
-+#include <asm/io.h>
-+
-+
-+#include "mtx-1_sysled.h"
-+
-+
-+#ifndef FALSE
-+# define FALSE (0)
-+#endif
-+
-+#ifndef TRUE
-+# define TRUE (!FALSE)
-+#endif
-+
-+
-+/* handle up_and_exit confusion */
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,9)
-+typedef struct semaphore THREAD_SEM;
-+#define THREAD_SEM_EXIT(c,l) up_and_exit(c,l)
-+#define THREAD_SEM_DECLARE(c) DECLARE_MUTEX_LOCKED(c)
-+#define THREAD_SEM_INIT(c) init_MUTEX_LOCKED(c)
-+#define THREAD_SEM_WAIT_COMPLETE(c) {down(c);up(c);}
-+
-+#else
-+#include <linux/completion.h>
-+typedef struct completion THREAD_SEM;
-+#define THREAD_SEM_EXIT(c,l) complete_and_exit(c,l)
-+#define THREAD_SEM_DECLARE(c) DECLARE_COMPLETION(c)
-+#define THREAD_SEM_INIT(c) init_completion(c)
-+#define THREAD_SEM_WAIT_COMPLETE(c) wait_for_completion(c)
-+#endif
-+
-+
-+//---------[ Hardware Functions ]-----------------
-+
-+
-+
-+static unsigned char sysled_gpios[10] =
-+{
-+ 211, // Power = GPIO211
-+ 212, // Status = GPIO212
-+
-+#if 1
-+ 12, // LEDBar1 Blue = GPIO12 0
-+ 13, // LEDBar1 Red = GPIO13
-+
-+ 26, // LEDBar3 Blue = GPIO27 1
-+ 27, // LEDBar3 Red = GPIO26
-+
-+ 10, // LEDBar0 Blue = GPIO10 2
-+ 11, // LEDBar0 Red = GPIO11
-+
-+ 14, // LEDBar2 Blue = GPIO14 3
-+ 25, // LEDBar2 Red = GPIO28
-+#else
-+ 7, // IOCTRL0
-+ 8, // IOCTRL1
-+
-+ 15, // IOCTRL2
-+ 205, // IOCTRL3
-+
-+ 206, // IOCTRL4
-+ 208, // LEDBar2 Blue = GPIO14
-+
-+ 255,
-+ 255
-+#endif
-+};
-+static int num_sysled_gpios = sizeof(sysled_gpios) / sizeof(sysled_gpios[0]);
-+
-+
-+static void mtx1_setled (int ledno, char on)
-+{
-+ if (ledno >= 0 && ledno < num_sysled_gpios)
-+ {
-+ if (sysled_gpios[ledno] >= 200 && sysled_gpios[ledno] < 231)
-+ {
-+ unsigned long pinmask = 1 << (sysled_gpios[ledno] - 200);
-+ au_writel((pinmask<<16) | (on ? pinmask : 0), GPIO2_OUTPUT);
-+ }
-+ else if (sysled_gpios[ledno] < 32)
-+ {
-+ unsigned long pinmask = 1 << sysled_gpios[ledno];
-+ if (on)
-+ au_writel(pinmask, SYS_OUTPUTSET);
-+ else
-+ au_writel(pinmask, SYS_OUTPUTCLR);
-+ }
-+ }
-+}
-+
-+
-+//---------[ LED Precalculation ]-----------------
-+
-+typedef struct current_led_config_s
-+{
-+ unsigned char period;
-+ unsigned long pattern[8]; /* bit-pattern: up to 3.2*8 seconds. 25.6 seconds at 10 Hz */
-+ short current_value;
-+ unsigned char led_state; /* 0 = off, 1 = on */
-+} current_led_config_t;
-+
-+static current_led_config_t current_led_config[10];
-+static THREAD_SEM mtx1_ledthread_exited;
-+static int mtx1_ledthread_pid;
-+
-+static int mtx1_led_thread (void *user_data)
-+{
-+ int last_jiffies = jiffies - HZ/10; /* initialize with meaningfull value */
-+
-+ lock_kernel();
-+
-+ daemonize ();
-+ spin_lock_irq (&current->sigmask_lock);
-+ sigemptyset (&current->blocked);
-+ recalc_sigpending (current);
-+ spin_unlock_irq (&current->sigmask_lock);
-+
-+ strncpy (current->comm, "mtx1led", sizeof(current->comm) - 1);
-+ current->comm[sizeof(current->comm) - 1] = '\0';
-+
-+ do {
-+ int i;
-+
-+ // missed_values = (jiffies - last_jiffies) / (HZ/10);
-+ last_jiffies = jiffies;
-+
-+ // 1/10 second later.
-+ for (i=0; i < num_sysled_gpios; i++)
-+ {
-+ int index = current_led_config[i].current_value;
-+ if (current_led_config[i].period > 0 && index < 256)
-+ {
-+ char led_on = (current_led_config[i].pattern[(index>>5)&7] >> (index&0x1f)) & 1;
-+
-+ if (led_on != current_led_config[i].led_state)
-+ mtx1_setled (i, led_on);
-+ current_led_config[i].led_state = led_on;
-+
-+ current_led_config[i].current_value++;
-+ if (current_led_config[i].current_value > current_led_config[i].period)
-+ current_led_config[i].current_value = 0;
-+ }
-+ }
-+
-+ current->state = TASK_INTERRUPTIBLE;
-+ /* long timeout = */ schedule_timeout(HZ / 10);
-+ } while (!signal_pending(current));
-+
-+ THREAD_SEM_EXIT (&mtx1_ledthread_exited, 0);
-+ return 0;
-+}
-+
-+
-+static int mtx1_start_ledthread (void)
-+{
-+ THREAD_SEM_INIT (&mtx1_ledthread_exited);
-+
-+ printk ("starting mtx1 ledthread\n");
-+ mtx1_ledthread_pid = kernel_thread(mtx1_led_thread,
-+ NULL,
-+ CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
-+ if (mtx1_ledthread_pid >= 0)
-+ return 0;
-+ return -1;
-+}
-+
-+
-+static void mtx1_stop_ledthread (void)
-+{
-+ int waitpid_result = 0;
-+ if (mtx1_ledthread_pid > 0) {
-+ int ret = kill_proc(mtx1_ledthread_pid, SIGTERM, 1);
-+ if (ret==0)
-+ {
-+ THREAD_SEM_WAIT_COMPLETE(&mtx1_ledthread_exited);
-+ waitpid_result = waitpid (mtx1_ledthread_pid, NULL, __WCLONE|WNOHANG);
-+ mtx1_ledthread_pid = 0;
-+ }
-+ }
-+// return waitpid_result;
-+}
-+
-+//---------[ File Functions ]-----------------
-+
-+static int mtx1sysled_minor = -1;
-+
-+static int mtx1sysled_open (struct inode *inode, struct file *file)
-+{
-+ if (MINOR(inode->i_rdev)!=mtx1sysled_minor) return -ENODEV;
-+ MOD_INC_USE_COUNT;
-+
-+ return 0;
-+}
-+
-+
-+static int mtx1sysled_release (struct inode *inode, struct file *file) {
-+ if (MINOR(inode->i_rdev)==mtx1sysled_minor) {
-+ }
-+ MOD_DEC_USE_COUNT;
-+ return 0;
-+}
-+
-+
-+static ssize_t mtx1sysled_write (struct file *file, const char *buf, size_t count, loff_t *ppos) {
-+ led_control_t ctrl_entry;
-+ size_t buflen;
-+
-+ if (ppos != &file->f_pos)
-+ return -ESPIPE;
-+
-+ if (count < 1)
-+ return -EINVAL;
-+
-+ if (copy_from_user (&ctrl_entry, buf, sizeof(unsigned char)))
-+ return -EFAULT;
-+
-+ if ((ctrl_entry.flags & 0x1f) <= 0)
-+ return -EINVAL;
-+
-+ buflen = (count < sizeof(led_control_t)) ? count : sizeof(led_control_t);
-+ if (copy_from_user (&ctrl_entry, buf, buflen))
-+ return -EFAULT;
-+
-+ int numentries = (buflen-1) / sizeof(led_control_entry_t);
-+
-+ if ((ctrl_entry.flags & 0x1f) < numentries)
-+ numentries = ctrl_entry.flags & 0x1f;
-+
-+ int i;
-+ for (i=0; i < numentries; i++) {
-+ unsigned short led_id = ctrl_entry.led[i].led_id;
-+ if (led_id < num_sysled_gpios) {
-+ current_led_config[led_id].period = ctrl_entry.led[i].period;
-+ memcpy (current_led_config[led_id].pattern, ctrl_entry.led[i].pattern, sizeof(unsigned long)*8);
-+ current_led_config[led_id].current_value = 0;
-+
-+ // may update the led output (if the led should be set to 1 or 0).
-+ }
-+ }
-+ return count;
-+}
-+
-+
-+
-+static struct file_operations mtx1sysled_fops = {
-+ .owner = THIS_MODULE,
-+ .llseek = NULL,
-+ .read = NULL,
-+ .write = mtx1sysled_write,
-+ .readdir = NULL,
-+ .poll = NULL,
-+ .ioctl = NULL,
-+ .mmap = NULL,
-+ .open = mtx1sysled_open,
-+ .flush = NULL,
-+ .release = mtx1sysled_release
-+};
-+
-+
-+static struct miscdevice mtx1sysled_miscdev = {
-+ MISC_DYNAMIC_MINOR /* SYSLED_MINOR */ ,
-+ "leds",
-+ &mtx1sysled_fops
-+};
-+
-+
-+
-+//---------[ Module Functions ]-----------------
-+
-+
-+void __exit cleanup_mtx1_sysled (void)
-+{
-+ mtx1_stop_ledthread ();
-+ misc_deregister(&mtx1sysled_miscdev);
-+}
-+
-+
-+int __init init_mtx1_sysled (void)
-+{
-+ printk("MTX-1 System LED driver\n");
-+
-+
-+ unsigned long gpio_mask = 0L;
-+ unsigned long gpio2_mask = 0L;
-+ int i;
-+ for (i=0; i < num_sysled_gpios; i++)
-+ {
-+ if (sysled_gpios[i] < 32) /* GPIO00..xx */
-+ gpio2_mask |= 1<<sysled_gpios[i];
-+
-+ else if (sysled_gpios[i] >= 200 && sysled_gpios[i] < 216) /* GPIO200..231 */
-+ gpio2_mask |= 1 << (sysled_gpios[i] - 200);
-+ }
-+
-+ if (gpio2_mask) {
-+ au_writel(au_readl(GPIO2_DIR) | gpio2_mask, GPIO2_DIR);
-+ au_writel(gpio2_mask<<16, GPIO2_OUTPUT);
-+ }
-+
-+ if (gpio_mask) {
-+ au_writel(gpio_mask, SYS_OUTPUTCLR);
-+ }
-+
-+ // Clear SYS_LED#10 = U910-OE#
-+ au_writel(1<<28, SYS_OUTPUTCLR);
-+
-+
-+ if (misc_register (&mtx1sysled_miscdev) < 0)
-+ {
-+ return 1;
-+ }
-+ mtx1sysled_minor = mtx1sysled_miscdev.minor;
-+
-+ for (i=0; i < num_sysled_gpios; i++) {
-+ current_led_config[i].period = 32;
-+ current_led_config[i].pattern[0] = 0x0;
-+ current_led_config[i].current_value = 0;
-+ current_led_config[i].led_state = 0;
-+ mtx1_setled (i, 0);
-+ }
-+ current_led_config[2].period = 31;
-+ current_led_config[2].pattern[0] = 0xFFFFFFFF;
-+ current_led_config[3].period = 31;
-+ current_led_config[3].pattern[0] = 0xFFFFFFFF;
-+ current_led_config[4].period = 31;
-+ current_led_config[4].pattern[0] = 0xFFFFFFFF;
-+ current_led_config[5].period = 31;
-+ current_led_config[5].pattern[0] = 0xFFFFFFFF;
-+ current_led_config[6].period = 31;
-+ current_led_config[6].pattern[0] = 0xFFFFFFFF;
-+ current_led_config[7].period = 31;
-+ current_led_config[7].pattern[0] = 0xFFFFFFFF;
-+
-+
-+ if (mtx1_start_ledthread ())
-+ {
-+ // Error
-+ }
-+
-+ return 0;
-+}
-+
-+__initcall(init_mtx1_sysled);
-+__exitcall(cleanup_mtx1_sysled);
-+
-+MODULE_AUTHOR("Michael Stickel");
-+MODULE_DESCRIPTION("Driver for the MTX-1 system LEDs");
-+MODULE_LICENSE("GPL");
-+EXPORT_NO_SYMBOLS;
---- /dev/null 1970-01-01 01:00:00.000000000 +0100
-+++ linux/arch/mips/au1000/mtx-1/mtx-1_sysled.h 2005-08-27 15:00:41.000000000 +0200
-@@ -0,0 +1,32 @@
-+#ifndef __MTX1_SYSLED_H__
-+#define __MTX1_SYSLED_H__
-+ /*
-+ * flags:
-+ * Bit Function
-+ * 7 set to 0
-+ * 6 set to 0
-+ * 5 set to 0
-+ * 4..0 The number of led-control records. 1 means one record, 15 means records.
-+ *
-+ */
-+
-+
-+typedef struct led_control_entry_s
-+{
-+ unsigned short led_id;
-+ unsigned char period; /* 0..0xff unit is 1/10 of a second */
-+ unsigned long pattern[8]; /* bit-pattern: up to 3.2*8 seconds. 25.6 seconds at 10 Hz */
-+} led_control_entry_t;
-+
-+
-+typedef struct led_control_s
-+{
-+ unsigned char flags;
-+ led_control_entry_t led[31];
-+} led_control_t;
-+
-+#define MTX1SYSLED_CONTROL_SIZE(x) (sizeof(unsigned char)+(x)*sizeof(led_control_entry_t))
-+
-+#define MTX1SYSLED_FLAGS_NUMENTRIES(n) ((n)&0x1f)
-+
-+#endif
---- linux/arch/mips/au1000/mtx-1/Makefile.orig 2005-08-27 15:59:31.000000000 +0200
-+++ linux/arch/mips/au1000/mtx-1/Makefile 2005-08-27 15:59:45.000000000 +0200
-@@ -15,6 +15,6 @@
-
- O_TARGET := mtx-1.o
-
--obj-y := init.o board_setup.o irqmap.o mtx-1_watchdog.o mtx-1_sysbtn.o
-+obj-y := init.o board_setup.o irqmap.o mtx-1_watchdog.o mtx-1_sysbtn.o mtx-1_sysled.o
-
- include $(TOPDIR)/Rules.make
diff --git a/recipes/linux/linux-mtx-1-2.4.27/31-mtx-1u-led-init.diff b/recipes/linux/linux-mtx-1-2.4.27/31-mtx-1u-led-init.diff
deleted file mode 100644
index 53e17e48bb..0000000000
--- a/recipes/linux/linux-mtx-1-2.4.27/31-mtx-1u-led-init.diff
+++ /dev/null
@@ -1,16 +0,0 @@
---- linux/arch/mips/au1000/mtx-1/board_setup.c.pre 2005-08-27 17:09:39.000000000 +0200
-+++ linux/arch/mips/au1000/mtx-1/board_setup.c 2005-08-27 17:38:56.000000000 +0200
-@@ -91,9 +91,12 @@
- au_writel( 0x00000002, SYS_OUTPUTSET ); // set EXT_IO3 ON
- au_writel( 0x00000020, SYS_OUTPUTCLR ); // set eth PHY TX_ER to OFF
-
-+ au_writel( 0x0c003000, SYS_OUTPUTSET );
-+ au_writel( 0x12004c00, SYS_OUTPUTCLR );
-+
- // enable LED and set it to green
- au_writel( au_readl(GPIO2_DIR) | 0x1800, GPIO2_DIR );
-- au_writel( 0x18000800, GPIO2_OUTPUT );
-+ au_writel( 0x18000000, GPIO2_OUTPUT );
-
- board_pci_idsel = mtx1_pci_idsel;
-
diff --git a/recipes/linux/linux-mtx-1-2.4.27/32-usbserial-stalled-hack.diff b/recipes/linux/linux-mtx-1-2.4.27/32-usbserial-stalled-hack.diff
deleted file mode 100644
index 1651bd5678..0000000000
--- a/recipes/linux/linux-mtx-1-2.4.27/32-usbserial-stalled-hack.diff
+++ /dev/null
@@ -1,22 +0,0 @@
---- linux-old/drivers/usb/serial/usbserial.c 2005-08-28 20:23:40.000000000 +0200
-+++ linux/drivers/usb/serial/usbserial.c 2005-08-28 20:23:12.000000000 +0200
-@@ -499,6 +499,19 @@
- /* get_usb_serial checks port->tty, so cannot be used */
- serial = port->serial;
- if (port->write_busy) {
-+
-+ /*-- how is the status of the outgoing urb? --*/
-+ /*-- did we miss a callback? --*/
-+ /*-- problem with the hack below is that we may */
-+ /* corrup structures we currently walk thru */
-+ if (port->write_urb && port->write_urb->status != -EINPROGRESS) {
-+ if (port->write_urb->complete)
-+ port->write_urb->complete(port->write_urb);
-+ else
-+ dbg("%s: URB %p has no complete function\n", __FUNCTION__, port->write_urb);
-+ }
-+
-+
- dbg("%s - port %d busy", __FUNCTION__, port->number);
- pos = pos->next;
- continue;
diff --git a/recipes/linux/linux-mtx-1-2.4.27/33-usbserial-bulk_in_size-4096.diff b/recipes/linux/linux-mtx-1-2.4.27/33-usbserial-bulk_in_size-4096.diff
deleted file mode 100644
index 91690057e2..0000000000
--- a/recipes/linux/linux-mtx-1-2.4.27/33-usbserial-bulk_in_size-4096.diff
+++ /dev/null
@@ -1,140 +0,0 @@
---- linux/drivers/usb/acm.c.orig 2006-04-07 13:56:33.837683000 +0200
-+++ linux/drivers/usb/acm.c 2006-04-07 12:14:37.995466750 +0200
-@@ -155,6 +155,11 @@
- unsigned char clocal; /* termios CLOCAL */
- };
-
-+/* global params controlling max sizes for read, write, control */
-+static int maxszr = 0;
-+static int maxszw = 0;
-+static int maxszc = 0;
-+
- static struct usb_driver acm_driver;
- static struct tty_driver acm_tty_driver;
- static struct acm *acm_table[ACM_TTY_MINORS];
-@@ -573,9 +578,13 @@
- }
- memset(acm, 0, sizeof(struct acm));
-
-- ctrlsize = epctrl->wMaxPacketSize;
-- readsize = epread->wMaxPacketSize;
-- acm->writesize = epwrite->wMaxPacketSize;
-+ ctrlsize = (epctrl->wMaxPacketSize > maxszc)?
-+ epctrl->wMaxPacketSize: maxszc;
-+ readsize = (epread->wMaxPacketSize > maxszr)?
-+ epread->wMaxPacketSize: maxszr;
-+ acm->writesize = (epwrite->wMaxPacketSize > maxszw)?
-+ epwrite->wMaxPacketSize: maxszw;
-+
- acm->iface = cfacm->interface + j;
- acm->minor = minor;
- acm->dev = dev;
-@@ -740,6 +749,16 @@
- module_init(acm_init);
- module_exit(acm_exit);
-
-+
-+MODULE_PARM(maxszr, "i");
-+MODULE_PARM_DESC(maxszr, "User specified USB endpoint read size");
-+
-+MODULE_PARM(maxszw, "i");
-+MODULE_PARM_DESC(maxszw, "User specified USB endpoint write size");
-+
-+MODULE_PARM(maxszc, "i");
-+MODULE_PARM_DESC(maxszc, "User specified USB endpoint control size");
-+
- MODULE_AUTHOR( DRIVER_AUTHOR );
- MODULE_DESCRIPTION( DRIVER_DESC );
- MODULE_LICENSE("GPL");
---- linux/drivers/usb/serial/usbserial.c-orig 2009-02-27 23:34:48.000000000 +0100
-+++ linux/drivers/usb/serial/usbserial.c 2009-02-27 23:34:54.000000000 +0100
-@@ -332,6 +332,9 @@
- static __u16 vendor = 0x05f9;
- static __u16 product = 0xffff;
-
-+static int count_smaller64 = 0;
-+static int count_bigger64 = 0;
-+
- static struct usb_device_id generic_device_ids[2]; /* Initially all zeroes. */
-
- /* All of the device info needed for the Generic Serial Converter */
-@@ -396,6 +399,10 @@
- drivers depend on it.
- */
-
-+/* global params controlling max sizes for read, write, control */
-+static int maxszr = 0;
-+static int maxszw = 0;
-+static int maxszc = 0;
-
- static int serial_refcount;
- static struct tty_driver serial_tty_driver;
-@@ -1272,6 +1279,14 @@
- tty_flip_buffer_push(tty);
- }
-
-+ if (urb->actual_length>64) {
-+ count_bigger64++;
-+ } else {
-+ count_smaller64++;
-+ }
-+
-+ /*printk("*** %d\n", urb->actual_length);*/
-+
- /* Continue trying to always read */
- usb_fill_bulk_urb (port->read_urb, serial->dev,
- usb_rcvbulkpipe (serial->dev,
-@@ -1505,7 +1520,8 @@
- err("No free urbs available");
- goto probe_error;
- }
-- buffer_size = endpoint->wMaxPacketSize;
-+ buffer_size = (endpoint->wMaxPacketSize > maxszr)?
-+ endpoint->wMaxPacketSize: maxszr;
- port->bulk_in_endpointAddress = endpoint->bEndpointAddress;
- port->bulk_in_buffer = kmalloc (buffer_size, GFP_KERNEL);
- if (!port->bulk_in_buffer) {
-@@ -1530,7 +1546,8 @@
- err("No free urbs available");
- goto probe_error;
- }
-- buffer_size = endpoint->wMaxPacketSize;
-+ buffer_size = (endpoint->wMaxPacketSize > maxszw)?
-+ endpoint->wMaxPacketSize: maxszw;
- port->bulk_out_size = buffer_size;
- port->bulk_out_endpointAddress = endpoint->bEndpointAddress;
- port->bulk_out_buffer = kmalloc (buffer_size, GFP_KERNEL);
-@@ -1556,7 +1573,8 @@
- err("No free urbs available");
- goto probe_error;
- }
-- buffer_size = endpoint->wMaxPacketSize;
-+ buffer_size = (endpoint->wMaxPacketSize > maxszc)?
-+ endpoint->wMaxPacketSize: maxszc;
- port->interrupt_in_endpointAddress = endpoint->bEndpointAddress;
- port->interrupt_in_buffer = kmalloc (buffer_size, GFP_KERNEL);
- if (!port->interrupt_in_buffer) {
-@@ -1798,6 +1816,7 @@
-
- static void __exit usb_serial_exit(void)
- {
-+ printk("*** received packets\n< 64: %d\n> 64: %d\n", count_smaller64, count_bigger64);
-
- #ifdef CONFIG_USB_SERIAL_GENERIC
- /* remove our generic driver */
-@@ -1865,6 +1884,15 @@
- MODULE_PARM(debug, "i");
- MODULE_PARM_DESC(debug, "Debug enabled or not");
-
-+MODULE_PARM(maxszr, "i");
-+MODULE_PARM_DESC(maxszr, "User specified USB endpoint read size");
-+
-+MODULE_PARM(maxszw, "i");
-+MODULE_PARM_DESC(maxszw, "User specified USB endpoint write size");
-+
-+MODULE_PARM(maxszc, "i");
-+MODULE_PARM_DESC(maxszc, "User specified USB endpoint control size");
-+
- #ifdef CONFIG_USB_SERIAL_GENERIC
- MODULE_PARM(vendor, "h");
- MODULE_PARM_DESC(vendor, "User specified USB idVendor");
diff --git a/recipes/linux/linux-mtx-1-2.4.27/39-mppe-mpc.patch b/recipes/linux/linux-mtx-1-2.4.27/39-mppe-mpc.patch
deleted file mode 100644
index 28ce19d467..0000000000
--- a/recipes/linux/linux-mtx-1-2.4.27/39-mppe-mpc.patch
+++ /dev/null
@@ -1,1665 +0,0 @@
-diff -ruN linux.orig/Documentation/Configure.help linux/Documentation/Configure.help
---- linux.orig/Documentation/Configure.help 2004-08-08 12:14:49.000000000 +0200
-+++ linux/Documentation/Configure.help 2004-08-15 09:22:18.000000000 +0200
-@@ -9905,6 +9905,28 @@
- module; it is called bsd_comp.o and will show up in the directory
- modules once you have said "make modules". If unsure, say N.
-
-+Microsoft PPP compression/encryption (MPPC/MPPE)
-+CONFIG_PPP_MPPE_MPPC
-+ Support for the Microsoft Point-To-Point Compression (RFC2118) and
-+ Microsoft Point-To-Point Encryption (RFC3078). These protocols are
-+ supported by Microsoft Windows and wide range of "hardware" access
-+ servers. MPPE is common protocol in Virtual Private Networks. According
-+ to RFC3078, MPPE supports 40, 56 and 128-bit key lengths. Depending on
-+ PPP daemon configuration on both ends of the link, following scenarios
-+ are possible:
-+ - only compression (MPPC) is used,
-+ - only encryption (MPPE) is used,
-+ - compression and encryption (MPPC+MPPE) are used.
-+
-+ Please note that Hi/Fn (http://www.hifn.com) holds patent on MPPC so
-+ you should check if this patent is valid in your country in order to
-+ avoid legal problems.
-+
-+ For more information please visit http://free.polbox.pl/h/hs001
-+
-+ To compile this driver as a module, choose M here. The module will
-+ be called ppp_mppe_mppc.o.
-+
- PPP over Ethernet
- CONFIG_PPPOE
- Support for PPP over Ethernet.
-diff -ruN linux.orig/crypto/Config.in linux/crypto/Config.in
---- linux.orig/crypto/Config.in 2004-08-08 12:14:50.000000000 +0200
-+++ linux/crypto/Config.in 2004-08-15 11:36:18.000000000 +0200
-@@ -11,7 +11,9 @@
- "$CONFIG_INET6_AH" = "y" -o \
- "$CONFIG_INET6_AH" = "m" -o \
- "$CONFIG_INET6_ESP" = "y" -o \
-- "$CONFIG_INET6_ESP" = "m" ]; then
-+ "$CONFIG_INET6_ESP" = "m" -o \
-+ "$CONFIG_PPP_MPPE_MPPC" = "y" -o \
-+ "$CONFIG_PPP_MPPE_MPPC" = "m" ]; then
- define_bool CONFIG_CRYPTO y
- else
- bool 'Cryptographic API' CONFIG_CRYPTO
-@@ -44,6 +46,7 @@
- else
- tristate ' MD5 digest algorithm' CONFIG_CRYPTO_MD5
- fi
-+
- if [ "$CONFIG_INET_AH" = "y" -o \
- "$CONFIG_INET_AH" = "m" -o \
- "$CONFIG_INET_ESP" = "y" -o \
-@@ -51,11 +54,24 @@
- "$CONFIG_INET6_AH" = "y" -o \
- "$CONFIG_INET6_AH" = "m" -o \
- "$CONFIG_INET6_ESP" = "y" -o \
-- "$CONFIG_INET6_ESP" = "m" ]; then
-- define_bool CONFIG_CRYPTO_SHA1 y
-- else
-- tristate ' SHA1 digest algorithm' CONFIG_CRYPTO_SHA1
-+ "$CONFIG_INET6_ESP" = "m" -o \
-+ "$CONFIG_PPP_MPPE_MPPC" = "y" -o \
-+ "$CONFIG_PPP_MPPE_MPPC" = "m" ]; then
-+ if [ "$CONFIG_INET_AH" = "y" -o \
-+ "$CONFIG_INET_ESP" = "y" -o \
-+ "$CONFIG_INET6_AH" = "y" -o \
-+ "$CONFIG_INET6_ESP" = "y" -o \
-+ "$CONFIG_PPP_MPPE_MPPC" = "y" ]; then
-+ define_tristate CONFIG_CRYPTO_SHA1 y
-+ else
-+ if [ "$CONFIG_CRYPTO_SHA1" != "y" -a \
-+ "$CONFIG_CRYPTO_SHA1" != "m" ]; then
-+ define_tristate CONFIG_CRYPTO_SHA1 m
-+ fi
-+ fi
- fi
-+ tristate ' SHA1 digest algorithm' CONFIG_CRYPTO_SHA1
-+
- tristate ' SHA256 digest algorithm' CONFIG_CRYPTO_SHA256
- tristate ' SHA384 and SHA512 digest algorithms' CONFIG_CRYPTO_SHA512
- if [ "$CONFIG_INET_ESP" = "y" -o \
-@@ -73,7 +89,20 @@
- tristate ' CAST5 (CAST-128) cipher algorithm' CONFIG_CRYPTO_CAST5
- tristate ' CAST6 (CAST-256) cipher algorithm' CONFIG_CRYPTO_CAST6
- tristate ' TEA and XTEA cipher algorithms' CONFIG_CRYPTO_TEA
-+
-+ if [ "$CONFIG_PPP_MPPE_MPPC" = "y" -o \
-+ "$CONFIG_PPP_MPPE_MPPC" = "m" ]; then
-+ if [ "$CONFIG_PPP_MPPE_MPPC" = "y" ]; then
-+ define_tristate CONFIG_CRYPTO_ARC4 y
-+ else
-+ if [ "$CONFIG_CRYPTO_ARC4" != "y" -a \
-+ "$CONFIG_CRYPTO_ARC4" != "m" ]; then
-+ define_tristate CONFIG_CRYPTO_ARC4 m
-+ fi
-+ fi
-+ fi
- tristate ' ARC4 cipher algorithm' CONFIG_CRYPTO_ARC4
-+
- if [ "$CONFIG_INET_IPCOMP" = "y" -o \
- "$CONFIG_INET_IPCOMP" = "m" -o \
- "$CONFIG_INET6_IPCOMP" = "y" -o \
-diff -ruN linux.orig/drivers/net/Config.in linux/drivers/net/Config.in
---- linux.orig/drivers/net/Config.in 2004-08-08 12:14:52.000000000 +0200
-+++ linux/drivers/net/Config.in 2004-08-08 12:17:43.000000000 +0200
-@@ -325,6 +325,7 @@
- dep_tristate ' PPP support for sync tty ports' CONFIG_PPP_SYNC_TTY $CONFIG_PPP
- dep_tristate ' PPP Deflate compression' CONFIG_PPP_DEFLATE $CONFIG_PPP
- dep_tristate ' PPP BSD-Compress compression' CONFIG_PPP_BSDCOMP $CONFIG_PPP
-+ dep_tristate ' Microsoft PPP compression/encryption (MPPC/MPPE)' CONFIG_PPP_MPPE_MPPC $CONFIG_PPP
- if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
- dep_tristate ' PPP over Ethernet (EXPERIMENTAL)' CONFIG_PPPOE $CONFIG_PPP
- fi
-diff -ruN linux.orig/drivers/net/Makefile linux/drivers/net/Makefile
---- linux.orig/drivers/net/Makefile 2004-08-08 12:14:52.000000000 +0200
-+++ linux/drivers/net/Makefile 2004-08-08 12:17:43.000000000 +0200
-@@ -161,6 +161,7 @@
- obj-$(CONFIG_PPP_SYNC_TTY) += ppp_synctty.o
- obj-$(CONFIG_PPP_DEFLATE) += ppp_deflate.o
- obj-$(CONFIG_PPP_BSDCOMP) += bsd_comp.o
-+obj-$(CONFIG_PPP_MPPE_MPPC) += ppp_mppe_mppc.o
- obj-$(CONFIG_PPPOE) += pppox.o pppoe.o
-
- obj-$(CONFIG_SLIP) += slip.o
-diff -ruN linux.orig/drivers/net/ppp_generic.c linux/drivers/net/ppp_generic.c
---- linux.orig/drivers/net/ppp_generic.c 2003-08-25 13:44:42.000000000 +0200
-+++ linux/drivers/net/ppp_generic.c 2004-08-08 12:17:43.000000000 +0200
-@@ -19,7 +19,7 @@
- * PPP driver, written by Michael Callahan and Al Longyear, and
- * subsequently hacked by Paul Mackerras.
- *
-- * ==FILEVERSION 20020217==
-+ * ==FILEVERSION 20040509==
- */
-
- #include <linux/config.h>
-@@ -102,6 +102,7 @@
- spinlock_t rlock; /* lock for receive side 58 */
- spinlock_t wlock; /* lock for transmit side 5c */
- int mru; /* max receive unit 60 */
-+ int mru_alloc; /* MAX(1500,MRU) for dev_alloc_skb() */
- unsigned int flags; /* control bits 64 */
- unsigned int xstate; /* transmit state bits 68 */
- unsigned int rstate; /* receive state bits 6c */
-@@ -552,7 +553,9 @@
- case PPPIOCSMRU:
- if (get_user(val, (int *) arg))
- break;
-- ppp->mru = val;
-+ ppp->mru_alloc = ppp->mru = val;
-+ if (ppp->mru_alloc < PPP_MRU)
-+ ppp->mru_alloc = PPP_MRU; /* increase for broken peers */
- err = 0;
- break;
-
-@@ -1025,14 +1028,37 @@
- case PPP_CCP:
- /* peek at outbound CCP frames */
- ppp_ccp_peek(ppp, skb, 0);
-+ /*
-+ * When LZS or MPPE/MPPC has been negotiated we don't send
-+ * CCP_RESETACK after receiving CCP_RESETREQ; in fact pppd
-+ * sends such a packet but we silently discard it here
-+ */
-+ if (CCP_CODE(skb->data+2) == CCP_RESETACK
-+ && (ppp->xcomp->compress_proto == CI_MPPE
-+ || ppp->xcomp->compress_proto == CI_LZS)) {
-+ --ppp->stats.tx_packets;
-+ ppp->stats.tx_bytes -= skb->len - 2;
-+ kfree_skb(skb);
-+ return;
-+ }
- break;
- }
-
- /* try to do packet compression */
- if ((ppp->xstate & SC_COMP_RUN) && ppp->xc_state != 0
- && proto != PPP_LCP && proto != PPP_CCP) {
-- new_skb = alloc_skb(ppp->dev->mtu + ppp->dev->hard_header_len,
-- GFP_ATOMIC);
-+ int comp_ovhd = 0;
-+ /*
-+ * because of possible data expansion when MPPC or LZS
-+ * is used, allocate compressor's buffer 12.5% bigger
-+ * than MTU
-+ */
-+ if (ppp->xcomp->compress_proto == CI_MPPE)
-+ comp_ovhd = ((ppp->dev->mtu * 9) / 8) + 1 + MPPE_OVHD;
-+ else if (ppp->xcomp->compress_proto == CI_LZS)
-+ comp_ovhd = ((ppp->dev->mtu * 9) / 8) + 1 + LZS_OVHD;
-+ new_skb = alloc_skb(ppp->dev->mtu + ppp->dev->hard_header_len
-+ + comp_ovhd, GFP_ATOMIC);
- if (new_skb == 0) {
- printk(KERN_ERR "PPP: no memory (comp pkt)\n");
- goto drop;
-@@ -1050,9 +1076,21 @@
- skb = new_skb;
- skb_put(skb, len);
- skb_pull(skb, 2); /* pull off A/C bytes */
-- } else {
-+ } else if (len == 0) {
- /* didn't compress, or CCP not up yet */
- kfree_skb(new_skb);
-+ } else {
-+ /*
-+ * (len < 0)
-+ * MPPE requires that we do not send unencrypted
-+ * frames. The compressor will return -1 if we
-+ * should drop the frame. We cannot simply test
-+ * the compress_proto because MPPE and MPPC share
-+ * the same number.
-+ */
-+ printk(KERN_ERR "ppp: compressor dropped pkt\n");
-+ kfree_skb(new_skb);
-+ goto drop;
- }
- }
-
-@@ -1540,14 +1578,15 @@
- int len;
-
- if (proto == PPP_COMP) {
-- ns = dev_alloc_skb(ppp->mru + PPP_HDRLEN);
-+ ns = dev_alloc_skb(ppp->mru_alloc + PPP_HDRLEN);
- if (ns == 0) {
- printk(KERN_ERR "ppp_decompress_frame: no memory\n");
- goto err;
- }
- /* the decompressor still expects the A/C bytes in the hdr */
- len = ppp->rcomp->decompress(ppp->rc_state, skb->data - 2,
-- skb->len + 2, ns->data, ppp->mru + PPP_HDRLEN);
-+ skb->len + 2, ns->data,
-+ ppp->mru_alloc + PPP_HDRLEN);
- if (len < 0) {
- /* Pass the compressed frame to pppd as an
- error indication. */
-@@ -1573,7 +1612,14 @@
- return skb;
-
- err:
-- ppp->rstate |= SC_DC_ERROR;
-+ if (ppp->rcomp->compress_proto != CI_MPPE
-+ && ppp->rcomp->compress_proto != CI_LZS) {
-+ /*
-+ * If decompression protocol isn't MPPE/MPPC or LZS, we set
-+ * SC_DC_ERROR flag and wait for CCP_RESETACK
-+ */
-+ ppp->rstate |= SC_DC_ERROR;
-+ }
- ppp_receive_error(ppp);
- return skb;
- }
-@@ -2253,6 +2299,7 @@
- /* Initialize the new ppp unit */
- ppp->file.index = unit;
- ppp->mru = PPP_MRU;
-+ ppp->mru_alloc = PPP_MRU;
- init_ppp_file(&ppp->file, INTERFACE);
- ppp->file.hdrlen = PPP_HDRLEN - 2; /* don't count proto bytes */
- for (i = 0; i < NUM_NP; ++i)
-diff -ruN linux.orig/drivers/net/ppp_mppe_mppc.c linux/drivers/net/ppp_mppe_mppc.c
---- linux.orig/drivers/net/ppp_mppe_mppc.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux/drivers/net/ppp_mppe_mppc.c 2004-08-15 10:12:23.000000000 +0200
-@@ -0,0 +1,1269 @@
-+/*
-+ * ppp_mppe_mppc.c - MPPC/MPPE "compressor/decompressor" module.
-+ *
-+ * Copyright (c) 1994 Árpád Magosányi <mag@bunuel.tii.matav.hu>
-+ * Copyright (c) 1999 Tim Hockin, Cobalt Networks Inc. <thockin@cobaltnet.com>
-+ * Copyright (c) 2002-2004 Jan Dubiec <jdx@slackware.pl>
-+ *
-+ * Permission to use, copy, modify, and distribute this software and its
-+ * documentation is hereby granted, provided that the above copyright
-+ * notice appears in all copies. This software is provided without any
-+ * warranty, express or implied.
-+ *
-+ * The code is based on MPPE kernel module written by Árpád Magosányi and
-+ * Tim Hockin which can be found on http://planetmirror.com/pub/mppe/.
-+ * I have added MPPC and 56 bit session keys support in MPPE.
-+ *
-+ * WARNING! Although this is open source code, its usage in some countries
-+ * (in particular in the USA) may violate Stac Inc. patent for MPPC.
-+ *
-+ * ==FILEVERSION 20040815==
-+ *
-+ */
-+
-+#include <linux/init.h>
-+#include <linux/module.h>
-+#include <linux/mm.h>
-+#include <linux/slab.h>
-+#include <asm/scatterlist.h>
-+#include <linux/vmalloc.h>
-+#include <linux/crypto.h>
-+
-+#include <linux/ppp_defs.h>
-+#include <linux/ppp-comp.h>
-+
-+/*
-+ * In 2.4.x kernels macro offset_in_page() is not defined in linux/mm.h so
-+ * we define it here; PAGE_MASK is defined in asm/page.h which is included
-+ * by linux/mm.h.
-+ */
-+#define offset_in_page(p) ((unsigned long)(p) & ~PAGE_MASK)
-+
-+/*
-+ * State for a mppc/mppe "(de)compressor".
-+ */
-+struct ppp_mppe_state {
-+ struct crypto_tfm *arc4_tfm;
-+ struct crypto_tfm *sha1_tfm;
-+ u8 master_key[MPPE_MAX_KEY_LEN];
-+ u8 session_key[MPPE_MAX_KEY_LEN];
-+ u8 mppc; /* do we use compression (MPPC)? */
-+ u8 mppe; /* do we use encryption (MPPE)? */
-+ u8 keylen; /* key length in bytes */
-+ u8 bitkeylen; /* key length in bits */
-+ u16 ccount; /* coherency counter */
-+ u16 bits; /* MPPC/MPPE control bits */
-+ u8 stateless; /* do we use stateless mode? */
-+ u8 nextflushed; /* set A bit in the next outgoing packet;
-+ used only by compressor*/
-+ u8 flushexpected; /* drop packets until A bit is received;
-+ used only by decompressor*/
-+ u8 *hist; /* MPPC history */
-+ u16 *hash; /* Hash table; used only by compressor */
-+ u16 histptr; /* history "cursor" */
-+ int unit;
-+ int debug;
-+ int mru;
-+ struct compstat stats;
-+};
-+
-+#define MPPE_HIST_LEN 8192 /* MPPC history size */
-+#define MPPE_MAX_CCOUNT 0x0FFF /* max. coherency counter value */
-+
-+#define MPPE_BIT_FLUSHED 0x80 /* bit A */
-+#define MPPE_BIT_RESET 0x40 /* bit B */
-+#define MPPE_BIT_COMP 0x20 /* bit C */
-+#define MPPE_BIT_ENCRYPTED 0x10 /* bit D */
-+
-+#define MPPE_SALT0 0xD1 /* values used in MPPE key derivation */
-+#define MPPE_SALT1 0x26 /* according to RFC3079 */
-+#define MPPE_SALT2 0x9E
-+
-+#define MPPE_CCOUNT(x) ((((x)[4] & 0x0f) << 8) + (x)[5])
-+#define MPPE_BITS(x) ((x)[4] & 0xf0)
-+#define MPPE_CTRLHI(x) ((((x)->ccount & 0xf00)>>8)|((x)->bits))
-+#define MPPE_CTRLLO(x) ((x)->ccount & 0xff)
-+
-+static inline void
-+setup_sg(struct scatterlist *sg, const void *address, unsigned int length)
-+{
-+ sg[0].page = virt_to_page(address);
-+ sg[0].offset = offset_in_page(address);
-+ sg[0].length = length;
-+}
-+
-+static inline void
-+arc4_setkey(struct ppp_mppe_state *state, const unsigned char *key,
-+ const unsigned int keylen)
-+{
-+ crypto_cipher_setkey(state->arc4_tfm, key, keylen);
-+}
-+
-+static inline void
-+arc4_encrypt(struct ppp_mppe_state *state, const unsigned char *in,
-+ const unsigned int len, unsigned char *out)
-+{
-+ struct scatterlist sgin[4], sgout[4];
-+
-+ setup_sg(sgin, in, len);
-+ setup_sg(sgout, out, len);
-+ crypto_cipher_encrypt(state->arc4_tfm, sgout, sgin, len);
-+}
-+
-+#define arc4_decrypt arc4_encrypt
-+
-+/*
-+ * Key Derivation, from RFC 3078, RFC 3079.
-+ * Equivalent to Get_Key() for MS-CHAP as described in RFC 3079.
-+ */
-+static void
-+GetNewKeyFromSHA(struct ppp_mppe_state *state, unsigned char *MasterKey,
-+ unsigned char *SessionKey, unsigned long SessionKeyLength,
-+ unsigned char *InterimKey)
-+{
-+ /*Pads used in key derivation */
-+ static const unsigned char SHAPad1[40] = {
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
-+ };
-+
-+ static const unsigned char SHAPad2[40] = {
-+ 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
-+ 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
-+ 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
-+ 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2
-+ };
-+
-+ unsigned char Digest[20]; /* SHA1_DIGEST_SIZE = 20 */
-+ struct scatterlist sg[2];
-+
-+ crypto_digest_init(state->sha1_tfm);
-+
-+ setup_sg(sg, MasterKey, SessionKeyLength);
-+ crypto_digest_update(state->sha1_tfm, sg, 1);
-+
-+ setup_sg(sg, SHAPad1, sizeof(SHAPad1));
-+ crypto_digest_update(state->sha1_tfm, sg, 1);
-+
-+ setup_sg(sg, SessionKey, SessionKeyLength);
-+ crypto_digest_update(state->sha1_tfm, sg, 1);
-+
-+ setup_sg(sg, SHAPad2, sizeof(SHAPad2));
-+ crypto_digest_update(state->sha1_tfm, sg, 1);
-+
-+ crypto_digest_final(state->sha1_tfm, Digest);
-+
-+ memcpy(InterimKey, Digest, SessionKeyLength);
-+}
-+
-+static void
-+mppe_change_key(struct ppp_mppe_state *state, int initialize)
-+{
-+ unsigned char InterimKey[MPPE_MAX_KEY_LEN];
-+
-+ GetNewKeyFromSHA(state, state->master_key, state->session_key,
-+ state->keylen, InterimKey);
-+ if (initialize) {
-+ memcpy(state->session_key, InterimKey, state->keylen);
-+ } else {
-+ arc4_setkey(state, InterimKey, state->keylen);
-+ arc4_encrypt(state, InterimKey, state->keylen, state->session_key);
-+ }
-+ if (state->keylen == 8) {
-+ if (state->bitkeylen == 40) {
-+ state->session_key[0] = MPPE_SALT0;
-+ state->session_key[1] = MPPE_SALT1;
-+ state->session_key[2] = MPPE_SALT2;
-+ } else {
-+ state->session_key[0] = MPPE_SALT0;
-+ }
-+ }
-+ arc4_setkey(state, state->session_key, state->keylen);
-+}
-+
-+/* increase 12-bit coherency counter */
-+static inline void
-+mppe_increase_ccount(struct ppp_mppe_state *state)
-+{
-+ state->ccount = (state->ccount + 1) & MPPE_MAX_CCOUNT;
-+ if (state->mppe) {
-+ if (state->stateless) {
-+ mppe_change_key(state, 0);
-+ state->nextflushed = 1;
-+ } else {
-+ if ((state->ccount & 0xff) == 0xff) {
-+ mppe_change_key(state, 0);
-+ }
-+ }
-+ }
-+}
-+
-+/* allocate space for a MPPE/MPPC (de)compressor. */
-+/* comp != 0 -> init compressor */
-+/* comp = 0 -> init decompressor */
-+static void *
-+mppe_alloc(unsigned char *options, int opt_len, int comp)
-+{
-+ struct ppp_mppe_state *state;
-+ u8* fname;
-+
-+ fname = comp ? "mppe_comp_alloc" : "mppe_decomp_alloc";
-+
-+ /*
-+ * Hack warning - additionally to the standard MPPC/MPPE configuration
-+ * options, pppd passes to the (de)copressor 8 or 16 byte session key.
-+ * Therefore options[1] contains MPPC/MPPE configuration option length
-+ * (CILEN_MPPE = 6), but the real options length, depending on the key
-+ * length, is 6+8 or 6+16.
-+ */
-+ if (opt_len < CILEN_MPPE) {
-+ printk(KERN_WARNING "%s: wrong options length: %u\n", fname, opt_len);
-+ return NULL;
-+ }
-+
-+ if (options[0] != CI_MPPE || options[1] != CILEN_MPPE ||
-+ (options[2] & ~MPPE_STATELESS) != 0 ||
-+ options[3] != 0 || options[4] != 0 ||
-+ (options[5] & ~(MPPE_128BIT|MPPE_56BIT|MPPE_40BIT|MPPE_MPPC)) != 0 ||
-+ (options[5] & (MPPE_128BIT|MPPE_56BIT|MPPE_40BIT|MPPE_MPPC)) == 0) {
-+ printk(KERN_WARNING "%s: options rejected: o[0]=%02x, o[1]=%02x, "
-+ "o[2]=%02x, o[3]=%02x, o[4]=%02x, o[5]=%02x\n", fname, options[0],
-+ options[1], options[2], options[3], options[4], options[5]);
-+ return NULL;
-+ }
-+
-+ state = (struct ppp_mppe_state *)kmalloc(sizeof(*state), GFP_KERNEL);
-+ if (state == NULL) {
-+ printk(KERN_ERR "%s: cannot allocate space for %scompressor\n", fname,
-+ comp ? "" : "de");
-+ return NULL;
-+ }
-+ memset(state, 0, sizeof(struct ppp_mppe_state));
-+
-+ state->mppc = options[5] & MPPE_MPPC; /* Do we use MPPC? */
-+ state->mppe = options[5] & (MPPE_128BIT | MPPE_56BIT |
-+ MPPE_40BIT); /* Do we use MPPE? */
-+
-+ if (state->mppc) {
-+ /* allocate MPPC history */
-+ state->hist = (u8*)vmalloc(2*MPPE_HIST_LEN*sizeof(u8));
-+ if (state->hist == NULL) {
-+ kfree(state);
-+ printk(KERN_ERR "%s: cannot allocate space for MPPC history\n",
-+ fname);
-+ return NULL;
-+ }
-+
-+ /* allocate hashtable for MPPC compressor */
-+ if (comp) {
-+ state->hash = (u16*)vmalloc(MPPE_HIST_LEN*sizeof(u16));
-+ if (state->hash == NULL) {
-+ vfree(state->hist);
-+ kfree(state);
-+ printk(KERN_ERR "%s: cannot allocate space for MPPC history\n",
-+ fname);
-+ return NULL;
-+ }
-+ }
-+ }
-+
-+ if (state->mppe) { /* specific for MPPE */
-+ /* Load SHA1 algorithm */
-+ state->sha1_tfm = crypto_alloc_tfm("sha1", 0);
-+ if (state->sha1_tfm == NULL) {
-+ vfree(state->hash);
-+ vfree(state->hist);
-+ kfree(state);
-+ printk(KERN_ERR "%s: cannot load SHA1 module\n", fname);
-+ return NULL;
-+ }
-+
-+ /* Load ARC4 algorithm */
-+ state->arc4_tfm = crypto_alloc_tfm("arc4", 0);
-+ if (state->arc4_tfm == NULL) {
-+ crypto_free_tfm(state->sha1_tfm);
-+ vfree(state->hash);
-+ vfree(state->hist);
-+ kfree(state);
-+ printk(KERN_ERR "%s: cannot load ARC4 module\n", fname);
-+ return NULL;
-+ }
-+
-+ memcpy(state->master_key, options+CILEN_MPPE, MPPE_MAX_KEY_LEN);
-+ memcpy(state->session_key, state->master_key, MPPE_MAX_KEY_LEN);
-+ /* initial key generation is done in mppe_init() */
-+ }
-+
-+ MOD_INC_USE_COUNT;
-+
-+ return (void *) state;
-+}
-+
-+static void *
-+mppe_comp_alloc(unsigned char *options, int opt_len)
-+{
-+ return mppe_alloc(options, opt_len, 1);
-+}
-+
-+static void *
-+mppe_decomp_alloc(unsigned char *options, int opt_len)
-+{
-+ return mppe_alloc(options, opt_len, 0);
-+}
-+
-+/* cleanup the (de)compressor */
-+static void
-+mppe_comp_free(void *arg)
-+{
-+ struct ppp_mppe_state *state = (struct ppp_mppe_state *) arg;
-+
-+ if (state != NULL) {
-+ if (state->mppe) {
-+ if (state->sha1_tfm != NULL)
-+ crypto_free_tfm(state->sha1_tfm);
-+ if (state->arc4_tfm != NULL)
-+ crypto_free_tfm(state->arc4_tfm);
-+ }
-+ if (state->hist != NULL)
-+ vfree(state->hist);
-+ if (state->hash != NULL)
-+ vfree(state->hash);
-+ kfree(state);
-+ }
-+
-+ MOD_DEC_USE_COUNT;
-+}
-+
-+/* init MPPC/MPPE (de)compresor */
-+/* comp != 0 -> init compressor */
-+/* comp = 0 -> init decompressor */
-+static int
-+mppe_init(void *arg, unsigned char *options, int opt_len, int unit,
-+ int hdrlen, int mru, int debug, int comp)
-+{
-+ struct ppp_mppe_state *state = (struct ppp_mppe_state *) arg;
-+ u8* fname;
-+
-+ fname = comp ? "mppe_comp_init" : "mppe_decomp_init";
-+
-+ if (opt_len < CILEN_MPPE) {
-+ if (debug)
-+ printk(KERN_WARNING "%s: wrong options length: %u\n",
-+ fname, opt_len);
-+ return 0;
-+ }
-+
-+ if (options[0] != CI_MPPE || options[1] != CILEN_MPPE ||
-+ (options[2] & ~MPPE_STATELESS) != 0 ||
-+ options[3] != 0 || options[4] != 0 ||
-+ (options[5] & ~(MPPE_56BIT|MPPE_128BIT|MPPE_40BIT|MPPE_MPPC)) != 0 ||
-+ (options[5] & (MPPE_56BIT|MPPE_128BIT|MPPE_40BIT|MPPE_MPPC)) == 0) {
-+ if (debug)
-+ printk(KERN_WARNING "%s: options rejected: o[0]=%02x, o[1]=%02x, "
-+ "o[2]=%02x, o[3]=%02x, o[4]=%02x, o[5]=%02x\n", fname,
-+ options[0], options[1], options[2], options[3], options[4],
-+ options[5]);
-+ return 0;
-+ }
-+
-+ if ((options[5] & ~MPPE_MPPC) != MPPE_128BIT &&
-+ (options[5] & ~MPPE_MPPC) != MPPE_56BIT &&
-+ (options[5] & ~MPPE_MPPC) != MPPE_40BIT &&
-+ (options[5] & MPPE_MPPC) != MPPE_MPPC) {
-+ if (debug)
-+ printk(KERN_WARNING "%s: don't know what to do: o[5]=%02x\n",
-+ fname, options[5]);
-+ return 0;
-+ }
-+
-+ state->mppc = options[5] & MPPE_MPPC; /* Do we use MPPC? */
-+ state->mppe = options[5] & (MPPE_128BIT | MPPE_56BIT |
-+ MPPE_40BIT); /* Do we use MPPE? */
-+ state->stateless = options[2] & MPPE_STATELESS; /* Do we use stateless mode? */
-+
-+ switch (state->mppe) {
-+ case MPPE_40BIT: /* 40 bit key */
-+ state->keylen = 8;
-+ state->bitkeylen = 40;
-+ break;
-+ case MPPE_56BIT: /* 56 bit key */
-+ state->keylen = 8;
-+ state->bitkeylen = 56;
-+ break;
-+ case MPPE_128BIT: /* 128 bit key */
-+ state->keylen = 16;
-+ state->bitkeylen = 128;
-+ break;
-+ default:
-+ state->keylen = 0;
-+ state->bitkeylen = 0;
-+ }
-+
-+ state->ccount = MPPE_MAX_CCOUNT;
-+ state->bits = 0;
-+ state->unit = unit;
-+ state->debug = debug;
-+ state->histptr = MPPE_HIST_LEN;
-+ if (state->mppc) { /* reset history if MPPC was negotiated */
-+ memset(state->hist, 0, 2*MPPE_HIST_LEN*sizeof(u8));
-+ }
-+
-+ if (state->mppe) { /* generate initial session keys */
-+ mppe_change_key(state, 1);
-+ }
-+
-+ if (comp) { /* specific for compressor */
-+ state->nextflushed = 1;
-+ } else { /* specific for decompressor */
-+ state->mru = mru;
-+ state->flushexpected = 1;
-+ }
-+
-+ return 1;
-+}
-+
-+static int
-+mppe_comp_init(void *arg, unsigned char *options, int opt_len, int unit,
-+ int hdrlen, int debug)
-+{
-+ return mppe_init(arg, options, opt_len, unit, hdrlen, 0, debug, 1);
-+}
-+
-+
-+static int
-+mppe_decomp_init(void *arg, unsigned char *options, int opt_len, int unit,
-+ int hdrlen, int mru, int debug)
-+{
-+ return mppe_init(arg, options, opt_len, unit, hdrlen, mru, debug, 0);
-+}
-+
-+static void
-+mppe_comp_reset(void *arg)
-+{
-+ struct ppp_mppe_state *state = (struct ppp_mppe_state *)arg;
-+
-+ if (state->debug)
-+ printk(KERN_DEBUG "%s%d: resetting MPPC/MPPE compressor\n",
-+ __FUNCTION__, state->unit);
-+
-+ state->nextflushed = 1;
-+ if (state->mppe)
-+ arc4_setkey(state, state->session_key, state->keylen);
-+}
-+
-+static void
-+mppe_decomp_reset(void *arg)
-+{
-+ /* When MPPC/MPPE is in use, we shouldn't receive any CCP Reset-Ack.
-+ But when we receive such a packet, we just ignore it. */
-+ return;
-+}
-+
-+static void
-+mppe_stats(void *arg, struct compstat *stats)
-+{
-+ struct ppp_mppe_state *state = (struct ppp_mppe_state *)arg;
-+
-+ *stats = state->stats;
-+}
-+
-+/***************************/
-+/**** Compression stuff ****/
-+/***************************/
-+/* inserts 1 to 8 bits into the output buffer */
-+static inline void putbits8(u8 *buf, u32 val, const u32 n, u32 *i, u32 *l)
-+{
-+ buf += *i;
-+ if (*l >= n) {
-+ *l = (*l) - n;
-+ val <<= *l;
-+ *buf = *buf | (val & 0xff);
-+ if (*l == 0) {
-+ *l = 8;
-+ (*i)++;
-+ *(++buf) = 0;
-+ }
-+ } else {
-+ (*i)++;
-+ *l = 8 - n + (*l);
-+ val <<= *l;
-+ *buf = *buf | ((val >> 8) & 0xff);
-+ *(++buf) = val & 0xff;
-+ }
-+}
-+
-+/* inserts 9 to 16 bits into the output buffer */
-+static inline void putbits16(u8 *buf, u32 val, const u32 n, u32 *i, u32 *l)
-+{
-+ buf += *i;
-+ if (*l >= n - 8) {
-+ (*i)++;
-+ *l = 8 - n + (*l);
-+ val <<= *l;
-+ *buf = *buf | ((val >> 8) & 0xff);
-+ *(++buf) = val & 0xff;
-+ if (*l == 0) {
-+ *l = 8;
-+ (*i)++;
-+ *(++buf) = 0;
-+ }
-+ } else {
-+ (*i)++; (*i)++;
-+ *l = 16 - n + (*l);
-+ val <<= *l;
-+ *buf = *buf | ((val >> 16) & 0xff);
-+ *(++buf) = (val >> 8) & 0xff;
-+ *(++buf) = val & 0xff;
-+ }
-+}
-+
-+/* inserts 17 to 24 bits into the output buffer */
-+static inline void putbits24(u8 *buf, u32 val, const u32 n, u32 *i, u32 *l)
-+{
-+ buf += *i;
-+ if (*l >= n - 16) {
-+ (*i)++; (*i)++;
-+ *l = 16 - n + (*l);
-+ val <<= *l;
-+ *buf = *buf | ((val >> 16) & 0xff);
-+ *(++buf) = (val >> 8) & 0xff;
-+ *(++buf) = val & 0xff;
-+ if (*l == 0) {
-+ *l = 8;
-+ (*i)++;
-+ *(++buf) = 0;
-+ }
-+ } else {
-+ (*i)++; (*i)++; (*i)++;
-+ *l = 24 - n + (*l);
-+ val <<= *l;
-+ *buf = *buf | ((val >> 24) & 0xff);
-+ *(++buf) = (val >> 16) & 0xff;
-+ *(++buf) = (val >> 8) & 0xff;
-+ *(++buf) = val & 0xff;
-+ }
-+}
-+
-+static int
-+mppc_compress(struct ppp_mppe_state *state, unsigned char *ibuf,
-+ unsigned char *obuf, int isize, int osize)
-+{
-+ u32 olen, off, len, idx, i, l;
-+ u8 *hist, *sbuf, *p, *q, *r, *s;
-+
-+ /*
-+ At this point, to avoid possible buffer overflow caused by packet
-+ expansion during/after compression, we should make sure that
-+ osize >= (((isize*9)/8)+1)+2, but we don't do that because in
-+ ppp_generic.c we simply allocate bigger obuf.
-+
-+ Maximum MPPC packet expansion is 12.5%. This is the worst case when
-+ all octets in the input buffer are >= 0x80 and we cannot find any
-+ repeated tokens. Additionally we have to reserve 2 bytes for MPPE/MPPC
-+ status bits and coherency counter.
-+ */
-+
-+ hist = state->hist + MPPE_HIST_LEN;
-+ /* check if there is enough room at the end of the history */
-+ if (state->histptr + isize >= 2*MPPE_HIST_LEN) {
-+ state->bits |= MPPE_BIT_RESET;
-+ state->histptr = MPPE_HIST_LEN;
-+ memcpy(state->hist, hist, MPPE_HIST_LEN);
-+ }
-+ /* add packet to the history; isize must be <= MPPE_HIST_LEN */
-+ sbuf = state->hist + state->histptr;
-+ memcpy(sbuf, ibuf, isize);
-+ state->histptr += isize;
-+
-+ /* compress data */
-+ r = sbuf + isize;
-+ *obuf = olen = i = 0;
-+ l = 8;
-+ while (i < isize - 2) {
-+ s = q = sbuf + i;
-+ idx = ((40543*((((s[0]<<4)^s[1])<<4)^s[2]))>>4) & 0x1fff;
-+ p = hist + state->hash[idx];
-+ state->hash[idx] = (u16) (s - hist);
-+ off = s - p;
-+ if (off > MPPE_HIST_LEN - 1 || off < 1 || *p++ != *s++ || *p++ != *s++ ||
-+ *p++ != *s++) {
-+ /* no match found; encode literal byte */
-+ if (ibuf[i] < 0x80) { /* literal byte < 0x80 */
-+ putbits8(obuf, (u32) ibuf[i], 8, &olen, &l);
-+ } else { /* literal byte >= 0x80 */
-+ putbits16(obuf, (u32) (0x100|(ibuf[i]&0x7f)), 9, &olen, &l);
-+ }
-+ ++i;
-+ continue;
-+ }
-+ if (r - q >= 64) {
-+ *p++ != *s++ || *p++ != *s++ || *p++ != *s++ || *p++ != *s++ ||
-+ *p++ != *s++ || *p++ != *s++ || *p++ != *s++ || *p++ != *s++ ||
-+ *p++ != *s++ || *p++ != *s++ || *p++ != *s++ || *p++ != *s++ ||
-+ *p++ != *s++ || *p++ != *s++ || *p++ != *s++ || *p++ != *s++ ||
-+ *p++ != *s++ || *p++ != *s++ || *p++ != *s++ || *p++ != *s++ ||
-+ *p++ != *s++ || *p++ != *s++ || *p++ != *s++ || *p++ != *s++ ||
-+ *p++ != *s++ || *p++ != *s++ || *p++ != *s++ || *p++ != *s++ ||
-+ *p++ != *s++ || *p++ != *s++ || *p++ != *s++ || *p++ != *s++ ||
-+ *p++ != *s++ || *p++ != *s++ || *p++ != *s++ || *p++ != *s++ ||
-+ *p++ != *s++ || *p++ != *s++ || *p++ != *s++ || *p++ != *s++ ||
-+ *p++ != *s++ || *p++ != *s++ || *p++ != *s++ || *p++ != *s++ ||
-+ *p++ != *s++ || *p++ != *s++ || *p++ != *s++ || *p++ != *s++ ||
-+ *p++ != *s++ || *p++ != *s++ || *p++ != *s++ || *p++ != *s++ ||
-+ *p++ != *s++ || *p++ != *s++ || *p++ != *s++ || *p++ != *s++ ||
-+ *p++ != *s++ || *p++ != *s++ || *p++ != *s++ || *p++ != *s++ ||
-+ *p++ != *s++;
-+ if (s - q == 64) {
-+ p--; s--;
-+ while((*p++ == *s++) && (s < r) && (p < q));
-+ }
-+ } else {
-+ while((*p++ == *s++) && (s < r) && (p < q));
-+ }
-+ len = s - q - 1;
-+ i += len;
-+
-+ /* at least 3 character match found; code data */
-+ /* encode offset */
-+ if (off < 64) { /* 10-bit offset; 0 <= offset < 64 */
-+ putbits16(obuf, 0x3c0|off, 10, &olen, &l);
-+ } else if (off < 320) { /* 12-bit offset; 64 <= offset < 320 */
-+ putbits16(obuf, 0xe00|(off-64), 12, &olen, &l);
-+ } else if (off < 8192) { /* 16-bit offset; 320 <= offset < 8192 */
-+ putbits16(obuf, 0xc000|(off-320), 16, &olen, &l);
-+ } else {
-+ /* This shouldn't happen; we return 0 what means "packet expands",
-+ and we send packet uncompressed. */
-+ if (state->debug)
-+ printk(KERN_DEBUG "%s%d: wrong offset value: %d\n",
-+ __FUNCTION__, state->unit, off);
-+ return 0;
-+ }
-+ /* encode length of match */
-+ if (len < 4) { /* length = 3 */
-+ putbits8(obuf, 0, 1, &olen, &l);
-+ } else if (len < 8) { /* 4 <= length < 8 */
-+ putbits8(obuf, 0x08|(len&0x03), 4, &olen, &l);
-+ } else if (len < 16) { /* 8 <= length < 16 */
-+ putbits8(obuf, 0x30|(len&0x07), 6, &olen, &l);
-+ } else if (len < 32) { /* 16 <= length < 32 */
-+ putbits8(obuf, 0xe0|(len&0x0f), 8, &olen, &l);
-+ } else if (len < 64) { /* 32 <= length < 64 */
-+ putbits16(obuf, 0x3c0|(len&0x1f), 10, &olen, &l);
-+ } else if (len < 128) { /* 64 <= length < 128 */
-+ putbits16(obuf, 0xf80|(len&0x3f), 12, &olen, &l);
-+ } else if (len < 256) { /* 128 <= length < 256 */
-+ putbits16(obuf, 0x3f00|(len&0x7f), 14, &olen, &l);
-+ } else if (len < 512) { /* 256 <= length < 512 */
-+ putbits16(obuf, 0xfe00|(len&0xff), 16, &olen, &l);
-+ } else if (len < 1024) { /* 512 <= length < 1024 */
-+ putbits24(obuf, 0x3fc00|(len&0x1ff), 18, &olen, &l);
-+ } else if (len < 2048) { /* 1024 <= length < 2048 */
-+ putbits24(obuf, 0xff800|(len&0x3ff), 20, &olen, &l);
-+ } else if (len < 4096) { /* 2048 <= length < 4096 */
-+ putbits24(obuf, 0x3ff000|(len&0x7ff), 22, &olen, &l);
-+ } else if (len < 8192) { /* 4096 <= length < 8192 */
-+ putbits24(obuf, 0xffe000|(len&0xfff), 24, &olen, &l);
-+ } else {
-+ /* This shouldn't happen; we return 0 what means "packet expands",
-+ and send packet uncompressed. */
-+ if (state->debug)
-+ printk(KERN_DEBUG "%s%d: wrong length of match value: %d\n",
-+ __FUNCTION__, state->unit, len);
-+ return 0;
-+ }
-+ }
-+
-+ /* Add remaining octets to the output */
-+ while(isize - i > 0) {
-+ if (ibuf[i] < 0x80) { /* literal byte < 0x80 */
-+ putbits8(obuf, (u32) ibuf[i++], 8, &olen, &l);
-+ } else { /* literal byte >= 0x80 */
-+ putbits16(obuf, (u32) (0x100|(ibuf[i++]&0x7f)), 9, &olen, &l);
-+ }
-+ }
-+ /* Reset unused bits of the last output octet */
-+ if ((l != 0) && (l != 8)) {
-+ putbits8(obuf, 0, l, &olen, &l);
-+ }
-+
-+ return (int) olen;
-+}
-+
-+int
-+mppe_compress(void *arg, unsigned char *ibuf, unsigned char *obuf,
-+ int isize, int osize)
-+{
-+ struct ppp_mppe_state *state = (struct ppp_mppe_state *) arg;
-+ int proto, olen, complen, off;
-+ unsigned char *wptr;
-+
-+ /* Check that the protocol is in the range we handle. */
-+ proto = PPP_PROTOCOL(ibuf);
-+ if (proto < 0x0021 || proto > 0x00fa)
-+ return 0;
-+
-+ wptr = obuf;
-+ /* Copy over the PPP header */
-+ wptr[0] = PPP_ADDRESS(ibuf);
-+ wptr[1] = PPP_CONTROL(ibuf);
-+ wptr[2] = PPP_COMP >> 8;
-+ wptr[3] = PPP_COMP;
-+ wptr += PPP_HDRLEN + (MPPE_OVHD / 2); /* Leave two octets for MPPE/MPPC bits */
-+
-+ /*
-+ * In ver. 0.99 protocol field was compressed. Deflate and BSD compress
-+ * do PFC before actual compression, RCF2118 and RFC3078 are not precise
-+ * on this topic so I decided to do PFC. Unfortunately this change caused
-+ * incompatibility with older/other MPPE/MPPC modules. I have received
-+ * a lot of complaints from unexperienced users so I have decided to revert
-+ * to previous state, i.e. the protocol field is sent uncompressed now.
-+ * Although this may be changed in the future.
-+ *
-+ * Receiving side (mppe_decompress()) still accepts packets with compressed
-+ * and uncompressed protocol field so you shouldn't get "Unsupported protocol
-+ * 0x2145 received" messages anymore.
-+ */
-+ //off = (proto > 0xff) ? 2 : 3; /* PFC - skip first protocol byte if 0 */
-+ off = 2;
-+
-+ ibuf += off;
-+
-+ mppe_increase_ccount(state);
-+
-+ if (state->nextflushed) {
-+ state->bits |= MPPE_BIT_FLUSHED;
-+ state->nextflushed = 0;
-+ if (state->mppe && !state->stateless) {
-+ /*
-+ * If this is the flag packet, the key has been already changed in
-+ * mppe_increase_ccount() so we dont't do it once again.
-+ */
-+ if ((state->ccount & 0xff) != 0xff) {
-+ arc4_setkey(state, state->session_key, state->keylen);
-+ }
-+ }
-+ if (state->mppc) { /* reset history */
-+ state->bits |= MPPE_BIT_RESET;
-+ state->histptr = MPPE_HIST_LEN;
-+ memset(state->hist + MPPE_HIST_LEN, 0, MPPE_HIST_LEN*sizeof(u8));
-+ }
-+ }
-+
-+ if (state->mppc && !state->mppe) { /* Do only compression */
-+ complen = mppc_compress(state, ibuf, wptr, isize - off,
-+ osize - PPP_HDRLEN - (MPPE_OVHD / 2));
-+ /*
-+ * TODO: Implement an heuristics to handle packet expansion in a smart
-+ * way. Now, when a packet expands, we send it as uncompressed and
-+ * when next packet is sent we have to reset compressor's history.
-+ * Maybe it would be better to send such packet as compressed in order
-+ * to keep history's continuity.
-+ */
-+ if ((complen > isize) || (complen > osize - PPP_HDRLEN) ||
-+ (complen == 0)) {
-+ /* packet expands */
-+ state->nextflushed = 1;
-+ memcpy(wptr, ibuf, isize - off);
-+ olen = isize - (off - 2) + MPPE_OVHD;
-+ (state->stats).inc_bytes += olen;
-+ (state->stats).inc_packets++;
-+ } else {
-+ state->bits |= MPPE_BIT_COMP;
-+ olen = complen + PPP_HDRLEN + (MPPE_OVHD / 2);
-+ (state->stats).comp_bytes += olen;
-+ (state->stats).comp_packets++;
-+ }
-+ } else { /* Do encryption with or without compression */
-+ state->bits |= MPPE_BIT_ENCRYPTED;
-+ if (!state->mppc && state->mppe) { /* Do only encryption */
-+ /* read from ibuf, write to wptr, adjust for PPP_HDRLEN */
-+ arc4_encrypt(state, ibuf, isize - off, wptr);
-+ olen = isize - (off - 2) + MPPE_OVHD;
-+ (state->stats).inc_bytes += olen;
-+ (state->stats).inc_packets++;
-+ } else { /* Do compression and then encryption - RFC3078 */
-+ complen = mppc_compress(state, ibuf, wptr, isize - off,
-+ osize - PPP_HDRLEN - (MPPE_OVHD / 2));
-+ /*
-+ * TODO: Implement an heuristics to handle packet expansion in a smart
-+ * way. Now, when a packet expands, we send it as uncompressed and
-+ * when next packet is sent we have to reset compressor's history.
-+ * Maybe it would be good to send such packet as compressed in order
-+ * to keep history's continuity.
-+ */
-+ if ((complen > isize) || (complen > osize - PPP_HDRLEN) ||
-+ (complen == 0)) {
-+ /* packet expands */
-+ state->nextflushed = 1;
-+ arc4_encrypt(state, ibuf, isize - off, wptr);
-+ olen = isize - (off - 2) + MPPE_OVHD;
-+ (state->stats).inc_bytes += olen;
-+ (state->stats).inc_packets++;
-+ } else {
-+ state->bits |= MPPE_BIT_COMP;
-+ /* Hack warning !!! RC4 implementation which we use does
-+ encryption "in place" - it means that input and output
-+ buffers can be *the same* memory area. Therefore we don't
-+ need to use a temporary buffer. But be careful - other
-+ implementations don't have to be so nice.
-+ I used to use ibuf as temporary buffer here, but it led
-+ packet sniffers into error. Thanks to Wilfried Weissmann
-+ for pointing that. */
-+ arc4_encrypt(state, wptr, complen, wptr);
-+ olen = complen + PPP_HDRLEN + (MPPE_OVHD / 2);
-+ (state->stats).comp_bytes += olen;
-+ (state->stats).comp_packets++;
-+ }
-+ }
-+ }
-+
-+ /* write status bits and coherency counter into the output buffer */
-+ wptr = obuf + PPP_HDRLEN;
-+ wptr[0] = MPPE_CTRLHI(state);
-+ wptr[1] = MPPE_CTRLLO(state);
-+
-+ state->bits = 0;
-+
-+ (state->stats).unc_bytes += isize;
-+ (state->stats).unc_packets++;
-+
-+ return olen;
-+}
-+
-+/***************************/
-+/*** Decompression stuff ***/
-+/***************************/
-+static inline u32 getbits(const u8 *buf, const u32 n, u32 *i, u32 *l)
-+{
-+ static const u32 m[] = {0x00, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff};
-+ u32 res, ol;
-+
-+ ol = *l;
-+ if (*l >= n) {
-+ *l = (*l) - n;
-+ res = (buf[*i] & m[ol]) >> (*l);
-+ if (*l == 0) {
-+ *l = 8;
-+ (*i)++;
-+ }
-+ } else {
-+ *l = 8 - n + (*l);
-+ res = (buf[(*i)++] & m[ol]) << 8;
-+ res = (res | buf[*i]) >> (*l);
-+ }
-+
-+ return res;
-+}
-+
-+static inline u32 getbyte(const u8 *buf, const u32 i, const u32 l)
-+{
-+ if (l == 8) {
-+ return buf[i];
-+ } else {
-+ return (((buf[i] << 8) | buf[i+1]) >> l) & 0xff;
-+ }
-+}
-+
-+static inline void lamecopy(u8 *dst, u8 *src, u32 len)
-+{
-+ while (len--)
-+ *dst++ = *src++;
-+}
-+
-+static int
-+mppc_decompress(struct ppp_mppe_state *state, unsigned char *ibuf,
-+ unsigned char *obuf, int isize, int osize)
-+{
-+ u32 olen, off, len, bits, val, sig, i, l;
-+ u8 *history, *s;
-+
-+ history = state->hist + state->histptr;
-+ olen = len = i = 0;
-+ l = 8;
-+ bits = isize * 8;
-+ while (bits >= 8) {
-+ val = getbyte(ibuf, i++, l);
-+ if (val < 0x80) { /* literal byte < 0x80 */
-+ if (state->histptr < 2*MPPE_HIST_LEN) {
-+ /* copy uncompressed byte to the history */
-+ (state->hist)[(state->histptr)++] = (u8) val;
-+ } else {
-+ /* buffer overflow; drop packet */
-+ if (state->debug)
-+ printk(KERN_ERR "%s%d: trying to write outside history "
-+ "buffer\n", __FUNCTION__, state->unit);
-+ return DECOMP_ERROR;
-+ }
-+ olen++;
-+ bits -= 8;
-+ continue;
-+ }
-+
-+ sig = val & 0xc0;
-+ if (sig == 0x80) { /* literal byte >= 0x80 */
-+ if (state->histptr < 2*MPPE_HIST_LEN) {
-+ /* copy uncompressed byte to the history */
-+ (state->hist)[(state->histptr)++] =
-+ (u8) (0x80|((val&0x3f)<<1)|getbits(ibuf, 1 , &i ,&l));
-+ } else {
-+ /* buffer overflow; drop packet */
-+ if (state->debug)
-+ printk(KERN_ERR "%s%d: trying to write outside history "
-+ "buffer\n", __FUNCTION__, state->unit);
-+ return DECOMP_ERROR;
-+ }
-+ olen++;
-+ bits -= 9;
-+ continue;
-+ }
-+
-+ /* Not a literal byte so it must be an (offset,length) pair */
-+ /* decode offset */
-+ sig = val & 0xf0;
-+ if (sig == 0xf0) { /* 10-bit offset; 0 <= offset < 64 */
-+ off = (((val&0x0f)<<2)|getbits(ibuf, 2 , &i ,&l));
-+ bits -= 10;
-+ } else {
-+ if (sig == 0xe0) { /* 12-bit offset; 64 <= offset < 320 */
-+ off = ((((val&0x0f)<<4)|getbits(ibuf, 4 , &i ,&l))+64);
-+ bits -= 12;
-+ } else {
-+ if ((sig&0xe0) == 0xc0) {/* 16-bit offset; 320 <= offset < 8192 */
-+ off = ((((val&0x1f)<<8)|getbyte(ibuf, i++, l))+320);
-+ bits -= 16;
-+ if (off > MPPE_HIST_LEN - 1) {
-+ if (state->debug)
-+ printk(KERN_DEBUG "%s%d: too big offset value: %d\n",
-+ __FUNCTION__, state->unit, off);
-+ return DECOMP_ERROR;
-+ }
-+ } else { /* this shouldn't happen */
-+ if (state->debug)
-+ printk(KERN_DEBUG "%s%d: cannot decode offset value\n",
-+ __FUNCTION__, state->unit);
-+ return DECOMP_ERROR;
-+ }
-+ }
-+ }
-+ /* decode length of match */
-+ val = getbyte(ibuf, i, l);
-+ if ((val & 0x80) == 0x00) { /* len = 3 */
-+ len = 3;
-+ bits--;
-+ getbits(ibuf, 1 , &i ,&l);
-+ } else if ((val & 0xc0) == 0x80) { /* 4 <= len < 8 */
-+ len = 0x04 | ((val>>4) & 0x03);
-+ bits -= 4;
-+ getbits(ibuf, 4 , &i ,&l);
-+ } else if ((val & 0xe0) == 0xc0) { /* 8 <= len < 16 */
-+ len = 0x08 | ((val>>2) & 0x07);
-+ bits -= 6;
-+ getbits(ibuf, 6 , &i ,&l);
-+ } else if ((val & 0xf0) == 0xe0) { /* 16 <= len < 32 */
-+ len = 0x10 | (val & 0x0f);
-+ bits -= 8;
-+ i++;
-+ } else {
-+ bits -= 8;
-+ val = (val << 8) | getbyte(ibuf, ++i, l);
-+ if ((val & 0xf800) == 0xf000) { /* 32 <= len < 64 */
-+ len = 0x0020 | ((val >> 6) & 0x001f);
-+ bits -= 2;
-+ getbits(ibuf, 2 , &i ,&l);
-+ } else if ((val & 0xfc00) == 0xf800) { /* 64 <= len < 128 */
-+ len = 0x0040 | ((val >> 4) & 0x003f);
-+ bits -= 4;
-+ getbits(ibuf, 4 , &i ,&l);
-+ } else if ((val & 0xfe00) == 0xfc00) { /* 128 <= len < 256 */
-+ len = 0x0080 | ((val >> 2) & 0x007f);
-+ bits -= 6;
-+ getbits(ibuf, 6 , &i ,&l);
-+ } else if ((val & 0xff00) == 0xfe00) { /* 256 <= len < 512 */
-+ len = 0x0100 | (val & 0x00ff);
-+ bits -= 8;
-+ i++;
-+ } else {
-+ bits -= 8;
-+ val = (val << 8) | getbyte(ibuf, ++i, l);
-+ if ((val & 0xff8000) == 0xff0000) { /* 512 <= len < 1024 */
-+ len = 0x000200 | ((val >> 6) & 0x0001ff);
-+ bits -= 2;
-+ getbits(ibuf, 2 , &i ,&l);
-+ } else if ((val & 0xffc000) == 0xff8000) {/* 1024 <= len < 2048 */
-+ len = 0x000400 | ((val >> 4) & 0x0003ff);
-+ bits -= 4;
-+ getbits(ibuf, 4 , &i ,&l);
-+ } else if ((val & 0xffe000) == 0xffc000) {/* 2048 <= len < 4096 */
-+ len = 0x000800 | ((val >> 2) & 0x0007ff);
-+ bits -= 6;
-+ getbits(ibuf, 6 , &i ,&l);
-+ } else if ((val & 0xfff000) == 0xffe000) {/* 4096 <= len < 8192 */
-+ len = 0x001000 | (val & 0x000fff);
-+ bits -= 8;
-+ i++;
-+ } else { /* this shouldn't happen */
-+ if (state->debug)
-+ printk(KERN_DEBUG "%s%d: wrong length code: 0x%X\n",
-+ __FUNCTION__, state->unit, val);
-+ return DECOMP_ERROR;
-+ }
-+ }
-+ }
-+ s = state->hist + state->histptr;
-+ state->histptr += len;
-+ olen += len;
-+ if (state->histptr < 2*MPPE_HIST_LEN) {
-+ /* copy uncompressed bytes to the history */
-+
-+ /* In some cases len may be greater than off. It means that memory
-+ * areas pointed by s and s-off overlap. I had used memmove() here
-+ * because I thought that it acts as libc's version. Unfortunately,
-+ * I was wrong. :-) I got strange errors sometimes. Wilfried suggested
-+ * using of byte by byte copying here and strange errors disappeared.
-+ */
-+ lamecopy(s, s - off, len);
-+ } else {
-+ /* buffer overflow; drop packet */
-+ if (state->debug)
-+ printk(KERN_ERR "%s%d: trying to write outside history "
-+ "buffer\n", __FUNCTION__, state->unit);
-+ return DECOMP_ERROR;
-+ }
-+ }
-+
-+ /* Do PFC decompression */
-+ len = olen;
-+ if ((history[0] & 0x01) != 0) {
-+ obuf[0] = 0;
-+ obuf++;
-+ len++;
-+ }
-+
-+ if (len <= osize) {
-+ /* copy uncompressed packet to the output buffer */
-+ memcpy(obuf, history, olen);
-+ } else {
-+ /* buffer overflow; drop packet */
-+ if (state->debug)
-+ printk(KERN_ERR "%s%d: too big uncompressed packet: %d\n",
-+ __FUNCTION__, state->unit, len + (PPP_HDRLEN / 2));
-+ return DECOMP_ERROR;
-+ }
-+
-+ return (int) len;
-+}
-+
-+int
-+mppe_decompress(void *arg, unsigned char *ibuf, int isize,
-+ unsigned char *obuf, int osize)
-+{
-+ struct ppp_mppe_state *state = (struct ppp_mppe_state *)arg;
-+ int seq, bits, uncomplen;
-+
-+ if (isize <= PPP_HDRLEN + MPPE_OVHD) {
-+ if (state->debug) {
-+ printk(KERN_DEBUG "%s%d: short packet (len=%d)\n", __FUNCTION__,
-+ state->unit, isize);
-+ }
-+ return DECOMP_ERROR;
-+ }
-+
-+ /* Get coherency counter and control bits from input buffer */
-+ seq = MPPE_CCOUNT(ibuf);
-+ bits = MPPE_BITS(ibuf);
-+
-+ if (state->stateless) {
-+ /* RFC 3078, sec 8.1. */
-+ mppe_increase_ccount(state);
-+ if ((seq != state->ccount) && state->debug)
-+ printk(KERN_DEBUG "%s%d: bad sequence number: %d, expected: %d\n",
-+ __FUNCTION__, state->unit, seq, state->ccount);
-+ while (seq != state->ccount)
-+ mppe_increase_ccount(state);
-+ } else {
-+ /* RFC 3078, sec 8.2. */
-+ if (state->flushexpected) { /* discard state */
-+ if ((bits & MPPE_BIT_FLUSHED)) { /* we received expected FLUSH bit */
-+ while (seq != state->ccount)
-+ mppe_increase_ccount(state);
-+ state->flushexpected = 0;
-+ } else /* drop packet*/
-+ return DECOMP_ERROR;
-+ } else { /* normal state */
-+ mppe_increase_ccount(state);
-+ if (seq != state->ccount) {
-+ /* Packet loss detected, enter the discard state. */
-+ if (state->debug)
-+ printk(KERN_DEBUG "%s%d: bad sequence number: %d, expected: %d\n",
-+ __FUNCTION__, state->unit, seq, state->ccount);
-+ state->flushexpected = 1;
-+ return DECOMP_ERROR;
-+ }
-+ }
-+ if (state->mppe && (bits & MPPE_BIT_FLUSHED)) {
-+ arc4_setkey(state, state->session_key, state->keylen);
-+ }
-+ }
-+
-+ if (state->mppc && (bits & (MPPE_BIT_FLUSHED | MPPE_BIT_RESET))) {
-+ state->histptr = MPPE_HIST_LEN;
-+ if ((bits & MPPE_BIT_FLUSHED)) {
-+ memset(state->hist + MPPE_HIST_LEN, 0, MPPE_HIST_LEN*sizeof(u8));
-+ } else
-+ if ((bits & MPPE_BIT_RESET)) {
-+ memcpy(state->hist, state->hist + MPPE_HIST_LEN, MPPE_HIST_LEN);
-+ }
-+ }
-+
-+ /* Fill in the first part of the PPP header. The protocol field
-+ comes from the decompressed data. */
-+ obuf[0] = PPP_ADDRESS(ibuf);
-+ obuf[1] = PPP_CONTROL(ibuf);
-+ obuf += PPP_HDRLEN / 2;
-+
-+ if (state->mppe) { /* process encrypted packet */
-+ if ((bits & MPPE_BIT_ENCRYPTED)) {
-+ /* OK, packet encrypted, so decrypt it */
-+ if (state->mppc && (bits & MPPE_BIT_COMP)) {
-+ /* Hack warning !!! RC4 implementation which we use does
-+ decryption "in place" - it means that input and output
-+ buffers can be *the same* memory area. Therefore we don't
-+ need to use a temporary buffer. But be careful - other
-+ implementations don't have to be so nice. */
-+ arc4_decrypt(state, ibuf + PPP_HDRLEN + (MPPE_OVHD / 2), isize -
-+ PPP_HDRLEN - (MPPE_OVHD / 2), ibuf + PPP_HDRLEN +
-+ (MPPE_OVHD / 2));
-+ uncomplen = mppc_decompress(state, ibuf + PPP_HDRLEN +
-+ (MPPE_OVHD / 2), obuf, isize -
-+ PPP_HDRLEN - (MPPE_OVHD / 2),
-+ osize - (PPP_HDRLEN / 2));
-+ if (uncomplen == DECOMP_ERROR) {
-+ state->flushexpected = 1;
-+ return DECOMP_ERROR;
-+ }
-+ uncomplen += PPP_HDRLEN / 2;
-+ (state->stats).comp_bytes += isize;
-+ (state->stats).comp_packets++;
-+ } else {
-+ uncomplen = isize - MPPE_OVHD;
-+ /* Decrypt the first byte in order to check if it is
-+ compressed or uncompressed protocol field */
-+ arc4_decrypt(state, ibuf + PPP_HDRLEN + (MPPE_OVHD / 2), 1, obuf);
-+ /* Do PFC decompression */
-+ if ((obuf[0] & 0x01) != 0) {
-+ obuf[1] = obuf[0];
-+ obuf[0] = 0;
-+ obuf++;
-+ uncomplen++;
-+ }
-+ /* And finally, decrypt the rest of the frame. */
-+ arc4_decrypt(state, ibuf + PPP_HDRLEN + (MPPE_OVHD / 2) + 1,
-+ isize - PPP_HDRLEN - (MPPE_OVHD / 2) - 1, obuf + 1);
-+ (state->stats).inc_bytes += isize;
-+ (state->stats).inc_packets++;
-+ }
-+ } else { /* this shouldn't happen */
-+ if (state->debug)
-+ printk(KERN_ERR "%s%d: encryption negotiated but not an "
-+ "encrypted packet received\n", __FUNCTION__, state->unit);
-+ mppe_change_key(state, 0);
-+ state->flushexpected = 1;
-+ return DECOMP_ERROR;
-+ }
-+ } else {
-+ if (state->mppc) { /* no MPPE, only MPPC */
-+ if ((bits & MPPE_BIT_COMP)) {
-+ uncomplen = mppc_decompress(state, ibuf + PPP_HDRLEN +
-+ (MPPE_OVHD / 2), obuf, isize -
-+ PPP_HDRLEN - (MPPE_OVHD / 2),
-+ osize - (PPP_HDRLEN / 2));
-+ if (uncomplen == DECOMP_ERROR) {
-+ state->flushexpected = 1;
-+ return DECOMP_ERROR;
-+ }
-+ uncomplen += PPP_HDRLEN / 2;
-+ (state->stats).comp_bytes += isize;
-+ (state->stats).comp_packets++;
-+ } else {
-+ memcpy(obuf, ibuf + PPP_HDRLEN + (MPPE_OVHD / 2), isize -
-+ PPP_HDRLEN - (MPPE_OVHD / 2));
-+ uncomplen = isize - MPPE_OVHD;
-+ (state->stats).inc_bytes += isize;
-+ (state->stats).inc_packets++;
-+ }
-+ } else { /* this shouldn't happen */
-+ if (state->debug)
-+ printk(KERN_ERR "%s%d: error - not an MPPC or MPPE frame "
-+ "received\n", __FUNCTION__, state->unit);
-+ state->flushexpected = 1;
-+ return DECOMP_ERROR;
-+ }
-+ }
-+
-+ (state->stats).unc_bytes += uncomplen;
-+ (state->stats).unc_packets++;
-+
-+ return uncomplen;
-+}
-+
-+
-+/************************************************************
-+ * Module interface table
-+ ************************************************************/
-+
-+/* These are in ppp_generic.c */
-+extern int ppp_register_compressor (struct compressor *cp);
-+extern void ppp_unregister_compressor (struct compressor *cp);
-+
-+/*
-+ * Functions exported to ppp_generic.c.
-+ *
-+ * In case of MPPC/MPPE there is no need to process incompressible data
-+ * because such a data is sent in MPPC/MPPE frame. Therefore the (*incomp)
-+ * callback function isn't needed.
-+ */
-+struct compressor ppp_mppe = {
-+ CI_MPPE, /* compress_proto */
-+ mppe_comp_alloc, /* comp_alloc */
-+ mppe_comp_free, /* comp_free */
-+ mppe_comp_init, /* comp_init */
-+ mppe_comp_reset, /* comp_reset */
-+ mppe_compress, /* compress */
-+ mppe_stats, /* comp_stat */
-+ mppe_decomp_alloc, /* decomp_alloc */
-+ mppe_comp_free, /* decomp_free */
-+ mppe_decomp_init, /* decomp_init */
-+ mppe_decomp_reset, /* decomp_reset */
-+ mppe_decompress, /* decompress */
-+ NULL, /* incomp */
-+ mppe_stats, /* decomp_stat */
-+};
-+
-+/************************************************************
-+ * Module support routines
-+ ************************************************************/
-+
-+int __init mppe_module_init(void)
-+{
-+ int answer = ppp_register_compressor(&ppp_mppe);
-+ if (answer == 0) {
-+ printk(KERN_INFO "MPPE/MPPC encryption/compression module registered\n");
-+ }
-+ return answer;
-+}
-+
-+void __exit mppe_module_cleanup(void)
-+{
-+ ppp_unregister_compressor(&ppp_mppe);
-+ printk(KERN_INFO "MPPE/MPPC encryption/compression module unregistered\n");
-+}
-+
-+module_init(mppe_module_init);
-+module_exit(mppe_module_cleanup);
-+
-+MODULE_AUTHOR("Jan Dubiec <jdx@slackware.pl>");
-+MODULE_DESCRIPTION("MPPE/MPPC encryption/compression module for Linux");
-+MODULE_LICENSE("Dual BSD/GPL");
-diff -ruN linux.orig/include/linux/ppp-comp.h linux/include/linux/ppp-comp.h
---- linux.orig/include/linux/ppp-comp.h 1999-08-06 19:44:11.000000000 +0200
-+++ linux/include/linux/ppp-comp.h 2004-08-08 12:17:43.000000000 +0200
-@@ -1,34 +1,42 @@
- /*
- * ppp-comp.h - Definitions for doing PPP packet compression.
- *
-- * Copyright (c) 1994 The Australian National University.
-- * All rights reserved.
-+ * Copyright (c) 1984 Paul Mackerras. All rights reserved.
- *
-- * Permission to use, copy, modify, and distribute this software and its
-- * documentation is hereby granted, provided that the above copyright
-- * notice appears in all copies. This software is provided without any
-- * warranty, express or implied. The Australian National University
-- * makes no representations about the suitability of this software for
-- * any purpose.
-- *
-- * IN NO EVENT SHALL THE AUSTRALIAN NATIONAL UNIVERSITY BE LIABLE TO ANY
-- * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
-- * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
-- * THE AUSTRALIAN NATIONAL UNIVERSITY HAVE BEEN ADVISED OF THE POSSIBILITY
-- * OF SUCH DAMAGE.
-- *
-- * THE AUSTRALIAN NATIONAL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES,
-- * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
-- * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
-- * ON AN "AS IS" BASIS, AND THE AUSTRALIAN NATIONAL UNIVERSITY HAS NO
-- * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS,
-- * OR MODIFICATIONS.
-+ * Redistribution and use in source and binary forms, with or without
-+ * modification, are permitted provided that the following conditions
-+ * are met:
- *
-- * $Id: ppp-comp.h,v 1.6 1997/11/27 06:04:44 paulus Exp $
-+ * 1. Redistributions of source code must retain the above copyright
-+ * notice, this list of conditions and the following disclaimer.
-+ *
-+ * 2. Redistributions in binary form must reproduce the above copyright
-+ * notice, this list of conditions and the following disclaimer in
-+ * the documentation and/or other materials provided with the
-+ * distribution.
-+ *
-+ * 3. The name(s) of the authors of this software must not be used to
-+ * endorse or promote products derived from this software without
-+ * prior written permission.
-+ *
-+ * 4. Redistributions of any form whatsoever must retain the following
-+ * acknowledgment:
-+ * "This product includes software developed by Paul Mackerras
-+ * <paulus@samba.org>".
-+ *
-+ * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO
-+ * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
-+ * AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
-+ * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
-+ * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
-+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-+ *
-+ * $Id: ppp-comp.h,v 1.10 2002/12/06 09:49:15 paulus Exp $
- */
-
- /*
-- * ==FILEVERSION 980319==
-+ * ==FILEVERSION 20040509==
- *
- * NOTE TO MAINTAINERS:
- * If you modify this file at all, please set the above date.
-@@ -78,7 +86,7 @@
-
- /* Compress a packet */
- int (*compress) (void *state, unsigned char *rptr,
-- unsigned char *obuf, int isize, int osize);
-+ unsigned char *obuf, int isize, int osize);
-
- /* Return compression statistics */
- void (*comp_stat) (void *state, struct compstat *stats);
-@@ -99,7 +107,7 @@
-
- /* Decompress a packet. */
- int (*decompress) (void *state, unsigned char *ibuf, int isize,
-- unsigned char *obuf, int osize);
-+ unsigned char *obuf, int osize);
-
- /* Update state for an incompressible packet received */
- void (*incomp) (void *state, unsigned char *ibuf, int icnt);
-@@ -187,6 +195,42 @@
- #define DEFLATE_CHK_SEQUENCE 0
-
- /*
-+ * Definitions for MPPE/MPPC.
-+ */
-+
-+#define CI_MPPE 18 /* config option for MPPE */
-+#define CILEN_MPPE 6 /* length of config option */
-+
-+#define MPPE_OVHD 4 /* MPPE overhead */
-+#define MPPE_MAX_KEY_LEN 16 /* largest key length (128-bit) */
-+
-+#define MPPE_STATELESS 0x01 /* configuration bit H */
-+#define MPPE_40BIT 0x20 /* configuration bit L */
-+#define MPPE_56BIT 0x80 /* configuration bit M */
-+#define MPPE_128BIT 0x40 /* configuration bit S */
-+#define MPPE_MPPC 0x01 /* configuration bit C */
-+
-+/*
-+ * Definitions for Stac LZS.
-+ */
-+
-+#define CI_LZS 17 /* config option for Stac LZS */
-+#define CILEN_LZS 5 /* length of config option */
-+
-+#define LZS_OVHD 4 /* max. LZS overhead */
-+#define LZS_HIST_LEN 2048 /* LZS history size */
-+#define LZS_MAX_CCOUNT 0x0FFF /* max. coherency counter value */
-+
-+#define LZS_MODE_NONE 0
-+#define LZS_MODE_LCB 1
-+#define LZS_MODE_CRC 2
-+#define LZS_MODE_SEQ 3
-+#define LZS_MODE_EXT 4
-+
-+#define LZS_EXT_BIT_FLUSHED 0x80 /* bit A */
-+#define LZS_EXT_BIT_COMP 0x20 /* bit C */
-+
-+/*
- * Definitions for other, as yet unsupported, compression methods.
- */
-
diff --git a/recipes/linux/linux-mtx-1-2.4.27/40-option-hsdpa.patch b/recipes/linux/linux-mtx-1-2.4.27/40-option-hsdpa.patch
deleted file mode 100644
index 2055f72312..0000000000
--- a/recipes/linux/linux-mtx-1-2.4.27/40-option-hsdpa.patch
+++ /dev/null
@@ -1,2961 +0,0 @@
-diff -uNr linux-org/Documentation/Configure.help linux/Documentation/Configure.help
---- linux-org/Documentation/Configure.help 2006-02-06 14:01:32.375955928 +0100
-+++ linux/Documentation/Configure.help 2006-02-06 15:51:13.332498464 +0100
-@@ -4057,6 +4057,9 @@
- The module will be called synclinkmp.o. If you want to do that, say M
- here.
-
-+Option HSDPA card support
-+CONFIG_NOZOMI
-+
- ACP Modem (Mwave) support
- CONFIG_MWAVE
- The ACP modem (Mwave) for Linux is a WinModem. It is composed of a
-diff -uNr linux-org/drivers/char/Config.in linux/drivers/char/Config.in
---- linux-org/drivers/char/Config.in 2006-02-06 14:01:55.767399888 +0100
-+++ linux/drivers/char/Config.in 2006-02-06 15:51:07.574373832 +0100
-@@ -388,6 +388,8 @@
-
- endmenu
-
-+tristate ' Option HSDPA card support' CONFIG_NOZOMI
-+
- if [ "$CONFIG_HOTPLUG" = "y" -a "$CONFIG_PCMCIA" != "n" ]; then
- source drivers/char/pcmcia/Config.in
- fi
-diff -uNr linux-org/drivers/char/Makefile linux/drivers/char/Makefile
---- linux-org/drivers/char/Makefile 2006-02-06 14:01:55.782397608 +0100
-+++ linux/drivers/char/Makefile 2006-02-06 15:30:37.949305256 +0100
-@@ -331,6 +331,11 @@
- obj-$(CONFIG_INDYDOG) += indydog.o
- obj-$(CONFIG_8xx_WDT) += mpc8xx_wdt.o
-
-+subdir-$(CONFIG_NOZOMI) += nozomi
-+ifeq ($(CONFIG_NOZOMI),y)
-+ obj-y += nozomi/noz.o
-+endif
-+
- subdir-$(CONFIG_MWAVE) += mwave
- ifeq ($(CONFIG_MWAVE),y)
- obj-y += mwave/mwave.o
-diff -uNr linux-org/drivers/char/nozomi/CHANGELOG linux/drivers/char/nozomi/CHANGELOG
---- linux-org/drivers/char/nozomi/CHANGELOG 1970-01-01 01:00:00.000000000 +0100
-+++ linux/drivers/char/nozomi/CHANGELOG 2006-02-06 15:30:07.370953872 +0100
-@@ -0,0 +1,7 @@
-+/*
-+ * Version 1.0
-+ *
-+ * First version of driver, only tested with card of type F32_2.
-+ * Works fine with 2.4 and 2.6 kernels.
-+ * Driver also support big endian architecture.
-+ */
-diff -uNr linux-org/drivers/char/nozomi/COPYING linux/drivers/char/nozomi/COPYING
---- linux-org/drivers/char/nozomi/COPYING 1970-01-01 01:00:00.000000000 +0100
-+++ linux/drivers/char/nozomi/COPYING 2006-02-06 15:30:07.371953720 +0100
-@@ -0,0 +1,340 @@
-+ GNU GENERAL PUBLIC LICENSE
-+ Version 2, June 1991
-+
-+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
-+ 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-+ Everyone is permitted to copy and distribute verbatim copies
-+ of this license document, but changing it is not allowed.
-+
-+ Preamble
-+
-+ The licenses for most software are designed to take away your
-+freedom to share and change it. By contrast, the GNU General Public
-+License is intended to guarantee your freedom to share and change free
-+software--to make sure the software is free for all its users. This
-+General Public License applies to most of the Free Software
-+Foundation's software and to any other program whose authors commit to
-+using it. (Some other Free Software Foundation software is covered by
-+the GNU Library General Public License instead.) You can apply it to
-+your programs, too.
-+
-+ When we speak of free software, we are referring to freedom, not
-+price. Our General Public Licenses are designed to make sure that you
-+have the freedom to distribute copies of free software (and charge for
-+this service if you wish), that you receive source code or can get it
-+if you want it, that you can change the software or use pieces of it
-+in new free programs; and that you know you can do these things.
-+
-+ To protect your rights, we need to make restrictions that forbid
-+anyone to deny you these rights or to ask you to surrender the rights.
-+These restrictions translate to certain responsibilities for you if you
-+distribute copies of the software, or if you modify it.
-+
-+ For example, if you distribute copies of such a program, whether
-+gratis or for a fee, you must give the recipients all the rights that
-+you have. You must make sure that they, too, receive or can get the
-+source code. And you must show them these terms so they know their
-+rights.
-+
-+ We protect your rights with two steps: (1) copyright the software, and
-+(2) offer you this license which gives you legal permission to copy,
-+distribute and/or modify the software.
-+
-+ Also, for each author's protection and ours, we want to make certain
-+that everyone understands that there is no warranty for this free
-+software. If the software is modified by someone else and passed on, we
-+want its recipients to know that what they have is not the original, so
-+that any problems introduced by others will not reflect on the original
-+authors' reputations.
-+
-+ Finally, any free program is threatened constantly by software
-+patents. We wish to avoid the danger that redistributors of a free
-+program will individually obtain patent licenses, in effect making the
-+program proprietary. To prevent this, we have made it clear that any
-+patent must be licensed for everyone's free use or not licensed at all.
-+
-+ The precise terms and conditions for copying, distribution and
-+modification follow.
-+
-+ GNU GENERAL PUBLIC LICENSE
-+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
-+
-+ 0. This License applies to any program or other work which contains
-+a notice placed by the copyright holder saying it may be distributed
-+under the terms of this General Public License. The "Program", below,
-+refers to any such program or work, and a "work based on the Program"
-+means either the Program or any derivative work under copyright law:
-+that is to say, a work containing the Program or a portion of it,
-+either verbatim or with modifications and/or translated into another
-+language. (Hereinafter, translation is included without limitation in
-+the term "modification".) Each licensee is addressed as "you".
-+
-+Activities other than copying, distribution and modification are not
-+covered by this License; they are outside its scope. The act of
-+running the Program is not restricted, and the output from the Program
-+is covered only if its contents constitute a work based on the
-+Program (independent of having been made by running the Program).
-+Whether that is true depends on what the Program does.
-+
-+ 1. You may copy and distribute verbatim copies of the Program's
-+source code as you receive it, in any medium, provided that you
-+conspicuously and appropriately publish on each copy an appropriate
-+copyright notice and disclaimer of warranty; keep intact all the
-+notices that refer to this License and to the absence of any warranty;
-+and give any other recipients of the Program a copy of this License
-+along with the Program.
-+
-+You may charge a fee for the physical act of transferring a copy, and
-+you may at your option offer warranty protection in exchange for a fee.
-+
-+ 2. You may modify your copy or copies of the Program or any portion
-+of it, thus forming a work based on the Program, and copy and
-+distribute such modifications or work under the terms of Section 1
-+above, provided that you also meet all of these conditions:
-+
-+ a) You must cause the modified files to carry prominent notices
-+ stating that you changed the files and the date of any change.
-+
-+ b) You must cause any work that you distribute or publish, that in
-+ whole or in part contains or is derived from the Program or any
-+ part thereof, to be licensed as a whole at no charge to all third
-+ parties under the terms of this License.
-+
-+ c) If the modified program normally reads commands interactively
-+ when run, you must cause it, when started running for such
-+ interactive use in the most ordinary way, to print or display an
-+ announcement including an appropriate copyright notice and a
-+ notice that there is no warranty (or else, saying that you provide
-+ a warranty) and that users may redistribute the program under
-+ these conditions, and telling the user how to view a copy of this
-+ License. (Exception: if the Program itself is interactive but
-+ does not normally print such an announcement, your work based on
-+ the Program is not required to print an announcement.)
-+
-+These requirements apply to the modified work as a whole. If
-+identifiable sections of that work are not derived from the Program,
-+and can be reasonably considered independent and separate works in
-+themselves, then this License, and its terms, do not apply to those
-+sections when you distribute them as separate works. But when you
-+distribute the same sections as part of a whole which is a work based
-+on the Program, the distribution of the whole must be on the terms of
-+this License, whose permissions for other licensees extend to the
-+entire whole, and thus to each and every part regardless of who wrote it.
-+
-+Thus, it is not the intent of this section to claim rights or contest
-+your rights to work written entirely by you; rather, the intent is to
-+exercise the right to control the distribution of derivative or
-+collective works based on the Program.
-+
-+In addition, mere aggregation of another work not based on the Program
-+with the Program (or with a work based on the Program) on a volume of
-+a storage or distribution medium does not bring the other work under
-+the scope of this License.
-+
-+ 3. You may copy and distribute the Program (or a work based on it,
-+under Section 2) in object code or executable form under the terms of
-+Sections 1 and 2 above provided that you also do one of the following:
-+
-+ a) Accompany it with the complete corresponding machine-readable
-+ source code, which must be distributed under the terms of Sections
-+ 1 and 2 above on a medium customarily used for software interchange; or,
-+
-+ b) Accompany it with a written offer, valid for at least three
-+ years, to give any third party, for a charge no more than your
-+ cost of physically performing source distribution, a complete
-+ machine-readable copy of the corresponding source code, to be
-+ distributed under the terms of Sections 1 and 2 above on a medium
-+ customarily used for software interchange; or,
-+
-+ c) Accompany it with the information you received as to the offer
-+ to distribute corresponding source code. (This alternative is
-+ allowed only for noncommercial distribution and only if you
-+ received the program in object code or executable form with such
-+ an offer, in accord with Subsection b above.)
-+
-+The source code for a work means the preferred form of the work for
-+making modifications to it. For an executable work, complete source
-+code means all the source code for all modules it contains, plus any
-+associated interface definition files, plus the scripts used to
-+control compilation and installation of the executable. However, as a
-+special exception, the source code distributed need not include
-+anything that is normally distributed (in either source or binary
-+form) with the major components (compiler, kernel, and so on) of the
-+operating system on which the executable runs, unless that component
-+itself accompanies the executable.
-+
-+If distribution of executable or object code is made by offering
-+access to copy from a designated place, then offering equivalent
-+access to copy the source code from the same place counts as
-+distribution of the source code, even though third parties are not
-+compelled to copy the source along with the object code.
-+
-+ 4. You may not copy, modify, sublicense, or distribute the Program
-+except as expressly provided under this License. Any attempt
-+otherwise to copy, modify, sublicense or distribute the Program is
-+void, and will automatically terminate your rights under this License.
-+However, parties who have received copies, or rights, from you under
-+this License will not have their licenses terminated so long as such
-+parties remain in full compliance.
-+
-+ 5. You are not required to accept this License, since you have not
-+signed it. However, nothing else grants you permission to modify or
-+distribute the Program or its derivative works. These actions are
-+prohibited by law if you do not accept this License. Therefore, by
-+modifying or distributing the Program (or any work based on the
-+Program), you indicate your acceptance of this License to do so, and
-+all its terms and conditions for copying, distributing or modifying
-+the Program or works based on it.
-+
-+ 6. Each time you redistribute the Program (or any work based on the
-+Program), the recipient automatically receives a license from the
-+original licensor to copy, distribute or modify the Program subject to
-+these terms and conditions. You may not impose any further
-+restrictions on the recipients' exercise of the rights granted herein.
-+You are not responsible for enforcing compliance by third parties to
-+this License.
-+
-+ 7. If, as a consequence of a court judgment or allegation of patent
-+infringement or for any other reason (not limited to patent issues),
-+conditions are imposed on you (whether by court order, agreement or
-+otherwise) that contradict the conditions of this License, they do not
-+excuse you from the conditions of this License. If you cannot
-+distribute so as to satisfy simultaneously your obligations under this
-+License and any other pertinent obligations, then as a consequence you
-+may not distribute the Program at all. For example, if a patent
-+license would not permit royalty-free redistribution of the Program by
-+all those who receive copies directly or indirectly through you, then
-+the only way you could satisfy both it and this License would be to
-+refrain entirely from distribution of the Program.
-+
-+If any portion of this section is held invalid or unenforceable under
-+any particular circumstance, the balance of the section is intended to
-+apply and the section as a whole is intended to apply in other
-+circumstances.
-+
-+It is not the purpose of this section to induce you to infringe any
-+patents or other property right claims or to contest validity of any
-+such claims; this section has the sole purpose of protecting the
-+integrity of the free software distribution system, which is
-+implemented by public license practices. Many people have made
-+generous contributions to the wide range of software distributed
-+through that system in reliance on consistent application of that
-+system; it is up to the author/donor to decide if he or she is willing
-+to distribute software through any other system and a licensee cannot
-+impose that choice.
-+
-+This section is intended to make thoroughly clear what is believed to
-+be a consequence of the rest of this License.
-+
-+ 8. If the distribution and/or use of the Program is restricted in
-+certain countries either by patents or by copyrighted interfaces, the
-+original copyright holder who places the Program under this License
-+may add an explicit geographical distribution limitation excluding
-+those countries, so that distribution is permitted only in or among
-+countries not thus excluded. In such case, this License incorporates
-+the limitation as if written in the body of this License.
-+
-+ 9. The Free Software Foundation may publish revised and/or new versions
-+of the General Public License from time to time. Such new versions will
-+be similar in spirit to the present version, but may differ in detail to
-+address new problems or concerns.
-+
-+Each version is given a distinguishing version number. If the Program
-+specifies a version number of this License which applies to it and "any
-+later version", you have the option of following the terms and conditions
-+either of that version or of any later version published by the Free
-+Software Foundation. If the Program does not specify a version number of
-+this License, you may choose any version ever published by the Free Software
-+Foundation.
-+
-+ 10. If you wish to incorporate parts of the Program into other free
-+programs whose distribution conditions are different, write to the author
-+to ask for permission. For software which is copyrighted by the Free
-+Software Foundation, write to the Free Software Foundation; we sometimes
-+make exceptions for this. Our decision will be guided by the two goals
-+of preserving the free status of all derivatives of our free software and
-+of promoting the sharing and reuse of software generally.
-+
-+ NO WARRANTY
-+
-+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
-+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
-+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
-+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
-+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
-+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
-+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
-+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
-+REPAIR OR CORRECTION.
-+
-+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
-+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
-+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
-+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
-+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
-+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
-+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
-+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
-+POSSIBILITY OF SUCH DAMAGES.
-+
-+ END OF TERMS AND CONDITIONS
-+
-+ How to Apply These Terms to Your New Programs
-+
-+ If you develop a new program, and you want it to be of the greatest
-+possible use to the public, the best way to achieve this is to make it
-+free software which everyone can redistribute and change under these terms.
-+
-+ To do so, attach the following notices to the program. It is safest
-+to attach them to the start of each source file to most effectively
-+convey the exclusion of warranty; and each file should have at least
-+the "copyright" line and a pointer to where the full notice is found.
-+
-+ <one line to give the program's name and a brief idea of what it does.>
-+ Copyright (C) <year> <name of author>
-+
-+ 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-+
-+
-+Also add information on how to contact you by electronic and paper mail.
-+
-+If the program is interactive, make it output a short notice like this
-+when it starts in an interactive mode:
-+
-+ Gnomovision version 69, Copyright (C) year name of author
-+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
-+ This is free software, and you are welcome to redistribute it
-+ under certain conditions; type `show c' for details.
-+
-+The hypothetical commands `show w' and `show c' should show the appropriate
-+parts of the General Public License. Of course, the commands you use may
-+be called something other than `show w' and `show c'; they could even be
-+mouse-clicks or menu items--whatever suits your program.
-+
-+You should also get your employer (if you work as a programmer) or your
-+school, if any, to sign a "copyright disclaimer" for the program, if
-+necessary. Here is a sample; alter the names:
-+
-+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
-+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
-+
-+ <signature of Ty Coon>, 1 April 1989
-+ Ty Coon, President of Vice
-+
-+This General Public License does not permit incorporating your program into
-+proprietary programs. If your program is a subroutine library, you may
-+consider it more useful to permit linking proprietary applications with the
-+library. If this is what you want to do, use the GNU Library General
-+Public License instead of this License.
-diff -uNr linux-org/drivers/char/nozomi/Makefile linux/drivers/char/nozomi/Makefile
---- linux-org/drivers/char/nozomi/Makefile 1970-01-01 01:00:00.000000000 +0100
-+++ linux/drivers/char/nozomi/Makefile 2006-02-06 15:30:07.379952504 +0100
-@@ -0,0 +1,25 @@
-+#
-+# Makefile for ACP Modem (Mwave).
-+#
-+# See the README file in this directory for more info. <paulsch@us.ibm.com>
-+#
-+# 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..
-+#
-+
-+# To compile in lots (~20 KiB) of run-time enablable printk()s for debugging:
-+#EXTRA_CFLAGS += -DMW_TRACE
-+
-+# To have the mwave driver disable other uarts if necessary
-+# EXTRA_CFLAGS += -DMWAVE_FUTZ_WITH_OTHER_DEVICES
-+
-+O_TARGET := noz.o
-+
-+obj-y := nozomi.o kfifo.o
-+obj-m := $(O_TARGET)
-+
-+include $(TOPDIR)/Rules.make
-diff -uNr linux-org/drivers/char/nozomi/README linux/drivers/char/nozomi/README
---- linux-org/drivers/char/nozomi/README 1970-01-01 01:00:00.000000000 +0100
-+++ linux/drivers/char/nozomi/README 2006-02-06 15:30:07.380952352 +0100
-@@ -0,0 +1,17 @@
-+To build this driver for your kernel, please check:
-+
-+For kernel 2.6
-+---------------
-+Check the Makefile and run 'make'.
-+
-+For kernel 2.4
-+----------
-+make HW=PC_24
-+
-+If you have troubles:
-+1) Have proper kernel headers/source as your running kernel.
-+2) Make sure this variable in Makefile is correct KERNELDIR = -I/path/to/kernel
-+3) If the /dev/noz[0-3] will not be created automatically, do:
-+mknod /dev/noz0 c 241 0; mknod /dev/noz1 c 241 1;
-+mknod /dev/noz2 c 241 2; mknod /dev/noz3 c 241 3
-+
-diff -uNr linux-org/drivers/char/nozomi/TODO linux/drivers/char/nozomi/TODO
---- linux-org/drivers/char/nozomi/TODO 1970-01-01 01:00:00.000000000 +0100
-+++ linux/drivers/char/nozomi/TODO 2006-02-06 15:30:07.361955240 +0100
-@@ -0,0 +1,6 @@
-+* When having a noz* open and rmmod module or removing card,
-+ the driver core dumps.
-+
-+* Does not yet support multiple cards.
-+
-+* Add a helpful description.
-diff -uNr linux-org/drivers/char/nozomi/kfifo.c linux/drivers/char/nozomi/kfifo.c
---- linux-org/drivers/char/nozomi/kfifo.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux/drivers/char/nozomi/kfifo.c 2006-02-06 15:30:07.361955240 +0100
-@@ -0,0 +1,189 @@
-+/*
-+ * A simple kernel FIFO implementation.
-+ *
-+ * Copyright (C) 2004 Stelian Pop <stelian@popies.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.
-+ *
-+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
-+ *
-+ */
-+
-+#include <linux/kernel.h>
-+#include <linux/module.h>
-+#include <linux/slab.h>
-+#include <asm/uaccess.h>
-+#include "kfifo.h"
-+
-+
-+/**
-+ * kfifo_init - allocates a new FIFO using a preallocated buffer
-+ * @buffer: the preallocated buffer to be used.
-+ * @size: the size of the internal buffer, this have to be a power of 2.
-+ * @gfp_mask: get_free_pages mask, passed to kmalloc()
-+ * @lock: the lock to be used to protect the fifo buffer
-+ *
-+ * Do NOT pass the kfifo to kfifo_free() after use ! Simply free the
-+ * struct kfifo with kfree().
-+ */
-+struct kfifo *kfifo_init(unsigned char *buffer, unsigned int size,
-+ unsigned int gfp_mask, void *lock)
-+{
-+ struct kfifo *fifo;
-+
-+ /* size must be a power of 2 */
-+ BUG_ON(size & (size - 1));
-+
-+ fifo = kmalloc(sizeof(struct kfifo), gfp_mask);
-+ if (!fifo)
-+ return ERR_PTR(-ENOMEM);
-+
-+ fifo->buffer = buffer;
-+ fifo->size = size;
-+ fifo->in = fifo->out = 0;
-+
-+ return fifo;
-+}
-+
-+/**
-+ * kfifo_alloc - allocates a new FIFO and its internal buffer
-+ * @size: the size of the internal buffer to be allocated.
-+ * @gfp_mask: get_free_pages mask, passed to kmalloc()
-+ * @lock: the lock to be used to protect the fifo buffer
-+ *
-+ * The size will be rounded-up to a power of 2.
-+ */
-+struct kfifo *kfifo_alloc(unsigned int size, unsigned int gfp_mask, void *lock)
-+{
-+ unsigned char *buffer;
-+ struct kfifo *ret;
-+
-+ /*
-+ * round up to the next power of 2, since our 'let the indices
-+ * wrap' tachnique works only in this case.
-+ */
-+ if (size & (size - 1)) {
-+ BUG_ON(size > 0x80000000);
-+ printk("Do not support no power of two!\n");
-+ //size = roundup_pow_of_two(size);
-+ }
-+
-+ buffer = kmalloc(size, gfp_mask);
-+ if (!buffer)
-+ return ERR_PTR(-ENOMEM);
-+
-+ ret = kfifo_init(buffer, size, gfp_mask, lock);
-+
-+ if (IS_ERR(ret))
-+ kfree(buffer);
-+
-+ return ret;
-+}
-+
-+/**
-+ * kfifo_free - frees the FIFO
-+ * @fifo: the fifo to be freed.
-+ */
-+void kfifo_free(struct kfifo *fifo)
-+{
-+ kfree(fifo->buffer);
-+ kfree(fifo);
-+}
-+
-+/**
-+ * __kfifo_put - puts some data into the FIFO, no locking version
-+ * @fifo: the fifo to be used.
-+ * @buffer: the data to be added.
-+ * @len: the length of the data to be added.
-+ *
-+ * This function copies at most 'len' bytes from the 'buffer' into
-+ * the FIFO depending on the free space, and returns the number of
-+ * bytes copied.
-+ *
-+ * Note that with only one concurrent reader and one concurrent
-+ * writer, you don't need extra locking to use these functions.
-+ */
-+unsigned int __kfifo_put(struct kfifo *fifo,
-+ unsigned char *buffer, unsigned int len)
-+{
-+ unsigned int l;
-+
-+ len = min(len, fifo->size - fifo->in + fifo->out);
-+
-+ /* first put the data starting from fifo->in to buffer end */
-+ l = min(len, fifo->size - (fifo->in & (fifo->size - 1)));
-+ memcpy(fifo->buffer + (fifo->in & (fifo->size - 1)), buffer, l);
-+
-+ /* then put the rest (if any) at the beginning of the buffer */
-+ memcpy(fifo->buffer, buffer + l, len - l);
-+
-+ fifo->in += len;
-+
-+ return len;
-+}
-+
-+/** __kfifio_put_user works like __kfifo_put, but copies data from
-+ * user space.
-+ */
-+
-+unsigned int __kfifo_put_user(struct kfifo *fifo,
-+ unsigned char *buffer, unsigned int len)
-+{
-+ unsigned int l;
-+
-+ len = min(len, fifo->size - fifo->in + fifo->out);
-+
-+ /* first put the data starting from fifo->in to buffer end */
-+ l = min(len, fifo->size - (fifo->in & (fifo->size - 1)));
-+ copy_from_user(fifo->buffer + (fifo->in & (fifo->size - 1)), buffer, l);
-+
-+ /* then put the rest (if any) at the beginning of the buffer */
-+ copy_from_user(fifo->buffer, buffer + l, len - l);
-+
-+ fifo->in += len;
-+
-+ return len;
-+}
-+
-+
-+
-+/**
-+ * __kfifo_get - gets some data from the FIFO, no locking version
-+ * @fifo: the fifo to be used.
-+ * @buffer: where the data must be copied.
-+ * @len: the size of the destination buffer.
-+ *
-+ * This function copies at most 'len' bytes from the FIFO into the
-+ * 'buffer' and returns the number of copied bytes.
-+ *
-+ * Note that with only one concurrent reader and one concurrent
-+ * writer, you don't need extra locking to use these functions.
-+ */
-+unsigned int __kfifo_get(struct kfifo *fifo,
-+ unsigned char *buffer, unsigned int len)
-+{
-+ unsigned int l;
-+
-+ len = min(len, fifo->in - fifo->out);
-+
-+ /* first get the data from fifo->out until the end of the buffer */
-+ l = min(len, fifo->size - (fifo->out & (fifo->size - 1)));
-+ memcpy(buffer, fifo->buffer + (fifo->out & (fifo->size - 1)), l);
-+
-+ /* then get the rest (if any) from the beginning of the buffer */
-+ memcpy(buffer + l, fifo->buffer, len - l);
-+
-+ fifo->out += len;
-+
-+ return len;
-+}
-diff -uNr linux-org/drivers/char/nozomi/kfifo.h linux/drivers/char/nozomi/kfifo.h
---- linux-org/drivers/char/nozomi/kfifo.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux/drivers/char/nozomi/kfifo.h 2006-02-06 15:30:07.361955240 +0100
-@@ -0,0 +1,67 @@
-+/*
-+ * A simple kernel FIFO implementation.
-+ *
-+ * Copyright (C) 2004 Stelian Pop <stelian@popies.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.
-+ *
-+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
-+ *
-+ */
-+#ifndef _LINUX_KFIFO_H
-+#define _LINUX_KFIFO_H
-+
-+#ifdef __KERNEL__
-+
-+#include <linux/version.h>
-+
-+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,0)
-+#warning "Don't include this header in 2.6, use header supplied with kernel"
-+#endif
-+
-+struct kfifo {
-+ unsigned char *buffer; /* the buffer holding the data */
-+ unsigned int size; /* the size of the allocated buffer */
-+ unsigned int in; /* data is added at offset (in % size) */
-+ unsigned int out; /* data is extracted from off. (out % size) */
-+};
-+
-+extern struct kfifo *kfifo_init(unsigned char *buffer, unsigned int size, unsigned int gfp_mask, void *lock);
-+extern struct kfifo *kfifo_alloc(unsigned int size, unsigned int gfp_mask, void *lock);
-+extern void kfifo_free(struct kfifo *fifo);
-+extern unsigned int __kfifo_put(struct kfifo *fifo, unsigned char *buffer, unsigned int len);
-+extern unsigned int __kfifo_put_user(struct kfifo *fifo, unsigned char *buffer, unsigned int len);
-+extern unsigned int __kfifo_get(struct kfifo *fifo, unsigned char *buffer, unsigned int len);
-+
-+/**
-+ * __kfifo_reset - removes the entire FIFO contents, no locking version
-+ * @fifo: the fifo to be emptied.
-+ */
-+static inline void __kfifo_reset(struct kfifo *fifo)
-+{
-+ fifo->in = fifo->out = 0;
-+}
-+
-+/**
-+ * __kfifo_len - returns the number of bytes available in the FIFO, no locking version
-+ * @fifo: the fifo to be used.
-+ */
-+static inline unsigned int __kfifo_len(struct kfifo *fifo)
-+{
-+ return fifo->in - fifo->out;
-+}
-+
-+#else
-+#warning "don't include kernel headers in userspace"
-+#endif /* __KERNEL__ */
-+#endif
-diff -uNr linux-org/drivers/char/nozomi/nozomi.c linux/drivers/char/nozomi/nozomi.c
---- linux-org/drivers/char/nozomi/nozomi.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux/drivers/char/nozomi/nozomi.c 2006-02-06 15:30:07.379952504 +0100
-@@ -0,0 +1,2238 @@
-+
-+/* nozomi.c -- HSDPA driver Broadband Wireless Data Card - Globe Trotter
-+ *
-+ * Written by: Ulf Jakobsson,
-+ * Jan Åkerfeldt,
-+ * Stefan Thomasson,
-+ *
-+ * Maintained by: Paul Hardwick, p.hardwick@option.com
-+ *
-+ * Source has been ported from an implementation made by Filip Aben, f.aben@option.com
-+ *
-+ * --------------------------------------------------------------------------
-+
-+ Copyright (c) 2005 Option Wireless Sweden AB
-+ All rights Reserved.
-+
-+ 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-+
-+ * --------------------------------------------------------------------------
-+ */
-+
-+/* CHANGELOG
-+ *
-+ * See CHANGELOG in this package
-+ */
-+
-+/* TODO
-+ *
-+ * See TODO file in this package
-+ */
-+
-+
-+/*
-+ * TODO2 fix the send_reset_token() routine not to use the fixed start address
-+ */
-+
-+
-+
-+#include <linux/version.h>
-+
-+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,0)
-+#define KERNEL_2_6
-+#elif LINUX_VERSION_CODE > KERNEL_VERSION(2,4,0)
-+#define KERNEL_2_4
-+#endif
-+
-+#include <linux/module.h>
-+#include <linux/pci.h>
-+#include <linux/ioport.h>
-+#include <linux/tty.h>
-+#include <linux/tty_driver.h>
-+#include <linux/tty_flip.h>
-+#include <linux/serial.h>
-+#include <linux/interrupt.h>
-+#include <linux/kmod.h>
-+#include <linux/proc_fs.h>
-+#include <asm/uaccess.h>
-+
-+#include <linux/init.h>
-+
-+#define VERSION_STRING DRIVER_DESC " (build date: " __DATE__ " " __TIME__ ")"
-+
-+#ifdef KERNEL_2_6
-+#include <linux/kfifo.h>
-+#else
-+#include "kfifo.h"
-+#endif
-+
-+#ifdef KERNEL_2_4
-+#ifndef IRQ_NONE
-+#define IRQ_NONE
-+#endif
-+#ifndef IRQ_HANDLED
-+#define IRQ_HANDLED
-+typedef void irqreturn_t;
-+#endif
-+#endif
-+
-+#ifndef CONFIG_PCI
-+#error "This driver needs PCI support to be available"
-+#endif
-+
-+/* Macros definitions */
-+
-+/* Enable this to have a lot of debug printouts */
-+/*#define NOZOMI_DEBUG */
-+
-+/* Default debug printout level */
-+#define NOZOMI_DEBUG_LEVEL 0xffff
-+
-+#define P_BUF_SIZE 128
-+#define NFO( _err_flag_, args...) \
-+ do{ \
-+ char t_m_p_[P_BUF_SIZE]; \
-+ snprintf(t_m_p_, sizeof(t_m_p_), ##args); \
-+ printk( _err_flag_ "[%d] %s(): %s\n", __LINE__, __FUNCTION__, t_m_p_); \
-+} while(0)
-+
-+#define INFO(args...) NFO(KERN_INFO, ##args)
-+#define ERR(args...) NFO( KERN_ERR, ##args)
-+
-+#define D1(args...) D_(0x01, ##args)
-+#define D2(args...) D_(0x02, ##args)
-+#define D3(args...) D_(0x04, ##args)
-+#define D4(args...) D_(0x08, ##args)
-+#define D5(args...) D_(0x10, ##args)
-+#define D6(args...) D_(0x20, ##args)
-+#define D7(args...) D_(0x40, ##args)
-+#define D8(args...) D_(0x80, ##args)
-+
-+
-+#ifdef NOZOMI_DEBUG
-+#define D_(lvl, args...) D(lvl, ##args)
-+ /* Do we need this settable at runtime? */
-+static int nzdebug = NOZOMI_DEBUG_LEVEL;
-+
-+#define D(lvl, args...) do{if(lvl & nzdebug) NFO(KERN_INFO, ##args );}while(0)
-+#define D_(lvl, args...) D(lvl, ##args)
-+
-+/* These printouts are always printed */
-+
-+#else
-+ static const int nzdebug = 0;
-+#define D_(lvl, args...)
-+#endif
-+
-+/* TODO: rewrite to optimize macros... */
-+#define SET_FCR(value__) \
-+ do { \
-+ writew((value__), (void*) (dc->REG_FCR )); \
-+} while(0)
-+
-+#define SET_IER(value__, mask__) \
-+ do { \
-+ dc->ier_last_written = (dc->ier_last_written & ~mask__) | (value__ & mask__ );\
-+ writew( dc->ier_last_written, (void*) (dc->REG_IER));\
-+} while(0)
-+
-+#define GET_IER(read_val__) \
-+ do { \
-+ (read_val__) = readw((void*) (dc->REG_IER));\
-+} while(0)
-+
-+#define GET_IIR(read_val__) \
-+ do { \
-+ (read_val__) = readw((void*) (dc->REG_IIR));\
-+} while(0)
-+
-+#define GET_MEM(value__, addr__, length__) \
-+ do { \
-+ read_mem32( (u32*) (value__), (u32) (addr__), (length__));\
-+} while(0)
-+
-+#define GET_MEM_BUF(value__, addr__, length__) \
-+ do { \
-+ read_mem32_buf( (u32*) (value__), (u32) (addr__), (length__));\
-+} while(0)
-+
-+#define SET_MEM(addr__, value__, length__) \
-+ do { \
-+ write_mem32( (addr__), (u32*) (value__), (length__));\
-+} while(0)
-+
-+#define SET_MEM_BUF(addr__, value__, length__) \
-+ do { \
-+ write_mem32_buf( (addr__), (u32*) (value__), (length__));\
-+} while(0)
-+
-+
-+#define TMP_BUF_MAX 256
-+
-+#define DUMP(buf__,len__) \
-+ do { \
-+ char tbuf[TMP_BUF_MAX]={0};\
-+ if (len__>1) {\
-+ snprintf(tbuf, len__ > TMP_BUF_MAX ? TMP_BUF_MAX : len__, "%s",buf__);\
-+ if(tbuf[len__-2] == '\r') {\
-+ tbuf[len__-2] = 'r';\
-+ }\
-+ D1( "SENDING: '%s' (%d+n)", tbuf, len__);\
-+ } else {\
-+ D1( "SENDING: '%s' (%d)", tbuf, len__);\
-+ }\
-+} while(0)
-+
-+#define RELEVANT_IFLAG(iflag) ((iflag) & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK))
-+
-+
-+/* Defines */
-+#define NOZOMI_NAME "nozomi"
-+#define NOZOMI_NAME_TTY "nozomi_tty"
-+#define DRIVER_DESC "Nozomi driver"
-+
-+#define NTTY_TTY_MAJOR 241
-+#define NTTY_TTY_MINORS MAX_PORT
-+#define NTTY_FIFO_BUFFER_SIZE 8192
-+
-+/* Must be power of 2 */
-+#define FIFO_BUFFER_SIZE_UL 8192
-+
-+/* Size of tmp send buffer to card */
-+#define SEND_BUF_MAX 1024
-+#define RECEIVE_BUF_MAX 4
-+
-+/* Our fake UART values */
-+#define MCR_DTR 0x01
-+#define MCR_RTS 0x02
-+#define MCR_LOOP 0x04
-+#define MSR_CTS 0x08
-+#define MSR_CD 0x10
-+#define MSR_RI 0x20
-+#define MSR_DSR 0x40
-+
-+/* Define all types of vendors and devices to support */
-+#define VENDOR1 0x1931 /* Vendor Option */
-+#define DEVICE1 0x000c /* HSDPA card */
-+
-+#define R_IIR 0x0000 /* Interrupt Identity Register */
-+#define R_FCR 0x0000 /* Flow Control Register */
-+#define R_IER 0x0004 /* Interrupt Enable Register */
-+
-+#define CONFIG_MAGIC 0xEFEFFEFE
-+#define TOGGLE_VALID 0x0000
-+
-+/* Definition of interrupt tokens */
-+#define MDM_DL1 0x0001
-+#define MDM_UL1 0x0002
-+#define MDM_DL2 0x0004
-+#define MDM_UL2 0x0008
-+#define DIAG_DL1 0x0010
-+#define DIAG_DL2 0x0020
-+#define DIAG_UL 0x0040
-+#define APP1_DL 0x0080
-+#define APP1_UL 0x0100
-+#define APP2_DL 0x0200
-+#define APP2_UL 0x0400
-+#define CTRL_DL 0x0800
-+#define CTRL_UL 0x1000
-+#define RESET 0x8000
-+
-+#define MDM_DL (MDM_DL1 | MDM_DL2)
-+#define MDM_UL (MDM_UL1 | MDM_UL2)
-+#define DIAG_DL (DIAG_DL1 | DIAG_DL2)
-+
-+/* modem signal definition */
-+#define CTRL_DSR 0x0001
-+#define CTRL_DCD 0x0002
-+#define CTRL_RI 0x0004
-+#define CTRL_CTS 0x0008
-+
-+#define CTRL_DTR 0x0001
-+#define CTRL_RTS 0x0002
-+
-+#define MAX_PORT 4
-+#define NOZOMI_MAX_PORTS 5
-+
-+/* Type definitions */
-+
-+/* There are two types of nozomi cards, one with 2048 memory and with 8192 memory */
-+typedef enum {
-+ F32_2 = 2048, /* Has 512 bytes downlink and uplink * 2 -> 2048 */
-+ F32_8 = 9192, /* Has 3072 bytes downlink and 1024 bytes uplink * 2 -> 8192 */
-+} card_type_t;
-+
-+/* Two different toggle channels exist */
-+typedef enum {
-+ CH_A=0,
-+ CH_B=1,
-+} channel_t;
-+
-+/* Port definition for the card regarding flow control */
-+typedef enum {
-+ CTRL_CMD = 0x00,
-+ CTRL_MDM = 0x01,
-+ CTRL_DIAG = 0x02,
-+ CTRL_APP1 = 0x03,
-+ CTRL_APP2 = 0x04,
-+ CTRL_ERROR = -1,
-+} ctrl_port_t;
-+
-+/* Ports that the nozomi has */
-+typedef enum {
-+ PORT_MDM = 0,
-+ PORT_DIAG= 1,
-+ PORT_APP1= 2,
-+ PORT_APP2= 3,
-+ PORT_CTRL= 4,
-+ PORT_ERROR=-1,
-+} port_type_t;
-+
-+#ifdef __ARMEB__
-+/* Big endian */
-+
-+typedef struct {
-+ unsigned enabled : 5; /* Toggle fields are valid if enabled is 0, else A-channels
-+ must always be used. */
-+ unsigned diag_dl : 1;
-+ unsigned mdm_dl : 1;
-+ unsigned mdm_ul : 1;
-+} __attribute__ ((packed)) toggles_t;
-+
-+/* Configuration table to read at startup of card */
-+/* Is for now only needed during initialization phase */
-+typedef struct {
-+ u32 signature;
-+ u16 product_information;
-+ u16 version;
-+ u8 pad3[3];
-+ toggles_t toggle;
-+ u8 pad1[4];
-+ u16 dl_mdm_len1; /* If this is 64, it can hold 60 bytes + 4 that is length field */
-+ u16 dl_start;
-+
-+ u16 dl_diag_len1;
-+ u16 dl_mdm_len2; /* If this is 64, it can hold 60 bytes + 4 that is length field */
-+ u16 dl_app1_len;
-+
-+ u16 dl_diag_len2;
-+ u16 dl_ctrl_len;
-+ u16 dl_app2_len;
-+ u8 pad2[16];
-+ u16 ul_mdm_len1;
-+ u16 ul_start;
-+ u16 ul_diag_len;
-+ u16 ul_mdm_len2;
-+ u16 ul_app1_len;
-+ u16 ul_app2_len;
-+ u16 ul_ctrl_len;
-+} __attribute__((packed)) config_table_t;
-+
-+/* This stores all control downlink flags */
-+typedef struct {
-+ u8 port;
-+ unsigned reserved : 4;
-+ unsigned CTS : 1;
-+ unsigned RI : 1;
-+ unsigned DCD : 1;
-+ unsigned DSR : 1;
-+} __attribute__ ((packed)) ctrl_dl_t;
-+
-+/* This stores all control uplink flags */
-+typedef struct {
-+ u8 port;
-+ unsigned reserved : 6;
-+ unsigned RTS : 1;
-+ unsigned DTR : 1;
-+} __attribute__ ((packed)) ctrl_ul_t;
-+
-+#else
-+/* Little endian */
-+
-+/* This represents the toggle information */
-+typedef struct {
-+ unsigned mdm_ul : 1;
-+ unsigned mdm_dl : 1;
-+ unsigned diag_dl : 1;
-+ unsigned enabled : 5; /* Toggle fields are valid if enabled is 0, else A-channels
-+ must always be used. */
-+} __attribute__ ((packed)) toggles_t;
-+
-+/* Configuration table to read at startup of card */
-+typedef struct {
-+ u32 signature;
-+ u16 version;
-+ u16 product_information;
-+ toggles_t toggle;
-+ u8 pad1[7];
-+ u16 dl_start;
-+ u16 dl_mdm_len1; /* If this is 64, it can hold 60 bytes + 4 that is length field */
-+ u16 dl_mdm_len2;
-+ u16 dl_diag_len1;
-+ u16 dl_diag_len2;
-+ u16 dl_app1_len;
-+ u16 dl_app2_len;
-+ u16 dl_ctrl_len;
-+ u8 pad2[16];
-+ u16 ul_start;
-+ u16 ul_mdm_len2;
-+ u16 ul_mdm_len1;
-+ u16 ul_diag_len;
-+ u16 ul_app1_len;
-+ u16 ul_app2_len;
-+ u16 ul_ctrl_len;
-+} __attribute__((packed)) config_table_t;
-+
-+/* This stores all control downlink flags */
-+typedef struct {
-+ unsigned DSR : 1;
-+ unsigned DCD : 1;
-+ unsigned RI : 1;
-+ unsigned CTS : 1;
-+ unsigned reserverd : 4;
-+ u8 port;
-+} __attribute__ ((packed)) ctrl_dl_t;
-+
-+/* This stores all control uplink flags */
-+typedef struct {
-+ unsigned DTR : 1;
-+ unsigned RTS : 1;
-+ unsigned reserved : 6;
-+ u8 port;
-+} __attribute__ ((packed)) ctrl_ul_t;
-+#endif
-+
-+/* This holds all information that is needed regarding a port */
-+typedef struct {
-+ u8 update_flow_control;
-+ ctrl_ul_t ctrl_ul;
-+ ctrl_dl_t ctrl_dl;
-+ struct kfifo *fifo_ul;
-+ u32 dl_addr[2];
-+ u32 dl_size[2];
-+ u8 toggle_dl;
-+ u32 ul_addr[2];
-+ u32 ul_size[2];
-+ u8 toggle_ul;
-+ u16 token_dl;
-+
-+ struct tty_struct *tty;
-+ int tty_open_count;
-+ struct semaphore tty_sem;
-+ wait_queue_head_t tty_wait;
-+ struct async_icount tty_icount;
-+ int tty_index;
-+ u32 rx_data, tx_data;
-+ u8 tty_dont_flip;
-+
-+} port_t;
-+
-+/* Private data one for each card in the system */
-+typedef struct {
-+ u32 base_addr;
-+ u8 closing;
-+
-+ /* Register addresses */
-+ u32 REG_IIR;
-+ u32 REG_FCR;
-+ u32 REG_IER;
-+
-+ volatile u16 ier_last_written;
-+ card_type_t card_type;
-+ config_table_t config_table; /* Configuration table */
-+ struct pci_dev *pdev;
-+ port_t port[NOZOMI_MAX_PORTS];
-+ u8 *send_buf;
-+
-+ struct tty_driver tty_driver;
-+
-+#ifdef KERNEL_2_4
-+ struct tty_struct *tty_table[NTTY_TTY_MINORS];
-+ struct tq_struct tty_flip_queue;
-+ s32 tty_refcount;
-+#endif
-+#ifdef KERNEL_2_6
-+ struct workqueue_struct *tty_flip_wq;
-+ struct work_struct tty_flip_wq_struct;
-+#endif
-+
-+ struct termios *tty_termios[NTTY_TTY_MINORS];
-+ struct termios *tty_termios_locked[NTTY_TTY_MINORS];
-+ spinlock_t spin_mutex;
-+
-+ u32 open_ttys;
-+ struct proc_dir_entry *proc_entry;
-+
-+} dc_t;
-+
-+/* This is a data packet that is read or written to/from card */
-+typedef struct {
-+ u32 size; /* size is the length of the data buffer */
-+ u8 *data;
-+} __attribute__ ((packed)) buf_t;
-+
-+/* Function declarations */
-+static int ntty_tty_init(dc_t *dc);
-+
-+static void tty_flip_queue_function(void *tmp_dc);
-+
-+/* Global variables */
-+static struct pci_device_id nozomi_pci_tbl[] __devinitdata = {
-+ {VENDOR1, DEVICE1},
-+ {0, }
-+};
-+
-+/* Used to store interrupt variables */
-+typedef struct {
-+ volatile u16 read_iir; /* Holds current interrupt tokens */
-+} irq_t;
-+
-+MODULE_DEVICE_TABLE(pci, nozomi_pci_tbl);
-+
-+/* Representing the pci device of interest */
-+static int cards_found = 0;
-+static int cards_initialized = 0;
-+dc_t* my_dev = NULL;
-+struct pci_dev *my_pdev = NULL;
-+irq_t my_irq;
-+
-+#define CARD_CHECK(rval) { \
-+ if (cards_found == 0 || cards_found != cards_initialized) { \
-+ ERR("Operation requested on uninitialized nozomi card."); \
-+ return rval; \
-+ } }
-+
-+
-+static inline dc_t* get_dc_by_pdev(struct pci_dev* pdev) {
-+ return my_dev;
-+}
-+
-+static inline dc_t* get_dc_by_index(s32 index ) {
-+ return my_dev;
-+}
-+
-+static inline s32 get_index(struct tty_struct *tty) {
-+#ifdef KERNEL_2_6
-+ return tty->index;
-+#else
-+ return MINOR(tty->device) - tty->driver.minor_start;
-+#endif
-+}
-+
-+static inline port_t* get_port_by_tty(struct tty_struct *tty) {
-+ return &my_dev->port[ get_index(tty) ];
-+}
-+
-+static inline dc_t* get_dc_by_tty(struct tty_struct *tty ) {
-+ return my_dev;
-+}
-+
-+
-+/* TODO: */
-+/* -Optimize */
-+/* -Rewrite cleaner */
-+static void read_mem32(u32 *buf, u32 mem_addr_start, u32 size_bytes) {
-+ u32 i = 0;
-+ u32* ptr = (u32*) mem_addr_start;
-+ u16* buf16;
-+
-+ /* 2 bytes */
-+ if (size_bytes == 2) {
-+ buf16 = (u16*) buf;
-+ *buf16 = readw( ptr );
-+ return;
-+ }
-+
-+ while (i < size_bytes) {
-+ if ( size_bytes - i == 2) {
-+ /* Handle 2 bytes in the end */
-+ buf16 = (u16*) buf;
-+ *(buf16) = readw( ptr );
-+ i+=2;
-+ } else {
-+ /* Read 4 bytes */
-+ *(buf) = readl( ptr );
-+ i+=4;
-+ }
-+ buf++; ptr++;
-+ }
-+}
-+
-+/* TODO: */
-+/* - Rewrite cleaner */
-+/* - merge with read_mem32() */
-+static void read_mem32_buf(u32 *buf, u32 mem_addr_start, u32 size_bytes) {
-+#ifdef __ARMEB__
-+ u32 i = 0;
-+ u32* ptr = (u32*) mem_addr_start;
-+ u16* buf16;
-+
-+ /* 2 bytes */
-+ if (size_bytes == 2) {
-+ buf16 = (u16*) buf;
-+ *buf16 = __le16_to_cpu( readw( ptr ));
-+ return;
-+ }
-+
-+ while (i < size_bytes) {
-+ if ( size_bytes - i == 2) {
-+ /* Handle 2 bytes in the end */
-+ buf16 = (u16*) buf;
-+ *(buf16) = __le16_to_cpu( readw( ptr ));
-+ i+=2;
-+ } else {
-+ /* Read 4 bytes */
-+ *(buf) = __le32_to_cpu( readl( ptr ));
-+ i+=4;
-+ }
-+ buf++; ptr++;
-+ }
-+#else
-+ read_mem32(buf, mem_addr_start, size_bytes);
-+#endif
-+}
-+
-+/* TODO: */
-+/* -Optimize */
-+/* -Rewrite cleaner */
-+static u32 write_mem32(u32 mem_addr_start, u32 *buf, u32 size_bytes) {
-+ u32 i = 0;
-+ u32* ptr = (u32*) mem_addr_start;
-+ u16* buf16;
-+
-+ /* 2 bytes */
-+ if (size_bytes == 2) {
-+ buf16 = (u16*) buf;
-+ writew( *buf16, ptr);
-+ return 2;
-+ }
-+
-+ while (i < size_bytes) {
-+ if ( size_bytes - i == 2) {
-+ /* 2 bytes */
-+ buf16 = (u16*) buf;
-+ writew( *buf16, ptr);
-+ i+=2;
-+ } else {
-+ /* 4 bytes */
-+ writel( *buf, ptr );
-+ i += 4;
-+ }
-+ buf++; ptr++;
-+ }
-+ return size_bytes;
-+}
-+
-+/* Todo: */
-+/* - Merge with write_mem32() */
-+static u32 write_mem32_buf(u32 mem_addr_start, u32 *buf, u32 size_bytes) {
-+#ifdef __ARMEB__
-+ u32 i = 0;
-+ u32* ptr = (u32*) mem_addr_start;
-+ u16* buf16;
-+
-+ /* 2 bytes */
-+ if (size_bytes == 2) {
-+ buf16 = (u16*) buf;
-+ writew( __le16_to_cpu(*buf16), ptr);
-+ return 2;
-+ }
-+
-+ while (i < size_bytes) {
-+ if ( size_bytes - i == 2) {
-+ /* 2 bytes */
-+ buf16 = (u16*) buf;
-+ writew( __le16_to_cpu(*buf16), ptr);
-+ i+=2;
-+ } else {
-+ /* 4 bytes */
-+ writel( __cpu_to_le32( *buf ), ptr );
-+ i += 4;
-+ }
-+ buf++; ptr++;
-+ }
-+ return size_bytes;
-+#else
-+ return write_mem32(mem_addr_start, buf, size_bytes);
-+#endif
-+}
-+
-+/* Setup pointers to different channels and also setup buffer sizes. */
-+static void setup_memory(dc_t *dc) {
-+
-+ u32 offset = dc->base_addr + dc->config_table.dl_start;
-+ /* The length reported is including the length field of 4 bytes, hence subtract with 4. */
-+ u16 buff_offset = 4;
-+
-+ /* Modem port dl configuration */
-+ dc->port[PORT_MDM].dl_addr[CH_A] = offset;
-+ dc->port[PORT_MDM].dl_addr[CH_B] = (offset += dc->config_table.dl_mdm_len1);
-+ dc->port[PORT_MDM].dl_size[CH_A] = dc->config_table.dl_mdm_len1 - buff_offset;
-+ dc->port[PORT_MDM].dl_size[CH_B] = dc->config_table.dl_mdm_len2 - buff_offset;
-+
-+ /* Diag port dl configuration */
-+ dc->port[PORT_DIAG].dl_addr[CH_A] = (offset += dc->config_table.dl_mdm_len2);
-+ dc->port[PORT_DIAG].dl_size[CH_A] = dc->config_table.dl_diag_len1 - buff_offset;
-+ dc->port[PORT_DIAG].dl_addr[CH_B] = (offset += dc->config_table.dl_diag_len1);
-+ dc->port[PORT_DIAG].dl_size[CH_B] = dc->config_table.dl_diag_len2 - buff_offset;
-+
-+ /* App1 port dl configuration */
-+ dc->port[PORT_APP1].dl_addr[CH_A] = (offset += dc->config_table.dl_diag_len2);
-+ dc->port[PORT_APP1].dl_size[CH_A] = dc->config_table.dl_app1_len - buff_offset;
-+
-+ /* App2 port dl configuration */
-+ dc->port[PORT_APP2].dl_addr[CH_A] = (offset += dc->config_table.dl_app1_len);
-+ dc->port[PORT_APP2].dl_size[CH_A] = dc->config_table.dl_app2_len - buff_offset;
-+
-+ /* Ctrl dl configuration */
-+ dc->port[PORT_CTRL].dl_addr[CH_A] = (offset += dc->config_table.dl_app2_len);
-+ dc->port[PORT_CTRL].dl_size[CH_A] = dc->config_table.dl_ctrl_len - buff_offset;
-+
-+
-+ /* Modem Port ul configuration */
-+ dc->port[PORT_MDM].ul_addr[CH_A] = (offset = dc->base_addr + dc->config_table.ul_start);
-+ dc->port[PORT_MDM].ul_size[CH_A] = dc->config_table.ul_mdm_len1 - buff_offset;
-+ dc->port[PORT_MDM].ul_addr[CH_B] = (offset += dc->config_table.ul_mdm_len1);
-+ dc->port[PORT_MDM].ul_size[CH_B] = dc->config_table.ul_mdm_len2 - buff_offset;
-+
-+ /* Diag port ul configuration */
-+ dc->port[PORT_DIAG].ul_addr[CH_A] = (offset += dc->config_table.ul_mdm_len2);
-+ dc->port[PORT_DIAG].ul_size[CH_A] = dc->config_table.ul_diag_len - buff_offset;
-+
-+ /* App1 port ul configuration */
-+ dc->port[PORT_APP1].ul_addr[CH_A] = (offset += dc->config_table.ul_diag_len);
-+ dc->port[PORT_APP1].ul_size[CH_A] = dc->config_table.ul_app1_len - buff_offset;
-+
-+ /* App2 port ul configuration */
-+ dc->port[PORT_APP2].ul_addr[CH_A] = (offset += dc->config_table.ul_app1_len);
-+ dc->port[PORT_APP2].ul_size[CH_A] = dc->config_table.ul_app2_len - buff_offset;
-+
-+ /* Ctrl ul configuration */
-+ dc->port[PORT_CTRL].ul_addr[CH_A] = (offset += dc->config_table.ul_app2_len);
-+ dc->port[PORT_CTRL].ul_size[CH_A] = dc->config_table.ul_ctrl_len - buff_offset;
-+ offset = dc->config_table.ul_start;
-+}
-+
-+/* Dump config table under initalization phase */
-+#ifdef NOZOMI_DEBUG
-+static void dump_table(dc_t *dc) {
-+ D3("signature: 0x%08X", dc->config_table.signature);
-+ D3("version: 0x%04X", dc->config_table.version);
-+ D3("product_information: 0x%04X", dc->config_table.product_information);
-+ D3("toggle enabled: %d", dc->config_table.toggle.enabled);
-+ D3("toggle up_mdm: %d", dc->config_table.toggle.mdm_ul);
-+ D3("toggle dl_mdm: %d", dc->config_table.toggle.mdm_dl);
-+ D3("toggle dl_dbg: %d", dc->config_table.toggle.diag_dl);
-+
-+ D3("dl_start: 0x%04X", dc->config_table.dl_start);
-+ D3("dl_mdm_len0: 0x%04X, %d", dc->config_table.dl_mdm_len1, dc->config_table.dl_mdm_len1);
-+ D3("dl_mdm_len1: 0x%04X, %d", dc->config_table.dl_mdm_len2, dc->config_table.dl_mdm_len2);
-+ D3("dl_diag_len0: 0x%04X, %d", dc->config_table.dl_diag_len1, dc->config_table.dl_diag_len1);
-+ D3("dl_diag_len1: 0x%04X, %d", dc->config_table.dl_diag_len2, dc->config_table.dl_diag_len2);
-+ D3("dl_app1_len: 0x%04X, %d", dc->config_table.dl_app1_len, dc->config_table.dl_app1_len);
-+ D3("dl_app2_len: 0x%04X, %d", dc->config_table.dl_app2_len, dc->config_table.dl_app2_len);
-+ D3("dl_ctrl_len: 0x%04X, %d", dc->config_table.dl_ctrl_len, dc->config_table.dl_ctrl_len);
-+ D3("ul_start: 0x%04X, %d", dc->config_table.ul_start, dc->config_table.ul_start);
-+ D3("ul_mdm_len[0]: 0x%04X, %d", dc->config_table.ul_mdm_len1, dc->config_table.ul_mdm_len1);
-+ D3("ul_mdm_len[1]: 0x%04X, %d", dc->config_table.ul_mdm_len2, dc->config_table.ul_mdm_len2);
-+ D3("ul_diag_len: 0x%04X, %d", dc->config_table.ul_diag_len, dc->config_table.ul_diag_len);
-+ D3("ul_app1_len: 0x%04X, %d", dc->config_table.ul_app1_len, dc->config_table.ul_app1_len);
-+ D3("ul_app2_len: 0x%04X, %d", dc->config_table.ul_app2_len, dc->config_table.ul_app2_len);
-+ D3("ul_ctrl_len: 0x%04X, %d", dc->config_table.ul_ctrl_len, dc->config_table.ul_ctrl_len);
-+}
-+#endif
-+
-+/* Read configuration table from card under intalization phase */
-+/* Returns 1 if ok, else 0 */
-+static int nozomi_read_config_table(dc_t *dc) {
-+
-+ if (cards_found > 0 && cards_found == cards_initialized) {
-+ return 1;
-+ }
-+
-+ GET_MEM( &dc->config_table, dc->base_addr + 0, sizeof(config_table_t));
-+
-+ /* D1( "0x%08X == 0x%08X ", dc->config_table.signature, CONFIG_MAGIC); */
-+
-+ if( dc->config_table.signature != CONFIG_MAGIC ) {
-+ ERR("ConfigTable Bad! 0x%08X != 0x%08X", dc->config_table.signature, CONFIG_MAGIC);
-+ return 0;
-+ }
-+
-+ if( (dc->config_table.version == 0) || (dc->config_table.toggle.enabled == TOGGLE_VALID) ) {
-+ int i;
-+ INFO( "Second phase, configuring card");
-+
-+ setup_memory(dc);
-+
-+ dc->port[PORT_MDM].toggle_ul = dc->config_table.toggle.mdm_ul;
-+ dc->port[PORT_MDM].toggle_dl = dc->config_table.toggle.mdm_dl;
-+ dc->port[PORT_DIAG].toggle_dl = dc->config_table.toggle.diag_dl;
-+ D1( "toggle ports: MDM UL:%d MDM DL:%d, DIAG DL:%d",
-+ dc->port[PORT_MDM].toggle_ul,
-+ dc->port[PORT_MDM].toggle_dl,
-+ dc->port[PORT_DIAG].toggle_dl);
-+
-+#ifdef NOZOMI_DEBUG
-+ dump_table(dc);
-+#endif
-+ for (i=PORT_MDM; i< MAX_PORT;i++) {
-+ dc->port[i].fifo_ul = kfifo_alloc( FIFO_BUFFER_SIZE_UL, GFP_ATOMIC , NULL);
-+ memset( &dc->port[i].ctrl_dl, 0, sizeof (ctrl_dl_t));
-+ memset( &dc->port[i].ctrl_ul, 0, sizeof (ctrl_ul_t));
-+ }
-+
-+ /* Enable control channel */
-+ SET_IER( CTRL_DL, CTRL_DL );
-+
-+ INFO("Initialization OK!");
-+ cards_initialized++;
-+ return 1;
-+ }
-+
-+ if( (dc->config_table.version > 0) && (dc->config_table.toggle.enabled != TOGGLE_VALID ) ) {
-+ u32 offset = 0;
-+ INFO( "First phase: pushing upload buffers, clearing download");
-+
-+ INFO("Version of card: %d", dc->config_table.version);
-+
-+ /* Here we should disable all I/O over F32. */
-+ setup_memory(dc);
-+
-+ /* We should send ALL channel pair tokens back along with reset token */
-+
-+ /* push upload modem buffers */
-+ SET_MEM( dc->port[PORT_MDM].ul_addr[CH_A], &offset, 4);
-+ SET_MEM( dc->port[PORT_MDM].ul_addr[CH_B], &offset, 4);
-+
-+ SET_FCR( MDM_UL | DIAG_DL | MDM_DL );
-+
-+ D1( "First phase done");
-+ }
-+
-+ return 1;
-+}
-+
-+/* Enable uplink interrupts */
-+static void enable_transmit_ul( port_type_t port , dc_t *dc ) {
-+
-+ switch( port ) {
-+ case PORT_MDM: SET_IER( MDM_UL , MDM_UL ); break;
-+ case PORT_DIAG: SET_IER( DIAG_UL, DIAG_UL ); break;
-+ case PORT_APP1: SET_IER( APP1_UL, APP1_UL ); break;
-+ case PORT_APP2: SET_IER( APP2_UL, APP2_UL ); break;
-+ case PORT_CTRL: SET_IER( CTRL_UL, CTRL_UL ); break;
-+ default:
-+ ERR("Called with wrong port?");
-+ break;
-+ };
-+}
-+
-+/* Disable uplink interrupts */
-+static void disable_transmit_ul( port_type_t port , dc_t *dc ) {
-+
-+ switch( port ) {
-+ case PORT_MDM: SET_IER( 0 ,MDM_UL ); break;
-+ case PORT_DIAG: SET_IER( 0, DIAG_UL ); break;
-+ case PORT_APP1: SET_IER( 0, APP1_UL ); break;
-+ case PORT_APP2: SET_IER( 0, APP2_UL ); break;
-+ case PORT_CTRL: SET_IER( 0, CTRL_UL ); break;
-+ default:
-+ ERR("Called with wrong port?");
-+ break;
-+ };
-+}
-+
-+/* Enable downlink interrupts */
-+static void enable_transmit_dl( port_type_t port , dc_t *dc ) {
-+
-+ switch( port ) {
-+ case PORT_MDM: SET_IER( MDM_DL , MDM_DL ); break;
-+ case PORT_DIAG: SET_IER( DIAG_DL, DIAG_DL ); break;
-+ case PORT_APP1: SET_IER( APP1_DL, APP1_DL ); break;
-+ case PORT_APP2: SET_IER( APP2_DL, APP2_DL ); break;
-+ case PORT_CTRL: SET_IER( CTRL_DL, CTRL_DL ); break;
-+ default:
-+ ERR("Called with wrong port?");
-+ break;
-+ };
-+}
-+
-+/* Disable downlink interrupts */
-+static void disable_transmit_dl( port_type_t port , dc_t *dc ) {
-+
-+ switch( port ) {
-+ case PORT_MDM: SET_IER( 0 ,MDM_DL ); break;
-+ case PORT_DIAG: SET_IER( 0, DIAG_DL ); break;
-+ case PORT_APP1: SET_IER( 0, APP1_DL ); break;
-+ case PORT_APP2: SET_IER( 0, APP2_DL ); break;
-+ case PORT_CTRL: SET_IER( 0, CTRL_DL ); break;
-+ default:
-+ ERR("Called with wrong port?");
-+ break;
-+ };
-+}
-+
-+/* Return 1 - send buffer to card and ack. */
-+/* Return 0 - don't ack, don't send buffer to card. */
-+int send_data( port_type_t index, dc_t *dc ) {
-+ u32 size = 0;
-+ port_t *port = &dc->port[index];
-+ u8 toggle = port->toggle_ul;
-+ u32 addr = port->ul_addr[toggle];
-+ u32 ul_size = port->ul_size[toggle];
-+ struct tty_struct *tty = port->tty;
-+
-+ if (index >= NTTY_TTY_MINORS) {
-+ ERR("Called with wrong index?");
-+ return 0;
-+ }
-+
-+ /* Get data from tty and place in buf for now */
-+ size = __kfifo_get( port->fifo_ul, dc->send_buf, ul_size < SEND_BUF_MAX ? ul_size : SEND_BUF_MAX );
-+
-+ if (size == 0) {
-+ D4("No more data to send, disable link:");
-+ return 0;
-+ }
-+
-+ port->tx_data += size;
-+
-+ /* DUMP(buf, size); */
-+
-+ /* Write length + data */
-+ SET_MEM( addr, &size, 4 );
-+ SET_MEM_BUF( addr + 4, dc->send_buf, size);
-+
-+ if (port->tty) {
-+ if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup) {
-+ tty->ldisc.write_wakeup(tty);
-+ }
-+ wake_up_interruptible(&tty->write_wait);
-+ }
-+
-+ return 1;
-+}
-+
-+/* If all data has been read, return 1, else 0 */
-+static int receive_data( port_type_t index, dc_t* dc ) {
-+ u8 buf[RECEIVE_BUF_MAX] = {0};
-+ int size;
-+ u32 offset = 4;
-+ port_t *port = &dc->port[index];
-+ u8 toggle = port->toggle_dl;
-+ u32 addr = port->dl_addr[toggle];
-+ struct tty_struct *tty = port->tty;
-+ int i;
-+
-+ if ( !tty ) {
-+ D1("tty not open for port: %d?", index);
-+ return 1;
-+ }
-+
-+ if (test_bit(TTY_DONT_FLIP, &tty->flags)) {
-+ D6("TTY_DONT_FLIP set!! %d", index);
-+ /* Here we disable interrupt for that port and schedule */
-+/* task. Task wakes up a little bit later and enables interrupt.. */
-+ port->tty_dont_flip = 1;
-+ disable_transmit_dl(index, dc);
-+#ifdef KERNEL_2_4
-+ schedule_task(&dc->tty_flip_queue);
-+#endif
-+#ifdef KERNEL_2_6
-+ if (!queue_work(dc->tty_flip_wq, &dc->tty_flip_wq_struct)) {
-+ ERR("Call to queue_work() failed.");
-+ }
-+#endif
-+ return 0;
-+ }
-+
-+ GET_MEM( &size, addr, 4 );
-+ /* D1( "%d bytes port: %d", size, index); */
-+
-+ if ( test_bit( TTY_THROTTLED, & tty->flags) ) {
-+ D1("No room in tty, don't read data, don't ack interrupt, disable interrupt");
-+
-+ /* disable interrupt in downlink... */
-+ disable_transmit_dl(index, dc);
-+ return 0;
-+ }
-+
-+ if (size == 0) {
-+ ERR("size == 0?");
-+ return 1;
-+ }
-+
-+ while( size > 0 ) {
-+ GET_MEM_BUF(buf, addr + offset, 4);
-+
-+ i = 0;
-+ while (i < 4 && size > 0) {
-+ if (tty->flip.count >= TTY_FLIPBUF_SIZE) {
-+ tty_flip_buffer_push(tty);
-+ }
-+ tty_insert_flip_char(tty, buf[i], TTY_NORMAL);
-+ port->rx_data++;
-+ i++;
-+ size--;
-+ }
-+
-+ offset += 4;
-+ }
-+
-+ tty_flip_buffer_push(tty);
-+
-+ return 1;
-+}
-+
-+/* Debug for interrupts */
-+#ifdef NOZOMI_DEBUG
-+static char* interrupt2str( u16 interrupt) {
-+ static char buf[TMP_BUF_MAX];
-+ char *p = buf;
-+
-+ interrupt & MDM_DL1 ? p += snprintf(p, TMP_BUF_MAX, "MDM_DL1 "):0;
-+ interrupt & MDM_DL2 ? p += snprintf(p, TMP_BUF_MAX, "MDM_DL2 "):0;
-+
-+ interrupt & MDM_UL1 ? p += snprintf(p, TMP_BUF_MAX, "MDM_UL1 "):0;
-+ interrupt & MDM_UL2 ? p += snprintf(p, TMP_BUF_MAX, "MDM_UL2 "):0;
-+
-+ interrupt & DIAG_DL1 ? p += snprintf(p, TMP_BUF_MAX, "DIAG_DL1 "):0;
-+ interrupt & DIAG_DL2 ? p += snprintf(p, TMP_BUF_MAX, "DIAG_DL2 "):0;
-+
-+ interrupt & DIAG_UL ? p += snprintf(p, TMP_BUF_MAX, "DIAG_UL "):0;
-+
-+ interrupt & APP1_DL ? p += snprintf(p, TMP_BUF_MAX, "APP1_DL "):0;
-+ interrupt & APP2_DL ? p += snprintf(p, TMP_BUF_MAX, "APP2_DL "):0;
-+
-+ interrupt & APP1_UL ? p += snprintf(p, TMP_BUF_MAX, "APP1_UL "):0;
-+ interrupt & APP2_UL ? p += snprintf(p, TMP_BUF_MAX, "APP2_UL "):0;
-+
-+ interrupt & CTRL_DL ? p += snprintf(p, TMP_BUF_MAX, "CTRL_DL "):0;
-+ interrupt & CTRL_UL ? p += snprintf(p, TMP_BUF_MAX, "CTRL_UL "):0;
-+
-+ interrupt & RESET ? p += snprintf(p, TMP_BUF_MAX, "RESET "):0;
-+
-+ return buf;
-+}
-+#endif
-+
-+/* Receive flow control */
-+/* Return 1 - If ok, else 0 */
-+static int receive_flow_control( dc_t *dc, irq_t *m) {
-+ port_type_t port = PORT_MDM;
-+ ctrl_dl_t ctrl_dl;
-+ ctrl_dl_t old_ctrl;
-+ u16 enable_ier = 0;
-+
-+ GET_MEM( &ctrl_dl, dc->port[PORT_CTRL].dl_addr[CH_A], 2);
-+
-+ switch( ctrl_dl.port ) {
-+ case CTRL_CMD:
-+ D1( "The Base Band sends this value as a response to a request for IMSI detach sent"
-+ " over the control channel uplink (see section 7.6.1).");
-+ break;
-+ case CTRL_MDM: port = PORT_MDM; enable_ier = MDM_DL; break;
-+ case CTRL_DIAG: port = PORT_DIAG; enable_ier = DIAG_DL; break;
-+ case CTRL_APP1: port = PORT_APP1; enable_ier = APP1_DL; break;
-+ case CTRL_APP2: port = PORT_APP2; enable_ier = APP2_DL; break;
-+ default:
-+ ERR("ERROR: flow control received for non-existing port");
-+ return 0;
-+ };
-+
-+ D1( "0x%04X->0x%04X", *((u16*) &dc->port[port].ctrl_dl), *((u16*)&ctrl_dl));
-+
-+ old_ctrl = dc->port[port].ctrl_dl;
-+ dc->port[port].ctrl_dl = ctrl_dl;
-+
-+ if ( old_ctrl.CTS == 1 && ctrl_dl.CTS == 0 ) {
-+ D1( "Disable interrupt (0x%04X) on port: %d", enable_ier, port);
-+ disable_transmit_ul(port, dc);
-+
-+ } else if ( old_ctrl.CTS == 0 && ctrl_dl.CTS == 1 ) {
-+
-+ if ( __kfifo_len(dc->port[port].fifo_ul) ) {
-+ D1( "Enable interrupt (0x%04X) on port: %d", enable_ier, port);
-+ D1( "Data in buffer [%d], enable transmit! ", __kfifo_len(dc->port[port].fifo_ul) );
-+ enable_transmit_ul( port, dc );
-+ } else {
-+ D1( "No data in buffer...");
-+ }
-+ }
-+
-+ if(*(u16*)&old_ctrl == *(u16*)&ctrl_dl)
-+ {
-+ D1( " No change in mctrl");
-+ return 1;
-+ }
-+ /* Update statistics */
-+ if(old_ctrl.CTS != ctrl_dl.CTS) {
-+ dc->port[port].tty_icount.cts++;
-+ }
-+ if(old_ctrl.DSR != ctrl_dl.DSR) {
-+ dc->port[port].tty_icount.dsr++;
-+ }
-+ if(old_ctrl.RI != ctrl_dl.RI) {
-+ dc->port[port].tty_icount.rng++;
-+ }
-+ if(old_ctrl.DCD != ctrl_dl.DCD) {
-+ dc->port[port].tty_icount.dcd++;
-+ }
-+ D1("port: %d DCD(%d), CTS(%d), RI(%d), DSR(%d)",
-+ port,
-+ dc->port[port].tty_icount.dcd, dc->port[port].tty_icount.cts,
-+ dc->port[port].tty_icount.rng, dc->port[port].tty_icount.dsr);
-+
-+ return 1;
-+}
-+
-+/* TODO: */
-+/* - return ctrl_port_t */
-+static u8 port2ctrl(port_type_t port) {
-+ switch( port ) {
-+ case PORT_MDM:
-+ return CTRL_MDM;
-+ case PORT_DIAG:
-+ return CTRL_DIAG;
-+ case PORT_APP1:
-+ return CTRL_APP1;
-+ case PORT_APP2:
-+ return CTRL_APP2;
-+ default:
-+ ERR("ERROR: send flow control received for non-existing port");
-+ return -1;
-+ };
-+ return -1;
-+}
-+
-+/* Send flow control, can only update one channel at a time */
-+/* Return 0 - If we have updated all flow control */
-+/* Return 1 - If we need to update more flow control, ack current enable more */
-+static int send_flow_control( dc_t *dc ) {
-+ u32 i, more_flow_control_to_be_updated = 0;
-+ u16* ctrl;
-+
-+ for( i=PORT_MDM; i<MAX_PORT ; i++ ) {
-+ if( dc->port[i].update_flow_control ) {
-+ if ( more_flow_control_to_be_updated ) {
-+ /* We have more flow control to be updated */
-+ return 1;
-+ }
-+ dc->port[i].ctrl_ul.port = port2ctrl(i);
-+ ctrl = (u16*) &dc->port[i].ctrl_ul;
-+ /* D1( "sending flow control 0x%04X for port %d, %d", (u16) *ctrl, i, dc->port[i].ctrl_ul.port ); */
-+ SET_MEM( dc->port[PORT_CTRL].ul_addr[0], (u32*) ctrl, 2 );
-+ dc->port[i].update_flow_control = 0;
-+ more_flow_control_to_be_updated = 1;
-+ }
-+ }
-+ return 0;
-+}
-+
-+/* Handle donlink data, ports that are handled are modem and diagnostics */
-+/* Return 1 - ok */
-+/* Return 0 - toggle fields are out of sync */
-+static int handle_data_dl(dc_t *dc, irq_t *m, port_type_t port, u8 *toggle, u16 mask1, u16 mask2) {
-+
-+ if ( *toggle == 0 && m->read_iir & mask1 ) {
-+ if (receive_data( port, dc )) {
-+ SET_FCR( mask1 );
-+ *toggle = !(*toggle);
-+ }
-+
-+ if ( m->read_iir & mask2 ) {
-+ if (receive_data( port, dc )) {
-+ SET_FCR( mask2 );
-+ *toggle = !(*toggle);
-+ }
-+ }
-+ } else if ( *toggle == 1 && m->read_iir & mask2 ) {
-+ if (receive_data( port, dc )) {
-+ SET_FCR( mask2 );
-+ *toggle = !(*toggle);
-+ }
-+
-+ if ( m->read_iir & mask1 ) {
-+ if (receive_data( port, dc )) {
-+ SET_FCR( mask1 );
-+ *toggle = !(*toggle);
-+ }
-+ }
-+ } else {
-+ ERR("port out of sync!, toggle:%d", *toggle);
-+ return 0;
-+ }
-+ return 1;
-+}
-+
-+/* Handle uplink data, this is currently for the modem port */
-+/* Return 1 - ok */
-+/* Return 0 - toggle field are out of sync */
-+static int handle_data_ul(dc_t *dc, irq_t *m, port_type_t port) {
-+
-+ u8 *toggle = &(dc->port[port].toggle_ul);
-+
-+ if ( *toggle==0 && m->read_iir & MDM_UL1 ) {
-+ SET_IER( 0, MDM_UL );
-+ if (send_data(port, dc)) {
-+ SET_FCR( MDM_UL1 );
-+ SET_IER( MDM_UL, MDM_UL);
-+ *toggle = !*toggle;
-+ }
-+
-+ if ( m->read_iir & MDM_UL2 ) {
-+ SET_IER( 0, MDM_UL );
-+ if (send_data(port, dc)) {
-+ SET_FCR( MDM_UL2 );
-+ SET_IER( MDM_UL, MDM_UL);
-+ *toggle = !*toggle;
-+ }
-+ }
-+
-+ } else if ( *toggle==1 && m->read_iir & MDM_UL2 ) {
-+ SET_IER( 0, MDM_UL );
-+ if (send_data(port, dc)) {
-+ SET_FCR( MDM_UL2 );
-+ SET_IER( MDM_UL, MDM_UL);
-+ *toggle = !*toggle;
-+ }
-+
-+ if ( m->read_iir & MDM_UL1 ) {
-+ SET_IER( 0, MDM_UL );
-+ if (send_data(port, dc)) {
-+ SET_FCR( MDM_UL1 );
-+ SET_IER( MDM_UL, MDM_UL);
-+ *toggle = !*toggle;
-+ }
-+ }
-+ } else {
-+ SET_FCR( m->read_iir & MDM_UL );
-+ ERR("port out of sync!");
-+ return 0;
-+ }
-+ return 1;
-+}
-+
-+static irqreturn_t interrupt_handler(int irq, void *dev_id, struct pt_regs *regs) {
-+ dc_t *dc = NULL;
-+ irq_t* m = &my_irq;
-+
-+ if (my_dev && my_dev->pdev != dev_id) {
-+ return IRQ_NONE;
-+ }
-+
-+ if ( !(dc = get_dc_by_pdev(dev_id)) ) {
-+ ERR("Could not find device context from pci_dev: %d", (u32) dev_id);
-+ return IRQ_NONE;
-+ }
-+
-+ GET_IIR( m->read_iir );
-+
-+ /* Just handle interrupt enabled in IER (by masking with dc->ier_last_written) */
-+ m->read_iir &= dc->ier_last_written;
-+
-+ if (m->read_iir == 0) {
-+ return IRQ_NONE;
-+ }
-+
-+ if (dc == NULL ) {
-+ ERR("ERROR!!");
-+ return IRQ_NONE;
-+ }
-+
-+ spin_lock(&dc->spin_mutex);
-+
-+ D4( "%s irq:0x%04X, prev:0x%04X", interrupt2str(m->read_iir), m->read_iir, dc->ier_last_written);
-+
-+ if ( m->read_iir & RESET) {
-+ if( !nozomi_read_config_table(dc) ) {
-+ SET_IER( 0, 0xFFFF);
-+ ERR("ERR: Could not read status from card, we should disable interface");
-+ } else {
-+ SET_FCR( RESET );
-+ }
-+ goto exit_handler; /* No more useful info if this was the reset interrupt. */
-+ }
-+ if ( m->read_iir & CTRL_UL ) {
-+ D1( "CTRL_UL");
-+ SET_IER( 0, CTRL_UL );
-+ if ( send_flow_control(dc) ) {
-+ SET_FCR( CTRL_UL );
-+ SET_IER( CTRL_UL, CTRL_UL );
-+ }
-+ }
-+ if ( m->read_iir & CTRL_DL ) {
-+ receive_flow_control(dc, m);
-+ SET_FCR( CTRL_DL );
-+ }
-+ if ( m->read_iir & MDM_DL ) {
-+ if ( !(handle_data_dl(dc, m, PORT_MDM, &(dc->port[PORT_MDM].toggle_dl), MDM_DL1, MDM_DL2)) ) {
-+ ERR("MDM_DL out of sync!");
-+ goto exit_handler;
-+ }
-+ }
-+ if ( m->read_iir & MDM_UL ) {
-+ if ( !handle_data_ul(dc, m, PORT_MDM ) ) {
-+ ERR("MDM_UL out of sync!");
-+ goto exit_handler;
-+ }
-+ }
-+ if ( m->read_iir & DIAG_DL ) {
-+ if ( !(handle_data_dl(dc, m, PORT_DIAG, &(dc->port[PORT_DIAG].toggle_dl), DIAG_DL1, DIAG_DL2)) ) {
-+ ERR("DIAG_DL out of sync!");
-+ goto exit_handler;
-+ }
-+ }
-+ if ( m->read_iir & DIAG_UL ) {
-+ SET_IER( 0, DIAG_UL );
-+ if( send_data( PORT_DIAG, dc ) ) {
-+ SET_FCR( DIAG_UL );
-+ SET_IER( DIAG_UL, DIAG_UL );
-+ }
-+ }
-+ if ( m->read_iir & APP1_DL ) {
-+ if (receive_data( PORT_APP1, dc ) ) {
-+ SET_FCR( APP1_DL );
-+ }
-+ }
-+ if ( m->read_iir & APP1_UL ) {
-+ SET_IER( 0, APP1_UL );
-+ if(send_data( PORT_APP1, dc )) {
-+ SET_FCR( APP1_UL );
-+ SET_IER( APP1_UL, APP1_UL );
-+ }
-+ }
-+ if ( m->read_iir & APP2_DL ) {
-+ if (receive_data( PORT_APP2, dc )) {
-+ SET_FCR( APP2_DL );
-+ }
-+ }
-+ if ( m->read_iir & APP2_UL ) {
-+ SET_IER( 0, APP2_UL );
-+ if(send_data( PORT_APP2, dc )) {
-+ SET_FCR( APP2_UL );
-+ SET_IER( APP2_UL, APP2_UL );
-+ }
-+ }
-+
-+ exit_handler:
-+ spin_unlock(&dc->spin_mutex);
-+ return IRQ_HANDLED;
-+}
-+
-+/* Request a shared IRQ from system */
-+static int nozomi_setup_interrupt(struct pci_dev *pdev) {
-+
-+ int rval = 0;
-+
-+ if ( (rval = request_irq( pdev->irq, &interrupt_handler, SA_SHIRQ, NOZOMI_NAME, pdev )) ) {
-+ ERR("Cannot open because IRQ %d is already in use.", pdev->irq );
-+ return rval;
-+ }
-+
-+ return rval;
-+}
-+
-+static void nozomi_get_card_type(dc_t *dc) {
-+ u32 i, size=0;
-+ for(i=0;i<6;i++) {
-+ size += pci_resource_len(dc->pdev, i);
-+ }
-+
-+ /* Assume card type F32_8 if no match */
-+ dc->card_type = size == 2048 ? F32_2 : F32_8;
-+
-+ INFO("Card type is: %d", dc->card_type );
-+}
-+
-+void nozomi_setup_private_data(dc_t *dc) {
-+ u32 offset = dc->base_addr + dc->card_type/2;
-+ int i;
-+
-+ dc->REG_FCR = offset + R_FCR;
-+ dc->REG_IIR = offset + R_IIR;
-+ dc->REG_IER = offset + R_IER;
-+ dc->ier_last_written = 0;
-+ dc->closing = 0;
-+
-+ dc->port[PORT_MDM ].token_dl = MDM_DL;
-+ dc->port[PORT_DIAG].token_dl = DIAG_DL;
-+ dc->port[PORT_APP1].token_dl = APP1_DL;
-+ dc->port[PORT_APP2].token_dl = APP2_DL;
-+
-+ for(i=PORT_MDM;i<MAX_PORT;i++) {
-+ dc->port[i].rx_data = dc->port[i].tx_data = 0;
-+ dc->port[i].tty_dont_flip = 0;
-+ }
-+}
-+
-+
-+static void tty_flip_queue_function(void *tmp_dc) {
-+ dc_t *dc = (dc_t*) tmp_dc;
-+ int i;
-+
-+ /* Enable interrupt for that port */
-+ for(i=0;i<MAX_PORT;i++) {
-+ if (dc->port[i].tty_dont_flip) {
-+ D6("Enable for port: %d", i);
-+ dc->port[i].tty_dont_flip = 0;
-+ enable_transmit_dl(dc->port[i].tty_index, dc);
-+ }
-+ }
-+}
-+
-+static int read_proc_card_type(char *buf, char **start, off_t offset, int len) {
-+ dc_t *dc = get_dc_by_index(0);
-+ len = 0;
-+
-+ len += sprintf(buf+len,"%d\n", dc->card_type);
-+ return len;
-+}
-+
-+static int read_proc_open_ttys(char *buf, char **start, off_t offset, int len) {
-+ dc_t *dc = get_dc_by_index(0);
-+ len = 0;
-+
-+ len += sprintf(buf+len,"%d\n", dc->open_ttys);
-+ return len;
-+}
-+
-+static int read_proc_version(char *buf, char **start, off_t offset, int len) {
-+ len = 0;
-+
-+ len += sprintf(buf+len, "%s\n", VERSION_STRING);
-+ return len;
-+}
-+
-+static int read_proc_rtx(char *buf, char **start, off_t offset, int len) {
-+ dc_t *dc = get_dc_by_index(0);
-+ int i;
-+
-+ len = 0;
-+
-+
-+ for(i=PORT_MDM;i<MAX_PORT;i++) {
-+ len += sprintf(buf+len,"noz%d rx: %d, tx: %d\n", i, dc->port[i].rx_data, dc->port[i].tx_data);
-+ }
-+ return len;
-+}
-+
-+static void make_proc_dirs(void) {
-+ dc_t *dc = get_dc_by_index(0);
-+
-+ dc->proc_entry = proc_mkdir("nozomi", &proc_root);
-+
-+ /* Register the read_proc */
-+ if ( !create_proc_info_entry("card_type",0,dc->proc_entry,read_proc_card_type) ) {
-+ ERR("ERROR: failed to register read_procmem");
-+ }
-+ if ( !create_proc_info_entry("open_ttys",0,dc->proc_entry,read_proc_open_ttys) ) {
-+ ERR("ERROR: failed to register read_procmem");
-+ }
-+ if ( !create_proc_info_entry("rtx",0,dc->proc_entry,read_proc_rtx) ) {
-+ ERR("ERROR: failed to register read_procmem");
-+ }
-+ if ( !create_proc_info_entry("version",0,dc->proc_entry,read_proc_version) ) {
-+ ERR("ERROR: failed to register read_procmem");
-+ }
-+}
-+
-+static void remove_proc_dirs(void) {
-+ dc_t *dc = get_dc_by_index(0);
-+
-+ remove_proc_entry("card_type", dc->proc_entry);
-+ remove_proc_entry("open_ttys", dc->proc_entry);
-+ remove_proc_entry("rtx", dc->proc_entry);
-+ remove_proc_entry("version", dc->proc_entry);
-+ remove_proc_entry("nozomi", &proc_root);
-+}
-+
-+static void send_reset_token(dc_t *dc) {
-+
-+ ctrl_ul_t ctrl;
-+
-+ /* Send 0x0001, command card to resend the reset token. */
-+ /* This is to get the reset when the module is reloaded. */
-+ ctrl.port = 0x00; ctrl.reserved = 0; ctrl.RTS=0; ctrl.DTR=1;
-+ D1( "sending flow control 0x%04X", * ((u16*) &ctrl) );
-+
-+
-+ /*SET_MEM( dc->port[PORT_CTRL].ul_addr[0], (u32*) &ctrl, 2 );*/
-+ /* hack alert :D (fixed address determined experimentally) */
-+ SET_MEM( dc->base_addr + 0x000002FC, (u32*) &ctrl, 2 );
-+ SET_FCR( CTRL_UL ); /* push the token to the card. */
-+ D1( "sent flow control 0x%04X", * ((u16*) &ctrl) );
-+}
-+
-+/* Allocate memory for one device */
-+static int __devinit nozomi_card_init(struct pci_dev *pdev, const struct pci_device_id *ent) {
-+ int ret = -EIO;
-+ dc_t *dc=NULL;
-+
-+ cards_found++;
-+ INFO("Init, cards_found: %d", cards_found);
-+
-+ if (!(my_dev = kmalloc(sizeof(dc_t), GFP_KERNEL))) {
-+ D1( "Could not allocate memory");
-+ return -EIO;
-+ }
-+
-+ memset(my_dev, 0, sizeof( dc_t ));
-+
-+ if (cards_found > 1) {
-+ ERR("This driver only supports 1 device");
-+ return -ENODEV;
-+ }
-+
-+ my_dev->pdev = pdev;
-+ dc = my_dev;
-+
-+ /* Find out what card type it is */
-+ nozomi_get_card_type(dc);
-+
-+ if (pci_enable_device(dc->pdev)) {
-+ ERR("Not possible to enable PCI Device");
-+ return -ENODEV;
-+ }
-+
-+ if ( (dc->base_addr = pci_resource_start(dc->pdev, 0)) == 0x0000) {
-+ ERR("No I/O-Address for card detected");
-+ ret = -ENODEV;
-+ goto err_disable_device;
-+ }
-+
-+ if (!(dc->base_addr = (u32) ioremap(dc->base_addr, dc->card_type))) {
-+ ERR("No I/O-Address for card detected");
-+ ret = -ENODEV;
-+ goto err_disable_device;
-+ }
-+
-+ dc->open_ttys=0;
-+
-+ nozomi_setup_private_data(dc);
-+
-+ if (pci_request_regions(dc->pdev, NOZOMI_NAME)) {
-+ ERR("I/O address 0x%04x already in use",
-+ (int) /* nozomi_private.io_addr */ 0);
-+ ret = -EIO;
-+ goto err_disable_regions;
-+ }
-+
-+ if ( !(dc->send_buf = kmalloc(SEND_BUF_MAX, GFP_KERNEL))) {
-+ ERR("Could not allocate send buffer?");
-+ goto err_disable_regions;
-+ }
-+
-+ /* Disable all interrupts */
-+ SET_IER( 0 , 0xFFFF );
-+
-+ /* Setup interrupt handler */
-+ if (nozomi_setup_interrupt(dc->pdev)) {
-+ ret = -EIO;
-+ goto err_disable_regions;
-+ }
-+
-+ D1( "base_addr: 0x%08X", dc->base_addr);
-+
-+#ifdef KERNEL_2_4
-+ dc->tty_flip_queue.list.next = NULL;
-+ dc->tty_flip_queue.list.prev = NULL;
-+ dc->tty_flip_queue.sync = 0;
-+ dc->tty_flip_queue.data = dc;
-+ dc->tty_flip_queue.routine = tty_flip_queue_function;
-+#endif
-+#ifdef KERNEL_2_6
-+ if ( !(dc->tty_flip_wq = create_singlethread_workqueue(NOZOMI_NAME )) ) {
-+ ERR("Could not create workqueue?");
-+ BUG_ON(!dc->tty_flip_wq);
-+ return -ENOMEM;
-+ }
-+ INIT_WORK( &dc->tty_flip_wq_struct, tty_flip_queue_function, (void*) dc);
-+#endif
-+
-+ spin_lock_init(&dc->spin_mutex);
-+
-+ make_proc_dirs();
-+
-+ ntty_tty_init(dc);
-+#if 0
-+ if (!nozomi_read_config_table(dc)) {
-+ ERR("Could not read config table (pass 1)");
-+ return -ENODEV;
-+ }
-+ if (!nozomi_read_config_table(dc)) {
-+ ERR("Could not read config table (pass 2)");
-+ return -ENODEV;
-+ }
-+#endif
-+ send_reset_token(dc);
-+
-+ /* Enable RESET interrupt. */
-+ SET_IER( RESET, 0xFFFF );
-+
-+ return 0;
-+
-+err_disable_regions:
-+ pci_release_regions(pdev);
-+ iounmap((void *)dc->base_addr );
-+ dc->base_addr = 0;
-+
-+err_disable_device:
-+ pci_disable_device(pdev);
-+ if(my_dev) {
-+ kfree( my_dev );
-+ }
-+ return ret;
-+}
-+
-+static void tty_do_close(dc_t *dc, port_t *port) {
-+
-+ down(&port->tty_sem);
-+
-+ if ( !port->tty_open_count ) {
-+ goto exit;
-+ }
-+
-+ dc->open_ttys--;
-+ port->tty_open_count--;
-+#ifdef KERNEL_2_4
-+ MOD_DEC_USE_COUNT;
-+#endif
-+
-+ if ( port->tty_open_count == 0) {
-+ D1("close: %d", port->token_dl );
-+ SET_IER( 0, port->token_dl );
-+ }
-+
-+exit:
-+ up(&port->tty_sem);
-+}
-+
-+static void __exit tty_exit(void) {
-+ int i;
-+ dc_t *dc = my_dev;
-+
-+ D1( " ");
-+
-+#ifdef KERNEL_2_6
-+ for (i = 0; i < NTTY_TTY_MINORS; ++i)
-+ tty_unregister_device(&dc->tty_driver, i);
-+#endif
-+
-+ tty_unregister_driver(&dc->tty_driver);
-+
-+ for (i = 0; i < NTTY_TTY_MINORS; i++) {
-+ while (dc->port[i].tty_open_count) {
-+ tty_do_close(dc, &dc->port[i]);
-+ }
-+
-+ dc->port[i].tty = NULL;
-+ }
-+}
-+
-+/* Deallocate memory for one device */
-+static void __devexit nozomi_card_exit(struct pci_dev *pdev) {
-+ int i;
-+ dc_t *dc = get_dc_by_pdev(pdev);
-+
-+ /* Disable all interrupts */
-+ SET_IER( 0, 0xFFFF);
-+
-+ /* Setup dc->reg addresses to we can use defines here */
-+ nozomi_setup_private_data(dc);
-+ send_reset_token(dc);
-+
-+ D1( "pci_release_regions");
-+ pci_release_regions(pdev);
-+
-+ if(dc->base_addr)
-+ iounmap((void *)dc->base_addr);
-+
-+ D1( "pci_disable_device");
-+ pci_disable_device(pdev);
-+
-+ free_irq( pdev->irq, pdev );
-+
-+ for (i=PORT_MDM; i< MAX_PORT;i++) {
-+ kfree ( dc->port[i].fifo_ul );
-+ }
-+
-+ kfree( dc->send_buf );
-+
-+ tty_exit();
-+
-+ remove_proc_dirs();
-+
-+#ifdef KERNEL_2_6
-+ destroy_workqueue(dc->tty_flip_wq);
-+#endif
-+
-+ if (my_dev) {
-+ kfree( my_dev );
-+ }
-+
-+ cards_found--;
-+ cards_initialized--;
-+}
-+
-+static void set_rts(int index, int rts) {
-+ dc_t *dc = get_dc_by_index(index);
-+
-+ dc->port[index].ctrl_ul.RTS = rts;
-+ dc->port[index].update_flow_control = 1;
-+ enable_transmit_ul(PORT_CTRL, dc);
-+}
-+
-+static void set_dtr(int index, int dtr) {
-+ dc_t *dc = get_dc_by_index(index);
-+
-+ D1("SETTING DTR index: %d, dtr: %d", index, dtr);
-+
-+ dc->port[index].ctrl_ul.DTR = dtr;
-+ dc->port[index].update_flow_control = 1;
-+ enable_transmit_ul(PORT_CTRL, dc);
-+}
-+
-+
-+/* ---------------------------------------------------------------------------------------------------
-+ TTY code
-+ ---------------------------------------------------------------------------------------------------*/
-+
-+
-+/* Called when the userspace process opens the tty, /dev/noz*. */
-+static int ntty_open(struct tty_struct *tty, struct file *file) {
-+
-+ s32 index = get_index(tty);
-+ port_t *port = get_port_by_tty(tty);
-+ dc_t *dc = get_dc_by_tty(tty);
-+
-+ CARD_CHECK(-ENODEV);
-+
-+ down(&port->tty_sem);
-+
-+ tty->low_latency = 1;
-+ tty->driver_data = port;
-+ port->tty = tty;
-+ port->tty_index = index;
-+
-+ port->tty_open_count++;
-+ dc->open_ttys++;
-+
-+#ifdef KERNEL_2_4
-+ MOD_INC_USE_COUNT;
-+#endif
-+
-+ /* Enable interrupt downlink for channel */
-+ if ( port->tty_open_count == 1) {
-+ port->rx_data = port->tx_data = 0;
-+ D1("open: %d", port->token_dl );
-+ SET_IER( port->token_dl, port->token_dl );
-+ }
-+
-+ up(&port->tty_sem);
-+
-+ return 0;
-+}
-+
-+/* Called when the userspace process close the tty, /dev/noz*. */
-+static void ntty_close(struct tty_struct *tty, struct file *file) {
-+ dc_t *dc;
-+ CARD_CHECK();
-+ dc = get_dc_by_tty(tty);
-+ tty_do_close(dc, (port_t *) tty->driver_data);
-+}
-+
-+/* called when the userspace process writes to the tty (/dev/noz*). */
-+/* Data is inserted into a fifo, which is then read and transfered to the modem. */
-+#ifdef KERNEL_2_6
-+static int ntty_write(struct tty_struct *tty, const unsigned char *buffer, int count) {
-+#else
-+static s32 ntty_write(struct tty_struct *tty, s32 from_user, const u8 *buffer, s32 count) {
-+#endif
-+ int rval = -EINVAL;
-+ dc_t *dc = get_dc_by_tty(tty);
-+ port_t *port = (port_t *) tty->driver_data;
-+
-+ CARD_CHECK(rval);
-+
-+ /* D1( "WRITEx: %d, index = %d", count, index); */
-+
-+ if (! port) {
-+ return -ENODEV;
-+ }
-+
-+ down(&port->tty_sem);
-+
-+ if (! port->tty_open_count) {
-+ D1( " ");
-+ goto exit;
-+ }
-+
-+#ifdef KERNEL_2_4
-+ if (from_user) {
-+ rval = __kfifo_put_user(port->fifo_ul, (unsigned char *) buffer, count);
-+ } else {
-+ rval = __kfifo_put(port->fifo_ul, (unsigned char *) buffer, count);
-+ }
-+#else
-+ rval = __kfifo_put(port->fifo_ul, (unsigned char *) buffer, count);
-+#endif
-+
-+ /* notify card */
-+ if ( dc == NULL) {
-+ D1( "No device context?");
-+ goto exit;
-+ }
-+
-+ // CTS is only valid on the modem channel
-+ if ( port == &(dc->port[PORT_MDM]) ) {
-+ if ( port->ctrl_dl.CTS ) {
-+ D4( "Enable interrupt");
-+ enable_transmit_ul(port->tty_index, dc );
-+ } else {
-+ ERR("CTS not active on modem port?");
-+ }
-+ } else {
-+ enable_transmit_ul(port->tty_index, dc );
-+ }
-+
-+exit:
-+ up(&port->tty_sem);
-+ return rval;
-+}
-+
-+/* Calculate how much is left in device */
-+/* This method is called by the upper tty layer. */
-+/* #according to sources N_TTY.c it expects a value >= 0 and does not check for negative values. */
-+static int ntty_write_room(struct tty_struct *tty) {
-+ port_t *port = (port_t *) tty->driver_data;
-+ int room = 0;
-+/* u32 flags = 0; */
-+/* dc_t *dc = get_dc_by_tty(tty); */
-+
-+ CARD_CHECK(-ENODEV);
-+
-+ if (! port) {
-+ return 0;
-+ }
-+
-+ down(&port->tty_sem);
-+
-+ if (! port->tty_open_count) {
-+ goto exit;
-+ }
-+
-+ room = port->fifo_ul->size - __kfifo_len(port->fifo_ul);
-+
-+exit:
-+ up(&port->tty_sem);
-+ return room;
-+}
-+
-+/* Sets termios flags, called by the tty layer. */
-+static void ntty_set_termios(struct tty_struct *tty, struct termios *old_termios) {
-+ unsigned int cflag;
-+
-+ CARD_CHECK();
-+
-+ cflag = tty->termios->c_cflag;
-+
-+ if (old_termios) {
-+ if ((cflag == old_termios->c_cflag) &&
-+ (RELEVANT_IFLAG(tty->termios->c_iflag) == RELEVANT_IFLAG(old_termios->c_iflag))) {
-+ D1( " - nothing to change...");
-+ goto exit_termios;
-+ }
-+ }
-+
-+ /* get the byte size */
-+ switch (cflag & CSIZE) {
-+ case CS5:
-+ D1( " - data bits = 5");
-+ break;
-+ case CS6:
-+ D1( " - data bits = 6");
-+ break;
-+ case CS7:
-+ D1( " - data bits = 7");
-+ break;
-+ default:
-+ case CS8:
-+ D1( " - data bits = 8");
-+ break;
-+ }
-+
-+ /* determine the parity */
-+ if (cflag & PARENB) {
-+ if (cflag & PARODD) {
-+ D1( " - parity = odd");
-+ } else {
-+ D1( " - parity = even");
-+ }
-+ } else {
-+ D1( " - parity = none");
-+ }
-+
-+ /* figure out the stop bits requested */
-+ if (cflag & CSTOPB) {
-+ D1( " - stop bits = 2");
-+ } else {
-+ D1( " - stop bits = 1");
-+ }
-+
-+ /* figure out the hardware flow control settings */
-+ if (cflag & CRTSCTS) {
-+ D1( " - RTS/CTS is enabled");
-+ } else {
-+ D1( " - RTS/CTS is disabled");
-+ }
-+
-+ /* determine software flow control */
-+ /* if we are implementing XON/XOFF, set the start and
-+ * stop character in the device */
-+ if (I_IXOFF(tty) || I_IXON(tty)) {
-+#ifdef NOZOMI_DEBUG
-+ unsigned char stop_char = STOP_CHAR(tty);
-+ unsigned char start_char = START_CHAR(tty);
-+#endif
-+ /* if we are implementing INBOUND XON/XOFF */
-+ if (I_IXOFF(tty)) {
-+ D1( " - INBOUND XON/XOFF is enabled, "
-+ "XON = %2x, XOFF = %2x", start_char, stop_char);
-+ } else {
-+ D1( " - INBOUND XON/XOFF is disabled");
-+ }
-+
-+ /* if we are implementing OUTBOUND XON/XOFF */
-+ if (I_IXON(tty)) {
-+ D1( " - OUTBOUND XON/XOFF is enabled, "
-+ "XON = %2x, XOFF = %2x", start_char, stop_char);
-+ } else {
-+ D1( " - OUTBOUND XON/XOFF is disabled");
-+ }
-+ }
-+
-+ exit_termios:
-+ return;
-+}
-+
-+/* Gets io control parameters */
-+static int ntty_tiocmget(struct tty_struct *tty, struct file *file) {
-+ port_t *port = (port_t *) tty->driver_data;
-+ ctrl_dl_t *ctrl_dl = &port->ctrl_dl;
-+ ctrl_ul_t *ctrl_ul = &port->ctrl_ul;
-+
-+ return 0
-+ | (ctrl_ul->RTS ? TIOCM_RTS : 0)
-+ | (ctrl_ul->DTR ? TIOCM_DTR : 0)
-+ | (ctrl_dl->DCD ? TIOCM_CAR : 0)
-+ | (ctrl_dl->RI ? TIOCM_RNG : 0)
-+ | (ctrl_dl->DSR ? TIOCM_DSR : 0)
-+ | (ctrl_dl->CTS ? TIOCM_CTS : 0);
-+}
-+
-+/* Sets io controls parameters */
-+static int ntty_tiocmset(struct tty_struct *tty, struct file *file, u32 arg) {
-+ port_t *port = (port_t *) tty->driver_data;
-+
-+ set_rts(port->tty_index, (arg & TIOCM_RTS) ? 1 : 0);
-+ set_dtr(port->tty_index, (arg & TIOCM_DTR) ? 1 : 0);
-+
-+ return 0;
-+}
-+
-+static int ntty_ioctl_tiocmiwait(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg) {
-+ port_t *port = (port_t *) tty->driver_data;
-+
-+ if (cmd == TIOCMIWAIT) {
-+ DECLARE_WAITQUEUE(wait, current);
-+ struct async_icount cnow;
-+ struct async_icount cprev;
-+
-+ cprev = port->tty_icount;
-+ while (1) {
-+ add_wait_queue(&port->tty_wait, &wait);
-+ set_current_state(TASK_INTERRUPTIBLE);
-+ schedule();
-+ remove_wait_queue(&port->tty_wait, &wait);
-+
-+ /* see if a signal woke us up */
-+ if (signal_pending(current))
-+ return -ERESTARTSYS;
-+
-+ cnow = port->tty_icount;
-+ if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr &&
-+ cnow.dcd == cprev.dcd && cnow.cts == cprev.cts)
-+ return -EIO; /* no change => error */
-+ if (((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) ||
-+ ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) ||
-+ ((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) ||
-+ ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts)) ) {
-+ return 0;
-+ }
-+ cprev = cnow;
-+ }
-+
-+ }
-+ return -ENOIOCTLCMD;
-+}
-+
-+static int ntty_ioctl_tiocgicount(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg) {
-+ port_t *port = (port_t *) tty->driver_data;
-+
-+ if (cmd == TIOCGICOUNT) {
-+ struct async_icount cnow = port->tty_icount;
-+ struct serial_icounter_struct icount;
-+
-+ icount.cts = cnow.cts;
-+ icount.dsr = cnow.dsr;
-+ icount.rng = cnow.rng;
-+ icount.dcd = cnow.dcd;
-+ icount.rx = cnow.rx;
-+ icount.tx = cnow.tx;
-+ icount.frame = cnow.frame;
-+ icount.overrun = cnow.overrun;
-+ icount.parity = cnow.parity;
-+ icount.brk = cnow.brk;
-+ icount.buf_overrun = cnow.buf_overrun;
-+
-+ if (copy_to_user((void *)arg, &icount, sizeof(icount)))
-+ return -EFAULT;
-+ return 0;
-+ }
-+ return -ENOIOCTLCMD;
-+}
-+
-+static int ntty_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg) {
-+ port_t *port = (port_t *) tty->driver_data;
-+ int mask;
-+ int rval = -ENOIOCTLCMD;
-+
-+ CARD_CHECK(rval);
-+
-+ D1("******** IOCTL, cmd: %d", cmd);
-+
-+
-+ switch (cmd) {
-+ case TCGETS:
-+ D1( "IOCTL TCGETS ...");
-+ rval = -ENOIOCTLCMD;
-+ break;
-+ case TCSETS:
-+ D1( "IOCTL TCSETS ...");
-+ rval = -ENOIOCTLCMD;
-+ break;
-+ case TIOCMIWAIT:
-+ rval = ntty_ioctl_tiocmiwait(tty, file, cmd, arg);
-+ break;
-+ case TIOCGICOUNT:
-+ rval = ntty_ioctl_tiocgicount(tty, file, cmd, arg);
-+ break;
-+ case TIOCMGET:
-+ rval = ntty_tiocmget(tty, file);
-+ break;
-+ case TIOCMSET:
-+ rval = ntty_tiocmset(tty, file, arg);
-+ break;
-+ case TIOCMBIC:
-+ if (get_user(mask, (unsigned long *) arg))
-+ return -EFAULT;
-+
-+ if (mask & TIOCM_RTS)
-+ set_rts(port->tty_index, 0);
-+ if (mask & TIOCM_DTR)
-+ set_dtr(port->tty_index, 0);
-+ rval = 0;
-+ break;
-+ case TIOCMBIS:
-+ if (get_user(mask, (unsigned long *) arg))
-+ return -EFAULT;
-+
-+ if (mask & TIOCM_RTS)
-+ set_rts(port->tty_index, 1);
-+ if (mask & TIOCM_DTR)
-+ set_dtr(port->tty_index, 1);
-+ rval = 0;
-+ break;
-+ case TCFLSH:
-+ D1( "IOCTL TCFLSH ...");
-+ rval = -ENOIOCTLCMD;
-+ break;
-+
-+ default:
-+ D1( "ERR: 0x%08X, %d", cmd, cmd);
-+ break;
-+ };
-+
-+ return rval;
-+}
-+
-+/* Called by the upper tty layer when tty buffers are ready */
-+/* to receive data again after a call to throttle. */
-+static void ntty_unthrottle(struct tty_struct *tty) {
-+ port_t *port = (port_t *) tty->driver_data;
-+ dc_t *dc = get_dc_by_tty(tty);
-+ u32 flags;
-+
-+ CARD_CHECK();
-+
-+ D1( "UNTHROTTLE");
-+ spin_lock_irqsave(&dc->spin_mutex, flags);
-+ enable_transmit_dl(port->tty_index, dc);
-+ set_rts(port->tty_index, 1);
-+
-+ spin_unlock_irqrestore(&dc->spin_mutex, flags);
-+}
-+
-+/* Called by the upper tty layer when the tty buffers are almost full. */
-+/* The driver should stop send more data. */
-+static void ntty_throttle(struct tty_struct *tty) {
-+ port_t *port = (port_t *) tty->driver_data;
-+ dc_t *dc = get_dc_by_tty(tty);
-+ u32 flags;
-+
-+ CARD_CHECK();
-+
-+ D1( "THROTTLE");
-+ spin_lock_irqsave(&dc->spin_mutex, flags);
-+ set_rts(port->tty_index, 0);
-+ spin_unlock_irqrestore(&dc->spin_mutex, flags);
-+}
-+
-+static void ntty_put_char(struct tty_struct *tty, unsigned char c) {
-+ CARD_CHECK();
-+ D2("PUT CHAR Function: %c", c);
-+}
-+
-+/* Returns number of chars in buffer, called by tty layer */
-+static s32 ntty_chars_in_buffer(struct tty_struct *tty) {
-+ port_t *port = (port_t *) tty->driver_data;
-+ s32 rval;
-+
-+ CARD_CHECK(-ENODEV);
-+
-+ if (! port) {
-+ rval = -ENODEV;
-+ goto exit_in_buffer;
-+ }
-+
-+ if (! port->tty_open_count) {
-+ ERR("No tty open?");
-+ rval = -ENODEV;
-+ goto exit_in_buffer;
-+ }
-+
-+ rval = __kfifo_len(port->fifo_ul);
-+
-+ exit_in_buffer:
-+ return rval;
-+}
-+
-+/* Initializes the tty */
-+static int ntty_tty_init(dc_t *dc) {
-+ struct tty_driver *td = &dc->tty_driver;
-+ int rval;
-+ int i;
-+
-+ memset(td, 0, sizeof(struct tty_driver));
-+
-+ td->magic = TTY_DRIVER_MAGIC;
-+ td->driver_name = NOZOMI_NAME_TTY;
-+ td->name = "noz";
-+ td->major = NTTY_TTY_MAJOR,
-+ td->type = TTY_DRIVER_TYPE_SERIAL,
-+ td->subtype = SERIAL_TYPE_NORMAL,
-+ td->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS,
-+ td->init_termios = tty_std_termios;
-+ td->init_termios.c_cflag = B115200 | CS8 | CREAD | HUPCL | CLOCAL;
-+
-+ td->num = MAX_PORT;
-+ td->name_base = 0;
-+ td->minor_start = 0;
-+
-+#ifdef KERNEL_2_4
-+ td->table = dc->tty_table;
-+ td->refcount = &dc->tty_refcount;
-+#endif
-+
-+ td->termios = dc->tty_termios;
-+ td->termios_locked = dc->tty_termios_locked;
-+
-+ td->ioctl = ntty_ioctl;
-+ td->open = ntty_open;
-+ td->close = ntty_close;
-+ td->write = ntty_write;
-+ td->write_room = ntty_write_room;
-+ td->unthrottle = ntty_unthrottle;
-+ td->throttle = ntty_throttle;
-+ td->set_termios = ntty_set_termios;
-+ td->chars_in_buffer = ntty_chars_in_buffer;
-+ td->put_char = ntty_put_char;
-+
-+ rval = tty_register_driver(td);
-+
-+ if (rval) {
-+ printk(KERN_ERR "failed to register ntty tty driver");
-+ D1( "failed to register ntty tty driver");
-+ return rval;
-+ }
-+
-+ for (i = 0; i < NTTY_TTY_MINORS; i++) {
-+ init_MUTEX(&dc->port[i].tty_sem);
-+ dc->port[i].tty_open_count = 0;
-+ dc->port[i].tty = NULL;
-+
-+#ifdef KERNEL_2_6
-+ tty_register_device(td, i, NULL);
-+#endif
-+ }
-+
-+ printk(KERN_INFO DRIVER_DESC " " NOZOMI_NAME_TTY);
-+ D1( " ");
-+ return rval;
-+}
-+
-+/* Module initialization */
-+static struct pci_driver nozomi_driver = {
-+ .name = NOZOMI_NAME,
-+ .id_table = nozomi_pci_tbl,
-+ .probe = nozomi_card_init,
-+ .remove = __devexit_p(nozomi_card_exit),
-+};
-+
-+static int __init nozomi_init(void) {
-+ int rval = 0;
-+
-+ rval = pci_module_init(&nozomi_driver);
-+ printk(KERN_INFO "Initializing %s\n", VERSION_STRING);
-+ return rval;
-+}
-+
-+static void nozomi_exit(void) {
-+ printk(KERN_INFO "Unloading %s", DRIVER_DESC);
-+
-+ pci_unregister_driver(&nozomi_driver);
-+}
-+
-+module_init(nozomi_init);
-+module_exit(nozomi_exit);
-+
-+#ifdef NOZOMI_DEBUG
-+ MODULE_PARM(nzdebug, "i");
-+#endif
-+
-+MODULE_LICENSE("Dual BSD/GPL");
-+MODULE_DESCRIPTION( DRIVER_DESC );
diff --git a/recipes/linux/linux-mtx-1-2.4.27/42-usb-ohci-fixes.patch b/recipes/linux/linux-mtx-1-2.4.27/42-usb-ohci-fixes.patch
deleted file mode 100644
index aa5a0d45f7..0000000000
--- a/recipes/linux/linux-mtx-1-2.4.27/42-usb-ohci-fixes.patch
+++ /dev/null
@@ -1,51 +0,0 @@
---- linux/drivers/usb/host/usb-ohci.c.orig 2006-03-30 11:38:08.972225500 +0200
-+++ linux/drivers/usb/host/usb-ohci.c 2006-03-30 11:39:46.858343000 +0200
-@@ -104,6 +104,10 @@
-
- #define OHCI_UNLINK_TIMEOUT (HZ / 10)
-
-+static int ohci_delay = 3000;
-+MODULE_PARM(ohci_delay, "i");
-+MODULE_PARM_DESC(ohci_delay, "Wait time [ms] for OHCI to come up");
-+
- /*-------------------------------------------------------------------------*/
-
- /* AMD-756 (D2 rev) reports corrupt register contents in some cases.
-@@ -147,7 +151,7 @@
- ohci->complete_head = urb;
- ohci->complete_tail = urb;
- } else {
-- ohci->complete_head->hcpriv = urb;
-+ ohci->complete_tail->hcpriv = urb;
- ohci->complete_tail = urb;
- }
- }
-@@ -2587,12 +2591,12 @@
- hc_release_ohci (ohci);
- return -ENODEV;
- }
--
-+#if 0
- /* FIXME this is a second HC reset; why?? */
- writel (ohci->hc_control = OHCI_USB_RESET, &ohci->regs->control);
- (void)readl (&ohci->regs->intrdisable); /* PCI posting flush */
- wait_ms (10);
--
-+#endif
- usb_register_bus (ohci->bus);
-
- if (request_irq (irq, hc_interrupt, SA_SHIRQ,
-@@ -2668,6 +2672,13 @@
- void *mem_base;
- int status;
-
-+ printk ("waiting for ohci to come up\n");
-+ mdelay(ohci_delay);
-+ /* We have to wait for about four seconds for some devices to be available.
-+ * This may only be a matter of the Option Globetrotter Fusion,
-+ * that may need to much time to start up correctly. */
-+ printk ("ohci should be up\n");
-+
- if (pci_enable_device(dev) < 0)
- return -ENODEV;
-
diff --git a/recipes/linux/linux-mtx-1-2.4.27/43-usbserial-27-32-backport.diff b/recipes/linux/linux-mtx-1-2.4.27/43-usbserial-27-32-backport.diff
deleted file mode 100644
index 6a98f76c7a..0000000000
--- a/recipes/linux/linux-mtx-1-2.4.27/43-usbserial-27-32-backport.diff
+++ /dev/null
@@ -1,33 +0,0 @@
---- linux/drivers/usb/serial/usbserial.c-27 2006-06-27 10:26:06.294476250 +0200
-+++ linux/drivers/usb/serial/usbserial.c 2006-06-27 10:30:31.011020000 +0200
-@@ -528,8 +528,18 @@
- down(&port->sem);
- dbg("%s - port %d len %d backlog %d", __FUNCTION__,
- port->number, job->len, port->write_backlog);
-- if (port->tty != NULL)
-- __serial_write(port, 0, job->buff, job->len);
-+ if (port->tty != NULL) {
-+ int rc;
-+ int sent = 0;
-+ while (sent < job->len) {
-+ rc = __serial_write(port, 0, job->buff + sent, job->len - sent);
-+ if ((rc < 0) || signal_pending(current))
-+ break;
-+ sent += rc;
-+ if ((sent < job->len) && current->need_resched)
-+ schedule();
-+ }
-+ }
- up(&port->sem);
-
- spin_lock_irqsave(&post_lock, flags);
-@@ -725,6 +735,9 @@
- struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
- int rc;
-
-+ if (!port)
-+ return -ENODEV;
-+
- if (!in_interrupt()) {
- /*
- * Run post_list to reduce a possiblity of reordered writes.
diff --git a/recipes/linux/linux-mtx-1-2.4.27/45-acm-tty-and-sb2.patch b/recipes/linux/linux-mtx-1-2.4.27/45-acm-tty-and-sb2.patch
deleted file mode 100644
index 4561facb73..0000000000
--- a/recipes/linux/linux-mtx-1-2.4.27/45-acm-tty-and-sb2.patch
+++ /dev/null
@@ -1,721 +0,0 @@
---- linux/drivers/usb/acm.c-orig 2007-04-13 18:32:16.352672105 +0200
-+++ linux/drivers/usb/acm.c 2007-04-13 18:33:21.063526545 +0200
-@@ -124,6 +124,9 @@
- #define ACM_CTRL_PARITY 0x20
- #define ACM_CTRL_OVERRUN 0x40
-
-+// some devices don't have one comm and one data interface, but only one interface with endpoints for comm and data
-+#define SINGLE_IF_ACM 0x01
-+
- /*
- * Line speed and caracter encoding.
- */
-@@ -139,6 +142,8 @@
- * Internal driver structures.
- */
-
-+#define TD_SIZE 16384
-+
- struct acm {
- struct usb_device *dev; /* the coresponding usb device */
- struct usb_interface *iface; /* the interfaces - +0 control +1 data */
-@@ -153,12 +158,23 @@
- unsigned int minor; /* acm minor number */
- unsigned char throttle; /* throttled by tty layer */
- unsigned char clocal; /* termios CLOCAL */
-+ unsigned long throttle_start;
-+ unsigned char resubmit_to_unthrottle; /* Leftover data from last operation */
-+ unsigned char *throttle_data;
-+ int td_len;
-+ int td_busy;
-+ unsigned char used_interfaces;
-+ struct semaphore mutex;
- };
-
-+#define mutex_lock(x) down(x)
-+#define mutex_unlock(x) up(x)
-+
- /* global params controlling max sizes for read, write, control */
- static int maxszr = 0;
- static int maxszw = 0;
- static int maxszc = 0;
-+static int nonlegacy = 0;
-
- static struct usb_driver acm_driver;
- static struct tty_driver acm_tty_driver;
-@@ -167,6 +183,95 @@
- #define ACM_READY(acm) (acm && acm->dev && acm->used)
-
- /*
-+ * Helper functions to optimize throttleing
-+ */
-+static int
-+acm_fill_tty(struct urb *urb, struct tty_struct *tty, unsigned char *data, int length)
-+{
-+ struct acm *acm = urb->context;
-+ int n = 0;
-+ /*printk("acm_fill_tty: %d bytes\n", length);*/
-+ if (!urb->status && !acm->throttle) {
-+ for (n = 0; n < length && !acm->throttle; n++) {
-+ /* if we insert more than TTY_FLIPBUF_SIZE characters,
-+ * we drop them. */
-+ if (tty->flip.count >= TTY_FLIPBUF_SIZE) {
-+ tty_flip_buffer_push(tty);
-+ }
-+ tty_insert_flip_char(tty, data[n], 0);
-+ }
-+ tty_flip_buffer_push(tty);
-+ }
-+ /*printk("copied %d bytes.\n", n);*/
-+ return n;
-+}
-+
-+static int
-+acm_shift_if_throttle(unsigned char *data, int *length, int shift_by)
-+{
-+ if (shift_by < *length) {
-+ dbg("need to shift uncopied %d bytes to front.", *length - shift_by);
-+ memmove(data, data + shift_by, *length - shift_by);
-+ *length -= shift_by;
-+ return 1;
-+ }
-+ return 0;
-+}
-+
-+static int
-+acm_buffer_if_thottle(struct acm *acm, unsigned char *data, int start, int *length)
-+{
-+ int copied = *length;
-+ if (start < *length) {
-+ int space = TD_SIZE - acm->td_len;
-+ int needed = *length - start;
-+ copied = (space < needed)? space: needed;
-+ dbg("need to push %d to throttle buffer, can copy %d.",
-+ needed, copied);
-+ memcpy(acm->throttle_data + acm->td_len, data, copied);
-+ acm->td_len += copied;
-+ *length -= copied;
-+ }
-+ return copied;
-+}
-+
-+static int
-+acm_empty_throttle(struct urb *urb, struct tty_struct *tty)
-+{
-+ unsigned long flags;
-+ struct acm *acm = urb->context;
-+
-+ save_flags(flags);
-+ cli();
-+
-+ if (acm->td_busy) {
-+ restore_flags(flags);
-+ return 0;
-+ }
-+ acm->td_busy = 1;
-+ restore_flags(flags);
-+
-+ if (acm->td_len > 0) {
-+
-+ dbg("acm_empty_throttle: trying to empty throttle buffer: %d bytes.",
-+ acm->td_len);
-+
-+ /* if there has been something left from previous operations
-+ * we try to complete this before looking at the urb */
-+ int copied = acm_fill_tty(urb, tty, acm->throttle_data, acm->td_len);
-+ if (acm_shift_if_throttle(acm->throttle_data, &acm->td_len, copied)) {
-+ /* we were unable to empty the throttle data, so we can't
-+ * copy anything more now */
-+ acm->td_busy = 0;
-+ return 0;
-+ }
-+ acm->td_len = 0;
-+ }
-+ acm->td_busy = 0;
-+ return 1;
-+}
-+
-+/*
- * Functions for ACM control messages.
- */
-
-@@ -174,7 +279,10 @@
- {
- int retval = usb_control_msg(acm->dev, usb_sndctrlpipe(acm->dev, 0),
- request, USB_RT_ACM, value, acm->iface[0].altsetting[0].bInterfaceNumber, buf, len, HZ * 5);
-- dbg("acm_control_msg: rq: 0x%02x val: %#x len: %#x result: %d", request, value, len, retval);
-+ if (retval < 0)
-+ err("acm_control_msg: rq: 0x%02x val: %#x len: %#x result: %d", request, value, len, retval);
-+ else
-+ dbg("acm_control_msg: rq: 0x%02x val: %#x len: %#x result: %d", request, value, len, retval);
- return retval < 0 ? retval : 0;
- }
-
-@@ -191,10 +299,12 @@
- struct acm *acm = urb->context;
- struct usb_ctrlrequest *dr = urb->transfer_buffer;
- unsigned char *data = (unsigned char *)(dr + 1);
-- int newctrl;
-+ int newctrl, s1, s2;
-
- if (!ACM_READY(acm)) return;
-
-+ //err("acm_ctrl_irq %p %i", urb, dr->bRequestType);
-+
- if (urb->status < 0) {
- dbg("nonzero ctrl irq status received: %d", urb->status);
- return;
-@@ -226,8 +336,15 @@
-
- return;
-
-+ case 0x2a:
-+ s1 = le32_to_cpup((__u32 *) data);
-+ s2 = le32_to_cpup((__u32 *) (data+4));
-+
-+ dbg("acm.c: ctrl 0x2a: idx %i len %i speed %i %i", dr->wIndex, dr->wLength, s1, s2);
-+ return;
-+
- default:
-- dbg("unknown control event received: request %d index %d len %d data0 %d data1 %d",
-+ err("unknown control event received: request %d index %d len %d data0 %d data1 %d",
- dr->bRequest, dr->wIndex, dr->wLength, data[0], data[1]);
- return;
- }
-@@ -238,36 +355,39 @@
- struct acm *acm = urb->context;
- struct tty_struct *tty = acm->tty;
- unsigned char *data = urb->transfer_buffer;
-- int i = 0;
-+ int copied = 0;
-+ int buffered = 0;
-
- if (!ACM_READY(acm)) return;
-
-- if (urb->status)
-- dbg("nonzero read bulk status received: %d", urb->status);
-+ if (urb->status) {
-+ err("nonzero read bulk status received: %d", urb->status);
-+ }
-
-- if (!urb->status && !acm->throttle) {
-- for (i = 0; i < urb->actual_length && !acm->throttle; i++) {
-- /* if we insert more than TTY_FLIPBUF_SIZE characters,
-- * we drop them. */
-- if (tty->flip.count >= TTY_FLIPBUF_SIZE) {
-- tty_flip_buffer_push(tty);
-- }
-- tty_insert_flip_char(tty, data[i], 0);
-- }
-- tty_flip_buffer_push(tty);
-+ if (!acm_empty_throttle(urb, tty)) {
-+ dbg("could not empty throttle buffer, entering throttle state, acm->td_busy: %d.", acm->td_busy);
- }
-
-+ /* got here, either there was nothing in the throttle data or it could
-+ * all be copied without throttleing again */
-+ copied = acm_fill_tty(urb, tty, data, urb->actual_length);
- if (acm->throttle) {
-- memmove(data, data + i, urb->actual_length - i);
-- urb->actual_length -= i;
-- return;
-+ int length = urb->actual_length;
-+ buffered = acm_buffer_if_thottle(acm, data, copied, &urb->actual_length);
-+ if (buffered < length - copied
-+ && acm_shift_if_throttle(data, &urb->actual_length, copied + buffered)) {
-+ dbg("need to resubmit to unthrottle\n");
-+ acm->resubmit_to_unthrottle = 1;
-+ return;
-+ }
- }
-
- urb->actual_length = 0;
- urb->dev = acm->dev;
-
-- if (usb_submit_urb(urb))
-+ if (usb_submit_urb(urb)) {
- dbg("failed resubmitting read urb");
-+ }
- }
-
- static void acm_write_bulk(struct urb *urb)
-@@ -283,6 +403,9 @@
- mark_bh(IMMEDIATE_BH);
- }
-
-+static int unlinking_in_progress=0;
-+static int closing=0;
-+
- static void acm_softint(void *private)
- {
- struct acm *acm = private;
-@@ -306,34 +429,57 @@
-
- if (!acm || !acm->dev) return -EINVAL;
-
-+ mutex_lock (&acm->mutex);
-+
- tty->driver_data = acm;
- acm->tty = tty;
-
- MOD_INC_USE_COUNT;
-
-- lock_kernel();
-+ if ( closing )
-+ err("acm_tty_open: potential possibility of race condition detected");
-+
-+ if ( unlinking_in_progress ) {
-+ err("acm_tty_open: cannot open because unlinking_in_progress %i", acm->used);
-+ mutex_unlock (&acm->mutex);
-+ return -1;
-+ }
-
-- if (acm->used++) {
-- unlock_kernel();
-- return 0;
-- }
-+ if (acm->used) {
-+ acm->used++;
-+ mutex_unlock (&acm->mutex);
-+ return 0;
-+ }
-
-- unlock_kernel();
-+ unlinking_in_progress=1;
-+ err("acm_tty_open: %i %p !!", acm->used, tty);
-+
-+ acm->resubmit_to_unthrottle = 0;
-+ acm->td_len = 0;
-+ acm->td_busy = 0;
-
- acm->ctrlurb.dev = acm->dev;
- if (usb_submit_urb(&acm->ctrlurb))
-- dbg("usb_submit_urb(ctrl irq) failed");
-+ dbg("acm open: usb_submit_urb(ctrl irq) failed");
-+ else
-+ dbg("acm open: ctrlurb %p submitted", &acm->ctrlurb);
-+
-+ acm->used++;
-+ acm_set_control(acm, acm->ctrlout = ACM_CTRL_DTR | ACM_CTRL_RTS);
-
- acm->readurb.dev = acm->dev;
- if (usb_submit_urb(&acm->readurb))
-- dbg("usb_submit_urb(read bulk) failed");
--
-- acm_set_control(acm, acm->ctrlout = ACM_CTRL_DTR | ACM_CTRL_RTS);
-+ dbg("acm open: usb_submit_urb(read bulk) failed");
-+ else
-+ dbg("acm open: readurb %p submitted", &acm->readurb);
-
-- /* force low_latency on so that our tty_push actually forces the data through,
-+ /* force low_latency on so that our tty_push actually forces the data through,
- otherwise it is scheduled, and with high data rates data can get lost. */
- tty->low_latency = 1;
-
-+ unlinking_in_progress=0;
-+ mutex_unlock (&acm->mutex);
-+
- return 0;
- }
-
-@@ -343,19 +489,35 @@
-
- if (!acm || !acm->used) return;
-
-- if (!--acm->used) {
-- if (acm->dev) {
-- acm_set_control(acm, acm->ctrlout = 0);
-- usb_unlink_urb(&acm->ctrlurb);
-- usb_unlink_urb(&acm->writeurb);
-- usb_unlink_urb(&acm->readurb);
-- } else {
-- tty_unregister_devfs(&acm_tty_driver, acm->minor);
-- acm_table[acm->minor] = NULL;
-- kfree(acm);
-- }
-+ mutex_lock (&acm->mutex);
-+
-+ closing = 1;
-+ if (--acm->used) {
-+ closing=0;
-+ MOD_DEC_USE_COUNT;
-+ mutex_unlock (&acm->mutex);
-+ return;
-+ }
-+ unlinking_in_progress = 1;
-+
-+ err("acm_tty_close: %i %p", acm->used, tty);
-+
-+ if (acm->dev) {
-+ acm_set_control(acm, acm->ctrlout = 0);
-+ usb_unlink_urb(&acm->ctrlurb);
-+ usb_unlink_urb(&acm->writeurb);
-+ usb_unlink_urb(&acm->readurb);
-+ } else {
-+ tty_unregister_devfs(&acm_tty_driver, acm->minor);
-+ acm_table[acm->minor] = NULL;
-+ kfree(acm->throttle_data);
-+ kfree(acm);
- }
-+
-+ closing=0;
-+ unlinking_in_progress = 0;
- MOD_DEC_USE_COUNT;
-+ mutex_unlock (&acm->mutex);
- }
-
- static int acm_tty_write(struct tty_struct *tty, int from_user, const unsigned char *buf, int count)
-@@ -363,8 +525,16 @@
- struct acm *acm = tty->driver_data;
-
- if (!ACM_READY(acm)) return -EINVAL;
-- if (acm->writeurb.status == -EINPROGRESS) return 0;
-- if (!count) return 0;
-+
-+ if (acm->writeurb.status == -EINPROGRESS) {
-+ dbg("tty_write in progress");
-+ return 0;
-+ }
-+
-+ if (!count) {
-+ dbg("tty_write: nothing to write");
-+ return 0;
-+ }
-
- count = (count > acm->writesize) ? acm->writesize : count;
-
-@@ -401,22 +571,44 @@
- {
- struct acm *acm = tty->driver_data;
- if (!ACM_READY(acm)) return;
-+ dbg("acm_tty_throttle ON %ld ---> %ld", jiffies-acm->throttle_start, jiffies);
- acm->throttle = 1;
-+ acm->throttle_start = jiffies;
- }
-
- static void acm_tty_unthrottle(struct tty_struct *tty)
- {
- struct acm *acm = tty->driver_data;
- if (!ACM_READY(acm)) return;
-+ dbg("acm_tty_throttle OFF %ld ---> %ld", jiffies, jiffies-acm->throttle_start);
- acm->throttle = 0;
-- if (acm->readurb.status != -EINPROGRESS)
-+
-+ if (!acm_empty_throttle(&acm->readurb, tty)) {
-+ if (acm->td_busy) {
-+ printk("***** pending acm_empty_throttle!\n");
-+ } else {
-+ dbg("throttle not emptied.\n");
-+ }
-+ }
-+
-+ if (acm->resubmit_to_unthrottle != 0) {
-+ dbg("resubmit_to_unthrottle: acm_read_bulk");
-+ acm->resubmit_to_unthrottle = 0;
- acm_read_bulk(&acm->readurb);
-+ }
- }
-
- static void acm_tty_break_ctl(struct tty_struct *tty, int state)
- {
- struct acm *acm = tty->driver_data;
-+
- if (!ACM_READY(acm)) return;
-+
-+ if (nonlegacy) {
-+ err("non-legacy port, skipping acm_tty_break_ctl");
-+ return;
-+ }
-+
- if (acm_send_break(acm, state ? 0xffff : 0))
- dbg("send break failed");
- }
-@@ -455,7 +647,19 @@
- case TIOCMBIC: newctrl &= ~mask; break;
- }
-
-- if (acm->ctrlout == newctrl) return 0;
-+ if (acm->ctrlout == newctrl) {
-+ dbg("acm_tty_ioctl: set old state %x", newctrl);
-+ return 0;
-+ }
-+
-+ err("acm_tty_ioctl: %s%s%s -> dtr%s rts%s (%lx)",
-+ cmd==TIOCMBIC?"Clear":(cmd==TIOCMBIS?"Set":"SET"),
-+ mask & ACM_CTRL_DTR ? " DTR":"",
-+ mask & ACM_CTRL_RTS ? " RTS":"",
-+ newctrl & ACM_CTRL_DTR ? "+":"-",
-+ newctrl & ACM_CTRL_RTS ? "+":"-",
-+ arg);
-+
- return acm_set_control(acm, acm->ctrlout = newctrl);
- }
-
-@@ -483,6 +687,12 @@
-
- if (!ACM_READY(acm)) return;
-
-+ if (nonlegacy) {
-+ acm->clocal = ((termios->c_cflag & CLOCAL) != 0);
-+ dbg("non-legacy port, skipping acm_tty_set_termios");
-+ return;
-+ }
-+
- newline.speed = cpu_to_le32p(acm_tty_speed +
- (termios->c_cflag & CBAUD & ~CBAUDEX) + (termios->c_cflag & CBAUDEX ? 15 : 0));
- newline.stopbits = termios->c_cflag & CSTOPB ? 2 : 0;
-@@ -518,34 +727,64 @@
- struct usb_config_descriptor *cfacm;
- struct usb_interface_descriptor *ifcom, *ifdata;
- struct usb_endpoint_descriptor *epctrl, *epread, *epwrite;
-- int readsize, ctrlsize, minor, i, j;
-+ int readsize, ctrlsize, minor, i;
- unsigned char *buf;
-+ unsigned char used_interfaces=2;
-
- for (i = 0; i < dev->descriptor.bNumConfigurations; i++) {
-
- cfacm = dev->config + i;
-
-- dbg("probing config %d", cfacm->bConfigurationValue);
-+ ifcom = cfacm->interface[ifnum].altsetting + 0;
-+
-+ if (id->driver_info == SINGLE_IF_ACM) {
-+ printk("using single_if_acm\n");
-+ struct usb_endpoint_descriptor *ep=ifcom->endpoint;
-+ int k;
-+
-+ if (ifcom->bNumEndpoints != 3) {
-+ continue;
-+ }
-+
-+ epctrl = epread = epwrite = NULL;
-+ for (k=0; k<3; ++k, ++ep) {
-+ if ((ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT &&
-+ (ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN) {
-+ epctrl = ep;
-+ } else if ((ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_BULK &&
-+ (ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN) {
-+ epread = ep;
-+ } else if ( (ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_BULK) {
-+ epwrite = ep;
-+ }
-+ }
-
-- for (j = 0; j < cfacm->bNumInterfaces - 1; j++) {
-+ if ( !epctrl || !epread || !epwrite ) {
-+ dbg("SINGLE_IF_ACM acm_probe inv eps epctrl %s epread %s epwrite %s", epctrl?"ok":"missing",
-+ epread?"ok":"missing", epwrite?"ok":"missing");
-+ dbg("SINGLE_IF_ACM Invalid enpoint configuration");
-+ continue;
-+ }
-
-- if (usb_interface_claimed(cfacm->interface + j) ||
-- usb_interface_claimed(cfacm->interface + j + 1))
-+ used_interfaces = 1;
-+ } else {
-+ if ((ifnum+1)>=cfacm->bNumInterfaces || usb_interface_claimed(cfacm->interface + ifnum + 1)) {
-+ // no data interface available
- continue;
-+ }
-
-- ifcom = cfacm->interface[j].altsetting + 0;
-- ifdata = cfacm->interface[j + 1].altsetting + 0;
-+ ifdata = cfacm->interface[ifnum + 1].altsetting + 0;
-
- if (ifdata->bInterfaceClass != 10 || ifdata->bNumEndpoints < 2) {
-- ifcom = cfacm->interface[j + 1].altsetting + 0;
-- ifdata = cfacm->interface[j].altsetting + 0;
-+ ifcom = cfacm->interface[ifnum + 1].altsetting + 0;
-+ ifdata = cfacm->interface[ifnum].altsetting + 0;
- if (ifdata->bInterfaceClass != 10 || ifdata->bNumEndpoints < 2)
- continue;
- }
-
- if (ifcom->bInterfaceClass != 2 || ifcom->bInterfaceSubClass != 2 ||
-- ifcom->bInterfaceProtocol < 1 || ifcom->bInterfaceProtocol > 6 ||
-- ifcom->bNumEndpoints < 1)
-+ ifcom->bInterfaceProtocol < 1 || ifcom->bInterfaceProtocol > 6 ||
-+ ifcom->bNumEndpoints < 1)
- continue;
-
- epctrl = ifcom->endpoint + 0;
-@@ -553,76 +792,86 @@
- epwrite = ifdata->endpoint + 1;
-
- if ((epctrl->bEndpointAddress & 0x80) != 0x80 || (epctrl->bmAttributes & 3) != 3 ||
-- (epread->bmAttributes & 3) != 2 || (epwrite->bmAttributes & 3) != 2 ||
-- ((epread->bEndpointAddress & 0x80) ^ (epwrite->bEndpointAddress & 0x80)) != 0x80)
-+ (epread->bmAttributes & 3) != 2 || (epwrite->bmAttributes & 3) != 2 ||
-+ ((epread->bEndpointAddress & 0x80) ^ (epwrite->bEndpointAddress & 0x80)) != 0x80)
- continue;
-
-- dbg("using interface %d\n", j);
--
- if ((epread->bEndpointAddress & 0x80) != 0x80) {
- epread = ifdata->endpoint + 1;
- epwrite = ifdata->endpoint + 0;
- }
-+ }
-
-- usb_set_configuration(dev, cfacm->bConfigurationValue);
-+ usb_set_configuration(dev, cfacm->bConfigurationValue);
-
-- for (minor = 0; minor < ACM_TTY_MINORS && acm_table[minor]; minor++);
-- if (acm_table[minor]) {
-- err("no more free acm devices");
-- return NULL;
-- }
-+ for (minor = 0; minor < ACM_TTY_MINORS && acm_table[minor]; minor++);
-+ if (acm_table[minor]) {
-+ err("no more free acm devices");
-+ return NULL;
-+ }
-
-- if (!(acm = kmalloc(sizeof(struct acm), GFP_KERNEL))) {
-- err("out of memory");
-- return NULL;
-- }
-- memset(acm, 0, sizeof(struct acm));
-+ if (!(acm = kmalloc(sizeof(struct acm), GFP_KERNEL))) {
-+ err("out of memory");
-+ return NULL;
-+ }
-+ memset(acm, 0, sizeof(struct acm));
-
-- ctrlsize = (epctrl->wMaxPacketSize > maxszc)?
-- epctrl->wMaxPacketSize: maxszc;
-- readsize = (epread->wMaxPacketSize > maxszr)?
-- epread->wMaxPacketSize: maxszr;
-- acm->writesize = (epwrite->wMaxPacketSize > maxszw)?
-- epwrite->wMaxPacketSize: maxszw;
--
-- acm->iface = cfacm->interface + j;
-- acm->minor = minor;
-- acm->dev = dev;
--
-- acm->tqueue.routine = acm_softint;
-- acm->tqueue.data = acm;
--
-- if (!(buf = kmalloc(ctrlsize + readsize + acm->writesize, GFP_KERNEL))) {
-- err("out of memory");
-- kfree(acm);
-- return NULL;
-- }
-+ ctrlsize = (epctrl->wMaxPacketSize > maxszc)?
-+ epctrl->wMaxPacketSize: maxszc;
-+ readsize = (epread->wMaxPacketSize > maxszr)?
-+ epread->wMaxPacketSize: maxszr;
-+ acm->writesize = (epwrite->wMaxPacketSize > maxszw)?
-+ epwrite->wMaxPacketSize: maxszw;
-+
-+ init_MUTEX (&acm->mutex);
-+ if (!(acm->throttle_data = kmalloc(TD_SIZE * sizeof (*acm->throttle_data), GFP_KERNEL))) {
-+ err("out of memory (throttle_data)");
-+ kfree(acm);
-+ return NULL;
-+ }
-+ acm->iface = cfacm->interface + ifnum;
-+ acm->minor = minor;
-+ acm->dev = dev;
-
-- FILL_INT_URB(&acm->ctrlurb, dev, usb_rcvintpipe(dev, epctrl->bEndpointAddress),
-- buf, ctrlsize, acm_ctrl_irq, acm, epctrl->bInterval);
-+ acm->used_interfaces = used_interfaces;
-
-- FILL_BULK_URB(&acm->readurb, dev, usb_rcvbulkpipe(dev, epread->bEndpointAddress),
-- buf += ctrlsize, readsize, acm_read_bulk, acm);
-- acm->readurb.transfer_flags |= USB_NO_FSBR;
-+ acm->tqueue.routine = acm_softint;
-+ acm->tqueue.data = acm;
-
-- FILL_BULK_URB(&acm->writeurb, dev, usb_sndbulkpipe(dev, epwrite->bEndpointAddress),
-- buf += readsize, acm->writesize, acm_write_bulk, acm);
-- acm->writeurb.transfer_flags |= USB_NO_FSBR;
-+ if (!(buf = kmalloc(ctrlsize + readsize + acm->writesize, GFP_KERNEL))) {
-+ err("out of memory (urb buf)");
-+ kfree(acm);
-+ return NULL;
-+ }
-
-- printk(KERN_INFO "ttyACM%d: USB ACM device\n", minor);
-+ FILL_INT_URB(&acm->ctrlurb, dev, usb_rcvintpipe(dev, epctrl->bEndpointAddress),
-+ buf, ctrlsize, acm_ctrl_irq, acm, epctrl->bInterval);
-
-- acm_set_control(acm, acm->ctrlout);
-+ FILL_BULK_URB(&acm->readurb, dev, usb_rcvbulkpipe(dev, epread->bEndpointAddress),
-+ buf += ctrlsize, readsize, acm_read_bulk, acm);
-+ acm->readurb.transfer_flags |= USB_NO_FSBR;
-
-- acm->line.speed = cpu_to_le32(9600);
-- acm->line.databits = 8;
-- acm_set_line(acm, &acm->line);
-+ FILL_BULK_URB(&acm->writeurb, dev, usb_sndbulkpipe(dev, epwrite->bEndpointAddress),
-+ buf += readsize, acm->writesize, acm_write_bulk, acm);
-+ acm->writeurb.transfer_flags |= USB_NO_FSBR;
-
-- usb_driver_claim_interface(&acm_driver, acm->iface + 0, acm);
-- usb_driver_claim_interface(&acm_driver, acm->iface + 1, acm);
-+ printk(KERN_INFO "ttyACM%d: USB ACM device C %p W %p R %p %x\n", minor, &acm->ctrlurb,
-+ &acm->writeurb, &acm->readurb, acm->ctrlout);
-+
-+ acm_set_control(acm, acm->ctrlout);
-
-- tty_register_devfs(&acm_tty_driver, 0, minor);
-- return acm_table[minor] = acm;
-+ acm->line.speed = cpu_to_le32(9600);
-+ acm->line.databits = 8;
-+ acm_set_line(acm, &acm->line);
-+
-+ if ( acm->used_interfaces == 2 ) {
-+ // only just checked interface is claimed automatically, so claim data interface too
-+ usb_driver_claim_interface(&acm_driver, acm->iface + 1, acm);
- }
-+
-+ tty_register_devfs(&acm_tty_driver, 0, minor);
-+
-+ return acm_table[minor] = acm;
- }
-
- return NULL;
-@@ -646,7 +895,9 @@
- kfree(acm->ctrlurb.transfer_buffer);
-
- usb_driver_release_interface(&acm_driver, acm->iface + 0);
-- usb_driver_release_interface(&acm_driver, acm->iface + 1);
-+ if ( acm->used_interfaces == 2 ) {
-+ usb_driver_release_interface(&acm_driver, acm->iface + 1);
-+ }
-
- if (!acm->used) {
- tty_unregister_devfs(&acm_tty_driver, acm->minor);
-@@ -665,6 +916,9 @@
-
- static struct usb_device_id acm_ids[] = {
- { USB_DEVICE(0x22B8, 0x1005) }, /* Motorola TimePort 280 */
-+ { USB_DEVICE(0x05C6, 0x7001), driver_info: SINGLE_IF_ACM }, /* Siemens HC15/HC25 */
-+ { USB_DEVICE(0x0681, 0x003e), driver_info: SINGLE_IF_ACM }, /* Siemens HC15/HC25 */
-+ { USB_DEVICE(0x22B8, 0x1006) },
- { USB_DEVICE_INFO(USB_CLASS_COMM, 0, 0) },
- { USB_DEVICE_INFO(USB_CLASS_COMM, 2, 0) },
- { }
-@@ -735,7 +989,7 @@
- return -1;
- }
-
-- info(DRIVER_VERSION ":" DRIVER_DESC);
-+ info(DRIVER_VERSION ":" DRIVER_DESC "(non-legacy %d)", nonlegacy);
-
- return 0;
- }
-@@ -759,7 +1013,9 @@
- MODULE_PARM(maxszc, "i");
- MODULE_PARM_DESC(maxszc, "User specified USB endpoint control size");
-
-+MODULE_PARM(nonlegacy, "i");
-+MODULE_PARM_DESC(nonlegacy, "Set this to 1 to for use with non-legacy device");
-+
- MODULE_AUTHOR( DRIVER_AUTHOR );
- MODULE_DESCRIPTION( DRIVER_DESC );
- MODULE_LICENSE("GPL");
--
diff --git a/recipes/linux/linux-mtx-1-2.4.27/48-pptp.patch b/recipes/linux/linux-mtx-1-2.4.27/48-pptp.patch
deleted file mode 100644
index 5896f90370..0000000000
--- a/recipes/linux/linux-mtx-1-2.4.27/48-pptp.patch
+++ /dev/null
@@ -1,5092 +0,0 @@
-diff -uNr linux_org/Documentation/Configure.help linux/Documentation/Configure.help
---- linux_org/Documentation/Configure.help 2006-10-27 14:08:20.000000000 +0200
-+++ linux/Documentation/Configure.help 2006-10-27 14:11:52.000000000 +0200
-@@ -2848,6 +2848,31 @@
- If you want to compile it as a module, say M here and read
- <file:Documentation/modules.txt>. If unsure, say `Y'.
-
-+PPTP conntrack and NAT support
-+CONFIG_IP_NF_PPTP
-+ This module adds support for PPTP (Point to Point Tunnelling Protocol,
-+ RFC2637) conncection tracking and NAT.
-+
-+ If you are running PPTP sessions over a stateful firewall or NAT box,
-+ you may want to enable this feature.
-+
-+ Please note that not all PPTP modes of operation are supported yet.
-+ For more info, read top of the file net/ipv4/netfilter/ip_conntrack_pptp.c
-+
-+ If you want to compile it as a module, say M here and read
-+ Documentation/modules.txt. If unsure, say `N'.
-+
-+GRE protocol conntrack and NAT support
-+CONFIG_IP_NF_CT_PROTO_GRE
-+ This module adds generic support for connection tracking and NAT of the
-+ GRE protocol (RFC1701, RFC2784). Please note that this will only work
-+ with GRE connections using the key field of the GRE header.
-+
-+ You will need GRE support to enable PPTP support.
-+
-+ If you want to compile it as a module, say `M' here and read
-+ Documentation/modules.txt. If unsire, say `N'.
-+
- User space queueing via NETLINK
- CONFIG_IP_NF_QUEUE
- Netfilter has the ability to queue packets to user space: the
-diff -uNr linux_org/include/linux/netfilter_ipv4/ip_conntrack.h linux/include/linux/netfilter_ipv4/ip_conntrack.h
---- linux_org/include/linux/netfilter_ipv4/ip_conntrack.h 2004-11-24 12:13:57.000000000 +0100
-+++ linux/include/linux/netfilter_ipv4/ip_conntrack.h 2006-10-27 14:11:52.000000000 +0200
-@@ -50,19 +50,23 @@
-
- #include <linux/netfilter_ipv4/ip_conntrack_tcp.h>
- #include <linux/netfilter_ipv4/ip_conntrack_icmp.h>
-+#include <linux/netfilter_ipv4/ip_conntrack_proto_gre.h>
-
- /* per conntrack: protocol private data */
- union ip_conntrack_proto {
- /* insert conntrack proto private data here */
-+ struct ip_ct_gre gre;
- struct ip_ct_tcp tcp;
- struct ip_ct_icmp icmp;
- };
-
- union ip_conntrack_expect_proto {
- /* insert expect proto private data here */
-+ struct ip_ct_gre_expect gre;
- };
-
- /* Add protocol helper include file here */
-+#include <linux/netfilter_ipv4/ip_conntrack_pptp.h>
- #include <linux/netfilter_ipv4/ip_conntrack_amanda.h>
-
- #include <linux/netfilter_ipv4/ip_conntrack_ftp.h>
-@@ -71,6 +75,7 @@
- /* per expectation: application helper private data */
- union ip_conntrack_expect_help {
- /* insert conntrack helper private data (expect) here */
-+ struct ip_ct_pptp_expect exp_pptp_info;
- struct ip_ct_amanda_expect exp_amanda_info;
- struct ip_ct_ftp_expect exp_ftp_info;
- struct ip_ct_irc_expect exp_irc_info;
-@@ -85,16 +90,19 @@
- /* per conntrack: application helper private data */
- union ip_conntrack_help {
- /* insert conntrack helper private data (master) here */
-+ struct ip_ct_pptp_master ct_pptp_info;
- struct ip_ct_ftp_master ct_ftp_info;
- struct ip_ct_irc_master ct_irc_info;
- };
-
- #ifdef CONFIG_IP_NF_NAT_NEEDED
- #include <linux/netfilter_ipv4/ip_nat.h>
-+#include <linux/netfilter_ipv4/ip_nat_pptp.h>
-
- /* per conntrack: nat application helper private data */
- union ip_conntrack_nat_help {
- /* insert nat helper private data here */
-+ struct ip_nat_pptp nat_pptp_info;
- };
- #endif
-
-diff -uNr linux_org/include/linux/netfilter_ipv4/ip_conntrack_pptp.h linux/include/linux/netfilter_ipv4/ip_conntrack_pptp.h
---- linux_org/include/linux/netfilter_ipv4/ip_conntrack_pptp.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux/include/linux/netfilter_ipv4/ip_conntrack_pptp.h 2006-10-27 14:11:52.000000000 +0200
-@@ -0,0 +1,313 @@
-+/* PPTP constants and structs */
-+#ifndef _CONNTRACK_PPTP_H
-+#define _CONNTRACK_PPTP_H
-+
-+/* state of the control session */
-+enum pptp_ctrlsess_state {
-+ PPTP_SESSION_NONE, /* no session present */
-+ PPTP_SESSION_ERROR, /* some session error */
-+ PPTP_SESSION_STOPREQ, /* stop_sess request seen */
-+ PPTP_SESSION_REQUESTED, /* start_sess request seen */
-+ PPTP_SESSION_CONFIRMED, /* session established */
-+};
-+
-+/* state of the call inside the control session */
-+enum pptp_ctrlcall_state {
-+ PPTP_CALL_NONE,
-+ PPTP_CALL_ERROR,
-+ PPTP_CALL_OUT_REQ,
-+ PPTP_CALL_OUT_CONF,
-+ PPTP_CALL_IN_REQ,
-+ PPTP_CALL_IN_REP,
-+ PPTP_CALL_IN_CONF,
-+ PPTP_CALL_CLEAR_REQ,
-+};
-+
-+
-+/* conntrack private data */
-+struct ip_ct_pptp_master {
-+ enum pptp_ctrlsess_state sstate; /* session state */
-+
-+ /* everything below is going to be per-expectation in newnat,
-+ * since there could be more than one call within one session */
-+ enum pptp_ctrlcall_state cstate; /* call state */
-+ u_int16_t pac_call_id; /* call id of PAC, host byte order */
-+ u_int16_t pns_call_id; /* call id of PNS, host byte order */
-+};
-+
-+/* conntrack_expect private member */
-+struct ip_ct_pptp_expect {
-+ enum pptp_ctrlcall_state cstate; /* call state */
-+ u_int16_t pac_call_id; /* call id of PAC */
-+ u_int16_t pns_call_id; /* call id of PNS */
-+};
-+
-+
-+#ifdef __KERNEL__
-+
-+#include <linux/netfilter_ipv4/lockhelp.h>
-+DECLARE_LOCK_EXTERN(ip_pptp_lock);
-+
-+#define IP_CONNTR_PPTP PPTP_CONTROL_PORT
-+
-+union pptp_ctrl_union {
-+ void *rawreq;
-+ struct PptpStartSessionRequest *sreq;
-+ struct PptpStartSessionReply *srep;
-+ struct PptpStopSessionReqest *streq;
-+ struct PptpStopSessionReply *strep;
-+ struct PptpOutCallRequest *ocreq;
-+ struct PptpOutCallReply *ocack;
-+ struct PptpInCallRequest *icreq;
-+ struct PptpInCallReply *icack;
-+ struct PptpInCallConnected *iccon;
-+ struct PptpClearCallRequest *clrreq;
-+ struct PptpCallDisconnectNotify *disc;
-+ struct PptpWanErrorNotify *wanerr;
-+ struct PptpSetLinkInfo *setlink;
-+};
-+
-+
-+
-+#define PPTP_CONTROL_PORT 1723
-+
-+#define PPTP_PACKET_CONTROL 1
-+#define PPTP_PACKET_MGMT 2
-+
-+#define PPTP_MAGIC_COOKIE 0x1a2b3c4d
-+
-+struct pptp_pkt_hdr {
-+ __u16 packetLength;
-+ __u16 packetType;
-+ __u32 magicCookie;
-+};
-+
-+/* PptpControlMessageType values */
-+#define PPTP_START_SESSION_REQUEST 1
-+#define PPTP_START_SESSION_REPLY 2
-+#define PPTP_STOP_SESSION_REQUEST 3
-+#define PPTP_STOP_SESSION_REPLY 4
-+#define PPTP_ECHO_REQUEST 5
-+#define PPTP_ECHO_REPLY 6
-+#define PPTP_OUT_CALL_REQUEST 7
-+#define PPTP_OUT_CALL_REPLY 8
-+#define PPTP_IN_CALL_REQUEST 9
-+#define PPTP_IN_CALL_REPLY 10
-+#define PPTP_IN_CALL_CONNECT 11
-+#define PPTP_CALL_CLEAR_REQUEST 12
-+#define PPTP_CALL_DISCONNECT_NOTIFY 13
-+#define PPTP_WAN_ERROR_NOTIFY 14
-+#define PPTP_SET_LINK_INFO 15
-+
-+#define PPTP_MSG_MAX 15
-+
-+/* PptpGeneralError values */
-+#define PPTP_ERROR_CODE_NONE 0
-+#define PPTP_NOT_CONNECTED 1
-+#define PPTP_BAD_FORMAT 2
-+#define PPTP_BAD_VALUE 3
-+#define PPTP_NO_RESOURCE 4
-+#define PPTP_BAD_CALLID 5
-+#define PPTP_REMOVE_DEVICE_ERROR 6
-+
-+struct PptpControlHeader {
-+ __u16 messageType;
-+ __u16 reserved;
-+};
-+
-+/* FramingCapability Bitmap Values */
-+#define PPTP_FRAME_CAP_ASYNC 0x1
-+#define PPTP_FRAME_CAP_SYNC 0x2
-+
-+/* BearerCapability Bitmap Values */
-+#define PPTP_BEARER_CAP_ANALOG 0x1
-+#define PPTP_BEARER_CAP_DIGITAL 0x2
-+
-+struct PptpStartSessionRequest {
-+ __u16 protocolVersion;
-+ __u8 reserved1;
-+ __u8 reserved2;
-+ __u32 framingCapability;
-+ __u32 bearerCapability;
-+ __u16 maxChannels;
-+ __u16 firmwareRevision;
-+ __u8 hostName[64];
-+ __u8 vendorString[64];
-+};
-+
-+/* PptpStartSessionResultCode Values */
-+#define PPTP_START_OK 1
-+#define PPTP_START_GENERAL_ERROR 2
-+#define PPTP_START_ALREADY_CONNECTED 3
-+#define PPTP_START_NOT_AUTHORIZED 4
-+#define PPTP_START_UNKNOWN_PROTOCOL 5
-+
-+struct PptpStartSessionReply {
-+ __u16 protocolVersion;
-+ __u8 resultCode;
-+ __u8 generalErrorCode;
-+ __u32 framingCapability;
-+ __u32 bearerCapability;
-+ __u16 maxChannels;
-+ __u16 firmwareRevision;
-+ __u8 hostName[64];
-+ __u8 vendorString[64];
-+};
-+
-+/* PptpStopReasons */
-+#define PPTP_STOP_NONE 1
-+#define PPTP_STOP_PROTOCOL 2
-+#define PPTP_STOP_LOCAL_SHUTDOWN 3
-+
-+struct PptpStopSessionRequest {
-+ __u8 reason;
-+};
-+
-+/* PptpStopSessionResultCode */
-+#define PPTP_STOP_OK 1
-+#define PPTP_STOP_GENERAL_ERROR 2
-+
-+struct PptpStopSessionReply {
-+ __u8 resultCode;
-+ __u8 generalErrorCode;
-+};
-+
-+struct PptpEchoRequest {
-+ __u32 identNumber;
-+};
-+
-+/* PptpEchoReplyResultCode */
-+#define PPTP_ECHO_OK 1
-+#define PPTP_ECHO_GENERAL_ERROR 2
-+
-+struct PptpEchoReply {
-+ __u32 identNumber;
-+ __u8 resultCode;
-+ __u8 generalErrorCode;
-+ __u16 reserved;
-+};
-+
-+/* PptpFramingType */
-+#define PPTP_ASYNC_FRAMING 1
-+#define PPTP_SYNC_FRAMING 2
-+#define PPTP_DONT_CARE_FRAMING 3
-+
-+/* PptpCallBearerType */
-+#define PPTP_ANALOG_TYPE 1
-+#define PPTP_DIGITAL_TYPE 2
-+#define PPTP_DONT_CARE_BEARER_TYPE 3
-+
-+struct PptpOutCallRequest {
-+ __u16 callID;
-+ __u16 callSerialNumber;
-+ __u32 minBPS;
-+ __u32 maxBPS;
-+ __u32 bearerType;
-+ __u32 framingType;
-+ __u16 packetWindow;
-+ __u16 packetProcDelay;
-+ __u16 reserved1;
-+ __u16 phoneNumberLength;
-+ __u16 reserved2;
-+ __u8 phoneNumber[64];
-+ __u8 subAddress[64];
-+};
-+
-+/* PptpCallResultCode */
-+#define PPTP_OUTCALL_CONNECT 1
-+#define PPTP_OUTCALL_GENERAL_ERROR 2
-+#define PPTP_OUTCALL_NO_CARRIER 3
-+#define PPTP_OUTCALL_BUSY 4
-+#define PPTP_OUTCALL_NO_DIAL_TONE 5
-+#define PPTP_OUTCALL_TIMEOUT 6
-+#define PPTP_OUTCALL_DONT_ACCEPT 7
-+
-+struct PptpOutCallReply {
-+ __u16 callID;
-+ __u16 peersCallID;
-+ __u8 resultCode;
-+ __u8 generalErrorCode;
-+ __u16 causeCode;
-+ __u32 connectSpeed;
-+ __u16 packetWindow;
-+ __u16 packetProcDelay;
-+ __u32 physChannelID;
-+};
-+
-+struct PptpInCallRequest {
-+ __u16 callID;
-+ __u16 callSerialNumber;
-+ __u32 callBearerType;
-+ __u32 physChannelID;
-+ __u16 dialedNumberLength;
-+ __u16 dialingNumberLength;
-+ __u8 dialedNumber[64];
-+ __u8 dialingNumber[64];
-+ __u8 subAddress[64];
-+};
-+
-+/* PptpInCallResultCode */
-+#define PPTP_INCALL_ACCEPT 1
-+#define PPTP_INCALL_GENERAL_ERROR 2
-+#define PPTP_INCALL_DONT_ACCEPT 3
-+
-+struct PptpInCallReply {
-+ __u16 callID;
-+ __u16 peersCallID;
-+ __u8 resultCode;
-+ __u8 generalErrorCode;
-+ __u16 packetWindow;
-+ __u16 packetProcDelay;
-+ __u16 reserved;
-+};
-+
-+struct PptpInCallConnected {
-+ __u16 peersCallID;
-+ __u16 reserved;
-+ __u32 connectSpeed;
-+ __u16 packetWindow;
-+ __u16 packetProcDelay;
-+ __u32 callFramingType;
-+};
-+
-+struct PptpClearCallRequest {
-+ __u16 callID;
-+ __u16 reserved;
-+};
-+
-+struct PptpCallDisconnectNotify {
-+ __u16 callID;
-+ __u8 resultCode;
-+ __u8 generalErrorCode;
-+ __u16 causeCode;
-+ __u16 reserved;
-+ __u8 callStatistics[128];
-+};
-+
-+struct PptpWanErrorNotify {
-+ __u16 peersCallID;
-+ __u16 reserved;
-+ __u32 crcErrors;
-+ __u32 framingErrors;
-+ __u32 hardwareOverRuns;
-+ __u32 bufferOverRuns;
-+ __u32 timeoutErrors;
-+ __u32 alignmentErrors;
-+};
-+
-+struct PptpSetLinkInfo {
-+ __u16 peersCallID;
-+ __u16 reserved;
-+ __u32 sendAccm;
-+ __u32 recvAccm;
-+};
-+
-+
-+struct pptp_priv_data {
-+ __u16 call_id;
-+ __u16 mcall_id;
-+ __u16 pcall_id;
-+};
-+
-+#endif /* __KERNEL__ */
-+#endif /* _CONNTRACK_PPTP_H */
-diff -uNr linux_org/include/linux/netfilter_ipv4/ip_conntrack_proto_gre.h linux/include/linux/netfilter_ipv4/ip_conntrack_proto_gre.h
---- linux_org/include/linux/netfilter_ipv4/ip_conntrack_proto_gre.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux/include/linux/netfilter_ipv4/ip_conntrack_proto_gre.h 2006-10-27 14:11:52.000000000 +0200
-@@ -0,0 +1,123 @@
-+#ifndef _CONNTRACK_PROTO_GRE_H
-+#define _CONNTRACK_PROTO_GRE_H
-+#include <asm/byteorder.h>
-+
-+/* GRE PROTOCOL HEADER */
-+
-+/* GRE Version field */
-+#define GRE_VERSION_1701 0x0
-+#define GRE_VERSION_PPTP 0x1
-+
-+/* GRE Protocol field */
-+#define GRE_PROTOCOL_PPTP 0x880B
-+
-+/* GRE Flags */
-+#define GRE_FLAG_C 0x80
-+#define GRE_FLAG_R 0x40
-+#define GRE_FLAG_K 0x20
-+#define GRE_FLAG_S 0x10
-+#define GRE_FLAG_A 0x80
-+
-+#define GRE_IS_C(f) ((f)&GRE_FLAG_C)
-+#define GRE_IS_R(f) ((f)&GRE_FLAG_R)
-+#define GRE_IS_K(f) ((f)&GRE_FLAG_K)
-+#define GRE_IS_S(f) ((f)&GRE_FLAG_S)
-+#define GRE_IS_A(f) ((f)&GRE_FLAG_A)
-+
-+/* GRE is a mess: Four different standards */
-+struct gre_hdr {
-+#if defined(__LITTLE_ENDIAN_BITFIELD)
-+ __u16 rec:3,
-+ srr:1,
-+ seq:1,
-+ key:1,
-+ routing:1,
-+ csum:1,
-+ version:3,
-+ reserved:4,
-+ ack:1;
-+#elif defined(__BIG_ENDIAN_BITFIELD)
-+ __u16 csum:1,
-+ routing:1,
-+ key:1,
-+ seq:1,
-+ srr:1,
-+ rec:3,
-+ ack:1,
-+ reserved:4,
-+ version:3;
-+#else
-+#error "Adjust your <asm/byteorder.h> defines"
-+#endif
-+ __u16 protocol;
-+};
-+
-+/* modified GRE header for PPTP */
-+struct gre_hdr_pptp {
-+ __u8 flags; /* bitfield */
-+ __u8 version; /* should be GRE_VERSION_PPTP */
-+ __u16 protocol; /* should be GRE_PROTOCOL_PPTP */
-+ __u16 payload_len; /* size of ppp payload, not inc. gre header */
-+ __u16 call_id; /* peer's call_id for this session */
-+ __u32 seq; /* sequence number. Present if S==1 */
-+ __u32 ack; /* seq number of highest packet recieved by */
-+ /* sender in this session */
-+};
-+
-+
-+/* this is part of ip_conntrack */
-+struct ip_ct_gre {
-+ unsigned int stream_timeout;
-+ unsigned int timeout;
-+};
-+
-+/* this is part of ip_conntrack_expect */
-+struct ip_ct_gre_expect {
-+ struct ip_ct_gre_keymap *keymap_orig, *keymap_reply;
-+};
-+
-+#ifdef __KERNEL__
-+struct ip_conntrack_expect;
-+
-+/* structure for original <-> reply keymap */
-+struct ip_ct_gre_keymap {
-+ struct list_head list;
-+
-+ struct ip_conntrack_tuple tuple;
-+};
-+
-+
-+/* add new tuple->key_reply pair to keymap */
-+int ip_ct_gre_keymap_add(struct ip_conntrack_expect *exp,
-+ struct ip_conntrack_tuple *t,
-+ int reply);
-+
-+/* change an existing keymap entry */
-+void ip_ct_gre_keymap_change(struct ip_ct_gre_keymap *km,
-+ struct ip_conntrack_tuple *t);
-+
-+/* delete keymap entries */
-+void ip_ct_gre_keymap_destroy(struct ip_conntrack_expect *exp);
-+
-+
-+/* get pointer to gre key, if present */
-+static inline u_int32_t *gre_key(struct gre_hdr *greh)
-+{
-+ if (!greh->key)
-+ return NULL;
-+ if (greh->csum || greh->routing)
-+ return (u_int32_t *) (greh+sizeof(*greh)+4);
-+ return (u_int32_t *) (greh+sizeof(*greh));
-+}
-+
-+/* get pointer ot gre csum, if present */
-+static inline u_int16_t *gre_csum(struct gre_hdr *greh)
-+{
-+ if (!greh->csum)
-+ return NULL;
-+ return (u_int16_t *) (greh+sizeof(*greh));
-+}
-+
-+#endif /* __KERNEL__ */
-+
-+#endif /* _CONNTRACK_PROTO_GRE_H */
-diff -uNr linux_org/include/linux/netfilter_ipv4/ip_conntrack_tuple.h linux/include/linux/netfilter_ipv4/ip_conntrack_tuple.h
---- linux_org/include/linux/netfilter_ipv4/ip_conntrack_tuple.h 2003-11-17 02:07:46.000000000 +0100
-+++ linux/include/linux/netfilter_ipv4/ip_conntrack_tuple.h 2006-10-27 14:11:52.000000000 +0200
-@@ -14,7 +14,7 @@
- union ip_conntrack_manip_proto
- {
- /* Add other protocols here. */
-- u_int16_t all;
-+ u_int32_t all;
-
- struct {
- u_int16_t port;
-@@ -25,6 +25,9 @@
- struct {
- u_int16_t id;
- } icmp;
-+ struct {
-+ u_int32_t key;
-+ } gre;
- };
-
- /* The manipulable part of the tuple. */
-@@ -44,7 +47,7 @@
- u_int32_t ip;
- union {
- /* Add other protocols here. */
-- u_int16_t all;
-+ u_int64_t all;
-
- struct {
- u_int16_t port;
-@@ -55,6 +58,11 @@
- struct {
- u_int8_t type, code;
- } icmp;
-+ struct {
-+ u_int16_t protocol;
-+ u_int8_t version;
-+ u_int32_t key;
-+ } gre;
- } u;
-
- /* The protocol. */
-@@ -80,10 +88,16 @@
- #ifdef __KERNEL__
-
- #define DUMP_TUPLE(tp) \
--DEBUGP("tuple %p: %u %u.%u.%u.%u:%hu -> %u.%u.%u.%u:%hu\n", \
-+DEBUGP("tuple %p: %u %u.%u.%u.%u:%u -> %u.%u.%u.%u:%u\n", \
- (tp), (tp)->dst.protonum, \
-- NIPQUAD((tp)->src.ip), ntohs((tp)->src.u.all), \
-- NIPQUAD((tp)->dst.ip), ntohs((tp)->dst.u.all))
-+ NIPQUAD((tp)->src.ip), ntohl((tp)->src.u.all), \
-+ NIPQUAD((tp)->dst.ip), ntohl((tp)->dst.u.all))
-+
-+#define DUMP_TUPLE_RAW(x) \
-+ DEBUGP("tuple %p: %u %u.%u.%u.%u:0x%08x -> %u.%u.%u.%u:0x%08x\n",\
-+ (x), (x)->dst.protonum, \
-+ NIPQUAD((x)->src.ip), ntohl((x)->src.u.all), \
-+ NIPQUAD((x)->dst.ip), ntohl((x)->dst.u.all))
-
- #define CTINFO2DIR(ctinfo) ((ctinfo) >= IP_CT_IS_REPLY ? IP_CT_DIR_REPLY : IP_CT_DIR_ORIGINAL)
-
-diff -uNr linux_org/include/linux/netfilter_ipv4/ip_conntrack_tuple.h.orig linux/include/linux/netfilter_ipv4/ip_conntrack_tuple.h.orig
---- linux_org/include/linux/netfilter_ipv4/ip_conntrack_tuple.h.orig 1970-01-01 01:00:00.000000000 +0100
-+++ linux/include/linux/netfilter_ipv4/ip_conntrack_tuple.h.orig 2003-11-17 02:07:46.000000000 +0100
-@@ -0,0 +1,139 @@
-+#ifndef _IP_CONNTRACK_TUPLE_H
-+#define _IP_CONNTRACK_TUPLE_H
-+
-+/* A `tuple' is a structure containing the information to uniquely
-+ identify a connection. ie. if two packets have the same tuple, they
-+ are in the same connection; if not, they are not.
-+
-+ We divide the structure along "manipulatable" and
-+ "non-manipulatable" lines, for the benefit of the NAT code.
-+*/
-+
-+/* The protocol-specific manipulable parts of the tuple: always in
-+ network order! */
-+union ip_conntrack_manip_proto
-+{
-+ /* Add other protocols here. */
-+ u_int16_t all;
-+
-+ struct {
-+ u_int16_t port;
-+ } tcp;
-+ struct {
-+ u_int16_t port;
-+ } udp;
-+ struct {
-+ u_int16_t id;
-+ } icmp;
-+};
-+
-+/* The manipulable part of the tuple. */
-+struct ip_conntrack_manip
-+{
-+ u_int32_t ip;
-+ union ip_conntrack_manip_proto u;
-+};
-+
-+/* This contains the information to distinguish a connection. */
-+struct ip_conntrack_tuple
-+{
-+ struct ip_conntrack_manip src;
-+
-+ /* These are the parts of the tuple which are fixed. */
-+ struct {
-+ u_int32_t ip;
-+ union {
-+ /* Add other protocols here. */
-+ u_int16_t all;
-+
-+ struct {
-+ u_int16_t port;
-+ } tcp;
-+ struct {
-+ u_int16_t port;
-+ } udp;
-+ struct {
-+ u_int8_t type, code;
-+ } icmp;
-+ } u;
-+
-+ /* The protocol. */
-+ u_int16_t protonum;
-+ } dst;
-+};
-+
-+/* This is optimized opposed to a memset of the whole structure. Everything we
-+ * really care about is the source/destination unions */
-+#define IP_CT_TUPLE_U_BLANK(tuple) \
-+ do { \
-+ (tuple)->src.u.all = 0; \
-+ (tuple)->dst.u.all = 0; \
-+ } while (0)
-+
-+enum ip_conntrack_dir
-+{
-+ IP_CT_DIR_ORIGINAL,
-+ IP_CT_DIR_REPLY,
-+ IP_CT_DIR_MAX
-+};
-+
-+#ifdef __KERNEL__
-+
-+#define DUMP_TUPLE(tp) \
-+DEBUGP("tuple %p: %u %u.%u.%u.%u:%hu -> %u.%u.%u.%u:%hu\n", \
-+ (tp), (tp)->dst.protonum, \
-+ NIPQUAD((tp)->src.ip), ntohs((tp)->src.u.all), \
-+ NIPQUAD((tp)->dst.ip), ntohs((tp)->dst.u.all))
-+
-+#define CTINFO2DIR(ctinfo) ((ctinfo) >= IP_CT_IS_REPLY ? IP_CT_DIR_REPLY : IP_CT_DIR_ORIGINAL)
-+
-+/* If we're the first tuple, it's the original dir. */
-+#define DIRECTION(h) ((enum ip_conntrack_dir)(&(h)->ctrack->tuplehash[1] == (h)))
-+
-+/* Connections have two entries in the hash table: one for each way */
-+struct ip_conntrack_tuple_hash
-+{
-+ struct list_head list;
-+
-+ struct ip_conntrack_tuple tuple;
-+
-+ /* this == &ctrack->tuplehash[DIRECTION(this)]. */
-+ struct ip_conntrack *ctrack;
-+};
-+
-+#endif /* __KERNEL__ */
-+
-+static inline int ip_ct_tuple_src_equal(const struct ip_conntrack_tuple *t1,
-+ const struct ip_conntrack_tuple *t2)
-+{
-+ return t1->src.ip == t2->src.ip
-+ && t1->src.u.all == t2->src.u.all;
-+}
-+
-+static inline int ip_ct_tuple_dst_equal(const struct ip_conntrack_tuple *t1,
-+ const struct ip_conntrack_tuple *t2)
-+{
-+ return t1->dst.ip == t2->dst.ip
-+ && t1->dst.u.all == t2->dst.u.all
-+ && t1->dst.protonum == t2->dst.protonum;
-+}
-+
-+static inline int ip_ct_tuple_equal(const struct ip_conntrack_tuple *t1,
-+ const struct ip_conntrack_tuple *t2)
-+{
-+ return ip_ct_tuple_src_equal(t1, t2) && ip_ct_tuple_dst_equal(t1, t2);
-+}
-+
-+static inline int ip_ct_tuple_mask_cmp(const struct ip_conntrack_tuple *t,
-+ const struct ip_conntrack_tuple *tuple,
-+ const struct ip_conntrack_tuple *mask)
-+{
-+ return !(((t->src.ip ^ tuple->src.ip) & mask->src.ip)
-+ || ((t->dst.ip ^ tuple->dst.ip) & mask->dst.ip)
-+ || ((t->src.u.all ^ tuple->src.u.all) & mask->src.u.all)
-+ || ((t->dst.u.all ^ tuple->dst.u.all) & mask->dst.u.all)
-+ || ((t->dst.protonum ^ tuple->dst.protonum)
-+ & mask->dst.protonum));
-+}
-+
-+#endif /* _IP_CONNTRACK_TUPLE_H */
-diff -uNr linux_org/include/linux/netfilter_ipv4/ip_nat_pptp.h linux/include/linux/netfilter_ipv4/ip_nat_pptp.h
---- linux_org/include/linux/netfilter_ipv4/ip_nat_pptp.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux/include/linux/netfilter_ipv4/ip_nat_pptp.h 2006-10-27 14:11:52.000000000 +0200
-@@ -0,0 +1,11 @@
-+/* PPTP constants and structs */
-+#ifndef _NAT_PPTP_H
-+#define _NAT_PPTP_H
-+
-+/* conntrack private data */
-+struct ip_nat_pptp {
-+ u_int16_t pns_call_id; /* NAT'ed PNS call id */
-+ u_int16_t pac_call_id; /* NAT'ed PAC call id */
-+};
-+
-+#endif /* _NAT_PPTP_H */
-diff -uNr linux_org/net/ipv4/netfilter/Config.in linux/net/ipv4/netfilter/Config.in
---- linux_org/net/ipv4/netfilter/Config.in 2003-08-13 19:19:30.000000000 +0200
-+++ linux/net/ipv4/netfilter/Config.in 2006-10-27 14:11:52.000000000 +0200
-@@ -7,6 +7,11 @@
- tristate 'Connection tracking (required for masq/NAT)' CONFIG_IP_NF_CONNTRACK
- if [ "$CONFIG_IP_NF_CONNTRACK" != "n" ]; then
- dep_tristate ' FTP protocol support' CONFIG_IP_NF_FTP $CONFIG_IP_NF_CONNTRACK
-+ dep_tristate ' GRE protocol support' CONFIG_IP_NF_CT_PROTO_GRE $CONFIG_IP_NF_CONNTRACK
-+ dep_tristate ' PPTP protocol support' CONFIG_IP_NF_PPTP $CONFIG_IP_NF_CONNTRACK
-+ if [ "$CONFIG_IP_NF_PPTP" != "n" ]; then
-+ bool ' PPTP verbose debug' CONFIG_IP_NF_PPTP_DEBUG
-+ fi
- dep_tristate ' Amanda protocol support' CONFIG_IP_NF_AMANDA $CONFIG_IP_NF_CONNTRACK
- dep_tristate ' TFTP protocol support' CONFIG_IP_NF_TFTP $CONFIG_IP_NF_CONNTRACK
- dep_tristate ' IRC protocol support' CONFIG_IP_NF_IRC $CONFIG_IP_NF_CONNTRACK
-@@ -67,6 +72,20 @@
- fi
- fi
- bool ' NAT of local connections (READ HELP)' CONFIG_IP_NF_NAT_LOCAL
-+ if [ "$CONFIG_IP_NF_PPTP" = "m" ]; then
-+ define_tristate CONFIG_IP_NF_NAT_PPTP m
-+ else
-+ if [ "$CONFIG_IP_NF_PPTP" = "y" ]; then
-+ define_tristate CONFIG_IP_NF_NAT_PPTP $CONFIG_IP_NF_NAT
-+ fi
-+ fi
-+ if [ "$CONFIG_IP_NF_CT_PROTO_GRE" = "m" ]; then
-+ define_tristate CONFIG_IP_NF_NAT_PROTO_GRE m
-+ else
-+ if [ "$CONFIG_IP_NF_CT_PROTO_GRE" = "y" ]; then
-+ define_tristate CONFIG_IP_NF_NAT_PROTO_GRE $CONFIG_IP_NF_NAT
-+ fi
-+ fi
- if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
- dep_tristate ' Basic SNMP-ALG support (EXPERIMENTAL)' CONFIG_IP_NF_NAT_SNMP_BASIC $CONFIG_IP_NF_NAT
- fi
-diff -uNr linux_org/net/ipv4/netfilter/Makefile linux/net/ipv4/netfilter/Makefile
---- linux_org/net/ipv4/netfilter/Makefile 2003-08-13 19:19:30.000000000 +0200
-+++ linux/net/ipv4/netfilter/Makefile 2006-10-27 14:11:52.000000000 +0200
-@@ -30,8 +30,21 @@
-
- # connection tracking
- obj-$(CONFIG_IP_NF_CONNTRACK) += ip_conntrack.o
-+
-+# connection tracking protocol helpers
-+obj-$(CONFIG_IP_NF_CT_PROTO_GRE) += ip_conntrack_proto_gre.o
-+ifdef CONFIG_IP_NF_CT_PROTO_GRE
-+ export-objs += ip_conntrack_proto_gre.o
-+endif
-+
-+# NAT protocol helpers
-+obj-$(CONFIG_IP_NF_NAT_PROTO_GRE) += ip_nat_proto_gre.o
-
- # connection tracking helpers
-+obj-$(CONFIG_IP_NF_PPTP) += ip_conntrack_pptp.o
-+ifdef CONFIG_IP_NF_NAT_PPTP
-+ export-objs += ip_conntrack_pptp.o
-+endif
- obj-$(CONFIG_IP_NF_AMANDA) += ip_conntrack_amanda.o
- ifdef CONFIG_IP_NF_AMANDA
- export-objs += ip_conntrack_amanda.o
-@@ -49,6 +62,7 @@
- endif
-
- # NAT helpers
-+obj-$(CONFIG_IP_NF_NAT_PPTP) += ip_nat_pptp.o
- obj-$(CONFIG_IP_NF_NAT_AMANDA) += ip_nat_amanda.o
- obj-$(CONFIG_IP_NF_NAT_TFTP) += ip_nat_tftp.o
- obj-$(CONFIG_IP_NF_NAT_FTP) += ip_nat_ftp.o
-diff -uNr linux_org/net/ipv4/netfilter/ip_conntrack_core.c linux/net/ipv4/netfilter/ip_conntrack_core.c
---- linux_org/net/ipv4/netfilter/ip_conntrack_core.c 2004-11-24 12:14:04.000000000 +0100
-+++ linux/net/ipv4/netfilter/ip_conntrack_core.c 2006-10-27 14:11:52.000000000 +0200
-@@ -142,6 +142,8 @@
- tuple->dst.ip = iph->daddr;
- tuple->dst.protonum = iph->protocol;
-
-+ tuple->src.u.all = tuple->dst.u.all = 0;
-+
- ret = protocol->pkt_to_tuple((u_int32_t *)iph + iph->ihl,
- len - 4*iph->ihl,
- tuple);
-@@ -157,6 +159,8 @@
- inverse->dst.ip = orig->src.ip;
- inverse->dst.protonum = orig->dst.protonum;
-
-+ inverse->src.u.all = inverse->dst.u.all = 0;
-+
- return protocol->invert_tuple(inverse, orig);
- }
-
-@@ -945,8 +949,8 @@
- * so there is no need to use the tuple lock too */
-
- DEBUGP("ip_conntrack_expect_related %p\n", related_to);
-- DEBUGP("tuple: "); DUMP_TUPLE(&expect->tuple);
-- DEBUGP("mask: "); DUMP_TUPLE(&expect->mask);
-+ DEBUGP("tuple: "); DUMP_TUPLE_RAW(&expect->tuple);
-+ DEBUGP("mask: "); DUMP_TUPLE_RAW(&expect->mask);
-
- old = LIST_FIND(&ip_conntrack_expect_list, resent_expect,
- struct ip_conntrack_expect *, &expect->tuple,
-@@ -1063,15 +1067,14 @@
-
- MUST_BE_READ_LOCKED(&ip_conntrack_lock);
- WRITE_LOCK(&ip_conntrack_expect_tuple_lock);
--
- DEBUGP("change_expect:\n");
-- DEBUGP("exp tuple: "); DUMP_TUPLE(&expect->tuple);
-- DEBUGP("exp mask: "); DUMP_TUPLE(&expect->mask);
-- DEBUGP("newtuple: "); DUMP_TUPLE(newtuple);
-+ DEBUGP("exp tuple: "); DUMP_TUPLE_RAW(&expect->tuple);
-+ DEBUGP("exp mask: "); DUMP_TUPLE_RAW(&expect->mask);
-+ DEBUGP("newtuple: "); DUMP_TUPLE_RAW(newtuple);
- if (expect->ct_tuple.dst.protonum == 0) {
- /* Never seen before */
- DEBUGP("change expect: never seen before\n");
-- if (!ip_ct_tuple_equal(&expect->tuple, newtuple)
-+ if (!ip_ct_tuple_mask_cmp(&expect->tuple, newtuple, &expect->mask)
- && LIST_FIND(&ip_conntrack_expect_list, expect_clash,
- struct ip_conntrack_expect *, newtuple, &expect->mask)) {
- /* Force NAT to find an unused tuple */
-diff -uNr linux_org/net/ipv4/netfilter/ip_conntrack_core.c.orig linux/net/ipv4/netfilter/ip_conntrack_core.c.orig
---- linux_org/net/ipv4/netfilter/ip_conntrack_core.c.orig 1970-01-01 01:00:00.000000000 +0100
-+++ linux/net/ipv4/netfilter/ip_conntrack_core.c.orig 2004-11-24 12:14:04.000000000 +0100
-@@ -0,0 +1,1446 @@
-+/* Connection state tracking for netfilter. This is separated from,
-+ but required by, the NAT layer; it can also be used by an iptables
-+ extension. */
-+
-+/* (c) 1999 Paul `Rusty' Russell. Licenced under the GNU General
-+ * Public Licence.
-+ *
-+ * 23 Apr 2001: Harald Welte <laforge@gnumonks.org>
-+ * - new API and handling of conntrack/nat helpers
-+ * - now capable of multiple expectations for one master
-+ * 16 Jul 2002: Harald Welte <laforge@gnumonks.org>
-+ * - add usage/reference counts to ip_conntrack_expect
-+ * - export ip_conntrack[_expect]_{find_get,put} functions
-+ * */
-+
-+#include <linux/version.h>
-+#include <linux/config.h>
-+#include <linux/types.h>
-+#include <linux/ip.h>
-+#include <linux/netfilter.h>
-+#include <linux/netfilter_ipv4.h>
-+#include <linux/module.h>
-+#include <linux/skbuff.h>
-+#include <linux/proc_fs.h>
-+#include <linux/vmalloc.h>
-+#include <linux/brlock.h>
-+#include <net/checksum.h>
-+#include <linux/stddef.h>
-+#include <linux/sysctl.h>
-+#include <linux/slab.h>
-+#include <linux/random.h>
-+#include <linux/jhash.h>
-+/* For ERR_PTR(). Yeah, I know... --RR */
-+#include <linux/fs.h>
-+
-+/* This rwlock protects the main hash table, protocol/helper/expected
-+ registrations, conntrack timers*/
-+#define ASSERT_READ_LOCK(x) MUST_BE_READ_LOCKED(&ip_conntrack_lock)
-+#define ASSERT_WRITE_LOCK(x) MUST_BE_WRITE_LOCKED(&ip_conntrack_lock)
-+
-+#include <linux/netfilter_ipv4/ip_conntrack.h>
-+#include <linux/netfilter_ipv4/ip_conntrack_protocol.h>
-+#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
-+#include <linux/netfilter_ipv4/ip_conntrack_core.h>
-+#include <linux/netfilter_ipv4/listhelp.h>
-+
-+#define IP_CONNTRACK_VERSION "2.1"
-+
-+#if 0
-+#define DEBUGP printk
-+#else
-+#define DEBUGP(format, args...)
-+#endif
-+
-+DECLARE_RWLOCK(ip_conntrack_lock);
-+DECLARE_RWLOCK(ip_conntrack_expect_tuple_lock);
-+
-+void (*ip_conntrack_destroyed)(struct ip_conntrack *conntrack) = NULL;
-+LIST_HEAD(ip_conntrack_expect_list);
-+LIST_HEAD(protocol_list);
-+static LIST_HEAD(helpers);
-+unsigned int ip_conntrack_htable_size = 0;
-+int ip_conntrack_max = 0;
-+static atomic_t ip_conntrack_count = ATOMIC_INIT(0);
-+struct list_head *ip_conntrack_hash;
-+static kmem_cache_t *ip_conntrack_cachep;
-+
-+extern struct ip_conntrack_protocol ip_conntrack_generic_protocol;
-+
-+static inline int proto_cmpfn(const struct ip_conntrack_protocol *curr,
-+ u_int8_t protocol)
-+{
-+ return protocol == curr->proto;
-+}
-+
-+struct ip_conntrack_protocol *__ip_ct_find_proto(u_int8_t protocol)
-+{
-+ struct ip_conntrack_protocol *p;
-+
-+ MUST_BE_READ_LOCKED(&ip_conntrack_lock);
-+ p = LIST_FIND(&protocol_list, proto_cmpfn,
-+ struct ip_conntrack_protocol *, protocol);
-+ if (!p)
-+ p = &ip_conntrack_generic_protocol;
-+
-+ return p;
-+}
-+
-+struct ip_conntrack_protocol *ip_ct_find_proto(u_int8_t protocol)
-+{
-+ struct ip_conntrack_protocol *p;
-+
-+ READ_LOCK(&ip_conntrack_lock);
-+ p = __ip_ct_find_proto(protocol);
-+ READ_UNLOCK(&ip_conntrack_lock);
-+ return p;
-+}
-+
-+inline void
-+ip_conntrack_put(struct ip_conntrack *ct)
-+{
-+ IP_NF_ASSERT(ct);
-+ IP_NF_ASSERT(ct->infos[0].master);
-+ /* nf_conntrack_put wants to go via an info struct, so feed it
-+ one at random. */
-+ nf_conntrack_put(&ct->infos[0]);
-+}
-+
-+static int ip_conntrack_hash_rnd_initted;
-+static unsigned int ip_conntrack_hash_rnd;
-+
-+static u_int32_t
-+hash_conntrack(const struct ip_conntrack_tuple *tuple)
-+{
-+#if 0
-+ dump_tuple(tuple);
-+#endif
-+ return (jhash_3words(tuple->src.ip,
-+ (tuple->dst.ip ^ tuple->dst.protonum),
-+ (tuple->src.u.all | (tuple->dst.u.all << 16)),
-+ ip_conntrack_hash_rnd) % ip_conntrack_htable_size);
-+}
-+
-+inline int
-+get_tuple(const struct iphdr *iph, size_t len,
-+ struct ip_conntrack_tuple *tuple,
-+ struct ip_conntrack_protocol *protocol)
-+{
-+ int ret;
-+
-+ /* Never happen */
-+ if (iph->frag_off & htons(IP_OFFSET)) {
-+ printk("ip_conntrack_core: Frag of proto %u.\n",
-+ iph->protocol);
-+ return 0;
-+ }
-+ /* Guarantee 8 protocol bytes: if more wanted, use len param */
-+ else if (iph->ihl * 4 + 8 > len)
-+ return 0;
-+
-+ tuple->src.ip = iph->saddr;
-+ tuple->dst.ip = iph->daddr;
-+ tuple->dst.protonum = iph->protocol;
-+
-+ ret = protocol->pkt_to_tuple((u_int32_t *)iph + iph->ihl,
-+ len - 4*iph->ihl,
-+ tuple);
-+ return ret;
-+}
-+
-+static int
-+invert_tuple(struct ip_conntrack_tuple *inverse,
-+ const struct ip_conntrack_tuple *orig,
-+ const struct ip_conntrack_protocol *protocol)
-+{
-+ inverse->src.ip = orig->dst.ip;
-+ inverse->dst.ip = orig->src.ip;
-+ inverse->dst.protonum = orig->dst.protonum;
-+
-+ return protocol->invert_tuple(inverse, orig);
-+}
-+
-+
-+/* ip_conntrack_expect helper functions */
-+
-+/* Compare tuple parts depending on mask. */
-+static inline int expect_cmp(const struct ip_conntrack_expect *i,
-+ const struct ip_conntrack_tuple *tuple)
-+{
-+ MUST_BE_READ_LOCKED(&ip_conntrack_expect_tuple_lock);
-+ return ip_ct_tuple_mask_cmp(tuple, &i->tuple, &i->mask);
-+}
-+
-+static void
-+destroy_expect(struct ip_conntrack_expect *exp)
-+{
-+ DEBUGP("destroy_expect(%p) use=%d\n", exp, atomic_read(&exp->use));
-+ IP_NF_ASSERT(atomic_read(&exp->use) == 0);
-+ IP_NF_ASSERT(!timer_pending(&exp->timeout));
-+
-+ kfree(exp);
-+}
-+
-+inline void ip_conntrack_expect_put(struct ip_conntrack_expect *exp)
-+{
-+ IP_NF_ASSERT(exp);
-+
-+ if (atomic_dec_and_test(&exp->use)) {
-+ /* usage count dropped to zero */
-+ destroy_expect(exp);
-+ }
-+}
-+
-+static inline struct ip_conntrack_expect *
-+__ip_ct_expect_find(const struct ip_conntrack_tuple *tuple)
-+{
-+ MUST_BE_READ_LOCKED(&ip_conntrack_lock);
-+ MUST_BE_READ_LOCKED(&ip_conntrack_expect_tuple_lock);
-+ return LIST_FIND(&ip_conntrack_expect_list, expect_cmp,
-+ struct ip_conntrack_expect *, tuple);
-+}
-+
-+/* Find a expectation corresponding to a tuple. */
-+struct ip_conntrack_expect *
-+ip_conntrack_expect_find_get(const struct ip_conntrack_tuple *tuple)
-+{
-+ struct ip_conntrack_expect *exp;
-+
-+ READ_LOCK(&ip_conntrack_lock);
-+ READ_LOCK(&ip_conntrack_expect_tuple_lock);
-+ exp = __ip_ct_expect_find(tuple);
-+ if (exp)
-+ atomic_inc(&exp->use);
-+ READ_UNLOCK(&ip_conntrack_expect_tuple_lock);
-+ READ_UNLOCK(&ip_conntrack_lock);
-+
-+ return exp;
-+}
-+
-+/* remove one specific expectation from all lists and drop refcount,
-+ * does _NOT_ delete the timer. */
-+static void __unexpect_related(struct ip_conntrack_expect *expect)
-+{
-+ DEBUGP("unexpect_related(%p)\n", expect);
-+ MUST_BE_WRITE_LOCKED(&ip_conntrack_lock);
-+
-+ /* we're not allowed to unexpect a confirmed expectation! */
-+ IP_NF_ASSERT(!expect->sibling);
-+
-+ /* delete from global and local lists */
-+ list_del(&expect->list);
-+ list_del(&expect->expected_list);
-+
-+ /* decrement expect-count of master conntrack */
-+ if (expect->expectant)
-+ expect->expectant->expecting--;
-+
-+ ip_conntrack_expect_put(expect);
-+}
-+
-+/* remove one specific expecatation from all lists, drop refcount
-+ * and expire timer.
-+ * This function can _NOT_ be called for confirmed expects! */
-+static void unexpect_related(struct ip_conntrack_expect *expect)
-+{
-+ IP_NF_ASSERT(expect->expectant);
-+ IP_NF_ASSERT(expect->expectant->helper);
-+ /* if we are supposed to have a timer, but we can't delete
-+ * it: race condition. __unexpect_related will
-+ * be calledd by timeout function */
-+ if (expect->expectant->helper->timeout
-+ && !del_timer(&expect->timeout))
-+ return;
-+
-+ __unexpect_related(expect);
-+}
-+
-+/* delete all unconfirmed expectations for this conntrack */
-+static void remove_expectations(struct ip_conntrack *ct, int drop_refcount)
-+{
-+ struct list_head *exp_entry, *next;
-+ struct ip_conntrack_expect *exp;
-+
-+ DEBUGP("remove_expectations(%p)\n", ct);
-+
-+ list_for_each_safe(exp_entry, next, &ct->sibling_list) {
-+ exp = list_entry(exp_entry, struct ip_conntrack_expect,
-+ expected_list);
-+
-+ /* we skip established expectations, as we want to delete
-+ * the un-established ones only */
-+ if (exp->sibling) {
-+ DEBUGP("remove_expectations: skipping established %p of %p\n", exp->sibling, ct);
-+ if (drop_refcount) {
-+ /* Indicate that this expectations parent is dead */
-+ ip_conntrack_put(exp->expectant);
-+ exp->expectant = NULL;
-+ }
-+ continue;
-+ }
-+
-+ IP_NF_ASSERT(list_inlist(&ip_conntrack_expect_list, exp));
-+ IP_NF_ASSERT(exp->expectant == ct);
-+
-+ /* delete expectation from global and private lists */
-+ unexpect_related(exp);
-+ }
-+}
-+
-+static void
-+clean_from_lists(struct ip_conntrack *ct)
-+{
-+ unsigned int ho, hr;
-+
-+ DEBUGP("clean_from_lists(%p)\n", ct);
-+ MUST_BE_WRITE_LOCKED(&ip_conntrack_lock);
-+
-+ ho = hash_conntrack(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
-+ hr = hash_conntrack(&ct->tuplehash[IP_CT_DIR_REPLY].tuple);
-+ LIST_DELETE(&ip_conntrack_hash[ho], &ct->tuplehash[IP_CT_DIR_ORIGINAL]);
-+ LIST_DELETE(&ip_conntrack_hash[hr], &ct->tuplehash[IP_CT_DIR_REPLY]);
-+
-+ /* Destroy all un-established, pending expectations */
-+ remove_expectations(ct, 1);
-+}
-+
-+static void
-+destroy_conntrack(struct nf_conntrack *nfct)
-+{
-+ struct ip_conntrack *ct = (struct ip_conntrack *)nfct, *master = NULL;
-+ struct ip_conntrack_protocol *proto;
-+
-+ DEBUGP("destroy_conntrack(%p)\n", ct);
-+ IP_NF_ASSERT(atomic_read(&nfct->use) == 0);
-+ IP_NF_ASSERT(!timer_pending(&ct->timeout));
-+
-+ /* To make sure we don't get any weird locking issues here:
-+ * destroy_conntrack() MUST NOT be called with a write lock
-+ * to ip_conntrack_lock!!! -HW */
-+ proto = ip_ct_find_proto(ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.protonum);
-+ if (proto && proto->destroy)
-+ proto->destroy(ct);
-+
-+ if (ip_conntrack_destroyed)
-+ ip_conntrack_destroyed(ct);
-+
-+ WRITE_LOCK(&ip_conntrack_lock);
-+ /* Make sure don't leave any orphaned expectations lying around */
-+ if (ct->expecting)
-+ remove_expectations(ct, 1);
-+
-+ /* Delete our master expectation */
-+ if (ct->master) {
-+ if (ct->master->expectant) {
-+ /* can't call __unexpect_related here,
-+ * since it would screw up expect_list */
-+ list_del(&ct->master->expected_list);
-+ master = ct->master->expectant;
-+ }
-+ kfree(ct->master);
-+ }
-+ WRITE_UNLOCK(&ip_conntrack_lock);
-+
-+ if (master)
-+ ip_conntrack_put(master);
-+
-+ DEBUGP("destroy_conntrack: returning ct=%p to slab\n", ct);
-+ kmem_cache_free(ip_conntrack_cachep, ct);
-+ atomic_dec(&ip_conntrack_count);
-+}
-+
-+static void death_by_timeout(unsigned long ul_conntrack)
-+{
-+ struct ip_conntrack *ct = (void *)ul_conntrack;
-+
-+ WRITE_LOCK(&ip_conntrack_lock);
-+ clean_from_lists(ct);
-+ WRITE_UNLOCK(&ip_conntrack_lock);
-+ ip_conntrack_put(ct);
-+}
-+
-+static inline int
-+conntrack_tuple_cmp(const struct ip_conntrack_tuple_hash *i,
-+ const struct ip_conntrack_tuple *tuple,
-+ const struct ip_conntrack *ignored_conntrack)
-+{
-+ MUST_BE_READ_LOCKED(&ip_conntrack_lock);
-+ return i->ctrack != ignored_conntrack
-+ && ip_ct_tuple_equal(tuple, &i->tuple);
-+}
-+
-+static struct ip_conntrack_tuple_hash *
-+__ip_conntrack_find(const struct ip_conntrack_tuple *tuple,
-+ const struct ip_conntrack *ignored_conntrack)
-+{
-+ struct ip_conntrack_tuple_hash *h;
-+ unsigned int hash = hash_conntrack(tuple);
-+
-+ MUST_BE_READ_LOCKED(&ip_conntrack_lock);
-+ h = LIST_FIND(&ip_conntrack_hash[hash],
-+ conntrack_tuple_cmp,
-+ struct ip_conntrack_tuple_hash *,
-+ tuple, ignored_conntrack);
-+ return h;
-+}
-+
-+/* Find a connection corresponding to a tuple. */
-+struct ip_conntrack_tuple_hash *
-+ip_conntrack_find_get(const struct ip_conntrack_tuple *tuple,
-+ const struct ip_conntrack *ignored_conntrack)
-+{
-+ struct ip_conntrack_tuple_hash *h;
-+
-+ READ_LOCK(&ip_conntrack_lock);
-+ h = __ip_conntrack_find(tuple, ignored_conntrack);
-+ if (h)
-+ atomic_inc(&h->ctrack->ct_general.use);
-+ READ_UNLOCK(&ip_conntrack_lock);
-+
-+ return h;
-+}
-+
-+static inline struct ip_conntrack *
-+__ip_conntrack_get(struct nf_ct_info *nfct, enum ip_conntrack_info *ctinfo)
-+{
-+ struct ip_conntrack *ct
-+ = (struct ip_conntrack *)nfct->master;
-+
-+ /* ctinfo is the index of the nfct inside the conntrack */
-+ *ctinfo = nfct - ct->infos;
-+ IP_NF_ASSERT(*ctinfo >= 0 && *ctinfo < IP_CT_NUMBER);
-+ return ct;
-+}
-+
-+/* Return conntrack and conntrack_info given skb->nfct->master */
-+struct ip_conntrack *
-+ip_conntrack_get(struct sk_buff *skb, enum ip_conntrack_info *ctinfo)
-+{
-+ if (skb->nfct)
-+ return __ip_conntrack_get(skb->nfct, ctinfo);
-+ return NULL;
-+}
-+
-+/* Confirm a connection given skb->nfct; places it in hash table */
-+int
-+__ip_conntrack_confirm(struct nf_ct_info *nfct)
-+{
-+ unsigned int hash, repl_hash;
-+ struct ip_conntrack *ct;
-+ enum ip_conntrack_info ctinfo;
-+
-+ ct = __ip_conntrack_get(nfct, &ctinfo);
-+
-+ /* ipt_REJECT uses ip_conntrack_attach to attach related
-+ ICMP/TCP RST packets in other direction. Actual packet
-+ which created connection will be IP_CT_NEW or for an
-+ expected connection, IP_CT_RELATED. */
-+ if (CTINFO2DIR(ctinfo) != IP_CT_DIR_ORIGINAL)
-+ return NF_ACCEPT;
-+
-+ hash = hash_conntrack(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
-+ repl_hash = hash_conntrack(&ct->tuplehash[IP_CT_DIR_REPLY].tuple);
-+
-+ /* We're not in hash table, and we refuse to set up related
-+ connections for unconfirmed conns. But packet copies and
-+ REJECT will give spurious warnings here. */
-+ /* IP_NF_ASSERT(atomic_read(&ct->ct_general.use) == 1); */
-+
-+ /* No external references means noone else could have
-+ confirmed us. */
-+ IP_NF_ASSERT(!is_confirmed(ct));
-+ DEBUGP("Confirming conntrack %p\n", ct);
-+
-+ WRITE_LOCK(&ip_conntrack_lock);
-+ /* See if there's one in the list already, including reverse:
-+ NAT could have grabbed it without realizing, since we're
-+ not in the hash. If there is, we lost race. */
-+ if (!LIST_FIND(&ip_conntrack_hash[hash],
-+ conntrack_tuple_cmp,
-+ struct ip_conntrack_tuple_hash *,
-+ &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple, NULL)
-+ && !LIST_FIND(&ip_conntrack_hash[repl_hash],
-+ conntrack_tuple_cmp,
-+ struct ip_conntrack_tuple_hash *,
-+ &ct->tuplehash[IP_CT_DIR_REPLY].tuple, NULL)) {
-+ list_prepend(&ip_conntrack_hash[hash],
-+ &ct->tuplehash[IP_CT_DIR_ORIGINAL]);
-+ list_prepend(&ip_conntrack_hash[repl_hash],
-+ &ct->tuplehash[IP_CT_DIR_REPLY]);
-+ /* Timer relative to confirmation time, not original
-+ setting time, otherwise we'd get timer wrap in
-+ weird delay cases. */
-+ ct->timeout.expires += jiffies;
-+ add_timer(&ct->timeout);
-+ atomic_inc(&ct->ct_general.use);
-+ set_bit(IPS_CONFIRMED_BIT, &ct->status);
-+ WRITE_UNLOCK(&ip_conntrack_lock);
-+ return NF_ACCEPT;
-+ }
-+
-+ WRITE_UNLOCK(&ip_conntrack_lock);
-+ return NF_DROP;
-+}
-+
-+/* Returns true if a connection correspondings to the tuple (required
-+ for NAT). */
-+int
-+ip_conntrack_tuple_taken(const struct ip_conntrack_tuple *tuple,
-+ const struct ip_conntrack *ignored_conntrack)
-+{
-+ struct ip_conntrack_tuple_hash *h;
-+
-+ READ_LOCK(&ip_conntrack_lock);
-+ h = __ip_conntrack_find(tuple, ignored_conntrack);
-+ READ_UNLOCK(&ip_conntrack_lock);
-+
-+ return h != NULL;
-+}
-+
-+/* Returns conntrack if it dealt with ICMP, and filled in skb fields */
-+struct ip_conntrack *
-+icmp_error_track(struct sk_buff *skb,
-+ enum ip_conntrack_info *ctinfo,
-+ unsigned int hooknum)
-+{
-+ const struct iphdr *iph = skb->nh.iph;
-+ struct icmphdr *hdr;
-+ struct ip_conntrack_tuple innertuple, origtuple;
-+ struct iphdr *inner;
-+ size_t datalen;
-+ struct ip_conntrack_protocol *innerproto;
-+ struct ip_conntrack_tuple_hash *h;
-+
-+ IP_NF_ASSERT(iph->protocol == IPPROTO_ICMP);
-+ IP_NF_ASSERT(skb->nfct == NULL);
-+
-+ hdr = (struct icmphdr *)((u_int32_t *)iph + iph->ihl);
-+ inner = (struct iphdr *)(hdr + 1);
-+ datalen = skb->len - iph->ihl*4 - sizeof(*hdr);
-+
-+ if (skb->len < iph->ihl * 4 + sizeof(*hdr) + sizeof(*iph)) {
-+ DEBUGP("icmp_error_track: too short\n");
-+ return NULL;
-+ }
-+
-+ if (hdr->type != ICMP_DEST_UNREACH
-+ && hdr->type != ICMP_SOURCE_QUENCH
-+ && hdr->type != ICMP_TIME_EXCEEDED
-+ && hdr->type != ICMP_PARAMETERPROB
-+ && hdr->type != ICMP_REDIRECT)
-+ return NULL;
-+
-+ /* Ignore ICMP's containing fragments (shouldn't happen) */
-+ if (inner->frag_off & htons(IP_OFFSET)) {
-+ DEBUGP("icmp_error_track: fragment of proto %u\n",
-+ inner->protocol);
-+ return NULL;
-+ }
-+
-+ /* Ignore it if the checksum's bogus. */
-+ if (ip_compute_csum((unsigned char *)hdr, sizeof(*hdr) + datalen)) {
-+ DEBUGP("icmp_error_track: bad csum\n");
-+ return NULL;
-+ }
-+
-+ innerproto = ip_ct_find_proto(inner->protocol);
-+ /* Are they talking about one of our connections? */
-+ if (inner->ihl * 4 + 8 > datalen
-+ || !get_tuple(inner, datalen, &origtuple, innerproto)) {
-+ DEBUGP("icmp_error: ! get_tuple p=%u (%u*4+%u dlen=%u)\n",
-+ inner->protocol, inner->ihl, 8,
-+ datalen);
-+ return NULL;
-+ }
-+
-+ /* Ordinarily, we'd expect the inverted tupleproto, but it's
-+ been preserved inside the ICMP. */
-+ if (!invert_tuple(&innertuple, &origtuple, innerproto)) {
-+ DEBUGP("icmp_error_track: Can't invert tuple\n");
-+ return NULL;
-+ }
-+
-+ *ctinfo = IP_CT_RELATED;
-+
-+ h = ip_conntrack_find_get(&innertuple, NULL);
-+ if (!h) {
-+ /* Locally generated ICMPs will match inverted if they
-+ haven't been SNAT'ed yet */
-+ /* FIXME: NAT code has to handle half-done double NAT --RR */
-+ if (hooknum == NF_IP_LOCAL_OUT)
-+ h = ip_conntrack_find_get(&origtuple, NULL);
-+
-+ if (!h) {
-+ DEBUGP("icmp_error_track: no match\n");
-+ return NULL;
-+ }
-+ /* Reverse direction from that found */
-+ if (DIRECTION(h) != IP_CT_DIR_REPLY)
-+ *ctinfo += IP_CT_IS_REPLY;
-+ } else {
-+ if (DIRECTION(h) == IP_CT_DIR_REPLY)
-+ *ctinfo += IP_CT_IS_REPLY;
-+ }
-+
-+ /* Update skb to refer to this connection */
-+ skb->nfct = &h->ctrack->infos[*ctinfo];
-+ return h->ctrack;
-+}
-+
-+/* There's a small race here where we may free a just-assured
-+ connection. Too bad: we're in trouble anyway. */
-+static inline int unreplied(const struct ip_conntrack_tuple_hash *i)
-+{
-+ return !(test_bit(IPS_ASSURED_BIT, &i->ctrack->status));
-+}
-+
-+static int early_drop(struct list_head *chain)
-+{
-+ /* Traverse backwards: gives us oldest, which is roughly LRU */
-+ struct ip_conntrack_tuple_hash *h;
-+ int dropped = 0;
-+
-+ READ_LOCK(&ip_conntrack_lock);
-+ h = LIST_FIND_B(chain, unreplied, struct ip_conntrack_tuple_hash *);
-+ if (h)
-+ atomic_inc(&h->ctrack->ct_general.use);
-+ READ_UNLOCK(&ip_conntrack_lock);
-+
-+ if (!h)
-+ return dropped;
-+
-+ if (del_timer(&h->ctrack->timeout)) {
-+ death_by_timeout((unsigned long)h->ctrack);
-+ dropped = 1;
-+ }
-+ ip_conntrack_put(h->ctrack);
-+ return dropped;
-+}
-+
-+static inline int helper_cmp(const struct ip_conntrack_helper *i,
-+ const struct ip_conntrack_tuple *rtuple)
-+{
-+ return ip_ct_tuple_mask_cmp(rtuple, &i->tuple, &i->mask);
-+}
-+
-+struct ip_conntrack_helper *ip_ct_find_helper(const struct ip_conntrack_tuple *tuple)
-+{
-+ return LIST_FIND(&helpers, helper_cmp,
-+ struct ip_conntrack_helper *,
-+ tuple);
-+}
-+
-+/* Allocate a new conntrack: we return -ENOMEM if classification
-+ failed due to stress. Otherwise it really is unclassifiable. */
-+static struct ip_conntrack_tuple_hash *
-+init_conntrack(const struct ip_conntrack_tuple *tuple,
-+ struct ip_conntrack_protocol *protocol,
-+ struct sk_buff *skb)
-+{
-+ struct ip_conntrack *conntrack;
-+ struct ip_conntrack_tuple repl_tuple;
-+ size_t hash;
-+ struct ip_conntrack_expect *expected;
-+ int i;
-+ static unsigned int drop_next = 0;
-+
-+ if (!ip_conntrack_hash_rnd_initted) {
-+ get_random_bytes(&ip_conntrack_hash_rnd, 4);
-+ ip_conntrack_hash_rnd_initted = 1;
-+ }
-+
-+ hash = hash_conntrack(tuple);
-+
-+ if (ip_conntrack_max &&
-+ atomic_read(&ip_conntrack_count) >= ip_conntrack_max) {
-+ /* Try dropping from random chain, or else from the
-+ chain about to put into (in case they're trying to
-+ bomb one hash chain). */
-+ unsigned int next = (drop_next++)%ip_conntrack_htable_size;
-+
-+ if (!early_drop(&ip_conntrack_hash[next])
-+ && !early_drop(&ip_conntrack_hash[hash])) {
-+ if (net_ratelimit())
-+ printk(KERN_WARNING
-+ "ip_conntrack: table full, dropping"
-+ " packet.\n");
-+ return ERR_PTR(-ENOMEM);
-+ }
-+ }
-+
-+ if (!invert_tuple(&repl_tuple, tuple, protocol)) {
-+ DEBUGP("Can't invert tuple.\n");
-+ return NULL;
-+ }
-+
-+ conntrack = kmem_cache_alloc(ip_conntrack_cachep, GFP_ATOMIC);
-+ if (!conntrack) {
-+ DEBUGP("Can't allocate conntrack.\n");
-+ return ERR_PTR(-ENOMEM);
-+ }
-+
-+ memset(conntrack, 0, sizeof(*conntrack));
-+ atomic_set(&conntrack->ct_general.use, 1);
-+ conntrack->ct_general.destroy = destroy_conntrack;
-+ conntrack->tuplehash[IP_CT_DIR_ORIGINAL].tuple = *tuple;
-+ conntrack->tuplehash[IP_CT_DIR_ORIGINAL].ctrack = conntrack;
-+ conntrack->tuplehash[IP_CT_DIR_REPLY].tuple = repl_tuple;
-+ conntrack->tuplehash[IP_CT_DIR_REPLY].ctrack = conntrack;
-+ for (i=0; i < IP_CT_NUMBER; i++)
-+ conntrack->infos[i].master = &conntrack->ct_general;
-+
-+ if (!protocol->new(conntrack, skb->nh.iph, skb->len)) {
-+ kmem_cache_free(ip_conntrack_cachep, conntrack);
-+ return NULL;
-+ }
-+ /* Don't set timer yet: wait for confirmation */
-+ init_timer(&conntrack->timeout);
-+ conntrack->timeout.data = (unsigned long)conntrack;
-+ conntrack->timeout.function = death_by_timeout;
-+
-+ INIT_LIST_HEAD(&conntrack->sibling_list);
-+
-+ WRITE_LOCK(&ip_conntrack_lock);
-+ /* Need finding and deleting of expected ONLY if we win race */
-+ READ_LOCK(&ip_conntrack_expect_tuple_lock);
-+ expected = LIST_FIND(&ip_conntrack_expect_list, expect_cmp,
-+ struct ip_conntrack_expect *, tuple);
-+ READ_UNLOCK(&ip_conntrack_expect_tuple_lock);
-+
-+ /* If master is not in hash table yet (ie. packet hasn't left
-+ this machine yet), how can other end know about expected?
-+ Hence these are not the droids you are looking for (if
-+ master ct never got confirmed, we'd hold a reference to it
-+ and weird things would happen to future packets). */
-+ if (expected && !is_confirmed(expected->expectant))
-+ expected = NULL;
-+
-+ /* Look up the conntrack helper for master connections only */
-+ if (!expected)
-+ conntrack->helper = ip_ct_find_helper(&repl_tuple);
-+
-+ /* If the expectation is dying, then this is a looser. */
-+ if (expected
-+ && expected->expectant->helper->timeout
-+ && ! del_timer(&expected->timeout))
-+ expected = NULL;
-+
-+ if (expected) {
-+ DEBUGP("conntrack: expectation arrives ct=%p exp=%p\n",
-+ conntrack, expected);
-+ /* Welcome, Mr. Bond. We've been expecting you... */
-+ __set_bit(IPS_EXPECTED_BIT, &conntrack->status);
-+ conntrack->master = expected;
-+ expected->sibling = conntrack;
-+ LIST_DELETE(&ip_conntrack_expect_list, expected);
-+ expected->expectant->expecting--;
-+ nf_conntrack_get(&master_ct(conntrack)->infos[0]);
-+ }
-+ atomic_inc(&ip_conntrack_count);
-+ WRITE_UNLOCK(&ip_conntrack_lock);
-+
-+ if (expected && expected->expectfn)
-+ expected->expectfn(conntrack);
-+ return &conntrack->tuplehash[IP_CT_DIR_ORIGINAL];
-+}
-+
-+/* On success, returns conntrack ptr, sets skb->nfct and ctinfo */
-+static inline struct ip_conntrack *
-+resolve_normal_ct(struct sk_buff *skb,
-+ struct ip_conntrack_protocol *proto,
-+ int *set_reply,
-+ unsigned int hooknum,
-+ enum ip_conntrack_info *ctinfo)
-+{
-+ struct ip_conntrack_tuple tuple;
-+ struct ip_conntrack_tuple_hash *h;
-+
-+ IP_NF_ASSERT((skb->nh.iph->frag_off & htons(IP_OFFSET)) == 0);
-+
-+ if (!get_tuple(skb->nh.iph, skb->len, &tuple, proto))
-+ return NULL;
-+
-+ /* look for tuple match */
-+ h = ip_conntrack_find_get(&tuple, NULL);
-+ if (!h) {
-+ h = init_conntrack(&tuple, proto, skb);
-+ if (!h)
-+ return NULL;
-+ if (IS_ERR(h))
-+ return (void *)h;
-+ }
-+
-+ /* It exists; we have (non-exclusive) reference. */
-+ if (DIRECTION(h) == IP_CT_DIR_REPLY) {
-+ *ctinfo = IP_CT_ESTABLISHED + IP_CT_IS_REPLY;
-+ /* Please set reply bit if this packet OK */
-+ *set_reply = 1;
-+ } else {
-+ /* Once we've had two way comms, always ESTABLISHED. */
-+ if (test_bit(IPS_SEEN_REPLY_BIT, &h->ctrack->status)) {
-+ DEBUGP("ip_conntrack_in: normal packet for %p\n",
-+ h->ctrack);
-+ *ctinfo = IP_CT_ESTABLISHED;
-+ } else if (test_bit(IPS_EXPECTED_BIT, &h->ctrack->status)) {
-+ DEBUGP("ip_conntrack_in: related packet for %p\n",
-+ h->ctrack);
-+ *ctinfo = IP_CT_RELATED;
-+ } else {
-+ DEBUGP("ip_conntrack_in: new packet for %p\n",
-+ h->ctrack);
-+ *ctinfo = IP_CT_NEW;
-+ }
-+ *set_reply = 0;
-+ }
-+ skb->nfct = &h->ctrack->infos[*ctinfo];
-+ return h->ctrack;
-+}
-+
-+/* Netfilter hook itself. */
-+unsigned int ip_conntrack_in(unsigned int hooknum,
-+ struct sk_buff **pskb,
-+ const struct net_device *in,
-+ const struct net_device *out,
-+ int (*okfn)(struct sk_buff *))
-+{
-+ struct ip_conntrack *ct;
-+ enum ip_conntrack_info ctinfo;
-+ struct ip_conntrack_protocol *proto;
-+ int set_reply;
-+ int ret;
-+
-+ /* FIXME: Do this right please. --RR */
-+ (*pskb)->nfcache |= NFC_UNKNOWN;
-+
-+/* Doesn't cover locally-generated broadcast, so not worth it. */
-+#if 0
-+ /* Ignore broadcast: no `connection'. */
-+ if ((*pskb)->pkt_type == PACKET_BROADCAST) {
-+ printk("Broadcast packet!\n");
-+ return NF_ACCEPT;
-+ } else if (((*pskb)->nh.iph->daddr & htonl(0x000000FF))
-+ == htonl(0x000000FF)) {
-+ printk("Should bcast: %u.%u.%u.%u->%u.%u.%u.%u (sk=%p, ptype=%u)\n",
-+ NIPQUAD((*pskb)->nh.iph->saddr),
-+ NIPQUAD((*pskb)->nh.iph->daddr),
-+ (*pskb)->sk, (*pskb)->pkt_type);
-+ }
-+#endif
-+
-+ /* Previously seen (loopback)? Ignore. Do this before
-+ fragment check. */
-+ if ((*pskb)->nfct)
-+ return NF_ACCEPT;
-+
-+ /* Gather fragments. */
-+ if ((*pskb)->nh.iph->frag_off & htons(IP_MF|IP_OFFSET)) {
-+ *pskb = ip_ct_gather_frags(*pskb);
-+ if (!*pskb)
-+ return NF_STOLEN;
-+ }
-+
-+ proto = ip_ct_find_proto((*pskb)->nh.iph->protocol);
-+
-+ /* It may be an icmp error... */
-+ if ((*pskb)->nh.iph->protocol == IPPROTO_ICMP
-+ && icmp_error_track(*pskb, &ctinfo, hooknum))
-+ return NF_ACCEPT;
-+
-+ if (!(ct = resolve_normal_ct(*pskb, proto,&set_reply,hooknum,&ctinfo)))
-+ /* Not valid part of a connection */
-+ return NF_ACCEPT;
-+
-+ if (IS_ERR(ct))
-+ /* Too stressed to deal. */
-+ return NF_DROP;
-+
-+ IP_NF_ASSERT((*pskb)->nfct);
-+
-+ ret = proto->packet(ct, (*pskb)->nh.iph, (*pskb)->len, ctinfo);
-+ if (ret == -1) {
-+ /* Invalid */
-+ nf_conntrack_put((*pskb)->nfct);
-+ (*pskb)->nfct = NULL;
-+ return NF_ACCEPT;
-+ }
-+
-+ if (ret != NF_DROP && ct->helper) {
-+ ret = ct->helper->help((*pskb)->nh.iph, (*pskb)->len,
-+ ct, ctinfo);
-+ if (ret == -1) {
-+ /* Invalid */
-+ nf_conntrack_put((*pskb)->nfct);
-+ (*pskb)->nfct = NULL;
-+ return NF_ACCEPT;
-+ }
-+ }
-+ if (set_reply)
-+ set_bit(IPS_SEEN_REPLY_BIT, &ct->status);
-+
-+ return ret;
-+}
-+
-+int invert_tuplepr(struct ip_conntrack_tuple *inverse,
-+ const struct ip_conntrack_tuple *orig)
-+{
-+ return invert_tuple(inverse, orig, ip_ct_find_proto(orig->dst.protonum));
-+}
-+
-+static inline int resent_expect(const struct ip_conntrack_expect *i,
-+ const struct ip_conntrack_tuple *tuple,
-+ const struct ip_conntrack_tuple *mask)
-+{
-+ DEBUGP("resent_expect\n");
-+ DEBUGP(" tuple: "); DUMP_TUPLE(&i->tuple);
-+ DEBUGP("ct_tuple: "); DUMP_TUPLE(&i->ct_tuple);
-+ DEBUGP("test tuple: "); DUMP_TUPLE(tuple);
-+ return (((i->ct_tuple.dst.protonum == 0 && ip_ct_tuple_equal(&i->tuple, tuple))
-+ || (i->ct_tuple.dst.protonum && ip_ct_tuple_equal(&i->ct_tuple, tuple)))
-+ && ip_ct_tuple_equal(&i->mask, mask));
-+}
-+
-+/* Would two expected things clash? */
-+static inline int expect_clash(const struct ip_conntrack_expect *i,
-+ const struct ip_conntrack_tuple *tuple,
-+ const struct ip_conntrack_tuple *mask)
-+{
-+ /* Part covered by intersection of masks must be unequal,
-+ otherwise they clash */
-+ struct ip_conntrack_tuple intersect_mask
-+ = { { i->mask.src.ip & mask->src.ip,
-+ { i->mask.src.u.all & mask->src.u.all } },
-+ { i->mask.dst.ip & mask->dst.ip,
-+ { i->mask.dst.u.all & mask->dst.u.all },
-+ i->mask.dst.protonum & mask->dst.protonum } };
-+
-+ return ip_ct_tuple_mask_cmp(&i->tuple, tuple, &intersect_mask);
-+}
-+
-+inline void ip_conntrack_unexpect_related(struct ip_conntrack_expect *expect)
-+{
-+ WRITE_LOCK(&ip_conntrack_lock);
-+ unexpect_related(expect);
-+ WRITE_UNLOCK(&ip_conntrack_lock);
-+}
-+
-+static void expectation_timed_out(unsigned long ul_expect)
-+{
-+ struct ip_conntrack_expect *expect = (void *) ul_expect;
-+
-+ DEBUGP("expectation %p timed out\n", expect);
-+ WRITE_LOCK(&ip_conntrack_lock);
-+ __unexpect_related(expect);
-+ WRITE_UNLOCK(&ip_conntrack_lock);
-+}
-+
-+/* Add a related connection. */
-+int ip_conntrack_expect_related(struct ip_conntrack *related_to,
-+ struct ip_conntrack_expect *expect)
-+{
-+ struct ip_conntrack_expect *old, *new;
-+ int ret = 0;
-+
-+ WRITE_LOCK(&ip_conntrack_lock);
-+ /* Because of the write lock, no reader can walk the lists,
-+ * so there is no need to use the tuple lock too */
-+
-+ DEBUGP("ip_conntrack_expect_related %p\n", related_to);
-+ DEBUGP("tuple: "); DUMP_TUPLE(&expect->tuple);
-+ DEBUGP("mask: "); DUMP_TUPLE(&expect->mask);
-+
-+ old = LIST_FIND(&ip_conntrack_expect_list, resent_expect,
-+ struct ip_conntrack_expect *, &expect->tuple,
-+ &expect->mask);
-+ if (old) {
-+ /* Helper private data may contain offsets but no pointers
-+ pointing into the payload - otherwise we should have to copy
-+ the data filled out by the helper over the old one */
-+ DEBUGP("expect_related: resent packet\n");
-+ if (related_to->helper->timeout) {
-+ if (!del_timer(&old->timeout)) {
-+ /* expectation is dying. Fall through */
-+ old = NULL;
-+ } else {
-+ old->timeout.expires = jiffies +
-+ related_to->helper->timeout * HZ;
-+ add_timer(&old->timeout);
-+ }
-+ }
-+
-+ if (old) {
-+ WRITE_UNLOCK(&ip_conntrack_lock);
-+ return -EEXIST;
-+ }
-+ } else if (related_to->helper->max_expected &&
-+ related_to->expecting >= related_to->helper->max_expected) {
-+ /* old == NULL */
-+ if (!(related_to->helper->flags &
-+ IP_CT_HELPER_F_REUSE_EXPECT)) {
-+ WRITE_UNLOCK(&ip_conntrack_lock);
-+ if (net_ratelimit())
-+ printk(KERN_WARNING
-+ "ip_conntrack: max number of expected "
-+ "connections %i of %s reached for "
-+ "%u.%u.%u.%u->%u.%u.%u.%u\n",
-+ related_to->helper->max_expected,
-+ related_to->helper->name,
-+ NIPQUAD(related_to->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip),
-+ NIPQUAD(related_to->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip));
-+ return -EPERM;
-+ }
-+ DEBUGP("ip_conntrack: max number of expected "
-+ "connections %i of %s reached for "
-+ "%u.%u.%u.%u->%u.%u.%u.%u, reusing\n",
-+ related_to->helper->max_expected,
-+ related_to->helper->name,
-+ NIPQUAD(related_to->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip),
-+ NIPQUAD(related_to->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip));
-+
-+ /* choose the the oldest expectation to evict */
-+ list_for_each_entry(old, &related_to->sibling_list,
-+ expected_list)
-+ if (old->sibling == NULL)
-+ break;
-+
-+ /* We cannot fail since related_to->expecting is the number
-+ * of unconfirmed expectations */
-+ IP_NF_ASSERT(old && old->sibling == NULL);
-+
-+ /* newnat14 does not reuse the real allocated memory
-+ * structures but rather unexpects the old and
-+ * allocates a new. unexpect_related will decrement
-+ * related_to->expecting.
-+ */
-+ unexpect_related(old);
-+ ret = -EPERM;
-+ } else if (LIST_FIND(&ip_conntrack_expect_list, expect_clash,
-+ struct ip_conntrack_expect *, &expect->tuple,
-+ &expect->mask)) {
-+ WRITE_UNLOCK(&ip_conntrack_lock);
-+ DEBUGP("expect_related: busy!\n");
-+ return -EBUSY;
-+ }
-+
-+ new = (struct ip_conntrack_expect *)
-+ kmalloc(sizeof(struct ip_conntrack_expect), GFP_ATOMIC);
-+ if (!new) {
-+ WRITE_UNLOCK(&ip_conntrack_lock);
-+ DEBUGP("expect_relaed: OOM allocating expect\n");
-+ return -ENOMEM;
-+ }
-+
-+ DEBUGP("new expectation %p of conntrack %p\n", new, related_to);
-+ memcpy(new, expect, sizeof(*expect));
-+ new->expectant = related_to;
-+ new->sibling = NULL;
-+ atomic_set(&new->use, 1);
-+
-+ /* add to expected list for this connection */
-+ list_add_tail(&new->expected_list, &related_to->sibling_list);
-+ /* add to global list of expectations */
-+ list_prepend(&ip_conntrack_expect_list, &new->list);
-+ /* add and start timer if required */
-+ if (related_to->helper->timeout) {
-+ init_timer(&new->timeout);
-+ new->timeout.data = (unsigned long)new;
-+ new->timeout.function = expectation_timed_out;
-+ new->timeout.expires = jiffies +
-+ related_to->helper->timeout * HZ;
-+ add_timer(&new->timeout);
-+ }
-+ related_to->expecting++;
-+
-+ WRITE_UNLOCK(&ip_conntrack_lock);
-+
-+ return ret;
-+}
-+
-+/* Change tuple in an existing expectation */
-+int ip_conntrack_change_expect(struct ip_conntrack_expect *expect,
-+ struct ip_conntrack_tuple *newtuple)
-+{
-+ int ret;
-+
-+ MUST_BE_READ_LOCKED(&ip_conntrack_lock);
-+ WRITE_LOCK(&ip_conntrack_expect_tuple_lock);
-+
-+ DEBUGP("change_expect:\n");
-+ DEBUGP("exp tuple: "); DUMP_TUPLE(&expect->tuple);
-+ DEBUGP("exp mask: "); DUMP_TUPLE(&expect->mask);
-+ DEBUGP("newtuple: "); DUMP_TUPLE(newtuple);
-+ if (expect->ct_tuple.dst.protonum == 0) {
-+ /* Never seen before */
-+ DEBUGP("change expect: never seen before\n");
-+ if (!ip_ct_tuple_equal(&expect->tuple, newtuple)
-+ && LIST_FIND(&ip_conntrack_expect_list, expect_clash,
-+ struct ip_conntrack_expect *, newtuple, &expect->mask)) {
-+ /* Force NAT to find an unused tuple */
-+ ret = -1;
-+ } else {
-+ memcpy(&expect->ct_tuple, &expect->tuple, sizeof(expect->tuple));
-+ memcpy(&expect->tuple, newtuple, sizeof(expect->tuple));
-+ ret = 0;
-+ }
-+ } else {
-+ /* Resent packet */
-+ DEBUGP("change expect: resent packet\n");
-+ if (ip_ct_tuple_equal(&expect->tuple, newtuple)) {
-+ ret = 0;
-+ } else {
-+ /* Force NAT to choose again the same port */
-+ ret = -1;
-+ }
-+ }
-+ WRITE_UNLOCK(&ip_conntrack_expect_tuple_lock);
-+
-+ return ret;
-+}
-+
-+/* Alter reply tuple (maybe alter helper). If it's already taken,
-+ return 0 and don't do alteration. */
-+int ip_conntrack_alter_reply(struct ip_conntrack *conntrack,
-+ const struct ip_conntrack_tuple *newreply)
-+{
-+ WRITE_LOCK(&ip_conntrack_lock);
-+ if (__ip_conntrack_find(newreply, conntrack)) {
-+ WRITE_UNLOCK(&ip_conntrack_lock);
-+ return 0;
-+ }
-+ /* Should be unconfirmed, so not in hash table yet */
-+ IP_NF_ASSERT(!is_confirmed(conntrack));
-+
-+ DEBUGP("Altering reply tuple of %p to ", conntrack);
-+ DUMP_TUPLE(newreply);
-+
-+ conntrack->tuplehash[IP_CT_DIR_REPLY].tuple = *newreply;
-+ if (!conntrack->master && list_empty(&conntrack->sibling_list))
-+ conntrack->helper = ip_ct_find_helper(newreply);
-+ WRITE_UNLOCK(&ip_conntrack_lock);
-+
-+ return 1;
-+}
-+
-+int ip_conntrack_helper_register(struct ip_conntrack_helper *me)
-+{
-+ MOD_INC_USE_COUNT;
-+
-+ WRITE_LOCK(&ip_conntrack_lock);
-+ list_prepend(&helpers, me);
-+ WRITE_UNLOCK(&ip_conntrack_lock);
-+
-+ return 0;
-+}
-+
-+static inline int unhelp(struct ip_conntrack_tuple_hash *i,
-+ const struct ip_conntrack_helper *me)
-+{
-+ if (i->ctrack->helper == me) {
-+ /* Get rid of any expected. */
-+ remove_expectations(i->ctrack, 0);
-+ /* And *then* set helper to NULL */
-+ i->ctrack->helper = NULL;
-+ }
-+ return 0;
-+}
-+
-+void ip_conntrack_helper_unregister(struct ip_conntrack_helper *me)
-+{
-+ unsigned int i;
-+
-+ /* Need write lock here, to delete helper. */
-+ WRITE_LOCK(&ip_conntrack_lock);
-+ LIST_DELETE(&helpers, me);
-+
-+ /* Get rid of expecteds, set helpers to NULL. */
-+ for (i = 0; i < ip_conntrack_htable_size; i++)
-+ LIST_FIND_W(&ip_conntrack_hash[i], unhelp,
-+ struct ip_conntrack_tuple_hash *, me);
-+ WRITE_UNLOCK(&ip_conntrack_lock);
-+
-+ /* Someone could be still looking at the helper in a bh. */
-+ br_write_lock_bh(BR_NETPROTO_LOCK);
-+ br_write_unlock_bh(BR_NETPROTO_LOCK);
-+
-+ MOD_DEC_USE_COUNT;
-+}
-+
-+/* Refresh conntrack for this many jiffies. */
-+void ip_ct_refresh(struct ip_conntrack *ct, unsigned long extra_jiffies)
-+{
-+ IP_NF_ASSERT(ct->timeout.data == (unsigned long)ct);
-+
-+ WRITE_LOCK(&ip_conntrack_lock);
-+ /* If not in hash table, timer will not be active yet */
-+ if (!is_confirmed(ct))
-+ ct->timeout.expires = extra_jiffies;
-+ else {
-+ /* Need del_timer for race avoidance (may already be dying). */
-+ if (del_timer(&ct->timeout)) {
-+ ct->timeout.expires = jiffies + extra_jiffies;
-+ add_timer(&ct->timeout);
-+ }
-+ }
-+ WRITE_UNLOCK(&ip_conntrack_lock);
-+}
-+
-+/* Returns new sk_buff, or NULL */
-+struct sk_buff *
-+ip_ct_gather_frags(struct sk_buff *skb)
-+{
-+ struct sock *sk = skb->sk;
-+#ifdef CONFIG_NETFILTER_DEBUG
-+ unsigned int olddebug = skb->nf_debug;
-+#endif
-+ if (sk) {
-+ sock_hold(sk);
-+ skb_orphan(skb);
-+ }
-+
-+ local_bh_disable();
-+ skb = ip_defrag(skb);
-+ local_bh_enable();
-+
-+ if (!skb) {
-+ if (sk) sock_put(sk);
-+ return skb;
-+ } else if (skb_is_nonlinear(skb) && skb_linearize(skb, GFP_ATOMIC) != 0) {
-+ kfree_skb(skb);
-+ if (sk) sock_put(sk);
-+ return NULL;
-+ }
-+
-+ if (sk) {
-+ skb_set_owner_w(skb, sk);
-+ sock_put(sk);
-+ }
-+
-+ ip_send_check(skb->nh.iph);
-+ skb->nfcache |= NFC_ALTERED;
-+#ifdef CONFIG_NETFILTER_DEBUG
-+ /* Packet path as if nothing had happened. */
-+ skb->nf_debug = olddebug;
-+#endif
-+ return skb;
-+}
-+
-+/* Used by ipt_REJECT. */
-+static void ip_conntrack_attach(struct sk_buff *nskb, struct nf_ct_info *nfct)
-+{
-+ struct ip_conntrack *ct;
-+ enum ip_conntrack_info ctinfo;
-+
-+ ct = __ip_conntrack_get(nfct, &ctinfo);
-+
-+ /* This ICMP is in reverse direction to the packet which
-+ caused it */
-+ if (CTINFO2DIR(ctinfo) == IP_CT_DIR_ORIGINAL)
-+ ctinfo = IP_CT_RELATED + IP_CT_IS_REPLY;
-+ else
-+ ctinfo = IP_CT_RELATED;
-+
-+ /* Attach new skbuff, and increment count */
-+ nskb->nfct = &ct->infos[ctinfo];
-+ atomic_inc(&ct->ct_general.use);
-+}
-+
-+static inline int
-+do_kill(const struct ip_conntrack_tuple_hash *i,
-+ int (*kill)(const struct ip_conntrack *i, void *data),
-+ void *data)
-+{
-+ return kill(i->ctrack, data);
-+}
-+
-+/* Bring out ya dead! */
-+static struct ip_conntrack_tuple_hash *
-+get_next_corpse(int (*kill)(const struct ip_conntrack *i, void *data),
-+ void *data, unsigned int *bucket)
-+{
-+ struct ip_conntrack_tuple_hash *h = NULL;
-+
-+ READ_LOCK(&ip_conntrack_lock);
-+ for (; !h && *bucket < ip_conntrack_htable_size; (*bucket)++) {
-+ h = LIST_FIND(&ip_conntrack_hash[*bucket], do_kill,
-+ struct ip_conntrack_tuple_hash *, kill, data);
-+ }
-+ if (h)
-+ atomic_inc(&h->ctrack->ct_general.use);
-+ READ_UNLOCK(&ip_conntrack_lock);
-+
-+ return h;
-+}
-+
-+void
-+ip_ct_selective_cleanup(int (*kill)(const struct ip_conntrack *i, void *data),
-+ void *data)
-+{
-+ struct ip_conntrack_tuple_hash *h;
-+ unsigned int bucket = 0;
-+
-+ while ((h = get_next_corpse(kill, data, &bucket)) != NULL) {
-+ /* Time to push up daises... */
-+ if (del_timer(&h->ctrack->timeout))
-+ death_by_timeout((unsigned long)h->ctrack);
-+ /* ... else the timer will get him soon. */
-+
-+ ip_conntrack_put(h->ctrack);
-+ }
-+}
-+
-+/* Fast function for those who don't want to parse /proc (and I don't
-+ blame them). */
-+/* Reversing the socket's dst/src point of view gives us the reply
-+ mapping. */
-+static int
-+getorigdst(struct sock *sk, int optval, void *user, int *len)
-+{
-+ struct ip_conntrack_tuple_hash *h;
-+ struct ip_conntrack_tuple tuple;
-+
-+ IP_CT_TUPLE_U_BLANK(&tuple);
-+ tuple.src.ip = sk->rcv_saddr;
-+ tuple.src.u.tcp.port = sk->sport;
-+ tuple.dst.ip = sk->daddr;
-+ tuple.dst.u.tcp.port = sk->dport;
-+ tuple.dst.protonum = IPPROTO_TCP;
-+
-+ /* We only do TCP at the moment: is there a better way? */
-+ if (strcmp(sk->prot->name, "TCP") != 0) {
-+ DEBUGP("SO_ORIGINAL_DST: Not a TCP socket\n");
-+ return -ENOPROTOOPT;
-+ }
-+
-+ if ((unsigned int) *len < sizeof(struct sockaddr_in)) {
-+ DEBUGP("SO_ORIGINAL_DST: len %u not %u\n",
-+ *len, sizeof(struct sockaddr_in));
-+ return -EINVAL;
-+ }
-+
-+ h = ip_conntrack_find_get(&tuple, NULL);
-+ if (h) {
-+ struct sockaddr_in sin;
-+
-+ sin.sin_family = AF_INET;
-+ sin.sin_port = h->ctrack->tuplehash[IP_CT_DIR_ORIGINAL]
-+ .tuple.dst.u.tcp.port;
-+ sin.sin_addr.s_addr = h->ctrack->tuplehash[IP_CT_DIR_ORIGINAL]
-+ .tuple.dst.ip;
-+
-+ DEBUGP("SO_ORIGINAL_DST: %u.%u.%u.%u %u\n",
-+ NIPQUAD(sin.sin_addr.s_addr), ntohs(sin.sin_port));
-+ ip_conntrack_put(h->ctrack);
-+ if (copy_to_user(user, &sin, sizeof(sin)) != 0)
-+ return -EFAULT;
-+ else
-+ return 0;
-+ }
-+ DEBUGP("SO_ORIGINAL_DST: Can't find %u.%u.%u.%u/%u-%u.%u.%u.%u/%u.\n",
-+ NIPQUAD(tuple.src.ip), ntohs(tuple.src.u.tcp.port),
-+ NIPQUAD(tuple.dst.ip), ntohs(tuple.dst.u.tcp.port));
-+ return -ENOENT;
-+}
-+
-+static struct nf_sockopt_ops so_getorigdst
-+= { { NULL, NULL }, PF_INET,
-+ 0, 0, NULL, /* Setsockopts */
-+ SO_ORIGINAL_DST, SO_ORIGINAL_DST+1, &getorigdst,
-+ 0, NULL };
-+
-+static int kill_all(const struct ip_conntrack *i, void *data)
-+{
-+ return 1;
-+}
-+
-+/* Mishearing the voices in his head, our hero wonders how he's
-+ supposed to kill the mall. */
-+void ip_conntrack_cleanup(void)
-+{
-+ ip_ct_attach = NULL;
-+ /* This makes sure all current packets have passed through
-+ netfilter framework. Roll on, two-stage module
-+ delete... */
-+ br_write_lock_bh(BR_NETPROTO_LOCK);
-+ br_write_unlock_bh(BR_NETPROTO_LOCK);
-+
-+ i_see_dead_people:
-+ ip_ct_selective_cleanup(kill_all, NULL);
-+ if (atomic_read(&ip_conntrack_count) != 0) {
-+ schedule();
-+ goto i_see_dead_people;
-+ }
-+
-+ kmem_cache_destroy(ip_conntrack_cachep);
-+ vfree(ip_conntrack_hash);
-+ nf_unregister_sockopt(&so_getorigdst);
-+}
-+
-+static int hashsize = 0;
-+MODULE_PARM(hashsize, "i");
-+
-+int __init ip_conntrack_init(void)
-+{
-+ unsigned int i;
-+ int ret;
-+
-+ /* Idea from tcp.c: use 1/16384 of memory. On i386: 32MB
-+ * machine has 256 buckets. >= 1GB machines have 8192 buckets. */
-+ if (hashsize) {
-+ ip_conntrack_htable_size = hashsize;
-+ } else {
-+ ip_conntrack_htable_size
-+ = (((num_physpages << PAGE_SHIFT) / 16384)
-+ / sizeof(struct list_head));
-+ if (num_physpages > (1024 * 1024 * 1024 / PAGE_SIZE))
-+ ip_conntrack_htable_size = 8192;
-+ if (ip_conntrack_htable_size < 16)
-+ ip_conntrack_htable_size = 16;
-+ }
-+ ip_conntrack_max = 8 * ip_conntrack_htable_size;
-+
-+ printk("ip_conntrack version %s (%u buckets, %d max)"
-+ " - %Zd bytes per conntrack\n", IP_CONNTRACK_VERSION,
-+ ip_conntrack_htable_size, ip_conntrack_max,
-+ sizeof(struct ip_conntrack));
-+
-+ ret = nf_register_sockopt(&so_getorigdst);
-+ if (ret != 0) {
-+ printk(KERN_ERR "Unable to register netfilter socket option\n");
-+ return ret;
-+ }
-+
-+ ip_conntrack_hash = vmalloc(sizeof(struct list_head)
-+ * ip_conntrack_htable_size);
-+ if (!ip_conntrack_hash) {
-+ printk(KERN_ERR "Unable to create ip_conntrack_hash\n");
-+ goto err_unreg_sockopt;
-+ }
-+
-+ ip_conntrack_cachep = kmem_cache_create("ip_conntrack",
-+ sizeof(struct ip_conntrack), 0,
-+ SLAB_HWCACHE_ALIGN, NULL, NULL);
-+ if (!ip_conntrack_cachep) {
-+ printk(KERN_ERR "Unable to create ip_conntrack slab cache\n");
-+ goto err_free_hash;
-+ }
-+ /* Don't NEED lock here, but good form anyway. */
-+ WRITE_LOCK(&ip_conntrack_lock);
-+ /* Sew in builtin protocols. */
-+ list_append(&protocol_list, &ip_conntrack_protocol_tcp);
-+ list_append(&protocol_list, &ip_conntrack_protocol_udp);
-+ list_append(&protocol_list, &ip_conntrack_protocol_icmp);
-+ WRITE_UNLOCK(&ip_conntrack_lock);
-+
-+ for (i = 0; i < ip_conntrack_htable_size; i++)
-+ INIT_LIST_HEAD(&ip_conntrack_hash[i]);
-+
-+ /* For use by ipt_REJECT */
-+ ip_ct_attach = ip_conntrack_attach;
-+ return ret;
-+
-+err_free_hash:
-+ vfree(ip_conntrack_hash);
-+err_unreg_sockopt:
-+ nf_unregister_sockopt(&so_getorigdst);
-+
-+ return -ENOMEM;
-+}
-diff -uNr linux_org/net/ipv4/netfilter/ip_conntrack_pptp.c linux/net/ipv4/netfilter/ip_conntrack_pptp.c
---- linux_org/net/ipv4/netfilter/ip_conntrack_pptp.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux/net/ipv4/netfilter/ip_conntrack_pptp.c 2006-10-27 14:11:52.000000000 +0200
-@@ -0,0 +1,637 @@
-+/*
-+ * ip_conntrack_pptp.c - Version 1.9
-+ *
-+ * Connection tracking support for PPTP (Point to Point Tunneling Protocol).
-+ * PPTP is a a protocol for creating virtual private networks.
-+ * It is a specification defined by Microsoft and some vendors
-+ * working with Microsoft. PPTP is built on top of a modified
-+ * version of the Internet Generic Routing Encapsulation Protocol.
-+ * GRE is defined in RFC 1701 and RFC 1702. Documentation of
-+ * PPTP can be found in RFC 2637
-+ *
-+ * (C) 2000-2003 by Harald Welte <laforge@gnumonks.org>
-+ *
-+ * Development of this code funded by Astaro AG (http://www.astaro.com/)
-+ *
-+ * Limitations:
-+ * - We blindly assume that control connections are always
-+ * established in PNS->PAC direction. This is a violation
-+ * of RFFC2673
-+ *
-+ * TODO: - finish support for multiple calls within one session
-+ * (needs expect reservations in newnat)
-+ * - testing of incoming PPTP calls
-+ *
-+ * Changes:
-+ * 2002-02-05 - Version 1.3
-+ * - Call ip_conntrack_unexpect_related() from
-+ * pptp_timeout_related() to destroy expectations in case
-+ * CALL_DISCONNECT_NOTIFY or tcp fin packet was seen
-+ * (Philip Craig <philipc@snapgear.com>)
-+ * - Add Version information at module loadtime
-+ * 2002-02-10 - Version 1.6
-+ * - move to C99 style initializers
-+ * - remove second expectation if first arrives
-+ *
-+ */
-+
-+#include <linux/config.h>
-+#include <linux/module.h>
-+#include <linux/netfilter.h>
-+#include <linux/ip.h>
-+#include <net/checksum.h>
-+#include <net/tcp.h>
-+
-+#include <linux/netfilter_ipv4/lockhelp.h>
-+#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
-+#include <linux/netfilter_ipv4/ip_conntrack_proto_gre.h>
-+#include <linux/netfilter_ipv4/ip_conntrack_pptp.h>
-+
-+#define IP_CT_PPTP_VERSION "1.9"
-+
-+MODULE_LICENSE("GPL");
-+MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>");
-+MODULE_DESCRIPTION("Netfilter connection tracking helper module for PPTP");
-+
-+DECLARE_LOCK(ip_pptp_lock);
-+
-+#if 0
-+#include "ip_conntrack_pptp_priv.h"
-+#define DEBUGP(format, args...) printk(KERN_DEBUG __FILE__ ":" __FUNCTION__ \
-+ ": " format, ## args)
-+#else
-+#define DEBUGP(format, args...)
-+#endif
-+
-+#define SECS *HZ
-+#define MINS * 60 SECS
-+#define HOURS * 60 MINS
-+#define DAYS * 24 HOURS
-+
-+#define PPTP_GRE_TIMEOUT (10 MINS)
-+#define PPTP_GRE_STREAM_TIMEOUT (5 DAYS)
-+
-+static int pptp_expectfn(struct ip_conntrack *ct)
-+{
-+ struct ip_conntrack *master;
-+ struct ip_conntrack_expect *exp;
-+
-+ DEBUGP("increasing timeouts\n");
-+ /* increase timeout of GRE data channel conntrack entry */
-+ ct->proto.gre.timeout = PPTP_GRE_TIMEOUT;
-+ ct->proto.gre.stream_timeout = PPTP_GRE_STREAM_TIMEOUT;
-+
-+ master = master_ct(ct);
-+ if (!master) {
-+ DEBUGP(" no master!!!\n");
-+ return 0;
-+ }
-+
-+ exp = ct->master;
-+ if (!exp) {
-+ DEBUGP("no expectation!!\n");
-+ return 0;
-+ }
-+
-+ DEBUGP("completing tuples with ct info\n");
-+ /* we can do this, since we're unconfirmed */
-+ if (ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u.gre.key ==
-+ htonl(master->help.ct_pptp_info.pac_call_id)) {
-+ /* assume PNS->PAC */
-+ ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u.gre.key =
-+ htonl(master->help.ct_pptp_info.pns_call_id);
-+ ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u.gre.key =
-+ htonl(master->help.ct_pptp_info.pns_call_id);
-+ } else {
-+ /* assume PAC->PNS */
-+ ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u.gre.key =
-+ htonl(master->help.ct_pptp_info.pac_call_id);
-+ ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u.gre.key =
-+ htonl(master->help.ct_pptp_info.pac_call_id);
-+ }
-+
-+ /* delete other expectation */
-+ if (exp->expected_list.next != &exp->expected_list) {
-+ struct ip_conntrack_expect *other_exp;
-+ struct list_head *cur_item, *next;
-+
-+ for (cur_item = master->sibling_list.next;
-+ cur_item != &master->sibling_list; cur_item = next) {
-+ next = cur_item->next;
-+ other_exp = list_entry(cur_item,
-+ struct ip_conntrack_expect,
-+ expected_list);
-+ /* remove only if occurred at same sequence number */
-+ if (other_exp != exp && other_exp->seq == exp->seq) {
-+ DEBUGP("unexpecting other direction\n");
-+ ip_ct_gre_keymap_destroy(other_exp);
-+ ip_conntrack_unexpect_related(other_exp);
-+ }
-+ }
-+ }
-+
-+ return 0;
-+}
-+
-+/* timeout GRE data connections */
-+static int pptp_timeout_related(struct ip_conntrack *ct)
-+{
-+ struct list_head *cur_item, *next;
-+ struct ip_conntrack_expect *exp;
-+
-+ /* FIXME: do we have to lock something ? */
-+ for (cur_item = ct->sibling_list.next;
-+ cur_item != &ct->sibling_list; cur_item = next) {
-+ next = cur_item->next;
-+ exp = list_entry(cur_item, struct ip_conntrack_expect,
-+ expected_list);
-+
-+ ip_ct_gre_keymap_destroy(exp);
-+ if (!exp->sibling) {
-+ ip_conntrack_unexpect_related(exp);
-+ continue;
-+ }
-+
-+ DEBUGP("setting timeout of conntrack %p to 0\n",
-+ exp->sibling);
-+ exp->sibling->proto.gre.timeout = 0;
-+ exp->sibling->proto.gre.stream_timeout = 0;
-+ ip_ct_refresh(exp->sibling, 0);
-+ }
-+
-+ return 0;
-+}
-+
-+/* expect GRE connections (PNS->PAC and PAC->PNS direction) */
-+static inline int
-+exp_gre(struct ip_conntrack *master,
-+ u_int32_t seq,
-+ u_int16_t callid,
-+ u_int16_t peer_callid)
-+{
-+ struct ip_conntrack_expect exp;
-+ struct ip_conntrack_tuple inv_tuple;
-+
-+ memset(&exp, 0, sizeof(exp));
-+ /* tuple in original direction, PNS->PAC */
-+ exp.tuple.src.ip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip;
-+ exp.tuple.src.u.gre.key = htonl(ntohs(peer_callid));
-+ exp.tuple.dst.ip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip;
-+ exp.tuple.dst.u.gre.key = htonl(ntohs(callid));
-+ exp.tuple.dst.u.gre.protocol = __constant_htons(GRE_PROTOCOL_PPTP);
-+ exp.tuple.dst.u.gre.version = GRE_VERSION_PPTP;
-+ exp.tuple.dst.protonum = IPPROTO_GRE;
-+
-+ exp.mask.src.ip = 0xffffffff;
-+ exp.mask.src.u.all = 0;
-+ exp.mask.dst.u.all = 0;
-+ exp.mask.dst.u.gre.key = 0xffffffff;
-+ exp.mask.dst.u.gre.version = 0xff;
-+ exp.mask.dst.u.gre.protocol = 0xffff;
-+ exp.mask.dst.ip = 0xffffffff;
-+ exp.mask.dst.protonum = 0xffff;
-+
-+ exp.seq = seq;
-+ exp.expectfn = pptp_expectfn;
-+
-+ exp.help.exp_pptp_info.pac_call_id = ntohs(callid);
-+ exp.help.exp_pptp_info.pns_call_id = ntohs(peer_callid);
-+
-+ DEBUGP("calling expect_related ");
-+ DUMP_TUPLE_RAW(&exp.tuple);
-+
-+ /* Add GRE keymap entries */
-+ if (ip_ct_gre_keymap_add(&exp, &exp.tuple, 0) != 0)
-+ return 1;
-+
-+ invert_tuplepr(&inv_tuple, &exp.tuple);
-+ if (ip_ct_gre_keymap_add(&exp, &inv_tuple, 1) != 0) {
-+ ip_ct_gre_keymap_destroy(&exp);
-+ return 1;
-+ }
-+
-+ if (ip_conntrack_expect_related(master, &exp) != 0) {
-+ ip_ct_gre_keymap_destroy(&exp);
-+ DEBUGP("cannot expect_related()\n");
-+ return 1;
-+ }
-+
-+ /* tuple in reply direction, PAC->PNS */
-+ exp.tuple.src.ip = master->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip;
-+ exp.tuple.src.u.gre.key = htonl(ntohs(callid));
-+ exp.tuple.dst.ip = master->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip;
-+ exp.tuple.dst.u.gre.key = htonl(ntohs(peer_callid));
-+
-+ DEBUGP("calling expect_related ");
-+ DUMP_TUPLE_RAW(&exp.tuple);
-+
-+ /* Add GRE keymap entries */
-+ ip_ct_gre_keymap_add(&exp, &exp.tuple, 0);
-+ invert_tuplepr(&inv_tuple, &exp.tuple);
-+ ip_ct_gre_keymap_add(&exp, &inv_tuple, 1);
-+ /* FIXME: cannot handle error correctly, since we need to free
-+ * the above keymap :( */
-+
-+ if (ip_conntrack_expect_related(master, &exp) != 0) {
-+ /* free the second pair of keypmaps */
-+ ip_ct_gre_keymap_destroy(&exp);
-+ DEBUGP("cannot expect_related():\n");
-+ return 1;
-+ }
-+
-+ return 0;
-+}
-+
-+static inline int
-+pptp_inbound_pkt(struct tcphdr *tcph,
-+ struct pptp_pkt_hdr *pptph,
-+ size_t datalen,
-+ struct ip_conntrack *ct,
-+ enum ip_conntrack_info ctinfo)
-+{
-+ struct PptpControlHeader *ctlh;
-+ union pptp_ctrl_union pptpReq;
-+
-+ struct ip_ct_pptp_master *info = &ct->help.ct_pptp_info;
-+ u_int16_t msg, *cid, *pcid;
-+ u_int32_t seq;
-+
-+ ctlh = (struct PptpControlHeader *)
-+ ((char *) pptph + sizeof(struct pptp_pkt_hdr));
-+ pptpReq.rawreq = (void *)
-+ ((char *) ctlh + sizeof(struct PptpControlHeader));
-+
-+ msg = ntohs(ctlh->messageType);
-+ DEBUGP("inbound control message %s\n", strMName[msg]);
-+
-+ switch (msg) {
-+ case PPTP_START_SESSION_REPLY:
-+ /* server confirms new control session */
-+ if (info->sstate < PPTP_SESSION_REQUESTED) {
-+ DEBUGP("%s without START_SESS_REQUEST\n",
-+ strMName[msg]);
-+ break;
-+ }
-+ if (pptpReq.srep->resultCode == PPTP_START_OK)
-+ info->sstate = PPTP_SESSION_CONFIRMED;
-+ else
-+ info->sstate = PPTP_SESSION_ERROR;
-+ break;
-+
-+ case PPTP_STOP_SESSION_REPLY:
-+ /* server confirms end of control session */
-+ if (info->sstate > PPTP_SESSION_STOPREQ) {
-+ DEBUGP("%s without STOP_SESS_REQUEST\n",
-+ strMName[msg]);
-+ break;
-+ }
-+ if (pptpReq.strep->resultCode == PPTP_STOP_OK)
-+ info->sstate = PPTP_SESSION_NONE;
-+ else
-+ info->sstate = PPTP_SESSION_ERROR;
-+ break;
-+
-+ case PPTP_OUT_CALL_REPLY:
-+ /* server accepted call, we now expect GRE frames */
-+ if (info->sstate != PPTP_SESSION_CONFIRMED) {
-+ DEBUGP("%s but no session\n", strMName[msg]);
-+ break;
-+ }
-+ if (info->cstate != PPTP_CALL_OUT_REQ &&
-+ info->cstate != PPTP_CALL_OUT_CONF) {
-+ DEBUGP("%s without OUTCALL_REQ\n", strMName[msg]);
-+ break;
-+ }
-+ if (pptpReq.ocack->resultCode != PPTP_OUTCALL_CONNECT) {
-+ info->cstate = PPTP_CALL_NONE;
-+ break;
-+ }
-+
-+ cid = &pptpReq.ocack->callID;
-+ pcid = &pptpReq.ocack->peersCallID;
-+
-+ info->pac_call_id = ntohs(*cid);
-+
-+ if (htons(info->pns_call_id) != *pcid) {
-+ DEBUGP("%s for unknown callid %u\n",
-+ strMName[msg], ntohs(*pcid));
-+ break;
-+ }
-+
-+ DEBUGP("%s, CID=%X, PCID=%X\n", strMName[msg],
-+ ntohs(*cid), ntohs(*pcid));
-+
-+ info->cstate = PPTP_CALL_OUT_CONF;
-+
-+ seq = ntohl(tcph->seq) + ((void *)pcid - (void *)pptph);
-+ if (exp_gre(ct, seq, *cid, *pcid) != 0)
-+ printk("ip_conntrack_pptp: error during exp_gre\n");
-+ break;
-+
-+ case PPTP_IN_CALL_REQUEST:
-+ /* server tells us about incoming call request */
-+ if (info->sstate != PPTP_SESSION_CONFIRMED) {
-+ DEBUGP("%s but no session\n", strMName[msg]);
-+ break;
-+ }
-+ pcid = &pptpReq.icack->peersCallID;
-+ DEBUGP("%s, PCID=%X\n", strMName[msg], ntohs(*pcid));
-+ info->cstate = PPTP_CALL_IN_REQ;
-+ info->pac_call_id= ntohs(*pcid);
-+ break;
-+
-+ case PPTP_IN_CALL_CONNECT:
-+ /* server tells us about incoming call established */
-+ if (info->sstate != PPTP_SESSION_CONFIRMED) {
-+ DEBUGP("%s but no session\n", strMName[msg]);
-+ break;
-+ }
-+ if (info->sstate != PPTP_CALL_IN_REP
-+ && info->sstate != PPTP_CALL_IN_CONF) {
-+ DEBUGP("%s but never sent IN_CALL_REPLY\n",
-+ strMName[msg]);
-+ break;
-+ }
-+
-+ pcid = &pptpReq.iccon->peersCallID;
-+ cid = &info->pac_call_id;
-+
-+ if (info->pns_call_id != ntohs(*pcid)) {
-+ DEBUGP("%s for unknown CallID %u\n",
-+ strMName[msg], ntohs(*cid));
-+ break;
-+ }
-+
-+ DEBUGP("%s, PCID=%X\n", strMName[msg], ntohs(*pcid));
-+ info->cstate = PPTP_CALL_IN_CONF;
-+
-+ /* we expect a GRE connection from PAC to PNS */
-+ seq = ntohl(tcph->seq) + ((void *)pcid - (void *)pptph);
-+ if (exp_gre(ct, seq, *cid, *pcid) != 0)
-+ printk("ip_conntrack_pptp: error during exp_gre\n");
-+
-+ break;
-+
-+ case PPTP_CALL_DISCONNECT_NOTIFY:
-+ /* server confirms disconnect */
-+ cid = &pptpReq.disc->callID;
-+ DEBUGP("%s, CID=%X\n", strMName[msg], ntohs(*cid));
-+ info->cstate = PPTP_CALL_NONE;
-+
-+ /* untrack this call id, unexpect GRE packets */
-+ pptp_timeout_related(ct);
-+ break;
-+
-+ case PPTP_WAN_ERROR_NOTIFY:
-+ break;
-+
-+ case PPTP_ECHO_REQUEST:
-+ case PPTP_ECHO_REPLY:
-+ /* I don't have to explain these ;) */
-+ break;
-+ default:
-+ DEBUGP("invalid %s (TY=%d)\n", (msg <= PPTP_MSG_MAX)
-+ ? strMName[msg]:strMName[0], msg);
-+ break;
-+ }
-+
-+ return NF_ACCEPT;
-+
-+}
-+
-+static inline int
-+pptp_outbound_pkt(struct tcphdr *tcph,
-+ struct pptp_pkt_hdr *pptph,
-+ size_t datalen,
-+ struct ip_conntrack *ct,
-+ enum ip_conntrack_info ctinfo)
-+{
-+ struct PptpControlHeader *ctlh;
-+ union pptp_ctrl_union pptpReq;
-+ struct ip_ct_pptp_master *info = &ct->help.ct_pptp_info;
-+ u_int16_t msg, *cid, *pcid;
-+
-+ ctlh = (struct PptpControlHeader *) ((void *) pptph + sizeof(*pptph));
-+ pptpReq.rawreq = (void *) ((void *) ctlh + sizeof(*ctlh));
-+
-+ msg = ntohs(ctlh->messageType);
-+ DEBUGP("outbound control message %s\n", strMName[msg]);
-+
-+ switch (msg) {
-+ case PPTP_START_SESSION_REQUEST:
-+ /* client requests for new control session */
-+ if (info->sstate != PPTP_SESSION_NONE) {
-+ DEBUGP("%s but we already have one",
-+ strMName[msg]);
-+ }
-+ info->sstate = PPTP_SESSION_REQUESTED;
-+ break;
-+ case PPTP_STOP_SESSION_REQUEST:
-+ /* client requests end of control session */
-+ info->sstate = PPTP_SESSION_STOPREQ;
-+ break;
-+
-+ case PPTP_OUT_CALL_REQUEST:
-+ /* client initiating connection to server */
-+ if (info->sstate != PPTP_SESSION_CONFIRMED) {
-+ DEBUGP("%s but no session\n",
-+ strMName[msg]);
-+ break;
-+ }
-+ info->cstate = PPTP_CALL_OUT_REQ;
-+ /* track PNS call id */
-+ cid = &pptpReq.ocreq->callID;
-+ DEBUGP("%s, CID=%X\n", strMName[msg], ntohs(*cid));
-+ info->pns_call_id = ntohs(*cid);
-+ break;
-+ case PPTP_IN_CALL_REPLY:
-+ /* client answers incoming call */
-+ if (info->cstate != PPTP_CALL_IN_REQ
-+ && info->cstate != PPTP_CALL_IN_REP) {
-+ DEBUGP("%s without incall_req\n",
-+ strMName[msg]);
-+ break;
-+ }
-+ if (pptpReq.icack->resultCode != PPTP_INCALL_ACCEPT) {
-+ info->cstate = PPTP_CALL_NONE;
-+ break;
-+ }
-+ pcid = &pptpReq.icack->peersCallID;
-+ if (info->pac_call_id != ntohs(*pcid)) {
-+ DEBUGP("%s for unknown call %u\n",
-+ strMName[msg], ntohs(*pcid));
-+ break;
-+ }
-+ DEBUGP("%s, CID=%X\n", strMName[msg], ntohs(*pcid));
-+ /* part two of the three-way handshake */
-+ info->cstate = PPTP_CALL_IN_REP;
-+ info->pns_call_id = ntohs(pptpReq.icack->callID);
-+ break;
-+
-+ case PPTP_CALL_CLEAR_REQUEST:
-+ /* client requests hangup of call */
-+ if (info->sstate != PPTP_SESSION_CONFIRMED) {
-+ DEBUGP("CLEAR_CALL but no session\n");
-+ break;
-+ }
-+ /* FUTURE: iterate over all calls and check if
-+ * call ID is valid. We don't do this without newnat,
-+ * because we only know about last call */
-+ info->cstate = PPTP_CALL_CLEAR_REQ;
-+ break;
-+ case PPTP_SET_LINK_INFO:
-+ break;
-+ case PPTP_ECHO_REQUEST:
-+ case PPTP_ECHO_REPLY:
-+ /* I don't have to explain these ;) */
-+ break;
-+ default:
-+ DEBUGP("invalid %s (TY=%d)\n", (msg <= PPTP_MSG_MAX)?
-+ strMName[msg]:strMName[0], msg);
-+ /* unknown: no need to create GRE masq table entry */
-+ break;
-+ }
-+
-+ return NF_ACCEPT;
-+}
-+
-+
-+/* track caller id inside control connection, call expect_related */
-+static int
-+conntrack_pptp_help(const struct iphdr *iph, size_t len,
-+ struct ip_conntrack *ct, enum ip_conntrack_info ctinfo)
-+
-+{
-+ struct pptp_pkt_hdr *pptph;
-+
-+ struct tcphdr *tcph = (void *) iph + iph->ihl * 4;
-+ u_int32_t tcplen = len - iph->ihl * 4;
-+ u_int32_t datalen = tcplen - tcph->doff * 4;
-+ void *datalimit;
-+ int dir = CTINFO2DIR(ctinfo);
-+ struct ip_ct_pptp_master *info = &ct->help.ct_pptp_info;
-+
-+ int oldsstate, oldcstate;
-+ int ret;
-+
-+ /* don't do any tracking before tcp handshake complete */
-+ if (ctinfo != IP_CT_ESTABLISHED
-+ && ctinfo != IP_CT_ESTABLISHED+IP_CT_IS_REPLY) {
-+ DEBUGP("ctinfo = %u, skipping\n", ctinfo);
-+ return NF_ACCEPT;
-+ }
-+
-+ /* not a complete TCP header? */
-+ if (tcplen < sizeof(struct tcphdr) || tcplen < tcph->doff * 4) {
-+ DEBUGP("tcplen = %u\n", tcplen);
-+ return NF_ACCEPT;
-+ }
-+
-+ /* checksum invalid? */
-+ if (tcp_v4_check(tcph, tcplen, iph->saddr, iph->daddr,
-+ csum_partial((char *) tcph, tcplen, 0))) {
-+ printk(KERN_NOTICE __FILE__ ": bad csum\n");
-+ /* W2K PPTP server sends TCP packets with wrong checksum :(( */
-+ //return NF_ACCEPT;
-+ }
-+
-+ if (tcph->fin || tcph->rst) {
-+ DEBUGP("RST/FIN received, timeouting GRE\n");
-+ /* can't do this after real newnat */
-+ info->cstate = PPTP_CALL_NONE;
-+
-+ /* untrack this call id, unexpect GRE packets */
-+ pptp_timeout_related(ct);
-+ }
-+
-+
-+ pptph = (struct pptp_pkt_hdr *) ((void *) tcph + tcph->doff * 4);
-+ datalimit = (void *) pptph + datalen;
-+
-+ /* not a full pptp packet header? */
-+ if ((void *) pptph+sizeof(*pptph) >= datalimit) {
-+ DEBUGP("no full PPTP header, can't track\n");
-+ return NF_ACCEPT;
-+ }
-+
-+ /* if it's not a control message we can't do anything with it */
-+ if (ntohs(pptph->packetType) != PPTP_PACKET_CONTROL ||
-+ ntohl(pptph->magicCookie) != PPTP_MAGIC_COOKIE) {
-+ DEBUGP("not a control packet\n");
-+ return NF_ACCEPT;
-+ }
-+
-+ oldsstate = info->sstate;
-+ oldcstate = info->cstate;
-+
-+ LOCK_BH(&ip_pptp_lock);
-+
-+ /* FIXME: We just blindly assume that the control connection is always
-+ * established from PNS->PAC. However, RFC makes no guarantee */
-+ if (dir == IP_CT_DIR_ORIGINAL)
-+ /* client -> server (PNS -> PAC) */
-+ ret = pptp_outbound_pkt(tcph, pptph, datalen, ct, ctinfo);
-+ else
-+ /* server -> client (PAC -> PNS) */
-+ ret = pptp_inbound_pkt(tcph, pptph, datalen, ct, ctinfo);
-+ DEBUGP("sstate: %d->%d, cstate: %d->%d\n",
-+ oldsstate, info->sstate, oldcstate, info->cstate);
-+ UNLOCK_BH(&ip_pptp_lock);
-+
-+ return ret;
-+}
-+
-+/* control protocol helper */
-+static struct ip_conntrack_helper pptp = {
-+ .list = { NULL, NULL },
-+ .name = "pptp",
-+ .flags = IP_CT_HELPER_F_REUSE_EXPECT,
-+ .me = THIS_MODULE,
-+ .max_expected = 2,
-+ .timeout = 0,
-+ .tuple = { .src = { .ip = 0,
-+ .u = { .tcp = { .port =
-+ __constant_htons(PPTP_CONTROL_PORT) } }
-+ },
-+ .dst = { .ip = 0,
-+ .u = { .all = 0 },
-+ .protonum = IPPROTO_TCP
-+ }
-+ },
-+ .mask = { .src = { .ip = 0,
-+ .u = { .tcp = { .port = 0xffff } }
-+ },
-+ .dst = { .ip = 0,
-+ .u = { .all = 0 },
-+ .protonum = 0xffff
-+ }
-+ },
-+ .help = conntrack_pptp_help
-+};
-+
-+/* ip_conntrack_pptp initialization */
-+static int __init init(void)
-+{
-+ int retcode;
-+
-+ DEBUGP(__FILE__ ": registering helper\n");
-+ if ((retcode = ip_conntrack_helper_register(&pptp))) {
-+ printk(KERN_ERR "Unable to register conntrack application "
-+ "helper for pptp: %d\n", retcode);
-+ return -EIO;
-+ }
-+
-+ printk("ip_conntrack_pptp version %s loaded\n", IP_CT_PPTP_VERSION);
-+ return 0;
-+}
-+
-+static void __exit fini(void)
-+{
-+ ip_conntrack_helper_unregister(&pptp);
-+ printk("ip_conntrack_pptp version %s unloaded\n", IP_CT_PPTP_VERSION);
-+}
-+
-+module_init(init);
-+module_exit(fini);
-+
-+EXPORT_SYMBOL(ip_pptp_lock);
-diff -uNr linux_org/net/ipv4/netfilter/ip_conntrack_pptp_priv.h linux/net/ipv4/netfilter/ip_conntrack_pptp_priv.h
---- linux_org/net/ipv4/netfilter/ip_conntrack_pptp_priv.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux/net/ipv4/netfilter/ip_conntrack_pptp_priv.h 2006-10-27 14:11:52.000000000 +0200
-@@ -0,0 +1,24 @@
-+#ifndef _IP_CT_PPTP_PRIV_H
-+#define _IP_CT_PPTP_PRIV_H
-+
-+/* PptpControlMessageType names */
-+static const char *strMName[] = {
-+ "UNKNOWN_MESSAGE",
-+ "START_SESSION_REQUEST",
-+ "START_SESSION_REPLY",
-+ "STOP_SESSION_REQUEST",
-+ "STOP_SESSION_REPLY",
-+ "ECHO_REQUEST",
-+ "ECHO_REPLY",
-+ "OUT_CALL_REQUEST",
-+ "OUT_CALL_REPLY",
-+ "IN_CALL_REQUEST",
-+ "IN_CALL_REPLY",
-+ "IN_CALL_CONNECT",
-+ "CALL_CLEAR_REQUEST",
-+ "CALL_DISCONNECT_NOTIFY",
-+ "WAN_ERROR_NOTIFY",
-+ "SET_LINK_INFO"
-+};
-+
-+#endif
-diff -uNr linux_org/net/ipv4/netfilter/ip_conntrack_proto_gre.c linux/net/ipv4/netfilter/ip_conntrack_proto_gre.c
---- linux_org/net/ipv4/netfilter/ip_conntrack_proto_gre.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux/net/ipv4/netfilter/ip_conntrack_proto_gre.c 2006-10-27 14:11:52.000000000 +0200
-@@ -0,0 +1,343 @@
-+/*
-+ * ip_conntrack_proto_gre.c - Version 1.2
-+ *
-+ * Connection tracking protocol helper module for GRE.
-+ *
-+ * GRE is a generic encapsulation protocol, which is generally not very
-+ * suited for NAT, as it has no protocol-specific part as port numbers.
-+ *
-+ * It has an optional key field, which may help us distinguishing two
-+ * connections between the same two hosts.
-+ *
-+ * GRE is defined in RFC 1701 and RFC 1702, as well as RFC 2784
-+ *
-+ * PPTP is built on top of a modified version of GRE, and has a mandatory
-+ * field called "CallID", which serves us for the same purpose as the key
-+ * field in plain GRE.
-+ *
-+ * Documentation about PPTP can be found in RFC 2637
-+ *
-+ * (C) 2000-2003 by Harald Welte <laforge@gnumonks.org>
-+ *
-+ * Development of this code funded by Astaro AG (http://www.astaro.com/)
-+ *
-+ */
-+
-+#include <linux/config.h>
-+#include <linux/module.h>
-+#include <linux/types.h>
-+#include <linux/timer.h>
-+#include <linux/netfilter.h>
-+#include <linux/ip.h>
-+#include <linux/in.h>
-+#include <linux/list.h>
-+
-+#include <linux/netfilter_ipv4/lockhelp.h>
-+
-+DECLARE_RWLOCK(ip_ct_gre_lock);
-+#define ASSERT_READ_LOCK(x) MUST_BE_READ_LOCKED(&ip_ct_gre_lock)
-+#define ASSERT_WRITE_LOCK(x) MUST_BE_WRITE_LOCKED(&ip_ct_gre_lock)
-+
-+#include <linux/netfilter_ipv4/listhelp.h>
-+#include <linux/netfilter_ipv4/ip_conntrack_protocol.h>
-+#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
-+#include <linux/netfilter_ipv4/ip_conntrack_core.h>
-+
-+#include <linux/netfilter_ipv4/ip_conntrack_proto_gre.h>
-+#include <linux/netfilter_ipv4/ip_conntrack_pptp.h>
-+
-+MODULE_LICENSE("GPL");
-+MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>");
-+MODULE_DESCRIPTION("netfilter connection tracking protocol helper for GRE");
-+
-+/* shamelessly stolen from ip_conntrack_proto_udp.c */
-+#define GRE_TIMEOUT (30*HZ)
-+#define GRE_STREAM_TIMEOUT (180*HZ)
-+
-+#if 0
-+#define DEBUGP(format, args...) printk(KERN_DEBUG __FILE__ ":" __FUNCTION__ \
-+ ": " format, ## args)
-+#define DUMP_TUPLE_GRE(x) printk("%u.%u.%u.%u:0x%x -> %u.%u.%u.%u:0x%x:%u:0x%x\n", \
-+ NIPQUAD((x)->src.ip), ntohl((x)->src.u.gre.key), \
-+ NIPQUAD((x)->dst.ip), ntohl((x)->dst.u.gre.key), \
-+ (x)->dst.u.gre.version, \
-+ ntohs((x)->dst.u.gre.protocol))
-+#else
-+#define DEBUGP(x, args...)
-+#define DUMP_TUPLE_GRE(x)
-+#endif
-+
-+/* GRE KEYMAP HANDLING FUNCTIONS */
-+static LIST_HEAD(gre_keymap_list);
-+
-+static inline int gre_key_cmpfn(const struct ip_ct_gre_keymap *km,
-+ const struct ip_conntrack_tuple *t)
-+{
-+ return ((km->tuple.src.ip == t->src.ip) &&
-+ (km->tuple.dst.ip == t->dst.ip) &&
-+ (km->tuple.dst.protonum == t->dst.protonum) &&
-+ (km->tuple.dst.u.all == t->dst.u.all));
-+}
-+
-+/* look up the source key for a given tuple */
-+static u_int32_t gre_keymap_lookup(struct ip_conntrack_tuple *t)
-+{
-+ struct ip_ct_gre_keymap *km;
-+ u_int32_t key;
-+
-+ READ_LOCK(&ip_ct_gre_lock);
-+ km = LIST_FIND(&gre_keymap_list, gre_key_cmpfn,
-+ struct ip_ct_gre_keymap *, t);
-+ if (!km) {
-+ READ_UNLOCK(&ip_ct_gre_lock);
-+ return 0;
-+ }
-+
-+ key = km->tuple.src.u.gre.key;
-+ READ_UNLOCK(&ip_ct_gre_lock);
-+
-+ return key;
-+}
-+
-+/* add a single keymap entry, associate with specified expect */
-+int ip_ct_gre_keymap_add(struct ip_conntrack_expect *exp,
-+ struct ip_conntrack_tuple *t, int reply)
-+{
-+ struct ip_ct_gre_keymap *km;
-+
-+ km = kmalloc(sizeof(*km), GFP_ATOMIC);
-+ if (!km)
-+ return -1;
-+
-+ /* initializing list head should be sufficient */
-+ memset(km, 0, sizeof(*km));
-+
-+ memcpy(&km->tuple, t, sizeof(*t));
-+
-+ if (!reply)
-+ exp->proto.gre.keymap_orig = km;
-+ else
-+ exp->proto.gre.keymap_reply = km;
-+
-+ DEBUGP("adding new entry %p: ", km);
-+ DUMP_TUPLE_GRE(&km->tuple);
-+
-+ WRITE_LOCK(&ip_ct_gre_lock);
-+ list_append(&gre_keymap_list, km);
-+ WRITE_UNLOCK(&ip_ct_gre_lock);
-+
-+ return 0;
-+}
-+
-+/* change the tuple of a keymap entry (used by nat helper) */
-+void ip_ct_gre_keymap_change(struct ip_ct_gre_keymap *km,
-+ struct ip_conntrack_tuple *t)
-+{
-+ DEBUGP("changing entry %p to: ", km);
-+ DUMP_TUPLE_GRE(t);
-+
-+ WRITE_LOCK(&ip_ct_gre_lock);
-+ memcpy(&km->tuple, t, sizeof(km->tuple));
-+ WRITE_UNLOCK(&ip_ct_gre_lock);
-+}
-+
-+/* destroy the keymap entries associated with specified expect */
-+void ip_ct_gre_keymap_destroy(struct ip_conntrack_expect *exp)
-+{
-+ DEBUGP("entering for exp %p\n", exp);
-+ WRITE_LOCK(&ip_ct_gre_lock);
-+ if (exp->proto.gre.keymap_orig) {
-+ DEBUGP("removing %p from list\n", exp->proto.gre.keymap_orig);
-+ list_del(&exp->proto.gre.keymap_orig->list);
-+ kfree(exp->proto.gre.keymap_orig);
-+ exp->proto.gre.keymap_orig = NULL;
-+ }
-+ if (exp->proto.gre.keymap_reply) {
-+ DEBUGP("removing %p from list\n", exp->proto.gre.keymap_reply);
-+ list_del(&exp->proto.gre.keymap_reply->list);
-+ kfree(exp->proto.gre.keymap_reply);
-+ exp->proto.gre.keymap_reply = NULL;
-+ }
-+ WRITE_UNLOCK(&ip_ct_gre_lock);
-+}
-+
-+
-+/* PUBLIC CONNTRACK PROTO HELPER FUNCTIONS */
-+
-+/* invert gre part of tuple */
-+static int gre_invert_tuple(struct ip_conntrack_tuple *tuple,
-+ const struct ip_conntrack_tuple *orig)
-+{
-+ tuple->dst.u.gre.protocol = orig->dst.u.gre.protocol;
-+ tuple->dst.u.gre.version = orig->dst.u.gre.version;
-+
-+ tuple->dst.u.gre.key = orig->src.u.gre.key;
-+ tuple->src.u.gre.key = orig->dst.u.gre.key;
-+
-+ return 1;
-+}
-+
-+/* gre hdr info to tuple */
-+static int gre_pkt_to_tuple(const void *datah, size_t datalen,
-+ struct ip_conntrack_tuple *tuple)
-+{
-+ struct gre_hdr *grehdr = (struct gre_hdr *) datah;
-+ struct gre_hdr_pptp *pgrehdr = (struct gre_hdr_pptp *) datah;
-+ u_int32_t srckey;
-+
-+ /* core guarantees 8 protocol bytes, no need for size check */
-+
-+ tuple->dst.u.gre.version = grehdr->version;
-+ tuple->dst.u.gre.protocol = grehdr->protocol;
-+
-+ switch (grehdr->version) {
-+ case GRE_VERSION_1701:
-+ if (!grehdr->key) {
-+ DEBUGP("Can't track GRE without key\n");
-+ return 0;
-+ }
-+ tuple->dst.u.gre.key = *(gre_key(grehdr));
-+ break;
-+
-+ case GRE_VERSION_PPTP:
-+ if (ntohs(grehdr->protocol) != GRE_PROTOCOL_PPTP) {
-+ DEBUGP("GRE_VERSION_PPTP but unknown proto\n");
-+ return 0;
-+ }
-+ tuple->dst.u.gre.key = htonl(ntohs(pgrehdr->call_id));
-+ break;
-+
-+ default:
-+ printk(KERN_WARNING "unknown GRE version %hu\n",
-+ tuple->dst.u.gre.version);
-+ return 0;
-+ }
-+
-+ srckey = gre_keymap_lookup(tuple);
-+
-+#if 0
-+ DEBUGP("found src key %x for tuple ", ntohl(srckey));
-+ DUMP_TUPLE_GRE(tuple);
-+#endif
-+ tuple->src.u.gre.key = srckey;
-+
-+ return 1;
-+}
-+
-+/* print gre part of tuple */
-+static unsigned int gre_print_tuple(char *buffer,
-+ const struct ip_conntrack_tuple *tuple)
-+{
-+ return sprintf(buffer, "version=%d protocol=0x%04x srckey=0x%x dstkey=0x%x ",
-+ tuple->dst.u.gre.version,
-+ ntohs(tuple->dst.u.gre.protocol),
-+ ntohl(tuple->src.u.gre.key),
-+ ntohl(tuple->dst.u.gre.key));
-+}
-+
-+/* print private data for conntrack */
-+static unsigned int gre_print_conntrack(char *buffer,
-+ const struct ip_conntrack *ct)
-+{
-+ return sprintf(buffer, "timeout=%u, stream_timeout=%u ",
-+ (ct->proto.gre.timeout / HZ),
-+ (ct->proto.gre.stream_timeout / HZ));
-+}
-+
-+/* Returns verdict for packet, and may modify conntrack */
-+static int gre_packet(struct ip_conntrack *ct,
-+ struct iphdr *iph, size_t len,
-+ enum ip_conntrack_info conntrackinfo)
-+{
-+ /* If we've seen traffic both ways, this is a GRE connection.
-+ * Extend timeout. */
-+ if (ct->status & IPS_SEEN_REPLY) {
-+ ip_ct_refresh(ct, ct->proto.gre.stream_timeout);
-+ /* Also, more likely to be important, and not a probe. */
-+ set_bit(IPS_ASSURED_BIT, &ct->status);
-+ } else
-+ ip_ct_refresh(ct, ct->proto.gre.timeout);
-+
-+ return NF_ACCEPT;
-+}
-+
-+/* Called when a new connection for this protocol found. */
-+static int gre_new(struct ip_conntrack *ct,
-+ struct iphdr *iph, size_t len)
-+{
-+ DEBUGP(": ");
-+ DUMP_TUPLE_GRE(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
-+
-+ /* initialize to sane value. Ideally a conntrack helper
-+ * (e.g. in case of pptp) is increasing them */
-+ ct->proto.gre.stream_timeout = GRE_STREAM_TIMEOUT;
-+ ct->proto.gre.timeout = GRE_TIMEOUT;
-+
-+ return 1;
-+}
-+
-+/* Called when a conntrack entry has already been removed from the hashes
-+ * and is about to be deleted from memory */
-+static void gre_destroy(struct ip_conntrack *ct)
-+{
-+ struct ip_conntrack_expect *master = ct->master;
-+
-+ DEBUGP(" entering\n");
-+
-+ if (!master) {
-+ DEBUGP("no master exp for ct %p\n", ct);
-+ return;
-+ }
-+
-+ ip_ct_gre_keymap_destroy(master);
-+}
-+
-+/* protocol helper struct */
-+static struct ip_conntrack_protocol gre = { { NULL, NULL }, IPPROTO_GRE,
-+ "gre",
-+ gre_pkt_to_tuple,
-+ gre_invert_tuple,
-+ gre_print_tuple,
-+ gre_print_conntrack,
-+ gre_packet,
-+ gre_new,
-+ gre_destroy,
-+ NULL,
-+ THIS_MODULE };
-+
-+/* ip_conntrack_proto_gre initialization */
-+static int __init init(void)
-+{
-+ int retcode;
-+
-+ if ((retcode = ip_conntrack_protocol_register(&gre))) {
-+ printk(KERN_ERR "Unable to register conntrack protocol "
-+ "helper for gre: %d\n", retcode);
-+ return -EIO;
-+ }
-+
-+ return 0;
-+}
-+
-+static void __exit fini(void)
-+{
-+ struct list_head *pos, *n;
-+
-+ /* delete all keymap entries */
-+ WRITE_LOCK(&ip_ct_gre_lock);
-+ list_for_each_safe(pos, n, &gre_keymap_list) {
-+ DEBUGP("deleting keymap %p at module unload time\n", pos);
-+ list_del(pos);
-+ kfree(pos);
-+ }
-+ WRITE_UNLOCK(&ip_ct_gre_lock);
-+
-+ ip_conntrack_protocol_unregister(&gre);
-+}
-+
-+EXPORT_SYMBOL(ip_ct_gre_keymap_add);
-+EXPORT_SYMBOL(ip_ct_gre_keymap_change);
-+EXPORT_SYMBOL(ip_ct_gre_keymap_destroy);
-+
-+module_init(init);
-+module_exit(fini);
-diff -uNr linux_org/net/ipv4/netfilter/ip_nat_core.c linux/net/ipv4/netfilter/ip_nat_core.c
---- linux_org/net/ipv4/netfilter/ip_nat_core.c 2004-11-24 12:14:04.000000000 +0100
-+++ linux/net/ipv4/netfilter/ip_nat_core.c 2006-10-27 14:11:52.000000000 +0200
-@@ -430,7 +430,7 @@
- *tuple = *orig_tuple;
- while ((rptr = find_best_ips_proto_fast(tuple, mr, conntrack, hooknum))
- != NULL) {
-- DEBUGP("Found best for "); DUMP_TUPLE(tuple);
-+ DEBUGP("Found best for "); DUMP_TUPLE_RAW(tuple);
- /* 3) The per-protocol part of the manip is made to
- map into the range to make a unique tuple. */
-
-@@ -572,9 +572,9 @@
- HOOK2MANIP(hooknum)==IP_NAT_MANIP_SRC ? "SRC" : "DST",
- conntrack);
- DEBUGP("Original: ");
-- DUMP_TUPLE(&orig_tp);
-+ DUMP_TUPLE_RAW(&orig_tp);
- DEBUGP("New: ");
-- DUMP_TUPLE(&new_tuple);
-+ DUMP_TUPLE_RAW(&new_tuple);
- #endif
-
- /* We now have two tuples (SRCIP/SRCPT/DSTIP/DSTPT):
-diff -uNr linux_org/net/ipv4/netfilter/ip_nat_core.c.orig linux/net/ipv4/netfilter/ip_nat_core.c.orig
---- linux_org/net/ipv4/netfilter/ip_nat_core.c.orig 1970-01-01 01:00:00.000000000 +0100
-+++ linux/net/ipv4/netfilter/ip_nat_core.c.orig 2004-11-24 12:14:04.000000000 +0100
-@@ -0,0 +1,1014 @@
-+/* NAT for netfilter; shared with compatibility layer. */
-+
-+/* (c) 1999 Paul `Rusty' Russell. Licenced under the GNU General
-+ Public Licence. */
-+#include <linux/version.h>
-+#include <linux/module.h>
-+#include <linux/types.h>
-+#include <linux/timer.h>
-+#include <linux/skbuff.h>
-+#include <linux/netfilter_ipv4.h>
-+#include <linux/brlock.h>
-+#include <linux/vmalloc.h>
-+#include <net/checksum.h>
-+#include <net/icmp.h>
-+#include <net/ip.h>
-+#include <net/tcp.h> /* For tcp_prot in getorigdst */
-+
-+#define ASSERT_READ_LOCK(x) MUST_BE_READ_LOCKED(&ip_nat_lock)
-+#define ASSERT_WRITE_LOCK(x) MUST_BE_WRITE_LOCKED(&ip_nat_lock)
-+
-+#include <linux/netfilter_ipv4/ip_conntrack.h>
-+#include <linux/netfilter_ipv4/ip_conntrack_core.h>
-+#include <linux/netfilter_ipv4/ip_conntrack_protocol.h>
-+#include <linux/netfilter_ipv4/ip_nat.h>
-+#include <linux/netfilter_ipv4/ip_nat_protocol.h>
-+#include <linux/netfilter_ipv4/ip_nat_core.h>
-+#include <linux/netfilter_ipv4/ip_nat_helper.h>
-+#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
-+#include <linux/netfilter_ipv4/listhelp.h>
-+
-+#if 0
-+#define DEBUGP printk
-+#else
-+#define DEBUGP(format, args...)
-+#endif
-+
-+DECLARE_RWLOCK(ip_nat_lock);
-+DECLARE_RWLOCK_EXTERN(ip_conntrack_lock);
-+
-+/* Calculated at init based on memory size */
-+static unsigned int ip_nat_htable_size;
-+
-+static struct list_head *bysource;
-+static struct list_head *byipsproto;
-+LIST_HEAD(protos);
-+LIST_HEAD(helpers);
-+
-+extern struct ip_nat_protocol unknown_nat_protocol;
-+
-+/* We keep extra hashes for each conntrack, for fast searching. */
-+static inline size_t
-+hash_by_ipsproto(u_int32_t src, u_int32_t dst, u_int16_t proto)
-+{
-+ /* Modified src and dst, to ensure we don't create two
-+ identical streams. */
-+ return (src + dst + proto) % ip_nat_htable_size;
-+}
-+
-+static inline size_t
-+hash_by_src(const struct ip_conntrack_manip *manip, u_int16_t proto)
-+{
-+ /* Original src, to ensure we map it consistently if poss. */
-+ return (manip->ip + manip->u.all + proto) % ip_nat_htable_size;
-+}
-+
-+/* Noone using conntrack by the time this called. */
-+static void ip_nat_cleanup_conntrack(struct ip_conntrack *conn)
-+{
-+ struct ip_nat_info *info = &conn->nat.info;
-+ unsigned int hs, hp;
-+
-+ if (!info->initialized)
-+ return;
-+
-+ IP_NF_ASSERT(info->bysource.conntrack);
-+ IP_NF_ASSERT(info->byipsproto.conntrack);
-+
-+ hs = hash_by_src(&conn->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src,
-+ conn->tuplehash[IP_CT_DIR_ORIGINAL]
-+ .tuple.dst.protonum);
-+
-+ hp = hash_by_ipsproto(conn->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip,
-+ conn->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip,
-+ conn->tuplehash[IP_CT_DIR_REPLY]
-+ .tuple.dst.protonum);
-+
-+ WRITE_LOCK(&ip_nat_lock);
-+ LIST_DELETE(&bysource[hs], &info->bysource);
-+ LIST_DELETE(&byipsproto[hp], &info->byipsproto);
-+ WRITE_UNLOCK(&ip_nat_lock);
-+}
-+
-+/* We do checksum mangling, so if they were wrong before they're still
-+ * wrong. Also works for incomplete packets (eg. ICMP dest
-+ * unreachables.) */
-+u_int16_t
-+ip_nat_cheat_check(u_int32_t oldvalinv, u_int32_t newval, u_int16_t oldcheck)
-+{
-+ u_int32_t diffs[] = { oldvalinv, newval };
-+ return csum_fold(csum_partial((char *)diffs, sizeof(diffs),
-+ oldcheck^0xFFFF));
-+}
-+
-+static inline int cmp_proto(const struct ip_nat_protocol *i, int proto)
-+{
-+ return i->protonum == proto;
-+}
-+
-+struct ip_nat_protocol *
-+find_nat_proto(u_int16_t protonum)
-+{
-+ struct ip_nat_protocol *i;
-+
-+ MUST_BE_READ_LOCKED(&ip_nat_lock);
-+ i = LIST_FIND(&protos, cmp_proto, struct ip_nat_protocol *, protonum);
-+ if (!i)
-+ i = &unknown_nat_protocol;
-+ return i;
-+}
-+
-+/* Is this tuple already taken? (not by us) */
-+int
-+ip_nat_used_tuple(const struct ip_conntrack_tuple *tuple,
-+ const struct ip_conntrack *ignored_conntrack)
-+{
-+ /* Conntrack tracking doesn't keep track of outgoing tuples; only
-+ incoming ones. NAT means they don't have a fixed mapping,
-+ so we invert the tuple and look for the incoming reply.
-+
-+ We could keep a separate hash if this proves too slow. */
-+ struct ip_conntrack_tuple reply;
-+
-+ invert_tuplepr(&reply, tuple);
-+ return ip_conntrack_tuple_taken(&reply, ignored_conntrack);
-+}
-+
-+/* Does tuple + the source manip come within the range mr */
-+static int
-+in_range(const struct ip_conntrack_tuple *tuple,
-+ const struct ip_conntrack_manip *manip,
-+ const struct ip_nat_multi_range *mr)
-+{
-+ struct ip_nat_protocol *proto = find_nat_proto(tuple->dst.protonum);
-+ unsigned int i;
-+ struct ip_conntrack_tuple newtuple = { *manip, tuple->dst };
-+
-+ for (i = 0; i < mr->rangesize; i++) {
-+ /* If we are allowed to map IPs, then we must be in the
-+ range specified, otherwise we must be unchanged. */
-+ if (mr->range[i].flags & IP_NAT_RANGE_MAP_IPS) {
-+ if (ntohl(newtuple.src.ip) < ntohl(mr->range[i].min_ip)
-+ || (ntohl(newtuple.src.ip)
-+ > ntohl(mr->range[i].max_ip)))
-+ continue;
-+ } else {
-+ if (newtuple.src.ip != tuple->src.ip)
-+ continue;
-+ }
-+
-+ if ((mr->range[i].flags & IP_NAT_RANGE_PROTO_SPECIFIED)
-+ && proto->in_range(&newtuple, IP_NAT_MANIP_SRC,
-+ &mr->range[i].min, &mr->range[i].max))
-+ return 1;
-+ }
-+ return 0;
-+}
-+
-+static inline int
-+src_cmp(const struct ip_nat_hash *i,
-+ const struct ip_conntrack_tuple *tuple,
-+ const struct ip_nat_multi_range *mr)
-+{
-+ return (i->conntrack->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum
-+ == tuple->dst.protonum
-+ && i->conntrack->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip
-+ == tuple->src.ip
-+ && i->conntrack->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u.all
-+ == tuple->src.u.all
-+ && in_range(tuple,
-+ &i->conntrack->tuplehash[IP_CT_DIR_ORIGINAL]
-+ .tuple.src,
-+ mr));
-+}
-+
-+/* Only called for SRC manip */
-+static struct ip_conntrack_manip *
-+find_appropriate_src(const struct ip_conntrack_tuple *tuple,
-+ const struct ip_nat_multi_range *mr)
-+{
-+ unsigned int h = hash_by_src(&tuple->src, tuple->dst.protonum);
-+ struct ip_nat_hash *i;
-+
-+ MUST_BE_READ_LOCKED(&ip_nat_lock);
-+ i = LIST_FIND(&bysource[h], src_cmp, struct ip_nat_hash *, tuple, mr);
-+ if (i)
-+ return &i->conntrack->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src;
-+ else
-+ return NULL;
-+}
-+
-+#ifdef CONFIG_IP_NF_NAT_LOCAL
-+/* If it's really a local destination manip, it may need to do a
-+ source manip too. */
-+static int
-+do_extra_mangle(u_int32_t var_ip, u_int32_t *other_ipp)
-+{
-+ struct rtable *rt;
-+
-+ /* FIXME: IPTOS_TOS(iph->tos) --RR */
-+ if (ip_route_output(&rt, var_ip, 0, 0, 0) != 0) {
-+ DEBUGP("do_extra_mangle: Can't get route to %u.%u.%u.%u\n",
-+ NIPQUAD(var_ip));
-+ return 0;
-+ }
-+
-+ *other_ipp = rt->rt_src;
-+ ip_rt_put(rt);
-+ return 1;
-+}
-+#endif
-+
-+/* Simple way to iterate through all. */
-+static inline int fake_cmp(const struct ip_nat_hash *i,
-+ u_int32_t src, u_int32_t dst, u_int16_t protonum,
-+ unsigned int *score,
-+ const struct ip_conntrack *conntrack)
-+{
-+ /* Compare backwards: we're dealing with OUTGOING tuples, and
-+ inside the conntrack is the REPLY tuple. Don't count this
-+ conntrack. */
-+ if (i->conntrack != conntrack
-+ && i->conntrack->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip == dst
-+ && i->conntrack->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip == src
-+ && (i->conntrack->tuplehash[IP_CT_DIR_REPLY].tuple.dst.protonum
-+ == protonum))
-+ (*score)++;
-+ return 0;
-+}
-+
-+static inline unsigned int
-+count_maps(u_int32_t src, u_int32_t dst, u_int16_t protonum,
-+ const struct ip_conntrack *conntrack)
-+{
-+ unsigned int score = 0;
-+ unsigned int h;
-+
-+ MUST_BE_READ_LOCKED(&ip_nat_lock);
-+ h = hash_by_ipsproto(src, dst, protonum);
-+ LIST_FIND(&byipsproto[h], fake_cmp, struct ip_nat_hash *,
-+ src, dst, protonum, &score, conntrack);
-+
-+ return score;
-+}
-+
-+/* For [FUTURE] fragmentation handling, we want the least-used
-+ src-ip/dst-ip/proto triple. Fairness doesn't come into it. Thus
-+ if the range specifies 1.2.3.4 ports 10000-10005 and 1.2.3.5 ports
-+ 1-65535, we don't do pro-rata allocation based on ports; we choose
-+ the ip with the lowest src-ip/dst-ip/proto usage.
-+
-+ If an allocation then fails (eg. all 6 ports used in the 1.2.3.4
-+ range), we eliminate that and try again. This is not the most
-+ efficient approach, but if you're worried about that, don't hand us
-+ ranges you don't really have. */
-+static struct ip_nat_range *
-+find_best_ips_proto(struct ip_conntrack_tuple *tuple,
-+ const struct ip_nat_multi_range *mr,
-+ const struct ip_conntrack *conntrack,
-+ unsigned int hooknum)
-+{
-+ unsigned int i;
-+ struct {
-+ const struct ip_nat_range *range;
-+ unsigned int score;
-+ struct ip_conntrack_tuple tuple;
-+ } best = { NULL, 0xFFFFFFFF };
-+ u_int32_t *var_ipp, *other_ipp, saved_ip, orig_dstip;
-+ static unsigned int randomness = 0;
-+
-+ if (HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC) {
-+ var_ipp = &tuple->src.ip;
-+ saved_ip = tuple->dst.ip;
-+ other_ipp = &tuple->dst.ip;
-+ } else {
-+ var_ipp = &tuple->dst.ip;
-+ saved_ip = tuple->src.ip;
-+ other_ipp = &tuple->src.ip;
-+ }
-+ /* Don't do do_extra_mangle unless neccessary (overrides
-+ explicit socket bindings, for example) */
-+ orig_dstip = tuple->dst.ip;
-+
-+ IP_NF_ASSERT(mr->rangesize >= 1);
-+ for (i = 0; i < mr->rangesize; i++) {
-+ /* Host order */
-+ u_int32_t minip, maxip, j;
-+
-+ /* Don't do ranges which are already eliminated. */
-+ if (mr->range[i].flags & IP_NAT_RANGE_FULL) {
-+ continue;
-+ }
-+
-+ if (mr->range[i].flags & IP_NAT_RANGE_MAP_IPS) {
-+ minip = ntohl(mr->range[i].min_ip);
-+ maxip = ntohl(mr->range[i].max_ip);
-+ } else
-+ minip = maxip = ntohl(*var_ipp);
-+
-+ randomness++;
-+ for (j = 0; j < maxip - minip + 1; j++) {
-+ unsigned int score;
-+
-+ *var_ipp = htonl(minip + (randomness + j)
-+ % (maxip - minip + 1));
-+
-+ /* Reset the other ip in case it was mangled by
-+ * do_extra_mangle last time. */
-+ *other_ipp = saved_ip;
-+
-+#ifdef CONFIG_IP_NF_NAT_LOCAL
-+ if (hooknum == NF_IP_LOCAL_OUT
-+ && *var_ipp != orig_dstip
-+ && !do_extra_mangle(*var_ipp, other_ipp)) {
-+ DEBUGP("Range %u %u.%u.%u.%u rt failed!\n",
-+ i, NIPQUAD(*var_ipp));
-+ /* Can't route? This whole range part is
-+ * probably screwed, but keep trying
-+ * anyway. */
-+ continue;
-+ }
-+#endif
-+
-+ /* Count how many others map onto this. */
-+ score = count_maps(tuple->src.ip, tuple->dst.ip,
-+ tuple->dst.protonum, conntrack);
-+ if (score < best.score) {
-+ /* Optimization: doesn't get any better than
-+ this. */
-+ if (score == 0)
-+ return (struct ip_nat_range *)
-+ &mr->range[i];
-+
-+ best.score = score;
-+ best.tuple = *tuple;
-+ best.range = &mr->range[i];
-+ }
-+ }
-+ }
-+ *tuple = best.tuple;
-+
-+ /* Discard const. */
-+ return (struct ip_nat_range *)best.range;
-+}
-+
-+/* Fast version doesn't iterate through hash chains, but only handles
-+ common case of single IP address (null NAT, masquerade) */
-+static struct ip_nat_range *
-+find_best_ips_proto_fast(struct ip_conntrack_tuple *tuple,
-+ const struct ip_nat_multi_range *mr,
-+ const struct ip_conntrack *conntrack,
-+ unsigned int hooknum)
-+{
-+ if (mr->rangesize != 1
-+ || (mr->range[0].flags & IP_NAT_RANGE_FULL)
-+ || ((mr->range[0].flags & IP_NAT_RANGE_MAP_IPS)
-+ && mr->range[0].min_ip != mr->range[0].max_ip))
-+ return find_best_ips_proto(tuple, mr, conntrack, hooknum);
-+
-+ if (mr->range[0].flags & IP_NAT_RANGE_MAP_IPS) {
-+ if (HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC)
-+ tuple->src.ip = mr->range[0].min_ip;
-+ else {
-+ /* Only do extra mangle when required (breaks
-+ socket binding) */
-+#ifdef CONFIG_IP_NF_NAT_LOCAL
-+ if (tuple->dst.ip != mr->range[0].min_ip
-+ && hooknum == NF_IP_LOCAL_OUT
-+ && !do_extra_mangle(mr->range[0].min_ip,
-+ &tuple->src.ip))
-+ return NULL;
-+#endif
-+ tuple->dst.ip = mr->range[0].min_ip;
-+ }
-+ }
-+
-+ /* Discard const. */
-+ return (struct ip_nat_range *)&mr->range[0];
-+}
-+
-+static int
-+get_unique_tuple(struct ip_conntrack_tuple *tuple,
-+ const struct ip_conntrack_tuple *orig_tuple,
-+ const struct ip_nat_multi_range *mrr,
-+ struct ip_conntrack *conntrack,
-+ unsigned int hooknum)
-+{
-+ struct ip_nat_protocol *proto
-+ = find_nat_proto(orig_tuple->dst.protonum);
-+ struct ip_nat_range *rptr;
-+ unsigned int i;
-+ int ret;
-+
-+ /* We temporarily use flags for marking full parts, but we
-+ always clean up afterwards */
-+ struct ip_nat_multi_range *mr = (void *)mrr;
-+
-+ /* 1) If this srcip/proto/src-proto-part is currently mapped,
-+ and that same mapping gives a unique tuple within the given
-+ range, use that.
-+
-+ This is only required for source (ie. NAT/masq) mappings.
-+ So far, we don't do local source mappings, so multiple
-+ manips not an issue. */
-+ if (hooknum == NF_IP_POST_ROUTING) {
-+ struct ip_conntrack_manip *manip;
-+
-+ manip = find_appropriate_src(orig_tuple, mr);
-+ if (manip) {
-+ /* Apply same source manipulation. */
-+ *tuple = ((struct ip_conntrack_tuple)
-+ { *manip, orig_tuple->dst });
-+ DEBUGP("get_unique_tuple: Found current src map\n");
-+ return 1;
-+ }
-+ }
-+
-+ /* 2) Select the least-used IP/proto combination in the given
-+ range.
-+ */
-+ *tuple = *orig_tuple;
-+ while ((rptr = find_best_ips_proto_fast(tuple, mr, conntrack, hooknum))
-+ != NULL) {
-+ DEBUGP("Found best for "); DUMP_TUPLE(tuple);
-+ /* 3) The per-protocol part of the manip is made to
-+ map into the range to make a unique tuple. */
-+
-+ /* Only bother mapping if it's not already in range
-+ and unique */
-+ if ((!(rptr->flags & IP_NAT_RANGE_PROTO_SPECIFIED)
-+ || proto->in_range(tuple, HOOK2MANIP(hooknum),
-+ &rptr->min, &rptr->max))
-+ && !ip_nat_used_tuple(tuple, conntrack)) {
-+ ret = 1;
-+ goto clear_fulls;
-+ } else {
-+ if (proto->unique_tuple(tuple, rptr,
-+ HOOK2MANIP(hooknum),
-+ conntrack)) {
-+ /* Must be unique. */
-+ IP_NF_ASSERT(!ip_nat_used_tuple(tuple,
-+ conntrack));
-+ ret = 1;
-+ goto clear_fulls;
-+ } else if (HOOK2MANIP(hooknum) == IP_NAT_MANIP_DST) {
-+ /* Try implicit source NAT; protocol
-+ may be able to play with ports to
-+ make it unique. */
-+ struct ip_nat_range r
-+ = { IP_NAT_RANGE_MAP_IPS,
-+ tuple->src.ip, tuple->src.ip,
-+ { 0 }, { 0 } };
-+ DEBUGP("Trying implicit mapping\n");
-+ if (proto->unique_tuple(tuple, &r,
-+ IP_NAT_MANIP_SRC,
-+ conntrack)) {
-+ /* Must be unique. */
-+ IP_NF_ASSERT(!ip_nat_used_tuple
-+ (tuple, conntrack));
-+ ret = 1;
-+ goto clear_fulls;
-+ }
-+ }
-+ DEBUGP("Protocol can't get unique tuple %u.\n",
-+ hooknum);
-+ }
-+
-+ /* Eliminate that from range, and try again. */
-+ rptr->flags |= IP_NAT_RANGE_FULL;
-+ *tuple = *orig_tuple;
-+ }
-+
-+ ret = 0;
-+
-+ clear_fulls:
-+ /* Clear full flags. */
-+ IP_NF_ASSERT(mr->rangesize >= 1);
-+ for (i = 0; i < mr->rangesize; i++)
-+ mr->range[i].flags &= ~IP_NAT_RANGE_FULL;
-+
-+ return ret;
-+}
-+
-+static inline int
-+helper_cmp(const struct ip_nat_helper *helper,
-+ const struct ip_conntrack_tuple *tuple)
-+{
-+ return ip_ct_tuple_mask_cmp(tuple, &helper->tuple, &helper->mask);
-+}
-+
-+/* Where to manip the reply packets (will be reverse manip). */
-+static unsigned int opposite_hook[NF_IP_NUMHOOKS]
-+= { [NF_IP_PRE_ROUTING] = NF_IP_POST_ROUTING,
-+ [NF_IP_POST_ROUTING] = NF_IP_PRE_ROUTING,
-+#ifdef CONFIG_IP_NF_NAT_LOCAL
-+ [NF_IP_LOCAL_OUT] = NF_IP_LOCAL_IN,
-+ [NF_IP_LOCAL_IN] = NF_IP_LOCAL_OUT,
-+#endif
-+};
-+
-+unsigned int
-+ip_nat_setup_info(struct ip_conntrack *conntrack,
-+ const struct ip_nat_multi_range *mr,
-+ unsigned int hooknum)
-+{
-+ struct ip_conntrack_tuple new_tuple, inv_tuple, reply;
-+ struct ip_conntrack_tuple orig_tp;
-+ struct ip_nat_info *info = &conntrack->nat.info;
-+ int in_hashes = info->initialized;
-+
-+ MUST_BE_WRITE_LOCKED(&ip_nat_lock);
-+ IP_NF_ASSERT(hooknum == NF_IP_PRE_ROUTING
-+ || hooknum == NF_IP_POST_ROUTING
-+ || hooknum == NF_IP_LOCAL_IN
-+ || hooknum == NF_IP_LOCAL_OUT);
-+ IP_NF_ASSERT(info->num_manips < IP_NAT_MAX_MANIPS);
-+ IP_NF_ASSERT(!(info->initialized & (1 << HOOK2MANIP(hooknum))));
-+
-+ /* What we've got will look like inverse of reply. Normally
-+ this is what is in the conntrack, except for prior
-+ manipulations (future optimization: if num_manips == 0,
-+ orig_tp =
-+ conntrack->tuplehash[IP_CT_DIR_ORIGINAL].tuple) */
-+ invert_tuplepr(&orig_tp,
-+ &conntrack->tuplehash[IP_CT_DIR_REPLY].tuple);
-+
-+#if 0
-+ {
-+ unsigned int i;
-+
-+ DEBUGP("Hook %u (%s), ", hooknum,
-+ HOOK2MANIP(hooknum)==IP_NAT_MANIP_SRC ? "SRC" : "DST");
-+ DUMP_TUPLE(&orig_tp);
-+ DEBUGP("Range %p: ", mr);
-+ for (i = 0; i < mr->rangesize; i++) {
-+ DEBUGP("%u:%s%s%s %u.%u.%u.%u - %u.%u.%u.%u %u - %u\n",
-+ i,
-+ (mr->range[i].flags & IP_NAT_RANGE_MAP_IPS)
-+ ? " MAP_IPS" : "",
-+ (mr->range[i].flags
-+ & IP_NAT_RANGE_PROTO_SPECIFIED)
-+ ? " PROTO_SPECIFIED" : "",
-+ (mr->range[i].flags & IP_NAT_RANGE_FULL)
-+ ? " FULL" : "",
-+ NIPQUAD(mr->range[i].min_ip),
-+ NIPQUAD(mr->range[i].max_ip),
-+ mr->range[i].min.all,
-+ mr->range[i].max.all);
-+ }
-+ }
-+#endif
-+
-+ do {
-+ if (!get_unique_tuple(&new_tuple, &orig_tp, mr, conntrack,
-+ hooknum)) {
-+ DEBUGP("ip_nat_setup_info: Can't get unique for %p.\n",
-+ conntrack);
-+ return NF_DROP;
-+ }
-+
-+#if 0
-+ DEBUGP("Hook %u (%s) %p\n", hooknum,
-+ HOOK2MANIP(hooknum)==IP_NAT_MANIP_SRC ? "SRC" : "DST",
-+ conntrack);
-+ DEBUGP("Original: ");
-+ DUMP_TUPLE(&orig_tp);
-+ DEBUGP("New: ");
-+ DUMP_TUPLE(&new_tuple);
-+#endif
-+
-+ /* We now have two tuples (SRCIP/SRCPT/DSTIP/DSTPT):
-+ the original (A/B/C/D') and the mangled one (E/F/G/H').
-+
-+ We're only allowed to work with the SRC per-proto
-+ part, so we create inverses of both to start, then
-+ derive the other fields we need. */
-+
-+ /* Reply connection: simply invert the new tuple
-+ (G/H/E/F') */
-+ invert_tuplepr(&reply, &new_tuple);
-+
-+ /* Alter conntrack table so it recognizes replies.
-+ If fail this race (reply tuple now used), repeat. */
-+ } while (!ip_conntrack_alter_reply(conntrack, &reply));
-+
-+ /* FIXME: We can simply used existing conntrack reply tuple
-+ here --RR */
-+ /* Create inverse of original: C/D/A/B' */
-+ invert_tuplepr(&inv_tuple, &orig_tp);
-+
-+ /* Has source changed?. */
-+ if (!ip_ct_tuple_src_equal(&new_tuple, &orig_tp)) {
-+ /* In this direction, a source manip. */
-+ info->manips[info->num_manips++] =
-+ ((struct ip_nat_info_manip)
-+ { IP_CT_DIR_ORIGINAL, hooknum,
-+ IP_NAT_MANIP_SRC, new_tuple.src });
-+
-+ IP_NF_ASSERT(info->num_manips < IP_NAT_MAX_MANIPS);
-+
-+ /* In the reverse direction, a destination manip. */
-+ info->manips[info->num_manips++] =
-+ ((struct ip_nat_info_manip)
-+ { IP_CT_DIR_REPLY, opposite_hook[hooknum],
-+ IP_NAT_MANIP_DST, orig_tp.src });
-+ IP_NF_ASSERT(info->num_manips <= IP_NAT_MAX_MANIPS);
-+ }
-+
-+ /* Has destination changed? */
-+ if (!ip_ct_tuple_dst_equal(&new_tuple, &orig_tp)) {
-+ /* In this direction, a destination manip */
-+ info->manips[info->num_manips++] =
-+ ((struct ip_nat_info_manip)
-+ { IP_CT_DIR_ORIGINAL, hooknum,
-+ IP_NAT_MANIP_DST, reply.src });
-+
-+ IP_NF_ASSERT(info->num_manips < IP_NAT_MAX_MANIPS);
-+
-+ /* In the reverse direction, a source manip. */
-+ info->manips[info->num_manips++] =
-+ ((struct ip_nat_info_manip)
-+ { IP_CT_DIR_REPLY, opposite_hook[hooknum],
-+ IP_NAT_MANIP_SRC, inv_tuple.src });
-+ IP_NF_ASSERT(info->num_manips <= IP_NAT_MAX_MANIPS);
-+ }
-+
-+ /* If there's a helper, assign it; based on new tuple. */
-+ if (!conntrack->master)
-+ info->helper = LIST_FIND(&helpers, helper_cmp, struct ip_nat_helper *,
-+ &reply);
-+
-+ /* It's done. */
-+ info->initialized |= (1 << HOOK2MANIP(hooknum));
-+
-+ if (in_hashes) {
-+ IP_NF_ASSERT(info->bysource.conntrack);
-+ replace_in_hashes(conntrack, info);
-+ } else {
-+ place_in_hashes(conntrack, info);
-+ }
-+
-+ return NF_ACCEPT;
-+}
-+
-+void replace_in_hashes(struct ip_conntrack *conntrack,
-+ struct ip_nat_info *info)
-+{
-+ /* Source has changed, so replace in hashes. */
-+ unsigned int srchash
-+ = hash_by_src(&conntrack->tuplehash[IP_CT_DIR_ORIGINAL]
-+ .tuple.src,
-+ conntrack->tuplehash[IP_CT_DIR_ORIGINAL]
-+ .tuple.dst.protonum);
-+ /* We place packet as seen OUTGOUNG in byips_proto hash
-+ (ie. reverse dst and src of reply packet. */
-+ unsigned int ipsprotohash
-+ = hash_by_ipsproto(conntrack->tuplehash[IP_CT_DIR_REPLY]
-+ .tuple.dst.ip,
-+ conntrack->tuplehash[IP_CT_DIR_REPLY]
-+ .tuple.src.ip,
-+ conntrack->tuplehash[IP_CT_DIR_REPLY]
-+ .tuple.dst.protonum);
-+
-+ IP_NF_ASSERT(info->bysource.conntrack == conntrack);
-+ MUST_BE_WRITE_LOCKED(&ip_nat_lock);
-+
-+ list_del(&info->bysource.list);
-+ list_del(&info->byipsproto.list);
-+
-+ list_prepend(&bysource[srchash], &info->bysource);
-+ list_prepend(&byipsproto[ipsprotohash], &info->byipsproto);
-+}
-+
-+void place_in_hashes(struct ip_conntrack *conntrack,
-+ struct ip_nat_info *info)
-+{
-+ unsigned int srchash
-+ = hash_by_src(&conntrack->tuplehash[IP_CT_DIR_ORIGINAL]
-+ .tuple.src,
-+ conntrack->tuplehash[IP_CT_DIR_ORIGINAL]
-+ .tuple.dst.protonum);
-+ /* We place packet as seen OUTGOUNG in byips_proto hash
-+ (ie. reverse dst and src of reply packet. */
-+ unsigned int ipsprotohash
-+ = hash_by_ipsproto(conntrack->tuplehash[IP_CT_DIR_REPLY]
-+ .tuple.dst.ip,
-+ conntrack->tuplehash[IP_CT_DIR_REPLY]
-+ .tuple.src.ip,
-+ conntrack->tuplehash[IP_CT_DIR_REPLY]
-+ .tuple.dst.protonum);
-+
-+ IP_NF_ASSERT(!info->bysource.conntrack);
-+
-+ MUST_BE_WRITE_LOCKED(&ip_nat_lock);
-+ info->byipsproto.conntrack = conntrack;
-+ info->bysource.conntrack = conntrack;
-+
-+ list_prepend(&bysource[srchash], &info->bysource);
-+ list_prepend(&byipsproto[ipsprotohash], &info->byipsproto);
-+}
-+
-+static void
-+manip_pkt(u_int16_t proto, struct iphdr *iph, size_t len,
-+ const struct ip_conntrack_manip *manip,
-+ enum ip_nat_manip_type maniptype,
-+ __u32 *nfcache)
-+{
-+ *nfcache |= NFC_ALTERED;
-+ find_nat_proto(proto)->manip_pkt(iph, len, manip, maniptype);
-+
-+ if (maniptype == IP_NAT_MANIP_SRC) {
-+ iph->check = ip_nat_cheat_check(~iph->saddr, manip->ip,
-+ iph->check);
-+ iph->saddr = manip->ip;
-+ } else {
-+ iph->check = ip_nat_cheat_check(~iph->daddr, manip->ip,
-+ iph->check);
-+ iph->daddr = manip->ip;
-+ }
-+#if 0
-+ if (ip_fast_csum((u8 *)iph, iph->ihl) != 0)
-+ DEBUGP("IP: checksum on packet bad.\n");
-+
-+ if (proto == IPPROTO_TCP) {
-+ void *th = (u_int32_t *)iph + iph->ihl;
-+ if (tcp_v4_check(th, len - 4*iph->ihl, iph->saddr, iph->daddr,
-+ csum_partial((char *)th, len-4*iph->ihl, 0)))
-+ DEBUGP("TCP: checksum on packet bad\n");
-+ }
-+#endif
-+}
-+
-+static inline int exp_for_packet(struct ip_conntrack_expect *exp,
-+ struct sk_buff **pskb)
-+{
-+ struct ip_conntrack_protocol *proto;
-+ int ret = 1;
-+
-+ MUST_BE_READ_LOCKED(&ip_conntrack_lock);
-+ proto = __ip_ct_find_proto((*pskb)->nh.iph->protocol);
-+ if (proto->exp_matches_pkt)
-+ ret = proto->exp_matches_pkt(exp, pskb);
-+
-+ return ret;
-+}
-+
-+/* Do packet manipulations according to binding. */
-+unsigned int
-+do_bindings(struct ip_conntrack *ct,
-+ enum ip_conntrack_info ctinfo,
-+ struct ip_nat_info *info,
-+ unsigned int hooknum,
-+ struct sk_buff **pskb)
-+{
-+ unsigned int i;
-+ struct ip_nat_helper *helper;
-+ enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
-+ int is_tcp = (*pskb)->nh.iph->protocol == IPPROTO_TCP;
-+
-+ /* Need nat lock to protect against modification, but neither
-+ conntrack (referenced) and helper (deleted with
-+ synchronize_bh()) can vanish. */
-+ READ_LOCK(&ip_nat_lock);
-+ for (i = 0; i < info->num_manips; i++) {
-+ /* raw socket (tcpdump) may have clone of incoming
-+ skb: don't disturb it --RR */
-+ if (skb_cloned(*pskb) && !(*pskb)->sk) {
-+ struct sk_buff *nskb = skb_copy(*pskb, GFP_ATOMIC);
-+ if (!nskb) {
-+ READ_UNLOCK(&ip_nat_lock);
-+ return NF_DROP;
-+ }
-+ kfree_skb(*pskb);
-+ *pskb = nskb;
-+ }
-+
-+ if (info->manips[i].direction == dir
-+ && info->manips[i].hooknum == hooknum) {
-+ DEBUGP("Mangling %p: %s to %u.%u.%u.%u %u\n",
-+ *pskb,
-+ info->manips[i].maniptype == IP_NAT_MANIP_SRC
-+ ? "SRC" : "DST",
-+ NIPQUAD(info->manips[i].manip.ip),
-+ htons(info->manips[i].manip.u.all));
-+ manip_pkt((*pskb)->nh.iph->protocol,
-+ (*pskb)->nh.iph,
-+ (*pskb)->len,
-+ &info->manips[i].manip,
-+ info->manips[i].maniptype,
-+ &(*pskb)->nfcache);
-+ }
-+ }
-+ helper = info->helper;
-+ READ_UNLOCK(&ip_nat_lock);
-+
-+ if (helper) {
-+ struct ip_conntrack_expect *exp = NULL;
-+ struct list_head *cur_item;
-+ int ret = NF_ACCEPT;
-+ int helper_called = 0;
-+
-+ DEBUGP("do_bindings: helper existing for (%p)\n", ct);
-+
-+ /* Always defragged for helpers */
-+ IP_NF_ASSERT(!((*pskb)->nh.iph->frag_off
-+ & htons(IP_MF|IP_OFFSET)));
-+
-+ /* Have to grab read lock before sibling_list traversal */
-+ READ_LOCK(&ip_conntrack_lock);
-+ list_for_each_prev(cur_item, &ct->sibling_list) {
-+ exp = list_entry(cur_item, struct ip_conntrack_expect,
-+ expected_list);
-+
-+ /* if this expectation is already established, skip */
-+ if (exp->sibling)
-+ continue;
-+
-+ if (exp_for_packet(exp, pskb)) {
-+ /* FIXME: May be true multiple times in the
-+ * case of UDP!! */
-+ DEBUGP("calling nat helper (exp=%p) for packet\n", exp);
-+ ret = helper->help(ct, exp, info, ctinfo,
-+ hooknum, pskb);
-+ if (ret != NF_ACCEPT) {
-+ READ_UNLOCK(&ip_conntrack_lock);
-+ return ret;
-+ }
-+ helper_called = 1;
-+ }
-+ }
-+ /* Helper might want to manip the packet even when there is no
-+ * matching expectation for this packet */
-+ if (!helper_called && helper->flags & IP_NAT_HELPER_F_ALWAYS) {
-+ DEBUGP("calling nat helper for packet without expectation\n");
-+ ret = helper->help(ct, NULL, info, ctinfo,
-+ hooknum, pskb);
-+ if (ret != NF_ACCEPT) {
-+ READ_UNLOCK(&ip_conntrack_lock);
-+ return ret;
-+ }
-+ }
-+ READ_UNLOCK(&ip_conntrack_lock);
-+
-+ /* Adjust sequence number only once per packet
-+ * (helper is called at all hooks) */
-+ if (is_tcp && (hooknum == NF_IP_POST_ROUTING
-+ || hooknum == NF_IP_LOCAL_IN)) {
-+ DEBUGP("ip_nat_core: adjusting sequence number\n");
-+ /* future: put this in a l4-proto specific function,
-+ * and call this function here. */
-+ ip_nat_seq_adjust(*pskb, ct, ctinfo);
-+ }
-+
-+ return ret;
-+
-+ } else
-+ return NF_ACCEPT;
-+
-+ /* not reached */
-+}
-+
-+unsigned int
-+icmp_reply_translation(struct sk_buff *skb,
-+ struct ip_conntrack *conntrack,
-+ unsigned int hooknum,
-+ int dir)
-+{
-+ struct iphdr *iph = skb->nh.iph;
-+ struct icmphdr *hdr = (struct icmphdr *)((u_int32_t *)iph + iph->ihl);
-+ struct iphdr *inner = (struct iphdr *)(hdr + 1);
-+ size_t datalen = skb->len - ((void *)inner - (void *)iph);
-+ unsigned int i;
-+ struct ip_nat_info *info = &conntrack->nat.info;
-+
-+ IP_NF_ASSERT(skb->len >= iph->ihl*4 + sizeof(struct icmphdr));
-+ /* Must be RELATED */
-+ IP_NF_ASSERT(skb->nfct
-+ - ((struct ip_conntrack *)skb->nfct->master)->infos
-+ == IP_CT_RELATED
-+ || skb->nfct
-+ - ((struct ip_conntrack *)skb->nfct->master)->infos
-+ == IP_CT_RELATED+IP_CT_IS_REPLY);
-+
-+ /* Redirects on non-null nats must be dropped, else they'll
-+ start talking to each other without our translation, and be
-+ confused... --RR */
-+ if (hdr->type == ICMP_REDIRECT) {
-+ /* Don't care about races here. */
-+ if (info->initialized
-+ != ((1 << IP_NAT_MANIP_SRC) | (1 << IP_NAT_MANIP_DST))
-+ || info->num_manips != 0)
-+ return NF_DROP;
-+ }
-+
-+ DEBUGP("icmp_reply_translation: translating error %p hook %u dir %s\n",
-+ skb, hooknum, dir == IP_CT_DIR_ORIGINAL ? "ORIG" : "REPLY");
-+ /* Note: May not be from a NAT'd host, but probably safest to
-+ do translation always as if it came from the host itself
-+ (even though a "host unreachable" coming from the host
-+ itself is a bit weird).
-+
-+ More explanation: some people use NAT for anonymizing.
-+ Also, CERT recommends dropping all packets from private IP
-+ addresses (although ICMP errors from internal links with
-+ such addresses are not too uncommon, as Alan Cox points
-+ out) */
-+
-+ READ_LOCK(&ip_nat_lock);
-+ for (i = 0; i < info->num_manips; i++) {
-+ DEBUGP("icmp_reply: manip %u dir %s hook %u\n",
-+ i, info->manips[i].direction == IP_CT_DIR_ORIGINAL ?
-+ "ORIG" : "REPLY", info->manips[i].hooknum);
-+
-+ if (info->manips[i].direction != dir)
-+ continue;
-+
-+ /* Mapping the inner packet is just like a normal
-+ packet, except it was never src/dst reversed, so
-+ where we would normally apply a dst manip, we apply
-+ a src, and vice versa. */
-+ if (info->manips[i].hooknum == hooknum) {
-+ DEBUGP("icmp_reply: inner %s -> %u.%u.%u.%u %u\n",
-+ info->manips[i].maniptype == IP_NAT_MANIP_SRC
-+ ? "DST" : "SRC",
-+ NIPQUAD(info->manips[i].manip.ip),
-+ ntohs(info->manips[i].manip.u.udp.port));
-+ manip_pkt(inner->protocol, inner,
-+ skb->len - ((void *)inner - (void *)iph),
-+ &info->manips[i].manip,
-+ !info->manips[i].maniptype,
-+ &skb->nfcache);
-+ /* Outer packet needs to have IP header NATed like
-+ it's a reply. */
-+
-+ /* Use mapping to map outer packet: 0 give no
-+ per-proto mapping */
-+ DEBUGP("icmp_reply: outer %s -> %u.%u.%u.%u\n",
-+ info->manips[i].maniptype == IP_NAT_MANIP_SRC
-+ ? "SRC" : "DST",
-+ NIPQUAD(info->manips[i].manip.ip));
-+ manip_pkt(0, iph, skb->len,
-+ &info->manips[i].manip,
-+ info->manips[i].maniptype,
-+ &skb->nfcache);
-+ }
-+ }
-+ READ_UNLOCK(&ip_nat_lock);
-+
-+ /* Since we mangled inside ICMP packet, recalculate its
-+ checksum from scratch. (Hence the handling of incorrect
-+ checksums in conntrack, so we don't accidentally fix one.) */
-+ hdr->checksum = 0;
-+ hdr->checksum = ip_compute_csum((unsigned char *)hdr,
-+ sizeof(*hdr) + datalen);
-+
-+ return NF_ACCEPT;
-+}
-+
-+int __init ip_nat_init(void)
-+{
-+ size_t i;
-+
-+ /* Leave them the same for the moment. */
-+ ip_nat_htable_size = ip_conntrack_htable_size;
-+
-+ /* One vmalloc for both hash tables */
-+ bysource = vmalloc(sizeof(struct list_head) * ip_nat_htable_size*2);
-+ if (!bysource) {
-+ return -ENOMEM;
-+ }
-+ byipsproto = bysource + ip_nat_htable_size;
-+
-+ /* Sew in builtin protocols. */
-+ WRITE_LOCK(&ip_nat_lock);
-+ list_append(&protos, &ip_nat_protocol_tcp);
-+ list_append(&protos, &ip_nat_protocol_udp);
-+ list_append(&protos, &ip_nat_protocol_icmp);
-+ WRITE_UNLOCK(&ip_nat_lock);
-+
-+ for (i = 0; i < ip_nat_htable_size; i++) {
-+ INIT_LIST_HEAD(&bysource[i]);
-+ INIT_LIST_HEAD(&byipsproto[i]);
-+ }
-+
-+ /* FIXME: Man, this is a hack. <SIGH> */
-+ IP_NF_ASSERT(ip_conntrack_destroyed == NULL);
-+ ip_conntrack_destroyed = &ip_nat_cleanup_conntrack;
-+
-+ return 0;
-+}
-+
-+/* Clear NAT section of all conntracks, in case we're loaded again. */
-+static int clean_nat(const struct ip_conntrack *i, void *data)
-+{
-+ memset((void *)&i->nat, 0, sizeof(i->nat));
-+ return 0;
-+}
-+
-+/* Not __exit: called from ip_nat_standalone.c:init_or_cleanup() --RR */
-+void ip_nat_cleanup(void)
-+{
-+ ip_ct_selective_cleanup(&clean_nat, NULL);
-+ ip_conntrack_destroyed = NULL;
-+ vfree(bysource);
-+}
-diff -uNr linux_org/net/ipv4/netfilter/ip_nat_pptp.c linux/net/ipv4/netfilter/ip_nat_pptp.c
---- linux_org/net/ipv4/netfilter/ip_nat_pptp.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux/net/ipv4/netfilter/ip_nat_pptp.c 2006-10-27 14:11:52.000000000 +0200
-@@ -0,0 +1,475 @@
-+/*
-+ * ip_nat_pptp.c - Version 1.5
-+ *
-+ * NAT support for PPTP (Point to Point Tunneling Protocol).
-+ * PPTP is a a protocol for creating virtual private networks.
-+ * It is a specification defined by Microsoft and some vendors
-+ * working with Microsoft. PPTP is built on top of a modified
-+ * version of the Internet Generic Routing Encapsulation Protocol.
-+ * GRE is defined in RFC 1701 and RFC 1702. Documentation of
-+ * PPTP can be found in RFC 2637
-+ *
-+ * (C) 2000-2003 by Harald Welte <laforge@gnumonks.org>
-+ *
-+ * Development of this code funded by Astaro AG (http://www.astaro.com/)
-+ *
-+ * TODO: - Support for multiple calls within one session
-+ * (needs netfilter newnat code)
-+ * - NAT to a unique tuple, not to TCP source port
-+ * (needs netfilter tuple reservation)
-+ *
-+ * Changes:
-+ * 2002-02-10 - Version 1.3
-+ * - Use ip_nat_mangle_tcp_packet() because of cloned skb's
-+ * in local connections (Philip Craig <philipc@snapgear.com>)
-+ * - add checks for magicCookie and pptp version
-+ * - make argument list of pptp_{out,in}bound_packet() shorter
-+ * - move to C99 style initializers
-+ * - print version number at module loadtime
-+ * 2003-09-22 - Version 1.5
-+ * - use SNATed tcp sourceport as callid, since we get called before
-+ * TCP header is mangled (Philip Craig <philipc@snapgear.com>)
-+ *
-+ */
-+
-+#include <linux/config.h>
-+#include <linux/module.h>
-+#include <linux/ip.h>
-+#include <linux/tcp.h>
-+#include <net/tcp.h>
-+#include <linux/netfilter_ipv4/ip_nat.h>
-+#include <linux/netfilter_ipv4/ip_nat_rule.h>
-+#include <linux/netfilter_ipv4/ip_nat_helper.h>
-+#include <linux/netfilter_ipv4/ip_nat_pptp.h>
-+#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
-+#include <linux/netfilter_ipv4/ip_conntrack_proto_gre.h>
-+#include <linux/netfilter_ipv4/ip_conntrack_pptp.h>
-+
-+#define IP_NAT_PPTP_VERSION "1.5"
-+
-+MODULE_LICENSE("GPL");
-+MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>");
-+MODULE_DESCRIPTION("Netfilter NAT helper module for PPTP");
-+
-+
-+#if 0
-+#include "ip_conntrack_pptp_priv.h"
-+#define DEBUGP(format, args...) printk(KERN_DEBUG __FILE__ ":" __FUNCTION__ \
-+ ": " format, ## args)
-+#else
-+#define DEBUGP(format, args...)
-+#endif
-+
-+static unsigned int
-+pptp_nat_expected(struct sk_buff **pskb,
-+ unsigned int hooknum,
-+ struct ip_conntrack *ct,
-+ struct ip_nat_info *info)
-+{
-+ struct ip_conntrack *master = master_ct(ct);
-+ struct ip_nat_multi_range mr;
-+ struct ip_ct_pptp_master *ct_pptp_info;
-+ struct ip_nat_pptp *nat_pptp_info;
-+ u_int32_t newip, newcid;
-+ int ret;
-+
-+ IP_NF_ASSERT(info);
-+ IP_NF_ASSERT(master);
-+ IP_NF_ASSERT(!(info->initialized & (1 << HOOK2MANIP(hooknum))));
-+
-+ DEBUGP("we have a connection!\n");
-+
-+ LOCK_BH(&ip_pptp_lock);
-+ ct_pptp_info = &master->help.ct_pptp_info;
-+ nat_pptp_info = &master->nat.help.nat_pptp_info;
-+
-+ /* need to alter GRE tuple because conntrack expectfn() used 'wrong'
-+ * (unmanipulated) values */
-+ if (HOOK2MANIP(hooknum) == IP_NAT_MANIP_DST) {
-+ DEBUGP("completing tuples with NAT info \n");
-+ /* we can do this, since we're unconfirmed */
-+ if (ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u.gre.key ==
-+ htonl(ct_pptp_info->pac_call_id)) {
-+ /* assume PNS->PAC */
-+ ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u.gre.key =
-+ htonl(nat_pptp_info->pns_call_id);
-+ ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u.gre.key =
-+ htonl(nat_pptp_info->pns_call_id);
-+ newip = master->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip;
-+ newcid = htonl(nat_pptp_info->pac_call_id);
-+ } else {
-+ /* assume PAC->PNS */
-+ ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u.gre.key =
-+ htonl(nat_pptp_info->pac_call_id);
-+ ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u.gre.key =
-+ htonl(nat_pptp_info->pac_call_id);
-+ newip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip;
-+ newcid = htonl(nat_pptp_info->pns_call_id);
-+ }
-+ } else {
-+ if (ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u.gre.key ==
-+ htonl(ct_pptp_info->pac_call_id)) {
-+ /* assume PNS->PAC */
-+ newip = master->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip;
-+ newcid = htonl(ct_pptp_info->pns_call_id);
-+ }
-+ else {
-+ /* assume PAC->PNS */
-+ newip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip;
-+ newcid = htonl(ct_pptp_info->pac_call_id);
-+ }
-+ }
-+
-+ mr.rangesize = 1;
-+ mr.range[0].flags = IP_NAT_RANGE_MAP_IPS | IP_NAT_RANGE_PROTO_SPECIFIED;
-+ mr.range[0].min_ip = mr.range[0].max_ip = newip;
-+ mr.range[0].min = mr.range[0].max =
-+ ((union ip_conntrack_manip_proto ) { newcid });
-+ DEBUGP("change ip to %u.%u.%u.%u\n",
-+ NIPQUAD(newip));
-+ DEBUGP("change key to 0x%x\n", ntohl(newcid));
-+ ret = ip_nat_setup_info(ct, &mr, hooknum);
-+
-+ UNLOCK_BH(&ip_pptp_lock);
-+
-+ return ret;
-+
-+}
-+
-+/* outbound packets == from PNS to PAC */
-+static inline unsigned int
-+pptp_outbound_pkt(struct sk_buff **pskb,
-+ struct ip_conntrack *ct,
-+ enum ip_conntrack_info ctinfo,
-+ struct ip_conntrack_expect *exp)
-+
-+{
-+ struct iphdr *iph = (*pskb)->nh.iph;
-+ struct tcphdr *tcph = (void *) iph + iph->ihl*4;
-+ struct pptp_pkt_hdr *pptph = (struct pptp_pkt_hdr *)
-+ ((void *)tcph + tcph->doff*4);
-+
-+ struct PptpControlHeader *ctlh;
-+ union pptp_ctrl_union pptpReq;
-+ struct ip_ct_pptp_master *ct_pptp_info = &ct->help.ct_pptp_info;
-+ struct ip_nat_pptp *nat_pptp_info = &ct->nat.help.nat_pptp_info;
-+
-+ u_int16_t msg, *cid = NULL, new_callid;
-+
-+ /* FIXME: size checks !!! */
-+ ctlh = (struct PptpControlHeader *) ((void *) pptph + sizeof(*pptph));
-+ pptpReq.rawreq = (void *) ((void *) ctlh + sizeof(*ctlh));
-+
-+ new_callid = htons(ct_pptp_info->pns_call_id);
-+
-+ switch (msg = ntohs(ctlh->messageType)) {
-+ case PPTP_OUT_CALL_REQUEST:
-+ cid = &pptpReq.ocreq->callID;
-+ /* FIXME: ideally we would want to reserve a call ID
-+ * here. current netfilter NAT core is not able to do
-+ * this :( For now we use TCP source port. This breaks
-+ * multiple calls within one control session */
-+
-+ /* save original call ID in nat_info */
-+ nat_pptp_info->pns_call_id = ct_pptp_info->pns_call_id;
-+
-+ /* don't use tcph->source since we are at a DSTmanip
-+ * hook (e.g. PREROUTING) and pkt is not mangled yet */
-+ new_callid = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u.tcp.port;
-+
-+ /* save new call ID in ct info */
-+ ct_pptp_info->pns_call_id = ntohs(new_callid);
-+ break;
-+ case PPTP_IN_CALL_REPLY:
-+ cid = &pptpReq.icreq->callID;
-+ break;
-+ case PPTP_CALL_CLEAR_REQUEST:
-+ cid = &pptpReq.clrreq->callID;
-+ break;
-+ default:
-+ DEBUGP("unknown outbound packet 0x%04x:%s\n", msg,
-+ (msg <= PPTP_MSG_MAX)? strMName[msg]:strMName[0]);
-+ /* fall through */
-+
-+ case PPTP_SET_LINK_INFO:
-+ /* only need to NAT in case PAC is behind NAT box */
-+ case PPTP_START_SESSION_REQUEST:
-+ case PPTP_START_SESSION_REPLY:
-+ case PPTP_STOP_SESSION_REQUEST:
-+ case PPTP_STOP_SESSION_REPLY:
-+ case PPTP_ECHO_REQUEST:
-+ case PPTP_ECHO_REPLY:
-+ /* no need to alter packet */
-+ return NF_ACCEPT;
-+ }
-+
-+ IP_NF_ASSERT(cid);
-+
-+ DEBUGP("altering call id from 0x%04x to 0x%04x\n",
-+ ntohs(*cid), ntohs(new_callid));
-+
-+ /* mangle packet */
-+ ip_nat_mangle_tcp_packet(pskb, ct, ctinfo, (void *)cid - (void *)pptph,
-+ sizeof(new_callid), (char *)&new_callid,
-+ sizeof(new_callid));
-+
-+ return NF_ACCEPT;
-+}
-+
-+/* inbound packets == from PAC to PNS */
-+static inline unsigned int
-+pptp_inbound_pkt(struct sk_buff **pskb,
-+ struct ip_conntrack *ct,
-+ enum ip_conntrack_info ctinfo,
-+ struct ip_conntrack_expect *oldexp)
-+{
-+ struct iphdr *iph = (*pskb)->nh.iph;
-+ struct tcphdr *tcph = (void *) iph + iph->ihl*4;
-+ struct pptp_pkt_hdr *pptph = (struct pptp_pkt_hdr *)
-+ ((void *)tcph + tcph->doff*4);
-+
-+ struct PptpControlHeader *ctlh;
-+ union pptp_ctrl_union pptpReq;
-+ struct ip_ct_pptp_master *ct_pptp_info = &ct->help.ct_pptp_info;
-+ struct ip_nat_pptp *nat_pptp_info = &ct->nat.help.nat_pptp_info;
-+
-+ u_int16_t msg, new_cid = 0, new_pcid, *pcid = NULL, *cid = NULL;
-+ u_int32_t old_dst_ip;
-+
-+ struct ip_conntrack_tuple t, inv_t;
-+ struct ip_conntrack_tuple *orig_t, *reply_t;
-+
-+ /* FIXME: size checks !!! */
-+ ctlh = (struct PptpControlHeader *) ((void *) pptph + sizeof(*pptph));
-+ pptpReq.rawreq = (void *) ((void *) ctlh + sizeof(*ctlh));
-+
-+ new_pcid = htons(nat_pptp_info->pns_call_id);
-+
-+ switch (msg = ntohs(ctlh->messageType)) {
-+ case PPTP_OUT_CALL_REPLY:
-+ pcid = &pptpReq.ocack->peersCallID;
-+ cid = &pptpReq.ocack->callID;
-+ if (!oldexp) {
-+ DEBUGP("outcall but no expectation\n");
-+ break;
-+ }
-+ old_dst_ip = oldexp->tuple.dst.ip;
-+ t = oldexp->tuple;
-+ invert_tuplepr(&inv_t, &t);
-+
-+ /* save original PAC call ID in nat_info */
-+ nat_pptp_info->pac_call_id = ct_pptp_info->pac_call_id;
-+
-+ /* alter expectation */
-+ orig_t = &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple;
-+ reply_t = &ct->tuplehash[IP_CT_DIR_REPLY].tuple;
-+ if (t.src.ip == orig_t->src.ip && t.dst.ip == orig_t->dst.ip) {
-+ /* expectation for PNS->PAC direction */
-+ t.src.u.gre.key = htonl(nat_pptp_info->pns_call_id);
-+ t.dst.u.gre.key = htonl(ct_pptp_info->pac_call_id);
-+ inv_t.src.ip = reply_t->src.ip;
-+ inv_t.dst.ip = reply_t->dst.ip;
-+ inv_t.src.u.gre.key = htonl(nat_pptp_info->pac_call_id);
-+ inv_t.dst.u.gre.key = htonl(ct_pptp_info->pns_call_id);
-+ } else {
-+ /* expectation for PAC->PNS direction */
-+ t.src.u.gre.key = htonl(nat_pptp_info->pac_call_id);
-+ t.dst.u.gre.key = htonl(ct_pptp_info->pns_call_id);
-+ inv_t.src.ip = orig_t->src.ip;
-+ inv_t.dst.ip = orig_t->dst.ip;
-+ inv_t.src.u.gre.key = htonl(nat_pptp_info->pns_call_id);
-+ inv_t.dst.u.gre.key = htonl(ct_pptp_info->pac_call_id);
-+ }
-+
-+ if (!ip_conntrack_change_expect(oldexp, &t)) {
-+ DEBUGP("successfully changed expect\n");
-+ } else {
-+ DEBUGP("can't change expect\n");
-+ }
-+ ip_ct_gre_keymap_change(oldexp->proto.gre.keymap_orig, &t);
-+ ip_ct_gre_keymap_change(oldexp->proto.gre.keymap_reply, &inv_t);
-+ break;
-+ case PPTP_IN_CALL_CONNECT:
-+ pcid = &pptpReq.iccon->peersCallID;
-+ if (!oldexp)
-+ break;
-+ old_dst_ip = oldexp->tuple.dst.ip;
-+ t = oldexp->tuple;
-+
-+ /* alter expectation, no need for callID */
-+ if (t.dst.ip == ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip) {
-+ /* expectation for PNS->PAC direction */
-+ t.src.ip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip;
-+ } else {
-+ /* expectation for PAC->PNS direction */
-+ t.dst.ip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip;
-+ }
-+
-+ if (!ip_conntrack_change_expect(oldexp, &t)) {
-+ DEBUGP("successfully changed expect\n");
-+ } else {
-+ DEBUGP("can't change expect\n");
-+ }
-+ break;
-+ case PPTP_IN_CALL_REQUEST:
-+ /* only need to nat in case PAC is behind NAT box */
-+ break;
-+ case PPTP_WAN_ERROR_NOTIFY:
-+ pcid = &pptpReq.wanerr->peersCallID;
-+ break;
-+ case PPTP_CALL_DISCONNECT_NOTIFY:
-+ pcid = &pptpReq.disc->callID;
-+ break;
-+
-+ default:
-+ DEBUGP("unknown inbound packet %s\n",
-+ (msg <= PPTP_MSG_MAX)? strMName[msg]:strMName[0]);
-+ /* fall through */
-+
-+ case PPTP_START_SESSION_REQUEST:
-+ case PPTP_START_SESSION_REPLY:
-+ case PPTP_STOP_SESSION_REQUEST:
-+ case PPTP_STOP_SESSION_REPLY:
-+ case PPTP_ECHO_REQUEST:
-+ case PPTP_ECHO_REPLY:
-+ /* no need to alter packet */
-+ return NF_ACCEPT;
-+ }
-+
-+ /* mangle packet */
-+ IP_NF_ASSERT(pcid);
-+ DEBUGP("altering peer call id from 0x%04x to 0x%04x\n",
-+ ntohs(*pcid), ntohs(new_pcid));
-+ ip_nat_mangle_tcp_packet(pskb, ct, ctinfo, (void *)pcid - (void *)pptph,
-+ sizeof(new_pcid), (char *)&new_pcid,
-+ sizeof(new_pcid));
-+
-+ if (new_cid) {
-+ IP_NF_ASSERT(cid);
-+ DEBUGP("altering call id from 0x%04x to 0x%04x\n",
-+ ntohs(*cid), ntohs(new_cid));
-+ ip_nat_mangle_tcp_packet(pskb, ct, ctinfo,
-+ (void *)cid - (void *)pptph,
-+ sizeof(new_cid), (char *)&new_cid,
-+ sizeof(new_cid));
-+ }
-+
-+ /* great, at least we don't need to resize packets */
-+ return NF_ACCEPT;
-+}
-+
-+
-+static unsigned int tcp_help(struct ip_conntrack *ct,
-+ struct ip_conntrack_expect *exp,
-+ struct ip_nat_info *info,
-+ enum ip_conntrack_info ctinfo,
-+ unsigned int hooknum, struct sk_buff **pskb)
-+{
-+ struct iphdr *iph = (*pskb)->nh.iph;
-+ struct tcphdr *tcph = (void *) iph + iph->ihl*4;
-+ unsigned int datalen = (*pskb)->len - iph->ihl*4 - tcph->doff*4;
-+ struct pptp_pkt_hdr *pptph;
-+
-+ int dir;
-+
-+ DEBUGP("entering\n");
-+
-+ /* Only mangle things once: DST for original direction
-+ and SRC for reply direction. */
-+ dir = CTINFO2DIR(ctinfo);
-+ if (!((HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC
-+ && dir == IP_CT_DIR_ORIGINAL)
-+ || (HOOK2MANIP(hooknum) == IP_NAT_MANIP_DST
-+ && dir == IP_CT_DIR_REPLY))) {
-+ DEBUGP("Not touching dir %s at hook %s\n",
-+ dir == IP_CT_DIR_ORIGINAL ? "ORIG" : "REPLY",
-+ hooknum == NF_IP_POST_ROUTING ? "POSTROUTING"
-+ : hooknum == NF_IP_PRE_ROUTING ? "PREROUTING"
-+ : hooknum == NF_IP_LOCAL_OUT ? "OUTPUT"
-+ : hooknum == NF_IP_LOCAL_IN ? "INPUT" : "???");
-+ return NF_ACCEPT;
-+ }
-+
-+ /* if packet is too small, just skip it */
-+ if (datalen < sizeof(struct pptp_pkt_hdr)+
-+ sizeof(struct PptpControlHeader)) {
-+ DEBUGP("pptp packet too short\n");
-+ return NF_ACCEPT;
-+ }
-+
-+ pptph = (struct pptp_pkt_hdr *) ((void *)tcph + tcph->doff*4);
-+
-+ /* if it's not a control message, we can't handle it */
-+ if (ntohs(pptph->packetType) != PPTP_PACKET_CONTROL ||
-+ ntohl(pptph->magicCookie) != PPTP_MAGIC_COOKIE) {
-+ DEBUGP("not a pptp control packet\n");
-+ return NF_ACCEPT;
-+ }
-+
-+ LOCK_BH(&ip_pptp_lock);
-+
-+ if (dir == IP_CT_DIR_ORIGINAL) {
-+ /* reuqests sent by client to server (PNS->PAC) */
-+ pptp_outbound_pkt(pskb, ct, ctinfo, exp);
-+ } else {
-+ /* response from the server to the client (PAC->PNS) */
-+ pptp_inbound_pkt(pskb, ct, ctinfo, exp);
-+ }
-+
-+ UNLOCK_BH(&ip_pptp_lock);
-+
-+ return NF_ACCEPT;
-+}
-+
-+/* nat helper struct for control connection */
-+static struct ip_nat_helper pptp_tcp_helper = {
-+ .list = { NULL, NULL },
-+ .name = "pptp",
-+ .flags = IP_NAT_HELPER_F_ALWAYS,
-+ .me = THIS_MODULE,
-+ .tuple = { .src = { .ip = 0,
-+ .u = { .tcp = { .port =
-+ __constant_htons(PPTP_CONTROL_PORT) }
-+ }
-+ },
-+ .dst = { .ip = 0,
-+ .u = { .all = 0 },
-+ .protonum = IPPROTO_TCP
-+ }
-+ },
-+
-+ .mask = { .src = { .ip = 0,
-+ .u = { .tcp = { .port = 0xFFFF } }
-+ },
-+ .dst = { .ip = 0,
-+ .u = { .all = 0 },
-+ .protonum = 0xFFFF
-+ }
-+ },
-+ .help = tcp_help,
-+ .expect = pptp_nat_expected
-+};
-+
-+
-+static int __init init(void)
-+{
-+ DEBUGP("%s: registering NAT helper\n", __FILE__);
-+ if (ip_nat_helper_register(&pptp_tcp_helper)) {
-+ printk(KERN_ERR "Unable to register NAT application helper "
-+ "for pptp\n");
-+ return -EIO;
-+ }
-+
-+ printk("ip_nat_pptp version %s loaded\n", IP_NAT_PPTP_VERSION);
-+ return 0;
-+}
-+
-+static void __exit fini(void)
-+{
-+ DEBUGP("cleanup_module\n" );
-+ ip_nat_helper_unregister(&pptp_tcp_helper);
-+ printk("ip_nat_pptp version %s unloaded\n", IP_NAT_PPTP_VERSION);
-+}
-+
-+module_init(init);
-+module_exit(fini);
-diff -uNr linux_org/net/ipv4/netfilter/ip_nat_proto_gre.c linux/net/ipv4/netfilter/ip_nat_proto_gre.c
---- linux_org/net/ipv4/netfilter/ip_nat_proto_gre.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux/net/ipv4/netfilter/ip_nat_proto_gre.c 2006-10-27 14:11:52.000000000 +0200
-@@ -0,0 +1,225 @@
-+/*
-+ * ip_nat_proto_gre.c - Version 1.2
-+ *
-+ * NAT protocol helper module for GRE.
-+ *
-+ * GRE is a generic encapsulation protocol, which is generally not very
-+ * suited for NAT, as it has no protocol-specific part as port numbers.
-+ *
-+ * It has an optional key field, which may help us distinguishing two
-+ * connections between the same two hosts.
-+ *
-+ * GRE is defined in RFC 1701 and RFC 1702, as well as RFC 2784
-+ *
-+ * PPTP is built on top of a modified version of GRE, and has a mandatory
-+ * field called "CallID", which serves us for the same purpose as the key
-+ * field in plain GRE.
-+ *
-+ * Documentation about PPTP can be found in RFC 2637
-+ *
-+ * (C) 2000-2003 by Harald Welte <laforge@gnumonks.org>
-+ *
-+ * Development of this code funded by Astaro AG (http://www.astaro.com/)
-+ *
-+ */
-+
-+#include <linux/config.h>
-+#include <linux/module.h>
-+#include <linux/ip.h>
-+#include <linux/netfilter_ipv4/ip_nat.h>
-+#include <linux/netfilter_ipv4/ip_nat_rule.h>
-+#include <linux/netfilter_ipv4/ip_nat_protocol.h>
-+#include <linux/netfilter_ipv4/ip_conntrack_proto_gre.h>
-+
-+MODULE_LICENSE("GPL");
-+MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>");
-+MODULE_DESCRIPTION("Netfilter NAT protocol helper module for GRE");
-+
-+#if 0
-+#define DEBUGP(format, args...) printk(KERN_DEBUG __FILE__ ":" __FUNCTION__ \
-+ ": " format, ## args)
-+#else
-+#define DEBUGP(x, args...)
-+#endif
-+
-+/* is key in given range between min and max */
-+static int
-+gre_in_range(const struct ip_conntrack_tuple *tuple,
-+ enum ip_nat_manip_type maniptype,
-+ const union ip_conntrack_manip_proto *min,
-+ const union ip_conntrack_manip_proto *max)
-+{
-+ u_int32_t key;
-+
-+ if (maniptype == IP_NAT_MANIP_SRC)
-+ key = tuple->src.u.gre.key;
-+ else
-+ key = tuple->dst.u.gre.key;
-+
-+ return ntohl(key) >= ntohl(min->gre.key)
-+ && ntohl(key) <= ntohl(max->gre.key);
-+}
-+
-+/* generate unique tuple ... */
-+static int
-+gre_unique_tuple(struct ip_conntrack_tuple *tuple,
-+ const struct ip_nat_range *range,
-+ enum ip_nat_manip_type maniptype,
-+ const struct ip_conntrack *conntrack)
-+{
-+ u_int32_t min, i, range_size;
-+ u_int32_t key = 0, *keyptr;
-+
-+ if (maniptype == IP_NAT_MANIP_SRC)
-+ keyptr = &tuple->src.u.gre.key;
-+ else
-+ keyptr = &tuple->dst.u.gre.key;
-+
-+ if (!(range->flags & IP_NAT_RANGE_PROTO_SPECIFIED)) {
-+
-+ switch (tuple->dst.u.gre.version) {
-+ case 0:
-+ DEBUGP("NATing GRE version 0 (ct=%p)\n",
-+ conntrack);
-+ min = 1;
-+ range_size = 0xffffffff;
-+ break;
-+ case GRE_VERSION_PPTP:
-+ DEBUGP("%p: NATing GRE PPTP\n",
-+ conntrack);
-+ min = 1;
-+ range_size = 0xffff;
-+ break;
-+ default:
-+ printk(KERN_WARNING "nat_gre: unknown GRE version\n");
-+ return 0;
-+ break;
-+ }
-+
-+ } else {
-+ min = ntohl(range->min.gre.key);
-+ range_size = ntohl(range->max.gre.key) - min + 1;
-+ }
-+
-+ DEBUGP("min = %u, range_size = %u\n", min, range_size);
-+
-+ for (i = 0; i < range_size; i++, key++) {
-+ *keyptr = htonl(min + key % range_size);
-+ if (!ip_nat_used_tuple(tuple, conntrack))
-+ return 1;
-+ }
-+
-+ DEBUGP("%p: no NAT mapping\n", conntrack);
-+
-+ return 0;
-+}
-+
-+/* manipulate a GRE packet according to maniptype */
-+static void
-+gre_manip_pkt(struct iphdr *iph, size_t len,
-+ const struct ip_conntrack_manip *manip,
-+ enum ip_nat_manip_type maniptype)
-+{
-+ struct gre_hdr *greh = (struct gre_hdr *)((u_int32_t *)iph+iph->ihl);
-+ struct gre_hdr_pptp *pgreh = (struct gre_hdr_pptp *) greh;
-+
-+ /* we only have destination manip of a packet, since 'source key'
-+ * is not present in the packet itself */
-+ if (maniptype == IP_NAT_MANIP_DST) {
-+ /* key manipulation is always dest */
-+ switch (greh->version) {
-+ case 0:
-+ if (!greh->key) {
-+ DEBUGP("can't nat GRE w/o key\n");
-+ break;
-+ }
-+ if (greh->csum) {
-+ /* FIXME: Never tested this code... */
-+ *(gre_csum(greh)) =
-+ ip_nat_cheat_check(~*(gre_key(greh)),
-+ manip->u.gre.key,
-+ *(gre_csum(greh)));
-+ }
-+ *(gre_key(greh)) = manip->u.gre.key;
-+ break;
-+ case GRE_VERSION_PPTP:
-+ DEBUGP("call_id -> 0x%04x\n",
-+ ntohl(manip->u.gre.key));
-+ pgreh->call_id = htons(ntohl(manip->u.gre.key));
-+ break;
-+ default:
-+ DEBUGP("can't nat unknown GRE version\n");
-+ break;
-+ }
-+ }
-+}
-+
-+/* print out a nat tuple */
-+static unsigned int
-+gre_print(char *buffer,
-+ const struct ip_conntrack_tuple *match,
-+ const struct ip_conntrack_tuple *mask)
-+{
-+ unsigned int len = 0;
-+
-+ if (mask->dst.u.gre.version)
-+ len += sprintf(buffer + len, "version=%d ",
-+ ntohs(match->dst.u.gre.version));
-+
-+ if (mask->dst.u.gre.protocol)
-+ len += sprintf(buffer + len, "protocol=0x%x ",
-+ ntohs(match->dst.u.gre.protocol));
-+
-+ if (mask->src.u.gre.key)
-+ len += sprintf(buffer + len, "srckey=0x%x ",
-+ ntohl(match->src.u.gre.key));
-+
-+ if (mask->dst.u.gre.key)
-+ len += sprintf(buffer + len, "dstkey=0x%x ",
-+ ntohl(match->src.u.gre.key));
-+
-+ return len;
-+}
-+
-+/* print a range of keys */
-+static unsigned int
-+gre_print_range(char *buffer, const struct ip_nat_range *range)
-+{
-+ if (range->min.gre.key != 0
-+ || range->max.gre.key != 0xFFFF) {
-+ if (range->min.gre.key == range->max.gre.key)
-+ return sprintf(buffer, "key 0x%x ",
-+ ntohl(range->min.gre.key));
-+ else
-+ return sprintf(buffer, "keys 0x%u-0x%u ",
-+ ntohl(range->min.gre.key),
-+ ntohl(range->max.gre.key));
-+ } else
-+ return 0;
-+}
-+
-+/* nat helper struct */
-+static struct ip_nat_protocol gre =
-+ { { NULL, NULL }, "GRE", IPPROTO_GRE,
-+ gre_manip_pkt,
-+ gre_in_range,
-+ gre_unique_tuple,
-+ gre_print,
-+ gre_print_range
-+ };
-+
-+static int __init init(void)
-+{
-+ if (ip_nat_protocol_register(&gre))
-+ return -EIO;
-+
-+ return 0;
-+}
-+
-+static void __exit fini(void)
-+{
-+ ip_nat_protocol_unregister(&gre);
-+}
-+
-+module_init(init);
-+module_exit(fini);
diff --git a/recipes/linux/linux-mtx-1-2.4.27/49-bash4-configure.patch b/recipes/linux/linux-mtx-1-2.4.27/49-bash4-configure.patch
deleted file mode 100644
index 222567d12e..0000000000
--- a/recipes/linux/linux-mtx-1-2.4.27/49-bash4-configure.patch
+++ /dev/null
@@ -1,11 +0,0 @@
---- linux/scripts/Configure-orig 2009-11-29 19:12:02.000000000 +0100
-+++ linux/scripts/Configure 2009-11-29 19:12:27.000000000 +0100
-@@ -543,7 +543,7 @@
- echo "#"
- echo "# Using defaults found in" $DEFAULTS
- echo "#"
-- . $DEFAULTS
-+ . ./$DEFAULTS
- sed -e 's/# \(CONFIG_[^ ]*\) is not.*/\1=n/' <$DEFAULTS >.config-is-not.$$
- . .config-is-not.$$
- rm .config-is-not.$$
diff --git a/recipes/linux/linux-mtx-1-2.4.27/defconfig-mtx-1 b/recipes/linux/linux-mtx-1-2.4.27/defconfig-mtx-1
deleted file mode 100644
index 5c189749fd..0000000000
--- a/recipes/linux/linux-mtx-1-2.4.27/defconfig-mtx-1
+++ /dev/null
@@ -1,1347 +0,0 @@
-#
-# Automatically generated by make menuconfig: don't edit
-#
-CONFIG_MIPS=y
-CONFIG_MIPS32=y
-# CONFIG_MIPS64 is not set
-
-#
-# Code maturity level options
-#
-CONFIG_EXPERIMENTAL=y
-
-#
-# Loadable module support
-#
-CONFIG_MODULES=y
-# CONFIG_MODVERSIONS is not set
-CONFIG_KMOD=y
-
-#
-# Machine selection
-#
-# CONFIG_ACER_PICA_61 is not set
-# CONFIG_MIPS_BOSPORUS is not set
-# CONFIG_MIPS_MIRAGE is not set
-# CONFIG_MIPS_DB1000 is not set
-# CONFIG_MIPS_DB1100 is not set
-# CONFIG_MIPS_DB1500 is not set
-# CONFIG_MIPS_DB1550 is not set
-# CONFIG_MIPS_PB1000 is not set
-# CONFIG_MIPS_PB1100 is not set
-# CONFIG_MIPS_PB1500 is not set
-# CONFIG_MIPS_HYDROGEN3 is not set
-# CONFIG_MIPS_PB1550 is not set
-# CONFIG_MIPS_XXS1500 is not set
-CONFIG_MIPS_MTX1=y
-# CONFIG_COGENT_CSB250 is not set
-# CONFIG_BAGET_MIPS is not set
-# CONFIG_CASIO_E55 is not set
-# CONFIG_MIPS_COBALT is not set
-# CONFIG_DECSTATION is not set
-# CONFIG_MIPS_EV64120 is not set
-# CONFIG_MIPS_EV96100 is not set
-# CONFIG_MIPS_IVR is not set
-# CONFIG_HP_LASERJET is not set
-# CONFIG_IBM_WORKPAD is not set
-# CONFIG_LASAT is not set
-# CONFIG_MIPS_ITE8172 is not set
-# CONFIG_MIPS_ATLAS is not set
-# CONFIG_MIPS_MAGNUM_4000 is not set
-# CONFIG_MIPS_MALTA is not set
-# CONFIG_MIPS_SEAD is not set
-# CONFIG_MOMENCO_OCELOT is not set
-# CONFIG_MOMENCO_OCELOT_G is not set
-# CONFIG_MOMENCO_OCELOT_C is not set
-# CONFIG_MOMENCO_JAGUAR_ATX is not set
-# CONFIG_PMC_BIG_SUR is not set
-# CONFIG_PMC_STRETCH is not set
-# CONFIG_PMC_YOSEMITE is not set
-# CONFIG_DDB5074 is not set
-# CONFIG_DDB5476 is not set
-# CONFIG_DDB5477 is not set
-# CONFIG_NEC_OSPREY is not set
-# CONFIG_NEC_EAGLE is not set
-# CONFIG_OLIVETTI_M700 is not set
-# CONFIG_NINO is not set
-# CONFIG_SGI_IP22 is not set
-# CONFIG_SGI_IP27 is not set
-# CONFIG_SIBYTE_SB1xxx_SOC is not set
-# CONFIG_SNI_RM200_PCI is not set
-# CONFIG_TANBAC_TB0226 is not set
-# CONFIG_TANBAC_TB0229 is not set
-# CONFIG_TOSHIBA_JMR3927 is not set
-# CONFIG_TOSHIBA_RBTX4927 is not set
-# CONFIG_VICTOR_MPC30X is not set
-# CONFIG_ZAO_CAPCELLA is not set
-# CONFIG_HIGHMEM is not set
-CONFIG_RWSEM_GENERIC_SPINLOCK=y
-# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
-CONFIG_SOC_AU1X00=y
-CONFIG_SOC_AU1500=y
-CONFIG_NONCOHERENT_IO=y
-# CONFIG_MIPS_AU1000 is not set
-
-#
-# CPU selection
-#
-CONFIG_CPU_MIPS32=y
-# CONFIG_CPU_MIPS64 is not set
-# CONFIG_CPU_R3000 is not set
-# CONFIG_CPU_TX39XX is not set
-# CONFIG_CPU_VR41XX is not set
-# CONFIG_CPU_R4300 is not set
-# CONFIG_CPU_R4X00 is not set
-# CONFIG_CPU_TX49XX is not set
-# CONFIG_CPU_R5000 is not set
-# CONFIG_CPU_R5432 is not set
-# CONFIG_CPU_R6000 is not set
-# CONFIG_CPU_NEVADA is not set
-# CONFIG_CPU_R8000 is not set
-# CONFIG_CPU_R10000 is not set
-# CONFIG_CPU_RM7000 is not set
-# CONFIG_CPU_RM9000 is not set
-# CONFIG_CPU_SB1 is not set
-CONFIG_PAGE_SIZE_4KB=y
-# CONFIG_PAGE_SIZE_16KB is not set
-# CONFIG_PAGE_SIZE_64KB is not set
-CONFIG_CPU_HAS_PREFETCH=y
-# CONFIG_VTAG_ICACHE is not set
-CONFIG_64BIT_PHYS_ADDR=y
-# CONFIG_CPU_ADVANCED is not set
-CONFIG_CPU_HAS_LLSC=y
-# CONFIG_CPU_HAS_LLDSCD is not set
-# CONFIG_CPU_HAS_WB is not set
-CONFIG_CPU_HAS_SYNC=y
-
-#
-# General setup
-#
-CONFIG_CPU_LITTLE_ENDIAN=y
-# CONFIG_BUILD_ELF64 is not set
-CONFIG_NET=y
-CONFIG_PCI=y
-CONFIG_PCI_NEW=y
-CONFIG_PCI_AUTO=y
-CONFIG_PCI_NAMES=y
-# CONFIG_ISA is not set
-# CONFIG_TC is not set
-# CONFIG_MCA is not set
-# CONFIG_SBUS is not set
-CONFIG_HOTPLUG=y
-
-#
-# PCMCIA/CardBus support
-#
-CONFIG_PCMCIA=m
-CONFIG_CARDBUS=y
-# CONFIG_TCIC is not set
-# CONFIG_I82092 is not set
-# CONFIG_I82365 is not set
-# CONFIG_PCMCIA_AU1X00 is not set
-
-#
-# PCI Hotplug Support
-#
-# CONFIG_HOTPLUG_PCI is not set
-# CONFIG_HOTPLUG_PCI_COMPAQ is not set
-# CONFIG_HOTPLUG_PCI_COMPAQ_NVRAM is not set
-# CONFIG_HOTPLUG_PCI_SHPC is not set
-# CONFIG_HOTPLUG_PCI_SHPC_POLL_EVENT_MODE is not set
-# CONFIG_HOTPLUG_PCI_PCIE is not set
-# CONFIG_HOTPLUG_PCI_PCIE_POLL_EVENT_MODE is not set
-CONFIG_SYSVIPC=y
-# CONFIG_BSD_PROCESS_ACCT is not set
-CONFIG_SYSCTL=y
-CONFIG_KCORE_ELF=y
-# CONFIG_KCORE_AOUT is not set
-# CONFIG_BINFMT_AOUT is not set
-CONFIG_BINFMT_ELF=y
-# CONFIG_MIPS32_COMPAT is not set
-# CONFIG_MIPS32_O32 is not set
-# CONFIG_MIPS32_N32 is not set
-# CONFIG_BINFMT_ELF32 is not set
-CONFIG_BINFMT_MISC=m
-# CONFIG_OOM_KILLER is not set
-# CONFIG_CMDLINE_BOOL is not set
-# CONFIG_PM is not set
-
-#
-# Memory Technology Devices (MTD)
-#
-CONFIG_MTD=y
-# CONFIG_MTD_DEBUG is not set
-CONFIG_MTD_PARTITIONS=y
-# CONFIG_MTD_CONCAT is not set
-# CONFIG_MTD_REDBOOT_PARTS is not set
-# CONFIG_MTD_CMDLINE_PARTS is not set
-CONFIG_MTD_CHAR=y
-CONFIG_MTD_BLOCK=y
-# CONFIG_FTL is not set
-# CONFIG_NFTL is not set
-# CONFIG_INFTL is not set
-
-#
-# RAM/ROM/Flash chip drivers
-#
-CONFIG_MTD_CFI=y
-# CONFIG_MTD_JEDECPROBE is not set
-CONFIG_MTD_GEN_PROBE=y
-# CONFIG_MTD_CFI_ADV_OPTIONS is not set
-CONFIG_MTD_CFI_INTELEXT=y
-CONFIG_MTD_CFI_AMDSTD=y
-CONFIG_MTD_CFI_AMDSTD_RETRY=y
-CONFIG_MTD_CFI_AMDSTD_RETRY_MAX=5
-# CONFIG_MTD_CFI_STAA is not set
-CONFIG_MTD_CFI_UTIL=y
-# CONFIG_MTD_RAM is not set
-# CONFIG_MTD_ROM is not set
-# CONFIG_MTD_ABSENT is not set
-# CONFIG_MTD_OBSOLETE_CHIPS is not set
-# CONFIG_MTD_AMDSTD is not set
-# CONFIG_MTD_SHARP is not set
-# CONFIG_MTD_JEDEC is not set
-
-#
-# Mapping drivers for chip access
-#
-# CONFIG_MTD_COMPLEX_MAPPINGS is not set
-# CONFIG_MTD_PHYSMAP is not set
-# CONFIG_MTD_DB1X00 is not set
-CONFIG_MTD_MTX1=y
-# CONFIG_MTD_CSTM_MIPS_IXX is not set
-# CONFIG_MTD_OCELOT is not set
-# CONFIG_MTD_LASAT is not set
-# CONFIG_MTD_PCI is not set
-# CONFIG_MTD_PCMCIA is not set
-
-#
-# Self-contained MTD device drivers
-#
-# CONFIG_MTD_PMC551 is not set
-# CONFIG_MTD_SLRAM is not set
-# CONFIG_MTD_MTDRAM is not set
-# CONFIG_MTD_BLKMTD is not set
-# CONFIG_MTD_DOC2000 is not set
-# CONFIG_MTD_DOC2001 is not set
-# CONFIG_MTD_DOC2001PLUS is not set
-# CONFIG_MTD_DOCPROBE is not set
-
-#
-# NAND Flash Device Drivers
-#
-# CONFIG_MTD_NAND is not set
-
-#
-# Parallel port support
-#
-# CONFIG_PARPORT is not set
-
-#
-# Plug and Play configuration
-#
-# CONFIG_PNP is not set
-# CONFIG_ISAPNP is not set
-
-#
-# Block devices
-#
-# CONFIG_BLK_DEV_FD is not set
-# CONFIG_BLK_DEV_XD is not set
-# CONFIG_PARIDE is not set
-# CONFIG_BLK_CPQ_DA is not set
-# CONFIG_BLK_CPQ_CISS_DA is not set
-# CONFIG_CISS_SCSI_TAPE is not set
-# CONFIG_CISS_MONITOR_THREAD is not set
-# CONFIG_BLK_DEV_DAC960 is not set
-# CONFIG_BLK_DEV_UMEM is not set
-# CONFIG_BLK_DEV_SX8 is not set
-CONFIG_BLK_DEV_LOOP=y
-CONFIG_BLK_DEV_NBD=m
-CONFIG_BLK_DEV_RAM=m
-CONFIG_BLK_DEV_RAM_SIZE=4096
-# CONFIG_BLK_DEV_INITRD is not set
-# CONFIG_BLK_STATS is not set
-
-#
-# Multi-device support (RAID and LVM)
-#
-# CONFIG_MD is not set
-# CONFIG_BLK_DEV_MD is not set
-# CONFIG_MD_LINEAR is not set
-# CONFIG_MD_RAID0 is not set
-# CONFIG_MD_RAID1 is not set
-# CONFIG_MD_RAID5 is not set
-# CONFIG_MD_MULTIPATH is not set
-# CONFIG_BLK_DEV_LVM is not set
-
-#
-# Networking options
-#
-CONFIG_PACKET=y
-CONFIG_PACKET_MMAP=y
-CONFIG_NETLINK_DEV=m
-CONFIG_NETFILTER=y
-# CONFIG_NETFILTER_DEBUG is not set
-CONFIG_FILTER=y
-CONFIG_UNIX=y
-CONFIG_INET=y
-CONFIG_IP_MULTICAST=y
-CONFIG_IP_ADVANCED_ROUTER=y
-CONFIG_IP_MULTIPLE_TABLES=y
-CONFIG_IP_ROUTE_FWMARK=y
-CONFIG_IP_ROUTE_NAT=y
-CONFIG_IP_ROUTE_MULTIPATH=y
-CONFIG_IP_ROUTE_TOS=y
-CONFIG_IP_ROUTE_VERBOSE=y
-CONFIG_IP_PNP=y
-CONFIG_IP_PNP_DHCP=y
-# CONFIG_IP_PNP_BOOTP is not set
-# CONFIG_IP_PNP_RARP is not set
-CONFIG_NET_IPIP=m
-CONFIG_NET_IPGRE=m
-CONFIG_NET_IPGRE_BROADCAST=y
-CONFIG_IP_MROUTE=y
-CONFIG_IP_PIMSM_V1=y
-CONFIG_IP_PIMSM_V2=y
-# CONFIG_ARPD is not set
-# CONFIG_INET_ECN is not set
-CONFIG_SYN_COOKIES=y
-
-#
-# IP: Netfilter Configuration
-#
-CONFIG_IP_NF_CONNTRACK=y
-CONFIG_IP_NF_FTP=m
-CONFIG_IP_NF_AMANDA=m
-CONFIG_IP_NF_TFTP=m
-CONFIG_IP_NF_IRC=m
-CONFIG_IP_NF_QUEUE=m
-CONFIG_IP_NF_IPTABLES=y
-CONFIG_IP_NF_MATCH_LIMIT=m
-CONFIG_IP_NF_MATCH_MAC=m
-CONFIG_IP_NF_MATCH_PKTTYPE=m
-CONFIG_IP_NF_MATCH_MARK=m
-CONFIG_IP_NF_MATCH_MULTIPORT=m
-CONFIG_IP_NF_MATCH_TOS=m
-CONFIG_IP_NF_MATCH_RECENT=m
-CONFIG_IP_NF_MATCH_ECN=m
-CONFIG_IP_NF_MATCH_DSCP=m
-CONFIG_IP_NF_MATCH_AH_ESP=m
-CONFIG_IP_NF_MATCH_LENGTH=m
-CONFIG_IP_NF_MATCH_TTL=m
-CONFIG_IP_NF_MATCH_TCPMSS=m
-CONFIG_IP_NF_MATCH_HELPER=m
-CONFIG_IP_NF_MATCH_STATE=y
-CONFIG_IP_NF_MATCH_CONNTRACK=y
-CONFIG_IP_NF_MATCH_UNCLEAN=m
-CONFIG_IP_NF_MATCH_OWNER=m
-CONFIG_IP_NF_FILTER=y
-CONFIG_IP_NF_TARGET_REJECT=y
-CONFIG_IP_NF_TARGET_MIRROR=m
-CONFIG_IP_NF_NAT=y
-CONFIG_IP_NF_NAT_NEEDED=y
-CONFIG_IP_NF_TARGET_MASQUERADE=y
-CONFIG_IP_NF_TARGET_REDIRECT=y
-CONFIG_IP_NF_NAT_AMANDA=m
-# CONFIG_IP_NF_NAT_LOCAL is not set
-CONFIG_IP_NF_NAT_SNMP_BASIC=m
-CONFIG_IP_NF_NAT_IRC=m
-CONFIG_IP_NF_NAT_FTP=m
-CONFIG_IP_NF_NAT_TFTP=m
-CONFIG_IP_NF_MANGLE=y
-CONFIG_IP_NF_TARGET_TOS=m
-CONFIG_IP_NF_TARGET_ECN=m
-CONFIG_IP_NF_TARGET_DSCP=m
-CONFIG_IP_NF_TARGET_MARK=y
-CONFIG_IP_NF_TARGET_LOG=y
-CONFIG_IP_NF_TARGET_ULOG=m
-CONFIG_IP_NF_TARGET_TCPMSS=m
-CONFIG_IP_NF_ARPTABLES=m
-CONFIG_IP_NF_ARPFILTER=m
-CONFIG_IP_NF_ARP_MANGLE=m
-# CONFIG_IP_NF_COMPAT_IPCHAINS is not set
-# CONFIG_IP_NF_COMPAT_IPFWADM is not set
-
-#
-# IP: Virtual Server Configuration
-#
-# CONFIG_IP_VS is not set
-CONFIG_IPV6=m
-
-#
-# IPv6: Netfilter Configuration
-#
-CONFIG_IP6_NF_QUEUE=m
-CONFIG_IP6_NF_IPTABLES=m
-CONFIG_IP6_NF_MATCH_LIMIT=m
-CONFIG_IP6_NF_MATCH_MAC=m
-CONFIG_IP6_NF_MATCH_RT=m
-CONFIG_IP6_NF_MATCH_OPTS=m
-CONFIG_IP6_NF_MATCH_FRAG=m
-CONFIG_IP6_NF_MATCH_HL=m
-CONFIG_IP6_NF_MATCH_MULTIPORT=m
-CONFIG_IP6_NF_MATCH_OWNER=m
-CONFIG_IP6_NF_MATCH_MARK=m
-CONFIG_IP6_NF_MATCH_IPV6HEADER=m
-CONFIG_IP6_NF_MATCH_AHESP=m
-CONFIG_IP6_NF_MATCH_LENGTH=m
-CONFIG_IP6_NF_MATCH_EUI64=m
-CONFIG_IP6_NF_FILTER=m
-CONFIG_IP6_NF_TARGET_LOG=m
-CONFIG_IP6_NF_MANGLE=m
-CONFIG_IP6_NF_TARGET_MARK=m
-# CONFIG_KHTTPD is not set
-
-#
-# SCTP Configuration (EXPERIMENTAL)
-#
-# CONFIG_IP_SCTP is not set
-# CONFIG_ATM is not set
-CONFIG_VLAN_8021Q=m
-# CONFIG_IPX is not set
-# CONFIG_ATALK is not set
-
-#
-# Appletalk devices
-#
-# CONFIG_DEV_APPLETALK is not set
-# CONFIG_DECNET is not set
-CONFIG_BRIDGE=m
-# CONFIG_X25 is not set
-# CONFIG_LAPB is not set
-# CONFIG_LLC is not set
-# CONFIG_NET_DIVERT is not set
-# CONFIG_ECONET is not set
-# CONFIG_WAN_ROUTER is not set
-# CONFIG_NET_FASTROUTE is not set
-# CONFIG_NET_HW_FLOWCONTROL is not set
-
-#
-# QoS and/or fair queueing
-#
-CONFIG_NET_SCHED=y
-CONFIG_NET_SCH_CBQ=m
-CONFIG_NET_SCH_HTB=m
-CONFIG_NET_SCH_CSZ=m
-# CONFIG_NET_SCH_HFSC is not set
-CONFIG_NET_SCH_PRIO=m
-CONFIG_NET_SCH_RED=m
-CONFIG_NET_SCH_SFQ=m
-CONFIG_NET_SCH_TEQL=m
-CONFIG_NET_SCH_TBF=m
-CONFIG_NET_SCH_GRED=m
-# CONFIG_NET_SCH_NETEM is not set
-CONFIG_NET_SCH_DSMARK=m
-CONFIG_NET_SCH_INGRESS=m
-CONFIG_NET_QOS=y
-CONFIG_NET_ESTIMATOR=y
-CONFIG_NET_CLS=y
-CONFIG_NET_CLS_TCINDEX=m
-CONFIG_NET_CLS_ROUTE4=m
-CONFIG_NET_CLS_ROUTE=y
-CONFIG_NET_CLS_FW=m
-CONFIG_NET_CLS_U32=m
-CONFIG_NET_CLS_RSVP=m
-CONFIG_NET_CLS_RSVP6=m
-CONFIG_NET_CLS_POLICE=y
-
-#
-# Network testing
-#
-CONFIG_NET_PKTGEN=m
-CONFIG_IPSEC_NAT_TRAVERSAL=y
-CONFIG_IPSEC=m
-CONFIG_IPSEC_IPIP=y
-CONFIG_IPSEC_AH=y
-CONFIG_IPSEC_AUTH_HMAC_MD5=y
-CONFIG_IPSEC_AUTH_HMAC_SHA1=y
-CONFIG_IPSEC_ESP=y
-CONFIG_IPSEC_ENC_3DES=y
-CONFIG_IPSEC_ENC_AES=y
-CONFIG_IPSEC_ALG=y
-CONFIG_IPSEC_ALG_AES=m
-CONFIG_IPSEC_ALG_CRYPTOAPI=m
-CONFIG_IPSEC_ALG_NON_LIBRE=y
-CONFIG_IPSEC_IPCOMP=y
-CONFIG_IPSEC_DEBUG=y
-
-#
-# Telephony Support
-#
-# CONFIG_PHONE is not set
-# CONFIG_PHONE_IXJ is not set
-# CONFIG_PHONE_IXJ_PCMCIA is not set
-
-#
-# ATA/IDE/MFM/RLL support
-#
-# CONFIG_IDE is not set
-# CONFIG_BLK_DEV_HD is not set
-
-#
-# SCSI support
-#
-CONFIG_SCSI=m
-CONFIG_BLK_DEV_SD=m
-CONFIG_SD_EXTRA_DEVS=40
-# CONFIG_CHR_DEV_ST is not set
-# CONFIG_CHR_DEV_OSST is not set
-CONFIG_BLK_DEV_SR=m
-# CONFIG_BLK_DEV_SR_VENDOR is not set
-CONFIG_SR_EXTRA_DEVS=2
-# CONFIG_CHR_DEV_SG is not set
-# CONFIG_SCSI_DEBUG_QUEUES is not set
-# CONFIG_SCSI_MULTI_LUN is not set
-# CONFIG_SCSI_CONSTANTS is not set
-# CONFIG_SCSI_LOGGING is not set
-
-#
-# SCSI low-level drivers
-#
-# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
-# CONFIG_SCSI_7000FASST is not set
-# CONFIG_SCSI_ACARD is not set
-# CONFIG_SCSI_AHA152X is not set
-# CONFIG_SCSI_AHA1542 is not set
-# CONFIG_SCSI_AHA1740 is not set
-# CONFIG_SCSI_AACRAID is not set
-# CONFIG_SCSI_AIC7XXX is not set
-# CONFIG_SCSI_AIC79XX is not set
-# CONFIG_SCSI_AIC7XXX_OLD is not set
-# CONFIG_SCSI_DPT_I2O is not set
-# CONFIG_SCSI_ADVANSYS is not set
-# CONFIG_SCSI_IN2000 is not set
-# CONFIG_SCSI_AM53C974 is not set
-# CONFIG_SCSI_MEGARAID is not set
-# CONFIG_SCSI_MEGARAID2 is not set
-# CONFIG_SCSI_SATA is not set
-# CONFIG_SCSI_SATA_SVW is not set
-# CONFIG_SCSI_SATA_PROMISE is not set
-# CONFIG_SCSI_SATA_SX4 is not set
-# CONFIG_SCSI_SATA_SIL is not set
-# CONFIG_SCSI_SATA_SIS is not set
-# CONFIG_SCSI_SATA_VIA is not set
-# CONFIG_SCSI_SATA_VITESSE is not set
-# CONFIG_SCSI_BUSLOGIC is not set
-# CONFIG_SCSI_CPQFCTS is not set
-# CONFIG_SCSI_DMX3191D is not set
-# CONFIG_SCSI_DTC3280 is not set
-# CONFIG_SCSI_EATA is not set
-# CONFIG_SCSI_EATA_DMA is not set
-# CONFIG_SCSI_EATA_PIO is not set
-# CONFIG_SCSI_FUTURE_DOMAIN is not set
-# CONFIG_SCSI_GDTH is not set
-# CONFIG_SCSI_GENERIC_NCR5380 is not set
-# CONFIG_SCSI_INITIO is not set
-# CONFIG_SCSI_INIA100 is not set
-# CONFIG_SCSI_NCR53C406A is not set
-# CONFIG_SCSI_NCR53C7xx is not set
-# CONFIG_SCSI_SYM53C8XX_2 is not set
-# CONFIG_SCSI_NCR53C8XX is not set
-# CONFIG_SCSI_SYM53C8XX is not set
-# CONFIG_SCSI_PAS16 is not set
-# CONFIG_SCSI_PCI2000 is not set
-# CONFIG_SCSI_PCI2220I is not set
-# CONFIG_SCSI_PSI240I is not set
-# CONFIG_SCSI_QLOGIC_FAS is not set
-# CONFIG_SCSI_QLOGIC_ISP is not set
-# CONFIG_SCSI_QLOGIC_FC is not set
-# CONFIG_SCSI_QLOGIC_1280 is not set
-# CONFIG_SCSI_SIM710 is not set
-# CONFIG_SCSI_SYM53C416 is not set
-# CONFIG_SCSI_DC390T is not set
-# CONFIG_SCSI_T128 is not set
-# CONFIG_SCSI_U14_34F is not set
-# CONFIG_SCSI_NSP32 is not set
-# CONFIG_SCSI_DEBUG is not set
-
-#
-# PCMCIA SCSI adapter support
-#
-# CONFIG_SCSI_PCMCIA is not set
-
-#
-# Fusion MPT device support
-#
-# CONFIG_FUSION is not set
-# CONFIG_FUSION_BOOT is not set
-# CONFIG_FUSION_ISENSE is not set
-# CONFIG_FUSION_CTL is not set
-# CONFIG_FUSION_LAN is not set
-
-#
-# IEEE 1394 (FireWire) support (EXPERIMENTAL)
-#
-# CONFIG_IEEE1394 is not set
-
-#
-# I2O device support
-#
-# CONFIG_I2O is not set
-# CONFIG_I2O_PCI is not set
-# CONFIG_I2O_BLOCK is not set
-# CONFIG_I2O_LAN is not set
-# CONFIG_I2O_SCSI is not set
-# CONFIG_I2O_PROC is not set
-
-#
-# Network device support
-#
-CONFIG_NETDEVICES=y
-
-#
-# ARCnet devices
-#
-# CONFIG_ARCNET is not set
-CONFIG_DUMMY=m
-CONFIG_BONDING=m
-# CONFIG_EQUALIZER is not set
-CONFIG_TUN=m
-# CONFIG_ETHERTAP is not set
-
-#
-# Ethernet (10 or 100Mbit)
-#
-CONFIG_NET_ETHERNET=y
-CONFIG_MIPS_AU1X00_ENET=y
-# CONFIG_BCM5222_DUAL_PHY is not set
-# CONFIG_SUNLANCE is not set
-# CONFIG_HAPPYMEAL is not set
-# CONFIG_SUNBMAC is not set
-# CONFIG_SUNQE is not set
-# CONFIG_SUNGEM is not set
-# CONFIG_NET_VENDOR_3COM is not set
-# CONFIG_LANCE is not set
-# CONFIG_NET_VENDOR_SMC is not set
-# CONFIG_NET_VENDOR_RACAL is not set
-# CONFIG_HP100 is not set
-# CONFIG_NET_ISA is not set
-# CONFIG_NET_PCI is not set
-# CONFIG_NET_POCKET is not set
-
-#
-# Ethernet (1000 Mbit)
-#
-# CONFIG_ACENIC is not set
-# CONFIG_DL2K is not set
-# CONFIG_E1000 is not set
-# CONFIG_MYRI_SBUS is not set
-# CONFIG_NS83820 is not set
-# CONFIG_HAMACHI is not set
-# CONFIG_YELLOWFIN is not set
-# CONFIG_R8169 is not set
-# CONFIG_SK98LIN is not set
-# CONFIG_TIGON3 is not set
-# CONFIG_FDDI is not set
-# CONFIG_HIPPI is not set
-# CONFIG_PLIP is not set
-CONFIG_PPP=y
-CONFIG_PPP_MULTILINK=y
-CONFIG_PPP_FILTER=y
-CONFIG_PPP_ASYNC=y
-CONFIG_PPP_SYNC_TTY=m
-CONFIG_PPP_DEFLATE=m
-CONFIG_PPP_BSDCOMP=m
-CONFIG_PPP_MPPE_MPPC=y
-CONFIG_PPPOE=m
-# CONFIG_SLIP is not set
-
-#
-# Wireless LAN (non-hamradio)
-#
-CONFIG_NET_RADIO=y
-# CONFIG_STRIP is not set
-# CONFIG_WAVELAN is not set
-# CONFIG_ARLAN is not set
-CONFIG_AIRONET4500=m
-CONFIG_AIRONET4500_NONCS=m
-# CONFIG_AIRONET4500_PNP is not set
-CONFIG_AIRONET4500_PCI=y
-# CONFIG_AIRONET4500_ISA is not set
-# CONFIG_AIRONET4500_I365 is not set
-CONFIG_AIRONET4500_PROC=m
-CONFIG_AIRO=m
-# CONFIG_HERMES is not set
-# CONFIG_PLX_HERMES is not set
-# CONFIG_TMD_HERMES is not set
-# CONFIG_PCI_HERMES is not set
-# CONFIG_PCMCIA_HERMES is not set
-# CONFIG_AIRO_CS is not set
-# CONFIG_PCMCIA_ATMEL is not set
-CONFIG_NET_WIRELESS=y
-
-#
-# Token Ring devices
-#
-# CONFIG_TR is not set
-# CONFIG_NET_FC is not set
-# CONFIG_RCPCI is not set
-CONFIG_SHAPER=m
-
-#
-# Wan interfaces
-#
-# CONFIG_WAN is not set
-
-#
-# PCMCIA network device support
-#
-# CONFIG_NET_PCMCIA is not set
-
-#
-# Amateur Radio support
-#
-# CONFIG_HAMRADIO is not set
-
-#
-# IrDA (infrared) support
-#
-# CONFIG_IRDA is not set
-
-#
-# ISDN subsystem
-#
-# CONFIG_ISDN is not set
-
-#
-# Input core support
-#
-# CONFIG_INPUT is not set
-# CONFIG_INPUT_KEYBDEV is not set
-# CONFIG_INPUT_MOUSEDEV is not set
-# CONFIG_INPUT_JOYDEV is not set
-# CONFIG_INPUT_EVDEV is not set
-# CONFIG_INPUT_UINPUT is not set
-
-#
-# Character devices
-#
-# CONFIG_VT is not set
-# CONFIG_SERIAL is not set
-# CONFIG_SERIAL_EXTENDED is not set
-CONFIG_SERIAL_NONSTANDARD=y
-# CONFIG_COMPUTONE is not set
-# CONFIG_ROCKETPORT is not set
-# CONFIG_CYCLADES is not set
-# CONFIG_DIGIEPCA is not set
-# CONFIG_DIGI is not set
-# CONFIG_ESPSERIAL is not set
-# CONFIG_MOXA_INTELLIO is not set
-# CONFIG_MOXA_SMARTIO is not set
-# CONFIG_ISI is not set
-# CONFIG_SYNCLINK is not set
-# CONFIG_SYNCLINKMP is not set
-# CONFIG_N_HDLC is not set
-# CONFIG_RISCOM8 is not set
-# CONFIG_SPECIALIX is not set
-# CONFIG_SX is not set
-# CONFIG_RIO is not set
-# CONFIG_STALDRV is not set
-# CONFIG_SERIAL_TX3912 is not set
-# CONFIG_SERIAL_TX3912_CONSOLE is not set
-# CONFIG_SERIAL_TXX9 is not set
-# CONFIG_SERIAL_TXX9_CONSOLE is not set
-CONFIG_AU1X00_UART=y
-CONFIG_AU1X00_SERIAL_CONSOLE=y
-# CONFIG_AU1X00_USB_TTY is not set
-# CONFIG_AU1X00_USB_RAW is not set
-# CONFIG_TXX927_SERIAL is not set
-# CONFIG_MIPS_HYDROGEN3_BUTTONS is not set
-CONFIG_UNIX98_PTYS=y
-CONFIG_UNIX98_PTY_COUNT=256
-CONFIG_NOZOMI=m
-
-#
-# I2C support
-#
-CONFIG_I2C=m
-CONFIG_I2C_ALGOBIT=m
-# CONFIG_I2C_PHILIPSPAR is not set
-# CONFIG_I2C_ELV is not set
-# CONFIG_I2C_VELLEMAN is not set
-# CONFIG_SCx200_I2C is not set
-CONFIG_I2C_AU1X00GPIO=m
-CONFIG_I2C_AU1X00GPIO_SCL=206
-CONFIG_I2C_AU1X00GPIO_SDA=207
-# CONFIG_SCx200_ACB is not set
-# CONFIG_I2C_ALGOPCF is not set
-# CONFIG_I2C_MAINBOARD is not set
-CONFIG_I2C_CHARDEV=m
-CONFIG_I2C_PROC=m
-
-#
-# Hardware sensors support
-#
-CONFIG_SENSORS=y
-# CONFIG_SENSORS_ADM1021 is not set
-# CONFIG_SENSORS_ADM1024 is not set
-# CONFIG_SENSORS_ADM1025 is not set
-# CONFIG_SENSORS_ADM1026 is not set
-# CONFIG_SENSORS_ADM9240 is not set
-# CONFIG_SENSORS_ASB100 is not set
-# CONFIG_SENSORS_DS1621 is not set
-# CONFIG_SENSORS_FSCPOS is not set
-# CONFIG_SENSORS_FSCSCY is not set
-# CONFIG_SENSORS_GL518SM is not set
-# CONFIG_SENSORS_GL520SM is not set
-# CONFIG_SENSORS_MAXILIFE is not set
-# CONFIG_SENSORS_XEONTEMP is not set
-# CONFIG_SENSORS_IT87 is not set
-# CONFIG_SENSORS_MAX6650 is not set
-# CONFIG_SENSORS_MTP008 is not set
-CONFIG_SENSORS_LM75=m
-CONFIG_SENSORS_LM78=m
-CONFIG_SENSORS_LM80=m
-CONFIG_SENSORS_LM83=m
-CONFIG_SENSORS_LM85=m
-CONFIG_SENSORS_LM87=m
-CONFIG_SENSORS_LM90=m
-CONFIG_SENSORS_LM92=m
-CONFIG_SENSORS_PC87360=m
-# CONFIG_SENSORS_SIS5595 is not set
-# CONFIG_SENSORS_SMSC47M1 is not set
-# CONFIG_SENSORS_THMC50 is not set
-# CONFIG_SENSORS_VIA686A is not set
-# CONFIG_SENSORS_VT1211 is not set
-# CONFIG_SENSORS_VT8231 is not set
-# CONFIG_SENSORS_W83781D is not set
-# CONFIG_SENSORS_W83627HF is not set
-# CONFIG_SENSORS_W83L785TS is not set
-CONFIG_SENSORS_OTHER=y
-CONFIG_SENSORS_BT869=m
-CONFIG_SENSORS_DDCMON=m
-CONFIG_SENSORS_EEPROM=m
-CONFIG_SENSORS_MATORB=m
-CONFIG_SENSORS_PCF8574=m
-CONFIG_SENSORS_PCF8591=m
-
-#
-# Mice
-#
-# CONFIG_BUSMOUSE is not set
-# CONFIG_MOUSE is not set
-
-#
-# Joysticks
-#
-# CONFIG_INPUT_GAMEPORT is not set
-# CONFIG_QIC02_TAPE is not set
-# CONFIG_IPMI_HANDLER is not set
-# CONFIG_IPMI_PANIC_EVENT is not set
-# CONFIG_IPMI_DEVICE_INTERFACE is not set
-# CONFIG_IPMI_KCS is not set
-# CONFIG_IPMI_WATCHDOG is not set
-
-#
-# Watchdog Cards
-#
-# CONFIG_WATCHDOG is not set
-# CONFIG_SCx200 is not set
-# CONFIG_SCx200_GPIO is not set
-# CONFIG_AMD_PM768 is not set
-# CONFIG_NVRAM is not set
-# CONFIG_RTC is not set
-# CONFIG_DTLK is not set
-# CONFIG_R3964 is not set
-# CONFIG_APPLICOM is not set
-
-#
-# Ftape, the floppy tape device driver
-#
-# CONFIG_FTAPE is not set
-# CONFIG_AGP is not set
-
-#
-# Direct Rendering Manager (XFree86 DRI support)
-#
-# CONFIG_DRM is not set
-
-#
-# PCMCIA character devices
-#
-# CONFIG_PCMCIA_SERIAL_CS is not set
-# CONFIG_SYNCLINK_CS is not set
-CONFIG_AU1X00_GPIO=m
-# CONFIG_TS_AU1X00_ADS7846 is not set
-
-#
-# File systems
-#
-# CONFIG_QUOTA is not set
-# CONFIG_QFMT_V2 is not set
-# CONFIG_AUTOFS_FS is not set
-# CONFIG_AUTOFS4_FS is not set
-CONFIG_REISERFS_FS=m
-# CONFIG_REISERFS_CHECK is not set
-# CONFIG_REISERFS_PROC_INFO is not set
-# CONFIG_ADFS_FS is not set
-# CONFIG_ADFS_FS_RW is not set
-# CONFIG_AFFS_FS is not set
-# CONFIG_HFS_FS is not set
-# CONFIG_HFSPLUS_FS is not set
-# CONFIG_BEFS_FS is not set
-# CONFIG_BEFS_DEBUG is not set
-# CONFIG_BFS_FS is not set
-CONFIG_EXT3_FS=m
-CONFIG_JBD=m
-# CONFIG_JBD_DEBUG is not set
-CONFIG_FAT_FS=m
-CONFIG_MSDOS_FS=m
-# CONFIG_UMSDOS_FS is not set
-CONFIG_VFAT_FS=m
-# CONFIG_EFS_FS is not set
-# CONFIG_JFFS_FS is not set
-CONFIG_JFFS2_FS=y
-CONFIG_JFFS2_FS_DEBUG=0
-# CONFIG_JFFS2_FS_NAND is not set
-# CONFIG_CRAMFS is not set
-CONFIG_TMPFS=y
-CONFIG_RAMFS=y
-CONFIG_ISO9660_FS=m
-CONFIG_JOLIET=y
-CONFIG_ZISOFS=y
-# CONFIG_JFS_FS is not set
-# CONFIG_JFS_DEBUG is not set
-# CONFIG_JFS_STATISTICS is not set
-# CONFIG_MINIX_FS is not set
-# CONFIG_VXFS_FS is not set
-CONFIG_NTFS_FS=m
-# CONFIG_NTFS_RW is not set
-# CONFIG_HPFS_FS is not set
-CONFIG_PROC_FS=y
-CONFIG_DEVFS_FS=y
-CONFIG_DEVFS_MOUNT=y
-# CONFIG_DEVFS_DEBUG is not set
-CONFIG_DEVPTS_FS=y
-# CONFIG_QNX4FS_FS is not set
-# CONFIG_QNX4FS_RW is not set
-# CONFIG_ROMFS_FS is not set
-CONFIG_EXT2_FS=m
-# CONFIG_SYSV_FS is not set
-# CONFIG_UDF_FS is not set
-# CONFIG_UDF_RW is not set
-# CONFIG_UFS_FS is not set
-# CONFIG_UFS_FS_WRITE is not set
-# CONFIG_XFS_FS is not set
-# CONFIG_XFS_QUOTA is not set
-# CONFIG_XFS_RT is not set
-# CONFIG_XFS_TRACE is not set
-# CONFIG_XFS_DEBUG is not set
-
-#
-# Network File Systems
-#
-# CONFIG_CODA_FS is not set
-# CONFIG_INTERMEZZO_FS is not set
-CONFIG_NFS_FS=y
-CONFIG_NFS_V3=y
-# CONFIG_NFS_DIRECTIO is not set
-CONFIG_ROOT_NFS=y
-CONFIG_NFSD=y
-CONFIG_NFSD_V3=y
-# CONFIG_NFSD_TCP is not set
-CONFIG_SUNRPC=y
-CONFIG_LOCKD=y
-CONFIG_LOCKD_V4=y
-CONFIG_SMB_FS=m
-# CONFIG_SMB_NLS_DEFAULT is not set
-# CONFIG_SMB_UNIX is not set
-# CONFIG_NCP_FS is not set
-# CONFIG_NCPFS_PACKET_SIGNING is not set
-# CONFIG_NCPFS_IOCTL_LOCKING is not set
-# CONFIG_NCPFS_STRONG is not set
-# CONFIG_NCPFS_NFS_NS is not set
-# CONFIG_NCPFS_OS2_NS is not set
-# CONFIG_NCPFS_SMALLDOS is not set
-# CONFIG_NCPFS_NLS is not set
-# CONFIG_NCPFS_EXTRAS is not set
-CONFIG_ZISOFS_FS=m
-
-#
-# Partition Types
-#
-# CONFIG_PARTITION_ADVANCED is not set
-CONFIG_MSDOS_PARTITION=y
-CONFIG_SMB_NLS=y
-CONFIG_NLS=y
-
-#
-# Native Language Support
-#
-CONFIG_NLS_DEFAULT="iso8859-15"
-CONFIG_NLS_CODEPAGE_437=m
-# CONFIG_NLS_CODEPAGE_737 is not set
-# CONFIG_NLS_CODEPAGE_775 is not set
-CONFIG_NLS_CODEPAGE_850=m
-# CONFIG_NLS_CODEPAGE_852 is not set
-# CONFIG_NLS_CODEPAGE_855 is not set
-# CONFIG_NLS_CODEPAGE_857 is not set
-# CONFIG_NLS_CODEPAGE_860 is not set
-# CONFIG_NLS_CODEPAGE_861 is not set
-# CONFIG_NLS_CODEPAGE_862 is not set
-# CONFIG_NLS_CODEPAGE_863 is not set
-# CONFIG_NLS_CODEPAGE_864 is not set
-# CONFIG_NLS_CODEPAGE_865 is not set
-# CONFIG_NLS_CODEPAGE_866 is not set
-# CONFIG_NLS_CODEPAGE_869 is not set
-# CONFIG_NLS_CODEPAGE_936 is not set
-# CONFIG_NLS_CODEPAGE_950 is not set
-# CONFIG_NLS_CODEPAGE_932 is not set
-# CONFIG_NLS_CODEPAGE_949 is not set
-# CONFIG_NLS_CODEPAGE_874 is not set
-# CONFIG_NLS_ISO8859_8 is not set
-# CONFIG_NLS_CODEPAGE_1250 is not set
-# CONFIG_NLS_CODEPAGE_1251 is not set
-CONFIG_NLS_ISO8859_1=m
-# CONFIG_NLS_ISO8859_2 is not set
-# CONFIG_NLS_ISO8859_3 is not set
-# CONFIG_NLS_ISO8859_4 is not set
-# CONFIG_NLS_ISO8859_5 is not set
-# CONFIG_NLS_ISO8859_6 is not set
-# CONFIG_NLS_ISO8859_7 is not set
-# CONFIG_NLS_ISO8859_9 is not set
-# CONFIG_NLS_ISO8859_13 is not set
-# CONFIG_NLS_ISO8859_14 is not set
-CONFIG_NLS_ISO8859_15=m
-# CONFIG_NLS_KOI8_R is not set
-# CONFIG_NLS_KOI8_U is not set
-CONFIG_NLS_UTF8=m
-
-#
-# Multimedia devices
-#
-CONFIG_VIDEO_DEV=m
-
-#
-# Video For Linux
-#
-CONFIG_VIDEO_PROC_FS=y
-# CONFIG_I2C_PARPORT is not set
-# CONFIG_VIDEO_BT848 is not set
-# CONFIG_VIDEO_PMS is not set
-CONFIG_VIDEO_CPIA=m
-# CONFIG_VIDEO_CPIA_PP is not set
-CONFIG_VIDEO_CPIA_USB=m
-# CONFIG_VIDEO_SAA5249 is not set
-# CONFIG_TUNER_3036 is not set
-# CONFIG_VIDEO_STRADIS is not set
-# CONFIG_VIDEO_ZORAN is not set
-# CONFIG_VIDEO_ZORAN_BUZ is not set
-# CONFIG_VIDEO_ZORAN_DC10 is not set
-# CONFIG_VIDEO_ZORAN_LML33 is not set
-# CONFIG_VIDEO_ZR36120 is not set
-# CONFIG_VIDEO_MEYE is not set
-
-#
-# Radio Adapters
-#
-# CONFIG_RADIO_GEMTEK_PCI is not set
-# CONFIG_RADIO_MAXIRADIO is not set
-# CONFIG_RADIO_MAESTRO is not set
-# CONFIG_RADIO_MIROPCM20 is not set
-
-#
-# Sound
-#
-CONFIG_SOUND=m
-# CONFIG_SOUND_ALI5455 is not set
-# CONFIG_SOUND_BT878 is not set
-# CONFIG_SOUND_CMPCI is not set
-# CONFIG_SOUND_EMU10K1 is not set
-# CONFIG_MIDI_EMU10K1 is not set
-# CONFIG_SOUND_FUSION is not set
-# CONFIG_SOUND_CS4281 is not set
-# CONFIG_SOUND_ES1370 is not set
-# CONFIG_SOUND_ES1371 is not set
-# CONFIG_SOUND_ESSSOLO1 is not set
-# CONFIG_SOUND_MAESTRO is not set
-# CONFIG_SOUND_MAESTRO3 is not set
-# CONFIG_SOUND_FORTE is not set
-# CONFIG_SOUND_ICH is not set
-# CONFIG_SOUND_RME96XX is not set
-# CONFIG_SOUND_SONICVIBES is not set
-CONFIG_SOUND_AU1X00=m
-# CONFIG_SOUND_AU1550_PSC is not set
-# CONFIG_SOUND_AU1550_I2S is not set
-# CONFIG_SOUND_TRIDENT is not set
-# CONFIG_SOUND_MSNDCLAS is not set
-# CONFIG_SOUND_MSNDPIN is not set
-# CONFIG_SOUND_VIA82CXXX is not set
-# CONFIG_MIDI_VIA82CXXX is not set
-CONFIG_SOUND_OSS=m
-# CONFIG_SOUND_TRACEINIT is not set
-# CONFIG_SOUND_DMAP is not set
-# CONFIG_SOUND_AD1816 is not set
-# CONFIG_SOUND_AD1889 is not set
-# CONFIG_SOUND_SGALAXY is not set
-# CONFIG_SOUND_ADLIB is not set
-# CONFIG_SOUND_ACI_MIXER is not set
-# CONFIG_SOUND_CS4232 is not set
-# CONFIG_SOUND_SSCAPE is not set
-# CONFIG_SOUND_GUS is not set
-# CONFIG_SOUND_VMIDI is not set
-# CONFIG_SOUND_TRIX is not set
-# CONFIG_SOUND_MSS is not set
-# CONFIG_SOUND_MPU401 is not set
-# CONFIG_SOUND_NM256 is not set
-# CONFIG_SOUND_MAD16 is not set
-# CONFIG_SOUND_PAS is not set
-# CONFIG_PAS_JOYSTICK is not set
-# CONFIG_SOUND_PSS is not set
-# CONFIG_SOUND_SB is not set
-# CONFIG_SOUND_AWE32_SYNTH is not set
-# CONFIG_SOUND_KAHLUA is not set
-# CONFIG_SOUND_WAVEFRONT is not set
-# CONFIG_SOUND_MAUI is not set
-# CONFIG_SOUND_YM3812 is not set
-# CONFIG_SOUND_OPL3SA1 is not set
-# CONFIG_SOUND_OPL3SA2 is not set
-# CONFIG_SOUND_YMFPCI is not set
-# CONFIG_SOUND_YMFPCI_LEGACY is not set
-# CONFIG_SOUND_UART6850 is not set
-# CONFIG_SOUND_AEDSP16 is not set
-# CONFIG_SOUND_TVMIXER is not set
-# CONFIG_SOUND_AD1980 is not set
-# CONFIG_SOUND_WM97XX is not set
-
-#
-# USB support
-#
-CONFIG_USB=y
-# CONFIG_USB_DEBUG is not set
-CONFIG_USB_DEVICEFS=y
-# CONFIG_USB_BANDWIDTH is not set
-# CONFIG_USB_EHCI_HCD is not set
-# CONFIG_USB_UHCI is not set
-# CONFIG_USB_UHCI_ALT is not set
-CONFIG_USB_OHCI=m
-CONFIG_USB_AUDIO=m
-CONFIG_USB_EMI26=m
-CONFIG_USB_MIDI=m
-CONFIG_USB_STORAGE=m
-CONFIG_USB_STORAGE_DEBUG=y
-CONFIG_USB_STORAGE_DATAFAB=y
-CONFIG_USB_STORAGE_FREECOM=y
-# CONFIG_USB_STORAGE_ISD200 is not set
-CONFIG_USB_STORAGE_DPCM=y
-CONFIG_USB_STORAGE_HP8200e=y
-CONFIG_USB_STORAGE_SDDR09=y
-CONFIG_USB_STORAGE_SDDR55=y
-CONFIG_USB_STORAGE_JUMPSHOT=y
-CONFIG_USB_ACM=m
-CONFIG_USB_PRINTER=m
-# CONFIG_USB_HID is not set
-# CONFIG_USB_HIDINPUT is not set
-# CONFIG_USB_HIDDEV is not set
-# CONFIG_USB_KBD is not set
-# CONFIG_USB_MOUSE is not set
-# CONFIG_USB_AIPTEK is not set
-# CONFIG_USB_WACOM is not set
-# CONFIG_USB_KBTAB is not set
-# CONFIG_USB_POWERMATE is not set
-CONFIG_USB_DC2XX=m
-CONFIG_USB_MDC800=m
-CONFIG_USB_SCANNER=m
-CONFIG_USB_MICROTEK=m
-CONFIG_USB_HPUSBSCSI=m
-CONFIG_USB_IBMCAM=m
-CONFIG_USB_KONICAWC=m
-CONFIG_USB_OV511=m
-CONFIG_USB_PWC=m
-CONFIG_USB_SE401=m
-CONFIG_USB_STV680=m
-# CONFIG_USB_W9968CF is not set
-CONFIG_USB_VICAM=m
-CONFIG_USB_DSBR=m
-CONFIG_USB_DABUSB=m
-CONFIG_USB_PEGASUS=m
-CONFIG_USB_RTL8150=m
-CONFIG_USB_KAWETH=m
-CONFIG_USB_CATC=m
-CONFIG_USB_CDCETHER=m
-CONFIG_USB_USBNET=m
-# CONFIG_USB_USS720 is not set
-
-#
-# USB Serial Converter support
-#
-CONFIG_USB_SERIAL=m
-# CONFIG_USB_SERIAL_DEBUG is not set
-CONFIG_USB_SERIAL_GENERIC=y
-CONFIG_USB_SERIAL_BELKIN=m
-CONFIG_USB_SERIAL_WHITEHEAT=m
-CONFIG_USB_SERIAL_DIGI_ACCELEPORT=m
-CONFIG_USB_SERIAL_EMPEG=m
-CONFIG_USB_SERIAL_FTDI_SIO=m
-CONFIG_USB_SERIAL_VISOR=m
-CONFIG_USB_SERIAL_IPAQ=m
-CONFIG_USB_SERIAL_IR=m
-CONFIG_USB_SERIAL_EDGEPORT=m
-CONFIG_USB_SERIAL_EDGEPORT_TI=m
-CONFIG_USB_SERIAL_KEYSPAN_PDA=m
-CONFIG_USB_SERIAL_KEYSPAN=m
-CONFIG_USB_SERIAL_KEYSPAN_USA28=y
-CONFIG_USB_SERIAL_KEYSPAN_USA28X=y
-CONFIG_USB_SERIAL_KEYSPAN_USA28XA=y
-CONFIG_USB_SERIAL_KEYSPAN_USA28XB=y
-CONFIG_USB_SERIAL_KEYSPAN_USA19=y
-CONFIG_USB_SERIAL_KEYSPAN_USA18X=y
-CONFIG_USB_SERIAL_KEYSPAN_USA19W=y
-CONFIG_USB_SERIAL_KEYSPAN_USA19QW=y
-CONFIG_USB_SERIAL_KEYSPAN_USA19QI=y
-CONFIG_USB_SERIAL_KEYSPAN_MPR=y
-CONFIG_USB_SERIAL_KEYSPAN_USA49W=y
-CONFIG_USB_SERIAL_KEYSPAN_USA49WLC=y
-CONFIG_USB_SERIAL_MCT_U232=m
-CONFIG_USB_SERIAL_KLSI=m
-CONFIG_USB_SERIAL_KOBIL_SCT=m
-CONFIG_USB_SERIAL_PL2303=m
-CONFIG_USB_SERIAL_CYBERJACK=m
-CONFIG_USB_SERIAL_XIRCOM=m
-CONFIG_USB_SERIAL_OMNINET=m
-CONFIG_USB_RIO500=m
-CONFIG_USB_AUERSWALD=m
-CONFIG_USB_TIGL=m
-CONFIG_USB_BRLVGER=m
-CONFIG_USB_LCD=m
-
-#
-# Support for USB gadgets
-#
-# CONFIG_USB_GADGET is not set
-
-#
-# USB clients (devices, not hosts)
-#
-CONFIG_USBD=m
-# CONFIG_USBD_HIGH_SPEED is not set
-# CONFIG_USBD_NO_SERIAL_NUMBER is not set
-CONFIG_USBD_SERIAL_NUMBER_STR=""
-CONFIG_USBD_MAXPOWER=0
-CONFIG_USBD_PROCFS=y
-CONFIG_USBD_PROCFSM=m
-
-#
-# Network Function
-#
-CONFIG_USBD_NETWORK=m
-CONFIG_USBD_NETWORK_VENDORID=12b9
-CONFIG_USBD_NETWORK_PRODUCTID=f001
-CONFIG_USBD_NETWORK_BCDDEVICE=0100
-CONFIG_USBD_NETWORK_MANUFACTURER="Belcarra"
-## CONFIG_USBD_NETWORK_PRODUCT_NAME="Belcarra BLAN Device"
-## CONFIG_USBD_NETWORK_BLAN=y
-## CONFIG_USBD_NETWORK_BLAN_DESC="BLAN Net Cfg"
-## CONFIG_USBD_NETWORK_BLAN_INTF="Comm/Data Intf"
-# CONFIG_USBD_NETWORK_BLAN_CRC is not set
-# CONFIG_USBD_NETWORK_BLAN_DO_NOT_SETTIME is not set
-# CONFIG_USBD_NETWORK_BLAN_HOSTNAME is not set
-# CONFIG_USBD_NETWORK_BLAN_NOBRIDGE is not set
-CONFIG_USBD_NETWORK_SAFE=y
-CONFIG_USBD_NETWORK_SAFE_NOBRIDGE=y
-# CONFIG_USBD_NETWORK_CDC is not set
-# CONFIG_USBD_NETWORK_BASIC is not set
-# CONFIG_USBD_NETWORK_BASIC2 is not set
-# CONFIG_USBD_NETWORK_START_SINGLE is not set
-# CONFIG_USBD_NETWORK_EP0TEST is not set
-
-#
-# CDC ACM Function
-#
-CONFIG_USBD_ACM=m
-CONFIG_USBD_ACM_VENDORID=12b9
-CONFIG_USBD_ACM_PRODUCTID=f002
-CONFIG_USBD_ACM_BCDDEVICE=0100
-CONFIG_USBD_ACM_MANUFACTURER="Belcarra"
-CONFIG_USBD_ACM_PRODUCT_NAME="Belcarra ACM Device"
-CONFIG_USBD_ACM_DESC="Acm Cfg"
-CONFIG_USBD_ACM_COMM_INTF="Comm Intf"
-CONFIG_USBD_ACM_DATA_INTF="Data Intf"
-# CONFIG_USBD_ACM_TRACE is not set
-
-#
-# Random Mouse Function
-#
-# CONFIG_USBD_MOUSE is not set
-
-#
-# AMD AU1X000 Bus Interface
-#
-CONFIG_USBD_AU1X00_BUS=m
-CONFIG_USBD_AU1X00_SCLOCK=400
-CONFIG_AU1000_USB_DEVICE=y
-CONFIG_AU1X00_USB_DEVICE=y
-# CONFIG_USBD_BI_REGISTER_TRACE is not set
-
-#
-# Bluetooth support
-#
-CONFIG_BLUEZ=m
-CONFIG_BLUEZ_L2CAP=m
-CONFIG_BLUEZ_SCO=m
-CONFIG_BLUEZ_RFCOMM=m
-CONFIG_BLUEZ_RFCOMM_TTY=y
-CONFIG_BLUEZ_BNEP=m
-CONFIG_BLUEZ_BNEP_MC_FILTER=y
-CONFIG_BLUEZ_BNEP_PROTO_FILTER=y
-
-#
-# Bluetooth device drivers
-#
-CONFIG_BLUEZ_HCIUSB=m
-CONFIG_BLUEZ_HCIUSB_SCO=y
-CONFIG_BLUEZ_HCIUART=m
-CONFIG_BLUEZ_HCIUART_H4=y
-CONFIG_BLUEZ_HCIUART_BCSP=y
-CONFIG_BLUEZ_HCIUART_BCSP_TXCRC=y
-CONFIG_BLUEZ_HCIBFUSB=m
-# CONFIG_BLUEZ_HCIDTL1 is not set
-# CONFIG_BLUEZ_HCIBT3C is not set
-# CONFIG_BLUEZ_HCIBLUECARD is not set
-# CONFIG_BLUEZ_HCIBTUART is not set
-CONFIG_BLUEZ_HCIVHCI=m
-
-#
-# Kernel hacking
-#
-CONFIG_CROSSCOMPILE=y
-# CONFIG_RUNTIME_DEBUG is not set
-# CONFIG_KGDB is not set
-# CONFIG_GDB_CONSOLE is not set
-# CONFIG_DEBUG_INFO is not set
-# CONFIG_MAGIC_SYSRQ is not set
-# CONFIG_MIPS_UNCACHED is not set
-CONFIG_LOG_BUF_SHIFT=0
-
-#
-# Cryptographic options
-#
-CONFIG_CRYPTO=y
-CONFIG_CRYPTO_HMAC=y
-CONFIG_CRYPTO_NULL=m
-CONFIG_CRYPTO_MD4=m
-CONFIG_CRYPTO_MD5=m
-CONFIG_CRYPTO_SHA1=m
-CONFIG_CRYPTO_SHA256=m
-CONFIG_CRYPTO_SHA512=m
-CONFIG_CRYPTO_DES=m
-CONFIG_CRYPTO_BLOWFISH=m
-CONFIG_CRYPTO_TWOFISH=m
-CONFIG_CRYPTO_SERPENT=m
-CONFIG_CRYPTO_AES=m
-CONFIG_CRYPTO_CAST5=m
-CONFIG_CRYPTO_CAST6=m
-CONFIG_CRYPTO_TEA=m
-CONFIG_CRYPTO_ARC4=m
-CONFIG_CRYPTO_DEFLATE=m
-CONFIG_CRYPTO_MICHAEL_MIC=m
-CONFIG_CRYPTO_TEST=m
-
-#
-# Library routines
-#
-CONFIG_CRC32=m
-CONFIG_ZLIB_INFLATE=y
-CONFIG_ZLIB_DEFLATE=y
-CONFIG_FW_LOADER=m