Index: pplinux/linuxnew/Build
diff -u /dev/null pplinux/linuxnew/Build:1.8
--- /dev/null	Tue May 24 10:37:58 2005
+++ pplinux/linuxnew/Build	Mon May  2 14:12:51 2005
@@ -0,0 +1,62 @@
+#!/bin/sh
+
+source ../../Config.sh
+
+pp_clean_local () {
+#    if [ "$PP_PRODUCT" = "lara_bmc_test" ]; then
+#    	make -C patches clean
+#    fi
+    make mrproper
+    return 0
+}
+
+pp_build_local () {
+    if [ ! -x "$FW_TOPDIR/pplinux/u-boot/tools/mkimage" ]; then
+	echo "Build u-boot first, please!"
+	return 1
+    fi
+
+    if [ "$PP_PRODUCTION" = "1" ]; then
+	config="${PP_BOARD}_${PP_SUBBOARD}_production_defconfig"
+    else
+	if [ "$PP_FEAT_WLAN" = "1" ]; then
+	    config="${PP_BOARD}_${PP_SUBBOARD}_wlan_defconfig"
+	elif [ "$PP_PRODUCT" = "lara_bmc_test" ]; then
+	    config="${PP_BOARD}_${PP_SUBBOARD}_ipmi_defconfig"
+	else
+	    config="${PP_BOARD}_${PP_SUBBOARD}_defconfig"
+	fi
+    fi
+
+#    # apply patches (only needed for lara_bmc_test)
+#    if [ "$PP_PRODUCT" = "lara_bmc_test" ]; then
+#    	make -C patches || return 1
+#    fi
+
+    # generate default config file
+    pushd arch/ppc/configs
+	echo -n "Using ${config} ... "
+	if [ -e "${config}" ]; then
+	    cp -f "${config}" peppercon_defconfig || return 1
+	else
+	    echo "not found. bailing out."
+	    return 1
+	fi
+    popd
+
+    # set environment variable LNX_FASTBUILD to 1 if you want to do a fast
+    # kernel build without oldconfig/dep/clean - this is ignored for final!
+    # Do this on command line and *not here* in this file!
+
+    # NOTE: "oldconfig" must be separate!
+    if [ "$PP_BUILD_TYPE" = "final" -o "$LNX_FASTBUILD" != "1" ]; then
+	# regular build
+	make peppercon_config oldconfig \
+	  && make dep clean uImage modules modules_install pp_install
+    else
+	# for kernel hackers: fast build
+	make uImage modules modules_install pp_install
+    fi
+}
+
+pp_do "$@"
Index: pplinux/linuxnew/Makefile
diff -u pplinux/linuxnew/Makefile:1.1.323.1 pplinux/linuxnew/Makefile:1.4
--- pplinux/linuxnew/Makefile:1.1.323.1	Thu Feb  3 10:00:11 2005
+++ pplinux/linuxnew/Makefile	Wed Apr  6 11:53:10 2005
@@ -3,9 +3,13 @@
 SUBLEVEL = 26
 EXTRAVERSION =
 
+USE_REAL_CROSS = 1
+include ../../Config.mk
+
 KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
 
-ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/)
+#ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/)
+ARCH := ppc
 KERNELPATH=kernel-$(shell echo $(KERNELRELEASE) | sed -e "s/-//g")
 
 CONFIG_SHELL := $(shell if [ -x "$$BASH" ]; then echo $$BASH; \
@@ -19,7 +23,7 @@
 HOSTCC  	= gcc
 HOSTCFLAGS	= -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer
 
-CROSS_COMPILE 	=
+CROSS_COMPILE 	= $(CROSS)
 
 #
 # Include the make variables (CC, etc...)
@@ -82,14 +86,17 @@
 # makefile but the arguement can be passed to make if needed.
 #
 
-MODLIB	:= $(INSTALL_MOD_PATH)/lib/modules/$(KERNELRELEASE)
+INSTALL_MOD_PATH=$(DESTDIR)
+export INSTALL_MOD_PATH
+
+MODLIB := $(INSTALL_MOD_PATH)/lib/modules/$(KERNELRELEASE)
 export MODLIB
 
 #
 # standard CFLAGS
 #
 
-CPPFLAGS := -D__KERNEL__ -I$(HPATH)
+CPPFLAGS := -D__KERNEL__ -I$(HPATH) -include $(FW_TOPDIR)/include/pp/features.h $(FW_CPPFLAGS)
 
 CFLAGS := $(CPPFLAGS) -Wall -Wstrict-prototypes -Wno-trigraphs -O2 \
 	  -fno-strict-aliasing -fno-common
@@ -359,6 +366,13 @@
 	@echo \#define UTS_RELEASE \"$(KERNELRELEASE)\" > .ver
 	@echo \#define LINUX_VERSION_CODE `expr $(VERSION) \\* 65536 + $(PATCHLEVEL) \\* 256 + $(SUBLEVEL)` >> .ver
 	@echo '#define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c))' >>.ver
+	@echo \#define UTS_BOARDTYPE \"$(PP_BOARD)\" >> .ver
+	@echo \#define UTS_PRODUCTTYPE \"$(PP_PRODUCT)\" >> .ver
+	@if [ "$(PP_PRODUCTION)" = "1" ]; then \
+	  echo \#define UTS_PRODUCTION \"$(PP_PRODUCTION)\" >> .ver; \
+	else \
+	  echo \#define UTS_PRODUCTION \"0\" >> .ver; \
+	fi
 	@mv -f .ver $@
 
 comma	:= ,
@@ -400,14 +414,12 @@
 	$(MAKE) -C $(patsubst _mod_%, %, $@) CFLAGS="$(CFLAGS) $(MODFLAGS)" MAKING_MODULES=1 modules
 
 .PHONY: modules_install
-modules_install: _modinst_ $(patsubst %, _modinst_%, $(SUBDIRS)) _modinst_post
+modules_install: _modinst_ $(patsubst %, _modinst_%, $(SUBDIRS))
 
 .PHONY: _modinst_
 _modinst_:
 	@rm -rf $(MODLIB)/kernel
-	@rm -f $(MODLIB)/build
 	@mkdir -p $(MODLIB)/kernel
-	@ln -s $(TOPDIR) $(MODLIB)/build
 
 # If System.map exists, run depmod.  This deliberately does not have a
 # dependency on System.map since that would run the dependency tree on
@@ -500,7 +512,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 -print0 | xargs -0 scripts/mkdep -- | cat > .hdepend
 	scripts/mkdep -- init/*.c > .depend
 
 ifdef CONFIG_MODVERSIONS
@@ -579,3 +591,42 @@
 	. scripts/mkversion > .version ; \
 	$(RPM) -ta $(TOPDIR)/../$(KERNELPATH).tar.gz ; \
 	rm $(TOPDIR)/../$(KERNELPATH).tar.gz
+
+pp_install:
+ifeq ($(PP_PRODUCTION),1)
+
+# PP_PRODUCTION
+
+ifeq ($(PP_BOARD),lara)
+    ifeq ($(PP_SUBBOARD),none)
+	cp -f arch/$(ARCH)/boot/images/uImage /tftpboot/zImage.lara.prod
+    else
+	cp -f arch/$(ARCH)/boot/images/uImage /tftpboot/zImage.lara.$(PP_SUBBOARD).prod
+    endif
+  else
+    ifeq ($(PP_BOARD),eric)
+	cp -f arch/$(ARCH)/boot/images/uImage /tftpboot/zImage.eric.prod
+    endif
+  endif
+
+else
+
+# !PP_PRODUCTION
+
+  ifeq ($(PP_BOARD),lara)
+    ifeq ($(PP_SUBBOARD),none)
+	cp -f arch/$(ARCH)/boot/images/uImage /tftpboot/zImage.lara.$(USER)
+    else
+	cp -f arch/$(ARCH)/boot/images/uImage /tftpboot/zImage.lara.$(PP_SUBBOARD).$(USER)
+    endif
+  else
+    ifeq ($(PP_BOARD),eric)
+	cp -f arch/$(ARCH)/boot/images/uImage /tftpboot/zImage.eric.$(USER)
+    endif
+  endif
+
+  ifeq ($(PP_BUILD_TYPE),final)
+	cp -f arch/$(ARCH)/boot/images/uImage $(FW_TOPDIR)/mkfirmware/zImage.bin
+  endif
+
+endif
Index: pplinux/linuxnew/Documentation/Configure.help
diff -u pplinux/linuxnew/Documentation/Configure.help:1.1.323.1 pplinux/linuxnew/Documentation/Configure.help:1.5
--- pplinux/linuxnew/Documentation/Configure.help:1.1.323.1	Thu Feb  3 10:00:11 2005
+++ pplinux/linuxnew/Documentation/Configure.help	Wed Apr  6 11:28:07 2005
@@ -320,6 +320,14 @@
   If you are not sure, say Y; apart from resulting in a 66 KB bigger
   kernel, it won't hurt.
 
+Support for big physical area reservation
+CONFIG_BIGPHYS_AREA
+  Enables kernel support for reserving large areas of physical memory
+  at boot-time for use by certain device drivers (such as video
+  framegrabbers, etc.) which require it. To use this feature, boot
+  the kernel with the boot-time option 'bigphysarea=nnn' where
+  'nnn' is the number of pages (a page is usually 4K) to reserve.
+
 Timer and CPU usage LEDs
 CONFIG_LEDS
   If you say Y here, the LEDs on your machine will be used
Index: pplinux/linuxnew/Documentation/bigphysarea.txt
diff -u /dev/null pplinux/linuxnew/Documentation/bigphysarea.txt:1.1
--- /dev/null	Tue May 24 10:37:58 2005
+++ pplinux/linuxnew/Documentation/bigphysarea.txt	Thu Feb  3 11:35:36 2005
@@ -0,0 +1,64 @@
+Bigphysarea
+===========
+
+This set of functions give you the ability to allocate big
+contineous (DMAable) memory for the entire runtime of Linux.
+Big meaning here more than 128KB, the maximum allocation
+limit of kmalloc(). Due to fragmentation reasons kmalloc()
+is unable to garantee allocs of this order during a prolonged
+run of the kernel. This new pool of memory blob can be used
+during the initialization or use of soundcards of framegrabbers
+which are designed without DMA scatter-gatter capabilities.
+
+For a sample use, see the zoran driver in drivers/char/zr36120_mem.c
+
+Enjoy,
+  Pauline Middelink
+
+How to start
+============
+First add bigphysarea=<number of pages to alloc> to the
+commandline of your kernel. Either do this by adding an
+append= line to your /etc/lilo/conf setup or use some
+magic marker...
+After booting the new kernel there should be a /proc/bigphysarea
+file telling your how many blocks/bytes are available.
+
+The interface description
+=========================
+The big physical area is mainly managed by two functions. The first one,
+
+caddr_t bigphysarea_alloc_pages(int count, int align, int priority)
+
+allocates 'count' pages. The pages are aligned so that there base
+address is a multiple of 'PAGE_SIZE * align'. If you don't need more
+than page alignment, set 'align' to 0 or 1. 'priority' has the same
+meaning as in kmalloc, it can be GFP_ATOMIC (for calls from interrupt
+handlers) or GFP_KERNEL (for usual calls). The base address of the
+allocated area is returned.
+
+Allocation can fail for two reasons, in both cases NULL is
+returned. First, the physical area is scattered too much or there is
+not enough memory, second it is not possible to allocate some memory
+with kmalloc for administration of the physical area (very unlikely).
+
+To free an allocated area, just call
+
+void bigphysarea_free_pages(caddr_t base)
+
+with 'base' set to the value returned by 'bigphysarea_alloc_pages'. 
+
+An example how to use this functions can be found in 'module.c'.
+
+There is still the old interface introduced by M. Welsh:
+
+caddr_t bigphysarea_alloc(int size)
+void bigphysarea_free(caddr_t addr, int size)
+
+The first function allocates 'size' bytes physically continous
+memory. To free the area, bigphysarea_free with a pointer to the area
+and its size has to be called. Due to a new allocation algorithm, the
+size parameter is no longer really needed when freeing an area.
+
+In the current version it is not safe to call any of the functions
+from an interrupt handler.
Index: pplinux/linuxnew/arch/ppc/Makefile
diff -u pplinux/linuxnew/arch/ppc/Makefile:1.1.323.1 pplinux/linuxnew/arch/ppc/Makefile:1.2
--- pplinux/linuxnew/arch/ppc/Makefile:1.1.323.1	Thu Feb  3 10:00:25 2005
+++ pplinux/linuxnew/arch/ppc/Makefile	Thu Feb  3 11:35:37 2005
@@ -25,6 +25,10 @@
 HOSTCFLAGS	+= -I$(TOPDIR)/arch/$(ARCH)
 CPP		= $(CC) -E $(CFLAGS)
 
+ifdef CONFIG_405
+CFLAGS := $(CFLAGS) -mcpu=405
+endif
+
 ifdef CONFIG_4xx
 CFLAGS := $(CFLAGS) -Wa,-m405
 endif
Index: pplinux/linuxnew/arch/ppc/config.in
diff -u pplinux/linuxnew/arch/ppc/config.in:1.1.323.1 pplinux/linuxnew/arch/ppc/config.in:1.3
--- pplinux/linuxnew/arch/ppc/config.in:1.1.323.1	Thu Feb  3 10:00:25 2005
+++ pplinux/linuxnew/arch/ppc/config.in	Fri Apr 29 10:43:28 2005
@@ -91,6 +91,8 @@
 	 Sycamore	CONFIG_SYCAMORE		\
 	 Tivo		CONFIG_TIVO 		\
 	 Walnut		CONFIG_WALNUT		\
+	 Peppercon405GP	CONFIG_PEPPERCON_405GP	\
+	 Peppercon405EP	CONFIG_PEPPERCON_405EP	\
 	 Xilinx-ML300	CONFIG_XILINX_ML300"	Walnut
 
    if [ "$CONFIG_EP405" = "y" ]; then
@@ -295,6 +297,7 @@
 
 if [ "$CONFIG_4xx" = "y" -o "$CONFIG_8xx" = "y" ]; then
   bool 'Math emulation' CONFIG_MATH_EMULATION
+  bool 'Support for big physical area reservation' CONFIG_BIGPHYS_AREA
 fi
 
 if [ "$CONFIG_4xx" = "y" ]; then
@@ -396,6 +399,14 @@
     define_bool CONFIG_440GX y
   fi
 
+  if [ "$CONFIG_PEPPERCON_405GP" = "y" ]; then
+    define_bool CONFIG_PEPPERCON y
+    define_bool CONFIG_405GP y
+  elif [ "$CONFIG_PEPPERCON_405EP" = "y" ]; then
+    define_bool CONFIG_PEPPERCON y
+    define_bool CONFIG_405EP y
+  fi
+
 #
 # Set options based on processor implementation
 #
@@ -404,6 +415,7 @@
        "$CONFIG_NP405GS" = "y" -o "$CONFIG_STB03xxx" = "y" -o \
        "$CONFIG_405LP" = "y" -o "$CONFIG_405GPR" = "y" ]; then
     define_bool CONFIG_IBM_OCP y
+    define_bool CONFIG_PPC_OCP y
     define_bool CONFIG_GEN550 y
     define_bool CONFIG_405 y
   fi
@@ -567,6 +579,7 @@
 bool 'Select task to kill on out of memory condition' CONFIG_OOM_KILLER
 
 source drivers/pci/Config.in
+source drivers/hotplug/Config.in
 
 bool 'Support for hot-pluggable devices' CONFIG_HOTPLUG
 
@@ -716,6 +729,9 @@
 if [ "$CONFIG_40x" != "y" -a "$CONFIG_8xx" != "y" ]; then
   bool 'Support for VGA Console' CONFIG_VGA_CONSOLE
 fi
+if [ "$CONFIG_PEPPERCON" = "y" ]; then
+  define_bool CONFIG_DUMMY_CONSOLE y
+fi
  source drivers/video/Config.in
 if [ "$CONFIG_FB" = "y" -a "$CONFIG_ALL_PPC" = "y" ]; then
   bool 'Backward compatibility mode for Xpmac' CONFIG_FB_COMPAT_XPMAC
Index: pplinux/linuxnew/arch/ppc/defconfig
diff -u pplinux/linuxnew/arch/ppc/defconfig:1.1.323.1 pplinux/linuxnew/arch/ppc/defconfig:removed
--- pplinux/linuxnew/arch/ppc/defconfig:1.1.323.1	Thu Feb  3 10:00:25 2005
+++ pplinux/linuxnew/arch/ppc/defconfig	Tue May 24 10:37:58 2005
@@ -1,1115 +0,0 @@
-#
-# Automatically generated make config: don't edit
-#
-# CONFIG_UID16 is not set
-# CONFIG_RWSEM_GENERIC_SPINLOCK is not set
-CONFIG_RWSEM_XCHGADD_ALGORITHM=y
-CONFIG_HAVE_DEC_LOCK=y
-
-#
-# Code maturity level options
-#
-CONFIG_EXPERIMENTAL=y
-# CONFIG_ADVANCED_OPTIONS is not set
-
-#
-# Loadable module support
-#
-CONFIG_MODULES=y
-CONFIG_MODVERSIONS=y
-CONFIG_KMOD=y
-
-#
-# Platform support
-#
-CONFIG_PPC=y
-CONFIG_PPC32=y
-CONFIG_6xx=y
-# CONFIG_40x is not set
-# CONFIG_440 is not set
-# CONFIG_POWER3 is not set
-# CONFIG_8xx is not set
-# CONFIG_8260 is not set
-CONFIG_PPC_STD_MMU=y
-CONFIG_ALL_PPC=y
-# CONFIG_APUS is not set
-# CONFIG_WILLOW is not set
-# CONFIG_CPCI690 is not set
-# CONFIG_PCORE is not set
-# CONFIG_POWERPMC250 is not set
-# CONFIG_PPMC260 is not set
-# CONFIG_EV64260 is not set
-# CONFIG_SPRUCE is not set
-# CONFIG_PUMA_A is not set
-# CONFIG_HXEB100 is not set
-# CONFIG_LOPEC is not set
-# CONFIG_MCPN765 is not set
-# CONFIG_MVME5100 is not set
-# CONFIG_PPLUS is not set
-# CONFIG_PRPMC750 is not set
-# CONFIG_PRPMC800 is not set
-# CONFIG_SANDPOINT is not set
-# CONFIG_ADIR is not set
-# CONFIG_K2 is not set
-# CONFIG_PAL4 is not set
-# CONFIG_GEMINI is not set
-# CONFIG_SMP is not set
-CONFIG_ALTIVEC=y
-CONFIG_TAU=y
-# CONFIG_TAU_INT is not set
-# CONFIG_TAU_AVERAGE is not set
-CONFIG_PPC_ISATIMER=y
-
-#
-# General setup
-#
-# CONFIG_HIGHMEM is not set
-# CONFIG_ISA is not set
-# CONFIG_EISA is not set
-# CONFIG_SBUS is not set
-# CONFIG_MCA is not set
-CONFIG_PCI=y
-CONFIG_NET=y
-CONFIG_SYSCTL=y
-CONFIG_SYSVIPC=y
-# CONFIG_BSD_PROCESS_ACCT is not set
-CONFIG_KCORE_ELF=y
-CONFIG_BINFMT_ELF=y
-CONFIG_KERNEL_ELF=y
-CONFIG_BINFMT_MISC=m
-# CONFIG_OOM_KILLER is not set
-CONFIG_PCI_NAMES=y
-CONFIG_HOTPLUG=y
-
-#
-# PCMCIA/CardBus support
-#
-# CONFIG_PCMCIA is not set
-
-#
-# Parallel port support
-#
-# CONFIG_PARPORT is not set
-CONFIG_GEN_RTC=y
-CONFIG_PPC601_SYNC_FIX=y
-CONFIG_PROC_DEVICETREE=y
-CONFIG_PPC_RTAS=y
-CONFIG_PREP_RESIDUAL=y
-CONFIG_PROC_PREPRESIDUAL=y
-CONFIG_PPCBUG_NVRAM=y
-CONFIG_CMDLINE_BOOL=y
-CONFIG_CMDLINE="console=ttyS0,9600 console=tty0 root=/dev/sda2"
-
-#
-# Memory Technology Devices (MTD)
-#
-# CONFIG_MTD is not set
-
-#
-# Plug and Play configuration
-#
-# CONFIG_PNP is not set
-# CONFIG_ISAPNP is not set
-
-#
-# Block devices
-#
-CONFIG_BLK_DEV_FD=m
-# 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_BLK_DEV_DAC960 is not set
-# CONFIG_BLK_DEV_UMEM is not set
-CONFIG_BLK_DEV_LOOP=y
-# CONFIG_BLK_DEV_NBD is not set
-CONFIG_BLK_DEV_RAM=y
-CONFIG_BLK_DEV_RAM_SIZE=4096
-CONFIG_BLK_DEV_INITRD=y
-CONFIG_BLK_STATS=y
-
-#
-# 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 is not set
-# CONFIG_NETLINK_DEV is not set
-CONFIG_NETFILTER=y
-# CONFIG_NETFILTER_DEBUG is not set
-# CONFIG_FILTER is not set
-CONFIG_UNIX=y
-CONFIG_INET=y
-CONFIG_IP_MULTICAST=y
-# CONFIG_IP_ADVANCED_ROUTER is not set
-# CONFIG_IP_PNP is not set
-# CONFIG_NET_IPIP is not set
-# CONFIG_NET_IPGRE is not set
-# CONFIG_IP_MROUTE is not set
-# CONFIG_ARPD is not set
-# CONFIG_INET_ECN is not set
-CONFIG_SYN_COOKIES=y
-
-#
-#   IP: Netfilter Configuration
-#
-CONFIG_IP_NF_CONNTRACK=m
-CONFIG_IP_NF_FTP=m
-CONFIG_IP_NF_AMANDA=m
-CONFIG_IP_NF_TFTP=m
-CONFIG_IP_NF_IRC=m
-# CONFIG_IP_NF_QUEUE is not set
-CONFIG_IP_NF_IPTABLES=m
-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=m
-CONFIG_IP_NF_MATCH_CONNTRACK=m
-CONFIG_IP_NF_MATCH_UNCLEAN=m
-CONFIG_IP_NF_MATCH_OWNER=m
-CONFIG_IP_NF_FILTER=m
-CONFIG_IP_NF_TARGET_REJECT=m
-CONFIG_IP_NF_TARGET_MIRROR=m
-CONFIG_IP_NF_NAT=m
-CONFIG_IP_NF_NAT_NEEDED=y
-CONFIG_IP_NF_TARGET_MASQUERADE=m
-CONFIG_IP_NF_TARGET_REDIRECT=m
-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 is not set
-# CONFIG_IP_NF_TARGET_LOG is not set
-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_COMPAT_IPCHAINS=m
-CONFIG_IP_NF_NAT_NEEDED=y
-# CONFIG_IP_NF_COMPAT_IPFWADM is not set
-# CONFIG_IPV6 is not set
-# CONFIG_KHTTPD is not set
-# CONFIG_ATM is not set
-# CONFIG_VLAN_8021Q is not set
-
-#
-#  
-#
-# CONFIG_IPX is not set
-CONFIG_ATALK=m
-
-#
-# Appletalk devices
-#
-# CONFIG_DEV_APPLETALK is not set
-# CONFIG_DECNET is not set
-# CONFIG_BRIDGE is not set
-# 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 is not set
-
-#
-# Network testing
-#
-# CONFIG_NET_PKTGEN is not set
-
-#
-# ATA/IDE/MFM/RLL support
-#
-CONFIG_IDE=y
-
-#
-# IDE, ATA and ATAPI Block devices
-#
-CONFIG_BLK_DEV_IDE=y
-
-#
-# Please see Documentation/ide.txt for help/info on IDE drives
-#
-# CONFIG_BLK_DEV_HD_IDE is not set
-# CONFIG_BLK_DEV_HD is not set
-CONFIG_BLK_DEV_IDEDISK=y
-# CONFIG_IDEDISK_MULTI_MODE is not set
-# CONFIG_IDEDISK_STROKE is not set
-# CONFIG_BLK_DEV_IDECS is not set
-CONFIG_BLK_DEV_IDECD=y
-# CONFIG_BLK_DEV_IDETAPE is not set
-CONFIG_BLK_DEV_IDEFLOPPY=y
-CONFIG_BLK_DEV_IDESCSI=y
-# CONFIG_IDE_TASK_IOCTL is not set
-
-#
-# IDE chipset support/bugfixes
-#
-# CONFIG_BLK_DEV_CMD640 is not set
-# CONFIG_BLK_DEV_CMD640_ENHANCED is not set
-# CONFIG_BLK_DEV_ISAPNP is not set
-CONFIG_BLK_DEV_IDEPCI=y
-CONFIG_BLK_DEV_GENERIC=y
-CONFIG_IDEPCI_SHARE_IRQ=y
-CONFIG_BLK_DEV_IDEDMA_PCI=y
-# CONFIG_BLK_DEV_OFFBOARD is not set
-# CONFIG_BLK_DEV_IDEDMA_FORCED is not set
-CONFIG_IDEDMA_PCI_AUTO=y
-# CONFIG_IDEDMA_ONLYDISK is not set
-CONFIG_BLK_DEV_IDEDMA=y
-# CONFIG_IDEDMA_PCI_WIP is not set
-# CONFIG_BLK_DEV_ADMA100 is not set
-# CONFIG_BLK_DEV_AEC62XX is not set
-# CONFIG_BLK_DEV_ALI15X3 is not set
-# CONFIG_WDC_ALI15X3 is not set
-# CONFIG_BLK_DEV_AMD74XX is not set
-# CONFIG_AMD74XX_OVERRIDE is not set
-CONFIG_BLK_DEV_CMD64X=y
-# CONFIG_BLK_DEV_TRIFLEX is not set
-# CONFIG_BLK_DEV_CY82C693 is not set
-# CONFIG_BLK_DEV_CS5530 is not set
-# CONFIG_BLK_DEV_HPT34X is not set
-# CONFIG_HPT34X_AUTODMA is not set
-# CONFIG_BLK_DEV_HPT366 is not set
-# CONFIG_BLK_DEV_PIIX is not set
-# CONFIG_BLK_DEV_NS87415 is not set
-# CONFIG_BLK_DEV_OPTI621 is not set
-# CONFIG_BLK_DEV_PDC202XX_OLD is not set
-# CONFIG_PDC202XX_BURST is not set
-# CONFIG_BLK_DEV_PDC202XX_NEW is not set
-# CONFIG_BLK_DEV_RZ1000 is not set
-# CONFIG_BLK_DEV_SC1200 is not set
-# CONFIG_BLK_DEV_SVWKS is not set
-# CONFIG_BLK_DEV_SIIMAGE is not set
-# CONFIG_BLK_DEV_SIS5513 is not set
-# CONFIG_BLK_DEV_SLC90E66 is not set
-# CONFIG_BLK_DEV_TRM290 is not set
-# CONFIG_BLK_DEV_VIA82CXXX is not set
-CONFIG_BLK_DEV_SL82C105=y
-CONFIG_BLK_DEV_IDE_PMAC=y
-# CONFIG_BLK_DEV_IDE_PMAC_ATA100FIRST is not set
-CONFIG_BLK_DEV_IDEDMA_PMAC=y
-CONFIG_BLK_DEV_IDEDMA_PMAC_AUTO=y
-CONFIG_BLK_DEV_IDEDMA=y
-CONFIG_BLK_DEV_IDEPCI=y
-# CONFIG_IDE_CHIPSETS is not set
-CONFIG_IDEDMA_AUTO=y
-# CONFIG_IDEDMA_IVB is not set
-# CONFIG_DMA_NONPCI is not set
-# CONFIG_BLK_DEV_ATARAID is not set
-# CONFIG_BLK_DEV_ATARAID_PDC is not set
-# CONFIG_BLK_DEV_ATARAID_HPT is not set
-# CONFIG_BLK_DEV_ATARAID_SII is not set
-
-#
-# SCSI support
-#
-CONFIG_SCSI=y
-
-#
-# SCSI support type (disk, tape, CD-ROM)
-#
-CONFIG_BLK_DEV_SD=y
-CONFIG_SD_EXTRA_DEVS=40
-CONFIG_CHR_DEV_ST=y
-# CONFIG_CHR_DEV_OSST is not set
-CONFIG_BLK_DEV_SR=y
-CONFIG_BLK_DEV_SR_VENDOR=y
-CONFIG_SR_EXTRA_DEVS=2
-CONFIG_CHR_DEV_SG=y
-
-#
-# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
-#
-# CONFIG_SCSI_DEBUG_QUEUES is not set
-# CONFIG_SCSI_MULTI_LUN is not set
-CONFIG_SCSI_CONSTANTS=y
-# 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=m
-CONFIG_AIC7XXX_CMDS_PER_DEVICE=253
-CONFIG_AIC7XXX_RESET_DELAY_MS=15000
-# CONFIG_AIC7XXX_PROBE_EISA_VL is not set
-# CONFIG_AIC7XXX_BUILD_FIRMWARE is not set
-# CONFIG_AIC7XXX_DEBUG_ENABLE is not set
-CONFIG_AIC7XXX_DEBUG_MASK=0
-# CONFIG_AIC7XXX_REG_PRETTY_PRINT is not set
-# CONFIG_SCSI_AIC79XX is not set
-CONFIG_SCSI_AIC7XXX_OLD=m
-# CONFIG_AIC7XXX_OLD_TCQ_ON_BY_DEFAULT is not set
-CONFIG_AIC7XXX_OLD_CMDS_PER_DEVICE=8
-CONFIG_AIC7XXX_OLD_PROC_STATS=y
-# CONFIG_SCSI_DPT_I2O is not set
-CONFIG_SCSI_ADVANSYS=m
-# CONFIG_SCSI_IN2000 is not set
-# CONFIG_SCSI_AM53C974 is not set
-# CONFIG_SCSI_MEGARAID 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=y
-CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=0
-CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS=16
-CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64
-# CONFIG_SCSI_SYM53C8XX_IOMAPPED 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
-CONFIG_SCSI_MESH=y
-CONFIG_SCSI_MESH_SYNC_RATE=5
-CONFIG_SCSI_MESH_RESET_DELAY_MS=4000
-CONFIG_SCSI_MAC53C94=y
-
-#
-# 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 is not set
-# CONFIG_BONDING is not set
-# CONFIG_EQUALIZER is not set
-# CONFIG_TUN is not set
-# CONFIG_ETHERTAP is not set
-
-#
-# Ethernet (10 or 100Mbit)
-#
-CONFIG_NET_ETHERNET=y
-CONFIG_MACE=y
-# CONFIG_MACE_AAUI_PORT is not set
-CONFIG_BMAC=y
-CONFIG_GMAC=y
-# 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=y
-CONFIG_PCNET32=y
-# CONFIG_AMD8111_ETH is not set
-# CONFIG_ADAPTEC_STARFIRE is not set
-# CONFIG_APRICOT is not set
-# CONFIG_CS89x0 is not set
-CONFIG_TULIP=y
-# CONFIG_TULIP_MWI is not set
-CONFIG_TULIP_MMIO=y
-CONFIG_DE4X5=m
-# CONFIG_DGRS is not set
-# CONFIG_DM9102 is not set
-# CONFIG_EEPRO100 is not set
-# CONFIG_EEPRO100_PIO is not set
-# CONFIG_E100 is not set
-# CONFIG_LNE390 is not set
-# CONFIG_FEALNX is not set
-# CONFIG_NATSEMI is not set
-# CONFIG_NE2K_PCI is not set
-# CONFIG_NE3210 is not set
-# CONFIG_ES3210 is not set
-# CONFIG_8139CP is not set
-# CONFIG_8139TOO is not set
-# CONFIG_8139TOO_PIO is not set
-# CONFIG_8139TOO_TUNE_TWISTER is not set
-# CONFIG_8139TOO_8129 is not set
-# CONFIG_8139_OLD_RX_RESET is not set
-# CONFIG_SIS900 is not set
-# CONFIG_EPIC100 is not set
-# CONFIG_SUNDANCE is not set
-# CONFIG_SUNDANCE_MMIO is not set
-# CONFIG_TLAN is not set
-# CONFIG_TC35815 is not set
-# CONFIG_VIA_RHINE is not set
-# CONFIG_VIA_RHINE_MMIO is not set
-# CONFIG_WINBOND_840 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 is not set
-CONFIG_PPP_ASYNC=y
-# CONFIG_PPP_SYNC_TTY is not set
-CONFIG_PPP_DEFLATE=y
-# CONFIG_PPP_BSDCOMP is not set
-# CONFIG_PPPOE is not set
-# 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 is not set
-# CONFIG_AIRONET4500_NONCS is not set
-# CONFIG_AIRONET4500_PROC is not set
-# CONFIG_AIRO is not set
-CONFIG_HERMES=m
-CONFIG_APPLE_AIRPORT=m
-# CONFIG_PLX_HERMES is not set
-# CONFIG_PCI_HERMES 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 is not set
-
-#
-# Wan interfaces
-#
-# CONFIG_WAN 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
-
-#
-# Old CD-ROM drivers (not SCSI, not IDE)
-#
-# CONFIG_CD_NO_IDESCSI is not set
-
-#
-# Console drivers
-#
-CONFIG_VGA_CONSOLE=y
-
-#
-# Frame-buffer support
-#
-CONFIG_FB=y
-CONFIG_DUMMY_CONSOLE=y
-# CONFIG_FB_RIVA is not set
-# CONFIG_FB_CLGEN is not set
-# CONFIG_FB_PM2 is not set
-# CONFIG_FB_PM3 is not set
-# CONFIG_FB_CYBER2000 is not set
-CONFIG_FB_OF=y
-CONFIG_FB_CONTROL=y
-CONFIG_FB_PLATINUM=y
-CONFIG_FB_VALKYRIE=y
-CONFIG_FB_CT65550=y
-CONFIG_FB_IMSTT=y
-# CONFIG_FB_S3TRIO is not set
-# CONFIG_FB_VESA is not set
-# CONFIG_FB_VGA16 is not set
-# CONFIG_FB_LYNX is not set
-CONFIG_FB_MATROX=y
-CONFIG_FB_MATROX_MILLENIUM=y
-CONFIG_FB_MATROX_MYSTIQUE=y
-# CONFIG_FB_MATROX_G450 is not set
-CONFIG_FB_MATROX_G100A=y
-CONFIG_FB_MATROX_G100=y
-# CONFIG_FB_MATROX_I2C is not set
-# CONFIG_FB_MATROX_MAVEN is not set
-# CONFIG_FB_MATROX_PROC is not set
-# CONFIG_FB_MATROX_MULTIHEAD is not set
-CONFIG_FB_ATY=y
-CONFIG_FB_ATY_GX=y
-CONFIG_FB_ATY_CT=y
-CONFIG_FB_RADEON=y
-CONFIG_FB_ATY128=y
-# CONFIG_FB_INTEL is not set
-# CONFIG_FB_SIS is not set
-# CONFIG_FB_NEOMAGIC is not set
-CONFIG_FB_3DFX=y
-# CONFIG_FB_VOODOO1 is not set
-# CONFIG_FB_TRIDENT is not set
-# CONFIG_FB_VIRTUAL is not set
-# CONFIG_FBCON_ADVANCED is not set
-CONFIG_FBCON_CFB8=y
-CONFIG_FBCON_CFB16=y
-CONFIG_FBCON_CFB24=y
-CONFIG_FBCON_CFB32=y
-# CONFIG_FBCON_FONTWIDTH8_ONLY is not set
-CONFIG_FBCON_FONTS=y
-# CONFIG_FONT_8x8 is not set
-CONFIG_FONT_8x16=y
-CONFIG_FONT_SUN8x16=y
-CONFIG_FONT_SUN12x22=y
-# CONFIG_FONT_6x11 is not set
-# CONFIG_FONT_PEARL_8x8 is not set
-# CONFIG_FONT_ACORN_8x8 is not set
-# CONFIG_FB_COMPAT_XPMAC is not set
-
-#
-# Input core support
-#
-CONFIG_INPUT=y
-CONFIG_INPUT_KEYBDEV=y
-CONFIG_INPUT_MOUSEDEV=y
-CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
-CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
-# CONFIG_INPUT_JOYDEV is not set
-CONFIG_INPUT_EVDEV=y
-
-#
-# Macintosh device drivers
-#
-CONFIG_ADB_CUDA=y
-CONFIG_ADB_PMU=y
-CONFIG_PMAC_PBOOK=y
-CONFIG_PM=y
-CONFIG_PMAC_APM_EMU=y
-CONFIG_PMAC_BACKLIGHT=y
-# CONFIG_MAC_FLOPPY is not set
-CONFIG_MAC_SERIAL=m
-CONFIG_ADB=y
-CONFIG_ADB_MACIO=y
-CONFIG_INPUT_ADBHID=y
-CONFIG_MAC_ADBKEYCODES=y
-CONFIG_MAC_EMUMOUSEBTN=y
-CONFIG_MAC_HID=y
-# CONFIG_ANSLCD is not set
-
-#
-# Character devices
-#
-CONFIG_VT=y
-CONFIG_VT_CONSOLE=y
-CONFIG_SERIAL=m
-# CONFIG_SERIAL_EXTENDED is not set
-# CONFIG_SERIAL_NONSTANDARD is not set
-CONFIG_UNIX98_PTYS=y
-CONFIG_UNIX98_PTY_COUNT=256
-# CONFIG_BRIQ_PANEL is not set
-
-#
-# I2C support
-#
-CONFIG_I2C=m
-# CONFIG_I2C_ALGOBIT is not set
-# CONFIG_I2C_ALGOPCF is not set
-CONFIG_I2C_KEYWEST=m
-CONFIG_I2C_CHARDEV=m
-CONFIG_I2C_PROC=m
-
-#
-# Mice
-#
-CONFIG_BUSMOUSE=y
-# CONFIG_ATIXL_BUSMOUSE is not set
-# CONFIG_LOGIBUSMOUSE is not set
-# CONFIG_MS_BUSMOUSE is not set
-CONFIG_MOUSE=y
-CONFIG_PSMOUSE=y
-# CONFIG_82C710_MOUSE is not set
-# CONFIG_PC110_PAD is not set
-# CONFIG_MK712_MOUSE is not set
-
-#
-# Joysticks
-#
-# CONFIG_INPUT_GAMEPORT is not set
-# CONFIG_INPUT_NS558 is not set
-# CONFIG_INPUT_LIGHTNING is not set
-# CONFIG_INPUT_PCIGAME is not set
-# CONFIG_INPUT_CS461X is not set
-# CONFIG_INPUT_EMU10K1 is not set
-# CONFIG_INPUT_SERIO is not set
-# CONFIG_INPUT_SERPORT is not set
-
-#
-# Joysticks
-#
-# CONFIG_INPUT_ANALOG is not set
-# CONFIG_INPUT_A3D is not set
-# CONFIG_INPUT_ADI is not set
-# CONFIG_INPUT_COBRA is not set
-# CONFIG_INPUT_GF2K is not set
-# CONFIG_INPUT_GRIP is not set
-# CONFIG_INPUT_INTERACT is not set
-# CONFIG_INPUT_TMDC is not set
-# CONFIG_INPUT_SIDEWINDER is not set
-# CONFIG_INPUT_IFORCE_USB is not set
-# CONFIG_INPUT_IFORCE_232 is not set
-# CONFIG_INPUT_WARRIOR is not set
-# CONFIG_INPUT_MAGELLAN is not set
-# CONFIG_INPUT_SPACEORB is not set
-# CONFIG_INPUT_SPACEBALL is not set
-# CONFIG_INPUT_STINGER is not set
-# CONFIG_INPUT_DB9 is not set
-# CONFIG_INPUT_GAMECON is not set
-# CONFIG_INPUT_TURBOGRAFX 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_GPIO is not set
-# CONFIG_AMD_PM768 is not set
-CONFIG_NVRAM=y
-# 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
-# CONFIG_DRM is not set
-
-#
-# Multimedia devices
-#
-# CONFIG_VIDEO_DEV is not set
-
-#
-# File systems
-#
-# CONFIG_QUOTA is not set
-# CONFIG_AUTOFS_FS is not set
-# CONFIG_AUTOFS4_FS is not set
-# CONFIG_REISERFS_FS is not set
-# 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=m
-# CONFIG_BEFS_FS is not set
-# CONFIG_BEFS_DEBUG is not set
-# CONFIG_BFS_FS is not set
-# CONFIG_EXT3_FS is not set
-# CONFIG_JBD is not set
-# 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 is not set
-# CONFIG_CRAMFS is not set
-CONFIG_TMPFS=y
-CONFIG_RAMFS=y
-CONFIG_ISO9660_FS=y
-# CONFIG_JOLIET is not set
-# CONFIG_ZISOFS is not set
-# 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 is not set
-# CONFIG_NTFS_RW is not set
-# CONFIG_HPFS_FS is not set
-CONFIG_PROC_FS=y
-CONFIG_DEVFS_FS=y
-# CONFIG_DEVFS_MOUNT is not set
-# 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=y
-# 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
-
-#
-# Network File Systems
-#
-# CONFIG_CODA_FS is not set
-# CONFIG_INTERMEZZO_FS is not set
-CONFIG_NFS_FS=y
-CONFIG_NFS_V3=y
-# CONFIG_ROOT_NFS is not set
-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 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 is not set
-
-#
-# Partition Types
-#
-CONFIG_PARTITION_ADVANCED=y
-# CONFIG_ACORN_PARTITION is not set
-# CONFIG_OSF_PARTITION is not set
-# CONFIG_AMIGA_PARTITION is not set
-# CONFIG_ATARI_PARTITION is not set
-CONFIG_MAC_PARTITION=y
-CONFIG_MSDOS_PARTITION=y
-# CONFIG_BSD_DISKLABEL is not set
-# CONFIG_MINIX_SUBPARTITION is not set
-# CONFIG_SOLARIS_X86_PARTITION is not set
-# CONFIG_UNIXWARE_DISKLABEL is not set
-# CONFIG_LDM_PARTITION is not set
-# CONFIG_SGI_PARTITION is not set
-# CONFIG_ULTRIX_PARTITION is not set
-# CONFIG_SUN_PARTITION is not set
-# CONFIG_EFI_PARTITION is not set
-# CONFIG_SMB_NLS is not set
-CONFIG_NLS=y
-
-#
-# Native Language Support
-#
-CONFIG_NLS_DEFAULT="iso8859-1"
-# CONFIG_NLS_CODEPAGE_437 is not set
-# CONFIG_NLS_CODEPAGE_737 is not set
-# CONFIG_NLS_CODEPAGE_775 is not set
-# CONFIG_NLS_CODEPAGE_850 is not set
-# 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 is not set
-# CONFIG_NLS_KOI8_R is not set
-# CONFIG_NLS_KOI8_U is not set
-# CONFIG_NLS_UTF8 is not set
-
-#
-# Sound
-#
-CONFIG_SOUND=m
-CONFIG_DMASOUND_PMAC=m
-CONFIG_DMASOUND=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_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 is not set
-# CONFIG_SOUND_TVMIXER is not set
-
-#
-# USB support
-#
-CONFIG_USB=y
-# CONFIG_USB_DEBUG is not set
-
-#
-# Miscellaneous USB options
-#
-CONFIG_USB_DEVICEFS=y
-# CONFIG_USB_BANDWIDTH is not set
-
-#
-# USB Host Controller Drivers
-#
-# CONFIG_USB_EHCI_HCD is not set
-# CONFIG_USB_UHCI is not set
-# CONFIG_USB_UHCI_ALT is not set
-CONFIG_USB_OHCI=y
-
-#
-# USB Device Class drivers
-#
-# CONFIG_USB_AUDIO is not set
-# CONFIG_USB_EMI26 is not set
-# CONFIG_USB_BLUETOOTH is not set
-# CONFIG_USB_MIDI is not set
-CONFIG_USB_STORAGE=m
-# CONFIG_USB_STORAGE_DEBUG is not set
-# CONFIG_USB_STORAGE_DATAFAB is not set
-CONFIG_USB_STORAGE_FREECOM=y
-# CONFIG_USB_STORAGE_ISD200 is not set
-CONFIG_USB_STORAGE_DPCM=y
-# CONFIG_USB_STORAGE_HP8200e is not set
-# CONFIG_USB_STORAGE_SDDR09 is not set
-# CONFIG_USB_STORAGE_SDDR55 is not set
-# CONFIG_USB_STORAGE_JUMPSHOT is not set
-CONFIG_USB_ACM=m
-CONFIG_USB_PRINTER=m
-
-#
-# USB Human Interface Devices (HID)
-#
-CONFIG_USB_HID=y
-CONFIG_USB_HIDINPUT=y
-# CONFIG_USB_HIDDEV 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
-
-#
-# USB Imaging devices
-#
-# CONFIG_USB_DC2XX is not set
-# CONFIG_USB_MDC800 is not set
-CONFIG_USB_SCANNER=m
-# CONFIG_USB_MICROTEK is not set
-# CONFIG_USB_HPUSBSCSI is not set
-
-#
-# USB Multimedia devices
-#
-
-#
-#   Video4Linux support is needed for USB Multimedia device support
-#
-
-#
-# USB Network adaptors
-#
-# CONFIG_USB_PEGASUS is not set
-# CONFIG_USB_RTL8150 is not set
-# CONFIG_USB_KAWETH is not set
-# CONFIG_USB_CATC is not set
-# CONFIG_USB_AX8817X is not set
-# CONFIG_USB_CDCETHER is not set
-# CONFIG_USB_USBNET is not set
-
-#
-# USB port drivers
-#
-# 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 is not set
-# CONFIG_USB_SERIAL_BELKIN is not set
-# CONFIG_USB_SERIAL_WHITEHEAT is not set
-# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set
-# CONFIG_USB_SERIAL_EMPEG is not set
-# CONFIG_USB_SERIAL_FTDI_SIO is not set
-CONFIG_USB_SERIAL_VISOR=m
-# CONFIG_USB_SERIAL_IPAQ is not set
-# CONFIG_USB_SERIAL_IR is not set
-# CONFIG_USB_SERIAL_EDGEPORT is not set
-# CONFIG_USB_SERIAL_EDGEPORT_TI is not set
-# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
-CONFIG_USB_SERIAL_KEYSPAN=m
-CONFIG_USB_SERIAL_KEYSPAN_USA28=y
-CONFIG_USB_SERIAL_KEYSPAN_USA28X=y
-# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set
-CONFIG_USB_SERIAL_KEYSPAN_USA19=y
-CONFIG_USB_SERIAL_KEYSPAN_USA18X=y
-CONFIG_USB_SERIAL_KEYSPAN_USA19W=y
-# CONFIG_USB_SERIAL_KEYSPAN_USA19QW is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA19QI is not set
-# CONFIG_USB_SERIAL_KEYSPAN_MPR is not set
-CONFIG_USB_SERIAL_KEYSPAN_USA49W=y
-# CONFIG_USB_SERIAL_KEYSPAN_USA49WLC is not set
-# CONFIG_USB_SERIAL_MCT_U232 is not set
-# CONFIG_USB_SERIAL_KLSI is not set
-# CONFIG_USB_SERIAL_KOBIL_SCT is not set
-# CONFIG_USB_SERIAL_PL2303 is not set
-# CONFIG_USB_SERIAL_CYBERJACK is not set
-# CONFIG_USB_SERIAL_XIRCOM is not set
-# CONFIG_USB_SERIAL_OMNINET is not set
-
-#
-# USB Miscellaneous drivers
-#
-# CONFIG_USB_RIO500 is not set
-# CONFIG_USB_AUERSWALD is not set
-# CONFIG_USB_TIGL is not set
-# CONFIG_USB_BRLVGER is not set
-# CONFIG_USB_LCD is not set
-# CONFIG_USB_SPEEDTOUCH is not set
-
-#
-# Bluetooth support
-#
-# CONFIG_BLUEZ is not set
-
-#
-# Library routines
-#
-# CONFIG_CRC32 is not set
-CONFIG_ZLIB_INFLATE=y
-CONFIG_ZLIB_DEFLATE=y
-
-#
-# Kernel hacking
-#
-# CONFIG_DEBUG_KERNEL is not set
-CONFIG_BOOTX_TEXT=y
Index: pplinux/linuxnew/arch/ppc/boot/Makefile
diff -u pplinux/linuxnew/arch/ppc/boot/Makefile:1.1.323.1 pplinux/linuxnew/arch/ppc/boot/Makefile:1.2
--- pplinux/linuxnew/arch/ppc/boot/Makefile:1.1.323.1	Thu Feb  3 10:00:25 2005
+++ pplinux/linuxnew/arch/ppc/boot/Makefile	Thu Feb  3 11:35:37 2005
@@ -17,7 +17,8 @@
 AFLAGS	+= -D__BOOTER__
 OBJCOPY_ARGS = -O elf32-powerpc
 
-MKIMAGE				:= $(TOPDIR)/scripts/mkuboot.sh
+#MKIMAGE				:= $(TOPDIR)/scripts/mkuboot.sh
+MKIMAGE				:= $(TOPDIR)/../u-boot/tools/mkimage
 
 lib/zlib.a: lib/zlib.c
 	$(MAKE) -C lib
@@ -25,9 +26,12 @@
 images/vmlinux.gz: $(TOPDIR)/vmlinux
 	$(MAKE) -C images vmlinux.gz
 
+images/vmlinux.bz2: $(TOPDIR)/vmlinux
+	$(MAKE) -C images vmlinux.bz2
+
 # Subdirs and tools needed for each.  Assume we always need to go into
 # 'simple' unless told otherwise.
-subdir-y			:= lib common simple
+subdir-y			:= lib common
 subdir-$(CONFIG_ALL_PPC)	:= chrp pmac prep
 tools-$(CONFIG_ALL_PPC)		:= addnote mknote hack-coff mkprep
 tools-$(CONFIG_4xx)		:= mktree
@@ -66,13 +70,11 @@
 endif
 
 # Make an image for PPCBoot / U-Boot.
-uImage: $(MKIMAGE) images/vmlinux.gz
-	$(CONFIG_SHELL) $(MKIMAGE) -A ppc -O linux -T kernel \
-	-C gzip -a 00000000 -e 00000000 \
+uImage: images/vmlinux.bz2
+	$(MKIMAGE) -A ppc -O linux -T kernel -C bzip2 -a 00000000 -e 00000000 \
 	-n 'Linux-$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)' \
-	-d images/vmlinux.gz images/vmlinux.UBoot
+	-d images/vmlinux.bz2 images/vmlinux.UBoot
 	ln -sf vmlinux.UBoot images/uImage
-	rm -f ./mkuboot
 
 # These are subdirs with files not normally rm'ed. -- Tom
 clean:
Index: pplinux/linuxnew/arch/ppc/boot/images/Makefile
diff -u pplinux/linuxnew/arch/ppc/boot/images/Makefile:1.1.323.1 pplinux/linuxnew/arch/ppc/boot/images/Makefile:1.2
--- pplinux/linuxnew/arch/ppc/boot/images/Makefile:1.1.323.1	Thu Feb  3 10:00:25 2005
+++ pplinux/linuxnew/arch/ppc/boot/images/Makefile	Thu Feb  3 11:35:37 2005
@@ -4,9 +4,14 @@
 
 include $(TOPDIR)/Rules.make
 
-vmlinux.gz: $(TOPDIR)/vmlinux
-	$(OBJCOPY) --strip-all -S -O binary $(TOPDIR)/vmlinux vmlinux
+vmlinux.gz: vmlinux
 	gzip -vf9 vmlinux
 
+vmlinux.bz2: vmlinux
+	bzip2 -vf9 vmlinux
+
+vmlinux: $(TOPDIR)/vmlinux
+	$(OBJCOPY) --strip-all -S -O binary $(TOPDIR)/vmlinux vmlinux
+
 clean:
 	rm -f sImage vmapus vmlinux* miboot* zImage* zvmlinux* uImage
Index: pplinux/linuxnew/arch/ppc/configs/lara_kim16_defconfig
diff -u /dev/null pplinux/linuxnew/arch/ppc/configs/lara_kim16_defconfig:1.1
--- /dev/null	Tue May 24 10:37:58 2005
+++ pplinux/linuxnew/arch/ppc/configs/lara_kim16_defconfig	Tue Feb 15 12:16:24 2005
@@ -0,0 +1,869 @@
+#
+# Automatically generated make config: don't edit
+#
+# CONFIG_UID16 is not set
+# CONFIG_RWSEM_GENERIC_SPINLOCK is not set
+CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_HAVE_DEC_LOCK=y
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_ADVANCED_OPTIONS=y
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+CONFIG_MODVERSIONS=y
+# CONFIG_KMOD is not set
+
+#
+# Platform support
+#
+CONFIG_PPC=y
+CONFIG_PPC32=y
+# CONFIG_6xx is not set
+CONFIG_40x=y
+# CONFIG_44x is not set
+# CONFIG_POWER3 is not set
+# CONFIG_POWER4 is not set
+# CONFIG_8xx is not set
+CONFIG_4xx=y
+# CONFIG_PPC_STD_MMU is not set
+# CONFIG_ARCTIC2 is not set
+# CONFIG_ASH is not set
+# CONFIG_CEDER is not set
+# CONFIG_BEECH is not set
+# CONFIG_CPCI405 is not set
+# CONFIG_EP405 is not set
+# CONFIG_EVB405EP is not set
+# CONFIG_OAK is not set
+# CONFIG_RAINIER is not set
+# CONFIG_REDWOOD_4 is not set
+# CONFIG_REDWOOD_5 is not set
+# CONFIG_REDWOOD_6 is not set
+# CONFIG_SYCAMORE is not set
+# CONFIG_TIVO is not set
+# CONFIG_WALNUT is not set
+# CONFIG_PEPPERCON_405GP is not set
+CONFIG_PEPPERCON_405EP=y
+# CONFIG_XILINX_ML300 is not set
+# CONFIG_ALL_PPC is not set
+# CONFIG_SMP is not set
+# CONFIG_MATH_EMULATION is not set
+CONFIG_BIGPHYS_AREA=y
+CONFIG_NOT_COHERENT_CACHE=y
+CONFIG_UART0_TTYS0=y
+# CONFIG_UART0_TTYS1 is not set
+# CONFIG_PM is not set
+CONFIG_PEPPERCON=y
+CONFIG_405EP=y
+CONFIG_IBM_OCP=y
+CONFIG_PPC_OCP=y
+CONFIG_GEN550=y
+CONFIG_405=y
+CONFIG_IBM405_ERR51=y
+CONFIG_IBM405_ERR77=y
+CONFIG_PPC4xx_DMA=y
+CONFIG_PPC4xx_EDMA=y
+CONFIG_OCP_PROC=y
+
+#
+# General setup
+#
+# CONFIG_HIGHMEM is not set
+# CONFIG_LOWMEM_SIZE_BOOL is not set
+# CONFIG_KERNEL_START_BOOL is not set
+# CONFIG_TASK_SIZE_BOOL is not set
+# CONFIG_PIN_TLB is not set
+CONFIG_HIGHMEM_START=0xfe000000
+CONFIG_LOWMEM_SIZE=0x30000000
+CONFIG_KERNEL_START=0xc0000000
+CONFIG_TASK_SIZE=0x80000000
+# CONFIG_ISA is not set
+# CONFIG_EISA is not set
+# CONFIG_SBUS is not set
+# CONFIG_MCA is not set
+CONFIG_PCI=y
+# CONFIG_8260_PCI9 is not set
+# CONFIG_PC_KEYBOARD is not set
+CONFIG_NET=y
+CONFIG_SYSCTL=y
+CONFIG_SYSVIPC=y
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_KCORE_ELF=y
+CONFIG_BINFMT_ELF=y
+CONFIG_KERNEL_ELF=y
+# CONFIG_BINFMT_MISC is not set
+# CONFIG_OOM_KILLER is not set
+# CONFIG_PCI_NAMES is not set
+# CONFIG_HOTPLUG is not set
+# CONFIG_PCMCIA is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+# CONFIG_GEN_RTC is not set
+# CONFIG_PPC_RTC is not set
+CONFIG_CMDLINE_BOOL=y
+CONFIG_CMDLINE="console=ttyS0,115200 root=/dev/nfs nfsroot=192.168.1.24:/eric_root_devel.miba ip=192.168.1.20:192.168.1.24"
+
+#
+# Memory Technology Devices (MTD)
+#
+CONFIG_MTD=m
+# CONFIG_MTD_DEBUG is not set
+CONFIG_MTD_PARTITIONS=m
+# CONFIG_MTD_CONCAT is not set
+# CONFIG_MTD_REDBOOT_PARTS is not set
+CONFIG_MTD_CMDLINE_PARTS=m
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=m
+CONFIG_MTD_BLOCK=m
+# CONFIG_MTD_BLOCK_RO is not set
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+CONFIG_MTD_CFI=m
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_GEN_PROBE=m
+CONFIG_MTD_CFI_ADV_OPTIONS=y
+CONFIG_MTD_CFI_NOSWAP=y
+# CONFIG_MTD_CFI_BE_BYTE_SWAP is not set
+# CONFIG_MTD_CFI_LE_BYTE_SWAP is not set
+CONFIG_MTD_CFI_GEOMETRY=y
+# CONFIG_MTD_CFI_B1 is not set
+CONFIG_MTD_CFI_B2=y
+# CONFIG_MTD_CFI_B4 is not set
+# CONFIG_MTD_CFI_B8 is not set
+CONFIG_MTD_CFI_I1=y
+# CONFIG_MTD_CFI_I2 is not set
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+CONFIG_MTD_CFI_INTELEXT=m
+# CONFIG_MTD_CFI_AMDSTD is not set
+# CONFIG_MTD_CFI_STAA is not set
+# CONFIG_MTD_RAM is not set
+CONFIG_MTD_ROM=m
+# 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_PHYSMAP=m
+CONFIG_MTD_PHYSMAP_BUSWIDTH=2
+# CONFIG_MTD_BEECH is not set
+# CONFIG_MTD_ARCTIC 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
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC1000 is not set
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOCPROBE is not set
+
+#
+# NAND Flash Device Drivers
+#
+# CONFIG_MTD_NAND 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_LOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=8192
+CONFIG_BLK_DEV_INITRD=y
+# 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 is not set
+CONFIG_NETFILTER=y
+# CONFIG_NETFILTER_DEBUG is not set
+# CONFIG_FILTER is not set
+CONFIG_UNIX=y
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_PNP=y
+# CONFIG_IP_PNP_DHCP is not set
+CONFIG_IP_PNP_BOOTP=y
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_IP_MROUTE is not set
+# CONFIG_ARPD is not set
+# CONFIG_INET_ECN is not set
+# CONFIG_SYN_COOKIES is not set
+
+#
+#   IP: Netfilter Configuration
+#
+CONFIG_IP_NF_CONNTRACK=y
+# CONFIG_IP_NF_FTP is not set
+# CONFIG_IP_NF_AMANDA is not set
+# CONFIG_IP_NF_TFTP is not set
+# CONFIG_IP_NF_IRC is not set
+CONFIG_IP_NF_QUEUE=y
+CONFIG_IP_NF_IPTABLES=y
+# CONFIG_IP_NF_MATCH_LIMIT is not set
+CONFIG_IP_NF_MATCH_MAC=y
+# CONFIG_IP_NF_MATCH_PKTTYPE is not set
+CONFIG_IP_NF_MATCH_MARK=y
+# CONFIG_IP_NF_MATCH_MULTIPORT is not set
+# CONFIG_IP_NF_MATCH_TOS is not set
+# CONFIG_IP_NF_MATCH_RECENT is not set
+# CONFIG_IP_NF_MATCH_ECN is not set
+# CONFIG_IP_NF_MATCH_DSCP is not set
+# CONFIG_IP_NF_MATCH_AH_ESP is not set
+# CONFIG_IP_NF_MATCH_LENGTH is not set
+# CONFIG_IP_NF_MATCH_TTL is not set
+# CONFIG_IP_NF_MATCH_TCPMSS is not set
+# CONFIG_IP_NF_MATCH_HELPER is not set
+# CONFIG_IP_NF_MATCH_STATE is not set
+# CONFIG_IP_NF_MATCH_CONNTRACK is not set
+# CONFIG_IP_NF_MATCH_UNCLEAN is not set
+# CONFIG_IP_NF_MATCH_OWNER is not set
+CONFIG_IP_NF_FILTER=y
+CONFIG_IP_NF_TARGET_REJECT=y
+# CONFIG_IP_NF_TARGET_MIRROR is not set
+CONFIG_IP_NF_FASTNAT=y
+CONFIG_IP_NF_TARGET_FASTNAT=y
+CONFIG_IP_NF_NAT=y
+CONFIG_IP_NF_NAT_NEEDED=y
+# CONFIG_IP_NF_TARGET_MASQUERADE is not set
+CONFIG_IP_NF_TARGET_REDIRECT=y
+CONFIG_IP_NF_NAT_LOCAL=y
+# CONFIG_IP_NF_NAT_SNMP_BASIC is not set
+CONFIG_IP_NF_MANGLE=y
+# CONFIG_IP_NF_TARGET_TOS is not set
+# CONFIG_IP_NF_TARGET_ECN is not set
+# CONFIG_IP_NF_TARGET_DSCP is not set
+CONFIG_IP_NF_TARGET_MARK=y
+# CONFIG_IP_NF_TARGET_LOG is not set
+# CONFIG_IP_NF_TARGET_ULOG is not set
+# CONFIG_IP_NF_TARGET_TCPMSS is not set
+# CONFIG_IP_NF_ARPTABLES is not set
+
+#
+#   IP: Virtual Server Configuration
+#
+CONFIG_IP_VS=y
+# CONFIG_IP_VS_DEBUG is not set
+CONFIG_IP_VS_TAB_BITS=12
+
+#
+# IPVS scheduler
+#
+CONFIG_IP_VS_RR=y
+CONFIG_IP_VS_WRR=y
+CONFIG_IP_VS_LC=y
+CONFIG_IP_VS_WLC=y
+CONFIG_IP_VS_LBLC=y
+CONFIG_IP_VS_LBLCR=y
+CONFIG_IP_VS_DH=y
+CONFIG_IP_VS_SH=y
+CONFIG_IP_VS_SED=y
+CONFIG_IP_VS_NQ=y
+
+#
+# IPVS application helper
+#
+# CONFIG_IP_VS_FTP is not set
+CONFIG_IPV6=y
+
+#
+#   IPv6: Netfilter Configuration
+#
+# CONFIG_IP6_NF_QUEUE is not set
+# CONFIG_IP6_NF_IPTABLES is not set
+# CONFIG_KHTTPD is not set
+
+#
+#    SCTP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_SCTP is not set
+# CONFIG_ATM is not set
+# CONFIG_VLAN_8021Q is not set
+
+#
+#  
+#
+# 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=y
+# 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 is not set
+# CONFIG_NET_SCH_HTB is not set
+# CONFIG_NET_SCH_CSZ is not set
+# CONFIG_NET_SCH_HFSC is not set
+# CONFIG_NET_SCH_PRIO is not set
+# CONFIG_NET_SCH_RED is not set
+# CONFIG_NET_SCH_SFQ is not set
+# CONFIG_NET_SCH_TEQL is not set
+CONFIG_NET_SCH_TBF=y
+# CONFIG_NET_SCH_GRED is not set
+# CONFIG_NET_SCH_DELAY is not set
+# CONFIG_NET_SCH_DSMARK is not set
+# CONFIG_NET_SCH_INGRESS is not set
+# CONFIG_NET_QOS is not set
+# CONFIG_NET_CLS is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+
+#
+# ATA/IDE/MFM/RLL support
+#
+# CONFIG_IDE is not set
+# CONFIG_BLK_DEV_HD is not set
+
+#
+# SCSI support
+#
+# CONFIG_SCSI 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 is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+# CONFIG_ETHERTAP is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+# CONFIG_MACE is not set
+# CONFIG_BMAC is not set
+# CONFIG_GMAC 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
+
+#
+# Backplane Networking
+#
+# CONFIG_NPNET is not set
+
+#
+# On-chip net devices
+#
+CONFIG_IBM_OCP_ENET=y
+# CONFIG_IBM_OCP_ENET_ERROR_MSG is not set
+CONFIG_IBM_OCP_ENET_RX_BUFF=64
+CONFIG_IBM_OCP_ENET_TX_BUFF=8
+CONFIG_IBM_OCP_ENET_GAP=4
+CONFIG_IBM_OCP_ENET_SKB_RES=2
+CONFIG_OCP_NET=y
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+# CONFIG_PLIP is not set
+CONFIG_PPP=y
+# CONFIG_PPP_MULTILINK is not set
+# CONFIG_PPP_FILTER is not set
+CONFIG_PPP_ASYNC=y
+# CONFIG_PPP_SYNC_TTY is not set
+CONFIG_PPP_DEFLATE=y
+CONFIG_PPP_BSDCOMP=y
+# CONFIG_PPPOE is not set
+# CONFIG_SLIP is not set
+
+#
+# Wireless LAN (non-hamradio)
+#
+# CONFIG_NET_RADIO is not set
+
+#
+# Token Ring devices
+#
+# CONFIG_TR is not set
+# CONFIG_NET_FC is not set
+# CONFIG_RCPCI is not set
+# CONFIG_SHAPER is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN 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
+
+#
+# Old CD-ROM drivers (not SCSI, not IDE)
+#
+# CONFIG_CD_NO_IDESCSI is not set
+
+#
+# Console drivers
+#
+CONFIG_DUMMY_CONSOLE=y
+
+#
+# Frame-buffer support
+#
+# CONFIG_FB 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
+
+#
+# Macintosh device drivers
+#
+
+#
+# Character devices
+#
+CONFIG_VT=y
+# CONFIG_VT_CONSOLE is not set
+CONFIG_SERIAL=y
+CONFIG_SERIAL_CONSOLE=y
+# CONFIG_SERIAL_EXTENDED is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+CONFIG_UNIX98_PTYS=y
+CONFIG_UNIX98_PTY_COUNT=256
+
+#
+# I2C support
+#
+CONFIG_I2C=m
+CONFIG_I2C_SLAVE=m
+# CONFIG_I2C_ALGOBIT is not set
+# CONFIG_SCx200_ACB is not set
+# CONFIG_I2C_ALGOPCF is not set
+CONFIG_I2C_IBM_IIC=y
+# CONFIG_I2C_ASICSMS is not set
+CONFIG_I2C_CHARDEV=y
+CONFIG_I2C_PROC=y
+
+#
+# Mice
+#
+# CONFIG_BUSMOUSE is not set
+# CONFIG_MOUSE is not set
+
+#
+# Joysticks
+#
+# CONFIG_INPUT_GAMEPORT is not set
+
+#
+# Input core support is needed for gameports
+#
+
+#
+# Input core support is needed for joysticks
+#
+# 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=y
+CONFIG_WATCHDOG_NOWAYOUT=y
+# CONFIG_ACQUIRE_WDT is not set
+# CONFIG_ADVANTECH_WDT is not set
+# CONFIG_ALIM1535_WDT is not set
+# CONFIG_ALIM7101_WDT is not set
+# CONFIG_SC520_WDT is not set
+# CONFIG_PCWATCHDOG is not set
+# CONFIG_EUROTECH_WDT is not set
+# CONFIG_IB700_WDT is not set
+CONFIG_PPC405_WDT=y
+# CONFIG_WAFER_WDT is not set
+# CONFIG_I810_TCO is not set
+# CONFIG_MIXCOMWD is not set
+# CONFIG_60XX_WDT is not set
+# CONFIG_SC1200_WDT is not set
+# CONFIG_SCx200_WDT is not set
+# CONFIG_SOFT_WATCHDOG is not set
+# CONFIG_W83877F_WDT is not set
+# CONFIG_WDT is not set
+# CONFIG_WDTPCI is not set
+# CONFIG_MACHZ_WDT is not set
+# CONFIG_AMD7XX_TCO 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_X1226_RTC=y
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+# CONFIG_IBM_OCP_GPIO 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
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV 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 is not set
+# 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 is not set
+# CONFIG_JBD is not set
+# CONFIG_JBD_DEBUG is not set
+# CONFIG_FAT_FS is not set
+# CONFIG_MSDOS_FS is not set
+# CONFIG_UMSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_JFFS_FS is not set
+CONFIG_JFFS2_FS=m
+CONFIG_JFFS2_FS_DEBUG=0
+# CONFIG_CRAMFS is not set
+# CONFIG_TMPFS is not set
+CONFIG_RAMFS=y
+# CONFIG_ISO9660_FS is not set
+# CONFIG_JOLIET is not set
+# CONFIG_ZISOFS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_JFS_DEBUG is not set
+# CONFIG_JFS_STATISTICS is not set
+CONFIG_MINIX_FS=y
+# CONFIG_VXFS_FS is not set
+# CONFIG_NTFS_FS is not set
+# CONFIG_NTFS_RW is not set
+# CONFIG_HPFS_FS is not set
+CONFIG_PROC_FS=y
+# CONFIG_DEVFS_FS is not set
+# CONFIG_DEVFS_MOUNT is not set
+# 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=y
+# 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 is not set
+# CONFIG_NFSD_V3 is not set
+# CONFIG_NFSD_TCP is not set
+CONFIG_SUNRPC=y
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_SMB_FS=y
+# 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 is not set
+
+#
+# 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-1"
+# CONFIG_NLS_CODEPAGE_437 is not set
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# 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 is not set
+# 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 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# IBM 4xx options
+#
+
+#
+# USB support
+#
+# CONFIG_USB is not set
+
+#
+# Support for USB gadgets
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# Bluetooth support
+#
+# CONFIG_BLUEZ is not set
+
+#
+# Cryptographic options
+#
+CONFIG_CRYPTO=y
+CONFIG_CRYPTO_HMAC=y
+CONFIG_CRYPTO_NULL=y
+# CONFIG_CRYPTO_MD4 is not set
+# CONFIG_CRYPTO_MD5 is not set
+# CONFIG_CRYPTO_SHA1 is not set
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_DES is not set
+# CONFIG_CRYPTO_BLOWFISH is not set
+# CONFIG_CRYPTO_TWOFISH is not set
+# CONFIG_CRYPTO_SERPENT is not set
+CONFIG_CRYPTO_AES=y
+# CONFIG_CRYPTO_CAST5 is not set
+# CONFIG_CRYPTO_CAST6 is not set
+# CONFIG_CRYPTO_ARC4 is not set
+# CONFIG_CRYPTO_DEFLATE is not set
+# CONFIG_CRYPTO_TEST is not set
+
+#
+# Library routines
+#
+# CONFIG_CRC32 is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
+
+#
+# Kernel hacking
+#
+# CONFIG_DEBUG_KERNEL is not set
+# CONFIG_SERIAL_TEXT_DEBUG is not set
+CONFIG_LOG_BUF_SHIFT=0
Index: pplinux/linuxnew/arch/ppc/configs/lara_kim2_defconfig
diff -u /dev/null pplinux/linuxnew/arch/ppc/configs/lara_kim2_defconfig:1.3
--- /dev/null	Tue May 24 10:37:58 2005
+++ pplinux/linuxnew/arch/ppc/configs/lara_kim2_defconfig	Mon May  2 14:20:10 2005
@@ -0,0 +1,878 @@
+#
+# Automatically generated make config: don't edit
+#
+# CONFIG_UID16 is not set
+# CONFIG_RWSEM_GENERIC_SPINLOCK is not set
+CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_HAVE_DEC_LOCK=y
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_ADVANCED_OPTIONS=y
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+CONFIG_MODVERSIONS=y
+# CONFIG_KMOD is not set
+
+#
+# Platform support
+#
+CONFIG_PPC=y
+CONFIG_PPC32=y
+# CONFIG_6xx is not set
+CONFIG_40x=y
+# CONFIG_44x is not set
+# CONFIG_POWER3 is not set
+# CONFIG_POWER4 is not set
+# CONFIG_8xx is not set
+CONFIG_4xx=y
+# CONFIG_PPC_STD_MMU is not set
+# CONFIG_ARCTIC2 is not set
+# CONFIG_ASH is not set
+# CONFIG_CEDER is not set
+# CONFIG_BEECH is not set
+# CONFIG_CPCI405 is not set
+# CONFIG_EP405 is not set
+# CONFIG_EVB405EP is not set
+# CONFIG_OAK is not set
+# CONFIG_RAINIER is not set
+# CONFIG_REDWOOD_4 is not set
+# CONFIG_REDWOOD_5 is not set
+# CONFIG_REDWOOD_6 is not set
+# CONFIG_SYCAMORE is not set
+# CONFIG_TIVO is not set
+# CONFIG_WALNUT is not set
+# CONFIG_PEPPERCON_405GP is not set
+CONFIG_PEPPERCON_405EP=y
+# CONFIG_XILINX_ML300 is not set
+# CONFIG_ALL_PPC is not set
+# CONFIG_SMP is not set
+# CONFIG_MATH_EMULATION is not set
+CONFIG_BIGPHYS_AREA=y
+CONFIG_NOT_COHERENT_CACHE=y
+CONFIG_UART0_TTYS0=y
+# CONFIG_UART0_TTYS1 is not set
+# CONFIG_PM is not set
+CONFIG_PEPPERCON=y
+CONFIG_405EP=y
+CONFIG_IBM_OCP=y
+CONFIG_PPC_OCP=y
+CONFIG_GEN550=y
+CONFIG_405=y
+CONFIG_IBM405_ERR51=y
+CONFIG_IBM405_ERR77=y
+CONFIG_PPC4xx_DMA=y
+CONFIG_PPC4xx_EDMA=y
+CONFIG_OCP_PROC=y
+
+#
+# General setup
+#
+# CONFIG_HIGHMEM is not set
+# CONFIG_LOWMEM_SIZE_BOOL is not set
+# CONFIG_KERNEL_START_BOOL is not set
+# CONFIG_TASK_SIZE_BOOL is not set
+# CONFIG_PIN_TLB is not set
+CONFIG_HIGHMEM_START=0xfe000000
+CONFIG_LOWMEM_SIZE=0x30000000
+CONFIG_KERNEL_START=0xc0000000
+CONFIG_TASK_SIZE=0x80000000
+# CONFIG_ISA is not set
+# CONFIG_EISA is not set
+# CONFIG_SBUS is not set
+# CONFIG_MCA is not set
+CONFIG_PCI=y
+# CONFIG_8260_PCI9 is not set
+# CONFIG_PC_KEYBOARD is not set
+CONFIG_NET=y
+CONFIG_SYSCTL=y
+CONFIG_SYSVIPC=y
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_KCORE_ELF=y
+CONFIG_BINFMT_ELF=y
+CONFIG_KERNEL_ELF=y
+# CONFIG_BINFMT_MISC is not set
+# CONFIG_OOM_KILLER is not set
+# CONFIG_PCI_NAMES is not set
+# CONFIG_HOTPLUG is not set
+# CONFIG_PCMCIA is not set
+
+#
+# PCI Hotplug Support
+#
+# CONFIG_HOTPLUG_PCI is not set
+# CONFIG_HOTPLUG_PCI_DUMMY is not set
+# CONFIG_HOTPLUG_PCI_COMPAQ is not set
+# CONFIG_HOTPLUG_PCI_COMPAQ_NVRAM is not set
+# CONFIG_HOTPLUG is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+# CONFIG_GEN_RTC is not set
+# CONFIG_PPC_RTC is not set
+CONFIG_CMDLINE_BOOL=y
+CONFIG_CMDLINE="console=ttyS0,115200 root=/dev/nfs nfsroot=192.168.1.24:/eric_root_devel.miba ip=192.168.1.20:192.168.1.24"
+
+#
+# Memory Technology Devices (MTD)
+#
+CONFIG_MTD=m
+# CONFIG_MTD_DEBUG is not set
+CONFIG_MTD_PARTITIONS=m
+# CONFIG_MTD_CONCAT is not set
+# CONFIG_MTD_REDBOOT_PARTS is not set
+CONFIG_MTD_CMDLINE_PARTS=m
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=m
+CONFIG_MTD_BLOCK=m
+# CONFIG_MTD_BLOCK_RO is not set
+CONFIG_FTL=m
+# CONFIG_NFTL is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+CONFIG_MTD_CFI=m
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_GEN_PROBE=m
+CONFIG_MTD_CFI_ADV_OPTIONS=y
+CONFIG_MTD_CFI_NOSWAP=y
+# CONFIG_MTD_CFI_BE_BYTE_SWAP is not set
+# CONFIG_MTD_CFI_LE_BYTE_SWAP is not set
+CONFIG_MTD_CFI_GEOMETRY=y
+# CONFIG_MTD_CFI_B1 is not set
+CONFIG_MTD_CFI_B2=y
+# CONFIG_MTD_CFI_B4 is not set
+# CONFIG_MTD_CFI_B8 is not set
+CONFIG_MTD_CFI_I1=y
+# CONFIG_MTD_CFI_I2 is not set
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+CONFIG_MTD_CFI_INTELEXT=m
+# CONFIG_MTD_CFI_AMDSTD is not set
+# CONFIG_MTD_CFI_STAA is not set
+# CONFIG_MTD_RAM is not set
+CONFIG_MTD_ROM=m
+# 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_PHYSMAP=m
+CONFIG_MTD_PHYSMAP_BUSWIDTH=2
+# CONFIG_MTD_BEECH is not set
+# CONFIG_MTD_ARCTIC 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
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC1000 is not set
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOCPROBE is not set
+
+#
+# NAND Flash Device Drivers
+#
+# CONFIG_MTD_NAND 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_LOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=8192
+CONFIG_BLK_DEV_INITRD=y
+# 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 is not set
+CONFIG_NETFILTER=y
+# CONFIG_NETFILTER_DEBUG is not set
+# CONFIG_FILTER is not set
+CONFIG_UNIX=y
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_PNP=y
+# CONFIG_IP_PNP_DHCP is not set
+CONFIG_IP_PNP_BOOTP=y
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_IP_MROUTE is not set
+# CONFIG_ARPD is not set
+# CONFIG_INET_ECN is not set
+# CONFIG_SYN_COOKIES is not set
+
+#
+#   IP: Netfilter Configuration
+#
+CONFIG_IP_NF_CONNTRACK=y
+# CONFIG_IP_NF_FTP is not set
+# CONFIG_IP_NF_AMANDA is not set
+# CONFIG_IP_NF_TFTP is not set
+# CONFIG_IP_NF_IRC is not set
+CONFIG_IP_NF_QUEUE=y
+CONFIG_IP_NF_IPTABLES=y
+# CONFIG_IP_NF_MATCH_LIMIT is not set
+CONFIG_IP_NF_MATCH_MAC=y
+# CONFIG_IP_NF_MATCH_PKTTYPE is not set
+CONFIG_IP_NF_MATCH_MARK=y
+# CONFIG_IP_NF_MATCH_MULTIPORT is not set
+# CONFIG_IP_NF_MATCH_TOS is not set
+# CONFIG_IP_NF_MATCH_RECENT is not set
+# CONFIG_IP_NF_MATCH_ECN is not set
+# CONFIG_IP_NF_MATCH_DSCP is not set
+# CONFIG_IP_NF_MATCH_AH_ESP is not set
+# CONFIG_IP_NF_MATCH_LENGTH is not set
+# CONFIG_IP_NF_MATCH_TTL is not set
+# CONFIG_IP_NF_MATCH_TCPMSS is not set
+# CONFIG_IP_NF_MATCH_HELPER is not set
+# CONFIG_IP_NF_MATCH_STATE is not set
+# CONFIG_IP_NF_MATCH_CONNTRACK is not set
+# CONFIG_IP_NF_MATCH_UNCLEAN is not set
+# CONFIG_IP_NF_MATCH_OWNER is not set
+CONFIG_IP_NF_FILTER=y
+CONFIG_IP_NF_TARGET_REJECT=y
+# CONFIG_IP_NF_TARGET_MIRROR is not set
+CONFIG_IP_NF_FASTNAT=y
+CONFIG_IP_NF_TARGET_FASTNAT=y
+CONFIG_IP_NF_NAT=y
+CONFIG_IP_NF_NAT_NEEDED=y
+# CONFIG_IP_NF_TARGET_MASQUERADE is not set
+CONFIG_IP_NF_TARGET_REDIRECT=y
+CONFIG_IP_NF_NAT_LOCAL=y
+# CONFIG_IP_NF_NAT_SNMP_BASIC is not set
+CONFIG_IP_NF_MANGLE=y
+# CONFIG_IP_NF_TARGET_TOS is not set
+# CONFIG_IP_NF_TARGET_ECN is not set
+# CONFIG_IP_NF_TARGET_DSCP is not set
+CONFIG_IP_NF_TARGET_MARK=y
+# CONFIG_IP_NF_TARGET_LOG is not set
+# CONFIG_IP_NF_TARGET_ULOG is not set
+# CONFIG_IP_NF_TARGET_TCPMSS is not set
+# CONFIG_IP_NF_ARPTABLES is not set
+
+#
+#   IP: Virtual Server Configuration
+#
+CONFIG_IP_VS=y
+# CONFIG_IP_VS_DEBUG is not set
+CONFIG_IP_VS_TAB_BITS=12
+
+#
+# IPVS scheduler
+#
+CONFIG_IP_VS_RR=y
+CONFIG_IP_VS_WRR=y
+CONFIG_IP_VS_LC=y
+CONFIG_IP_VS_WLC=y
+CONFIG_IP_VS_LBLC=y
+CONFIG_IP_VS_LBLCR=y
+CONFIG_IP_VS_DH=y
+CONFIG_IP_VS_SH=y
+CONFIG_IP_VS_SED=y
+CONFIG_IP_VS_NQ=y
+
+#
+# IPVS application helper
+#
+# CONFIG_IP_VS_FTP is not set
+CONFIG_IPV6=y
+
+#
+#   IPv6: Netfilter Configuration
+#
+# CONFIG_IP6_NF_QUEUE is not set
+# CONFIG_IP6_NF_IPTABLES is not set
+# CONFIG_KHTTPD is not set
+
+#
+#    SCTP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_SCTP is not set
+# CONFIG_ATM is not set
+# CONFIG_VLAN_8021Q is not set
+
+#
+#  
+#
+# 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=y
+# 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 is not set
+# CONFIG_NET_SCH_HTB is not set
+# CONFIG_NET_SCH_CSZ is not set
+# CONFIG_NET_SCH_HFSC is not set
+# CONFIG_NET_SCH_PRIO is not set
+# CONFIG_NET_SCH_RED is not set
+# CONFIG_NET_SCH_SFQ is not set
+# CONFIG_NET_SCH_TEQL is not set
+CONFIG_NET_SCH_TBF=y
+# CONFIG_NET_SCH_GRED is not set
+# CONFIG_NET_SCH_DELAY is not set
+# CONFIG_NET_SCH_DSMARK is not set
+# CONFIG_NET_SCH_INGRESS is not set
+# CONFIG_NET_QOS is not set
+# CONFIG_NET_CLS is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+
+#
+# ATA/IDE/MFM/RLL support
+#
+# CONFIG_IDE is not set
+# CONFIG_BLK_DEV_HD is not set
+
+#
+# SCSI support
+#
+# CONFIG_SCSI 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 is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+# CONFIG_ETHERTAP is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+# CONFIG_MACE is not set
+# CONFIG_BMAC is not set
+# CONFIG_GMAC 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
+
+#
+# Backplane Networking
+#
+# CONFIG_NPNET is not set
+
+#
+# On-chip net devices
+#
+CONFIG_IBM_OCP_ENET=y
+# CONFIG_IBM_OCP_ENET_ERROR_MSG is not set
+CONFIG_IBM_OCP_ENET_RX_BUFF=64
+CONFIG_IBM_OCP_ENET_TX_BUFF=8
+CONFIG_IBM_OCP_ENET_GAP=4
+CONFIG_IBM_OCP_ENET_SKB_RES=2
+CONFIG_OCP_NET=y
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+# CONFIG_PLIP is not set
+CONFIG_PPP=y
+# CONFIG_PPP_MULTILINK is not set
+# CONFIG_PPP_FILTER is not set
+CONFIG_PPP_ASYNC=y
+# CONFIG_PPP_SYNC_TTY is not set
+CONFIG_PPP_DEFLATE=y
+CONFIG_PPP_BSDCOMP=y
+# CONFIG_PPPOE is not set
+# CONFIG_SLIP is not set
+
+#
+# Wireless LAN (non-hamradio)
+#
+# CONFIG_NET_RADIO is not set
+
+#
+# Token Ring devices
+#
+# CONFIG_TR is not set
+# CONFIG_NET_FC is not set
+# CONFIG_RCPCI is not set
+# CONFIG_SHAPER is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN 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
+
+#
+# Old CD-ROM drivers (not SCSI, not IDE)
+#
+# CONFIG_CD_NO_IDESCSI is not set
+
+#
+# Console drivers
+#
+CONFIG_DUMMY_CONSOLE=y
+
+#
+# Frame-buffer support
+#
+# CONFIG_FB 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
+
+#
+# Macintosh device drivers
+#
+
+#
+# Character devices
+#
+CONFIG_VT=y
+# CONFIG_VT_CONSOLE is not set
+CONFIG_SERIAL=y
+CONFIG_SERIAL_CONSOLE=y
+# CONFIG_SERIAL_EXTENDED is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+CONFIG_UNIX98_PTYS=y
+CONFIG_UNIX98_PTY_COUNT=256
+
+#
+# I2C support
+#
+CONFIG_I2C=y
+CONFIG_I2C_SLAVE=y
+# CONFIG_I2C_ALGOBIT is not set
+# CONFIG_SCx200_ACB is not set
+# CONFIG_I2C_ALGOPCF is not set
+CONFIG_I2C_IBM_IIC=y
+# CONFIG_I2C_ASICSMS is not set
+CONFIG_I2C_CHARDEV=y
+CONFIG_I2C_PROC=y
+
+#
+# Mice
+#
+# CONFIG_BUSMOUSE is not set
+# CONFIG_MOUSE is not set
+
+#
+# Joysticks
+#
+# CONFIG_INPUT_GAMEPORT is not set
+
+#
+# Input core support is needed for gameports
+#
+
+#
+# Input core support is needed for joysticks
+#
+# 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=y
+CONFIG_WATCHDOG_NOWAYOUT=y
+# CONFIG_ACQUIRE_WDT is not set
+# CONFIG_ADVANTECH_WDT is not set
+# CONFIG_ALIM1535_WDT is not set
+# CONFIG_ALIM7101_WDT is not set
+# CONFIG_SC520_WDT is not set
+# CONFIG_PCWATCHDOG is not set
+# CONFIG_EUROTECH_WDT is not set
+# CONFIG_IB700_WDT is not set
+CONFIG_PPC405_WDT=y
+# CONFIG_WAFER_WDT is not set
+# CONFIG_I810_TCO is not set
+# CONFIG_MIXCOMWD is not set
+# CONFIG_60XX_WDT is not set
+# CONFIG_SC1200_WDT is not set
+# CONFIG_SCx200_WDT is not set
+# CONFIG_SOFT_WATCHDOG is not set
+# CONFIG_W83877F_WDT is not set
+# CONFIG_WDT is not set
+# CONFIG_WDTPCI is not set
+# CONFIG_MACHZ_WDT is not set
+# CONFIG_AMD7XX_TCO 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_X1226_RTC=y
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+# CONFIG_IBM_OCP_GPIO 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
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV 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 is not set
+# 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 is not set
+# CONFIG_JBD is not set
+# CONFIG_JBD_DEBUG is not set
+# CONFIG_FAT_FS is not set
+# CONFIG_MSDOS_FS is not set
+# CONFIG_UMSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_JFFS_FS is not set
+CONFIG_JFFS2_FS=m
+CONFIG_JFFS2_FS_DEBUG=0
+# CONFIG_CRAMFS is not set
+# CONFIG_TMPFS is not set
+CONFIG_RAMFS=y
+# CONFIG_ISO9660_FS is not set
+# CONFIG_JOLIET is not set
+# CONFIG_ZISOFS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_JFS_DEBUG is not set
+# CONFIG_JFS_STATISTICS is not set
+CONFIG_MINIX_FS=y
+# CONFIG_VXFS_FS is not set
+# CONFIG_NTFS_FS is not set
+# CONFIG_NTFS_RW is not set
+# CONFIG_HPFS_FS is not set
+CONFIG_PROC_FS=y
+# CONFIG_DEVFS_FS is not set
+# CONFIG_DEVFS_MOUNT is not set
+# 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=y
+# 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 is not set
+# CONFIG_NFSD_V3 is not set
+# CONFIG_NFSD_TCP is not set
+CONFIG_SUNRPC=y
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_SMB_FS=y
+# 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 is not set
+
+#
+# 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-1"
+# CONFIG_NLS_CODEPAGE_437 is not set
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# 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 is not set
+# 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 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# IBM 4xx options
+#
+
+#
+# USB support
+#
+# CONFIG_USB is not set
+
+#
+# Support for USB gadgets
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# Bluetooth support
+#
+# CONFIG_BLUEZ is not set
+
+#
+# Cryptographic options
+#
+CONFIG_CRYPTO=y
+CONFIG_CRYPTO_HMAC=y
+CONFIG_CRYPTO_NULL=y
+# CONFIG_CRYPTO_MD4 is not set
+# CONFIG_CRYPTO_MD5 is not set
+# CONFIG_CRYPTO_SHA1 is not set
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_DES is not set
+# CONFIG_CRYPTO_BLOWFISH is not set
+# CONFIG_CRYPTO_TWOFISH is not set
+# CONFIG_CRYPTO_SERPENT is not set
+CONFIG_CRYPTO_AES=y
+# CONFIG_CRYPTO_CAST5 is not set
+# CONFIG_CRYPTO_CAST6 is not set
+# CONFIG_CRYPTO_ARC4 is not set
+# CONFIG_CRYPTO_DEFLATE is not set
+# CONFIG_CRYPTO_TEST is not set
+
+#
+# Library routines
+#
+# CONFIG_CRC32 is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
+
+#
+# Kernel hacking
+#
+# CONFIG_DEBUG_KERNEL is not set
+# CONFIG_SERIAL_TEXT_DEBUG is not set
+CONFIG_LOG_BUF_SHIFT=0
Index: pplinux/linuxnew/arch/ppc/configs/lara_kim_defconfig
diff -u /dev/null pplinux/linuxnew/arch/ppc/configs/lara_kim_defconfig:1.3
--- /dev/null	Tue May 24 10:37:58 2005
+++ pplinux/linuxnew/arch/ppc/configs/lara_kim_defconfig	Mon May  2 14:20:10 2005
@@ -0,0 +1,878 @@
+#
+# Automatically generated make config: don't edit
+#
+# CONFIG_UID16 is not set
+# CONFIG_RWSEM_GENERIC_SPINLOCK is not set
+CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_HAVE_DEC_LOCK=y
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_ADVANCED_OPTIONS=y
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+CONFIG_MODVERSIONS=y
+# CONFIG_KMOD is not set
+
+#
+# Platform support
+#
+CONFIG_PPC=y
+CONFIG_PPC32=y
+# CONFIG_6xx is not set
+CONFIG_40x=y
+# CONFIG_44x is not set
+# CONFIG_POWER3 is not set
+# CONFIG_POWER4 is not set
+# CONFIG_8xx is not set
+CONFIG_4xx=y
+# CONFIG_PPC_STD_MMU is not set
+# CONFIG_ARCTIC2 is not set
+# CONFIG_ASH is not set
+# CONFIG_CEDER is not set
+# CONFIG_BEECH is not set
+# CONFIG_CPCI405 is not set
+# CONFIG_EP405 is not set
+# CONFIG_EVB405EP is not set
+# CONFIG_OAK is not set
+# CONFIG_RAINIER is not set
+# CONFIG_REDWOOD_4 is not set
+# CONFIG_REDWOOD_5 is not set
+# CONFIG_REDWOOD_6 is not set
+# CONFIG_SYCAMORE is not set
+# CONFIG_TIVO is not set
+# CONFIG_WALNUT is not set
+# CONFIG_PEPPERCON_405GP is not set
+CONFIG_PEPPERCON_405EP=y
+# CONFIG_XILINX_ML300 is not set
+# CONFIG_ALL_PPC is not set
+# CONFIG_SMP is not set
+# CONFIG_MATH_EMULATION is not set
+CONFIG_BIGPHYS_AREA=y
+CONFIG_NOT_COHERENT_CACHE=y
+CONFIG_UART0_TTYS0=y
+# CONFIG_UART0_TTYS1 is not set
+# CONFIG_PM is not set
+CONFIG_PEPPERCON=y
+CONFIG_405EP=y
+CONFIG_IBM_OCP=y
+CONFIG_PPC_OCP=y
+CONFIG_GEN550=y
+CONFIG_405=y
+CONFIG_IBM405_ERR51=y
+CONFIG_IBM405_ERR77=y
+CONFIG_PPC4xx_DMA=y
+CONFIG_PPC4xx_EDMA=y
+CONFIG_OCP_PROC=y
+
+#
+# General setup
+#
+# CONFIG_HIGHMEM is not set
+# CONFIG_LOWMEM_SIZE_BOOL is not set
+# CONFIG_KERNEL_START_BOOL is not set
+# CONFIG_TASK_SIZE_BOOL is not set
+# CONFIG_PIN_TLB is not set
+CONFIG_HIGHMEM_START=0xfe000000
+CONFIG_LOWMEM_SIZE=0x30000000
+CONFIG_KERNEL_START=0xc0000000
+CONFIG_TASK_SIZE=0x80000000
+# CONFIG_ISA is not set
+# CONFIG_EISA is not set
+# CONFIG_SBUS is not set
+# CONFIG_MCA is not set
+CONFIG_PCI=y
+# CONFIG_8260_PCI9 is not set
+# CONFIG_PC_KEYBOARD is not set
+CONFIG_NET=y
+CONFIG_SYSCTL=y
+CONFIG_SYSVIPC=y
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_KCORE_ELF=y
+CONFIG_BINFMT_ELF=y
+CONFIG_KERNEL_ELF=y
+# CONFIG_BINFMT_MISC is not set
+# CONFIG_OOM_KILLER is not set
+# CONFIG_PCI_NAMES is not set
+# CONFIG_HOTPLUG is not set
+# CONFIG_PCMCIA is not set
+
+#
+# PCI Hotplug Support
+#
+# CONFIG_HOTPLUG_PCI is not set
+# CONFIG_HOTPLUG_PCI_DUMMY is not set
+# CONFIG_HOTPLUG_PCI_COMPAQ is not set
+# CONFIG_HOTPLUG_PCI_COMPAQ_NVRAM is not set
+# CONFIG_HOTPLUG is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+# CONFIG_GEN_RTC is not set
+# CONFIG_PPC_RTC is not set
+CONFIG_CMDLINE_BOOL=y
+CONFIG_CMDLINE="console=ttyS0,115200 root=/dev/nfs nfsroot=192.168.1.24:/eric_root_devel.miba ip=192.168.1.20:192.168.1.24"
+
+#
+# Memory Technology Devices (MTD)
+#
+CONFIG_MTD=m
+# CONFIG_MTD_DEBUG is not set
+CONFIG_MTD_PARTITIONS=m
+# CONFIG_MTD_CONCAT is not set
+# CONFIG_MTD_REDBOOT_PARTS is not set
+CONFIG_MTD_CMDLINE_PARTS=m
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=m
+CONFIG_MTD_BLOCK=m
+# CONFIG_MTD_BLOCK_RO is not set
+CONFIG_FTL=m
+# CONFIG_NFTL is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+CONFIG_MTD_CFI=m
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_GEN_PROBE=m
+CONFIG_MTD_CFI_ADV_OPTIONS=y
+CONFIG_MTD_CFI_NOSWAP=y
+# CONFIG_MTD_CFI_BE_BYTE_SWAP is not set
+# CONFIG_MTD_CFI_LE_BYTE_SWAP is not set
+CONFIG_MTD_CFI_GEOMETRY=y
+# CONFIG_MTD_CFI_B1 is not set
+CONFIG_MTD_CFI_B2=y
+# CONFIG_MTD_CFI_B4 is not set
+# CONFIG_MTD_CFI_B8 is not set
+CONFIG_MTD_CFI_I1=y
+# CONFIG_MTD_CFI_I2 is not set
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+CONFIG_MTD_CFI_INTELEXT=m
+# CONFIG_MTD_CFI_AMDSTD is not set
+# CONFIG_MTD_CFI_STAA is not set
+# CONFIG_MTD_RAM is not set
+CONFIG_MTD_ROM=m
+# 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_PHYSMAP=m
+CONFIG_MTD_PHYSMAP_BUSWIDTH=2
+# CONFIG_MTD_BEECH is not set
+# CONFIG_MTD_ARCTIC 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
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC1000 is not set
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOCPROBE is not set
+
+#
+# NAND Flash Device Drivers
+#
+# CONFIG_MTD_NAND 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_LOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=8192
+CONFIG_BLK_DEV_INITRD=y
+# 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 is not set
+CONFIG_NETFILTER=y
+# CONFIG_NETFILTER_DEBUG is not set
+# CONFIG_FILTER is not set
+CONFIG_UNIX=y
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_PNP=y
+# CONFIG_IP_PNP_DHCP is not set
+CONFIG_IP_PNP_BOOTP=y
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_IP_MROUTE is not set
+# CONFIG_ARPD is not set
+# CONFIG_INET_ECN is not set
+# CONFIG_SYN_COOKIES is not set
+
+#
+#   IP: Netfilter Configuration
+#
+CONFIG_IP_NF_CONNTRACK=y
+# CONFIG_IP_NF_FTP is not set
+# CONFIG_IP_NF_AMANDA is not set
+# CONFIG_IP_NF_TFTP is not set
+# CONFIG_IP_NF_IRC is not set
+CONFIG_IP_NF_QUEUE=y
+CONFIG_IP_NF_IPTABLES=y
+# CONFIG_IP_NF_MATCH_LIMIT is not set
+CONFIG_IP_NF_MATCH_MAC=y
+# CONFIG_IP_NF_MATCH_PKTTYPE is not set
+CONFIG_IP_NF_MATCH_MARK=y
+# CONFIG_IP_NF_MATCH_MULTIPORT is not set
+# CONFIG_IP_NF_MATCH_TOS is not set
+# CONFIG_IP_NF_MATCH_RECENT is not set
+# CONFIG_IP_NF_MATCH_ECN is not set
+# CONFIG_IP_NF_MATCH_DSCP is not set
+# CONFIG_IP_NF_MATCH_AH_ESP is not set
+# CONFIG_IP_NF_MATCH_LENGTH is not set
+# CONFIG_IP_NF_MATCH_TTL is not set
+# CONFIG_IP_NF_MATCH_TCPMSS is not set
+# CONFIG_IP_NF_MATCH_HELPER is not set
+# CONFIG_IP_NF_MATCH_STATE is not set
+# CONFIG_IP_NF_MATCH_CONNTRACK is not set
+# CONFIG_IP_NF_MATCH_UNCLEAN is not set
+# CONFIG_IP_NF_MATCH_OWNER is not set
+CONFIG_IP_NF_FILTER=y
+CONFIG_IP_NF_TARGET_REJECT=y
+# CONFIG_IP_NF_TARGET_MIRROR is not set
+CONFIG_IP_NF_FASTNAT=y
+CONFIG_IP_NF_TARGET_FASTNAT=y
+CONFIG_IP_NF_NAT=y
+CONFIG_IP_NF_NAT_NEEDED=y
+# CONFIG_IP_NF_TARGET_MASQUERADE is not set
+CONFIG_IP_NF_TARGET_REDIRECT=y
+CONFIG_IP_NF_NAT_LOCAL=y
+# CONFIG_IP_NF_NAT_SNMP_BASIC is not set
+CONFIG_IP_NF_MANGLE=y
+# CONFIG_IP_NF_TARGET_TOS is not set
+# CONFIG_IP_NF_TARGET_ECN is not set
+# CONFIG_IP_NF_TARGET_DSCP is not set
+CONFIG_IP_NF_TARGET_MARK=y
+# CONFIG_IP_NF_TARGET_LOG is not set
+# CONFIG_IP_NF_TARGET_ULOG is not set
+# CONFIG_IP_NF_TARGET_TCPMSS is not set
+# CONFIG_IP_NF_ARPTABLES is not set
+
+#
+#   IP: Virtual Server Configuration
+#
+CONFIG_IP_VS=y
+# CONFIG_IP_VS_DEBUG is not set
+CONFIG_IP_VS_TAB_BITS=12
+
+#
+# IPVS scheduler
+#
+CONFIG_IP_VS_RR=y
+CONFIG_IP_VS_WRR=y
+CONFIG_IP_VS_LC=y
+CONFIG_IP_VS_WLC=y
+CONFIG_IP_VS_LBLC=y
+CONFIG_IP_VS_LBLCR=y
+CONFIG_IP_VS_DH=y
+CONFIG_IP_VS_SH=y
+CONFIG_IP_VS_SED=y
+CONFIG_IP_VS_NQ=y
+
+#
+# IPVS application helper
+#
+# CONFIG_IP_VS_FTP is not set
+CONFIG_IPV6=y
+
+#
+#   IPv6: Netfilter Configuration
+#
+# CONFIG_IP6_NF_QUEUE is not set
+# CONFIG_IP6_NF_IPTABLES is not set
+# CONFIG_KHTTPD is not set
+
+#
+#    SCTP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_SCTP is not set
+# CONFIG_ATM is not set
+# CONFIG_VLAN_8021Q is not set
+
+#
+#  
+#
+# 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=y
+# 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 is not set
+# CONFIG_NET_SCH_HTB is not set
+# CONFIG_NET_SCH_CSZ is not set
+# CONFIG_NET_SCH_HFSC is not set
+# CONFIG_NET_SCH_PRIO is not set
+# CONFIG_NET_SCH_RED is not set
+# CONFIG_NET_SCH_SFQ is not set
+# CONFIG_NET_SCH_TEQL is not set
+CONFIG_NET_SCH_TBF=y
+# CONFIG_NET_SCH_GRED is not set
+# CONFIG_NET_SCH_DELAY is not set
+# CONFIG_NET_SCH_DSMARK is not set
+# CONFIG_NET_SCH_INGRESS is not set
+# CONFIG_NET_QOS is not set
+# CONFIG_NET_CLS is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+
+#
+# ATA/IDE/MFM/RLL support
+#
+# CONFIG_IDE is not set
+# CONFIG_BLK_DEV_HD is not set
+
+#
+# SCSI support
+#
+# CONFIG_SCSI 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 is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+# CONFIG_ETHERTAP is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+# CONFIG_MACE is not set
+# CONFIG_BMAC is not set
+# CONFIG_GMAC 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
+
+#
+# Backplane Networking
+#
+# CONFIG_NPNET is not set
+
+#
+# On-chip net devices
+#
+CONFIG_IBM_OCP_ENET=y
+# CONFIG_IBM_OCP_ENET_ERROR_MSG is not set
+CONFIG_IBM_OCP_ENET_RX_BUFF=64
+CONFIG_IBM_OCP_ENET_TX_BUFF=8
+CONFIG_IBM_OCP_ENET_GAP=4
+CONFIG_IBM_OCP_ENET_SKB_RES=2
+CONFIG_OCP_NET=y
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+# CONFIG_PLIP is not set
+CONFIG_PPP=y
+# CONFIG_PPP_MULTILINK is not set
+# CONFIG_PPP_FILTER is not set
+CONFIG_PPP_ASYNC=y
+# CONFIG_PPP_SYNC_TTY is not set
+CONFIG_PPP_DEFLATE=y
+CONFIG_PPP_BSDCOMP=y
+# CONFIG_PPPOE is not set
+# CONFIG_SLIP is not set
+
+#
+# Wireless LAN (non-hamradio)
+#
+# CONFIG_NET_RADIO is not set
+
+#
+# Token Ring devices
+#
+# CONFIG_TR is not set
+# CONFIG_NET_FC is not set
+# CONFIG_RCPCI is not set
+# CONFIG_SHAPER is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN 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
+
+#
+# Old CD-ROM drivers (not SCSI, not IDE)
+#
+# CONFIG_CD_NO_IDESCSI is not set
+
+#
+# Console drivers
+#
+CONFIG_DUMMY_CONSOLE=y
+
+#
+# Frame-buffer support
+#
+# CONFIG_FB 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
+
+#
+# Macintosh device drivers
+#
+
+#
+# Character devices
+#
+CONFIG_VT=y
+# CONFIG_VT_CONSOLE is not set
+CONFIG_SERIAL=y
+CONFIG_SERIAL_CONSOLE=y
+# CONFIG_SERIAL_EXTENDED is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+CONFIG_UNIX98_PTYS=y
+CONFIG_UNIX98_PTY_COUNT=256
+
+#
+# I2C support
+#
+CONFIG_I2C=y
+CONFIG_I2C_SLAVE=y
+# CONFIG_I2C_ALGOBIT is not set
+# CONFIG_SCx200_ACB is not set
+# CONFIG_I2C_ALGOPCF is not set
+CONFIG_I2C_IBM_IIC=y
+# CONFIG_I2C_ASICSMS is not set
+CONFIG_I2C_CHARDEV=y
+CONFIG_I2C_PROC=y
+
+#
+# Mice
+#
+# CONFIG_BUSMOUSE is not set
+# CONFIG_MOUSE is not set
+
+#
+# Joysticks
+#
+# CONFIG_INPUT_GAMEPORT is not set
+
+#
+# Input core support is needed for gameports
+#
+
+#
+# Input core support is needed for joysticks
+#
+# 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=y
+CONFIG_WATCHDOG_NOWAYOUT=y
+# CONFIG_ACQUIRE_WDT is not set
+# CONFIG_ADVANTECH_WDT is not set
+# CONFIG_ALIM1535_WDT is not set
+# CONFIG_ALIM7101_WDT is not set
+# CONFIG_SC520_WDT is not set
+# CONFIG_PCWATCHDOG is not set
+# CONFIG_EUROTECH_WDT is not set
+# CONFIG_IB700_WDT is not set
+CONFIG_PPC405_WDT=y
+# CONFIG_WAFER_WDT is not set
+# CONFIG_I810_TCO is not set
+# CONFIG_MIXCOMWD is not set
+# CONFIG_60XX_WDT is not set
+# CONFIG_SC1200_WDT is not set
+# CONFIG_SCx200_WDT is not set
+# CONFIG_SOFT_WATCHDOG is not set
+# CONFIG_W83877F_WDT is not set
+# CONFIG_WDT is not set
+# CONFIG_WDTPCI is not set
+# CONFIG_MACHZ_WDT is not set
+# CONFIG_AMD7XX_TCO 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_X1226_RTC=y
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+# CONFIG_IBM_OCP_GPIO 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
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV 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 is not set
+# 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 is not set
+# CONFIG_JBD is not set
+# CONFIG_JBD_DEBUG is not set
+# CONFIG_FAT_FS is not set
+# CONFIG_MSDOS_FS is not set
+# CONFIG_UMSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_JFFS_FS is not set
+CONFIG_JFFS2_FS=m
+CONFIG_JFFS2_FS_DEBUG=0
+# CONFIG_CRAMFS is not set
+# CONFIG_TMPFS is not set
+CONFIG_RAMFS=y
+# CONFIG_ISO9660_FS is not set
+# CONFIG_JOLIET is not set
+# CONFIG_ZISOFS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_JFS_DEBUG is not set
+# CONFIG_JFS_STATISTICS is not set
+CONFIG_MINIX_FS=y
+# CONFIG_VXFS_FS is not set
+# CONFIG_NTFS_FS is not set
+# CONFIG_NTFS_RW is not set
+# CONFIG_HPFS_FS is not set
+CONFIG_PROC_FS=y
+# CONFIG_DEVFS_FS is not set
+# CONFIG_DEVFS_MOUNT is not set
+# 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=y
+# 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 is not set
+# CONFIG_NFSD_V3 is not set
+# CONFIG_NFSD_TCP is not set
+CONFIG_SUNRPC=y
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_SMB_FS=y
+# 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 is not set
+
+#
+# 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-1"
+# CONFIG_NLS_CODEPAGE_437 is not set
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# 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 is not set
+# 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 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# IBM 4xx options
+#
+
+#
+# USB support
+#
+# CONFIG_USB is not set
+
+#
+# Support for USB gadgets
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# Bluetooth support
+#
+# CONFIG_BLUEZ is not set
+
+#
+# Cryptographic options
+#
+CONFIG_CRYPTO=y
+CONFIG_CRYPTO_HMAC=y
+CONFIG_CRYPTO_NULL=y
+# CONFIG_CRYPTO_MD4 is not set
+# CONFIG_CRYPTO_MD5 is not set
+# CONFIG_CRYPTO_SHA1 is not set
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_DES is not set
+# CONFIG_CRYPTO_BLOWFISH is not set
+# CONFIG_CRYPTO_TWOFISH is not set
+# CONFIG_CRYPTO_SERPENT is not set
+CONFIG_CRYPTO_AES=y
+# CONFIG_CRYPTO_CAST5 is not set
+# CONFIG_CRYPTO_CAST6 is not set
+# CONFIG_CRYPTO_ARC4 is not set
+# CONFIG_CRYPTO_DEFLATE is not set
+# CONFIG_CRYPTO_TEST is not set
+
+#
+# Library routines
+#
+# CONFIG_CRC32 is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
+
+#
+# Kernel hacking
+#
+# CONFIG_DEBUG_KERNEL is not set
+# CONFIG_SERIAL_TEXT_DEBUG is not set
+CONFIG_LOG_BUF_SHIFT=0
Index: pplinux/linuxnew/arch/ppc/configs/lara_kim_ipmi_defconfig
diff -u /dev/null pplinux/linuxnew/arch/ppc/configs/lara_kim_ipmi_defconfig:1.3
--- /dev/null	Tue May 24 10:37:58 2005
+++ pplinux/linuxnew/arch/ppc/configs/lara_kim_ipmi_defconfig	Mon May  2 14:20:10 2005
@@ -0,0 +1,878 @@
+#
+# Automatically generated make config: don't edit
+#
+# CONFIG_UID16 is not set
+# CONFIG_RWSEM_GENERIC_SPINLOCK is not set
+CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_HAVE_DEC_LOCK=y
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_ADVANCED_OPTIONS=y
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+CONFIG_MODVERSIONS=y
+# CONFIG_KMOD is not set
+
+#
+# Platform support
+#
+CONFIG_PPC=y
+CONFIG_PPC32=y
+# CONFIG_6xx is not set
+CONFIG_40x=y
+# CONFIG_44x is not set
+# CONFIG_POWER3 is not set
+# CONFIG_POWER4 is not set
+# CONFIG_8xx is not set
+CONFIG_4xx=y
+# CONFIG_PPC_STD_MMU is not set
+# CONFIG_ARCTIC2 is not set
+# CONFIG_ASH is not set
+# CONFIG_CEDER is not set
+# CONFIG_BEECH is not set
+# CONFIG_CPCI405 is not set
+# CONFIG_EP405 is not set
+# CONFIG_EVB405EP is not set
+# CONFIG_OAK is not set
+# CONFIG_RAINIER is not set
+# CONFIG_REDWOOD_4 is not set
+# CONFIG_REDWOOD_5 is not set
+# CONFIG_REDWOOD_6 is not set
+# CONFIG_SYCAMORE is not set
+# CONFIG_TIVO is not set
+# CONFIG_WALNUT is not set
+# CONFIG_PEPPERCON_405GP is not set
+CONFIG_PEPPERCON_405EP=y
+# CONFIG_XILINX_ML300 is not set
+# CONFIG_ALL_PPC is not set
+# CONFIG_SMP is not set
+# CONFIG_MATH_EMULATION is not set
+CONFIG_BIGPHYS_AREA=y
+CONFIG_NOT_COHERENT_CACHE=y
+CONFIG_UART0_TTYS0=y
+# CONFIG_UART0_TTYS1 is not set
+# CONFIG_PM is not set
+CONFIG_PEPPERCON=y
+CONFIG_405EP=y
+CONFIG_IBM_OCP=y
+CONFIG_PPC_OCP=y
+CONFIG_GEN550=y
+CONFIG_405=y
+CONFIG_IBM405_ERR51=y
+CONFIG_IBM405_ERR77=y
+CONFIG_PPC4xx_DMA=y
+CONFIG_PPC4xx_EDMA=y
+CONFIG_OCP_PROC=y
+
+#
+# General setup
+#
+# CONFIG_HIGHMEM is not set
+# CONFIG_LOWMEM_SIZE_BOOL is not set
+# CONFIG_KERNEL_START_BOOL is not set
+# CONFIG_TASK_SIZE_BOOL is not set
+# CONFIG_PIN_TLB is not set
+CONFIG_HIGHMEM_START=0xfe000000
+CONFIG_LOWMEM_SIZE=0x30000000
+CONFIG_KERNEL_START=0xc0000000
+CONFIG_TASK_SIZE=0x80000000
+# CONFIG_ISA is not set
+# CONFIG_EISA is not set
+# CONFIG_SBUS is not set
+# CONFIG_MCA is not set
+CONFIG_PCI=y
+# CONFIG_8260_PCI9 is not set
+# CONFIG_PC_KEYBOARD is not set
+CONFIG_NET=y
+CONFIG_SYSCTL=y
+CONFIG_SYSVIPC=y
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_KCORE_ELF=y
+CONFIG_BINFMT_ELF=y
+CONFIG_KERNEL_ELF=y
+# CONFIG_BINFMT_MISC is not set
+# CONFIG_OOM_KILLER is not set
+# CONFIG_PCI_NAMES is not set
+# CONFIG_HOTPLUG is not set
+# CONFIG_PCMCIA is not set
+
+#
+# PCI Hotplug Support
+#
+# CONFIG_HOTPLUG_PCI is not set
+# CONFIG_HOTPLUG_PCI_DUMMY is not set
+# CONFIG_HOTPLUG_PCI_COMPAQ is not set
+# CONFIG_HOTPLUG_PCI_COMPAQ_NVRAM is not set
+# CONFIG_HOTPLUG is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+# CONFIG_GEN_RTC is not set
+# CONFIG_PPC_RTC is not set
+CONFIG_CMDLINE_BOOL=y
+CONFIG_CMDLINE="console=ttyS0,115200 root=/dev/nfs nfsroot=192.168.1.24:/eric_root_devel.miba ip=192.168.1.20:192.168.1.24"
+
+#
+# Memory Technology Devices (MTD)
+#
+CONFIG_MTD=m
+# CONFIG_MTD_DEBUG is not set
+CONFIG_MTD_PARTITIONS=m
+# CONFIG_MTD_CONCAT is not set
+# CONFIG_MTD_REDBOOT_PARTS is not set
+CONFIG_MTD_CMDLINE_PARTS=m
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=m
+CONFIG_MTD_BLOCK=m
+# CONFIG_MTD_BLOCK_RO is not set
+CONFIG_FTL=m
+# CONFIG_NFTL is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+CONFIG_MTD_CFI=m
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_GEN_PROBE=m
+CONFIG_MTD_CFI_ADV_OPTIONS=y
+CONFIG_MTD_CFI_NOSWAP=y
+# CONFIG_MTD_CFI_BE_BYTE_SWAP is not set
+# CONFIG_MTD_CFI_LE_BYTE_SWAP is not set
+CONFIG_MTD_CFI_GEOMETRY=y
+# CONFIG_MTD_CFI_B1 is not set
+CONFIG_MTD_CFI_B2=y
+# CONFIG_MTD_CFI_B4 is not set
+# CONFIG_MTD_CFI_B8 is not set
+CONFIG_MTD_CFI_I1=y
+# CONFIG_MTD_CFI_I2 is not set
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+CONFIG_MTD_CFI_INTELEXT=m
+# CONFIG_MTD_CFI_AMDSTD is not set
+# CONFIG_MTD_CFI_STAA is not set
+# CONFIG_MTD_RAM is not set
+CONFIG_MTD_ROM=m
+# 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_PHYSMAP=m
+CONFIG_MTD_PHYSMAP_BUSWIDTH=2
+# CONFIG_MTD_BEECH is not set
+# CONFIG_MTD_ARCTIC 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
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC1000 is not set
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOCPROBE is not set
+
+#
+# NAND Flash Device Drivers
+#
+# CONFIG_MTD_NAND 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_LOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=8192
+CONFIG_BLK_DEV_INITRD=y
+# 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 is not set
+CONFIG_NETFILTER=y
+# CONFIG_NETFILTER_DEBUG is not set
+# CONFIG_FILTER is not set
+CONFIG_UNIX=y
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_PNP=y
+# CONFIG_IP_PNP_DHCP is not set
+CONFIG_IP_PNP_BOOTP=y
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_IP_MROUTE is not set
+# CONFIG_ARPD is not set
+# CONFIG_INET_ECN is not set
+# CONFIG_SYN_COOKIES is not set
+
+#
+#   IP: Netfilter Configuration
+#
+CONFIG_IP_NF_CONNTRACK=y
+# CONFIG_IP_NF_FTP is not set
+# CONFIG_IP_NF_AMANDA is not set
+# CONFIG_IP_NF_TFTP is not set
+# CONFIG_IP_NF_IRC is not set
+CONFIG_IP_NF_QUEUE=y
+CONFIG_IP_NF_IPTABLES=y
+# CONFIG_IP_NF_MATCH_LIMIT is not set
+CONFIG_IP_NF_MATCH_MAC=y
+# CONFIG_IP_NF_MATCH_PKTTYPE is not set
+CONFIG_IP_NF_MATCH_MARK=y
+# CONFIG_IP_NF_MATCH_MULTIPORT is not set
+# CONFIG_IP_NF_MATCH_TOS is not set
+# CONFIG_IP_NF_MATCH_RECENT is not set
+# CONFIG_IP_NF_MATCH_ECN is not set
+# CONFIG_IP_NF_MATCH_DSCP is not set
+# CONFIG_IP_NF_MATCH_AH_ESP is not set
+# CONFIG_IP_NF_MATCH_LENGTH is not set
+# CONFIG_IP_NF_MATCH_TTL is not set
+# CONFIG_IP_NF_MATCH_TCPMSS is not set
+# CONFIG_IP_NF_MATCH_HELPER is not set
+# CONFIG_IP_NF_MATCH_STATE is not set
+# CONFIG_IP_NF_MATCH_CONNTRACK is not set
+# CONFIG_IP_NF_MATCH_UNCLEAN is not set
+# CONFIG_IP_NF_MATCH_OWNER is not set
+CONFIG_IP_NF_FILTER=y
+CONFIG_IP_NF_TARGET_REJECT=y
+# CONFIG_IP_NF_TARGET_MIRROR is not set
+CONFIG_IP_NF_FASTNAT=y
+CONFIG_IP_NF_TARGET_FASTNAT=y
+CONFIG_IP_NF_NAT=y
+CONFIG_IP_NF_NAT_NEEDED=y
+# CONFIG_IP_NF_TARGET_MASQUERADE is not set
+CONFIG_IP_NF_TARGET_REDIRECT=y
+CONFIG_IP_NF_NAT_LOCAL=y
+# CONFIG_IP_NF_NAT_SNMP_BASIC is not set
+CONFIG_IP_NF_MANGLE=y
+# CONFIG_IP_NF_TARGET_TOS is not set
+# CONFIG_IP_NF_TARGET_ECN is not set
+# CONFIG_IP_NF_TARGET_DSCP is not set
+CONFIG_IP_NF_TARGET_MARK=y
+# CONFIG_IP_NF_TARGET_LOG is not set
+# CONFIG_IP_NF_TARGET_ULOG is not set
+# CONFIG_IP_NF_TARGET_TCPMSS is not set
+# CONFIG_IP_NF_ARPTABLES is not set
+
+#
+#   IP: Virtual Server Configuration
+#
+CONFIG_IP_VS=y
+# CONFIG_IP_VS_DEBUG is not set
+CONFIG_IP_VS_TAB_BITS=12
+
+#
+# IPVS scheduler
+#
+CONFIG_IP_VS_RR=y
+CONFIG_IP_VS_WRR=y
+CONFIG_IP_VS_LC=y
+CONFIG_IP_VS_WLC=y
+CONFIG_IP_VS_LBLC=y
+CONFIG_IP_VS_LBLCR=y
+CONFIG_IP_VS_DH=y
+CONFIG_IP_VS_SH=y
+CONFIG_IP_VS_SED=y
+CONFIG_IP_VS_NQ=y
+
+#
+# IPVS application helper
+#
+# CONFIG_IP_VS_FTP is not set
+CONFIG_IPV6=y
+
+#
+#   IPv6: Netfilter Configuration
+#
+# CONFIG_IP6_NF_QUEUE is not set
+# CONFIG_IP6_NF_IPTABLES is not set
+# CONFIG_KHTTPD is not set
+
+#
+#    SCTP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_SCTP is not set
+# CONFIG_ATM is not set
+# CONFIG_VLAN_8021Q is not set
+
+#
+#  
+#
+# 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=y
+# 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 is not set
+# CONFIG_NET_SCH_HTB is not set
+# CONFIG_NET_SCH_CSZ is not set
+# CONFIG_NET_SCH_HFSC is not set
+# CONFIG_NET_SCH_PRIO is not set
+# CONFIG_NET_SCH_RED is not set
+# CONFIG_NET_SCH_SFQ is not set
+# CONFIG_NET_SCH_TEQL is not set
+CONFIG_NET_SCH_TBF=y
+# CONFIG_NET_SCH_GRED is not set
+# CONFIG_NET_SCH_DELAY is not set
+# CONFIG_NET_SCH_DSMARK is not set
+# CONFIG_NET_SCH_INGRESS is not set
+# CONFIG_NET_QOS is not set
+# CONFIG_NET_CLS is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+
+#
+# ATA/IDE/MFM/RLL support
+#
+# CONFIG_IDE is not set
+# CONFIG_BLK_DEV_HD is not set
+
+#
+# SCSI support
+#
+# CONFIG_SCSI 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 is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+# CONFIG_ETHERTAP is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+# CONFIG_MACE is not set
+# CONFIG_BMAC is not set
+# CONFIG_GMAC 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
+
+#
+# Backplane Networking
+#
+# CONFIG_NPNET is not set
+
+#
+# On-chip net devices
+#
+CONFIG_IBM_OCP_ENET=y
+# CONFIG_IBM_OCP_ENET_ERROR_MSG is not set
+CONFIG_IBM_OCP_ENET_RX_BUFF=64
+CONFIG_IBM_OCP_ENET_TX_BUFF=8
+CONFIG_IBM_OCP_ENET_GAP=4
+CONFIG_IBM_OCP_ENET_SKB_RES=2
+CONFIG_OCP_NET=y
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+# CONFIG_PLIP is not set
+CONFIG_PPP=y
+# CONFIG_PPP_MULTILINK is not set
+# CONFIG_PPP_FILTER is not set
+CONFIG_PPP_ASYNC=y
+# CONFIG_PPP_SYNC_TTY is not set
+CONFIG_PPP_DEFLATE=y
+CONFIG_PPP_BSDCOMP=y
+# CONFIG_PPPOE is not set
+# CONFIG_SLIP is not set
+
+#
+# Wireless LAN (non-hamradio)
+#
+# CONFIG_NET_RADIO is not set
+
+#
+# Token Ring devices
+#
+# CONFIG_TR is not set
+# CONFIG_NET_FC is not set
+# CONFIG_RCPCI is not set
+# CONFIG_SHAPER is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN 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
+
+#
+# Old CD-ROM drivers (not SCSI, not IDE)
+#
+# CONFIG_CD_NO_IDESCSI is not set
+
+#
+# Console drivers
+#
+CONFIG_DUMMY_CONSOLE=y
+
+#
+# Frame-buffer support
+#
+# CONFIG_FB 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
+
+#
+# Macintosh device drivers
+#
+
+#
+# Character devices
+#
+CONFIG_VT=y
+# CONFIG_VT_CONSOLE is not set
+CONFIG_SERIAL=y
+CONFIG_SERIAL_CONSOLE=y
+# CONFIG_SERIAL_EXTENDED is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+CONFIG_UNIX98_PTYS=y
+CONFIG_UNIX98_PTY_COUNT=256
+
+#
+# I2C support
+#
+CONFIG_I2C=y
+CONFIG_I2C_SLAVE=y
+# CONFIG_I2C_ALGOBIT is not set
+# CONFIG_SCx200_ACB is not set
+# CONFIG_I2C_ALGOPCF is not set
+CONFIG_I2C_IBM_IIC=y
+# CONFIG_I2C_ASICSMS is not set
+CONFIG_I2C_CHARDEV=y
+CONFIG_I2C_PROC=y
+
+#
+# Mice
+#
+# CONFIG_BUSMOUSE is not set
+# CONFIG_MOUSE is not set
+
+#
+# Joysticks
+#
+# CONFIG_INPUT_GAMEPORT is not set
+
+#
+# Input core support is needed for gameports
+#
+
+#
+# Input core support is needed for joysticks
+#
+# 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=y
+CONFIG_WATCHDOG_NOWAYOUT=y
+# CONFIG_ACQUIRE_WDT is not set
+# CONFIG_ADVANTECH_WDT is not set
+# CONFIG_ALIM1535_WDT is not set
+# CONFIG_ALIM7101_WDT is not set
+# CONFIG_SC520_WDT is not set
+# CONFIG_PCWATCHDOG is not set
+# CONFIG_EUROTECH_WDT is not set
+# CONFIG_IB700_WDT is not set
+CONFIG_PPC405_WDT=y
+# CONFIG_WAFER_WDT is not set
+# CONFIG_I810_TCO is not set
+# CONFIG_MIXCOMWD is not set
+# CONFIG_60XX_WDT is not set
+# CONFIG_SC1200_WDT is not set
+# CONFIG_SCx200_WDT is not set
+# CONFIG_SOFT_WATCHDOG is not set
+# CONFIG_W83877F_WDT is not set
+# CONFIG_WDT is not set
+# CONFIG_WDTPCI is not set
+# CONFIG_MACHZ_WDT is not set
+# CONFIG_AMD7XX_TCO 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_X1226_RTC=y
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+# CONFIG_IBM_OCP_GPIO 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
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV 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 is not set
+# 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 is not set
+# CONFIG_JBD is not set
+# CONFIG_JBD_DEBUG is not set
+# CONFIG_FAT_FS is not set
+# CONFIG_MSDOS_FS is not set
+# CONFIG_UMSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_JFFS_FS is not set
+CONFIG_JFFS2_FS=m
+CONFIG_JFFS2_FS_DEBUG=0
+# CONFIG_CRAMFS is not set
+# CONFIG_TMPFS is not set
+CONFIG_RAMFS=y
+# CONFIG_ISO9660_FS is not set
+# CONFIG_JOLIET is not set
+# CONFIG_ZISOFS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_JFS_DEBUG is not set
+# CONFIG_JFS_STATISTICS is not set
+CONFIG_MINIX_FS=y
+# CONFIG_VXFS_FS is not set
+# CONFIG_NTFS_FS is not set
+# CONFIG_NTFS_RW is not set
+# CONFIG_HPFS_FS is not set
+CONFIG_PROC_FS=y
+# CONFIG_DEVFS_FS is not set
+# CONFIG_DEVFS_MOUNT is not set
+# 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=y
+# 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 is not set
+# CONFIG_NFSD_V3 is not set
+# CONFIG_NFSD_TCP is not set
+CONFIG_SUNRPC=y
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_SMB_FS=y
+# 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 is not set
+
+#
+# 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-1"
+# CONFIG_NLS_CODEPAGE_437 is not set
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# 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 is not set
+# 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 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# IBM 4xx options
+#
+
+#
+# USB support
+#
+# CONFIG_USB is not set
+
+#
+# Support for USB gadgets
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# Bluetooth support
+#
+# CONFIG_BLUEZ is not set
+
+#
+# Cryptographic options
+#
+CONFIG_CRYPTO=y
+CONFIG_CRYPTO_HMAC=y
+CONFIG_CRYPTO_NULL=y
+# CONFIG_CRYPTO_MD4 is not set
+# CONFIG_CRYPTO_MD5 is not set
+# CONFIG_CRYPTO_SHA1 is not set
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_DES is not set
+# CONFIG_CRYPTO_BLOWFISH is not set
+# CONFIG_CRYPTO_TWOFISH is not set
+# CONFIG_CRYPTO_SERPENT is not set
+CONFIG_CRYPTO_AES=y
+# CONFIG_CRYPTO_CAST5 is not set
+# CONFIG_CRYPTO_CAST6 is not set
+# CONFIG_CRYPTO_ARC4 is not set
+# CONFIG_CRYPTO_DEFLATE is not set
+# CONFIG_CRYPTO_TEST is not set
+
+#
+# Library routines
+#
+# CONFIG_CRC32 is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
+
+#
+# Kernel hacking
+#
+# CONFIG_DEBUG_KERNEL is not set
+# CONFIG_SERIAL_TEXT_DEBUG is not set
+CONFIG_LOG_BUF_SHIFT=0
Index: pplinux/linuxnew/arch/ppc/configs/lara_kim_production_defconfig
diff -u /dev/null pplinux/linuxnew/arch/ppc/configs/lara_kim_production_defconfig:1.1
--- /dev/null	Tue May 24 10:37:58 2005
+++ pplinux/linuxnew/arch/ppc/configs/lara_kim_production_defconfig	Tue Feb 15 12:16:24 2005
@@ -0,0 +1,870 @@
+#
+# Automatically generated make config: don't edit
+#
+# CONFIG_UID16 is not set
+# CONFIG_RWSEM_GENERIC_SPINLOCK is not set
+CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_HAVE_DEC_LOCK=y
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_ADVANCED_OPTIONS=y
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+CONFIG_MODVERSIONS=y
+# CONFIG_KMOD is not set
+
+#
+# Platform support
+#
+CONFIG_PPC=y
+CONFIG_PPC32=y
+# CONFIG_6xx is not set
+CONFIG_40x=y
+# CONFIG_44x is not set
+# CONFIG_POWER3 is not set
+# CONFIG_POWER4 is not set
+# CONFIG_8xx is not set
+CONFIG_4xx=y
+# CONFIG_PPC_STD_MMU is not set
+# CONFIG_ARCTIC2 is not set
+# CONFIG_ASH is not set
+# CONFIG_CEDER is not set
+# CONFIG_BEECH is not set
+# CONFIG_CPCI405 is not set
+# CONFIG_EP405 is not set
+# CONFIG_EVB405EP is not set
+# CONFIG_OAK is not set
+# CONFIG_RAINIER is not set
+# CONFIG_REDWOOD_4 is not set
+# CONFIG_REDWOOD_5 is not set
+# CONFIG_REDWOOD_6 is not set
+# CONFIG_SYCAMORE is not set
+# CONFIG_TIVO is not set
+# CONFIG_WALNUT is not set
+# CONFIG_PEPPERCON_405GP is not set
+CONFIG_PEPPERCON_405EP=y
+# CONFIG_XILINX_ML300 is not set
+# CONFIG_ALL_PPC is not set
+# CONFIG_SMP is not set
+# CONFIG_MATH_EMULATION is not set
+CONFIG_BIGPHYS_AREA=y
+CONFIG_NOT_COHERENT_CACHE=y
+CONFIG_UART0_TTYS0=y
+# CONFIG_UART0_TTYS1 is not set
+# CONFIG_PM is not set
+CONFIG_PEPPERCON=y
+CONFIG_405EP=y
+CONFIG_IBM_OCP=y
+CONFIG_PPC_OCP=y
+CONFIG_GEN550=y
+CONFIG_405=y
+CONFIG_IBM405_ERR51=y
+CONFIG_IBM405_ERR77=y
+CONFIG_PPC4xx_DMA=y
+CONFIG_PPC4xx_EDMA=y
+CONFIG_OCP_PROC=y
+
+#
+# General setup
+#
+# CONFIG_HIGHMEM is not set
+# CONFIG_LOWMEM_SIZE_BOOL is not set
+# CONFIG_KERNEL_START_BOOL is not set
+# CONFIG_TASK_SIZE_BOOL is not set
+# CONFIG_PIN_TLB is not set
+CONFIG_HIGHMEM_START=0xfe000000
+CONFIG_LOWMEM_SIZE=0x30000000
+CONFIG_KERNEL_START=0xc0000000
+CONFIG_TASK_SIZE=0x80000000
+# CONFIG_ISA is not set
+# CONFIG_EISA is not set
+# CONFIG_SBUS is not set
+# CONFIG_MCA is not set
+CONFIG_PCI=y
+# CONFIG_8260_PCI9 is not set
+# CONFIG_PC_KEYBOARD is not set
+CONFIG_NET=y
+CONFIG_SYSCTL=y
+CONFIG_SYSVIPC=y
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_KCORE_ELF=y
+CONFIG_BINFMT_ELF=y
+CONFIG_KERNEL_ELF=y
+# CONFIG_BINFMT_MISC is not set
+# CONFIG_OOM_KILLER is not set
+# CONFIG_PCI_NAMES is not set
+# CONFIG_HOTPLUG is not set
+# CONFIG_PCMCIA is not set
+
+#
+# PCI Hotplug Support
+#
+# CONFIG_HOTPLUG_PCI is not set
+# CONFIG_HOTPLUG_PCI_DUMMY is not set
+# CONFIG_HOTPLUG_PCI_COMPAQ is not set
+# CONFIG_HOTPLUG_PCI_COMPAQ_NVRAM is not set
+# CONFIG_HOTPLUG is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+# CONFIG_GEN_RTC is not set
+# CONFIG_PPC_RTC is not set
+CONFIG_CMDLINE_BOOL=y
+CONFIG_CMDLINE="console=ttyS0,115200 root=/dev/nfs nfsroot=192.168.1.24:/eric_root_devel.miba ip=192.168.1.20:192.168.1.24"
+
+#
+# Memory Technology Devices (MTD)
+#
+CONFIG_MTD=m
+# CONFIG_MTD_DEBUG is not set
+CONFIG_MTD_PARTITIONS=m
+# CONFIG_MTD_CONCAT is not set
+# CONFIG_MTD_REDBOOT_PARTS is not set
+CONFIG_MTD_CMDLINE_PARTS=m
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=m
+CONFIG_MTD_BLOCK=m
+# CONFIG_MTD_BLOCK_RO is not set
+CONFIG_FTL=m
+# CONFIG_NFTL is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+CONFIG_MTD_CFI=m
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_GEN_PROBE=m
+CONFIG_MTD_CFI_ADV_OPTIONS=y
+CONFIG_MTD_CFI_NOSWAP=y
+# CONFIG_MTD_CFI_BE_BYTE_SWAP is not set
+# CONFIG_MTD_CFI_LE_BYTE_SWAP is not set
+CONFIG_MTD_CFI_GEOMETRY=y
+# CONFIG_MTD_CFI_B1 is not set
+CONFIG_MTD_CFI_B2=y
+# CONFIG_MTD_CFI_B4 is not set
+# CONFIG_MTD_CFI_B8 is not set
+CONFIG_MTD_CFI_I1=y
+# CONFIG_MTD_CFI_I2 is not set
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+CONFIG_MTD_CFI_INTELEXT=m
+# CONFIG_MTD_CFI_AMDSTD is not set
+# CONFIG_MTD_CFI_STAA is not set
+# CONFIG_MTD_RAM is not set
+CONFIG_MTD_ROM=m
+# 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_PHYSMAP=m
+CONFIG_MTD_PHYSMAP_BUSWIDTH=2
+# CONFIG_MTD_BEECH is not set
+# CONFIG_MTD_ARCTIC 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
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC1000 is not set
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOCPROBE is not set
+
+#
+# NAND Flash Device Drivers
+#
+# CONFIG_MTD_NAND 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_LOOP=y
+# CONFIG_BLK_DEV_NBD is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=8192
+CONFIG_BLK_DEV_INITRD=y
+# 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 is not set
+# CONFIG_NETLINK_DEV is not set
+CONFIG_NETFILTER=y
+# CONFIG_NETFILTER_DEBUG is not set
+# CONFIG_FILTER is not set
+CONFIG_UNIX=y
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_PNP=y
+# CONFIG_IP_PNP_DHCP is not set
+CONFIG_IP_PNP_BOOTP=y
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
+# CONFIG_INET_ECN is not set
+# CONFIG_SYN_COOKIES is not set
+
+#
+#   IP: Netfilter Configuration
+#
+# CONFIG_IP_NF_CONNTRACK is not set
+CONFIG_IP_NF_QUEUE=y
+CONFIG_IP_NF_IPTABLES=y
+# CONFIG_IP_NF_MATCH_LIMIT is not set
+# CONFIG_IP_NF_MATCH_MAC is not set
+# CONFIG_IP_NF_MATCH_PKTTYPE is not set
+# CONFIG_IP_NF_MATCH_MARK is not set
+# CONFIG_IP_NF_MATCH_MULTIPORT is not set
+# CONFIG_IP_NF_MATCH_TOS is not set
+# CONFIG_IP_NF_MATCH_RECENT is not set
+# CONFIG_IP_NF_MATCH_ECN is not set
+# CONFIG_IP_NF_MATCH_DSCP is not set
+# CONFIG_IP_NF_MATCH_AH_ESP is not set
+# CONFIG_IP_NF_MATCH_LENGTH is not set
+# CONFIG_IP_NF_MATCH_TTL is not set
+# CONFIG_IP_NF_MATCH_TCPMSS is not set
+# CONFIG_IP_NF_MATCH_UNCLEAN is not set
+# CONFIG_IP_NF_MATCH_OWNER is not set
+CONFIG_IP_NF_FILTER=y
+CONFIG_IP_NF_TARGET_REJECT=y
+# CONFIG_IP_NF_TARGET_MIRROR is not set
+CONFIG_IP_NF_FASTNAT=y
+CONFIG_IP_NF_TARGET_FASTNAT=y
+# CONFIG_IP_NF_MANGLE is not set
+# CONFIG_IP_NF_TARGET_LOG is not set
+# CONFIG_IP_NF_TARGET_ULOG is not set
+# CONFIG_IP_NF_TARGET_TCPMSS is not set
+# CONFIG_IP_NF_ARPTABLES is not set
+
+#
+#   IP: Virtual Server Configuration
+#
+# CONFIG_IP_VS is not set
+CONFIG_IPV6=y
+
+#
+#   IPv6: Netfilter Configuration
+#
+# CONFIG_IP6_NF_QUEUE is not set
+CONFIG_IP6_NF_IPTABLES=m
+# CONFIG_IP6_NF_MATCH_LIMIT is not set
+# CONFIG_IP6_NF_MATCH_MAC is not set
+# CONFIG_IP6_NF_MATCH_RT is not set
+# CONFIG_IP6_NF_MATCH_OPTS is not set
+# CONFIG_IP6_NF_MATCH_FRAG is not set
+# CONFIG_IP6_NF_MATCH_HL is not set
+# CONFIG_IP6_NF_MATCH_MULTIPORT is not set
+# CONFIG_IP6_NF_MATCH_OWNER is not set
+# CONFIG_IP6_NF_MATCH_MARK is not set
+# CONFIG_IP6_NF_MATCH_IPV6HEADER is not set
+# CONFIG_IP6_NF_MATCH_AHESP is not set
+# CONFIG_IP6_NF_MATCH_LENGTH is not set
+# CONFIG_IP6_NF_MATCH_EUI64 is not set
+CONFIG_IP6_NF_FILTER=m
+# CONFIG_IP6_NF_TARGET_LOG is not set
+# CONFIG_IP6_NF_MANGLE is not set
+# CONFIG_KHTTPD is not set
+
+#
+#    SCTP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_SCTP is not set
+# CONFIG_ATM is not set
+# CONFIG_VLAN_8021Q is not set
+
+#
+#  
+#
+# 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 is not set
+# 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 is not set
+# CONFIG_NET_SCH_HTB is not set
+# CONFIG_NET_SCH_CSZ is not set
+# CONFIG_NET_SCH_HFSC is not set
+# CONFIG_NET_SCH_PRIO is not set
+# CONFIG_NET_SCH_RED is not set
+# CONFIG_NET_SCH_SFQ is not set
+# CONFIG_NET_SCH_TEQL is not set
+CONFIG_NET_SCH_TBF=y
+# CONFIG_NET_SCH_GRED is not set
+# CONFIG_NET_SCH_DELAY is not set
+# CONFIG_NET_SCH_DSMARK is not set
+# CONFIG_NET_SCH_INGRESS is not set
+# CONFIG_NET_QOS is not set
+# CONFIG_NET_CLS is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+
+#
+# ATA/IDE/MFM/RLL support
+#
+# CONFIG_IDE is not set
+# CONFIG_BLK_DEV_HD is not set
+
+#
+# SCSI support
+#
+# CONFIG_SCSI 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 is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+# CONFIG_ETHERTAP is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+# CONFIG_MACE is not set
+# CONFIG_BMAC is not set
+# CONFIG_GMAC 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
+
+#
+# Backplane Networking
+#
+# CONFIG_NPNET is not set
+
+#
+# On-chip net devices
+#
+CONFIG_IBM_OCP_ENET=y
+# CONFIG_IBM_OCP_ENET_ERROR_MSG is not set
+CONFIG_IBM_OCP_ENET_RX_BUFF=64
+CONFIG_IBM_OCP_ENET_TX_BUFF=8
+CONFIG_IBM_OCP_ENET_GAP=4
+CONFIG_IBM_OCP_ENET_SKB_RES=0
+CONFIG_OCP_NET=y
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+# CONFIG_PLIP is not set
+CONFIG_PPP=y
+# CONFIG_PPP_MULTILINK is not set
+# CONFIG_PPP_FILTER is not set
+CONFIG_PPP_ASYNC=y
+# CONFIG_PPP_SYNC_TTY is not set
+CONFIG_PPP_DEFLATE=y
+CONFIG_PPP_BSDCOMP=y
+# CONFIG_PPPOE is not set
+# CONFIG_SLIP is not set
+
+#
+# Wireless LAN (non-hamradio)
+#
+# CONFIG_NET_RADIO is not set
+
+#
+# Token Ring devices
+#
+# CONFIG_TR is not set
+# CONFIG_NET_FC is not set
+# CONFIG_RCPCI is not set
+# CONFIG_SHAPER is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+
+#
+# Amateur Radio support
+#
+# CONFIG_HAMRADIO is not set
+
+#
+# IrDA (infrared) support
+#
+# CONFIG_IRDA is not set
+
+#
+# ISDN subsystem
+#
+CONFIG_ISDN=m
+CONFIG_ISDN_BOOL=y
+CONFIG_ISDN_PPP=y
+# CONFIG_IPPP_FILTER is not set
+CONFIG_ISDN_PPP_VJ=y
+CONFIG_ISDN_MPP=y
+CONFIG_ISDN_PPP_BSDCOMP=m
+# CONFIG_ISDN_AUDIO is not set
+
+#
+# ISDN feature submodules
+#
+# CONFIG_ISDN_DRV_LOOP is not set
+# CONFIG_ISDN_DIVERSION is not set
+
+#
+# low-level hardware drivers
+#
+
+#
+# Passive ISDN cards
+#
+CONFIG_ISDN_DRV_HISAX=m
+CONFIG_ISDN_HISAX=y
+
+#
+#   D-channel protocol features
+#
+CONFIG_HISAX_EURO=y
+# CONFIG_DE_AOC is not set
+# CONFIG_HISAX_NO_SENDCOMPLETE is not set
+# CONFIG_HISAX_NO_LLC is not set
+# CONFIG_HISAX_NO_KEYPAD is not set
+# CONFIG_HISAX_1TR6 is not set
+# CONFIG_HISAX_NI1 is not set
+CONFIG_HISAX_MAX_CARDS=8
+
+#
+#   HiSax supported cards
+#
+# CONFIG_HISAX_TELESPCI is not set
+# CONFIG_HISAX_S0BOX is not set
+# CONFIG_HISAX_FRITZPCI is not set
+# CONFIG_HISAX_AVM_A1_PCMCIA is not set
+# CONFIG_HISAX_ELSA is not set
+# CONFIG_HISAX_DIEHLDIVA is not set
+# CONFIG_HISAX_SEDLBAUER is not set
+# CONFIG_HISAX_NETJET is not set
+# CONFIG_HISAX_NETJET_U is not set
+# CONFIG_HISAX_NICCY is not set
+# CONFIG_HISAX_BKM_A4T is not set
+# CONFIG_HISAX_SCT_QUADRO is not set
+# CONFIG_HISAX_GAZEL is not set
+CONFIG_HISAX_HFC_PCI=y
+# CONFIG_HISAX_W6692 is not set
+# CONFIG_HISAX_HFC_SX is not set
+# CONFIG_HISAX_ENTERNOW_PCI is not set
+# CONFIG_HISAX_DEBUG is not set
+# CONFIG_HISAX_SEDLBAUER_CS is not set
+# CONFIG_HISAX_ELSA_CS is not set
+# CONFIG_HISAX_AVM_A1_CS is not set
+# CONFIG_HISAX_ST5481 is not set
+# CONFIG_HISAX_FRITZ_PCIPNP is not set
+# CONFIG_USB_AUERISDN is not set
+
+#
+# Active ISDN cards
+#
+# CONFIG_ISDN_DRV_ICN is not set
+# CONFIG_ISDN_DRV_PCBIT is not set
+# CONFIG_ISDN_DRV_SC is not set
+# CONFIG_ISDN_DRV_ACT2000 is not set
+# CONFIG_ISDN_DRV_EICON is not set
+# CONFIG_ISDN_DRV_TPAM is not set
+# CONFIG_ISDN_CAPI is not set
+# CONFIG_HYSDN is not set
+# CONFIG_HYSDN_CAPI is not set
+
+#
+# Old CD-ROM drivers (not SCSI, not IDE)
+#
+# CONFIG_CD_NO_IDESCSI is not set
+
+#
+# Console drivers
+#
+CONFIG_DUMMY_CONSOLE=y
+
+#
+# Frame-buffer support
+#
+# CONFIG_FB 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
+
+#
+# Macintosh device drivers
+#
+
+#
+# Character devices
+#
+CONFIG_VT=y
+# CONFIG_VT_CONSOLE is not set
+CONFIG_SERIAL=y
+CONFIG_SERIAL_CONSOLE=y
+# CONFIG_SERIAL_EXTENDED is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+CONFIG_UNIX98_PTYS=y
+CONFIG_UNIX98_PTY_COUNT=256
+
+#
+# I2C support
+#
+CONFIG_I2C=m
+CONFIG_I2C_SLAVE=m
+# CONFIG_I2C_ALGOBIT is not set
+# CONFIG_SCx200_ACB is not set
+# CONFIG_I2C_ALGOPCF is not set
+CONFIG_I2C_IBM_IIC=m
+# CONFIG_I2C_ASICSMS is not set
+CONFIG_I2C_CHARDEV=m
+CONFIG_I2C_PROC=m
+
+#
+# Mice
+#
+# CONFIG_BUSMOUSE is not set
+# CONFIG_MOUSE is not set
+
+#
+# Joysticks
+#
+# CONFIG_INPUT_GAMEPORT is not set
+
+#
+# Input core support is needed for gameports
+#
+
+#
+# Input core support is needed for joysticks
+#
+# 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=y
+CONFIG_WATCHDOG_NOWAYOUT=y
+# CONFIG_ACQUIRE_WDT is not set
+# CONFIG_ADVANTECH_WDT is not set
+# CONFIG_ALIM1535_WDT is not set
+# CONFIG_ALIM7101_WDT is not set
+# CONFIG_SC520_WDT is not set
+# CONFIG_PCWATCHDOG is not set
+# CONFIG_EUROTECH_WDT is not set
+# CONFIG_IB700_WDT is not set
+CONFIG_PPC405_WDT=y
+# CONFIG_WAFER_WDT is not set
+# CONFIG_I810_TCO is not set
+# CONFIG_MIXCOMWD is not set
+# CONFIG_60XX_WDT is not set
+# CONFIG_SC1200_WDT is not set
+# CONFIG_SCx200_WDT is not set
+# CONFIG_SOFT_WATCHDOG is not set
+# CONFIG_W83877F_WDT is not set
+# CONFIG_WDT is not set
+# CONFIG_WDTPCI is not set
+# CONFIG_MACHZ_WDT is not set
+# CONFIG_AMD7XX_TCO 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_X1226_RTC=m
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+# CONFIG_IBM_OCP_GPIO 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
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV 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 is not set
+# 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 is not set
+# CONFIG_JBD is not set
+# CONFIG_JBD_DEBUG is not set
+# CONFIG_FAT_FS is not set
+# CONFIG_MSDOS_FS is not set
+# CONFIG_UMSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_JFFS_FS is not set
+CONFIG_JFFS2_FS=m
+CONFIG_JFFS2_FS_DEBUG=0
+# CONFIG_CRAMFS is not set
+# CONFIG_TMPFS is not set
+CONFIG_RAMFS=y
+# CONFIG_ISO9660_FS is not set
+# CONFIG_JOLIET is not set
+# CONFIG_ZISOFS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_JFS_DEBUG is not set
+# CONFIG_JFS_STATISTICS is not set
+CONFIG_MINIX_FS=y
+# CONFIG_VXFS_FS is not set
+# CONFIG_NTFS_FS is not set
+# CONFIG_NTFS_RW is not set
+# CONFIG_HPFS_FS is not set
+CONFIG_PROC_FS=y
+# CONFIG_DEVFS_FS is not set
+# CONFIG_DEVFS_MOUNT is not set
+# 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=y
+# 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 is not set
+# CONFIG_NFSD_V3 is not set
+# CONFIG_NFSD_TCP is not set
+CONFIG_SUNRPC=y
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+# CONFIG_SMB_FS 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 is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_SMB_NLS is not set
+# CONFIG_NLS is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# IBM 4xx options
+#
+
+#
+# USB support
+#
+# CONFIG_USB is not set
+
+#
+# Support for USB gadgets
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# Bluetooth support
+#
+# CONFIG_BLUEZ is not set
+
+#
+# Cryptographic options
+#
+# CONFIG_CRYPTO is not set
+
+#
+# Library routines
+#
+# CONFIG_CRC32 is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
+
+#
+# Kernel hacking
+#
+# CONFIG_DEBUG_KERNEL is not set
+# CONFIG_SERIAL_TEXT_DEBUG is not set
+CONFIG_LOG_BUF_SHIFT=0
Index: pplinux/linuxnew/arch/ppc/configs/lara_kim_wlan_defconfig
diff -u /dev/null pplinux/linuxnew/arch/ppc/configs/lara_kim_wlan_defconfig:1.4
--- /dev/null	Tue May 24 10:37:58 2005
+++ pplinux/linuxnew/arch/ppc/configs/lara_kim_wlan_defconfig	Mon May  2 14:20:10 2005
@@ -0,0 +1,886 @@
+#
+# Automatically generated make config: don't edit
+#
+# CONFIG_UID16 is not set
+# CONFIG_RWSEM_GENERIC_SPINLOCK is not set
+CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_HAVE_DEC_LOCK=y
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_ADVANCED_OPTIONS=y
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+CONFIG_MODVERSIONS=y
+# CONFIG_KMOD is not set
+
+#
+# Platform support
+#
+CONFIG_PPC=y
+CONFIG_PPC32=y
+# CONFIG_6xx is not set
+CONFIG_40x=y
+# CONFIG_44x is not set
+# CONFIG_POWER3 is not set
+# CONFIG_POWER4 is not set
+# CONFIG_8xx is not set
+CONFIG_4xx=y
+# CONFIG_PPC_STD_MMU is not set
+# CONFIG_ARCTIC2 is not set
+# CONFIG_ASH is not set
+# CONFIG_CEDER is not set
+# CONFIG_BEECH is not set
+# CONFIG_CPCI405 is not set
+# CONFIG_EP405 is not set
+# CONFIG_EVB405EP is not set
+# CONFIG_OAK is not set
+# CONFIG_RAINIER is not set
+# CONFIG_REDWOOD_4 is not set
+# CONFIG_REDWOOD_5 is not set
+# CONFIG_REDWOOD_6 is not set
+# CONFIG_SYCAMORE is not set
+# CONFIG_TIVO is not set
+# CONFIG_WALNUT is not set
+CONFIG_PEPPERCON_405GP=y
+# CONFIG_PEPPERCON_405EP is not set
+# CONFIG_XILINX_ML300 is not set
+# CONFIG_ALL_PPC is not set
+# CONFIG_SMP is not set
+# CONFIG_MATH_EMULATION is not set
+CONFIG_BIGPHYS_AREA=y
+CONFIG_NOT_COHERENT_CACHE=y
+CONFIG_UART0_TTYS0=y
+# CONFIG_UART0_TTYS1 is not set
+# CONFIG_PM is not set
+CONFIG_PEPPERCON=y
+CONFIG_405GP=y
+CONFIG_IBM_OCP=y
+CONFIG_PPC_OCP=y
+CONFIG_GEN550=y
+CONFIG_405=y
+CONFIG_IBM405_ERR51=y
+CONFIG_IBM405_ERR77=y
+CONFIG_PPC4xx_DMA=y
+CONFIG_PPC4xx_EDMA=y
+CONFIG_OCP_PROC=y
+
+#
+# General setup
+#
+# CONFIG_HIGHMEM is not set
+# CONFIG_LOWMEM_SIZE_BOOL is not set
+# CONFIG_KERNEL_START_BOOL is not set
+# CONFIG_TASK_SIZE_BOOL is not set
+# CONFIG_PIN_TLB is not set
+CONFIG_HIGHMEM_START=0xfe000000
+CONFIG_LOWMEM_SIZE=0x30000000
+CONFIG_KERNEL_START=0xc0000000
+CONFIG_TASK_SIZE=0x80000000
+# CONFIG_ISA is not set
+# CONFIG_EISA is not set
+# CONFIG_SBUS is not set
+# CONFIG_MCA is not set
+CONFIG_PCI=y
+# CONFIG_8260_PCI9 is not set
+# CONFIG_PC_KEYBOARD is not set
+CONFIG_NET=y
+CONFIG_SYSCTL=y
+CONFIG_SYSVIPC=y
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_KCORE_ELF=y
+CONFIG_BINFMT_ELF=y
+CONFIG_KERNEL_ELF=y
+# CONFIG_BINFMT_MISC is not set
+# CONFIG_OOM_KILLER is not set
+# CONFIG_PCI_NAMES is not set
+CONFIG_HOTPLUG=y
+
+#
+# PCMCIA/CardBus support
+#
+# CONFIG_PCMCIA is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+# CONFIG_GEN_RTC is not set
+# CONFIG_PPC_RTC is not set
+CONFIG_CMDLINE_BOOL=y
+CONFIG_CMDLINE="console=ttyS0,115200 root=/dev/nfs nfsroot=192.168.1.24:/eric_root_devel.miba ip=192.168.1.20:192.168.1.24"
+
+#
+# Memory Technology Devices (MTD)
+#
+CONFIG_MTD=m
+# CONFIG_MTD_DEBUG is not set
+CONFIG_MTD_PARTITIONS=m
+# CONFIG_MTD_CONCAT is not set
+# CONFIG_MTD_REDBOOT_PARTS is not set
+CONFIG_MTD_CMDLINE_PARTS=m
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=m
+CONFIG_MTD_BLOCK=m
+# CONFIG_MTD_BLOCK_RO is not set
+CONFIG_FTL=m
+# CONFIG_NFTL is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+CONFIG_MTD_CFI=m
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_GEN_PROBE=m
+CONFIG_MTD_CFI_ADV_OPTIONS=y
+CONFIG_MTD_CFI_NOSWAP=y
+# CONFIG_MTD_CFI_BE_BYTE_SWAP is not set
+# CONFIG_MTD_CFI_LE_BYTE_SWAP is not set
+CONFIG_MTD_CFI_GEOMETRY=y
+# CONFIG_MTD_CFI_B1 is not set
+CONFIG_MTD_CFI_B2=y
+# CONFIG_MTD_CFI_B4 is not set
+# CONFIG_MTD_CFI_B8 is not set
+CONFIG_MTD_CFI_I1=y
+# CONFIG_MTD_CFI_I2 is not set
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+CONFIG_MTD_CFI_INTELEXT=m
+# CONFIG_MTD_CFI_AMDSTD is not set
+# CONFIG_MTD_CFI_STAA is not set
+# CONFIG_MTD_RAM is not set
+CONFIG_MTD_ROM=m
+# 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_PHYSMAP=m
+CONFIG_MTD_PHYSMAP_BUSWIDTH=2
+# CONFIG_MTD_BEECH is not set
+# CONFIG_MTD_ARCTIC 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
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC1000 is not set
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOCPROBE is not set
+
+#
+# NAND Flash Device Drivers
+#
+# CONFIG_MTD_NAND 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_LOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=8192
+CONFIG_BLK_DEV_INITRD=y
+# 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 is not set
+CONFIG_NETFILTER=y
+# CONFIG_NETFILTER_DEBUG is not set
+# CONFIG_FILTER is not set
+CONFIG_UNIX=y
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_PNP=y
+# CONFIG_IP_PNP_DHCP is not set
+CONFIG_IP_PNP_BOOTP=y
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_IP_MROUTE is not set
+# CONFIG_ARPD is not set
+# CONFIG_INET_ECN is not set
+# CONFIG_SYN_COOKIES is not set
+
+#
+#   IP: Netfilter Configuration
+#
+CONFIG_IP_NF_CONNTRACK=y
+# CONFIG_IP_NF_FTP is not set
+# CONFIG_IP_NF_AMANDA is not set
+# CONFIG_IP_NF_TFTP is not set
+# CONFIG_IP_NF_IRC is not set
+CONFIG_IP_NF_QUEUE=y
+CONFIG_IP_NF_IPTABLES=y
+# CONFIG_IP_NF_MATCH_LIMIT is not set
+CONFIG_IP_NF_MATCH_MAC=y
+# CONFIG_IP_NF_MATCH_PKTTYPE is not set
+CONFIG_IP_NF_MATCH_MARK=y
+# CONFIG_IP_NF_MATCH_MULTIPORT is not set
+# CONFIG_IP_NF_MATCH_TOS is not set
+# CONFIG_IP_NF_MATCH_RECENT is not set
+# CONFIG_IP_NF_MATCH_ECN is not set
+# CONFIG_IP_NF_MATCH_DSCP is not set
+# CONFIG_IP_NF_MATCH_AH_ESP is not set
+# CONFIG_IP_NF_MATCH_LENGTH is not set
+# CONFIG_IP_NF_MATCH_TTL is not set
+# CONFIG_IP_NF_MATCH_TCPMSS is not set
+# CONFIG_IP_NF_MATCH_HELPER is not set
+# CONFIG_IP_NF_MATCH_STATE is not set
+# CONFIG_IP_NF_MATCH_CONNTRACK is not set
+# CONFIG_IP_NF_MATCH_UNCLEAN is not set
+# CONFIG_IP_NF_MATCH_OWNER is not set
+CONFIG_IP_NF_FILTER=y
+CONFIG_IP_NF_TARGET_REJECT=y
+# CONFIG_IP_NF_TARGET_MIRROR is not set
+CONFIG_IP_NF_FASTNAT=y
+CONFIG_IP_NF_TARGET_FASTNAT=y
+CONFIG_IP_NF_NAT=y
+CONFIG_IP_NF_NAT_NEEDED=y
+# CONFIG_IP_NF_TARGET_MASQUERADE is not set
+CONFIG_IP_NF_TARGET_REDIRECT=y
+CONFIG_IP_NF_NAT_LOCAL=y
+# CONFIG_IP_NF_NAT_SNMP_BASIC is not set
+CONFIG_IP_NF_MANGLE=y
+# CONFIG_IP_NF_TARGET_TOS is not set
+# CONFIG_IP_NF_TARGET_ECN is not set
+# CONFIG_IP_NF_TARGET_DSCP is not set
+CONFIG_IP_NF_TARGET_MARK=y
+# CONFIG_IP_NF_TARGET_LOG is not set
+# CONFIG_IP_NF_TARGET_ULOG is not set
+# CONFIG_IP_NF_TARGET_TCPMSS is not set
+# CONFIG_IP_NF_ARPTABLES is not set
+
+#
+#   IP: Virtual Server Configuration
+#
+CONFIG_IP_VS=y
+# CONFIG_IP_VS_DEBUG is not set
+CONFIG_IP_VS_TAB_BITS=12
+
+#
+# IPVS scheduler
+#
+CONFIG_IP_VS_RR=y
+CONFIG_IP_VS_WRR=y
+CONFIG_IP_VS_LC=y
+CONFIG_IP_VS_WLC=y
+CONFIG_IP_VS_LBLC=y
+CONFIG_IP_VS_LBLCR=y
+CONFIG_IP_VS_DH=y
+CONFIG_IP_VS_SH=y
+CONFIG_IP_VS_SED=y
+CONFIG_IP_VS_NQ=y
+
+#
+# IPVS application helper
+#
+# CONFIG_IP_VS_FTP is not set
+CONFIG_IPV6=y
+
+#
+#   IPv6: Netfilter Configuration
+#
+# CONFIG_IP6_NF_QUEUE is not set
+# CONFIG_IP6_NF_IPTABLES is not set
+# CONFIG_KHTTPD is not set
+
+#
+#    SCTP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_SCTP is not set
+# CONFIG_ATM is not set
+# CONFIG_VLAN_8021Q is not set
+
+#
+#  
+#
+# 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=y
+# 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 is not set
+# CONFIG_NET_SCH_HTB is not set
+# CONFIG_NET_SCH_CSZ is not set
+# CONFIG_NET_SCH_HFSC is not set
+# CONFIG_NET_SCH_PRIO is not set
+# CONFIG_NET_SCH_RED is not set
+# CONFIG_NET_SCH_SFQ is not set
+# CONFIG_NET_SCH_TEQL is not set
+CONFIG_NET_SCH_TBF=y
+# CONFIG_NET_SCH_GRED is not set
+# CONFIG_NET_SCH_DELAY is not set
+# CONFIG_NET_SCH_DSMARK is not set
+# CONFIG_NET_SCH_INGRESS is not set
+# CONFIG_NET_QOS is not set
+# CONFIG_NET_CLS is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+
+#
+# ATA/IDE/MFM/RLL support
+#
+# CONFIG_IDE is not set
+# CONFIG_BLK_DEV_HD is not set
+
+#
+# SCSI support
+#
+# CONFIG_SCSI 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 is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+# CONFIG_ETHERTAP is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+# CONFIG_MACE is not set
+# CONFIG_BMAC is not set
+# CONFIG_GMAC 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
+
+#
+# Backplane Networking
+#
+# CONFIG_NPNET is not set
+
+#
+# On-chip net devices
+#
+CONFIG_IBM_OCP_ENET=y
+# CONFIG_IBM_OCP_ENET_ERROR_MSG is not set
+CONFIG_IBM_OCP_ENET_RX_BUFF=64
+CONFIG_IBM_OCP_ENET_TX_BUFF=8
+CONFIG_IBM_OCP_ENET_GAP=4
+CONFIG_IBM_OCP_ENET_SKB_RES=2
+CONFIG_OCP_NET=y
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+# CONFIG_PLIP is not set
+CONFIG_PPP=y
+# CONFIG_PPP_MULTILINK is not set
+# CONFIG_PPP_FILTER is not set
+CONFIG_PPP_ASYNC=y
+# CONFIG_PPP_SYNC_TTY is not set
+CONFIG_PPP_DEFLATE=y
+CONFIG_PPP_BSDCOMP=y
+# CONFIG_PPPOE is not set
+# 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 is not set
+# CONFIG_AIRONET4500_NONCS is not set
+# CONFIG_AIRONET4500_PROC is not set
+# CONFIG_AIRO is not set
+# CONFIG_HERMES is not set
+# CONFIG_PLX_HERMES is not set
+# CONFIG_TMD_HERMES is not set
+# CONFIG_PCI_HERMES 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 is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN 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
+
+#
+# Old CD-ROM drivers (not SCSI, not IDE)
+#
+# CONFIG_CD_NO_IDESCSI is not set
+
+#
+# Console drivers
+#
+CONFIG_DUMMY_CONSOLE=y
+
+#
+# Frame-buffer support
+#
+# CONFIG_FB 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
+
+#
+# Macintosh device drivers
+#
+
+#
+# Character devices
+#
+CONFIG_VT=y
+# CONFIG_VT_CONSOLE is not set
+CONFIG_SERIAL=y
+CONFIG_SERIAL_CONSOLE=y
+# CONFIG_SERIAL_EXTENDED is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+CONFIG_UNIX98_PTYS=y
+CONFIG_UNIX98_PTY_COUNT=256
+
+#
+# I2C support
+#
+CONFIG_I2C=y
+CONFIG_I2C_SLAVE=y
+# CONFIG_I2C_ALGOBIT is not set
+# CONFIG_SCx200_ACB is not set
+# CONFIG_I2C_ALGOPCF is not set
+CONFIG_I2C_IBM_IIC=y
+# CONFIG_I2C_ASICSMS is not set
+CONFIG_I2C_CHARDEV=y
+CONFIG_I2C_PROC=y
+
+#
+# Mice
+#
+# CONFIG_BUSMOUSE is not set
+# CONFIG_MOUSE is not set
+
+#
+# Joysticks
+#
+# CONFIG_INPUT_GAMEPORT is not set
+
+#
+# Input core support is needed for gameports
+#
+
+#
+# Input core support is needed for joysticks
+#
+# 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=y
+CONFIG_WATCHDOG_NOWAYOUT=y
+# CONFIG_ACQUIRE_WDT is not set
+# CONFIG_ADVANTECH_WDT is not set
+# CONFIG_ALIM1535_WDT is not set
+# CONFIG_ALIM7101_WDT is not set
+# CONFIG_SC520_WDT is not set
+# CONFIG_PCWATCHDOG is not set
+# CONFIG_EUROTECH_WDT is not set
+# CONFIG_IB700_WDT is not set
+CONFIG_PPC405_WDT=y
+# CONFIG_WAFER_WDT is not set
+# CONFIG_I810_TCO is not set
+# CONFIG_MIXCOMWD is not set
+# CONFIG_60XX_WDT is not set
+# CONFIG_SC1200_WDT is not set
+# CONFIG_SCx200_WDT is not set
+# CONFIG_SOFT_WATCHDOG is not set
+# CONFIG_W83877F_WDT is not set
+# CONFIG_WDT is not set
+# CONFIG_WDTPCI is not set
+# CONFIG_MACHZ_WDT is not set
+# CONFIG_AMD7XX_TCO 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_X1226_RTC=y
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+# CONFIG_IBM_OCP_GPIO 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
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV 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 is not set
+# 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 is not set
+# CONFIG_JBD is not set
+# CONFIG_JBD_DEBUG is not set
+# CONFIG_FAT_FS is not set
+# CONFIG_MSDOS_FS is not set
+# CONFIG_UMSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_JFFS_FS is not set
+CONFIG_JFFS2_FS=m
+CONFIG_JFFS2_FS_DEBUG=0
+# CONFIG_CRAMFS is not set
+# CONFIG_TMPFS is not set
+CONFIG_RAMFS=y
+# CONFIG_ISO9660_FS is not set
+# CONFIG_JOLIET is not set
+# CONFIG_ZISOFS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_JFS_DEBUG is not set
+# CONFIG_JFS_STATISTICS is not set
+CONFIG_MINIX_FS=y
+# CONFIG_VXFS_FS is not set
+# CONFIG_NTFS_FS is not set
+# CONFIG_NTFS_RW is not set
+# CONFIG_HPFS_FS is not set
+CONFIG_PROC_FS=y
+# CONFIG_DEVFS_FS is not set
+# CONFIG_DEVFS_MOUNT is not set
+# 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=y
+# 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 is not set
+# CONFIG_NFSD_V3 is not set
+# CONFIG_NFSD_TCP is not set
+CONFIG_SUNRPC=y
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_SMB_FS=y
+# 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 is not set
+
+#
+# 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-1"
+# CONFIG_NLS_CODEPAGE_437 is not set
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# 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 is not set
+# 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 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# IBM 4xx options
+#
+
+#
+# USB support
+#
+# CONFIG_USB is not set
+
+#
+# Support for USB gadgets
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# Bluetooth support
+#
+# CONFIG_BLUEZ is not set
+
+#
+# Cryptographic options
+#
+CONFIG_CRYPTO=y
+CONFIG_CRYPTO_HMAC=y
+CONFIG_CRYPTO_NULL=y
+# CONFIG_CRYPTO_MD4 is not set
+# CONFIG_CRYPTO_MD5 is not set
+# CONFIG_CRYPTO_SHA1 is not set
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_DES is not set
+# CONFIG_CRYPTO_BLOWFISH is not set
+# CONFIG_CRYPTO_TWOFISH is not set
+# CONFIG_CRYPTO_SERPENT is not set
+CONFIG_CRYPTO_AES=y
+# CONFIG_CRYPTO_CAST5 is not set
+# CONFIG_CRYPTO_CAST6 is not set
+# CONFIG_CRYPTO_ARC4 is not set
+# CONFIG_CRYPTO_DEFLATE is not set
+# CONFIG_CRYPTO_TEST is not set
+
+#
+# Library routines
+#
+# CONFIG_CRC32 is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
+CONFIG_FW_LOADER=m
+
+#
+# Kernel hacking
+#
+# CONFIG_DEBUG_KERNEL is not set
+# CONFIG_SERIAL_TEXT_DEBUG is not set
+CONFIG_LOG_BUF_SHIFT=0
Index: pplinux/linuxnew/arch/ppc/configs/lara_kimamd_defconfig
diff -u /dev/null pplinux/linuxnew/arch/ppc/configs/lara_kimamd_defconfig:1.3
--- /dev/null	Tue May 24 10:37:58 2005
+++ pplinux/linuxnew/arch/ppc/configs/lara_kimamd_defconfig	Mon May  9 11:06:26 2005
@@ -0,0 +1,862 @@
+#
+# Automatically generated by make menuconfig: don't edit
+#
+# CONFIG_UID16 is not set
+# CONFIG_RWSEM_GENERIC_SPINLOCK is not set
+CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_HAVE_DEC_LOCK=y
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_ADVANCED_OPTIONS=y
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+CONFIG_MODVERSIONS=y
+# CONFIG_KMOD is not set
+
+#
+# Platform support
+#
+CONFIG_PPC=y
+CONFIG_PPC32=y
+# CONFIG_6xx is not set
+CONFIG_40x=y
+# CONFIG_44x is not set
+# CONFIG_POWER3 is not set
+# CONFIG_POWER4 is not set
+# CONFIG_8xx is not set
+CONFIG_4xx=y
+# CONFIG_PPC_STD_MMU is not set
+# CONFIG_ARCTIC2 is not set
+# CONFIG_ASH is not set
+# CONFIG_CEDER is not set
+# CONFIG_BEECH is not set
+# CONFIG_CPCI405 is not set
+# CONFIG_EP405 is not set
+# CONFIG_EVB405EP is not set
+# CONFIG_OAK is not set
+# CONFIG_RAINIER is not set
+# CONFIG_REDWOOD_4 is not set
+# CONFIG_REDWOOD_5 is not set
+# CONFIG_REDWOOD_6 is not set
+# CONFIG_SYCAMORE is not set
+# CONFIG_TIVO is not set
+# CONFIG_WALNUT is not set
+# CONFIG_PEPPERCON_405GP is not set
+CONFIG_PEPPERCON_405EP=y
+# CONFIG_XILINX_ML300 is not set
+# CONFIG_ALL_PPC is not set
+# CONFIG_SMP is not set
+# CONFIG_MATH_EMULATION is not set
+CONFIG_BIGPHYS_AREA=y
+CONFIG_NOT_COHERENT_CACHE=y
+CONFIG_UART0_TTYS0=y
+# CONFIG_UART0_TTYS1 is not set
+# CONFIG_PM is not set
+CONFIG_PEPPERCON=y
+CONFIG_405EP=y
+CONFIG_IBM_OCP=y
+CONFIG_PPC_OCP=y
+CONFIG_GEN550=y
+CONFIG_405=y
+CONFIG_IBM405_ERR51=y
+CONFIG_IBM405_ERR77=y
+CONFIG_PPC4xx_DMA=y
+CONFIG_PPC4xx_EDMA=y
+CONFIG_OCP_PROC=y
+
+#
+# General setup
+#
+# CONFIG_HIGHMEM is not set
+# CONFIG_LOWMEM_SIZE_BOOL is not set
+# CONFIG_KERNEL_START_BOOL is not set
+# CONFIG_TASK_SIZE_BOOL is not set
+# CONFIG_PIN_TLB is not set
+CONFIG_HIGHMEM_START=0xfe000000
+CONFIG_LOWMEM_SIZE=0x30000000
+CONFIG_KERNEL_START=0xc0000000
+CONFIG_TASK_SIZE=0x80000000
+# CONFIG_ISA is not set
+# CONFIG_EISA is not set
+# CONFIG_SBUS is not set
+# CONFIG_MCA is not set
+CONFIG_PCI=y
+# CONFIG_8260_PCI9 is not set
+# CONFIG_PC_KEYBOARD is not set
+CONFIG_NET=y
+CONFIG_SYSCTL=y
+CONFIG_SYSVIPC=y
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_KCORE_ELF=y
+CONFIG_BINFMT_ELF=y
+CONFIG_KERNEL_ELF=y
+# CONFIG_BINFMT_MISC is not set
+# CONFIG_OOM_KILLER is not set
+# CONFIG_PCI_NAMES is not set
+
+#
+# PCI Hotplug Support
+#
+CONFIG_HOTPLUG_PCI=m
+CONFIG_HOTPLUG_PCI_DUMMY=m
+# CONFIG_HOTPLUG_PCI_COMPAQ is not set
+# CONFIG_HOTPLUG_PCI_COMPAQ_NVRAM is not set
+CONFIG_HOTPLUG=y
+
+#
+# PCMCIA/CardBus support
+#
+# CONFIG_PCMCIA is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+# CONFIG_GEN_RTC is not set
+# CONFIG_PPC_RTC is not set
+CONFIG_CMDLINE_BOOL=y
+CONFIG_CMDLINE="console=ttyS0,115200 root=/dev/nfs nfsroot=192.168.1.24:/eric_root_devel.miba ip=192.168.1.20:192.168.1.24"
+
+#
+# Memory Technology Devices (MTD)
+#
+CONFIG_MTD=m
+# CONFIG_MTD_DEBUG is not set
+CONFIG_MTD_PARTITIONS=m
+# CONFIG_MTD_CONCAT is not set
+# CONFIG_MTD_REDBOOT_PARTS is not set
+CONFIG_MTD_CMDLINE_PARTS=m
+CONFIG_MTD_CHAR=m
+CONFIG_MTD_BLOCK=m
+# CONFIG_MTD_BLOCK_RO is not set
+CONFIG_FTL=m
+# CONFIG_NFTL is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+CONFIG_MTD_CFI=m
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_GEN_PROBE=m
+CONFIG_MTD_CFI_ADV_OPTIONS=y
+CONFIG_MTD_CFI_NOSWAP=y
+# CONFIG_MTD_CFI_BE_BYTE_SWAP is not set
+# CONFIG_MTD_CFI_LE_BYTE_SWAP is not set
+CONFIG_MTD_CFI_GEOMETRY=y
+# CONFIG_MTD_CFI_B1 is not set
+CONFIG_MTD_CFI_B2=y
+# CONFIG_MTD_CFI_B4 is not set
+# CONFIG_MTD_CFI_B8 is not set
+CONFIG_MTD_CFI_I1=y
+# CONFIG_MTD_CFI_I2 is not set
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+CONFIG_MTD_CFI_INTELEXT=m
+# CONFIG_MTD_CFI_AMDSTD is not set
+# CONFIG_MTD_CFI_STAA is not set
+# CONFIG_MTD_RAM is not set
+CONFIG_MTD_ROM=m
+# 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_PHYSMAP=m
+CONFIG_MTD_PHYSMAP_BUSWIDTH=2
+# CONFIG_MTD_BEECH is not set
+# CONFIG_MTD_ARCTIC 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_DOC1000 is not set
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOCPROBE is not set
+
+#
+# NAND Flash Device Drivers
+#
+# CONFIG_MTD_NAND 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_LOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=8192
+CONFIG_BLK_DEV_INITRD=y
+# 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 is not set
+CONFIG_NETFILTER=y
+# CONFIG_NETFILTER_DEBUG is not set
+# CONFIG_FILTER is not set
+CONFIG_UNIX=y
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_PNP=y
+# CONFIG_IP_PNP_DHCP is not set
+CONFIG_IP_PNP_BOOTP=y
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_IP_MROUTE is not set
+# CONFIG_ARPD is not set
+# CONFIG_INET_ECN is not set
+# CONFIG_SYN_COOKIES is not set
+
+#
+#   IP: Netfilter Configuration
+#
+CONFIG_IP_NF_CONNTRACK=y
+# CONFIG_IP_NF_FTP is not set
+# CONFIG_IP_NF_AMANDA is not set
+# CONFIG_IP_NF_TFTP is not set
+# CONFIG_IP_NF_IRC is not set
+CONFIG_IP_NF_QUEUE=y
+CONFIG_IP_NF_IPTABLES=y
+# CONFIG_IP_NF_MATCH_LIMIT is not set
+CONFIG_IP_NF_MATCH_MAC=y
+# CONFIG_IP_NF_MATCH_PKTTYPE is not set
+CONFIG_IP_NF_MATCH_MARK=y
+# CONFIG_IP_NF_MATCH_MULTIPORT is not set
+# CONFIG_IP_NF_MATCH_TOS is not set
+# CONFIG_IP_NF_MATCH_RECENT is not set
+# CONFIG_IP_NF_MATCH_ECN is not set
+# CONFIG_IP_NF_MATCH_DSCP is not set
+# CONFIG_IP_NF_MATCH_AH_ESP is not set
+# CONFIG_IP_NF_MATCH_LENGTH is not set
+# CONFIG_IP_NF_MATCH_TTL is not set
+# CONFIG_IP_NF_MATCH_TCPMSS is not set
+# CONFIG_IP_NF_MATCH_HELPER is not set
+# CONFIG_IP_NF_MATCH_STATE is not set
+# CONFIG_IP_NF_MATCH_CONNTRACK is not set
+# CONFIG_IP_NF_MATCH_UNCLEAN is not set
+# CONFIG_IP_NF_MATCH_OWNER is not set
+CONFIG_IP_NF_FILTER=y
+CONFIG_IP_NF_TARGET_REJECT=y
+# CONFIG_IP_NF_TARGET_MIRROR is not set
+CONFIG_IP_NF_FASTNAT=y
+CONFIG_IP_NF_TARGET_FASTNAT=y
+CONFIG_IP_NF_NAT=y
+CONFIG_IP_NF_NAT_NEEDED=y
+# CONFIG_IP_NF_TARGET_MASQUERADE is not set
+CONFIG_IP_NF_TARGET_REDIRECT=y
+CONFIG_IP_NF_NAT_LOCAL=y
+# CONFIG_IP_NF_NAT_SNMP_BASIC is not set
+CONFIG_IP_NF_MANGLE=y
+# CONFIG_IP_NF_TARGET_TOS is not set
+# CONFIG_IP_NF_TARGET_ECN is not set
+# CONFIG_IP_NF_TARGET_DSCP is not set
+CONFIG_IP_NF_TARGET_MARK=y
+# CONFIG_IP_NF_TARGET_LOG is not set
+# CONFIG_IP_NF_TARGET_ULOG is not set
+# CONFIG_IP_NF_TARGET_TCPMSS is not set
+# CONFIG_IP_NF_ARPTABLES is not set
+
+#
+#   IP: Virtual Server Configuration
+#
+CONFIG_IP_VS=y
+# CONFIG_IP_VS_DEBUG is not set
+CONFIG_IP_VS_TAB_BITS=12
+
+#
+# IPVS scheduler
+#
+CONFIG_IP_VS_RR=y
+CONFIG_IP_VS_WRR=y
+CONFIG_IP_VS_LC=y
+CONFIG_IP_VS_WLC=y
+CONFIG_IP_VS_LBLC=y
+CONFIG_IP_VS_LBLCR=y
+CONFIG_IP_VS_DH=y
+CONFIG_IP_VS_SH=y
+CONFIG_IP_VS_SED=y
+CONFIG_IP_VS_NQ=y
+
+#
+# IPVS application helper
+#
+# CONFIG_IP_VS_FTP is not set
+CONFIG_IPV6=y
+
+#
+#   IPv6: Netfilter Configuration
+#
+# CONFIG_IP6_NF_QUEUE is not set
+# CONFIG_IP6_NF_IPTABLES is not set
+# CONFIG_KHTTPD is not set
+
+#
+#    SCTP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_SCTP is not set
+# CONFIG_ATM is not set
+# CONFIG_VLAN_8021Q is not set
+# 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=y
+# 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 is not set
+# CONFIG_NET_SCH_HTB is not set
+# CONFIG_NET_SCH_CSZ is not set
+# CONFIG_NET_SCH_HFSC is not set
+# CONFIG_NET_SCH_PRIO is not set
+# CONFIG_NET_SCH_RED is not set
+# CONFIG_NET_SCH_SFQ is not set
+# CONFIG_NET_SCH_TEQL is not set
+CONFIG_NET_SCH_TBF=y
+# CONFIG_NET_SCH_GRED is not set
+# CONFIG_NET_SCH_DELAY is not set
+# CONFIG_NET_SCH_DSMARK is not set
+# CONFIG_NET_SCH_INGRESS is not set
+# CONFIG_NET_QOS is not set
+# CONFIG_NET_CLS is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+
+#
+# ATA/IDE/MFM/RLL support
+#
+# CONFIG_IDE is not set
+# CONFIG_BLK_DEV_HD is not set
+
+#
+# SCSI support
+#
+# CONFIG_SCSI 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 is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+# CONFIG_ETHERTAP is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+# CONFIG_MACE is not set
+# CONFIG_BMAC is not set
+# CONFIG_GMAC 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
+
+#
+# Backplane Networking
+#
+# CONFIG_NPNET is not set
+
+#
+# On-chip net devices
+#
+CONFIG_IBM_OCP_ENET=y
+# CONFIG_IBM_OCP_ENET_ERROR_MSG is not set
+CONFIG_IBM_OCP_ENET_RX_BUFF=64
+CONFIG_IBM_OCP_ENET_TX_BUFF=8
+CONFIG_IBM_OCP_ENET_GAP=4
+CONFIG_IBM_OCP_ENET_SKB_RES=2
+CONFIG_OCP_NET=y
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+# CONFIG_PLIP is not set
+CONFIG_PPP=y
+# CONFIG_PPP_MULTILINK is not set
+# CONFIG_PPP_FILTER is not set
+CONFIG_PPP_ASYNC=y
+# CONFIG_PPP_SYNC_TTY is not set
+CONFIG_PPP_DEFLATE=y
+CONFIG_PPP_BSDCOMP=y
+# CONFIG_PPPOE is not set
+# CONFIG_SLIP is not set
+
+#
+# Wireless LAN (non-hamradio)
+#
+# CONFIG_NET_RADIO is not set
+
+#
+# Token Ring devices
+#
+# CONFIG_TR is not set
+# CONFIG_NET_FC is not set
+# CONFIG_RCPCI is not set
+# CONFIG_SHAPER is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN 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
+
+#
+# Old CD-ROM drivers (not SCSI, not IDE)
+#
+# CONFIG_CD_NO_IDESCSI is not set
+
+#
+# Console drivers
+#
+CONFIG_DUMMY_CONSOLE=y
+
+#
+# Frame-buffer support
+#
+# CONFIG_FB 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
+
+#
+# Macintosh device drivers
+#
+
+#
+# Character devices
+#
+CONFIG_VT=y
+# CONFIG_VT_CONSOLE is not set
+CONFIG_SERIAL=y
+CONFIG_SERIAL_CONSOLE=y
+# CONFIG_SERIAL_EXTENDED is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+CONFIG_UNIX98_PTYS=y
+CONFIG_UNIX98_PTY_COUNT=256
+
+#
+# I2C support
+#
+CONFIG_I2C=m
+CONFIG_I2C_SLAVE=m
+# CONFIG_I2C_ALGOBIT is not set
+# CONFIG_SCx200_ACB is not set
+# CONFIG_I2C_ALGOPCF is not set
+CONFIG_I2C_IBM_IIC=m
+CONFIG_I2C_ASICSMS=m
+CONFIG_I2C_CHARDEV=m
+CONFIG_I2C_PROC=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=y
+CONFIG_WATCHDOG_NOWAYOUT=y
+# CONFIG_ACQUIRE_WDT is not set
+# CONFIG_ADVANTECH_WDT is not set
+# CONFIG_ALIM1535_WDT is not set
+# CONFIG_ALIM7101_WDT is not set
+# CONFIG_SC520_WDT is not set
+# CONFIG_PCWATCHDOG is not set
+# CONFIG_EUROTECH_WDT is not set
+# CONFIG_IB700_WDT is not set
+CONFIG_PPC405_WDT=y
+# CONFIG_WAFER_WDT is not set
+# CONFIG_I810_TCO is not set
+# CONFIG_MIXCOMWD is not set
+# CONFIG_60XX_WDT is not set
+# CONFIG_SC1200_WDT is not set
+# CONFIG_SCx200_WDT is not set
+# CONFIG_SOFT_WATCHDOG is not set
+# CONFIG_W83877F_WDT is not set
+# CONFIG_WDT is not set
+# CONFIG_WDTPCI is not set
+# CONFIG_MACHZ_WDT is not set
+# CONFIG_AMD7XX_TCO 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_X1226_RTC=y
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+# CONFIG_IBM_OCP_GPIO 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
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV 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 is not set
+# 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 is not set
+# CONFIG_JBD is not set
+# CONFIG_JBD_DEBUG is not set
+# CONFIG_FAT_FS is not set
+# CONFIG_MSDOS_FS is not set
+# CONFIG_UMSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_JFFS_FS is not set
+CONFIG_JFFS2_FS=m
+CONFIG_JFFS2_FS_DEBUG=0
+# CONFIG_CRAMFS is not set
+# CONFIG_TMPFS is not set
+CONFIG_RAMFS=y
+# CONFIG_ISO9660_FS is not set
+# CONFIG_JOLIET is not set
+# CONFIG_ZISOFS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_JFS_DEBUG is not set
+# CONFIG_JFS_STATISTICS is not set
+CONFIG_MINIX_FS=y
+# CONFIG_VXFS_FS is not set
+# CONFIG_NTFS_FS is not set
+# CONFIG_NTFS_RW is not set
+# CONFIG_HPFS_FS is not set
+CONFIG_PROC_FS=y
+# CONFIG_DEVFS_FS is not set
+# CONFIG_DEVFS_MOUNT is not set
+# 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=y
+# 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 is not set
+# CONFIG_NFSD_V3 is not set
+# CONFIG_NFSD_TCP is not set
+CONFIG_SUNRPC=y
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_SMB_FS=y
+# 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 is not set
+
+#
+# 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-1"
+# CONFIG_NLS_CODEPAGE_437 is not set
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# 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 is not set
+# 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 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# IBM 4xx options
+#
+
+#
+# USB support
+#
+# CONFIG_USB is not set
+
+#
+# Support for USB gadgets
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# Bluetooth support
+#
+# CONFIG_BLUEZ is not set
+
+#
+# Cryptographic options
+#
+CONFIG_CRYPTO=y
+CONFIG_CRYPTO_HMAC=y
+CONFIG_CRYPTO_NULL=y
+# CONFIG_CRYPTO_MD4 is not set
+# CONFIG_CRYPTO_MD5 is not set
+# CONFIG_CRYPTO_SHA1 is not set
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_DES is not set
+# CONFIG_CRYPTO_BLOWFISH is not set
+# CONFIG_CRYPTO_TWOFISH is not set
+# CONFIG_CRYPTO_SERPENT is not set
+CONFIG_CRYPTO_AES=y
+# CONFIG_CRYPTO_CAST5 is not set
+# CONFIG_CRYPTO_CAST6 is not set
+# CONFIG_CRYPTO_ARC4 is not set
+# CONFIG_CRYPTO_DEFLATE is not set
+# CONFIG_CRYPTO_TEST is not set
+
+#
+# Library routines
+#
+# CONFIG_CRC32 is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
+# CONFIG_FW_LOADER is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_DEBUG_KERNEL is not set
+# CONFIG_SERIAL_TEXT_DEBUG is not set
+CONFIG_LOG_BUF_SHIFT=0
Index: pplinux/linuxnew/arch/ppc/configs/lara_kimmsi_defconfig
diff -u /dev/null pplinux/linuxnew/arch/ppc/configs/lara_kimmsi_defconfig:1.3
--- /dev/null	Tue May 24 10:37:58 2005
+++ pplinux/linuxnew/arch/ppc/configs/lara_kimmsi_defconfig	Mon May  9 11:06:26 2005
@@ -0,0 +1,862 @@
+#
+# Automatically generated by make menuconfig: don't edit
+#
+# CONFIG_UID16 is not set
+# CONFIG_RWSEM_GENERIC_SPINLOCK is not set
+CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_HAVE_DEC_LOCK=y
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_ADVANCED_OPTIONS=y
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+CONFIG_MODVERSIONS=y
+# CONFIG_KMOD is not set
+
+#
+# Platform support
+#
+CONFIG_PPC=y
+CONFIG_PPC32=y
+# CONFIG_6xx is not set
+CONFIG_40x=y
+# CONFIG_44x is not set
+# CONFIG_POWER3 is not set
+# CONFIG_POWER4 is not set
+# CONFIG_8xx is not set
+CONFIG_4xx=y
+# CONFIG_PPC_STD_MMU is not set
+# CONFIG_ARCTIC2 is not set
+# CONFIG_ASH is not set
+# CONFIG_CEDER is not set
+# CONFIG_BEECH is not set
+# CONFIG_CPCI405 is not set
+# CONFIG_EP405 is not set
+# CONFIG_EVB405EP is not set
+# CONFIG_OAK is not set
+# CONFIG_RAINIER is not set
+# CONFIG_REDWOOD_4 is not set
+# CONFIG_REDWOOD_5 is not set
+# CONFIG_REDWOOD_6 is not set
+# CONFIG_SYCAMORE is not set
+# CONFIG_TIVO is not set
+# CONFIG_WALNUT is not set
+# CONFIG_PEPPERCON_405GP is not set
+CONFIG_PEPPERCON_405EP=y
+# CONFIG_XILINX_ML300 is not set
+# CONFIG_ALL_PPC is not set
+# CONFIG_SMP is not set
+# CONFIG_MATH_EMULATION is not set
+CONFIG_BIGPHYS_AREA=y
+CONFIG_NOT_COHERENT_CACHE=y
+CONFIG_UART0_TTYS0=y
+# CONFIG_UART0_TTYS1 is not set
+# CONFIG_PM is not set
+CONFIG_PEPPERCON=y
+CONFIG_405EP=y
+CONFIG_IBM_OCP=y
+CONFIG_PPC_OCP=y
+CONFIG_GEN550=y
+CONFIG_405=y
+CONFIG_IBM405_ERR51=y
+CONFIG_IBM405_ERR77=y
+CONFIG_PPC4xx_DMA=y
+CONFIG_PPC4xx_EDMA=y
+CONFIG_OCP_PROC=y
+
+#
+# General setup
+#
+# CONFIG_HIGHMEM is not set
+# CONFIG_LOWMEM_SIZE_BOOL is not set
+# CONFIG_KERNEL_START_BOOL is not set
+# CONFIG_TASK_SIZE_BOOL is not set
+# CONFIG_PIN_TLB is not set
+CONFIG_HIGHMEM_START=0xfe000000
+CONFIG_LOWMEM_SIZE=0x30000000
+CONFIG_KERNEL_START=0xc0000000
+CONFIG_TASK_SIZE=0x80000000
+# CONFIG_ISA is not set
+# CONFIG_EISA is not set
+# CONFIG_SBUS is not set
+# CONFIG_MCA is not set
+CONFIG_PCI=y
+# CONFIG_8260_PCI9 is not set
+# CONFIG_PC_KEYBOARD is not set
+CONFIG_NET=y
+CONFIG_SYSCTL=y
+CONFIG_SYSVIPC=y
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_KCORE_ELF=y
+CONFIG_BINFMT_ELF=y
+CONFIG_KERNEL_ELF=y
+# CONFIG_BINFMT_MISC is not set
+# CONFIG_OOM_KILLER is not set
+# CONFIG_PCI_NAMES is not set
+
+#
+# PCI Hotplug Support
+#
+CONFIG_HOTPLUG_PCI=m
+CONFIG_HOTPLUG_PCI_DUMMY=m
+# CONFIG_HOTPLUG_PCI_COMPAQ is not set
+# CONFIG_HOTPLUG_PCI_COMPAQ_NVRAM is not set
+CONFIG_HOTPLUG=y
+
+#
+# PCMCIA/CardBus support
+#
+# CONFIG_PCMCIA is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+# CONFIG_GEN_RTC is not set
+# CONFIG_PPC_RTC is not set
+CONFIG_CMDLINE_BOOL=y
+CONFIG_CMDLINE="console=ttyS0,115200 root=/dev/nfs nfsroot=192.168.1.24:/eric_root_devel.miba ip=192.168.1.20:192.168.1.24"
+
+#
+# Memory Technology Devices (MTD)
+#
+CONFIG_MTD=m
+# CONFIG_MTD_DEBUG is not set
+CONFIG_MTD_PARTITIONS=m
+# CONFIG_MTD_CONCAT is not set
+# CONFIG_MTD_REDBOOT_PARTS is not set
+CONFIG_MTD_CMDLINE_PARTS=m
+CONFIG_MTD_CHAR=m
+CONFIG_MTD_BLOCK=m
+# CONFIG_MTD_BLOCK_RO is not set
+CONFIG_FTL=m
+# CONFIG_NFTL is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+CONFIG_MTD_CFI=m
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_GEN_PROBE=m
+CONFIG_MTD_CFI_ADV_OPTIONS=y
+CONFIG_MTD_CFI_NOSWAP=y
+# CONFIG_MTD_CFI_BE_BYTE_SWAP is not set
+# CONFIG_MTD_CFI_LE_BYTE_SWAP is not set
+CONFIG_MTD_CFI_GEOMETRY=y
+# CONFIG_MTD_CFI_B1 is not set
+CONFIG_MTD_CFI_B2=y
+# CONFIG_MTD_CFI_B4 is not set
+# CONFIG_MTD_CFI_B8 is not set
+CONFIG_MTD_CFI_I1=y
+# CONFIG_MTD_CFI_I2 is not set
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+CONFIG_MTD_CFI_INTELEXT=m
+# CONFIG_MTD_CFI_AMDSTD is not set
+# CONFIG_MTD_CFI_STAA is not set
+# CONFIG_MTD_RAM is not set
+CONFIG_MTD_ROM=m
+# 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_PHYSMAP=m
+CONFIG_MTD_PHYSMAP_BUSWIDTH=2
+# CONFIG_MTD_BEECH is not set
+# CONFIG_MTD_ARCTIC 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_DOC1000 is not set
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOCPROBE is not set
+
+#
+# NAND Flash Device Drivers
+#
+# CONFIG_MTD_NAND 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_LOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=8192
+CONFIG_BLK_DEV_INITRD=y
+# 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 is not set
+CONFIG_NETFILTER=y
+# CONFIG_NETFILTER_DEBUG is not set
+# CONFIG_FILTER is not set
+CONFIG_UNIX=y
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_PNP=y
+# CONFIG_IP_PNP_DHCP is not set
+CONFIG_IP_PNP_BOOTP=y
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_IP_MROUTE is not set
+# CONFIG_ARPD is not set
+# CONFIG_INET_ECN is not set
+# CONFIG_SYN_COOKIES is not set
+
+#
+#   IP: Netfilter Configuration
+#
+CONFIG_IP_NF_CONNTRACK=y
+# CONFIG_IP_NF_FTP is not set
+# CONFIG_IP_NF_AMANDA is not set
+# CONFIG_IP_NF_TFTP is not set
+# CONFIG_IP_NF_IRC is not set
+CONFIG_IP_NF_QUEUE=y
+CONFIG_IP_NF_IPTABLES=y
+# CONFIG_IP_NF_MATCH_LIMIT is not set
+CONFIG_IP_NF_MATCH_MAC=y
+# CONFIG_IP_NF_MATCH_PKTTYPE is not set
+CONFIG_IP_NF_MATCH_MARK=y
+# CONFIG_IP_NF_MATCH_MULTIPORT is not set
+# CONFIG_IP_NF_MATCH_TOS is not set
+# CONFIG_IP_NF_MATCH_RECENT is not set
+# CONFIG_IP_NF_MATCH_ECN is not set
+# CONFIG_IP_NF_MATCH_DSCP is not set
+# CONFIG_IP_NF_MATCH_AH_ESP is not set
+# CONFIG_IP_NF_MATCH_LENGTH is not set
+# CONFIG_IP_NF_MATCH_TTL is not set
+# CONFIG_IP_NF_MATCH_TCPMSS is not set
+# CONFIG_IP_NF_MATCH_HELPER is not set
+# CONFIG_IP_NF_MATCH_STATE is not set
+# CONFIG_IP_NF_MATCH_CONNTRACK is not set
+# CONFIG_IP_NF_MATCH_UNCLEAN is not set
+# CONFIG_IP_NF_MATCH_OWNER is not set
+CONFIG_IP_NF_FILTER=y
+CONFIG_IP_NF_TARGET_REJECT=y
+# CONFIG_IP_NF_TARGET_MIRROR is not set
+CONFIG_IP_NF_FASTNAT=y
+CONFIG_IP_NF_TARGET_FASTNAT=y
+CONFIG_IP_NF_NAT=y
+CONFIG_IP_NF_NAT_NEEDED=y
+# CONFIG_IP_NF_TARGET_MASQUERADE is not set
+CONFIG_IP_NF_TARGET_REDIRECT=y
+CONFIG_IP_NF_NAT_LOCAL=y
+# CONFIG_IP_NF_NAT_SNMP_BASIC is not set
+CONFIG_IP_NF_MANGLE=y
+# CONFIG_IP_NF_TARGET_TOS is not set
+# CONFIG_IP_NF_TARGET_ECN is not set
+# CONFIG_IP_NF_TARGET_DSCP is not set
+CONFIG_IP_NF_TARGET_MARK=y
+# CONFIG_IP_NF_TARGET_LOG is not set
+# CONFIG_IP_NF_TARGET_ULOG is not set
+# CONFIG_IP_NF_TARGET_TCPMSS is not set
+# CONFIG_IP_NF_ARPTABLES is not set
+
+#
+#   IP: Virtual Server Configuration
+#
+CONFIG_IP_VS=y
+# CONFIG_IP_VS_DEBUG is not set
+CONFIG_IP_VS_TAB_BITS=12
+
+#
+# IPVS scheduler
+#
+CONFIG_IP_VS_RR=y
+CONFIG_IP_VS_WRR=y
+CONFIG_IP_VS_LC=y
+CONFIG_IP_VS_WLC=y
+CONFIG_IP_VS_LBLC=y
+CONFIG_IP_VS_LBLCR=y
+CONFIG_IP_VS_DH=y
+CONFIG_IP_VS_SH=y
+CONFIG_IP_VS_SED=y
+CONFIG_IP_VS_NQ=y
+
+#
+# IPVS application helper
+#
+# CONFIG_IP_VS_FTP is not set
+CONFIG_IPV6=y
+
+#
+#   IPv6: Netfilter Configuration
+#
+# CONFIG_IP6_NF_QUEUE is not set
+# CONFIG_IP6_NF_IPTABLES is not set
+# CONFIG_KHTTPD is not set
+
+#
+#    SCTP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_SCTP is not set
+# CONFIG_ATM is not set
+# CONFIG_VLAN_8021Q is not set
+# 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=y
+# 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 is not set
+# CONFIG_NET_SCH_HTB is not set
+# CONFIG_NET_SCH_CSZ is not set
+# CONFIG_NET_SCH_HFSC is not set
+# CONFIG_NET_SCH_PRIO is not set
+# CONFIG_NET_SCH_RED is not set
+# CONFIG_NET_SCH_SFQ is not set
+# CONFIG_NET_SCH_TEQL is not set
+CONFIG_NET_SCH_TBF=y
+# CONFIG_NET_SCH_GRED is not set
+# CONFIG_NET_SCH_DELAY is not set
+# CONFIG_NET_SCH_DSMARK is not set
+# CONFIG_NET_SCH_INGRESS is not set
+# CONFIG_NET_QOS is not set
+# CONFIG_NET_CLS is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+
+#
+# ATA/IDE/MFM/RLL support
+#
+# CONFIG_IDE is not set
+# CONFIG_BLK_DEV_HD is not set
+
+#
+# SCSI support
+#
+# CONFIG_SCSI 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 is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+# CONFIG_ETHERTAP is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+# CONFIG_MACE is not set
+# CONFIG_BMAC is not set
+# CONFIG_GMAC 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
+
+#
+# Backplane Networking
+#
+# CONFIG_NPNET is not set
+
+#
+# On-chip net devices
+#
+CONFIG_IBM_OCP_ENET=y
+# CONFIG_IBM_OCP_ENET_ERROR_MSG is not set
+CONFIG_IBM_OCP_ENET_RX_BUFF=64
+CONFIG_IBM_OCP_ENET_TX_BUFF=8
+CONFIG_IBM_OCP_ENET_GAP=4
+CONFIG_IBM_OCP_ENET_SKB_RES=2
+CONFIG_OCP_NET=y
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+# CONFIG_PLIP is not set
+CONFIG_PPP=y
+# CONFIG_PPP_MULTILINK is not set
+# CONFIG_PPP_FILTER is not set
+CONFIG_PPP_ASYNC=y
+# CONFIG_PPP_SYNC_TTY is not set
+CONFIG_PPP_DEFLATE=y
+CONFIG_PPP_BSDCOMP=y
+# CONFIG_PPPOE is not set
+# CONFIG_SLIP is not set
+
+#
+# Wireless LAN (non-hamradio)
+#
+# CONFIG_NET_RADIO is not set
+
+#
+# Token Ring devices
+#
+# CONFIG_TR is not set
+# CONFIG_NET_FC is not set
+# CONFIG_RCPCI is not set
+# CONFIG_SHAPER is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN 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
+
+#
+# Old CD-ROM drivers (not SCSI, not IDE)
+#
+# CONFIG_CD_NO_IDESCSI is not set
+
+#
+# Console drivers
+#
+CONFIG_DUMMY_CONSOLE=y
+
+#
+# Frame-buffer support
+#
+# CONFIG_FB 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
+
+#
+# Macintosh device drivers
+#
+
+#
+# Character devices
+#
+CONFIG_VT=y
+# CONFIG_VT_CONSOLE is not set
+CONFIG_SERIAL=y
+CONFIG_SERIAL_CONSOLE=y
+# CONFIG_SERIAL_EXTENDED is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+CONFIG_UNIX98_PTYS=y
+CONFIG_UNIX98_PTY_COUNT=256
+
+#
+# I2C support
+#
+CONFIG_I2C=m
+CONFIG_I2C_SLAVE=m
+# CONFIG_I2C_ALGOBIT is not set
+# CONFIG_SCx200_ACB is not set
+# CONFIG_I2C_ALGOPCF is not set
+CONFIG_I2C_IBM_IIC=m
+CONFIG_I2C_ASICSMS=m
+CONFIG_I2C_CHARDEV=m
+CONFIG_I2C_PROC=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=y
+CONFIG_WATCHDOG_NOWAYOUT=y
+# CONFIG_ACQUIRE_WDT is not set
+# CONFIG_ADVANTECH_WDT is not set
+# CONFIG_ALIM1535_WDT is not set
+# CONFIG_ALIM7101_WDT is not set
+# CONFIG_SC520_WDT is not set
+# CONFIG_PCWATCHDOG is not set
+# CONFIG_EUROTECH_WDT is not set
+# CONFIG_IB700_WDT is not set
+CONFIG_PPC405_WDT=y
+# CONFIG_WAFER_WDT is not set
+# CONFIG_I810_TCO is not set
+# CONFIG_MIXCOMWD is not set
+# CONFIG_60XX_WDT is not set
+# CONFIG_SC1200_WDT is not set
+# CONFIG_SCx200_WDT is not set
+# CONFIG_SOFT_WATCHDOG is not set
+# CONFIG_W83877F_WDT is not set
+# CONFIG_WDT is not set
+# CONFIG_WDTPCI is not set
+# CONFIG_MACHZ_WDT is not set
+# CONFIG_AMD7XX_TCO 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_X1226_RTC=y
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+# CONFIG_IBM_OCP_GPIO 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
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV 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 is not set
+# 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 is not set
+# CONFIG_JBD is not set
+# CONFIG_JBD_DEBUG is not set
+# CONFIG_FAT_FS is not set
+# CONFIG_MSDOS_FS is not set
+# CONFIG_UMSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_JFFS_FS is not set
+CONFIG_JFFS2_FS=m
+CONFIG_JFFS2_FS_DEBUG=0
+# CONFIG_CRAMFS is not set
+# CONFIG_TMPFS is not set
+CONFIG_RAMFS=y
+# CONFIG_ISO9660_FS is not set
+# CONFIG_JOLIET is not set
+# CONFIG_ZISOFS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_JFS_DEBUG is not set
+# CONFIG_JFS_STATISTICS is not set
+CONFIG_MINIX_FS=y
+# CONFIG_VXFS_FS is not set
+# CONFIG_NTFS_FS is not set
+# CONFIG_NTFS_RW is not set
+# CONFIG_HPFS_FS is not set
+CONFIG_PROC_FS=y
+# CONFIG_DEVFS_FS is not set
+# CONFIG_DEVFS_MOUNT is not set
+# 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=y
+# 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 is not set
+# CONFIG_NFSD_V3 is not set
+# CONFIG_NFSD_TCP is not set
+CONFIG_SUNRPC=y
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_SMB_FS=y
+# 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 is not set
+
+#
+# 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-1"
+# CONFIG_NLS_CODEPAGE_437 is not set
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# 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 is not set
+# 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 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# IBM 4xx options
+#
+
+#
+# USB support
+#
+# CONFIG_USB is not set
+
+#
+# Support for USB gadgets
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# Bluetooth support
+#
+# CONFIG_BLUEZ is not set
+
+#
+# Cryptographic options
+#
+CONFIG_CRYPTO=y
+CONFIG_CRYPTO_HMAC=y
+CONFIG_CRYPTO_NULL=y
+# CONFIG_CRYPTO_MD4 is not set
+# CONFIG_CRYPTO_MD5 is not set
+# CONFIG_CRYPTO_SHA1 is not set
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_DES is not set
+# CONFIG_CRYPTO_BLOWFISH is not set
+# CONFIG_CRYPTO_TWOFISH is not set
+# CONFIG_CRYPTO_SERPENT is not set
+CONFIG_CRYPTO_AES=y
+# CONFIG_CRYPTO_CAST5 is not set
+# CONFIG_CRYPTO_CAST6 is not set
+# CONFIG_CRYPTO_ARC4 is not set
+# CONFIG_CRYPTO_DEFLATE is not set
+# CONFIG_CRYPTO_TEST is not set
+
+#
+# Library routines
+#
+# CONFIG_CRC32 is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
+# CONFIG_FW_LOADER is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_DEBUG_KERNEL is not set
+# CONFIG_SERIAL_TEXT_DEBUG is not set
+CONFIG_LOG_BUF_SHIFT=0
Index: pplinux/linuxnew/arch/ppc/kernel/Makefile
diff -u pplinux/linuxnew/arch/ppc/kernel/Makefile:1.1.323.1 pplinux/linuxnew/arch/ppc/kernel/Makefile:1.2
--- pplinux/linuxnew/arch/ppc/kernel/Makefile:1.1.323.1	Thu Feb  3 10:00:25 2005
+++ pplinux/linuxnew/arch/ppc/kernel/Makefile	Thu Feb  3 11:35:37 2005
@@ -34,7 +34,8 @@
 export-objs			:= ppc_ksyms.o time.o ocp.o ppc4xx_setup.o \
 					ppc4xx_dma.o ppc4xx_sgdma.o \
 					ppc4xx_stbdma.o ppc4xx_pm.o \
-					gt64260_common.o
+					gt64260_common.o \
+					ppc405_pcimcs.o
 
 obj-y				:= entry.o traps.o irq.o idle.o time.o misc.o \
 					process.o signal.o ptrace.o align.o \
@@ -60,7 +61,7 @@
 obj-$(CONFIG_SERIAL_TEXT_DEBUG)	+= gt64260_dbg.o
 endif
 
-obj-$(CONFIG_40x)		+= ppc4xx_setup.o
+obj-$(CONFIG_40x)		+= ppc4xx_setup.o ppc4xx_i2c.o
 obj-$(CONFIG_4xx)		+= ocp.o todc_time.o
 ifeq ($(CONFIG_XILINX_OCP),y)
 obj-$(CONFIG_4xx)		+= xilinx_pic.o
@@ -73,6 +74,7 @@
 ifeq ($(CONFIG_PCI),y)
 obj-$(CONFIG_40x)		+= ppc405_pci.o
 obj-$(CONFIG_4xx)		+= indirect_pci.o pci_auto.o
+obj-$(CONFIG_PEPPERCON)		+= ppc405_pcimcs.o
 endif
 obj-$(CONFIG_44x)		+= ppc4xx_pic.o ibm44x_common.o
 obj-$(CONFIG_440GP)		+= ibm440gp_common.o
Index: pplinux/linuxnew/arch/ppc/kernel/ocp.c
diff -u pplinux/linuxnew/arch/ppc/kernel/ocp.c:1.1.323.1 pplinux/linuxnew/arch/ppc/kernel/ocp.c:1.2
--- pplinux/linuxnew/arch/ppc/kernel/ocp.c:1.1.323.1	Thu Feb  3 10:00:25 2005
+++ pplinux/linuxnew/arch/ppc/kernel/ocp.c	Fri Apr 29 10:43:28 2005
@@ -327,7 +327,7 @@
 {
 	struct	ocp_device	*dev;
 
-	DBG(("ocp: ocp_add_one_device(vendor: %x, function: %x, index: %d)...\n", vendor, function, index));
+	DBG(("ocp: ocp_add_one_device(vendor: %x, function: %x, index: %d)...\n", def->vendor, def->function, def->index));
 
 	/* Can't be called after ocp driver init */
 	if (ocp_inited)
@@ -349,7 +349,7 @@
 	list_add_tail(&dev->link, &ocp_devices);
 	up_write(&ocp_devices_sem);
 
-	DBG(("ocp: ocp_add_one_device(vendor: %x, function: %x, index: %d)...done.\n", vendor, function, index));
+	DBG(("ocp: ocp_add_one_device(vendor: %x, function: %x, index: %d)...done.\n", def->vendor, def->function, def->index));
 
 	return 0;
 }
Index: pplinux/linuxnew/arch/ppc/kernel/pci.c
diff -u pplinux/linuxnew/arch/ppc/kernel/pci.c:1.1.323.1 pplinux/linuxnew/arch/ppc/kernel/pci.c:1.2
--- pplinux/linuxnew/arch/ppc/kernel/pci.c:1.1.323.1	Thu Feb  3 10:00:25 2005
+++ pplinux/linuxnew/arch/ppc/kernel/pci.c	Thu Feb  3 11:35:37 2005
@@ -22,7 +22,7 @@
 #include <asm/irq.h>
 #include <asm/uaccess.h>
 
-#undef DEBUG
+#define DEBUG
 
 #ifdef DEBUG
 #define DBG(x...) printk(x)
Index: pplinux/linuxnew/arch/ppc/kernel/pci_auto.c
diff -u pplinux/linuxnew/arch/ppc/kernel/pci_auto.c:1.1.323.1 pplinux/linuxnew/arch/ppc/kernel/pci_auto.c:1.2
--- pplinux/linuxnew/arch/ppc/kernel/pci_auto.c:1.1.323.1	Thu Feb  3 10:00:25 2005
+++ pplinux/linuxnew/arch/ppc/kernel/pci_auto.c	Thu Feb  3 11:35:37 2005
@@ -29,7 +29,7 @@
 
 #define	PCIAUTO_IDE_MODE_MASK		0x05
 
-#undef DEBUG
+#define DEBUG
 
 #ifdef DEBUG
 #define DBG(x...) printk(x)
Index: pplinux/linuxnew/arch/ppc/kernel/ppc405_pci.c
diff -u pplinux/linuxnew/arch/ppc/kernel/ppc405_pci.c:1.1.323.1 pplinux/linuxnew/arch/ppc/kernel/ppc405_pci.c:1.2
--- pplinux/linuxnew/arch/ppc/kernel/ppc405_pci.c:1.1.323.1	Thu Feb  3 10:00:25 2005
+++ pplinux/linuxnew/arch/ppc/kernel/ppc405_pci.c	Thu Feb  3 11:35:37 2005
@@ -31,6 +31,7 @@
  *  675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
+#include <linux/config.h>
 #include <linux/pci.h>
 #include <asm/io.h>
 #include <asm/system.h>
@@ -41,6 +42,8 @@
 #include <asm/pci-bridge.h>
 #include <asm/ocp.h>
 
+#define CONFIG_DEBUG_BRINGUP
+
 #ifdef  CONFIG_DEBUG_BRINGUP
 #define DBG(x...) printk(x)
 #else
Index: pplinux/linuxnew/arch/ppc/kernel/ppc405_pcimcs.c
diff -u /dev/null pplinux/linuxnew/arch/ppc/kernel/ppc405_pcimcs.c:1.1
--- /dev/null	Tue May 24 10:37:58 2005
+++ pplinux/linuxnew/arch/ppc/kernel/ppc405_pcimcs.c	Thu Feb  3 11:35:37 2005
@@ -0,0 +1,293 @@
+/*
+ * FILE NAME: ppc405_pcimcs.c
+ *
+ * BRIEF MODULE DESCRIPTION:
+ * machine check save pci access and configuration routines.
+ * These routines may also be used in case a certain PCI
+ * resource is physically not present. The according functions
+ * will return an error code.
+ *
+ * Author: Peppercon AG
+ *         Thomas Breitfeld <thomas@peppercon.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  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 <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/module.h>
+#include <asm/io.h>
+#include <asm/system.h>
+#include <asm/machdep.h>
+#include <asm/ppc405_pcimcs.h>
+#include <linux/init.h>
+#include <asm/pci-bridge.h>
+
+/*
+ * NOTE:
+ *
+ *   after a data machine check the NIP is set to the next instruction in
+ *   stream. Normally it should be the "eieio" instruction following our
+ *   I/O operation. But there are cases where this isn't true, e.g. if an
+ *   interupt occured. In this case the NIP is set to the first
+ *   instruction of the interrupt handler. This prevents the execution of
+ *   our exception handler. Solution: disable interrupts.
+ */
+u8 mcs_in_8(volatile u8 * addr, int * error)
+{
+	u_long flags;
+	u32 err;
+	u32 data;
+
+	local_irq_save(flags);
+        __asm__ __volatile__(
+			     "       lbz%U2%X2 %0,%2\n"
+			     "1:     eieio\n"
+			     "       li %1,0\n"
+			     "2:\n"
+			     ".section .fixup,\"ax\"\n"
+			     "3:     li %1,-1\n"
+			     "       b 2b\n"
+			     ".section __ex_table,\"a\"\n"
+			     "       .align 2\n"
+			     "       .long 1b,3b\n"
+			     ".text"
+			     : "=r" (data), "=r" (err)
+			     : "m" (*addr) );
+	local_irq_restore(flags);
+	*error = err;
+	return data;
+}
+
+u16 mcs_in_le16(volatile u16 * addr, int * error)
+{
+	u_long flags;
+	u32 err;
+	u32 data;
+
+	local_irq_save(flags);
+        __asm__ __volatile__(
+			     "       lhbrx %0,0,%2\n"
+			     "1:     eieio\n"
+			     "       li %1,0\n"
+			     "2:\n"
+			     ".section .fixup,\"ax\"\n"
+			     "3:     li %1,-1\n"
+			     "       b 2b\n"
+			     ".section __ex_table,\"a\"\n"
+			     "       .align 2\n"
+			     "       .long 1b,3b\n"
+			     ".text"
+			     : "=r" (data), "=r" (err)
+			     : "r" (addr), "m" (*addr) );
+	local_irq_restore(flags);
+	*error = err;
+	return data;
+}
+
+u32 mcs_in_le32(volatile u32 * addr, int * error)
+{
+	u_long flags;
+	u32 err;
+	u32 data;
+
+	local_irq_save(flags);
+	__asm__ __volatile__(
+			     "       lwbrx %0,0,%2\n"
+			     "1:     eieio\n"
+			     "       li %1,0\n"
+			     "2:\n"
+			     ".section .fixup,\"ax\"\n"
+			     "3:     li %1,-1\n"
+			     "       b 2b\n"
+			     ".section __ex_table,\"a\"\n"
+			     "       .align 2\n"
+			     "       .long 1b,3b\n"
+			     ".text"
+			     : "=r" (data), "=r" (err)
+			     : "r" (addr), "m" (*addr) );
+	local_irq_restore(flags);
+	*error = err;
+	return data;
+}
+
+void mcs_out_8(u32 data, volatile u8 * addr, int * error)
+{
+	u_long flags;
+	u32 err;
+
+	local_irq_save(flags);
+        __asm__ __volatile__(
+			     "       stb%U0%X0 %2,%0\n"
+			     "1:     eieio\n"
+			     "       li %1,0\n"
+			     "2:\n"
+			     ".section .fixup,\"ax\"\n"
+			     "3:     li %1,-1\n"
+			     "       b 2b\n"
+			     ".section __ex_table,\"a\"\n"
+			     "       .align 2\n"
+			     "       .long 1b,3b\n"
+			     ".text"
+			     : "=m" (*addr), "=r" (err)
+			     : "r" (data) );
+	local_irq_restore(flags);
+	*error = err;
+}
+
+void mcs_out_le16(u32 data, volatile u16 * addr, int * error)
+{
+	u_long flags;
+	u32 err;
+
+	local_irq_save(flags);
+        __asm__ __volatile__(
+			     "       sthbrx %2,0,%3\n"
+			     "1:     eieio\n"
+			     "       li %1,0\n"
+			     "2:\n"
+			     ".section .fixup,\"ax\"\n"
+			     "3:     li %1,-1\n"
+			     "       b 2b\n"
+			     ".section __ex_table,\"a\"\n"
+			     "       .align 2\n"
+			     "       .long 1b,3b\n"
+			     ".text"
+			     : "=m" (*addr), "=r" (err)
+			     : "r" (data), "r" (addr) );
+	local_irq_restore(flags);
+	*error = err;
+}
+
+void mcs_out_le32(u32 data, volatile u32 * addr, int * error)
+{
+	u_long flags;
+	u32 err;
+
+	local_irq_save(flags);
+        __asm__ __volatile__(
+			     "       stwbrx %2,0,%3\n"
+			     "1:     eieio\n"
+			     "       li %1,0\n"
+			     "2:\n"
+			     ".section .fixup,\"ax\"\n"
+			     "3:     li %1,-1\n"
+			     "       b 2b\n"
+			     ".section __ex_table,\"a\"\n"
+			     "       .align 2\n"
+			     "       .long 1b,3b\n"
+			     ".text"
+			     : "=m" (*addr), "=r" (err)
+			     : "r" (data), "r" (addr) );
+	local_irq_restore(flags);
+	*error = err;
+}
+
+/*
+ *  config space access with caught
+ *  Machine Check exception. This is necessary
+ *  as we try to detect our VGA chip with an
+ *  config cycle, means also in case it is switched
+ *  off. The advanced error reporting leads in this
+ *  case to a machine check exception that needs
+ *  to be handled
+ *  mcs - means machine check save
+ */
+#define MCS_read(val, addr, type, op, errp) *val = op((type)(addr), errp)
+#define MCS_write(val, addr, type, op, errp) op((val), (type*)(addr), errp)
+ 
+#define MCS_PCI_CONFIG_OP(rw, size, type, op, mask)                        \
+int                                                                        \
+mcs_pci_##rw##_config_##size(struct pci_dev *dev, int offset, type value)  \
+{                                                                          \
+  u32 error;                                                               \
+  struct pci_controller* hose = dev->sysdata;                              \
+  out_be32(hose->cfg_addr, ((offset & 0xfc) << 24) | (dev->devfn << 16)    \
+           | (dev->bus->number << 8) | 0x80);                              \
+  MCS_##rw(value, hose->cfg_data + (offset & mask), type, op, &error);     \
+  return error;                                                            \
+}
+
+MCS_PCI_CONFIG_OP(read, byte, u8*, mcs_in_8, 3)
+MCS_PCI_CONFIG_OP(read, word, u16*, mcs_in_le16, 2)
+MCS_PCI_CONFIG_OP(read, dword, u32*, mcs_in_le32, 0)
+MCS_PCI_CONFIG_OP(write, byte, u8, mcs_out_8, 3)
+MCS_PCI_CONFIG_OP(write, word, u16, mcs_out_le16, 2)
+MCS_PCI_CONFIG_OP(write, dword, u32, mcs_out_le32, 0)
+ 
+#if 0
+/*
+ * I'll better leave an example in here to show
+ * to what the macros will expand... ;-)
+ */
+int
+mcs_pci_read_config_byte(struct pci_dev *dev, int offset, u8* value)
+{
+  u32 error;
+  struct pci_controller* hose = dev->sysdata;
+  out_be32(hose->cfg_addr,
+           ((offset & 0xfc) << 24) | (dev->devfn << 16)
+           | (dev->bus->number << 8) | 0x80);
+  *value = mcs_in_8((u8*)hose->cfg_data + (offset & 3), &error);
+  return error;
+}
+#endif
+
+#define CFG_read(val, addr, type, op) *val = op((type)(addr))
+#define CFG_write(val, addr, type, op) op((type*)(addr), (val))
+ 
+#define FIX_PCI_CONFIG_OP(rw, size, type, op, mask)                        \
+void                                                                       \
+fix_pci_##rw##_config_##size(u32 cfg_addr, u32 cfg_data,                   \
+			     int offset, type value)                       \
+{                                                                          \
+  out_be32((u32*)cfg_addr, ((offset & 0xfc) << 24) | (0 << 16)             \
+           | (0 << 8) | 0x80);                                             \
+  CFG_##rw(value, cfg_data + (offset & mask), type, op);                   \
+}
+ 
+FIX_PCI_CONFIG_OP(read,  byte,  u8*,  in_8,   3)
+FIX_PCI_CONFIG_OP(read,  word,  u16*, in_le16,   2)
+FIX_PCI_CONFIG_OP(read,  dword, u32*, in_le32,  0)
+FIX_PCI_CONFIG_OP(write, byte,  u8,   out_8,   3)
+FIX_PCI_CONFIG_OP(write, word,  u16,  out_le16,  2)
+FIX_PCI_CONFIG_OP(write, dword, u32,  out_le32, 0)
+
+
+EXPORT_SYMBOL(mcs_in_8);
+EXPORT_SYMBOL(mcs_in_le16);
+EXPORT_SYMBOL(mcs_in_le32);
+EXPORT_SYMBOL(mcs_out_8);
+EXPORT_SYMBOL(mcs_out_le16);
+EXPORT_SYMBOL(mcs_out_le32);
+EXPORT_SYMBOL(mcs_pci_read_config_byte);
+EXPORT_SYMBOL(mcs_pci_read_config_word);
+EXPORT_SYMBOL(mcs_pci_read_config_dword);
+EXPORT_SYMBOL(mcs_pci_write_config_byte);
+EXPORT_SYMBOL(mcs_pci_write_config_word);
+EXPORT_SYMBOL(mcs_pci_write_config_dword);
+EXPORT_SYMBOL(fix_pci_read_config_byte);
+EXPORT_SYMBOL(fix_pci_read_config_word);
+EXPORT_SYMBOL(fix_pci_read_config_dword);
+EXPORT_SYMBOL(fix_pci_write_config_byte);
+EXPORT_SYMBOL(fix_pci_write_config_word);
+EXPORT_SYMBOL(fix_pci_write_config_dword);
+
Index: pplinux/linuxnew/arch/ppc/kernel/ppc4xx_i2c.c
diff -u /dev/null pplinux/linuxnew/arch/ppc/kernel/ppc4xx_i2c.c:1.2
--- /dev/null	Tue May 24 10:37:58 2005
+++ pplinux/linuxnew/arch/ppc/kernel/ppc4xx_i2c.c	Fri Apr 29 10:43:28 2005
@@ -0,0 +1,475 @@
+/*****************************************************************************/
+/* I2C Bus interface initialisation and I2C Commands                         */
+/* for PPC405GP		                                                     */
+/* Author : AS HARNOIS                                                       */
+/* Date   : 13.Dec.00                                                        */
+/*****************************************************************************/
+
+#include <linux/config.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/smp.h>
+#include <linux/threads.h>
+#include <linux/spinlock.h>
+
+#include <asm/system.h>
+#include <linux/interrupt.h>
+
+#include <linux/param.h>
+#include <linux/string.h>
+#include <linux/blk.h>
+#include <linux/pci.h>
+#include <linux/rtc.h>
+#include <linux/console.h>
+#include <linux/ide.h>
+
+#include <asm/processor.h>
+#include <asm/ibm4xx.h>
+#include <asm/machdep.h>
+#include <asm/page.h>
+#include <asm/kgdb.h>
+#include <asm/time.h>
+#include <asm/ppc4xx_i2c.h>
+
+#ifdef DEBUG
+# define D(fmt, args...)	{ printk(fmt, ##args); }
+#else
+# define D(fmt, args...)	{ }
+#endif
+
+static void out8(void *ptr, unsigned char val){
+ /* Ensure I/O operations complete */
+/* __asm__ volatile("eieio");
+ * writeb has internal eieio
+ */
+
+   writeb(val, ptr);
+		
+}
+
+static unsigned char in8(void *ptr){
+
+   return readb(ptr);
+}
+
+
+void i2c_init(void)
+{
+  bd_t* bd = (bd_t*)__res;
+  int divisor;
+
+  D("I2C_INIT\n");
+  /* clear lo master address */
+  out8(IIC_LMADR,0);
+  /* clear hi master address */
+  out8(IIC_HMADR,0);
+  /* clear lo slave address */
+  out8(IIC_LSADR,0);
+  /* clear hi slave address */
+  out8(IIC_HSADR,0);
+
+  /* Reset status register */
+  /* write 1 in SCMP IRQA to clear these fields */
+  /* !!! ASH QpenBios says 0x08 */
+  /*  out8(IIC_STS, 0x0C);  */
+  out8(IIC_STS, 0x08);
+  /* write 1 in IRQP IRQD LA ICT XFRA to clear these fields */
+  out8(IIC_EXTSTS, 0x8F);
+
+
+  /* Clock divide Register */
+  
+  /* set divisor according to OPB frequency */
+  if (bd->bi_opb_busfreq <= 20000000)
+    divisor = 0x1;
+  else if (bd->bi_opb_busfreq <= 30000000)
+    divisor = 0x2;
+  else if (bd->bi_opb_busfreq <= 40000000)
+    divisor = 0x3;
+  else if (bd->bi_opb_busfreq <= 50000000)
+    divisor = 0x4;
+  else
+    divisor = 0x5;
+  out8(IIC_CLKDIV,divisor);
+
+  /* no interrupts */
+  out8(IIC_INTRMSK,0);
+
+  /* clear transfer count */
+  out8(IIC_XFRCNT,0);
+
+
+  /* clear extended control & stat */
+  /* write 1 in SRC SRS SWC SWS to clear these fields */
+  out8(IIC_XTCNTLSS,0xF0);
+
+
+  /* Mode Control Register
+     Flush Slave/Master data buffer
+     Ignore General Call, 100kHz, slave transfers are ignored,
+     disable interrupts, exit unknown bus state, enable hold
+     SCL
+  */
+  out8(IIC_MDCNTL, IIC_MDCNTL_FSDB | IIC_MDCNTL_FMDB | IIC_MDCNTL_EUBS);
+
+
+//  out8(IIC_MDCNTL, ((in8(IIC_MDCNTL))|IIC_MDCNTL_EUBS|IIC_MDCNTL_HSCL));
+//sand
+//  out8(IIC_MDCNTL, (IIC_MDCNTL_EUBS);
+//
+
+  /* clear control reg */
+  out8(IIC_CNTL,0x00);
+
+
+}
+
+
+static int i2c_transfer(unsigned char command_is_reading, unsigned char address,
+		 unsigned short size_to_transfer, unsigned char data[] )
+{
+  bd_t* bd = (bd_t*)__res;
+  int bytes_transfered;
+  int result;
+  int status;
+  int i, TimeReady, TimeOut;
+
+  result = IIC_OK;
+  bytes_transfered = 0;
+
+  D("i2c transfer called\n");
+
+  /* Check init */
+  i=10;
+  do{
+    /* Get status */
+    status = in8(IIC_STS);
+
+    i--;
+  }while ((status & IIC_STS_PT) && (i>0));
+  if (status & IIC_STS_PT)
+    {
+      result = IIC_NOK_TOUT;
+      D("IIC_NOK_TOUT \n");
+      return(result);
+    }
+
+  /* 7-bit adressing */
+  out8(IIC_HMADR,0);
+
+  out8(IIC_LMADR, address);
+
+
+  /* In worst case, you need to wait 4 OPB clocks */
+  /* for data being ready on IIC bus */
+  /* (because FIFO is 4 bytes depth) */
+  TimeReady = (4/(bd->bi_procfreq/bd->bi_opb_busfreq)) + 1;
+
+  /* IIC time out => wait for TimeOut cycles */
+  /* TimeOut /= 2; because waiting-loop is 2-instruction loop */
+  TimeOut = bd->bi_procfreq*IIC_TIMEOUT;// * 10;
+  TimeOut /= 2;
+
+  while ((bytes_transfered < size_to_transfer) && (result == IIC_OK))
+    {
+      D("\niic transfer: write %d byte (size %d)\n",bytes_transfered, size_to_transfer);
+  
+      /* Control register =
+	 Normal transfer, 7-bits adressing, Transfer 1 byte, Normal start,
+	 Transfer is a sequence of transfers
+	 Write/Read, Start transfer */
+
+      /* ACTION => Start - Transfer - Ack - pause */
+      /* ACTION - LAST BYTE => Start - Transfer - Nack  - Stop */
+      if (command_is_reading)
+	{
+          D("iic transfer: read command\n");
+	  /* issue read command */
+	  if (bytes_transfered == size_to_transfer-1)
+	    {
+	    out8(IIC_CNTL, IIC_CNTL_READ | IIC_CNTL_PT);
+	
+	    }
+	  else
+	    {
+	      out8(IIC_CNTL, IIC_CNTL_READ | IIC_CNTL_CHT | IIC_CNTL_PT);
+	
+	    }
+	}
+      else
+	{
+          D("iic transfer: write command\n");
+	  /* Set buffer */
+	  out8(IIC_MDBUF,data[bytes_transfered]);
+	
+	  i=TimeReady;
+	  do{
+	    i--;
+	  }while(i>0);
+	  /* issue write command */
+	  if (bytes_transfered == size_to_transfer-1)
+	    {
+	    out8(IIC_CNTL, IIC_CNTL_PT);
+	
+	    }
+	  else
+	    {
+	    out8(IIC_CNTL, IIC_CNTL_CHT | IIC_CNTL_PT);
+	
+	    }
+	}
+
+	D("iic transfer in progress\n");
+      /* Transfer is in progress */
+      i=TimeOut;
+      do{
+	/* Get status */
+	status = in8(IIC_STS);
+	
+	i--;
+      }while ((status & IIC_STS_PT) && (i>0));
+
+      if (status & IIC_STS_PT)
+	{
+	  D("Transfer pending\n");	
+	  result = IIC_NOK_TOUT;
+	}
+      else if (status & IIC_STS_ERR)
+	{
+          D("iic transfer: IIC_STS_ERR\n");
+	  result = IIC_NOK;
+	  status = in8(IIC_EXTSTS);
+          D("iic transfer: IIC_EXTSTS: %02x\n",status);
+	
+	  /* Lost arbitration? */
+	  if (status & IIC_EXTSTS_LA)
+	    result = IIC_NOK_LA;
+	  /* Incomplete transfer? */
+	  if (status & IIC_EXTSTS_ICT)
+	    result = IIC_NOK_ICT;
+	  /* Transfer aborted? */
+	  if (status & IIC_EXTSTS_XFRA)
+	    result = IIC_NOK_XFRA;
+	}
+      /* Command is reading => get buffer */
+      if ((command_is_reading) && (result == IIC_OK))
+	{
+	  /* Are there data in buffer */
+	  if (status & IIC_STS_MDBS)
+	    {
+	      i=TimeReady;
+	      do{
+		i--;
+	      }while(i>0);
+	      data[bytes_transfered] = in8(IIC_MDBUF);
+	
+	    }
+	  else result = IIC_NOK_DATA;
+	}
+      bytes_transfered++;
+    }
+  D("iic transfer: bytes transfered: %d\n",bytes_transfered);
+  return(result);
+}
+
+
+int i2c_receive(unsigned char address,
+		 unsigned short size_to_expect, unsigned char datain[] )
+{
+  int status;
+  
+  status = i2c_transfer(1, address, size_to_expect, datain);
+#ifdef CONFIG_PEPPERCON
+  if (status != 0) {
+  	D("I2C error => status = %d\n", status);
+#if 0
+  	D("I2C error => status = %02x\n", in8(IIC_STS));
+  	D("I2C error => ext status = %02x\n", in8(IIC_EXTSTS));
+  	D("I2C error => transfer count  = %02x\n", in8(IIC_XFRCNT));
+  	D("I2C error => ext slave status = %02x\n", in8(IIC_XTCNTLSS));
+#endif
+  }
+#endif
+  return status;
+}
+
+
+int i2c_send(unsigned char address,
+		 unsigned short size_to_send, unsigned char dataout[] )
+{
+  int status;
+  status = i2c_transfer(0, address, size_to_send, dataout);
+#if defined(CONFIG_WALNUT405) || defined (CONFIG_PEPPERCON)
+  if (status != 0) {
+  	D("I2C error => status = %d\n", status);
+#if 0
+  	D("I2C error => status = %02x\n", in8(IIC_STS));
+  	D("I2C error => ext status = %02x\n", in8(IIC_EXTSTS));
+  	D("I2C error => transfer count  = %02x\n", in8(IIC_XFRCNT));
+  	D("I2C error => ext slave status = %02x\n", in8(IIC_XTCNTLSS));
+#endif
+  }
+#endif
+  return status;
+}
+
+
+int i2c_read (unsigned char *addr, int alen, unsigned char *buffer, int len)
+{
+	int ret = 0;
+
+	D ("I2C read: addr len %d len %x\n", alen, len);
+	if (alen == 2) {
+		ret = i2c_send(addr[0] << 1, 1, addr+1);
+		if (ret) return ret;
+		ret = i2c_receive ((addr[0] << 1) | 0x01, len, buffer);
+	}
+	else if (alen == 3) {
+		ret = i2c_send(addr[0] << 1, 2, addr+1);
+		if (ret) return ret;
+		ret = i2c_receive((addr[0] << 1) | 0x01, len, buffer);
+	} else{
+		D("I2C read: addr len %d not supported\n", alen);
+		ret = -1;
+	}
+	
+	return ret;
+}
+
+int i2c_write (unsigned char *addr, int alen, unsigned char *buffer, int len)
+{
+	unsigned char xbuf[3];
+//	unsigned char intaddr[2];
+	unsigned short eepaddr;
+	int timeout;
+
+	D ("I2C write: addr len %d len %x\n", alen,len);
+	if (alen == 2) {
+		/* write with ack polling */
+		/* XXX this should be improved to allow page write mode XXX - wd */
+		while (len-- > 0) {
+          		xbuf[0] = addr[1]++; /* increase write offset */
+          		xbuf[1] = *buffer++;
+          		while (i2c_send(addr[0] << 1, 2, xbuf) != 0) /* single write + ack polling */
+            		udelay(100);
+		}
+	}else if (alen == 3){
+		/* write with ack polling */
+		/* XXX this should be improved to allow page write mode XXX - wd */
+		eepaddr = addr[1];
+		eepaddr <<= 8;
+		eepaddr |= addr[2];
+		while (len-- > 0) {
+//          		D("\nwrite %02x to eep (%02x) address %02x%02x\n", xbuf[2],addr[0]<<1,xbuf[0],xbuf[1]);
+			xbuf[0] = eepaddr >> 8; /* increase write offset */
+          		xbuf[1] = (unsigned char) eepaddr & 0xFF;
+          		xbuf[2] = *buffer++;
+			eepaddr++;
+//          		D("write %02x to eep (%02x) address %02x%02x\n", xbuf[2],addr[0]<<1,xbuf[0],xbuf[1]);
+          		timeout = 0;
+          		while (i2c_send(addr[0] << 1, 3, xbuf) != 0){ /* single write + ack polling */
+            			udelay(100);
+            			timeout++;	
+            			if (timeout > 10) {
+            				D("I2C write timeout after %d * 100 udelays\n",timeout);
+            				return -1;
+            			}
+            		};
+//			D("I2C write need %d * 100 udelays\n",timeout);
+            		
+		}
+	}else {
+		D("I2C write: addr len %d not supported\n", alen);
+		return -1;
+	}
+
+	return 0;
+}
+
+/*-----------------------------------------------------------------------
+ */
+
+int rtc_read (unsigned offset, unsigned char *buffer, unsigned cnt)
+{
+	unsigned end = offset + cnt;
+	unsigned blk_off;
+	int ret;
+
+	D("RTC read\n");
+	/* Read data until done or would cross a page boundary.
+	 * We must write the address again when changing pages
+	 * because the next page may be in a different device.
+	 */
+	while (offset < end) {
+		unsigned alen, len, maxlen;
+		unsigned char addr[3];
+
+		blk_off = offset & 0xFF;	/* block offset */
+
+		addr[0] = offset >> 16;		/* block number */
+		addr[1] = offset >>  8;		/* upper address octet */
+		addr[2] = blk_off;		/* lower address octet */
+		alen	= 3;
+
+		addr[0] |= CFG_I2C_RTC_ADDR;	/* insert device address */
+
+		maxlen = 0x100 - blk_off;
+		len    = end - offset;
+		if (len > maxlen)
+			len = maxlen;
+
+		if ((ret = i2c_read(addr, alen, buffer, len))) {
+			return ret;
+		}
+		buffer += len;
+		offset += len;
+	}
+
+	return 0;
+}
+
+/*-----------------------------------------------------------------------
+ */
+
+int rtc_write (unsigned offset, unsigned char *buffer, unsigned cnt)
+{
+	unsigned end = offset + cnt;
+	unsigned blk_off;
+	int ret;
+
+	/* Write data until done or would cross a write page boundary.
+	 * We must write the address again when changing pages
+	 * because the address counter only increments within a page.
+	 */
+
+	D("RTC write\n");
+	while (offset < end) {
+		unsigned alen, len, maxlen;
+		unsigned char addr[3];
+
+		blk_off = offset & 0xFF;	/* block offset */
+
+		addr[0] = 0;			/* block number */
+		addr[1] = offset >>  8;		/* upper address octet */
+		addr[2] = blk_off;		/* lower address octet */
+		alen	= 3;
+
+		addr[0] |= CFG_I2C_RTC_ADDR;	/* insert device address */
+
+		maxlen = 0x100 - blk_off;
+		len = end - offset;
+		if (len > maxlen)
+			len = maxlen;
+
+		if ((ret = i2c_write(addr, alen, buffer, len))) {
+			return ret;
+		}
+		buffer += len;
+		buffer += len;
+		offset += len;
+	}
+
+	return 0;
+}
+
+
Index: pplinux/linuxnew/arch/ppc/kernel/ppc4xx_setup.c
diff -u pplinux/linuxnew/arch/ppc/kernel/ppc4xx_setup.c:1.1.323.1 pplinux/linuxnew/arch/ppc/kernel/ppc4xx_setup.c:1.2
--- pplinux/linuxnew/arch/ppc/kernel/ppc4xx_setup.c:1.1.323.1	Thu Feb  3 10:00:25 2005
+++ pplinux/linuxnew/arch/ppc/kernel/ppc4xx_setup.c	Thu Feb  3 11:35:37 2005
@@ -236,7 +236,8 @@
 	bd_t *bip = (bd_t *) __res;
 
 #if defined(CONFIG_WALNUT) || defined(CONFIG_CEDER) 	\
-	|| defined(CONFIG_ASH) || defined(CONFIG_SYCAMORE)
+	|| defined(CONFIG_ASH) || defined(CONFIG_SYCAMORE) \
+	|| (defined(CONFIG_PEPPERCON) && !defined(CONFIG_405EP))
 	/* Openbios sets cpu  timers to CPU clk
 	 * we want to use the external clk
 	 * DCR CHCR1 (aka CPC0_CR1) bit CETE to 1 */
Index: pplinux/linuxnew/arch/ppc/kernel/ppc4xx_sgdma.c
diff -u pplinux/linuxnew/arch/ppc/kernel/ppc4xx_sgdma.c:1.1.323.1 pplinux/linuxnew/arch/ppc/kernel/ppc4xx_sgdma.c:1.2
--- pplinux/linuxnew/arch/ppc/kernel/ppc4xx_sgdma.c:1.1.323.1	Thu Feb  3 10:00:25 2005
+++ pplinux/linuxnew/arch/ppc/kernel/ppc4xx_sgdma.c	Thu Feb  3 11:35:37 2005
@@ -31,7 +31,7 @@
 #include <asm/io.h>
 #include <asm/ppc4xx_dma.h>
 
-static __inline__ void
+void
 ppc4xx_set_sg_addr(int dmanr, phys_addr_t sg_addr)
 {
 	switch (dmanr) {
@@ -73,7 +73,7 @@
  *   memory to peripheral: set dst_addr to NULL,
  *   peripheral to memory: set src_addr to NULL.
  */
-static __inline__ int
+int
 ppc4xx_add_dma_sgl(sgl_handle_t handle, phys_addr_t src_addr, phys_addr_t dst_addr,
 		   unsigned int count)
 {
@@ -152,7 +152,7 @@
 /*
  * Enable (start) the DMA described by the sgl handle.
  */
-static __inline__ void
+void
 ppc4xx_enable_dma_sgl(sgl_handle_t handle)
 {
 	sgl_list_info_t *psgl = (sgl_list_info_t *) handle;
@@ -200,7 +200,7 @@
 /*
  * Halt an active scatter/gather DMA operation.
  */
-static __inline__ void
+void
 ppc4xx_disable_dma_sgl(sgl_handle_t handle)
 {
 	sgl_list_info_t *psgl = (sgl_list_info_t *) handle;
@@ -243,7 +243,7 @@
  *
  *  An sgl transfer must NOT be active when this function is called.
  */
-static __inline__ int
+int
 ppc4xx_get_dma_sgl_residue(sgl_handle_t handle, phys_addr_t * src_addr,
 			   phys_addr_t * dst_addr)
 {
@@ -346,7 +346,7 @@
  *
  * This function should only be called when the DMA is not active.
  */
-static __inline__ int
+int
 ppc4xx_delete_dma_sgl_element(sgl_handle_t handle, phys_addr_t * src_dma_addr,
 			      phys_addr_t * dst_dma_addr)
 {
@@ -382,6 +382,29 @@
 	return DMA_STATUS_GOOD;
 }
 
+/*
+ * Clear the scatter/gather list.
+ *
+ * This function should only be called when the DMA is not active.
+ */
+int
+ppc4xx_clear_dma_sgl(sgl_handle_t handle)
+{
+	sgl_list_info_t *psgl = (sgl_list_info_t *) handle;
+
+	if (!handle) {
+		printk("ppc4xx_delete_sgl_element: null handle\n");
+		return DMA_STATUS_BAD_HANDLE;
+	} else if (psgl->dmanr > (MAX_PPC4xx_DMA_CHANNELS - 1)) {
+		printk("ppc4xx_delete_sgl_element: bad channel in handle %d\n",
+		       psgl->dmanr);
+		return DMA_STATUS_BAD_CHANNEL;
+	}
+
+	psgl->phead = psgl->ptail = NULL;
+
+	return DMA_STATUS_GOOD;
+}
 
 /*
  *   Create a scatter/gather list handle.  This is simply a structure which
@@ -531,6 +554,7 @@
 EXPORT_SYMBOL(ppc4xx_free_dma_handle);
 EXPORT_SYMBOL(ppc4xx_add_dma_sgl);
 EXPORT_SYMBOL(ppc4xx_delete_dma_sgl_element);
+EXPORT_SYMBOL(ppc4xx_clear_dma_sgl);
 EXPORT_SYMBOL(ppc4xx_enable_dma_sgl);
 EXPORT_SYMBOL(ppc4xx_disable_dma_sgl);
 EXPORT_SYMBOL(ppc4xx_get_dma_sgl_residue);
Index: pplinux/linuxnew/arch/ppc/kernel/ppc_ksyms.c
diff -u pplinux/linuxnew/arch/ppc/kernel/ppc_ksyms.c:1.1.323.1 pplinux/linuxnew/arch/ppc/kernel/ppc_ksyms.c:1.2
--- pplinux/linuxnew/arch/ppc/kernel/ppc_ksyms.c:1.1.323.1	Thu Feb  3 10:00:25 2005
+++ pplinux/linuxnew/arch/ppc/kernel/ppc_ksyms.c	Thu Feb  3 11:35:37 2005
@@ -199,6 +199,7 @@
 EXPORT_SYMBOL(consistent_sync);
 EXPORT_SYMBOL(consistent_sync_page);
 EXPORT_SYMBOL(flush_dcache_all);
+EXPORT_SYMBOL(invalidate_dcache_range);
 #endif
 
 EXPORT_SYMBOL(start_thread);
Index: pplinux/linuxnew/arch/ppc/kernel/setup.c
diff -u pplinux/linuxnew/arch/ppc/kernel/setup.c:1.1.323.1 pplinux/linuxnew/arch/ppc/kernel/setup.c:1.2
--- pplinux/linuxnew/arch/ppc/kernel/setup.c:1.1.323.1	Thu Feb  3 10:00:25 2005
+++ pplinux/linuxnew/arch/ppc/kernel/setup.c	Thu Feb  3 11:35:37 2005
@@ -598,7 +598,7 @@
 			= cur_cpu_spec[0]->dcache_bsize;
 
 	/* reboot on panic */
-	panic_timeout = 180;
+	panic_timeout = 1;
 
 	init_mm.start_code = PAGE_OFFSET;
 	init_mm.end_code = (unsigned long) _etext;
Index: pplinux/linuxnew/arch/ppc/kernel/time.c
diff -u pplinux/linuxnew/arch/ppc/kernel/time.c:1.1.323.1 pplinux/linuxnew/arch/ppc/kernel/time.c:1.2
--- pplinux/linuxnew/arch/ppc/kernel/time.c:1.1.323.1	Thu Feb  3 10:00:25 2005
+++ pplinux/linuxnew/arch/ppc/kernel/time.c	Thu Feb  3 11:35:37 2005
@@ -314,12 +314,15 @@
 	 * next second boundary to try to achieve some precision.  If there
 	 * is no RTC, we still need to set tb_last_stamp and
 	 * last_jiffy_stamp(cpu 0) to the current stamp.
+	 * time_offset == -1 (from time_init) means that init failed,
+	 * so don't read the time from rtc
+	 *
 	 */
 	stamp = get_native_tbl();
-	if (ppc_md.get_rtc_time) {
-		sec = ppc_md.get_rtc_time();
+	if (ppc_md.get_rtc_time && time_offset != -1) {
+		sec = old_sec = ppc_md.get_rtc_time();
 		elapsed = 0;
-		do {
+		while (sec != -1 && sec == old_sec && elapsed < 2*HZ*tb_ticks_per_jiffy) {
 			old_stamp = stamp;
 			old_sec = sec;
 			stamp = get_native_tbl();
@@ -327,8 +330,10 @@
 				old_stamp -= 1000000000;
 			elapsed += stamp - old_stamp;
 			sec = ppc_md.get_rtc_time();
-		} while ( sec == old_sec && elapsed < 2*HZ*tb_ticks_per_jiffy);
-		if (sec == old_sec)
+		}
+		if (sec == -1)
+			printk("Warning: could not read real time clock !\n");
+		else if (sec == old_sec)
 			printk("Warning: real time clock seems stuck!\n");
 		xtime.tv_sec = sec;
 		xtime.tv_usec = 0;
Index: pplinux/linuxnew/arch/ppc/kernel/traps.c
diff -u pplinux/linuxnew/arch/ppc/kernel/traps.c:1.1.323.1 pplinux/linuxnew/arch/ppc/kernel/traps.c:1.2
--- pplinux/linuxnew/arch/ppc/kernel/traps.c:1.1.323.1	Thu Feb  3 10:00:25 2005
+++ pplinux/linuxnew/arch/ppc/kernel/traps.c	Thu Feb  3 11:35:37 2005
@@ -35,6 +35,7 @@
 #include <asm/system.h>
 #include <asm/io.h>
 #include <asm/processor.h>
+#include <asm/ppc405_pcimcs.h>
 #ifdef CONFIG_PMAC_BACKLIGHT
 #include <asm/backlight.h>
 #endif
@@ -76,11 +77,25 @@
 #endif
 #endif
 
+#if 0
+static
+void print_pci_config(void) {
+    int i;
+    printk("+++ PCI CONFIG SPACE DUMP from Machine Check Handler >>>\n");
+    for (i = 0; i < 0x78; i += 4) {
+	u32 val;
+	fix_pci_read_config_long(PPC405_PCI_CONFIG_ADDR,
+				  PPC405_PCI_CONFIG_DATA,
+				  i, &val);
+	printk("PCI Reg 0x%02x: 0x%08x\n", i, val);
+    }
+}
+#endif
+ 
 /*
  * Trap & Exception support
  */
 
-
 spinlock_t die_lock = SPIN_LOCK_UNLOCKED;
 
 void die(const char * str, struct pt_regs * fp, long err)
@@ -103,10 +118,20 @@
 	force_printk_to_btext = 0;
 #endif
 	spin_unlock_irq(&die_lock);
+#ifdef CONFIG_PEPPERCON
+	/*
+	 * we need to die completely for the moment as killing
+	 * a faulty thread is not handled currently.
+	 * that means we unconditionally panic even if it 
+	 * is just a normal task that has caused the machine check
+	 */
+	panic("Ufff, I'll better give up and try again!");
+#else 
 	/* do_exit() should take care of panic'ing from an interrupt
 	 * context so we don't handle it here
 	 */
 	do_exit(err);
+#endif
 }
 
 void
@@ -137,7 +162,78 @@
  */
 static inline int check_io_access(struct pt_regs *regs)
 {
-#ifdef CONFIG_ALL_PPC
+#if defined(CONFIG_PEPPERCON)
+	unsigned long fixup;
+
+	if ((fixup = search_exception_table(regs->nip)) != 0) {
+		regs->nip = fixup;
+		return 1;
+	}
+		
+	/* This may happen in eRIC for obscure reasons in cases
+	   where the VGA resource is not available any longer.
+	   Usually this kind of problem should be caught by the
+	   exception fixup (see above) but sometime it doesn't. 
+	   This can be detected by a PCI Master abort. In this case
+	   we try to resume by simply redoing the current instruction */
+	{
+		u16 sts;
+		u8 errsts;
+		u32 besr0;
+		u32 besr1;
+		u32 eaddr;
+		// printk(KERN_ALERT "Machine Check: NIP= 0x%lx\n", regs->nip);
+		// print pci config space
+		// print_pci_config();
+	    
+		// check whether it is a PCI Master Abort, that means
+		// it is most probably caused be a missing device in
+		// our host system, because of power off
+		fix_pci_read_config_word(PPC405_PCI_CONFIG_ADDR,
+					 PPC405_PCI_CONFIG_DATA,
+					 0x06  /*PCI_STATUS*/, &sts);
+		if (0 != (sts & PCI_STATUS_REC_MASTER_ABORT)) {
+			fix_pci_read_config_long(PPC405_PCI_CONFIG_ADDR,
+						 PPC405_PCI_CONFIG_DATA,
+						 0x54 /*PCIC0_PLBBEAR*/,
+						 &eaddr);
+			printk(KERN_ALERT "eRIC MC-handler: PCI Master Abort at 0x%x,"
+			       "NIP=0x%lx, resuming...\n", eaddr, regs->nip);
+			// clear all possible PCI errors
+			fix_pci_write_config_word(PPC405_PCI_CONFIG_ADDR,
+						  PPC405_PCI_CONFIG_DATA,
+						  0x06 /*PCI_STATUS*/, sts);
+			fix_pci_read_config_byte(PPC405_PCI_CONFIG_ADDR,
+						 PPC405_PCI_CONFIG_DATA,
+						 0x49  /*PCICO_ERRSTS*/,
+						 &errsts);
+			fix_pci_write_config_byte(PPC405_PCI_CONFIG_ADDR,
+						  PPC405_PCI_CONFIG_DATA,
+						  0x49 /*PCICO_ERRSTS*/,
+						  errsts);
+			fix_pci_read_config_long(PPC405_PCI_CONFIG_ADDR,
+						 PPC405_PCI_CONFIG_DATA,
+						 0x4c /*PCICO_PLBBESR0*/,
+						 &besr0);
+			fix_pci_write_config_long(PPC405_PCI_CONFIG_ADDR,
+						  PPC405_PCI_CONFIG_DATA,
+						  0x4c/*PCICO_PLBBESR0*/,
+						  besr0);
+			fix_pci_read_config_long(PPC405_PCI_CONFIG_ADDR,
+						 PPC405_PCI_CONFIG_DATA,
+						 0x50 /*PCICO_PLBBESR1*/,
+						 &besr1);
+			fix_pci_write_config_long(PPC405_PCI_CONFIG_ADDR,
+						  PPC405_PCI_CONFIG_DATA,
+						  0x50/*PCICO_PLBBESR1*/,
+						  besr1);
+			// try to resume
+			// THAT'S A SERIOUS HACK !!!!!!!!!!!
+			// let's see wether it's going to work
+			return 1;
+		}
+	}
+#elif defined(CONFIG_ALL_PPC)
 	unsigned long fixup;
 	unsigned long msr = regs->msr;
 
@@ -169,6 +265,7 @@
 			return 1;
 		}
 	}
+
 #endif /* CONFIG_ALL_PPC */
 	return 0;
 }
Index: pplinux/linuxnew/arch/ppc/platforms/Makefile
diff -u pplinux/linuxnew/arch/ppc/platforms/Makefile:1.1.323.1 pplinux/linuxnew/arch/ppc/platforms/Makefile:1.2
--- pplinux/linuxnew/arch/ppc/platforms/Makefile:1.1.323.1	Thu Feb  3 10:00:25 2005
+++ pplinux/linuxnew/arch/ppc/platforms/Makefile	Thu Feb  3 11:35:37 2005
@@ -23,7 +23,7 @@
 O_TARGET := platform.o
 
 export-objs			:= prep_setup.o beech.o ibm405lp.o arctic2.o \
-				   mpc8260_pci9.o ibm440gp.o ibm440gx.o
+				   mpc8260_pci9.o ibm440gp.o ibm440gx.o peppercon.o
 
 obj-$(CONFIG_405GP)		+= ibm405gp.o
 obj-$(CONFIG_405LP)		+= ibm405lp.o
@@ -94,6 +94,7 @@
 obj-$(CONFIG_SANDPOINT)		+= sandpoint_setup.o sandpoint_pci.o
 obj-$(CONFIG_SPRUCE)		+= spruce_setup.o spruce_pci.o cpc700_pic.o
 obj-$(CONFIG_HXEB100)		+= hxeb100.o
+obj-$(CONFIG_PEPPERCON)		+= peppercon.o
 
 ifeq ($(CONFIG_SMP),y)
 obj-$(CONFIG_ALL_PPC)		+= pmac_smp.o chrp_smp.o
Index: pplinux/linuxnew/arch/ppc/platforms/ibm405ep.c
diff -u pplinux/linuxnew/arch/ppc/platforms/ibm405ep.c:1.1.323.1 pplinux/linuxnew/arch/ppc/platforms/ibm405ep.c:1.2
--- pplinux/linuxnew/arch/ppc/platforms/ibm405ep.c:1.1.323.1	Thu Feb  3 10:00:25 2005
+++ pplinux/linuxnew/arch/ppc/platforms/ibm405ep.c	Thu Feb  3 11:35:37 2005
@@ -31,7 +31,7 @@
 	.mal_tx1_chan	= 0,		/* MAL tx channel 1 number */
 	.mal_tx2_chan	= 1,		/* MAL tx channel 2 number */
 	.wol_irq	= BL_MAC_WOL,	/* WOL interrupt number */
-	.mdio_idx	= -1,		/* No shared MDIO */
+	.mdio_idx	= 0,		/* No shared MDIO */
 };
 
 // FIXME: Check WOL IRQ
@@ -43,15 +43,15 @@
 	.mal_tx1_chan	= 2,		/* MAL tx channel 1 number */
 	.mal_tx2_chan	= 3,		/* MAL tx channel 2 number */
 	.wol_irq	= BL_MAC_WOL,	/* WOL interrupt number */
-	.mdio_idx	= -1,		/* No shared MDIO */
+	.mdio_idx	= 0,		/* No shared MDIO */
 };
 
 static struct ocp_func_mal_data ibm405ep_mal0_def = {
-	.num_tx_chans	= 2*EMAC_NUMS,	/* Number of TX channels */
-	.num_rx_chans	= EMAC_NUMS,	/* Number of RX channels */
+	.num_tx_chans	= 4,	/* Number of TX channels */
+	.num_rx_chans	= 2,	/* Number of RX channels */
 };
 
-struct ocp_def core_ocp[]  __initdata = {
+struct ocp_def core_ocp[]  = {
 	{ .vendor	= OCP_VENDOR_IBM,
 	  .function	= OCP_FUNC_OPB,
 	  .index	= 0,
@@ -103,7 +103,7 @@
 	{ .vendor	= OCP_VENDOR_IBM,
 	  .function	= OCP_FUNC_EMAC,
 	  .index	= 1,
-	  .paddr	= EMAC0_BASE,
+	  .paddr	= EMAC1_BASE,
 	  .irq		= BL_MAC_ETH1,
 	  .pm		= OCP_CPM_NA,
 	  .additions	= &ibm405ep_emac1_def,
Index: pplinux/linuxnew/arch/ppc/platforms/ibm405ep.h
diff -u pplinux/linuxnew/arch/ppc/platforms/ibm405ep.h:1.1.323.1 pplinux/linuxnew/arch/ppc/platforms/ibm405ep.h:1.2
--- pplinux/linuxnew/arch/ppc/platforms/ibm405ep.h:1.1.323.1	Thu Feb  3 10:00:25 2005
+++ pplinux/linuxnew/arch/ppc/platforms/ibm405ep.h	Thu Feb  3 11:35:37 2005
@@ -55,6 +55,8 @@
 #define PPC4xx_ONB_IO_VADDR	PPC4xx_ONB_IO_PADDR
 #define PPC4xx_ONB_IO_SIZE	((uint)4*1024)
 
+#define OPB_BASE_START  0x40000000
+
 /* serial port defines */
 #define RS_TABLE_SIZE	2
 
Index: pplinux/linuxnew/arch/ppc/platforms/ibm405gp.c
diff -u pplinux/linuxnew/arch/ppc/platforms/ibm405gp.c:1.1.323.1 pplinux/linuxnew/arch/ppc/platforms/ibm405gp.c:1.2
--- pplinux/linuxnew/arch/ppc/platforms/ibm405gp.c:1.1.323.1	Thu Feb  3 10:00:25 2005
+++ pplinux/linuxnew/arch/ppc/platforms/ibm405gp.c	Thu Feb  3 11:35:37 2005
@@ -53,7 +53,7 @@
 	.num_rx_chans	= EMAC_NUMS,	/* Number of RX channels */
 };
 
-struct ocp_def core_ocp[]  __initdata = {
+struct ocp_def core_ocp[]  = {
 	{ .vendor	= OCP_VENDOR_IBM,
 	  .function	= OCP_FUNC_OPB,
 	  .index	= 0,
Index: pplinux/linuxnew/arch/ppc/platforms/ibm405gp.h
diff -u pplinux/linuxnew/arch/ppc/platforms/ibm405gp.h:1.1.323.1 pplinux/linuxnew/arch/ppc/platforms/ibm405gp.h:1.2
--- pplinux/linuxnew/arch/ppc/platforms/ibm405gp.h:1.1.323.1	Thu Feb  3 10:00:25 2005
+++ pplinux/linuxnew/arch/ppc/platforms/ibm405gp.h	Thu Feb  3 11:35:37 2005
@@ -104,7 +104,11 @@
 
 #define IIC_OWN		0x55
 #define IIC_CLOCK	50
-#define BD_EMAC_ADDR(e,i) bi_enetaddr[i]
+#ifdef CONFIG_PEPPERCON
+# define BD_EMAC_ADDR(e,i) bi_enetaddr[e][i]
+#else
+# define BD_EMAC_ADDR(e,i) bi_enetaddr[i]
+#endif
 
 #define STD_UART_OP(num)					\
 	{ 0, BASE_BAUD, 0, UART##num##_INT,			\
Index: pplinux/linuxnew/arch/ppc/platforms/peppercon.c
diff -u /dev/null pplinux/linuxnew/arch/ppc/platforms/peppercon.c:1.1
--- /dev/null	Tue May 24 10:37:58 2005
+++ pplinux/linuxnew/arch/ppc/platforms/peppercon.c	Thu Feb  3 11:35:37 2005
@@ -0,0 +1,375 @@
+/*
+ *
+ *    Copyright (c) 2003 Peppercon AG
+ *
+ *    Module name: peppercon.c
+ *
+ *    Description:
+ *      Architecture- / platform-specific boot-time initialization code for
+ *      Peppercons remote management boards.
+ *
+ * Please read the COPYING file for all license details.
+ */
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/smp.h>
+#include <linux/threads.h>
+#include <linux/param.h>
+#include <linux/string.h>
+#include <linux/blk.h>
+#include <linux/pci.h>
+#include <linux/rtc.h>
+#include <linux/console.h>
+#include <linux/timer.h>
+#include <linux/module.h>
+
+#include <asm/system.h>
+#include <asm/pci-bridge.h>
+#include <asm/processor.h>
+#include <asm/machdep.h>
+#include <asm/page.h>
+#include <asm/time.h>
+#include <asm/io.h>
+#include <asm/todc.h>
+#include <asm/ppc4xx_i2c.h>
+#include <platforms/ibm_ocp.h>
+#include <platforms/ibm405ep.h>
+
+#undef DEBUG
+
+#ifdef DEBUG
+#define DBG(x...) printk(x)
+#else
+#define DBG(x...)
+#endif
+
+#ifdef PP_FEAT_SYSOK_BLINKING
+# define GPIO_REGS_ADDR		(GPIO0_BASE)
+# define GPIO_REGS_SIZE		((size_t)0x20)
+
+static struct timer_list status_led_timer;
+static volatile u32 * gpio_regs;
+static unsigned char status_led_state;
+static unsigned char status_led_initialized = 0;
+
+static int  status_led_init(void);
+static void status_led_toggle(unsigned long data);
+#endif
+
+#ifdef CONFIG_PCI
+/*
+ * Some IRQs unique to Peppercon boards.
+ * Used by the generic 405 PCI setup functions in ppc4xx_pci.c
+ */
+int __init
+ppc405_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin)
+{
+	static char pci_irq_table[][4] =
+	    /*
+	     *      PCI IDSEL/INTPIN->INTLINE
+	     *      A       B       C       D
+	     */
+	{
+		{31, 31, 31, 0},        /* IDSEL 1 - ??? */
+		{30, 30, 30, 0},        /* IDSEL 2 - ??? */
+		{29, 29, 29, 0},        /* IDSEL 3 - ??? */
+		{ 0,  0,  0, 0},        /* IDSEL 4 - ??? */
+	};
+
+	const long min_idsel = 1, max_idsel = 4, irqs_per_slot = 3;
+	return PCI_IRQ_TABLE_LOOKUP;
+};
+#endif
+
+void __init
+board_setup_arch(void)
+{
+#if defined(CONFIG_VT) && defined(CONFIG_DUMMY_CONSOLE)
+	conswitchp = &dummy_con;
+#endif
+	/* Identify the system */
+	printk("Peppercon port (C) 2001-2003 Peppercon AG\n");
+}
+
+#ifdef CONFIG_PCI
+void __init
+bios_fixup(struct pci_controller *hose, struct pcil0_regs *pcip)
+{
+}
+#endif
+
+void __init
+board_io_mapping(void)
+{
+}
+
+void __init
+board_setup_irq(void)
+{
+}
+
+#define RTC_READ_SAVE(off, buf, count)			\
+	if ((rtc_ret = rtc_read(off, buf, count))) {	\
+		goto rtc_error;				\
+	}
+#define RTC_WRITE_SAVE(off, buf, count)			\
+	if ((rtc_ret = rtc_write(off, buf, count))) {	\
+		goto rtc_error;				\
+	}
+
+long __init
+pp_time_init(void)
+{
+	static int not_initialized = 1;
+
+        /* Make sure clocks are running */
+        if (not_initialized) {
+		unsigned char century, year, mon, day, mday, hour, min, sec;
+		unsigned char rtc_val = 0;
+		int rtc_ret;
+
+		i2c_init();
+
+		RTC_READ_SAVE(X1240_STATUS, (unsigned char *)&rtc_val, 1);
+		
+		if (rtc_val & X1240_STATUS_BATTERY_FLAG) {
+			printk(KERN_INFO "Real Time Clock battery exhuasted, value of RTC may be incorrect\n");
+		}
+#if 0
+		printk(KERN_INFO "RTC X1240: Status %02x\n",rtc_val);
+#endif	
+	
+		/* unlock Register write access */
+		rtc_val = X1240_STATUS_WEL;
+		RTC_WRITE_SAVE(X1240_STATUS, &rtc_val, 1);
+		rtc_val |= X1240_STATUS_RWEL;
+		RTC_WRITE_SAVE(X1240_STATUS, &rtc_val, 1);
+	
+		RTC_READ_SAVE(X1240_STATUS, &rtc_val, 1);
+	
+		/* 
+		 * start a new powered on rtc
+		 * a simple write turns on the RTC
+		 */
+		if (rtc_val & X1240_STATUS_RTCF){
+			rtc_read(X1240_Y2K, &century, 1);
+			rtc_write(X1240_Y2K, &century, 1);
+		}
+	
+		/* lock Register write access, leave EEPROM enabled */
+		rtc_val = X1240_STATUS_WEL;
+		RTC_WRITE_SAVE(X1240_STATUS, &rtc_val, sizeof(rtc_val));
+	
+		RTC_READ_SAVE(X1240_SC,  &sec, 1);
+		RTC_READ_SAVE(X1240_MIN, &min, 1);
+		RTC_READ_SAVE(X1240_HR,  &hour, 1);
+		RTC_READ_SAVE(X1240_DT,  &mday, 1);
+		RTC_READ_SAVE(X1240_MO,  &mon, 1);
+		RTC_READ_SAVE(X1240_YR,  &year, 1);
+		RTC_READ_SAVE(X1240_DW,  &day, 1); day++;
+		RTC_READ_SAVE(X1240_Y2K, &century, 1);
+
+#if 0
+		printk(KERN_INFO "RTC X1240: Time: %02x:%02x:%02x Date: %1x. %02x%02x/%02x/%02x\n",
+		       hour & 0x3f,min,sec,day,century,year,mon,mday);
+#endif
+
+		not_initialized = 0;
+        }
+
+#ifdef PP_FEAT_SYSOK_BLINKING
+	if (status_led_init() == 0) {
+	    status_led_initialized = 1;
+	}
+	pp_status_led_blinking(1);
+#endif
+
+	return 0;
+
+rtc_error:
+	printk(KERN_INFO "RTC X1240: Error while accessing RTC\n");
+	return -1;
+}
+
+int
+pp_set_rtc_time(unsigned long nowtime)
+{
+	struct rtc_time tm;
+	unsigned char rtc_val = 0;
+	unsigned int  save_year;
+        unsigned char century;
+	int rtc_ret;
+
+	to_tm(nowtime, &tm);
+
+	save_year  = tm.tm_year;
+	tm.tm_year = (tm.tm_year - 1900) % 100;
+	century    = (save_year - tm.tm_year) / 100;
+
+	BIN_TO_BCD(tm.tm_sec);
+	BIN_TO_BCD(tm.tm_min);
+	BIN_TO_BCD(tm.tm_hour);
+	BIN_TO_BCD(tm.tm_mon);
+	BIN_TO_BCD(tm.tm_mday);
+	BIN_TO_BCD(tm.tm_year);
+	BIN_TO_BCD(century);
+
+	spin_lock(&rtc_lock);
+
+	/* unlock Register write access */
+	rtc_val = X1240_STATUS_WEL;
+	RTC_WRITE_SAVE(X1240_STATUS, &rtc_val, 1);
+	rtc_val |= X1240_STATUS_RWEL;
+	RTC_WRITE_SAVE(X1240_STATUS, &rtc_val, 1);
+
+	rtc_val = tm.tm_sec  & 0x7f;
+	RTC_WRITE_SAVE(X1240_SC,  &rtc_val, 1);
+
+	rtc_val = tm.tm_min  & 0x7f;
+	RTC_WRITE_SAVE(X1240_MIN, &rtc_val, 1);
+
+	rtc_val = (tm.tm_hour & 0x3f) | X1240_HR_MIL; /* set 24 hour mode*/
+	RTC_WRITE_SAVE(X1240_HR,  &rtc_val, 1);
+
+	rtc_val = tm.tm_mday & 0x3f;
+	RTC_WRITE_SAVE(X1240_DT,  &rtc_val, 1);
+
+	rtc_val = tm.tm_mon  & 0x1f;
+	RTC_WRITE_SAVE(X1240_MO,  &rtc_val, 1);
+
+	rtc_val = tm.tm_year;
+	RTC_WRITE_SAVE(X1240_YR,  &rtc_val, 1);
+
+//      rtc_write(X1240_DW,  &rtc_val, 1);
+
+	rtc_val = (century   & 0x3f);
+	RTC_WRITE_SAVE(X1240_Y2K, &rtc_val, 1);
+
+	/* lock Register write access, leave EEPROM enabled */
+	rtc_val = X1240_STATUS_WEL;
+	RTC_WRITE_SAVE(X1240_STATUS, &rtc_val, 1);
+
+	spin_unlock(&rtc_lock);
+	return 0;
+
+rtc_error:
+	spin_unlock(&rtc_lock);
+	printk(KERN_INFO "RTC X1240: Error while accessing RTC\n");
+	return -1;
+}
+
+unsigned long
+pp_get_rtc_time(void)
+{
+        unsigned int century, year, mon, mday, hour, min, sec;
+	unsigned char rtc_val;
+        int rtc_ret;
+
+	spin_lock(&rtc_lock);
+
+        RTC_READ_SAVE(X1240_SC,  &rtc_val, 1);
+        sec = (unsigned int) rtc_val & 0x7f;
+
+        RTC_READ_SAVE(X1240_MIN, &rtc_val, 1);
+        min = (unsigned int) rtc_val & 0x7f;
+
+        RTC_READ_SAVE(X1240_HR,  &rtc_val, 1);
+        hour = (unsigned int) rtc_val & 0x3f;
+
+        RTC_READ_SAVE(X1240_DT,  &rtc_val, 1);
+        mday = (unsigned int) rtc_val & 0x3f;
+
+        RTC_READ_SAVE(X1240_MO,  &rtc_val, 1);
+        mon = (unsigned int) rtc_val & 0x1f;
+
+        RTC_READ_SAVE(X1240_YR,  &rtc_val, 1);
+        year = (unsigned int) rtc_val;
+
+//      RTC_READ_SAVE(X1240_DW,  &rtc_val, 1);
+
+        RTC_READ_SAVE(X1240_Y2K, &rtc_val, 1);
+        century = (unsigned int) rtc_val & 0x3f;
+
+	spin_unlock(&rtc_lock);
+
+	BCD_TO_BIN(sec);
+	BCD_TO_BIN(min);
+	BCD_TO_BIN(hour);
+	BCD_TO_BIN(mday);
+	BCD_TO_BIN(mon);
+	BCD_TO_BIN(year);
+	BCD_TO_BIN(century);
+
+        year = year + (100 * century);
+
+#if 0
+        printk(KERN_INFO "RTC X1240 gettime(): Time: %02x:%02x:%02x Date: %02x%02x/%02x/%02x\n",
+	       hour & 0x3f,min,sec,century,year,mon,mday);
+#endif
+
+        return mktime(year, mon, mday, hour, min, sec);
+
+rtc_error:
+	spin_unlock(&rtc_lock);
+	printk(KERN_ALERT "RTC X1240: Error while accessing RTC\n");
+        return -1;
+}
+
+void __init
+board_init(void)
+{
+	ppc_md.time_init = pp_time_init;
+	ppc_md.set_rtc_time = pp_set_rtc_time;
+	ppc_md.get_rtc_time = pp_get_rtc_time;
+}
+
+#ifdef PP_FEAT_SYSOK_BLINKING
+EXPORT_SYMBOL(pp_status_led_blinking);
+void
+pp_status_led_blinking(unsigned char blinking)
+{
+    if (!status_led_initialized) return;
+    
+    del_timer_sync(&status_led_timer);
+        
+    if (blinking) {
+	init_timer(&status_led_timer);
+	status_led_timer.expires = jiffies + HZ/10;
+	status_led_timer.data = 0;
+	status_led_timer.function = status_led_toggle;
+	add_timer(&status_led_timer);
+    } else {
+	// if not blinking, turn on unconditioally
+	status_led_state = 1;
+	clear_bit((31 - 9), &gpio_regs[0]);
+    }
+}
+
+static int
+status_led_init(void)
+{
+    int ret = 0;
+    
+    gpio_regs = ioremap_nocache(GPIO0_BASE, GPIO_REGS_SIZE);
+    if (gpio_regs == NULL) {
+	printk("Failed to map GPIO registers\n");
+	ret = -1;
+    }
+
+    return ret;
+}
+
+static void
+status_led_toggle(unsigned long data)
+{
+    if (status_led_state) {
+	set_bit((31 - 9), &gpio_regs[0]);
+    } else {
+	clear_bit((31 - 9), &gpio_regs[0]);
+    }
+
+    status_led_state = (status_led_state) ? 0 : 1;
+    status_led_timer.expires = jiffies + HZ/10;
+    add_timer(&status_led_timer);
+}
+#endif
Index: pplinux/linuxnew/arch/ppc/platforms/peppercon.h
diff -u /dev/null pplinux/linuxnew/arch/ppc/platforms/peppercon.h:1.2
--- /dev/null	Tue May 24 10:37:58 2005
+++ pplinux/linuxnew/arch/ppc/platforms/peppercon.h	Fri Apr 29 10:43:28 2005
@@ -0,0 +1,90 @@
+/*
+ *
+ *    Copyright (c) 2003 Peppercon AG
+ *
+ *    Module name: peppercon.h
+ *
+ *    Description:
+ *      Macros, definitions, and data structures specific to Peppercon's
+ *      remote management boards.
+ *
+ * Please read the COPYING file for all license details.
+ */
+
+#ifdef __KERNEL__
+#ifndef __ASM_PEPPERCON_H__
+#define __ASM_PEPPERCON_H__
+
+#include <linux/config.h>
+#if defined(CONFIG_405GP)
+# include <platforms/ibm405gp.h>
+#elif defined(CONFIG_405EP)
+# include <platforms/ibm405ep.h>
+#else
+# error Unexpected processor type!
+#endif
+
+#ifndef __ASSEMBLY__
+/*
+ * Data structure defining board information maintained by the boot
+ * ROM on IBM's "Walnut" evaluation board. An effort has been made to
+ * keep the field names consistent with the 8xx 'bd_t' board info
+ * structures.
+ */
+
+typedef struct board_info {
+	unsigned long	bi_memstart;	/* start of  DRAM memory              */
+	unsigned long	bi_memsize;	/* size  of  DRAM memory in bytes     */
+	unsigned long	bi_flashstart;	/* start of FLASH memory              */
+	unsigned long	bi_flashsize;	/* size  of FLASH memory              */
+	unsigned long	bi_flashoffset;	/* reserved area for startup monitor  */
+	unsigned long	bi_sramstart;	/* start of  SRAM memory              */
+	unsigned long	bi_sramsize;	/* size  of  SRAM memory              */
+	unsigned long	bi_bootflags;	/* boot / reboot flag (for LynxOS)    */
+	unsigned long	bi_ip_addr;	/* IP Address                         */
+	unsigned char	bi_enetaddr[2][6]; /* Ethernet adress                 */
+	unsigned short	bi_ethspeed;	/* Ethernet speed in Mbps             */
+	unsigned long	bi_intfreq;	/* Internal Freq, in MHz              */
+	unsigned long	bi_busfreq;	/* Bus Freq, in MHz                   */
+	unsigned long	bi_baudrate;	/* Console Baudrate                   */
+	unsigned char	bi_s_version[4];/* Version of this structure          */
+	unsigned char	bi_r_version[32];/* Version of the ROM (IBM)          */
+	unsigned int	bi_procfreq;	/* CPU (Internal) Freq, in Hz         */
+	unsigned int	bi_plb_busfreq;	/* PLB Bus speed, in Hz               */
+	unsigned int	bi_pci_busfreq;	/* PCI Bus speed, in Hz               */
+	unsigned char	bi_pci_enetaddr[6];/* PCI Ethernet MAC address        */
+	unsigned int	bi_debug_mode;  /* 1 if debug cable detected          */
+	unsigned int    bi_def_jumper_set; /* defaults jumper state           */
+	unsigned int    bi_cable_kme;    /* 1 if cable kme was detected       */
+	unsigned int    bi_config_mode;  /* 1 if config command used for boot */
+	unsigned int	bi_opb_busfreq;	 /* OPB Bus speed, in Hz	      */
+	int		bi_iic_fast[1];	 /* Use fast i2c mode		      */
+	unsigned char   bi_hwid;	 /* hardware id of the board	      */
+        unsigned int	bi_epb_busfreq;	 /* EPB Bus speed, in Hz	      */
+} bd_t;
+
+/* Some 4xx parts use a different timebase frequency from the internal clock.
+*/
+#define bi_tbfreq bi_intfreq
+
+
+/* Memory map for the Peppercon boards.  */
+
+#ifdef CONFIG_PPC405GP_INTERNAL_CLOCK
+#define BASE_BAUD		201600
+#else
+#define BASE_BAUD		691200
+#endif
+
+#define PPC4xx_MACHINE_NAME	"Peppercon"
+
+#define RTC_ALWAYS_BCD  1
+
+#ifdef PP_FEAT_SYSOK_BLINKING
+extern void pp_status_led_blinking(unsigned char blinking);
+#endif
+
+#endif /* !__ASSEMBLY__ */
+#endif /* __ASM_PEPPERCON_H__ */
+
+#endif /* __KERNEL__ */
Index: pplinux/linuxnew/drivers/char/ppc405_wdt.c
diff -u pplinux/linuxnew/drivers/char/ppc405_wdt.c:1.1.323.1 pplinux/linuxnew/drivers/char/ppc405_wdt.c:1.3
--- pplinux/linuxnew/drivers/char/ppc405_wdt.c:1.1.323.1	Thu Feb  3 10:00:34 2005
+++ pplinux/linuxnew/drivers/char/ppc405_wdt.c	Wed Feb 23 18:03:37 2005
@@ -65,9 +65,6 @@
 #include <asm/machdep.h>
 #include <asm/hardirq.h>
 
-#define WDIOC_GETPERIOD         _IOR(WATCHDOG_IOCTL_BASE, 6, int)
-#define WDIOC_SETPERIOD         _IOW(WATCHDOG_IOCTL_BASE, 7, int)
-
 int wdt_enable;
 unsigned long wdt_period;
 int wdt_default = 1;
@@ -188,7 +185,7 @@
 				printk(KERN_NOTICE "Soft watchdog timer is enabled\n");
 				break;
 			}
-		case WDIOC_GETPERIOD:
+		case WDIOC_GETTIMEOUT:
 			/* return watchdog period (units = microseconds) */
 			period = (wdt_period / HZ) * MICROSECBASE;
 			if (copy_to_user((unsigned long *)arg, &period, 
@@ -196,7 +193,7 @@
 				return -EFAULT;
 			}
 			break;
-		case WDIOC_SETPERIOD:
+		case WDIOC_SETTIMEOUT:
 			/*
 			** set watchdog period (units = microseconds)
 			** value of zero means maximum
@@ -233,8 +230,8 @@
 			if (period == 0)
 				period = MAXONEHOUR * MICROSECBASE;        
 
-			heartbeat_count(0) = (period / TENMSBASE) +
-				(period % TENMSBASE ? 1 : 0);
+			wdt_period = ((period / TENMSBASE) +
+				(period % TENMSBASE ? 1 : 0)) / HZ;
 			ppc405wd_update_timer();
 
 			break;
Index: pplinux/linuxnew/drivers/char/serial.c
diff -u pplinux/linuxnew/drivers/char/serial.c:1.1.323.1 pplinux/linuxnew/drivers/char/serial.c:1.2
--- pplinux/linuxnew/drivers/char/serial.c:1.1.323.1	Thu Feb  3 10:00:35 2005
+++ pplinux/linuxnew/drivers/char/serial.c	Thu Feb  3 11:35:37 2005
@@ -1361,7 +1361,7 @@
 		} else 
 			handler = rs_interrupt_single;
 
-		retval = request_irq(state->irq, handler, SA_SHIRQ,
+		retval = request_irq(state->irq, handler, SA_SHIRQ|SA_SAMPLE_RANDOM,
 				     "serial", &IRQ_ports[state->irq]);
 		if (retval) {
 			if (capable(CAP_SYS_ADMIN)) {
@@ -1514,7 +1514,7 @@
 		if (IRQ_ports[state->irq]) {
 			free_irq(state->irq, &IRQ_ports[state->irq]);
 			retval = request_irq(state->irq, rs_interrupt_single,
-					     SA_SHIRQ, "serial",
+					     SA_SHIRQ|SA_SAMPLE_RANDOM, "serial",
 					     &IRQ_ports[state->irq]);
 			
 			if (retval)
@@ -1693,7 +1693,7 @@
 			/* Special case since 134 is really 134.5 */
 			quot = (2*baud_base / 269);
 		else if (baud)
-			quot = baud_base / baud;
+			quot = ((baud_base * 10) / baud + 5) / 10;
 	}
 	/* If the quotient is zero refuse the change */
 	if (!quot && old_termios) {
@@ -1710,7 +1710,7 @@
 				/* Special case since 134 is really 134.5 */
 				quot = (2*baud_base / 269);
 			else if (baud)
-				quot = baud_base / baud;
+				quot = ((baud_base * 10) / baud + 5) / 10; 
 		}
 	}
 	/* As a last resort, if the quotient is zero, default to 9600 bps */
@@ -2529,7 +2529,7 @@
 		else
 			handler = rs_interrupt;
 
-		retval = request_irq(state->irq, handler, SA_SHIRQ,
+		retval = request_irq(state->irq, handler, SA_SHIRQ|SA_SAMPLE_RANDOM,
 				     "serial", &IRQ_ports[state->irq]);
 		if (retval) {
 			printk("Couldn't reallocate serial interrupt "
@@ -5890,7 +5890,7 @@
 	static struct async_struct *info;
 	struct serial_state *state;
 	unsigned cval;
-	int	baud = 9600;
+	int	baud = 115200;
 	int	bits = 8;
 	int	parity = 'n';
 	int	doflow = 0;
@@ -5978,7 +5978,7 @@
 	info->io_type = state->io_type;
 	info->iomem_base = state->iomem_base;
 	info->iomem_reg_shift = state->iomem_reg_shift;
-	quot = state->baud_base / baud;
+	quot = ((state->baud_base * 10) / baud + 5) / 10;
 	cval = cflag & (CSIZE | CSTOPB);
 #if defined(__powerpc__) || defined(__alpha__)
 	cval >>= 8;
Index: pplinux/linuxnew/drivers/char/ipmi/ipmi_bt_sm.c
diff -u /dev/null pplinux/linuxnew/drivers/char/ipmi/ipmi_bt_sm.c:1.1
--- /dev/null	Tue May 24 10:37:58 2005
+++ pplinux/linuxnew/drivers/char/ipmi/ipmi_bt_sm.c	Tue Feb 15 12:18:46 2005
@@ -0,0 +1,513 @@
+/*
+ *  ipmi_bt_sm.c
+ *
+ *  The state machine for an Open IPMI BT sub-driver under ipmi_si.c, part
+ *  of the driver architecture at http://sourceforge.net/project/openipmi
+ *
+ *  Author:	Rocky Craig <first.last@hp.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/kernel.h> /* For printk. */
+#include <linux/string.h>
+#include <linux/ipmi_msgdefs.h>		/* for completion codes */
+#include "ipmi_si_sm.h"
+
+#define IPMI_BT_VERSION "v33"
+
+static int bt_debug = 0x00;	/* Production value 0, see following flags */
+
+#define	BT_DEBUG_ENABLE	1
+#define BT_DEBUG_MSG	2
+#define BT_DEBUG_STATES	4
+
+/* Typical "Get BT Capabilities" values are 2-3 retries, 5-10 seconds,
+   and 64 byte buffers.  However, one HP implementation wants 255 bytes of
+   buffer (with a documented message of 160 bytes) so go for the max. 
+   Since the Open IPMI architecture is single-message oriented at this
+   stage, the queue depth of BT is of no concern. */
+
+#define BT_NORMAL_TIMEOUT	2000000	/* seconds in microseconds */
+#define BT_RETRY_LIMIT		2
+#define BT_RESET_DELAY		6000000	/* 6 seconds after warm reset */
+
+enum bt_states {
+	BT_STATE_IDLE,
+	BT_STATE_XACTION_START,
+	BT_STATE_WRITE_BYTES,
+	BT_STATE_WRITE_END,
+	BT_STATE_WRITE_CONSUME,
+	BT_STATE_B2H_WAIT,
+	BT_STATE_READ_END,
+	BT_STATE_RESET1,		/* These must come last */
+	BT_STATE_RESET2,
+	BT_STATE_RESET3,
+	BT_STATE_RESTART,
+	BT_STATE_HOSED
+};
+
+struct si_sm_data {
+	enum bt_states	state;
+	enum bt_states	last_state;	/* assist printing and resets */
+	unsigned char	seq;		/* BT sequence number */
+	struct si_sm_io	*io;
+        unsigned char	write_data[IPMI_MAX_MSG_LENGTH];
+        int		write_count;
+        unsigned char	read_data[IPMI_MAX_MSG_LENGTH];
+        int		read_count;
+        int		truncated;
+        long		timeout;
+        unsigned int	error_retries;	/* end of "common" fields */
+	int		nonzero_status;	/* hung BMCs stay all 0 */
+};
+
+#define BT_CLR_WR_PTR	0x01	/* See IPMI 1.5 table 11.6.4 */
+#define BT_CLR_RD_PTR	0x02
+#define BT_H2B_ATN	0x04
+#define BT_B2H_ATN	0x08
+#define BT_SMS_ATN	0x10
+#define BT_OEM0		0x20
+#define BT_H_BUSY	0x40
+#define BT_B_BUSY	0x80
+
+/* Some bits are toggled on each write: write once to set it, once
+   more to clear it; writing a zero does nothing.  To absolutely
+   clear it, check its state and write if set.  This avoids the "get 
+   current then use as mask" scheme to modify one bit.  Note that the 
+   variable "bt" is hardcoded into these macros. */ 
+
+#define BT_STATUS	bt->io->inputb(bt->io, 0)
+#define BT_CONTROL(x)	bt->io->outputb(bt->io, 0, x)
+
+#define BMC2HOST	bt->io->inputb(bt->io, 1)
+#define HOST2BMC(x)	bt->io->outputb(bt->io, 1, x)
+
+#define BT_INTMASK_R	bt->io->inputb(bt->io, 2)
+#define BT_INTMASK_W(x)	bt->io->outputb(bt->io, 2, x)
+
+/* Convenience routines for debugging.  These are not multi-open safe!
+   Note the macros have hardcoded variables in them. */
+
+static char *state2txt(unsigned char state)
+{
+	switch (state) {
+		case BT_STATE_IDLE:		return("IDLE");
+		case BT_STATE_XACTION_START:	return("XACTION");
+		case BT_STATE_WRITE_BYTES:	return("WR_BYTES");
+		case BT_STATE_WRITE_END:	return("WR_END");
+		case BT_STATE_WRITE_CONSUME:	return("WR_CONSUME");
+		case BT_STATE_B2H_WAIT:		return("B2H_WAIT");
+		case BT_STATE_READ_END:		return("RD_END");
+		case BT_STATE_RESET1:		return("RESET1");
+		case BT_STATE_RESET2:		return("RESET2");
+		case BT_STATE_RESET3:		return("RESET3");
+		case BT_STATE_RESTART:		return("RESTART");
+		case BT_STATE_HOSED:		return("HOSED");
+	}
+	return("BAD STATE");
+}
+#define STATE2TXT state2txt(bt->state)
+
+static char *status2txt(unsigned char status, char *buf)
+{
+	strcpy(buf, "[ ");
+	if (status & BT_B_BUSY) strcat(buf, "B_BUSY ");
+	if (status & BT_H_BUSY) strcat(buf, "H_BUSY ");
+	if (status & BT_OEM0) strcat(buf, "OEM0 ");
+	if (status & BT_SMS_ATN) strcat(buf, "SMS ");
+	if (status & BT_B2H_ATN) strcat(buf, "B2H ");
+	if (status & BT_H2B_ATN) strcat(buf, "H2B ");
+	strcat(buf, "]");
+	return buf;
+}
+#define STATUS2TXT(buf) status2txt(status, buf)
+
+/* This will be called from within this module on a hosed condition */
+#define FIRST_SEQ	0
+static unsigned int bt_init_data(struct si_sm_data *bt, struct si_sm_io *io)
+{
+	bt->state = BT_STATE_IDLE;
+	bt->last_state = BT_STATE_IDLE;
+	bt->seq = FIRST_SEQ;
+	bt->io = io;
+	bt->write_count = 0;
+	bt->read_count = 0;
+	bt->error_retries = 0;
+	bt->nonzero_status = 0;
+	bt->truncated = 0;
+	bt->timeout = BT_NORMAL_TIMEOUT;
+	return 3; /* We claim 3 bytes of space; ought to check SPMI table */
+}
+
+static int bt_start_transaction(struct si_sm_data *bt,
+				unsigned char *data, 
+				unsigned int size)
+{
+	unsigned int i;
+
+	if ((size < 2) || (size > IPMI_MAX_MSG_LENGTH)) return -1;
+	
+	if ((bt->state != BT_STATE_IDLE) && (bt->state != BT_STATE_HOSED))
+		return -2;
+	
+	if (bt_debug & BT_DEBUG_MSG) {
+    		printk(KERN_WARNING "+++++++++++++++++++++++++++++++++++++\n");
+		printk(KERN_WARNING "BT: write seq=0x%02X:", bt->seq);
+		for (i = 0; i < size; i ++) printk (" %02x", data[i]);
+		printk("\n");
+	}
+	bt->write_data[0] = size + 1;	/* all data plus seq byte */
+	bt->write_data[1] = *data;	/* NetFn/LUN */
+	bt->write_data[2] = bt->seq;
+	memcpy(bt->write_data + 3, data + 1, size - 1);
+	bt->write_count = size + 2;
+
+	bt->error_retries = 0;
+	bt->nonzero_status = 0;
+	bt->read_count = 0;
+	bt->truncated = 0;
+	bt->state = BT_STATE_XACTION_START;
+	bt->last_state = BT_STATE_IDLE;
+	bt->timeout = BT_NORMAL_TIMEOUT;
+	return 0;
+}
+
+/* After the upper state machine has been told SI_SM_TRANSACTION_COMPLETE 
+   it calls this.  Strip out the length and seq bytes. */
+
+static int bt_get_result(struct si_sm_data *bt,
+			   unsigned char *data, 
+			   unsigned int length)
+{
+	int i, msg_len;
+
+	msg_len = bt->read_count - 2;		/* account for length & seq */
+	/* Always NetFn, Cmd, cCode */
+	if (msg_len < 3 || msg_len > IPMI_MAX_MSG_LENGTH) {
+		printk(KERN_WARNING "BT results: bad msg_len = %d\n", msg_len);
+		data[0] = bt->write_data[1] | 0x4;	/* Kludge a response */
+		data[1] = bt->write_data[3];
+		data[2] = IPMI_ERR_UNSPECIFIED;
+		msg_len = 3;
+	} else {
+		data[0] = bt->read_data[1];
+		data[1] = bt->read_data[3];
+		if (length < msg_len) bt->truncated = 1;
+		if (bt->truncated) {	/* can be set in read_all_bytes() */
+			data[2] = IPMI_ERR_MSG_TRUNCATED;
+			msg_len = 3;
+		} else memcpy(data + 2, bt->read_data + 4, msg_len - 2);
+	
+		if (bt_debug & BT_DEBUG_MSG) {
+			printk (KERN_WARNING "BT: res (raw)");
+			for (i = 0; i < msg_len; i++) printk(" %02x", data[i]);
+			printk ("\n");
+		}
+	}
+	bt->read_count = 0;	/* paranoia */
+	return msg_len;
+}
+
+/* This bit's functionality is optional */
+#define BT_BMC_HWRST	0x80
+
+static void reset_flags(struct si_sm_data *bt)
+{
+	if (BT_STATUS & BT_H_BUSY) BT_CONTROL(BT_H_BUSY);
+	if (BT_STATUS & BT_B_BUSY) BT_CONTROL(BT_B_BUSY);
+	BT_CONTROL(BT_CLR_WR_PTR);
+	BT_CONTROL(BT_SMS_ATN);
+	BT_INTMASK_W(BT_BMC_HWRST);
+#ifdef DEVELOPMENT_ONLY_NOT_FOR_PRODUCTION
+	if (BT_STATUS & BT_B2H_ATN) {
+		int i;
+		BT_CONTROL(BT_H_BUSY);
+		BT_CONTROL(BT_B2H_ATN);
+		BT_CONTROL(BT_CLR_RD_PTR);
+		for (i = 0; i < IPMI_MAX_MSG_LENGTH + 2; i++) BMC2HOST;
+		BT_CONTROL(BT_H_BUSY);
+	}
+#endif
+}
+
+static inline void write_all_bytes(struct si_sm_data *bt)
+{
+	int i;
+
+	if (bt_debug & BT_DEBUG_MSG) {
+    		printk(KERN_WARNING "BT: write %d bytes seq=0x%02X", 
+			bt->write_count, bt->seq);
+		for (i = 0; i < bt->write_count; i++) 
+			printk (" %02x", bt->write_data[i]);
+		printk ("\n");
+	}
+	for (i = 0; i < bt->write_count; i++) HOST2BMC(bt->write_data[i]);
+}
+
+static inline int read_all_bytes(struct si_sm_data *bt)
+{
+	unsigned char i;
+
+	bt->read_data[0] = BMC2HOST;	
+	bt->read_count = bt->read_data[0];
+	if (bt_debug & BT_DEBUG_MSG) 
+    		printk(KERN_WARNING "BT: read %d bytes:", bt->read_count);
+
+	/* minimum: length, NetFn, Seq, Cmd, cCode == 5 total, or 4 more 
+	   following the length byte. */
+	if (bt->read_count < 4 || bt->read_count >= IPMI_MAX_MSG_LENGTH) {
+		if (bt_debug & BT_DEBUG_MSG) 
+			printk("bad length %d\n", bt->read_count);
+		bt->truncated = 1;
+		return 1;	/* let next XACTION START clean it up */
+	}
+	for (i = 1; i <= bt->read_count; i++) bt->read_data[i] = BMC2HOST;	
+	bt->read_count++;	/* account for the length byte */
+
+	if (bt_debug & BT_DEBUG_MSG) {
+	    	for (i = 0; i < bt->read_count; i++) 
+			printk (" %02x", bt->read_data[i]);
+	    	printk ("\n");
+	}
+	if (bt->seq != bt->write_data[2])	/* idiot check */
+		printk(KERN_WARNING "BT: internal error: sequence mismatch\n");
+
+	/* per the spec, the (NetFn, Seq, Cmd) tuples should match */
+	if ((bt->read_data[3] == bt->write_data[3]) &&		/* Cmd */
+        	(bt->read_data[2] == bt->write_data[2]) &&	/* Sequence */
+        	((bt->read_data[1] & 0xF8) == (bt->write_data[1] & 0xF8))) 
+			return 1;
+
+	if (bt_debug & BT_DEBUG_MSG) printk(KERN_WARNING "BT: bad packet: "
+		"want 0x(%02X, %02X, %02X) got (%02X, %02X, %02X)\n", 
+		bt->write_data[1], bt->write_data[2], bt->write_data[3],
+		bt->read_data[1],  bt->read_data[2],  bt->read_data[3]);
+	return 0;
+}
+
+/* Modifies bt->state appropriately, need to get into the bt_event() switch */
+
+static void error_recovery(struct si_sm_data *bt, char *reason)
+{
+	unsigned char status;
+	char buf[40]; /* For getting status */
+
+	bt->timeout = BT_NORMAL_TIMEOUT; /* various places want to retry */
+
+	status = BT_STATUS;
+	printk(KERN_WARNING "BT: %s in %s %s ", reason, STATE2TXT,
+	       STATUS2TXT(buf));
+
+	(bt->error_retries)++;
+	if (bt->error_retries > BT_RETRY_LIMIT) {
+		printk("retry limit (%d) exceeded\n", BT_RETRY_LIMIT);
+		bt->state = BT_STATE_HOSED;
+		if (!bt->nonzero_status)
+			printk(KERN_ERR "IPMI: BT stuck, try power cycle\n");
+		else if (bt->seq == FIRST_SEQ + BT_RETRY_LIMIT) {
+			/* most likely during insmod */
+			printk(KERN_WARNING "IPMI: BT reset (takes 5 secs)\n");
+        		bt->state = BT_STATE_RESET1;
+		}
+	return;
+	}
+
+	/* Sometimes the BMC queues get in an "off-by-one" state...*/
+	if ((bt->state == BT_STATE_B2H_WAIT) && (status & BT_B2H_ATN)) {
+    		printk("retry B2H_WAIT\n");
+		return;
+	}
+    
+	printk("restart command\n");
+	bt->state = BT_STATE_RESTART;
+}
+
+/* Check the status and (possibly) advance the BT state machine.  The
+   default return is SI_SM_CALL_WITH_DELAY. */
+
+static enum si_sm_result bt_event(struct si_sm_data *bt, long time)
+{
+	unsigned char status;
+	char buf[40]; /* For getting status */
+	int i;
+
+	status = BT_STATUS;
+	bt->nonzero_status |= status;
+
+	if ((bt_debug & BT_DEBUG_STATES) && (bt->state != bt->last_state))
+		printk(KERN_WARNING "BT: %s %s TO=%ld - %ld \n",
+			STATE2TXT,
+			STATUS2TXT(buf), 
+			bt->timeout, 
+			time);
+	bt->last_state = bt->state;
+  
+	if (bt->state == BT_STATE_HOSED) return SI_SM_HOSED;
+    
+	if (bt->state != BT_STATE_IDLE) {	/* do timeout test */
+
+		/* Certain states, on error conditions, can lock up a CPU 
+		   because they are effectively in an infinite loop with 
+		   CALL_WITHOUT_DELAY (right back here with time == 0).  
+		   Prevent infinite lockup by ALWAYS decrementing timeout. */
+
+    	/* FIXME: bt_event is sometimes called with time > BT_NORMAL_TIMEOUT
+              (noticed in ipmi_smic_sm.c January 2004) */
+
+		if ((time <= 0) || (time >= BT_NORMAL_TIMEOUT)) time = 100;
+		bt->timeout -= time;
+		if ((bt->timeout < 0) && (bt->state < BT_STATE_RESET1)) {
+			error_recovery(bt, "timed out");
+			return SI_SM_CALL_WITHOUT_DELAY;
+		}
+	}
+
+	switch (bt->state) {
+
+    	case BT_STATE_IDLE:	/* check for asynchronous messages */
+		if (status & BT_SMS_ATN) {
+			BT_CONTROL(BT_SMS_ATN);	/* clear it */
+			return SI_SM_ATTN;
+		}
+		return SI_SM_IDLE;
+
+	case BT_STATE_XACTION_START:
+		if (status & BT_H_BUSY) { 
+			BT_CONTROL(BT_H_BUSY);
+			break;
+		}
+    		if (status & BT_B2H_ATN) break;
+		bt->state = BT_STATE_WRITE_BYTES;
+		return SI_SM_CALL_WITHOUT_DELAY;	/* for logging */
+
+	case BT_STATE_WRITE_BYTES:
+		if (status & (BT_B_BUSY | BT_H2B_ATN)) break;
+		BT_CONTROL(BT_CLR_WR_PTR);
+		write_all_bytes(bt);
+		BT_CONTROL(BT_H2B_ATN);	/* clears too fast to catch? */
+		bt->state = BT_STATE_WRITE_CONSUME;
+		return SI_SM_CALL_WITHOUT_DELAY; /* it MIGHT sail through */
+
+	case BT_STATE_WRITE_CONSUME: /* BMCs usually blow right thru here */
+        	if (status & (BT_H2B_ATN | BT_B_BUSY)) break;
+		bt->state = BT_STATE_B2H_WAIT;
+		/* fall through with status */
+
+	/* Stay in BT_STATE_B2H_WAIT until a packet matches.  However, spinning 
+	   hard here, constantly reading status, seems to hold off the 
+	   generation of B2H_ATN so ALWAYS return CALL_WITH_DELAY. */
+
+	case BT_STATE_B2H_WAIT:
+    		if (!(status & BT_B2H_ATN)) break;
+		
+		/* Assume ordered, uncached writes: no need to wait */
+		if (!(status & BT_H_BUSY)) BT_CONTROL(BT_H_BUSY); /* set */
+		BT_CONTROL(BT_B2H_ATN);		/* clear it, ACK to the BMC */
+		BT_CONTROL(BT_CLR_RD_PTR);	/* reset the queue */
+		i = read_all_bytes(bt);
+		BT_CONTROL(BT_H_BUSY);		/* clear */
+		if (!i) break;			/* Try this state again */
+		bt->state = BT_STATE_READ_END;
+		return SI_SM_CALL_WITHOUT_DELAY;	/* for logging */
+
+    	case BT_STATE_READ_END:
+
+		/* I could wait on BT_H_BUSY to go clear for a truly clean 
+		   exit.  However, this is already done in XACTION_START
+		   and the (possible) extra loop/status/possible wait affects 
+		   performance.  So, as long as it works, just ignore H_BUSY */
+
+#ifdef MAKE_THIS_TRUE_IF_NECESSARY
+
+		if (status & BT_H_BUSY) break;
+#endif
+		bt->seq++;
+		bt->state = BT_STATE_IDLE;
+		return SI_SM_TRANSACTION_COMPLETE;
+
+	case BT_STATE_RESET1:
+    		reset_flags(bt);
+    		bt->timeout = BT_RESET_DELAY;;
+		bt->state = BT_STATE_RESET2;
+		break;
+
+	case BT_STATE_RESET2:		/* Send a soft reset */
+		BT_CONTROL(BT_CLR_WR_PTR);
+		HOST2BMC(3);		/* number of bytes following */
+		HOST2BMC(0x18);		/* NetFn/LUN == Application, LUN 0 */
+		HOST2BMC(42);		/* Sequence number */
+		HOST2BMC(3);		/* Cmd == Soft reset */
+		BT_CONTROL(BT_H2B_ATN);	
+		bt->state = BT_STATE_RESET3;
+		break;
+
+	case BT_STATE_RESET3:
+		if (bt->timeout > 0) return SI_SM_CALL_WITH_DELAY;
+		bt->state = BT_STATE_RESTART;	/* printk in debug modes */
+		break;
+
+	case BT_STATE_RESTART:		/* don't reset retries! */
+		bt->write_data[2] = ++bt->seq;
+		bt->read_count = 0;
+		bt->nonzero_status = 0;
+		bt->timeout = BT_NORMAL_TIMEOUT;
+		bt->state = BT_STATE_XACTION_START;
+		break;
+
+	default:	/* HOSED is supposed to be caught much earlier */
+		error_recovery(bt, "internal logic error");
+		break;
+  	}
+  	return SI_SM_CALL_WITH_DELAY;
+}
+
+static int bt_detect(struct si_sm_data *bt)
+{
+	/* It's impossible for the BT status and interrupt registers to be 
+	   all 1's, (assuming a properly functioning, self-initialized BMC)
+	   but that's what you get from reading a bogus address, so we
+	   test that first.  The calling routine uses negative logic. */
+
+	if ((BT_STATUS == 0xFF) && (BT_INTMASK_R == 0xFF)) return 1;
+	reset_flags(bt);
+	return 0;
+}
+
+static void bt_cleanup(struct si_sm_data *bt)
+{
+}
+
+static int bt_size(void)
+{
+	return sizeof(struct si_sm_data);
+}
+
+struct si_sm_handlers bt_smi_handlers =
+{
+	.version           = IPMI_BT_VERSION,
+	.init_data         = bt_init_data,
+	.start_transaction = bt_start_transaction,
+	.get_result        = bt_get_result,
+	.event             = bt_event,
+	.detect            = bt_detect,
+	.cleanup           = bt_cleanup,
+	.size              = bt_size,
+};
Index: pplinux/linuxnew/drivers/char/ipmi/ipmi_poweroff.c
diff -u /dev/null pplinux/linuxnew/drivers/char/ipmi/ipmi_poweroff.c:1.1
--- /dev/null	Tue May 24 10:37:58 2005
+++ pplinux/linuxnew/drivers/char/ipmi/ipmi_poweroff.c	Tue Feb 15 12:18:46 2005
@@ -0,0 +1,543 @@
+/*
+ * ipmi_poweroff.c
+ *
+ * MontaVista IPMI Poweroff extension to sys_reboot
+ *
+ * Author: MontaVista Software, Inc.
+ *         Steven Dake <sdake@mvista.com>
+ *         Corey Minyard <cminyard@mvista.com>
+ *         source@mvista.com
+ *
+ * Copyright 2002,2004 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 <asm/semaphore.h>
+#include <linux/kdev_t.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/ipmi.h>
+#include <linux/ipmi_smi.h>
+
+#define PFX "IPMI poweroff: "
+#define IPMI_POWEROFF_VERSION	"v33"
+
+/* Where to we insert our poweroff function? */
+extern void (*pm_power_off)(void);
+
+/* Stuff from the get device id command. */
+unsigned int mfg_id;
+unsigned int prod_id;
+unsigned char capabilities;
+
+/* We use our own messages for this operation, we don't let the system
+   allocate them, since we may be in a panic situation.  The whole
+   thing is single-threaded, anyway, so multiple messages are not
+   required. */
+static void dummy_smi_free(struct ipmi_smi_msg *msg)
+{
+}
+static void dummy_recv_free(struct ipmi_recv_msg *msg)
+{
+}
+static struct ipmi_smi_msg halt_smi_msg =
+{
+	.done = dummy_smi_free
+};
+static struct ipmi_recv_msg halt_recv_msg =
+{
+	.done = dummy_recv_free
+};
+
+
+/*
+ * Code to send a message and wait for the reponse.
+ */
+
+static void receive_handler(struct ipmi_recv_msg *recv_msg, void *handler_data)
+{
+	struct semaphore *sem = recv_msg->user_msg_data;
+
+	if (sem)
+		up(sem);
+}
+
+static struct ipmi_user_hndl ipmi_poweroff_handler =
+{
+	ipmi_recv_hndl : receive_handler
+};
+
+
+static int ipmi_request_wait_for_response(ipmi_user_t          user,
+					  struct ipmi_addr     *addr,
+					  struct ipmi_msg      *send_msg)
+{
+	int              rv;
+	struct semaphore sem;
+
+	sema_init (&sem, 0);
+
+	rv = ipmi_request_supply_msgs(user, addr, 0, send_msg, &sem,
+				      &halt_smi_msg, &halt_recv_msg, 0);
+	if (rv)
+		return rv;
+
+	down (&sem);
+
+	return halt_recv_msg.msg.data[0];
+}
+
+/* We are in run-to-completion mode, no semaphore is desired. */
+static int ipmi_request_in_rc_mode(ipmi_user_t          user,
+				   struct ipmi_addr     *addr,
+				   struct ipmi_msg      *send_msg)
+{
+	int              rv;
+
+	rv = ipmi_request_supply_msgs(user, addr, 0, send_msg, NULL,
+				      &halt_smi_msg, &halt_recv_msg, 0);
+	if (rv)
+		return rv;
+
+	return halt_recv_msg.msg.data[0];
+}
+
+/*
+ * ATCA Support
+ */
+
+#define IPMI_NETFN_ATCA			0x2c
+#define IPMI_ATCA_SET_POWER_CMD		0x11
+#define IPMI_ATCA_GET_ADDR_INFO_CMD	0x01
+#define IPMI_PICMG_ID			0
+
+static int ipmi_atca_detect (ipmi_user_t user)
+{
+	struct ipmi_system_interface_addr smi_addr;
+	struct ipmi_msg                   send_msg;
+	int                               rv;
+	unsigned char                     data[1];
+
+        /*
+         * Configure IPMI address for local access
+         */
+        smi_addr.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
+        smi_addr.channel = IPMI_BMC_CHANNEL;
+        smi_addr.lun = 0;
+
+	/*
+	 * Use get address info to check and see if we are ATCA
+	 */
+	send_msg.netfn = IPMI_NETFN_ATCA;
+	send_msg.cmd = IPMI_ATCA_GET_ADDR_INFO_CMD;
+	data[0] = IPMI_PICMG_ID;
+	send_msg.data = data;
+	send_msg.data_len = sizeof(data);
+	rv = ipmi_request_wait_for_response(user,
+					    (struct ipmi_addr *) &smi_addr,
+					    &send_msg);
+	return !rv;
+}
+
+static void ipmi_poweroff_atca (ipmi_user_t user)
+{
+	struct ipmi_system_interface_addr smi_addr;
+	struct ipmi_msg                   send_msg;
+	int                               rv;
+	unsigned char                     data[4];
+
+        /*
+         * Configure IPMI address for local access
+         */
+        smi_addr.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
+        smi_addr.channel = IPMI_BMC_CHANNEL;
+        smi_addr.lun = 0;
+
+	printk(KERN_INFO PFX "Powering down via ATCA power command\n");
+
+	/*
+	 * Power down
+	 */
+	send_msg.netfn = IPMI_NETFN_ATCA;
+	send_msg.cmd = IPMI_ATCA_SET_POWER_CMD;
+	data[0] = IPMI_PICMG_ID;
+	data[1] = 0; /* FRU id */
+	data[2] = 0; /* Power Level */
+	data[3] = 0; /* Don't change saved presets */
+	send_msg.data = data;
+	send_msg.data_len = sizeof (data);
+	rv = ipmi_request_in_rc_mode(user,
+				     (struct ipmi_addr *) &smi_addr,
+				     &send_msg);
+	if (rv) {
+		printk(KERN_ERR PFX "Unable to send ATCA powerdown message,"
+		       " IPMI error 0x%x\n", rv);
+		goto out;
+	}
+
+ out:
+	return;
+}
+
+/*
+ * CPI1 Support
+ */
+
+#define IPMI_NETFN_OEM_1				0xf8
+#define OEM_GRP_CMD_SET_RESET_STATE		0x84
+#define OEM_GRP_CMD_SET_POWER_STATE		0x82
+#define IPMI_NETFN_OEM_8				0xf8
+#define OEM_GRP_CMD_REQUEST_HOTSWAP_CTRL	0x80
+#define OEM_GRP_CMD_GET_SLOT_GA			0xa3
+#define IPMI_NETFN_SENSOR_EVT			0x10
+#define IPMI_CMD_GET_EVENT_RECEIVER		0x01
+
+#define IPMI_CPI1_PRODUCT_ID		0x000157
+#define IPMI_CPI1_MANUFACTURER_ID	0x0108
+
+static int ipmi_cpi1_detect (ipmi_user_t user)
+{
+	return ((mfg_id == IPMI_CPI1_MANUFACTURER_ID)
+		&& (prod_id == IPMI_CPI1_PRODUCT_ID));
+}
+
+static void ipmi_poweroff_cpi1 (ipmi_user_t user)
+{
+	struct ipmi_system_interface_addr smi_addr;
+	struct ipmi_ipmb_addr             ipmb_addr;
+	struct ipmi_msg                   send_msg;
+	int                               rv;
+	unsigned char                     data[1];
+	int                               slot;
+	unsigned char                     hotswap_ipmb;
+	unsigned char                     aer_addr;
+	unsigned char                     aer_lun;
+
+        /*
+         * Configure IPMI address for local access
+         */
+        smi_addr.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
+        smi_addr.channel = IPMI_BMC_CHANNEL;
+        smi_addr.lun = 0;
+
+	printk(KERN_INFO PFX "Powering down via CPI1 power command\n");
+
+	/*
+	 * Get IPMI ipmb address
+	 */
+	send_msg.netfn = IPMI_NETFN_OEM_8 >> 2;
+	send_msg.cmd = OEM_GRP_CMD_GET_SLOT_GA;
+	send_msg.data = NULL;
+	send_msg.data_len = 0;
+	rv = ipmi_request_in_rc_mode(user,
+				     (struct ipmi_addr *) &smi_addr,
+				     &send_msg);
+	if (rv)
+		goto out;
+	slot = halt_recv_msg.msg.data[1];
+	hotswap_ipmb = (slot > 9) ? (0xb0 + 2 * slot) : (0xae + 2 * slot);
+
+	/*
+	 * Get active event receiver
+	 */
+	send_msg.netfn = IPMI_NETFN_SENSOR_EVT >> 2;
+	send_msg.cmd = IPMI_CMD_GET_EVENT_RECEIVER;
+	send_msg.data = NULL;
+	send_msg.data_len = 0;
+	rv = ipmi_request_in_rc_mode(user,
+				     (struct ipmi_addr *) &smi_addr,
+				     &send_msg);
+	if (rv)
+		goto out;
+	aer_addr = halt_recv_msg.msg.data[1];
+	aer_lun = halt_recv_msg.msg.data[2];
+
+	/*
+	 * Setup IPMB address target instead of local target
+	 */
+	ipmb_addr.addr_type = IPMI_IPMB_ADDR_TYPE;
+	ipmb_addr.channel = 0;
+	ipmb_addr.slave_addr = aer_addr;
+	ipmb_addr.lun = aer_lun;
+
+	/*
+	 * Send request hotswap control to remove blade from dpv
+	 */
+	send_msg.netfn = IPMI_NETFN_OEM_8 >> 2;
+	send_msg.cmd = OEM_GRP_CMD_REQUEST_HOTSWAP_CTRL;
+	send_msg.data = &hotswap_ipmb;
+	send_msg.data_len = 1;
+	ipmi_request_in_rc_mode(user,
+				(struct ipmi_addr *) &ipmb_addr,
+				&send_msg);
+
+	/*
+	 * Set reset asserted
+	 */
+	send_msg.netfn = IPMI_NETFN_OEM_1 >> 2;
+	send_msg.cmd = OEM_GRP_CMD_SET_RESET_STATE;
+	send_msg.data = data;
+	data[0] = 1; /* Reset asserted state */
+	send_msg.data_len = 1;
+	rv = ipmi_request_in_rc_mode(user,
+				     (struct ipmi_addr *) &smi_addr,
+				     &send_msg);
+	if (rv)
+		goto out;
+
+	/*
+	 * Power down
+	 */
+	send_msg.netfn = IPMI_NETFN_OEM_1 >> 2;
+	send_msg.cmd = OEM_GRP_CMD_SET_POWER_STATE;
+	send_msg.data = data;
+	data[0] = 1; /* Power down state */
+	send_msg.data_len = 1;
+	rv = ipmi_request_in_rc_mode(user,
+				     (struct ipmi_addr *) &smi_addr,
+				     &send_msg);
+	if (rv)
+		goto out;
+
+ out:
+	return;
+}
+
+/*
+ * Standard chassis support
+ */
+
+#define IPMI_NETFN_CHASSIS_REQUEST	0
+#define IPMI_CHASSIS_CONTROL_CMD	0x02
+
+static int ipmi_chassis_detect (ipmi_user_t user)
+{
+	/* Chassis support, use it. */
+	return (capabilities & 0x80);
+}
+
+static void ipmi_poweroff_chassis (ipmi_user_t user)
+{
+	struct ipmi_system_interface_addr smi_addr;
+	struct ipmi_msg                   send_msg;
+	int                               rv;
+	unsigned char                     data[1];
+
+        /*
+         * Configure IPMI address for local access
+         */
+        smi_addr.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
+        smi_addr.channel = IPMI_BMC_CHANNEL;
+        smi_addr.lun = 0;
+
+	printk(KERN_INFO PFX "Powering down via IPMI chassis control command\n");
+
+	/*
+	 * Power down
+	 */
+	send_msg.netfn = IPMI_NETFN_CHASSIS_REQUEST;
+	send_msg.cmd = IPMI_CHASSIS_CONTROL_CMD;
+	data[0] = 0; /* Power down */
+	send_msg.data = data;
+	send_msg.data_len = sizeof(data);
+	rv = ipmi_request_in_rc_mode(user,
+				     (struct ipmi_addr *) &smi_addr,
+				     &send_msg);
+	if (rv) {
+		printk(KERN_ERR PFX "Unable to send chassis powerdown message,"
+		       " IPMI error 0x%x\n", rv);
+		goto out;
+	}
+
+ out:
+	return;
+}
+
+
+/* Table of possible power off functions. */
+struct poweroff_function {
+	char *platform_type;
+	int  (*detect)(ipmi_user_t user);
+	void (*poweroff_func)(ipmi_user_t user);
+};
+
+static struct poweroff_function poweroff_functions[] = {
+	{ "ATCA",    ipmi_atca_detect, ipmi_poweroff_atca },
+	{ "CPI1",    ipmi_cpi1_detect, ipmi_poweroff_cpi1 },
+	/* Chassis should generally be last, other things should override
+	   it. */
+	{ "chassis", ipmi_chassis_detect, ipmi_poweroff_chassis },
+};
+#define NUM_PO_FUNCS (sizeof(poweroff_functions) \
+		      / sizeof(struct poweroff_function))
+
+
+/* Our local state. */
+static int ready = 0;
+static ipmi_user_t ipmi_user;
+static void (*specific_poweroff_func)(ipmi_user_t user) = NULL;
+
+/* Holds the old poweroff function so we can restore it on removal. */
+static void (*old_poweroff_func)(void);
+
+
+/* Called on a powerdown request. */
+static void ipmi_poweroff_function (void)
+{
+	if (!ready)
+		return;
+
+	/* Use run-to-completion mode, since interrupts may be off. */
+	ipmi_user_set_run_to_completion(ipmi_user, 1);
+	specific_poweroff_func(ipmi_user);
+	ipmi_user_set_run_to_completion(ipmi_user, 0);
+}
+
+/* Wait for an IPMI interface to be installed, the first one installed
+   will be grabbed by this code and used to perform the powerdown. */
+static void ipmi_po_new_smi(int if_num)
+{
+	struct ipmi_system_interface_addr smi_addr;
+	struct ipmi_msg                   send_msg;
+	int                               rv;
+	int                               i;
+
+	if (ready)
+		return;
+
+	rv = ipmi_create_user(if_num, &ipmi_poweroff_handler, 0, &ipmi_user);
+	if (rv) {
+		printk(KERN_ERR PFX "could not create IPMI user, error %d\n",
+		       rv);
+		return;
+	}
+
+        /*
+         * Do a get device ide and store some results, since this is
+	 * used by several functions.
+         */
+        smi_addr.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
+        smi_addr.channel = IPMI_BMC_CHANNEL;
+        smi_addr.lun = 0;
+
+	send_msg.netfn = IPMI_NETFN_APP_REQUEST;
+	send_msg.cmd = IPMI_GET_DEVICE_ID_CMD;
+	send_msg.data = NULL;
+	send_msg.data_len = 0;
+	rv = ipmi_request_wait_for_response(ipmi_user,
+					    (struct ipmi_addr *) &smi_addr,
+					    &send_msg);
+	if (rv) {
+		printk(KERN_ERR PFX "Unable to send IPMI get device id info,"
+		       " IPMI error 0x%x\n", rv);
+		goto out_err;
+	}
+
+	if (halt_recv_msg.msg.data_len < 12) {
+		printk(KERN_ERR PFX "(chassis) IPMI get device id info too,"
+		       " short, was %d bytes, needed %d bytes\n",
+		       halt_recv_msg.msg.data_len, 12);
+		goto out_err;
+	}
+
+	mfg_id = (halt_recv_msg.msg.data[7]
+		  | (halt_recv_msg.msg.data[8] << 8)
+		  | (halt_recv_msg.msg.data[9] << 16));
+	prod_id = (halt_recv_msg.msg.data[10]
+		   | (halt_recv_msg.msg.data[11] << 8));
+	capabilities = halt_recv_msg.msg.data[6];
+
+
+	/* Scan for a poweroff method */
+	for (i=0; i<NUM_PO_FUNCS; i++) {
+		if (poweroff_functions[i].detect(ipmi_user))
+			goto found;
+	}
+
+ out_err:
+	printk(KERN_ERR PFX "Unable to find a poweroff function that"
+	       " will work, giving up\n");
+	ipmi_destroy_user(ipmi_user);
+	return;
+
+ found:
+	printk(KERN_INFO PFX "Found a %s style poweroff function\n",
+	       poweroff_functions[i].platform_type);
+	specific_poweroff_func = poweroff_functions[i].poweroff_func;
+	old_poweroff_func = pm_power_off;
+	pm_power_off = ipmi_poweroff_function;
+	ready = 1;
+}
+
+static void ipmi_po_smi_gone(int if_num)
+{
+	/* This can never be called, because once poweroff driver is
+	   registered, the interface can't go away until the power
+	   driver is unregistered. */
+}
+
+static struct ipmi_smi_watcher smi_watcher =
+{
+	.owner    = THIS_MODULE,
+	.new_smi  = ipmi_po_new_smi,
+	.smi_gone = ipmi_po_smi_gone
+};
+
+
+/*
+ * Startup and shutdown functions.
+ */
+static int ipmi_poweroff_init (void)
+{
+	int rv;
+
+	printk ("Copyright (C) 2004 MontaVista Software -"
+		" IPMI Powerdown via sys_reboot version "
+		IPMI_POWEROFF_VERSION ".\n");
+
+	rv = ipmi_smi_watcher_register(&smi_watcher);
+	if (rv)
+		printk(KERN_ERR PFX "Unable to register SMI watcher: %d\n", rv);
+
+	return rv;
+}
+
+#ifdef MODULE
+static __exit void ipmi_poweroff_cleanup(void)
+{
+	int rv;
+
+	ipmi_smi_watcher_unregister(&smi_watcher);
+
+	if (ready) {
+		rv = ipmi_destroy_user(ipmi_user);
+		if (rv)
+			printk(KERN_ERR PFX "could not cleanup the IPMI"
+			       " user: 0x%x\n", rv);
+		pm_power_off = old_poweroff_func;
+	}
+}
+module_exit(ipmi_poweroff_cleanup);
+#endif
+
+module_init(ipmi_poweroff_init);
+MODULE_LICENSE("GPL");
Index: pplinux/linuxnew/drivers/char/ipmi/ipmi_si.c
diff -u /dev/null pplinux/linuxnew/drivers/char/ipmi/ipmi_si.c:1.1
--- /dev/null	Tue May 24 10:37:58 2005
+++ pplinux/linuxnew/drivers/char/ipmi/ipmi_si.c	Tue Feb 15 12:18:46 2005
@@ -0,0 +1,2360 @@
+/*
+ * ipmi_si.c
+ *
+ * The interface to the IPMI driver for the system interfaces (KCS, SMIC,
+ * BT in the future).
+ *
+ * Author: MontaVista Software, Inc.
+ *         Corey Minyard <minyard@mvista.com>
+ *         source@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.
+ *
+ *
+ *  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.
+ */
+
+/*
+ * This file holds the "policy" for the interface to the SMI state
+ * machine.  It does the configuration, handles timers and interrupts,
+ * and drives the real SMI state machine.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <asm/system.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/errno.h>
+#include <linux/spinlock.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/list.h>
+#include <linux/pci.h>
+#include <linux/ioport.h>
+#ifdef CONFIG_HIGH_RES_TIMERS
+#include <linux/hrtime.h>
+# if defined(schedule_next_int)
+/* Old high-res timer code, do translations. */
+#  define get_arch_cycles(a) quick_update_jiffies_sub(a) 
+#  define arch_cycles_per_jiffy cycles_per_jiffies
+# endif
+static inline void add_usec_to_timer(struct timer_list *t, long v)
+{
+	t->sub_expires += nsec_to_arch_cycle(v * 1000);
+	while (t->sub_expires >= arch_cycles_per_jiffy)
+	{
+		t->expires++;
+		t->sub_expires -= arch_cycles_per_jiffy;
+	}
+}
+#endif
+#include <linux/interrupt.h>
+#include <linux/ipmi_smi.h>
+#include <asm/io.h>
+#include "ipmi_si_sm.h"
+#include <linux/init.h>
+
+#define IPMI_SI_VERSION "v33"
+
+/* Measure times between events in the driver. */
+#undef DEBUG_TIMING
+
+/* Call every 10 ms when nothing is going on. */
+#define SI_TIMEOUT_TIME_USEC	10000
+#define SI_USEC_PER_JIFFY	(1000000/HZ)
+#define SI_TIMEOUT_JIFFIES	(SI_TIMEOUT_TIME_USEC/SI_USEC_PER_JIFFY)
+#define SI_SHORT_TIMEOUT_USEC	250 /* .25ms when the SM request a
+                                       short timeout */
+
+enum si_intf_state {
+	SI_NORMAL,
+	SI_GETTING_FLAGS,
+	SI_GETTING_EVENTS,
+	SI_CLEARING_FLAGS,
+	SI_CLEARING_FLAGS_THEN_SET_IRQ,
+	SI_GETTING_MESSAGES,
+	SI_ENABLE_INTERRUPTS1,
+	SI_ENABLE_INTERRUPTS2
+	/* FIXME - add watchdog stuff. */
+};
+
+enum si_type {
+	SI_KCS, SI_SMIC, SI_BT
+};
+
+struct smi_info
+{
+	ipmi_smi_t             intf;
+	struct si_sm_data      *si_sm;
+	struct si_sm_handlers  *handlers;
+	enum si_type           si_type;
+	spinlock_t             si_lock;
+	spinlock_t             msg_lock;
+	struct list_head       xmit_msgs;
+	struct list_head       hp_xmit_msgs;
+	struct ipmi_smi_msg    *curr_msg;
+	enum si_intf_state     si_state;
+
+	/* Used to handle the various types of I/O that can occur with
+           IPMI */
+	struct si_sm_io io;
+	int (*io_setup)(struct smi_info *info);
+	void (*io_cleanup)(struct smi_info *info);
+	int (*irq_setup)(struct smi_info *info);
+	void (*irq_cleanup)(struct smi_info *info);
+	unsigned int io_size;
+
+	/* Flags from the last GET_MSG_FLAGS command, used when an ATTN
+	   is set to hold the flags until we are done handling everything
+	   from the flags. */
+#define RECEIVE_MSG_AVAIL	0x01
+#define EVENT_MSG_BUFFER_FULL	0x02
+#define WDT_PRE_TIMEOUT_INT	0x08
+	unsigned char       msg_flags;
+
+	/* If set to true, this will request events the next time the
+	   state machine is idle. */
+	atomic_t            req_events;
+
+	/* If true, run the state machine to completion on every send
+	   call.  Generally used after a panic to make sure stuff goes
+	   out. */
+	int                 run_to_completion;
+
+	/* The I/O port of an SI interface. */
+	int                 port;
+
+	/* The space between start addresses of the two ports.  For
+	   instance, if the first port is 0xca2 and the spacing is 4, then
+	   the second port is 0xca6. */
+	unsigned int        spacing;
+
+	/* zero if no irq; */
+	int                 irq;
+
+	/* The timer for this si. */
+	struct timer_list   si_timer;
+
+	/* The time (in jiffies) the last timeout occurred at. */
+	unsigned long       last_timeout_jiffies;
+
+	/* Used to gracefully stop the timer without race conditions. */
+	volatile int        stop_operation;
+	volatile int        timer_stopped;
+
+	/* The driver will disable interrupts when it gets into a
+	   situation where it cannot handle messages due to lack of
+	   memory.  Once that situation clears up, it will re-enable
+	   interrupts. */
+	int interrupt_disabled;
+
+	unsigned char ipmi_si_dev_rev;
+	unsigned char ipmi_si_fw_rev_major;
+	unsigned char ipmi_si_fw_rev_minor;
+	unsigned char ipmi_version_major;
+	unsigned char ipmi_version_minor;
+
+	/* Counters and things for the proc filesystem. */
+	spinlock_t count_lock;
+	unsigned long short_timeouts;
+	unsigned long long_timeouts;
+	unsigned long timeout_restarts;
+	unsigned long idles;
+	unsigned long interrupts;
+	unsigned long attentions;
+	unsigned long flag_fetches;
+	unsigned long hosed_count;
+	unsigned long complete_transactions;
+	unsigned long events;
+	unsigned long watchdog_pretimeouts;
+	unsigned long incoming_messages;
+};
+
+static void si_restart_short_timer(struct smi_info *smi_info);
+
+static void deliver_recv_msg(struct smi_info *smi_info,
+			     struct ipmi_smi_msg *msg)
+{
+	/* Deliver the message to the upper layer with the lock
+           released. */
+	spin_unlock(&(smi_info->si_lock));
+	ipmi_smi_msg_received(smi_info->intf, msg);
+	spin_lock(&(smi_info->si_lock));
+}
+
+static void return_hosed_msg(struct smi_info *smi_info)
+{
+	struct ipmi_smi_msg *msg = smi_info->curr_msg;
+
+	/* Make it a reponse */
+	msg->rsp[0] = msg->data[0] | 4;
+	msg->rsp[1] = msg->data[1];
+	msg->rsp[2] = 0xFF; /* Unknown error. */
+	msg->rsp_size = 3;
+			
+	smi_info->curr_msg = NULL;
+	deliver_recv_msg(smi_info, msg);
+}
+
+static enum si_sm_result start_next_msg(struct smi_info *smi_info)
+{
+	int              rv;
+	struct list_head *entry = NULL;
+#ifdef DEBUG_TIMING
+	struct timeval t;
+#endif
+
+	/* No need to save flags, we aleady have interrupts off and we
+	   already hold the SMI lock. */
+	spin_lock(&(smi_info->msg_lock));
+	
+	/* Pick the high priority queue first. */
+	if (! list_empty(&(smi_info->hp_xmit_msgs))) {
+		entry = smi_info->hp_xmit_msgs.next;
+	} else if (! list_empty(&(smi_info->xmit_msgs))) {
+		entry = smi_info->xmit_msgs.next;
+	}
+
+	if (!entry) {
+		smi_info->curr_msg = NULL;
+		rv = SI_SM_IDLE;
+	} else {
+		int err;
+
+		list_del(entry);
+		smi_info->curr_msg = list_entry(entry,
+						struct ipmi_smi_msg,
+						link);
+#ifdef DEBUG_TIMING
+		do_gettimeofday(&t);
+		printk("**Start2: %d.%9.9d\n", t.tv_sec, t.tv_usec);
+#endif
+		err = smi_info->handlers->start_transaction(
+			smi_info->si_sm,
+			smi_info->curr_msg->data,
+			smi_info->curr_msg->data_size);
+		if (err) {
+			return_hosed_msg(smi_info);
+		}
+
+		rv = SI_SM_CALL_WITHOUT_DELAY;
+	}
+	spin_unlock(&(smi_info->msg_lock));
+
+	return rv;
+}
+
+static void start_enable_irq(struct smi_info *smi_info)
+{
+	unsigned char msg[2];
+
+	/* If we are enabling interrupts, we have to tell the
+	   BMC to use them. */
+	msg[0] = (IPMI_NETFN_APP_REQUEST << 2);
+	msg[1] = IPMI_GET_BMC_GLOBAL_ENABLES_CMD;
+
+	smi_info->handlers->start_transaction(smi_info->si_sm, msg, 2);
+	smi_info->si_state = SI_ENABLE_INTERRUPTS1;
+}
+
+static void start_clear_flags(struct smi_info *smi_info)
+{
+	unsigned char msg[3];
+
+	/* Make sure the watchdog pre-timeout flag is not set at startup. */
+	msg[0] = (IPMI_NETFN_APP_REQUEST << 2);
+	msg[1] = IPMI_CLEAR_MSG_FLAGS_CMD;
+	msg[2] = WDT_PRE_TIMEOUT_INT;
+
+	smi_info->handlers->start_transaction(smi_info->si_sm, msg, 3);
+	smi_info->si_state = SI_CLEARING_FLAGS;
+}
+
+/* When we have a situtaion where we run out of memory and cannot
+   allocate messages, we just leave them in the BMC and run the system
+   polled until we can allocate some memory.  Once we have some
+   memory, we will re-enable the interrupt. */
+static inline void disable_si_irq(struct smi_info *smi_info)
+{
+	if ((smi_info->irq) && (!smi_info->interrupt_disabled)) {
+		disable_irq_nosync(smi_info->irq);
+		smi_info->interrupt_disabled = 1;
+	}
+}
+
+static inline void enable_si_irq(struct smi_info *smi_info)
+{
+	if ((smi_info->irq) && (smi_info->interrupt_disabled)) {
+		enable_irq(smi_info->irq);
+		smi_info->interrupt_disabled = 0;
+	}
+}
+
+static void handle_flags(struct smi_info *smi_info)
+{
+	if (smi_info->msg_flags & WDT_PRE_TIMEOUT_INT) {
+		/* Watchdog pre-timeout */
+		spin_lock(&smi_info->count_lock);
+		smi_info->watchdog_pretimeouts++;
+		spin_unlock(&smi_info->count_lock);
+
+		start_clear_flags(smi_info);
+		smi_info->msg_flags &= ~WDT_PRE_TIMEOUT_INT;
+		spin_unlock(&(smi_info->si_lock));
+		ipmi_smi_watchdog_pretimeout(smi_info->intf);
+		spin_lock(&(smi_info->si_lock));
+	} else if (smi_info->msg_flags & RECEIVE_MSG_AVAIL) {
+		/* Messages available. */
+		smi_info->curr_msg = ipmi_alloc_smi_msg();
+		if (!smi_info->curr_msg) {
+			disable_si_irq(smi_info);
+			smi_info->si_state = SI_NORMAL;
+			return;
+		}
+		enable_si_irq(smi_info);
+
+		smi_info->curr_msg->data[0] = (IPMI_NETFN_APP_REQUEST << 2);
+		smi_info->curr_msg->data[1] = IPMI_GET_MSG_CMD;
+		smi_info->curr_msg->data_size = 2;
+
+		smi_info->handlers->start_transaction(
+			smi_info->si_sm,
+			smi_info->curr_msg->data,
+			smi_info->curr_msg->data_size);
+		smi_info->si_state = SI_GETTING_MESSAGES;
+	} else if (smi_info->msg_flags & EVENT_MSG_BUFFER_FULL) {
+		/* Events available. */
+		smi_info->curr_msg = ipmi_alloc_smi_msg();
+		if (!smi_info->curr_msg) {
+			disable_si_irq(smi_info);
+			smi_info->si_state = SI_NORMAL;
+			return;
+		}
+		enable_si_irq(smi_info);
+
+		smi_info->curr_msg->data[0] = (IPMI_NETFN_APP_REQUEST << 2);
+		smi_info->curr_msg->data[1] = IPMI_READ_EVENT_MSG_BUFFER_CMD;
+		smi_info->curr_msg->data_size = 2;
+
+		smi_info->handlers->start_transaction(
+			smi_info->si_sm,
+			smi_info->curr_msg->data,
+			smi_info->curr_msg->data_size);
+		smi_info->si_state = SI_GETTING_EVENTS;
+	} else {
+		smi_info->si_state = SI_NORMAL;
+	}
+}
+
+static void handle_transaction_done(struct smi_info *smi_info)
+{
+	struct ipmi_smi_msg *msg;
+#ifdef DEBUG_TIMING
+	struct timeval t;
+
+	do_gettimeofday(&t);
+	printk("**Done: %d.%9.9d\n", t.tv_sec, t.tv_usec);
+#endif
+	switch (smi_info->si_state) {
+	case SI_NORMAL:
+		if (!smi_info->curr_msg)
+			break;
+			
+		smi_info->curr_msg->rsp_size
+			= smi_info->handlers->get_result(
+				smi_info->si_sm,
+				smi_info->curr_msg->rsp,
+				IPMI_MAX_MSG_LENGTH);
+		
+		/* Do this here becase deliver_recv_msg() releases the
+		   lock, and a new message can be put in during the
+		   time the lock is released. */
+		msg = smi_info->curr_msg;
+		smi_info->curr_msg = NULL;
+		deliver_recv_msg(smi_info, msg);
+		break;
+		
+	case SI_GETTING_FLAGS:
+	{
+		unsigned char msg[4];
+		unsigned int  len;
+
+		/* We got the flags from the SMI, now handle them. */
+		len = smi_info->handlers->get_result(smi_info->si_sm, msg, 4);
+		if (msg[2] != 0) {
+			/* Error fetching flags, just give up for
+			   now. */
+			smi_info->si_state = SI_NORMAL;
+		} else if (len < 3) {
+			/* Hmm, no flags.  That's technically illegal, but
+			   don't use uninitialized data. */
+			smi_info->si_state = SI_NORMAL;
+		} else {
+			smi_info->msg_flags = msg[3];
+			handle_flags(smi_info);
+		}
+		break;
+	}
+
+	case SI_CLEARING_FLAGS:
+	case SI_CLEARING_FLAGS_THEN_SET_IRQ:
+	{
+		unsigned char msg[3];
+
+		/* We cleared the flags. */
+		smi_info->handlers->get_result(smi_info->si_sm, msg, 3);
+		if (msg[2] != 0) {
+			/* Error clearing flags */
+			printk(KERN_WARNING
+			       "ipmi_si: Error clearing flags: %2.2x\n",
+			       msg[2]);
+		}
+		if (smi_info->si_state == SI_CLEARING_FLAGS_THEN_SET_IRQ)
+			start_enable_irq(smi_info);
+		else
+			smi_info->si_state = SI_NORMAL;
+		break;
+	}
+
+	case SI_GETTING_EVENTS:
+	{
+		smi_info->curr_msg->rsp_size
+			= smi_info->handlers->get_result(
+				smi_info->si_sm,
+				smi_info->curr_msg->rsp,
+				IPMI_MAX_MSG_LENGTH);
+
+		/* Do this here becase deliver_recv_msg() releases the
+		   lock, and a new message can be put in during the
+		   time the lock is released. */
+		msg = smi_info->curr_msg;
+		smi_info->curr_msg = NULL;
+		if (msg->rsp[2] != 0) {
+			/* Error getting event, probably done. */
+			msg->done(msg);
+
+			/* Take off the event flag. */
+			smi_info->msg_flags &= ~EVENT_MSG_BUFFER_FULL;
+			handle_flags(smi_info);
+		} else {
+			spin_lock(&smi_info->count_lock);
+			smi_info->events++;
+			spin_unlock(&smi_info->count_lock);
+
+			/* Do this before we deliver the message
+			   because delivering the message releases the
+			   lock and something else can mess with the
+			   state. */
+			handle_flags(smi_info);
+
+			deliver_recv_msg(smi_info, msg);
+		}
+		break;
+	}
+
+	case SI_GETTING_MESSAGES:
+	{
+		smi_info->curr_msg->rsp_size
+			= smi_info->handlers->get_result(
+				smi_info->si_sm,
+				smi_info->curr_msg->rsp,
+				IPMI_MAX_MSG_LENGTH);
+
+		/* Do this here becase deliver_recv_msg() releases the
+		   lock, and a new message can be put in during the
+		   time the lock is released. */
+		msg = smi_info->curr_msg;
+		smi_info->curr_msg = NULL;
+		if (msg->rsp[2] != 0) {
+			/* Error getting event, probably done. */
+			msg->done(msg);
+
+			/* Take off the msg flag. */
+			smi_info->msg_flags &= ~RECEIVE_MSG_AVAIL;
+			handle_flags(smi_info);
+		} else {
+			spin_lock(&smi_info->count_lock);
+			smi_info->incoming_messages++;
+			spin_unlock(&smi_info->count_lock);
+
+			/* Do this before we deliver the message
+			   because delivering the message releases the
+			   lock and something else can mess with the
+			   state. */
+			handle_flags(smi_info);
+
+			deliver_recv_msg(smi_info, msg);
+		}
+		break;
+	}
+
+	case SI_ENABLE_INTERRUPTS1:
+	{
+		unsigned char msg[4];
+
+		/* We got the flags from the SMI, now handle them. */
+		smi_info->handlers->get_result(smi_info->si_sm, msg, 4);
+		if (msg[2] != 0) {
+			printk(KERN_WARNING
+			       "ipmi_si: Could not enable interrupts"
+			       ", failed get, using polled mode.\n");
+			smi_info->si_state = SI_NORMAL;
+		} else {
+			msg[0] = (IPMI_NETFN_APP_REQUEST << 2);
+			msg[1] = IPMI_SET_BMC_GLOBAL_ENABLES_CMD;
+			msg[2] = msg[3] | 1; /* enable msg queue int */
+			smi_info->handlers->start_transaction(
+				smi_info->si_sm, msg, 3);
+			smi_info->si_state = SI_ENABLE_INTERRUPTS2;
+		}
+		break;
+	}
+
+	case SI_ENABLE_INTERRUPTS2:
+	{
+		unsigned char msg[4];
+
+		/* We got the flags from the SMI, now handle them. */
+		smi_info->handlers->get_result(smi_info->si_sm, msg, 4);
+		if (msg[2] != 0) {
+			printk(KERN_WARNING
+			       "ipmi_si: Could not enable interrupts"
+			       ", failed set, using polled mode.\n");
+		}
+		smi_info->si_state = SI_NORMAL;
+		break;
+	}
+	}
+}
+
+/* Called on timeouts and events.  Timeouts should pass the elapsed
+   time, interrupts should pass in zero. */
+static enum si_sm_result smi_event_handler(struct smi_info *smi_info,
+					   int time)
+{
+	enum si_sm_result si_sm_result;
+
+ restart:
+	/* There used to be a loop here that waited a little while
+	   (around 25us) before giving up.  That turned out to be
+	   pointless, the minimum delays I was seeing were in the 300us
+	   range, which is far too long to wait in an interrupt.  So
+	   we just run until the state machine tells us something
+	   happened or it needs a delay. */
+	si_sm_result = smi_info->handlers->event(smi_info->si_sm, time);
+	time = 0;
+	while (si_sm_result == SI_SM_CALL_WITHOUT_DELAY)
+	{
+		si_sm_result = smi_info->handlers->event(smi_info->si_sm, 0);
+	}
+
+	if (si_sm_result == SI_SM_TRANSACTION_COMPLETE)
+	{
+		spin_lock(&smi_info->count_lock);
+		smi_info->complete_transactions++;
+		spin_unlock(&smi_info->count_lock);
+
+		handle_transaction_done(smi_info);
+		si_sm_result = smi_info->handlers->event(smi_info->si_sm, 0);
+	}
+	else if (si_sm_result == SI_SM_HOSED)
+	{
+		spin_lock(&smi_info->count_lock);
+		smi_info->hosed_count++;
+		spin_unlock(&smi_info->count_lock);
+
+		/* Do the before return_hosed_msg, because that
+		   releases the lock. */
+		smi_info->si_state = SI_NORMAL;
+		if (smi_info->curr_msg != NULL) {
+			/* If we were handling a user message, format
+                           a response to send to the upper layer to
+                           tell it about the error. */
+			return_hosed_msg(smi_info);
+		}
+		si_sm_result = smi_info->handlers->event(smi_info->si_sm, 0);
+	}
+
+	/* We prefer handling attn over new messages. */
+	if (si_sm_result == SI_SM_ATTN)
+	{
+		unsigned char msg[2];
+
+		spin_lock(&smi_info->count_lock);
+		smi_info->attentions++;
+		spin_unlock(&smi_info->count_lock);
+
+		/* Got a attn, send down a get message flags to see
+                   what's causing it.  It would be better to handle
+                   this in the upper layer, but due to the way
+                   interrupts work with the SMI, that's not really
+                   possible. */
+		msg[0] = (IPMI_NETFN_APP_REQUEST << 2);
+		msg[1] = IPMI_GET_MSG_FLAGS_CMD;
+
+		smi_info->handlers->start_transaction(
+			smi_info->si_sm, msg, 2);
+		smi_info->si_state = SI_GETTING_FLAGS;
+		goto restart;
+	}
+
+	/* If we are currently idle, try to start the next message. */
+	if (si_sm_result == SI_SM_IDLE) {
+		spin_lock(&smi_info->count_lock);
+		smi_info->idles++;
+		spin_unlock(&smi_info->count_lock);
+
+		si_sm_result = start_next_msg(smi_info);
+		if (si_sm_result != SI_SM_IDLE)
+			goto restart;
+        }
+
+	if ((si_sm_result == SI_SM_IDLE)
+	    && (atomic_read(&smi_info->req_events)))
+	{
+		/* We are idle and the upper layer requested that I fetch
+		   events, so do so. */
+		unsigned char msg[2];
+
+		spin_lock(&smi_info->count_lock);
+		smi_info->flag_fetches++;
+		spin_unlock(&smi_info->count_lock);
+
+		atomic_set(&smi_info->req_events, 0);
+		msg[0] = (IPMI_NETFN_APP_REQUEST << 2);
+		msg[1] = IPMI_GET_MSG_FLAGS_CMD;
+
+		smi_info->handlers->start_transaction(
+			smi_info->si_sm, msg, 2);
+		smi_info->si_state = SI_GETTING_FLAGS;
+		goto restart;
+	}
+
+	return si_sm_result;
+}
+
+static void sender(void                *send_info,
+		   struct ipmi_smi_msg *msg,
+		   int                 priority)
+{
+	struct smi_info   *smi_info = send_info;
+	enum si_sm_result result;
+	unsigned long     flags;
+#ifdef DEBUG_TIMING
+	struct timeval    t;
+#endif
+
+	spin_lock_irqsave(&(smi_info->msg_lock), flags);
+#ifdef DEBUG_TIMING
+	do_gettimeofday(&t);
+	printk("**Enqueue: %d.%9.9d\n", t.tv_sec, t.tv_usec);
+#endif
+
+	if (smi_info->run_to_completion) {
+		/* If we are running to completion, then throw it in
+		   the list and run transactions until everything is
+		   clear.  Priority doesn't matter here. */
+		list_add_tail(&(msg->link), &(smi_info->xmit_msgs));
+
+		/* We have to release the msg lock and claim the smi
+		   lock in this case, because of race conditions. */
+		spin_unlock_irqrestore(&(smi_info->msg_lock), flags);
+
+		spin_lock_irqsave(&(smi_info->si_lock), flags);
+		result = smi_event_handler(smi_info, 0);
+		while (result != SI_SM_IDLE) {
+			udelay(SI_SHORT_TIMEOUT_USEC);
+			result = smi_event_handler(smi_info,
+						   SI_SHORT_TIMEOUT_USEC);
+		}
+		spin_unlock_irqrestore(&(smi_info->si_lock), flags);
+		return;
+	} else {
+		if (priority > 0) {
+			list_add_tail(&(msg->link), &(smi_info->hp_xmit_msgs));
+		} else {
+			list_add_tail(&(msg->link), &(smi_info->xmit_msgs));
+		}
+	}
+	spin_unlock_irqrestore(&(smi_info->msg_lock), flags);
+
+	spin_lock_irqsave(&(smi_info->si_lock), flags);
+	if ((smi_info->si_state == SI_NORMAL)
+	    && (smi_info->curr_msg == NULL))
+	{
+		start_next_msg(smi_info);
+		si_restart_short_timer(smi_info);
+	}
+	spin_unlock_irqrestore(&(smi_info->si_lock), flags);
+}
+
+static void set_run_to_completion(void *send_info, int i_run_to_completion)
+{
+	struct smi_info   *smi_info = send_info;
+	enum si_sm_result result;
+	unsigned long     flags;
+
+	spin_lock_irqsave(&(smi_info->si_lock), flags);
+
+	smi_info->run_to_completion = i_run_to_completion;
+	if (i_run_to_completion) {
+		result = smi_event_handler(smi_info, 0);
+		while (result != SI_SM_IDLE) {
+			udelay(SI_SHORT_TIMEOUT_USEC);
+			result = smi_event_handler(smi_info,
+						   SI_SHORT_TIMEOUT_USEC);
+		}
+	}
+
+	spin_unlock_irqrestore(&(smi_info->si_lock), flags);
+}
+
+static void poll(void *send_info)
+{
+	struct smi_info *smi_info = send_info;
+
+	smi_event_handler(smi_info, 0);
+}
+
+static void request_events(void *send_info)
+{
+	struct smi_info *smi_info = send_info;
+
+	atomic_set(&smi_info->req_events, 1);
+}
+
+static int new_user(void *send_info)
+{
+	if (!try_inc_mod_count(THIS_MODULE))
+		return -EBUSY;
+	return 0;
+}
+
+static void user_left(void *send_info)
+{
+	MOD_DEC_USE_COUNT;
+}
+
+static int initialized = 0;
+
+/* Must be called with interrupts off and with the si_lock held. */
+static void si_restart_short_timer(struct smi_info *smi_info)
+{
+#if defined(CONFIG_HIGH_RES_TIMERS)
+	unsigned long flags;
+	unsigned long jiffies_now;
+
+	if (del_timer(&(smi_info->si_timer))) {
+		/* If we don't delete the timer, then it will go off
+		   immediately, anyway.  So we only process if we
+		   actually delete the timer. */
+
+		/* We already have irqsave on, so no need for it
+                   here. */
+		read_lock(&xtime_lock);
+		jiffies_now = jiffies;
+		smi_info->si_timer.expires = jiffies_now;
+		smi_info->si_timer.sub_expires = get_arch_cycles(jiffies_now);
+		read_unlock(&xtime_lock);
+
+		add_usec_to_timer(&smi_info->si_timer, SI_SHORT_TIMEOUT_USEC);
+
+		add_timer(&(smi_info->si_timer));
+		spin_lock_irqsave(&smi_info->count_lock, flags);
+		smi_info->timeout_restarts++;
+		spin_unlock_irqrestore(&smi_info->count_lock, flags);
+	}
+#endif
+}
+
+static void smi_timeout(unsigned long data)
+{
+	struct smi_info   *smi_info = (struct smi_info *) data;
+	enum si_sm_result smi_result;
+	unsigned long     flags;
+	unsigned long     jiffies_now;
+	unsigned long     time_diff;
+#ifdef DEBUG_TIMING
+	struct timeval    t;
+#endif
+
+	if (smi_info->stop_operation) {
+		smi_info->timer_stopped = 1;
+		return;
+	}
+
+	spin_lock_irqsave(&(smi_info->si_lock), flags);
+#ifdef DEBUG_TIMING
+	do_gettimeofday(&t);
+	printk("**Timer: %d.%9.9d\n", t.tv_sec, t.tv_usec);
+#endif
+	jiffies_now = jiffies;
+	time_diff = ((jiffies_now - smi_info->last_timeout_jiffies)
+		     * SI_USEC_PER_JIFFY);
+	smi_result = smi_event_handler(smi_info, time_diff);
+
+	spin_unlock_irqrestore(&(smi_info->si_lock), flags);
+
+	smi_info->last_timeout_jiffies = jiffies_now;
+
+	if ((smi_info->irq) && (! smi_info->interrupt_disabled)) {
+		/* Running with interrupts, only do long timeouts. */
+		smi_info->si_timer.expires = jiffies + SI_TIMEOUT_JIFFIES;
+		spin_lock_irqsave(&smi_info->count_lock, flags);
+		smi_info->long_timeouts++;
+		spin_unlock_irqrestore(&smi_info->count_lock, flags);
+		goto do_add_timer;
+	}
+
+	/* If the state machine asks for a short delay, then shorten
+           the timer timeout. */
+	if (smi_result == SI_SM_CALL_WITH_DELAY) {
+		spin_lock_irqsave(&smi_info->count_lock, flags);
+		smi_info->short_timeouts++;
+		spin_unlock_irqrestore(&smi_info->count_lock, flags);
+#if defined(CONFIG_HIGH_RES_TIMERS)
+		read_lock(&xtime_lock);
+                smi_info->si_timer.expires = jiffies;
+                smi_info->si_timer.sub_expires
+                        = get_arch_cycles(smi_info->si_timer.expires);
+                read_unlock(&xtime_lock);
+		add_usec_to_timer(&smi_info->si_timer, SI_SHORT_TIMEOUT_USEC);
+#else
+		smi_info->si_timer.expires = jiffies + 1;
+#endif
+	} else {
+		spin_lock_irqsave(&smi_info->count_lock, flags);
+		smi_info->long_timeouts++;
+		spin_unlock_irqrestore(&smi_info->count_lock, flags);
+		smi_info->si_timer.expires = jiffies + SI_TIMEOUT_JIFFIES;
+#if defined(CONFIG_HIGH_RES_TIMERS)
+		smi_info->si_timer.sub_expires = 0;
+#endif
+	}
+
+ do_add_timer:
+	add_timer(&(smi_info->si_timer));
+}
+
+static void si_irq_handler(int irq, void *data, struct pt_regs *regs)
+{
+	struct smi_info *smi_info = data;
+	unsigned long   flags;
+#ifdef DEBUG_TIMING
+	struct timeval  t;
+#endif
+
+	spin_lock_irqsave(&(smi_info->si_lock), flags);
+
+	spin_lock(&smi_info->count_lock);
+	smi_info->interrupts++;
+	spin_unlock(&smi_info->count_lock);
+
+	if (smi_info->stop_operation)
+		goto out;
+
+#ifdef DEBUG_TIMING
+	do_gettimeofday(&t);
+	printk("**Interrupt: %d.%9.9d\n", t.tv_sec, t.tv_usec);
+#endif
+	smi_event_handler(smi_info, 0);
+ out:
+	spin_unlock_irqrestore(&(smi_info->si_lock), flags);
+}
+
+static struct ipmi_smi_handlers handlers =
+{
+	sender:		       sender,
+	request_events:        request_events,
+	new_user:	       new_user,
+	user_left:	       user_left,
+	set_run_to_completion: set_run_to_completion,
+	poll:		       poll,
+};
+
+/* There can be 4 IO ports passed in (with or without IRQs), 4 addresses,
+   a default IO port, and 1 ACPI/SPMI address.  That sets SI_MAX_DRIVERS */
+
+#define SI_MAX_PARMS 4
+#define SI_MAX_DRIVERS ((SI_MAX_PARMS * 2) + 2)
+static struct smi_info *smi_infos[SI_MAX_DRIVERS] =
+{ NULL, NULL, NULL, NULL };
+
+#define DEVICE_NAME "ipmi_si"
+
+#define DEFAULT_KCS_IO_PORT	0xca2
+#define DEFAULT_SMIC_IO_PORT	0xca9
+#define DEFAULT_BT_IO_PORT	0xe4
+#define DEFAULT_REGSPACING	1
+
+static int           si_trydefaults = 1;
+static char          *si_type[SI_MAX_PARMS] = { NULL, NULL, NULL, NULL };
+static unsigned long si_addrs[SI_MAX_PARMS] = { 0, 0, 0, 0 };
+static unsigned int  si_ports[SI_MAX_PARMS] = { 0, 0, 0, 0 };
+static int           si_irqs[SI_MAX_PARMS] = { 0, 0, 0, 0 };
+static int           si_regspacings[SI_MAX_PARMS] = { 0, 0, 0, 0 };
+static int           si_regsizes[SI_MAX_PARMS] = { 0, 0, 0, 0 };
+static int           si_regshifts[SI_MAX_PARMS] = { 0, 0, 0, 0 };
+
+
+MODULE_PARM(si_trydefaults, "i");
+MODULE_PARM(si_type, "1-4s");
+MODULE_PARM(si_addrs, "1-4l");
+MODULE_PARM(si_irqs, "1-4i");
+MODULE_PARM(si_ports, "1-4i");
+MODULE_PARM(si_regspacings, "1-4i");
+MODULE_PARM(si_regsizes, "1-4i");
+MODULE_PARM(si_regshifts, "1-4i");
+
+
+#if defined(CONFIG_ACPI_INTERPRETER) || defined(CONFIG_X86) || defined(CONFIG_PCI)
+#define IPMI_MEM_ADDR_SPACE 1
+#define IPMI_IO_ADDR_SPACE  2
+static int is_new_interface(int intf, u8 addr_space, unsigned long base_addr)
+{
+	int i;
+
+	for (i = 0; i < SI_MAX_PARMS; ++i) {
+		/* Don't check our address. */
+		if (i == intf)
+			continue;
+		if (si_type[i] != NULL) {
+			if ((addr_space == IPMI_MEM_ADDR_SPACE && 
+			     base_addr == si_addrs[i]) ||
+			    (addr_space == IPMI_IO_ADDR_SPACE &&
+			     base_addr == si_ports[i]))
+				return 0;
+		}
+		else
+			break;
+	}
+	
+	return 1;
+}
+#endif
+ 
+static int std_irq_setup(struct smi_info *info)
+{
+	int rv;
+
+	if (!info->irq)
+		return 0;
+
+	rv = request_irq(info->irq,
+			 si_irq_handler,
+			 SA_INTERRUPT,
+			 DEVICE_NAME,
+			 info);
+	if (rv) {
+		printk(KERN_WARNING
+		       "ipmi_si: %s unable to claim interrupt %d,"
+		       " running polled\n",
+		       DEVICE_NAME, info->irq);
+		info->irq = 0;
+	} else {
+		printk("  Using irq %d\n", info->irq);
+	}
+
+	return rv;
+}
+
+static void std_irq_cleanup(struct smi_info *info)
+{
+	if (!info->irq)
+		return;
+
+	free_irq(info->irq, info);
+}
+
+static unsigned char port_inb(struct si_sm_io *io, unsigned int offset)
+{
+	unsigned int *addr = io->info;
+
+	return inb((*addr)+(offset*io->regspacing));
+}
+
+static void port_outb(struct si_sm_io *io, unsigned int offset,
+		      unsigned char b)
+{
+	unsigned int *addr = io->info;
+
+	outb(b, (*addr)+(offset * io->regspacing));
+}
+
+static unsigned char port_inw(struct si_sm_io *io, unsigned int offset)
+{
+	unsigned int *addr = io->info;
+
+	return (inw((*addr)+(offset * io->regspacing)) >> io->regshift) & 0xff;
+}
+
+static void port_outw(struct si_sm_io *io, unsigned int offset,
+		      unsigned char b)
+{
+	unsigned int *addr = io->info;
+
+	outw(b << io->regshift, (*addr)+(offset * io->regspacing));
+}
+
+static unsigned char port_inl(struct si_sm_io *io, unsigned int offset)
+{
+	unsigned int *addr = io->info;
+
+	return (inl((*addr)+(offset * io->regspacing)) >> io->regshift) & 0xff;
+}
+
+static void port_outl(struct si_sm_io *io, unsigned int offset,
+		      unsigned char b)
+{
+	unsigned int *addr = io->info;
+
+	outl(b << io->regshift, (*addr)+(offset * io->regspacing));
+}
+
+static void port_cleanup(struct smi_info *info)
+{
+	unsigned int *addr = info->io.info;
+	int           mapsize;
+
+	if (addr && (*addr)) {
+		mapsize = ((info->io_size * info->io.regspacing)
+			   - (info->io.regspacing - info->io.regsize));
+
+		release_region (*addr, mapsize);
+	}
+	kfree(info);
+}
+
+static int port_setup(struct smi_info *info)
+{
+	unsigned int *addr = info->io.info;
+	int           mapsize;
+
+	if (!addr || (!*addr))
+		return -ENODEV;
+
+	info->io_cleanup = port_cleanup;
+
+	/* Figure out the actual inb/inw/inl/etc routine to use based
+	   upon the register size. */
+	switch (info->io.regsize) {
+	case 1:
+		info->io.inputb = port_inb;
+		info->io.outputb = port_outb;
+		break;
+	case 2:
+		info->io.inputb = port_inw;
+		info->io.outputb = port_outw;
+		break;
+	case 4:
+		info->io.inputb = port_inl;
+		info->io.outputb = port_outl;
+		break;
+	default:
+		printk("ipmi_si: Invalid register size: %d\n",
+		       info->io.regsize);
+		return -EINVAL;
+	}
+
+	/* Calculate the total amount of memory to claim.  This is an
+	 * unusual looking calculation, but it avoids claiming any
+	 * more memory than it has to.  It will claim everything
+	 * between the first address to the end of the last full
+	 * register. */
+	mapsize = ((info->io_size * info->io.regspacing)
+		   - (info->io.regspacing - info->io.regsize));
+
+	if (request_region(*addr, mapsize, DEVICE_NAME) == NULL)
+		return -EIO;
+	return 0;
+}
+
+static int try_init_port(int intf_num, struct smi_info **new_info)
+{
+	struct smi_info *info;
+
+	if (!si_ports[intf_num])
+		return -ENODEV;
+
+	if (!is_new_interface(intf_num, IPMI_IO_ADDR_SPACE,
+			      si_ports[intf_num]))
+		return -ENODEV;
+
+	info = kmalloc(sizeof(*info), GFP_KERNEL);
+	if (!info) {
+		printk(KERN_ERR "ipmi_si: Could not allocate SI data (1)\n");
+		return -ENOMEM;
+	}
+	memset(info, 0, sizeof(*info));
+
+	info->io_setup = port_setup;
+	info->io.info = &(si_ports[intf_num]);
+	info->io.addr = NULL;
+	info->io.regspacing = si_regspacings[intf_num];
+	if (!info->io.regspacing)
+		info->io.regspacing = DEFAULT_REGSPACING;
+	info->io.regsize = si_regsizes[intf_num];
+	if (!info->io.regsize)
+		info->io.regsize = DEFAULT_REGSPACING;
+	info->io.regshift = si_regshifts[intf_num];
+	info->irq = 0;
+	info->irq_setup = NULL;
+	*new_info = info;
+
+	if (si_type[intf_num] == NULL)
+		si_type[intf_num] = "kcs";
+
+	printk("ipmi_si: Trying \"%s\" at I/O port 0x%x\n",
+	       si_type[intf_num], si_ports[intf_num]);
+	return 0;
+}
+
+static unsigned char mem_inb(struct si_sm_io *io, unsigned int offset)
+{
+	return readb((io->addr)+(offset * io->regspacing));
+}
+
+static void mem_outb(struct si_sm_io *io, unsigned int offset,
+		     unsigned char b)
+{
+	writeb(b, (io->addr)+(offset * io->regspacing));
+}
+
+static unsigned char mem_inw(struct si_sm_io *io, unsigned int offset)
+{
+	return (readw((io->addr)+(offset * io->regspacing)) >> io->regshift)
+		&& 0xff;
+}
+
+static void mem_outw(struct si_sm_io *io, unsigned int offset,
+		     unsigned char b)
+{
+	writeb(b << io->regshift, (io->addr)+(offset * io->regspacing));
+}
+
+static unsigned char mem_inl(struct si_sm_io *io, unsigned int offset)
+{
+	return (readl((io->addr)+(offset * io->regspacing)) >> io->regshift)
+		&& 0xff;
+}
+
+static void mem_outl(struct si_sm_io *io, unsigned int offset,
+		     unsigned char b)
+{
+	writel(b << io->regshift, (io->addr)+(offset * io->regspacing));
+}
+
+#ifdef readq
+static unsigned char mem_inq(struct si_sm_io *io, unsigned int offset)
+{
+	return (readq((io->addr)+(offset * io->regspacing)) >> io->regshift)
+		&& 0xff;
+}
+
+static void mem_outq(struct si_sm_io *io, unsigned int offset,
+		     unsigned char b)
+{
+	writeq(b << io->regshift, (io->addr)+(offset * io->regspacing));
+}
+#endif
+
+static void mem_cleanup(struct smi_info *info)
+{
+	unsigned long *addr = info->io.info;
+	int           mapsize;
+
+	if (info->io.addr) {
+		iounmap(info->io.addr);
+
+		mapsize = ((info->io_size * info->io.regspacing)
+			   - (info->io.regspacing - info->io.regsize));
+
+		release_mem_region(*addr, mapsize);
+	}
+	kfree(info);
+}
+
+static int mem_setup(struct smi_info *info)
+{
+	unsigned long *addr = info->io.info;
+	int           mapsize;
+
+	if (!addr || (!*addr))
+		return -ENODEV;
+
+	info->io_cleanup = mem_cleanup;
+
+	/* Figure out the actual readb/readw/readl/etc routine to use based
+	   upon the register size. */
+	switch (info->io.regsize) {
+	case 1:
+		info->io.inputb = mem_inb;
+		info->io.outputb = mem_outb;
+		break;
+	case 2:
+		info->io.inputb = mem_inw;
+		info->io.outputb = mem_outw;
+		break;
+	case 4:
+		info->io.inputb = mem_inl;
+		info->io.outputb = mem_outl;
+		break;
+#ifdef readq
+	case 8:
+		info->io.inputb = mem_inq;
+		info->io.outputb = mem_outq;
+		break;
+#endif
+	default:
+		printk("ipmi_si: Invalid register size: %d\n",
+		       info->io.regsize);
+		return -EINVAL;
+	}
+
+	/* Calculate the total amount of memory to claim.  This is an
+	 * unusual looking calculation, but it avoids claiming any
+	 * more memory than it has to.  It will claim everything
+	 * between the first address to the end of the last full
+	 * register. */
+	mapsize = ((info->io_size * info->io.regspacing)
+		   - (info->io.regspacing - info->io.regsize));
+
+	if (request_mem_region(*addr, mapsize, DEVICE_NAME) == NULL)
+		return -EIO;
+
+	info->io.addr = ioremap(*addr, mapsize);
+	if (info->io.addr == NULL) {
+		release_mem_region(*addr, mapsize);
+		return -EIO;
+	}
+	return 0;
+}
+
+static int try_init_mem(int intf_num, struct smi_info **new_info)
+{
+	struct smi_info *info;
+
+	if (!si_addrs[intf_num])
+		return -ENODEV;
+
+	if (!is_new_interface(intf_num, IPMI_MEM_ADDR_SPACE,
+			      si_addrs[intf_num]))
+		return -ENODEV;
+
+	info = kmalloc(sizeof(*info), GFP_KERNEL);
+	if (!info) {
+		printk(KERN_ERR "ipmi_si: Could not allocate SI data (2)\n");
+		return -ENOMEM;
+	}
+	memset(info, 0, sizeof(*info));
+
+	info->io_setup = mem_setup;
+	info->io.info = (void *) si_addrs[intf_num];
+	info->io.addr = NULL;
+	info->io.regspacing = si_regspacings[intf_num];
+	if (!info->io.regspacing)
+		info->io.regspacing = DEFAULT_REGSPACING;
+	info->io.regsize = si_regsizes[intf_num];
+	if (!info->io.regsize)
+		info->io.regsize = DEFAULT_REGSPACING;
+	info->io.regshift = si_regshifts[intf_num];
+	info->irq = 0;
+	info->irq_setup = NULL;
+	*new_info = info;
+
+	if (si_type[intf_num] == NULL)
+		si_type[intf_num] = "kcs";
+
+	printk("ipmi_si: Trying \"%s\" at memory address 0x%lx\n",
+	       si_type[intf_num], si_addrs[intf_num]);
+	return 0;
+}
+
+#ifdef CONFIG_ACPI_INTERPRETER
+
+#include <linux/acpi.h>
+#include <acpi/acpi.h>
+#include <acpi/actypes.h>
+#include <acpi/actbl.h>
+
+/* Once we get an ACPI failure, we don't try any more, because we go
+   through the tables sequentially.  Once we don't find a table, there
+   are no more. */
+static int acpi_failure = 0;
+
+/* For GPE-type interrupts. */
+void ipmi_acpi_gpe(void *context)
+{
+	struct smi_info *smi_info = context;
+	unsigned long   flags;
+#ifdef DEBUG_TIMING
+	struct timeval t;
+#endif
+
+	spin_lock_irqsave(&(smi_info->si_lock), flags);
+
+	spin_lock(&smi_info->count_lock);
+	smi_info->interrupts++;
+	spin_unlock(&smi_info->count_lock);
+
+	if (smi_info->stop_operation)
+		goto out;
+
+#ifdef DEBUG_TIMING
+	do_gettimeofday(&t);
+	printk("**ACPI_GPE: %d.%9.9d\n", t.tv_sec, t.tv_usec);
+#endif
+	smi_event_handler(smi_info, 0);
+ out:
+	spin_unlock_irqrestore(&(smi_info->si_lock), flags);
+}
+
+static int acpi_gpe_irq_setup(struct smi_info *info)
+{
+	acpi_status status;
+
+	if (!info->irq)
+		return 0;
+
+	/* FIXME - is level triggered right? */
+	status = acpi_install_gpe_handler(NULL,
+					  info->irq,
+					  ACPI_GPE_LEVEL_TRIGGERED,
+					  ipmi_acpi_gpe,
+					  info);
+	if (status != AE_OK) {
+		printk(KERN_WARNING
+		       "ipmi_si: %s unable to claim ACPI GPE %d,"
+		       " running polled\n",
+		       DEVICE_NAME, info->irq);
+		info->irq = 0;
+		return -EINVAL;
+	} else {
+		printk("  Using ACPI GPE %d\n", info->irq);
+		return 0;
+	}
+
+}
+
+static void acpi_gpe_irq_cleanup(struct smi_info *info)
+{
+	if (!info->irq)
+		return;
+
+	acpi_remove_gpe_handler(NULL, info->irq, ipmi_acpi_gpe);
+}
+
+/*
+ * Defined at
+ * http://h21007.www2.hp.com/dspp/files/unprotected/devresource/Docs/TechPapers/IA64/hpspmi.pdf
+ */
+struct SPMITable {
+	s8	Signature[4];
+	u32	Length;
+	u8	Revision;
+	u8	Checksum;
+	s8	OEMID[6];
+	s8	OEMTableID[8];
+	s8	OEMRevision[4];
+	s8	CreatorID[4];
+	s8	CreatorRevision[4];
+	u8	InterfaceType;
+	u8	IPMIlegacy;
+	s16	SpecificationRevision;
+
+	/*
+	 * Bit 0 - SCI interrupt supported
+	 * Bit 1 - I/O APIC/SAPIC
+	 */
+	u8	InterruptType;
+
+	/* If bit 0 of InterruptType is set, then this is the SCI
+           interrupt in the GPEx_STS register. */
+	u8	GPE;
+
+	s16	Reserved;
+
+	/* If bit 1 of InterruptType is set, then this is the I/O
+           APIC/SAPIC interrupt. */
+	u32	GlobalSystemInterrupt;
+
+	/* The actual register address. */
+	struct acpi_generic_address addr;
+
+	u8	UID[4];
+
+	s8      spmi_id[1]; /* A '\0' terminated array starts here. */
+};
+
+static int try_init_acpi(int intf_num, struct smi_info **new_info)
+{
+	struct smi_info  *info;
+	acpi_status      status;
+	struct SPMITable *spmi;
+	char             *io_type;
+	u8 		 addr_space;
+
+	if (acpi_failure)
+		return -ENODEV;
+
+	status = acpi_get_firmware_table("SPMI", intf_num+1,
+					 ACPI_LOGICAL_ADDRESSING,
+					 (struct acpi_table_header **) &spmi);
+	if (status != AE_OK) {
+		acpi_failure = 1;
+		return -ENODEV;
+	}
+
+	if (spmi->IPMIlegacy != 1) {
+	    printk(KERN_INFO "IPMI: Bad SPMI legacy %d\n", spmi->IPMIlegacy);
+	    return -ENODEV;
+	}
+
+	if (spmi->addr.address_space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY)
+		addr_space = IPMI_MEM_ADDR_SPACE;
+	else
+		addr_space = IPMI_IO_ADDR_SPACE;
+	if (!is_new_interface(-1, addr_space, spmi->addr.address))
+		return -ENODEV;
+
+	/* Figure out the interface type. */
+	switch (spmi->InterfaceType)
+	{
+	case 1:	/* KCS */
+		si_type[intf_num] = "kcs";
+		break;
+
+	case 2:	/* SMIC */
+		si_type[intf_num] = "smic";
+		break;
+
+	case 3:	/* BT */
+		si_type[intf_num] = "bt";
+		break;
+
+	default:
+		printk(KERN_INFO "ipmi_si: Unknown ACPI/SPMI SI type %d\n",
+			spmi->InterfaceType);
+		return -EIO;
+	} 
+
+	info = kmalloc(sizeof(*info), GFP_KERNEL);
+	if (!info) {
+		printk(KERN_ERR "ipmi_si: Could not allocate SI data (3)\n");
+		return -ENOMEM;
+	}
+	memset(info, 0, sizeof(*info));
+
+	if (spmi->InterruptType & 1) {
+		/* We've got a GPE interrupt. */
+		info->irq = spmi->GPE;
+		info->irq_setup = acpi_gpe_irq_setup;
+		info->irq_cleanup = acpi_gpe_irq_cleanup;
+	} else if (spmi->InterruptType & 2) {
+		/* We've got an APIC/SAPIC interrupt. */
+		info->irq = spmi->GlobalSystemInterrupt;
+		info->irq_setup = std_irq_setup;
+		info->irq_cleanup = std_irq_cleanup;
+	} else {
+		/* Use the default interrupt setting. */
+		info->irq = 0;
+		info->irq_setup = NULL;
+	}
+
+	si_regspacings[intf_num] = spmi->addr.register_bit_width / 8;
+	info->io.regspacing = spmi->addr.register_bit_width / 8;
+	si_regsizes[intf_num] = si_regspacings[intf_num];
+	info->io.regsize = si_regsizes[intf_num];
+	si_regshifts[intf_num] = spmi->addr.register_bit_offset;
+	info->io.regshift = si_regshifts[intf_num];
+
+	if (spmi->addr.address_space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) {
+		io_type = "memory";
+		info->io_setup = mem_setup;
+		si_addrs[intf_num] = spmi->addr.address;
+		info->io.info = &(si_addrs[intf_num]);
+	} else if (spmi->addr.address_space_id == ACPI_ADR_SPACE_SYSTEM_IO) {
+		io_type = "I/O";
+		info->io_setup = port_setup;
+		si_ports[intf_num] = spmi->addr.address;
+		info->io.info = &(si_ports[intf_num]);
+	} else {
+		kfree(info);
+		printk("ipmi_si: Unknown ACPI I/O Address type\n");
+		return -EIO;
+	}
+
+	*new_info = info;
+
+	printk("ipmi_si: ACPI/SPMI specifies \"%s\" %s SI @ 0x%lx\n",
+	       si_type[intf_num], io_type, (unsigned long) spmi->addr.address);
+	return 0;
+}
+#endif
+
+#ifdef CONFIG_X86
+
+typedef struct dmi_ipmi_data
+{
+	u8   		type;
+	u8   		addr_space;
+	unsigned long	base_addr;
+	u8   		irq;
+	u8              offset;
+}dmi_ipmi_data_t;
+
+typedef struct dmi_header
+{
+	u8	type;
+	u8	length;
+	u16	handle;
+}dmi_header_t;
+
+static int decode_dmi(dmi_header_t *dm, dmi_ipmi_data_t *ipmi_data)
+{
+	u8		*data = (u8 *)dm;
+	unsigned long  	base_addr;
+	u8		reg_spacing;
+	
+	ipmi_data->type = data[0x04];
+	
+	memcpy(&base_addr,&data[0x08],sizeof(unsigned long));
+	if (base_addr & 1) {
+		/* I/O */
+		base_addr &= 0xFFFE;
+		ipmi_data->addr_space = IPMI_IO_ADDR_SPACE;
+	}
+	else {
+		/* Memory */
+		ipmi_data->addr_space = IPMI_MEM_ADDR_SPACE;
+	}
+		
+	/* The top two bits of byte 0x10 hold the register spacing. */
+	reg_spacing = (data[0x10] & 0xC0) >> 6;
+	switch(reg_spacing){
+	case 0x00: /* Byte boundaries */
+		ipmi_data->offset = 1;
+		break;
+	case 0x01: /* 32-bit boundaries */
+		ipmi_data->offset = 4;
+		break;
+	case 0x02: /* 16-bit boundaries */
+		ipmi_data->offset = 2;
+	default:
+		printk("ipmi_si: Unknown SMBIOS IPMI Base Addr"
+		       " Modifier: 0x%x\n", reg_spacing);
+		return -EIO;
+	}
+
+	/* If bit 4 of byte 0x10 is set, then the lsb for the address
+	   is odd. */
+	ipmi_data->base_addr = base_addr | ((data[0x10] & 0x10) >> 4);
+
+	ipmi_data->irq = data[0x11];
+	
+	if (is_new_interface(-1, ipmi_data->addr_space,ipmi_data->base_addr))
+	    return 0;
+	    
+	memset(ipmi_data,0,sizeof(dmi_ipmi_data_t));
+	    
+	return -1;
+}
+
+static int dmi_table(u32 base, int len, int num, 
+	dmi_ipmi_data_t *ipmi_data)
+{
+	u8 		  *buf;
+	struct dmi_header *dm;
+	u8 		  *data;
+	int 		  i=1;
+	int		  status=-1;
+
+	buf = ioremap(base, len);
+	if(buf==NULL)
+		return -1;
+
+	data = buf;
+
+	while(i<num && (data - buf) < len)
+	{        
+		dm=(dmi_header_t *)data;
+
+		if((data-buf+dm->length) >= len)
+        		break;
+       
+		if (dm->type == 38) {
+			if (decode_dmi(dm, ipmi_data) == 0) {
+				status = 0;
+				break;
+			}
+		}
+       
+	        data+=dm->length;
+		while((data-buf) < len && (*data || data[1]))
+			data++;
+		data+=2;
+		i++;
+	}
+	iounmap(buf);
+	
+	return status;
+}
+
+inline static int dmi_checksum(u8 *buf)
+{
+	u8   sum=0;
+	int  a;
+	
+	for(a=0; a<15; a++)
+		sum+=buf[a];
+	return (sum==0);
+}
+
+static int dmi_iterator(dmi_ipmi_data_t *ipmi_data)
+{
+	u8   buf[15];
+	u32  fp=0xF0000;
+
+#ifdef CONFIG_SIMNOW
+	return -1;
+#endif
+ 	
+	while(fp < 0xFFFFF)
+	{
+		isa_memcpy_fromio(buf, fp, 15);
+		if(memcmp(buf, "_DMI_", 5)==0 && dmi_checksum(buf))
+		{
+			u16 num=buf[13]<<8|buf[12];
+			u16 len=buf[7]<<8|buf[6];
+			u32 base=buf[11]<<24|buf[10]<<16|buf[9]<<8|buf[8];
+
+			if(dmi_table(base, len, num, ipmi_data) == 0)
+				return 0;
+		}
+		fp+=16;
+	}
+	
+	return -1;
+}
+
+static int try_init_smbios(int intf_num, struct smi_info **new_info)
+{
+	struct smi_info   *info;
+	dmi_ipmi_data_t   ipmi_data;
+	char              *io_type;
+	int               status;
+
+	status = dmi_iterator(&ipmi_data);
+
+	if (status < 0)
+		return -ENODEV;
+	
+	switch(ipmi_data.type) {
+		case 0x01: /* KCS */
+			si_type[intf_num] = "kcs";
+			break;
+		case 0x02: /* SMIC */
+			si_type[intf_num] = "smic";
+			break;
+		case 0x03: /* BT */
+			si_type[intf_num] = "bt";
+			break;
+		default:
+			printk("ipmi_si: Unknown SMBIOS SI type.\n");
+			return -EIO;
+	}
+	
+	info = kmalloc(sizeof(*info), GFP_KERNEL);
+	if (!info) {
+		printk(KERN_ERR "ipmi_si: Could not allocate SI data (4)\n");
+		return -ENOMEM;
+	}
+	memset(info, 0, sizeof(*info));
+
+	if (ipmi_data.addr_space == 1) {
+		io_type = "memory";
+		info->io_setup = mem_setup;
+		si_addrs[intf_num] = ipmi_data.base_addr;
+		info->io.info = &(si_addrs[intf_num]);
+	} else if (ipmi_data.addr_space == 2) {
+		io_type = "I/O";
+		info->io_setup = port_setup;
+		si_ports[intf_num] = ipmi_data.base_addr;
+		info->io.info = &(si_ports[intf_num]);
+	} else {
+		kfree(info);
+		printk("ipmi_si: Unknown SMBIOS I/O Address type.\n");
+		return -EIO;
+	}
+
+	si_regspacings[intf_num] = ipmi_data.offset;
+	info->io.regspacing = si_regspacings[intf_num];
+	if (!info->io.regspacing)
+		info->io.regspacing = DEFAULT_REGSPACING;
+	info->io.regsize = DEFAULT_REGSPACING;
+	info->io.regshift = si_regshifts[intf_num];
+
+	si_irqs[intf_num] = ipmi_data.irq;
+
+	*new_info = info;
+
+	printk("ipmi_si: Found SMBIOS-specified state machine at %s"
+	       " address 0x%lx\n",
+	       io_type, (unsigned long)ipmi_data.base_addr);
+	return 0;
+}
+#endif /* CONFIG_X86 */
+
+#ifdef CONFIG_PCI
+
+#define PCI_ERMC_CLASSCODE  0x0C0700
+#define PCI_HP_VENDOR_ID    0x103C
+#define PCI_MMC_DEVICE_ID   0x121A
+#define PCI_MMC_ADDR_CW     0x10
+
+/* Avoid more than one attempt to probe pci smic. */
+static int pci_smic_checked = 0;
+
+static int find_pci_smic(int intf_num, struct smi_info **new_info)
+{
+	struct smi_info  *info;
+	int              error;
+	struct pci_dev   *pci_dev = NULL;
+	u16    		 base_addr;
+	int              fe_rmc = 0;
+	
+	if (!pci_present() || pci_smic_checked)
+		return -ENODEV;
+
+	pci_smic_checked = 1;
+	
+	if ((pci_dev = pci_find_device(PCI_HP_VENDOR_ID, PCI_MMC_DEVICE_ID,
+				       NULL)))
+		;
+	else if ((pci_dev = pci_find_class(PCI_ERMC_CLASSCODE, NULL)) &&
+		 pci_dev->subsystem_vendor == PCI_HP_VENDOR_ID)
+		fe_rmc = 1;
+	else
+		return -ENODEV;
+	
+	error = pci_read_config_word(pci_dev, PCI_MMC_ADDR_CW, &base_addr);
+	if (error)
+	{
+		printk(KERN_ERR
+		       "ipmi_si: pci_read_config_word() failed (%d).\n",
+		       error);
+		return -ENODEV;
+	}
+	
+	/* Bit 0: 1 specifies programmed I/O, 0 specifies memory mapped I/O */
+	if (!(base_addr & 0x0001))
+	{
+		printk(KERN_ERR
+		       "ipmi_si: memory mapped I/O not supported for PCI"
+		       " smic.\n");
+		return -ENODEV;
+	}
+	
+	base_addr &= 0xFFFE;
+	if (!fe_rmc)
+		/* Data register starts at base address + 1 in eRMC */
+		++base_addr;
+	
+	if (!is_new_interface(-1, IPMI_IO_ADDR_SPACE, base_addr))
+	    return -ENODEV;
+	
+	info = kmalloc(sizeof(*info), GFP_KERNEL);
+	if (!info) {
+		printk(KERN_ERR "ipmi_si: Could not allocate SI data (5)\n");
+		return -ENOMEM;
+	}
+	memset(info, 0, sizeof(*info));
+	
+	info->io_setup = port_setup;
+	si_ports[intf_num] = base_addr;
+	info->io.info = &(si_ports[intf_num]);
+	info->io.regspacing = si_regspacings[intf_num];
+	if (!info->io.regspacing)
+		info->io.regspacing = DEFAULT_REGSPACING;
+	info->io.regsize = DEFAULT_REGSPACING;
+	info->io.regshift = si_regshifts[intf_num];
+
+	*new_info = info;
+	
+	si_irqs[intf_num] = pci_dev->irq;
+	si_type[intf_num] = "smic";
+
+	printk("ipmi_si: Found PCI SMIC at I/O address 0x%lx\n",
+		(long unsigned int) base_addr);
+	
+	return 0;
+}
+#endif /* CONFIG_PCI */
+
+static int try_init_plug_and_play(int intf_num, struct smi_info **new_info)
+{
+#ifdef CONFIG_PCI
+	if (find_pci_smic(intf_num, new_info)==0)
+		return 0;
+#endif
+	/* Include other methods here. */
+    
+	return -ENODEV;
+}
+
+
+static int try_get_dev_id(struct smi_info *smi_info)
+{
+	unsigned char      msg[2];
+	unsigned char      *resp;
+	unsigned long      resp_len;
+	enum si_sm_result smi_result;
+	int               rv = 0;
+
+	resp = kmalloc(IPMI_MAX_MSG_LENGTH, GFP_KERNEL);
+	if (!resp)
+		return -ENOMEM;
+
+	/* Do a Get Device ID command, since it comes back with some
+	   useful info. */
+	msg[0] = IPMI_NETFN_APP_REQUEST << 2;
+	msg[1] = IPMI_GET_DEVICE_ID_CMD;
+	smi_info->handlers->start_transaction(smi_info->si_sm, msg, 2);
+	
+	smi_result = smi_info->handlers->event(smi_info->si_sm, 0);
+	for (;;)
+	{
+		if (smi_result == SI_SM_CALL_WITH_DELAY) {
+			set_current_state(TASK_UNINTERRUPTIBLE);
+			schedule_timeout(1);
+			smi_result = smi_info->handlers->event(
+				smi_info->si_sm, 100);
+		}
+		else if (smi_result == SI_SM_CALL_WITHOUT_DELAY)
+		{
+			smi_result = smi_info->handlers->event(
+				smi_info->si_sm, 0);
+		}
+		else
+			break;
+	}
+	if (smi_result == SI_SM_HOSED) {
+		/* We couldn't get the state machine to run, so whatever's at
+		   the port is probably not an IPMI SMI interface. */
+		rv = -ENODEV;
+		goto out;
+	}
+
+	/* Otherwise, we got some data. */
+	resp_len = smi_info->handlers->get_result(smi_info->si_sm,
+						  resp, IPMI_MAX_MSG_LENGTH);
+	if (resp_len < 6) {
+		/* That's odd, it should be longer. */
+		rv = -EINVAL;
+		goto out;
+	}
+	
+	if ((resp[1] != IPMI_GET_DEVICE_ID_CMD) || (resp[2] != 0)) {
+		/* That's odd, it shouldn't be able to fail. */
+		rv = -EINVAL;
+		goto out;
+	}
+
+	/* Record info from the get device id, in case we need it. */
+	smi_info->ipmi_si_dev_rev = resp[4] & 0xf;
+	smi_info->ipmi_si_fw_rev_major = resp[5] & 0x7f;
+	smi_info->ipmi_si_fw_rev_minor = resp[6];
+	smi_info->ipmi_version_major = resp[7] & 0xf;
+	smi_info->ipmi_version_minor = resp[7] >> 4;
+
+ out:
+	kfree(resp);
+	return rv;
+}
+
+static int type_file_read_proc(char *page, char **start, off_t off,
+			       int count, int *eof, void *data)
+{
+	char            *out = (char *) page;
+	struct smi_info *smi = data;
+
+	switch (smi->si_type) {
+	    case SI_KCS:
+		return sprintf(out, "kcs\n");
+	    case SI_SMIC:
+		return sprintf(out, "smic\n");
+	    case SI_BT:
+		return sprintf(out, "bt\n");
+	    default:
+		return 0;
+	}
+}
+
+static int stat_file_read_proc(char *page, char **start, off_t off,
+			       int count, int *eof, void *data)
+{
+	char            *out = (char *) page;
+	struct smi_info *smi = data;
+
+	out += sprintf(out, "interrupts_enabled:    %d\n",
+		       smi->irq && !smi->interrupt_disabled);
+	out += sprintf(out, "short_timeouts:        %ld\n",
+		       smi->short_timeouts);
+	out += sprintf(out, "long_timeouts:         %ld\n",
+		       smi->long_timeouts);
+	out += sprintf(out, "timeout_restarts:      %ld\n",
+		       smi->timeout_restarts);
+	out += sprintf(out, "idles:                 %ld\n",
+		       smi->idles);
+	out += sprintf(out, "interrupts:            %ld\n",
+		       smi->interrupts);
+	out += sprintf(out, "attentions:            %ld\n",
+		       smi->attentions);
+	out += sprintf(out, "flag_fetches:          %ld\n",
+		       smi->flag_fetches);
+	out += sprintf(out, "hosed_count:           %ld\n",
+		       smi->hosed_count);
+	out += sprintf(out, "complete_transactions: %ld\n",
+		       smi->complete_transactions);
+	out += sprintf(out, "events:                %ld\n",
+		       smi->events);
+	out += sprintf(out, "watchdog_pretimeouts:  %ld\n",
+		       smi->watchdog_pretimeouts);
+	out += sprintf(out, "incoming_messages:     %ld\n",
+		       smi->incoming_messages);
+
+	return (out - ((char *) page));
+}
+
+/* Returns 0 if initialized, or negative on an error. */
+static int init_one_smi(int intf_num, struct smi_info **smi)
+{
+	int		rv;
+	struct smi_info *new_smi;
+
+
+	rv = try_init_mem(intf_num, &new_smi);
+	if (rv)
+		rv = try_init_port(intf_num, &new_smi);
+#ifdef CONFIG_ACPI_INTERPRETER
+	if ((rv) && (si_trydefaults)) {
+		rv = try_init_acpi(intf_num, &new_smi);
+	}
+#endif
+#ifdef CONFIG_X86
+	if ((rv) && (si_trydefaults)) {
+		rv = try_init_smbios(intf_num, &new_smi);
+        }
+#endif
+	if ((rv) && (si_trydefaults)) {
+		rv = try_init_plug_and_play(intf_num, &new_smi);
+	}
+
+
+	if (rv)
+		return rv;
+
+	/* So we know not to free it unless we have allocated one. */
+	new_smi->intf = NULL;
+	new_smi->si_sm = NULL;
+	new_smi->handlers = 0;
+
+	if (!new_smi->irq_setup) {
+		new_smi->irq = si_irqs[intf_num];
+		new_smi->irq_setup = std_irq_setup;
+		new_smi->irq_cleanup = std_irq_cleanup;
+	}
+
+	/* Default to KCS if no type is specified. */
+	if (si_type[intf_num] == NULL) {
+		if (si_trydefaults)
+			si_type[intf_num] = "kcs";
+		else {
+			rv = -EINVAL;
+			goto out_err;
+		}
+	}
+
+	/* Set up the state machine to use. */
+	if (strcmp(si_type[intf_num], "kcs") == 0) {
+		new_smi->handlers = &kcs_smi_handlers;
+		new_smi->si_type = SI_KCS;
+	} else if (strcmp(si_type[intf_num], "smic") == 0) {
+		new_smi->handlers = &smic_smi_handlers;
+		new_smi->si_type = SI_SMIC;
+	} else if (strcmp(si_type[intf_num], "bt") == 0) {
+		new_smi->handlers = &bt_smi_handlers;
+		new_smi->si_type = SI_BT;
+	} else {
+		/* No support for anything else yet. */
+		rv = -EIO;
+		goto out_err;
+	}
+
+	/* Allocate the state machine's data and initialize it. */
+	new_smi->si_sm = kmalloc(new_smi->handlers->size(), GFP_KERNEL);
+	if (!new_smi->si_sm) {
+		printk(" Could not allocate state machine memory\n");
+		rv = -ENOMEM;
+		goto out_err;
+	}
+	new_smi->io_size = new_smi->handlers->init_data(new_smi->si_sm,
+							&new_smi->io);
+
+	/* Now that we know the I/O size, we can set up the I/O. */
+	rv = new_smi->io_setup(new_smi);
+	if (rv) {
+		printk(" Could not set up I/O space\n");
+		goto out_err;
+	}
+	
+	spin_lock_init(&(new_smi->si_lock));
+	spin_lock_init(&(new_smi->msg_lock));
+	spin_lock_init(&(new_smi->count_lock));
+
+	/* Do low-level detection first. */
+	if (new_smi->handlers->detect(new_smi->si_sm)) {
+		rv = -ENODEV;
+		goto out_err;
+	}
+
+	/* Attempt a get device id command.  If it fails, we probably
+           don't have a SMI here. */
+	rv = try_get_dev_id(new_smi);
+	if (rv)
+		goto out_err;
+
+	/* Try to claim any interrupts. */
+	new_smi->irq_setup(new_smi);
+
+	INIT_LIST_HEAD(&(new_smi->xmit_msgs));
+	INIT_LIST_HEAD(&(new_smi->hp_xmit_msgs));
+	new_smi->curr_msg = NULL;
+	atomic_set(&new_smi->req_events, 0);
+	new_smi->run_to_completion = 0;
+
+	new_smi->interrupt_disabled = 0;
+	new_smi->timer_stopped = 0;
+	new_smi->stop_operation = 0;
+
+	/* Start clearing the flags before we enable interrupts or the
+	   timer to avoid racing with the timer. */
+	start_clear_flags(new_smi);
+	/* IRQ is defined to be set when non-zero. */
+	if (new_smi->irq)
+		new_smi->si_state = SI_CLEARING_FLAGS_THEN_SET_IRQ;
+
+	/* The ipmi_register_smi() code does some operations to
+	   determine the channel information, so we must be ready to
+	   handle operations before it is called.  This means we have
+	   to stop the timer if we get an error after this point. */
+	init_timer(&(new_smi->si_timer));
+	new_smi->si_timer.data = (long) new_smi;
+	new_smi->si_timer.function = smi_timeout;
+	new_smi->last_timeout_jiffies = jiffies;
+	new_smi->si_timer.expires = jiffies + SI_TIMEOUT_JIFFIES;
+	add_timer(&(new_smi->si_timer));
+
+	rv = ipmi_register_smi(&handlers,
+			       new_smi,
+			       new_smi->ipmi_version_major,
+			       new_smi->ipmi_version_minor,
+			       &(new_smi->intf));
+	if (rv) {
+		printk(KERN_ERR 
+		       "ipmi_si: Unable to register device: error %d\n",
+		       rv);
+		goto out_err_stop_timer;
+	}
+
+	rv = ipmi_smi_add_proc_entry(new_smi->intf, "type",
+				     type_file_read_proc, NULL,
+				     new_smi, THIS_MODULE);
+	if (rv) {
+		printk(KERN_ERR 
+		       "ipmi_si: Unable to create proc entry: %d\n",
+		       rv);
+		goto out_err_stop_timer;
+	}
+
+	rv = ipmi_smi_add_proc_entry(new_smi->intf, "si_stats",
+				     stat_file_read_proc, NULL,
+				     new_smi, THIS_MODULE);
+	if (rv) {
+		printk(KERN_ERR 
+		       "ipmi_si: Unable to create proc entry: %d\n",
+		       rv);
+		goto out_err_stop_timer;
+	}
+
+	*smi = new_smi;
+
+	printk(" IPMI %s interface initialized\n", si_type[intf_num]);
+
+	return 0;
+
+ out_err_stop_timer:
+	new_smi->stop_operation = 1;
+
+	/* Wait for the timer to stop.  This avoids problems with race
+	   conditions removing the timer here. */
+	while (!new_smi->timer_stopped) {
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		schedule_timeout(1);
+	}
+
+ out_err:
+	if (new_smi->intf)
+		ipmi_unregister_smi(new_smi->intf);
+
+	new_smi->irq_cleanup(new_smi);
+	if (new_smi->si_sm) {
+		if (new_smi->handlers)
+			new_smi->handlers->cleanup(new_smi->si_sm);
+		kfree(new_smi->si_sm);
+	}
+	new_smi->io_cleanup(new_smi);
+	return rv;
+}
+
+static __init int init_ipmi_si(void)
+{
+	int		rv = 0;
+	int		pos = 0;
+	int		i = 0;
+
+	if (initialized)
+		return 0;
+	initialized = 1;
+
+	printk(KERN_INFO "IPMI System Interface driver version "
+	       IPMI_SI_VERSION);
+	if (kcs_smi_handlers.version)
+		printk(", KCS version %s", kcs_smi_handlers.version);
+	if (smic_smi_handlers.version)
+		printk(", SMIC version %s", smic_smi_handlers.version);
+	if (bt_smi_handlers.version)
+   	        printk(", BT version %s", bt_smi_handlers.version);
+	printk("\n");
+
+	rv = init_one_smi(0, &(smi_infos[pos]));
+	if (rv && !si_ports[0] && si_trydefaults) {
+		/* If we are trying defaults and the initial port is
+                   not set, then set it. */
+		si_type[0] = "kcs";
+		si_ports[0] = DEFAULT_KCS_IO_PORT;
+		rv = init_one_smi(0, &(smi_infos[pos]));
+		if (rv) {
+			/* No KCS - try SMIC */
+			si_type[0] = "smic";
+			si_ports[0] = DEFAULT_SMIC_IO_PORT;
+			rv = init_one_smi(0, &(smi_infos[pos]));
+		}
+		if (rv) {
+			/* No SMIC - try BT */
+			si_type[0] = "bt";
+			si_ports[0] = DEFAULT_BT_IO_PORT;
+			rv = init_one_smi(0, &(smi_infos[pos]));
+		}
+	}
+	if (rv == 0)
+		pos++;
+
+	for (i=1; i < SI_MAX_PARMS; i++) {
+		rv = init_one_smi(i, &(smi_infos[pos]));
+		if (rv == 0)
+			pos++;
+	}
+
+	if (smi_infos[0] == NULL) {
+		printk("ipmi_si: Unable to find any System Interface(s)\n");
+		return -ENODEV;
+	} 
+
+	return 0;
+}
+module_init(init_ipmi_si);
+
+#ifdef MODULE
+void __exit cleanup_one_si(struct smi_info *to_clean)
+{
+	int           rv;
+	unsigned long flags;
+
+	if (! to_clean)
+		return;
+
+	/* Tell the timer and interrupt handlers that we are shutting
+	   down. */
+	spin_lock_irqsave(&(to_clean->si_lock), flags);
+	spin_lock(&(to_clean->msg_lock));
+
+	to_clean->stop_operation = 1;
+
+	to_clean->irq_cleanup(to_clean);
+
+	spin_unlock(&(to_clean->msg_lock));
+	spin_unlock_irqrestore(&(to_clean->si_lock), flags);
+
+	/* Wait for the timer to stop.  This avoids problems with race
+	   conditions removing the timer here.  Hopefully this will be
+	   long enough to avoid problems with interrupts still
+	   running. */
+	set_current_state(TASK_UNINTERRUPTIBLE);
+	schedule_timeout(2);
+	while (!to_clean->timer_stopped) {
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		schedule_timeout(1);
+	}
+
+	/* Interrupts and timeouts are stopped, now make sure the
+	   interface is in a clean state. */
+	while ((to_clean->curr_msg) || (to_clean->si_state != SI_NORMAL)) {
+		poll(to_clean);
+		schedule_timeout(1);
+	}
+
+	rv = ipmi_unregister_smi(to_clean->intf);
+	if (rv) {
+		printk(KERN_ERR 
+		       "ipmi_si: Unable to unregister device: errno=%d\n",
+		       rv);
+	}
+
+	to_clean->handlers->cleanup(to_clean->si_sm);
+
+	kfree(to_clean->si_sm);
+
+	to_clean->io_cleanup(to_clean);
+}
+
+static __exit void cleanup_ipmi_si(void)
+{
+	int i;
+
+	if (!initialized)
+		return;
+
+	for (i=0; i<SI_MAX_DRIVERS; i++) {
+		cleanup_one_si(smi_infos[i]);
+	}
+}
+module_exit(cleanup_ipmi_si);
+#else
+
+/* Unfortunately, cmdline::get_options() only returns integers, not
+   longs.  Since we need ulongs (64-bit physical addresses) parse the 
+   comma-separated list manually.  Arguments can be one of these forms:
+   m0xaabbccddeeff	A physical memory address without an IRQ
+   m0xaabbccddeeff:cc	A physical memory address with an IRQ
+   p0xaabb		An IO port without an IRQ
+   p0xaabb:cc		An IO port with an IRQ
+   nodefaults		Suppress trying the default IO port or ACPI address 
+
+   For example, to pass one IO port with an IRQ, one address, and 
+   suppress the use of the default IO port and ACPI address,
+   use this option string: ipmi_smi=p0xCA2:5,m0xFF5B0022,nodefaults
+
+   Remember, ipmi_si_setup() is passed the string after the equal sign. */
+
+static int __init ipmi_si_setup(char *str)
+{
+	unsigned long val;
+	char *cur, *colon;
+	int pos;
+
+	pos = 0;
+	
+	cur = strsep(&str, ",");
+	while ((cur) && (*cur) && (pos < SI_MAX_PARMS)) {
+		switch (*cur) {
+		case 'n':
+			if (strcmp(cur, "nodefaults") == 0)
+				si_trydefaults = 0;
+			else
+				printk(KERN_INFO 
+				       "ipmi_si: bad parameter value %s\n",
+				       cur);
+			break;
+
+		case 'k': /* KCS */
+			si_type[pos] = "kcs";
+			break;
+		
+		case 's': /* SMIC */
+			si_type[pos] = "smic";
+			break;
+		
+		case 'b': /* BT */
+			si_type[pos] = "bt";
+			break;
+		
+		case 'm':
+		case 'p':
+			val = simple_strtoul(cur + 1,
+					     &colon,
+					     0);
+			if (*cur == 'p')
+				si_ports[pos] = val;
+			else
+				si_addrs[pos] = val;
+			if (*colon == '#') {
+				val = simple_strtoul(colon + 1,
+						     &colon,
+						     0);
+				si_regspacings[pos] = val;
+				if (*colon == '.') {
+					val = simple_strtoul(colon + 1,
+							     &colon,
+							     0);
+					si_regsizes[pos] = val;
+				}
+				if (*colon == '.') {
+					val = simple_strtoul(colon + 1,
+							     &colon,
+							     0);
+					si_regshifts[pos] = val;
+				}
+			}
+			if (*colon == ':') {
+				val = simple_strtoul(colon + 1,
+						     &colon,
+						     0);
+				si_irqs[pos] = val;
+			}
+			pos++;
+			break;
+
+		default:
+			printk(KERN_INFO 
+			       "ipmi_si: bad parameter value %s\n",
+			       cur);
+		}
+		cur = strsep(&str, ",");
+	}
+
+	return 1;
+}
+__setup("ipmi_si=", ipmi_si_setup);
+#endif
+
+MODULE_LICENSE("GPL");
Index: pplinux/linuxnew/drivers/char/ipmi/ipmi_si_sm.h
diff -u /dev/null pplinux/linuxnew/drivers/char/ipmi/ipmi_si_sm.h:1.1
--- /dev/null	Tue May 24 10:37:58 2005
+++ pplinux/linuxnew/drivers/char/ipmi/ipmi_si_sm.h	Tue Feb 15 12:18:46 2005
@@ -0,0 +1,120 @@
+/*
+ * ipmi_si_sm.h
+ *
+ * State machine interface for low-level IPMI system management
+ * interface state machines.  This code is the interface between
+ * the ipmi_smi code (that handles the policy of a KCS, SMIC, or
+ * BT interface) and the actual low-level state machine.
+ *
+ * Author: MontaVista Software, Inc.
+ *         Corey Minyard <minyard@mvista.com>
+ *         source@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.
+ *
+ *
+ *  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.
+ */
+
+/* This is defined by the state machines themselves, it is an opaque
+   data type for them to use. */
+struct si_sm_data;
+
+/* The structure for doing I/O in the state machine.  The state
+   machine doesn't have the actual I/O routines, they are done through
+   this interface. */
+struct si_sm_io
+{
+	unsigned char (*inputb)(struct si_sm_io *io, unsigned int offset);
+	void (*outputb)(struct si_sm_io *io,
+			unsigned int  offset,
+			unsigned char b);
+
+	/* Generic info used by the actual handling routines, the
+           state machine shouldn't touch these. */
+	void *info;
+	void *addr;
+	int  regspacing;
+	int  regsize;
+	int  regshift;
+};
+
+/* Results of SMI events. */
+enum si_sm_result
+{
+	SI_SM_CALL_WITHOUT_DELAY, /* Call the driver again immediately */
+	SI_SM_CALL_WITH_DELAY,	/* Delay some before calling again. */
+	SI_SM_TRANSACTION_COMPLETE, /* A transaction is finished. */
+	SI_SM_IDLE,		/* The SM is in idle state. */
+	SI_SM_HOSED,		/* The hardware violated the state machine. */
+	SI_SM_ATTN		/* The hardware is asserting attn and the
+				   state machine is idle. */
+};
+
+/* Handlers for the SMI state machine. */
+struct si_sm_handlers
+{
+	/* Put the version number of the state machine here so the
+           upper layer can print it. */
+	char *version;
+
+	/* Initialize the data and return the amount of I/O space to
+           reserve for the space. */
+	unsigned int (*init_data)(struct si_sm_data *smi,
+				  struct si_sm_io   *io);
+
+	/* Start a new transaction in the state machine.  This will
+	   return -2 if the state machine is not idle, -1 if the size
+	   is invalid (to large or too small), or 0 if the transaction
+	   is successfully completed. */
+	int (*start_transaction)(struct si_sm_data *smi,
+				 unsigned char *data, unsigned int size);
+
+	/* Return the results after the transaction.  This will return
+	   -1 if the buffer is too small, zero if no transaction is
+	   present, or the actual length of the result data. */
+	int (*get_result)(struct si_sm_data *smi,
+			  unsigned char *data, unsigned int length);
+
+	/* Call this periodically (for a polled interface) or upon
+	   receiving an interrupt (for a interrupt-driven interface).
+	   If interrupt driven, you should probably poll this
+	   periodically when not in idle state.  This should be called
+	   with the time that passed since the last call, if it is
+	   significant.  Time is in microseconds. */
+	enum si_sm_result (*event)(struct si_sm_data *smi, long time);
+
+	/* Attempt to detect an SMI.  Returns 0 on success or nonzero
+           on failure. */
+	int (*detect)(struct si_sm_data *smi);
+
+	/* The interface is shutting down, so clean it up. */
+	void (*cleanup)(struct si_sm_data *smi);
+
+	/* Return the size of the SMI structure in bytes. */
+	int (*size)(void);
+};
+
+/* Current state machines that we can use. */
+extern struct si_sm_handlers kcs_smi_handlers;
+extern struct si_sm_handlers smic_smi_handlers;
+extern struct si_sm_handlers bt_smi_handlers;
+
Index: pplinux/linuxnew/drivers/char/ipmi/ipmi_smic_sm.c
diff -u /dev/null pplinux/linuxnew/drivers/char/ipmi/ipmi_smic_sm.c:1.1
--- /dev/null	Tue May 24 10:37:58 2005
+++ pplinux/linuxnew/drivers/char/ipmi/ipmi_smic_sm.c	Tue Feb 15 12:18:46 2005
@@ -0,0 +1,599 @@
+/*
+ * ipmi_smic_sm.c
+ *
+ * The state-machine driver for an IPMI SMIC driver
+ *
+ * It started as a copy of Corey Minyard's driver for the KSC interface
+ * and the kernel patch "mmcdev-patch-245" by HP
+ *
+ * modified by:	Hannes Schulz <schulz@schwaar.com>
+ *		ipmi@schwaar.com
+ *
+ *
+ * Corey Minyard's driver for the KSC interface has the following
+ * copyright notice:
+ *   Copyright 2002 MontaVista Software Inc.
+ *
+ * the kernel patch "mmcdev-patch-245" by HP has the following
+ * copyright notice:
+ * (c) Copyright 2001 Grant Grundler (c) Copyright
+ * 2001 Hewlett-Packard Company
+ * 
+ *
+ *  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/kernel.h> /* For printk. */
+#include <linux/string.h>
+#include <linux/ipmi_msgdefs.h>		/* for completion codes */
+#include "ipmi_si_sm.h"
+
+#define IPMI_SMIC_VERSION "v33"
+
+/* smic_debug is a bit-field 
+ *	SMIC_DEBUG_ENABLE -	turned on for now 
+ *	SMIC_DEBUG_MSG -	commands and their responses
+ *	SMIC_DEBUG_STATES -	state machine
+*/
+#define SMIC_DEBUG_STATES	4
+#define SMIC_DEBUG_MSG		2
+#define	SMIC_DEBUG_ENABLE	1
+
+static int smic_debug = 1;
+
+enum smic_states {
+	SMIC_IDLE,
+	SMIC_START_OP,
+	SMIC_OP_OK,
+	SMIC_WRITE_START,
+	SMIC_WRITE_NEXT,
+	SMIC_WRITE_END,
+	SMIC_WRITE2READ,
+	SMIC_READ_START,
+	SMIC_READ_NEXT,
+	SMIC_READ_END,
+	SMIC_HOSED
+};
+
+#define MAX_SMIC_READ_SIZE 80
+#define MAX_SMIC_WRITE_SIZE 80
+#define SMIC_MAX_ERROR_RETRIES 3
+
+/* Timeouts in microseconds. */
+#define SMIC_RETRY_TIMEOUT 100000
+
+/* SMIC Flags Register Bits */
+#define SMIC_RX_DATA_READY	0x80
+#define SMIC_TX_DATA_READY	0x40
+#define SMIC_SMI		0x10
+#define SMIC_EVM_DATA_AVAIL	0x08
+#define SMIC_SMS_DATA_AVAIL	0x04
+#define SMIC_FLAG_BSY		0x01
+
+/* SMIC Error Codes */
+#define	EC_NO_ERROR		0x00
+#define	EC_ABORTED		0x01
+#define	EC_ILLEGAL_CONTROL	0x02
+#define	EC_NO_RESPONSE		0x03
+#define	EC_ILLEGAL_COMMAND	0x04
+#define	EC_BUFFER_FULL		0x05
+
+struct si_sm_data
+{
+	enum smic_states state;
+	struct si_sm_io *io;
+        unsigned char	 write_data[MAX_SMIC_WRITE_SIZE];
+        int		 write_pos;
+        int		 write_count;
+        int		 orig_write_count;
+        unsigned char	 read_data[MAX_SMIC_READ_SIZE];
+        int		 read_pos;
+        int		 truncated;
+        unsigned int	 error_retries;
+        long		 smic_timeout;
+};
+
+static unsigned int init_smic_data (struct si_sm_data *smic,
+				    struct si_sm_io *io)
+{
+	smic->state = SMIC_IDLE;
+	smic->io = io;
+	smic->write_pos = 0;
+	smic->write_count = 0;
+	smic->orig_write_count = 0;
+	smic->read_pos = 0;
+	smic->error_retries = 0;
+	smic->truncated = 0;
+	smic->smic_timeout = SMIC_RETRY_TIMEOUT;
+
+	/* We use 3 bytes of I/O. */
+	return 3;
+}
+
+static int start_smic_transaction(struct si_sm_data *smic,
+				  unsigned char *data, unsigned int size)
+{
+	unsigned int i;
+
+	if ((size < 2) || (size > MAX_SMIC_WRITE_SIZE)) {
+		return -1;
+	}
+	if ((smic->state != SMIC_IDLE) && (smic->state != SMIC_HOSED)) {
+		return -2;
+	}
+	if (smic_debug & SMIC_DEBUG_MSG) {
+		printk(KERN_INFO "start_smic_transaction -");
+		for (i = 0; i < size; i ++) {
+			printk (" %02x", (unsigned char) (data [i]));
+		}
+		printk ("\n");
+	}
+	smic->error_retries = 0;
+	memcpy(smic->write_data, data, size);
+	smic->write_count = size;
+	smic->orig_write_count = size;
+	smic->write_pos = 0;
+	smic->read_pos = 0;
+	smic->state = SMIC_START_OP;
+	smic->smic_timeout = SMIC_RETRY_TIMEOUT;
+	return 0;
+}
+
+static int smic_get_result(struct si_sm_data *smic,
+			   unsigned char *data, unsigned int length)
+{
+	int i;
+
+	if (smic_debug & SMIC_DEBUG_MSG) {
+		printk (KERN_INFO "smic_get result -");
+		for (i = 0; i < smic->read_pos; i ++) {
+			printk (" %02x", (smic->read_data [i]));
+		}
+		printk ("\n");
+	}
+	if (length < smic->read_pos) {
+		smic->read_pos = length;
+		smic->truncated = 1;
+	}
+	memcpy(data, smic->read_data, smic->read_pos);
+
+	if ((length >= 3) && (smic->read_pos < 3)) {
+		data[2] = IPMI_ERR_UNSPECIFIED;
+		smic->read_pos = 3;
+	}
+	if (smic->truncated) {
+		data[2] = IPMI_ERR_MSG_TRUNCATED;
+		smic->truncated = 0;
+	}
+	return smic->read_pos;
+}
+
+static inline unsigned char read_smic_flags(struct si_sm_data *smic)
+{
+	return smic->io->inputb(smic->io, 2);
+}
+
+static inline unsigned char read_smic_status(struct si_sm_data *smic)
+{
+	return smic->io->inputb(smic->io, 1);
+}
+
+static inline unsigned char read_smic_data(struct si_sm_data *smic)
+{
+	return smic->io->inputb(smic->io, 0);
+}
+
+static inline void write_smic_flags(struct si_sm_data *smic,
+				    unsigned char   flags)
+{
+	smic->io->outputb(smic->io, 2, flags);
+}
+
+static inline void write_smic_control(struct si_sm_data *smic,
+				      unsigned char   control)
+{
+	smic->io->outputb(smic->io, 1, control);
+}
+
+static inline void write_si_sm_data (struct si_sm_data *smic,
+				   unsigned char   data)
+{
+	smic->io->outputb(smic->io, 0, data);
+}
+
+static inline void start_error_recovery(struct si_sm_data *smic, char *reason)
+{
+	(smic->error_retries)++;
+	if (smic->error_retries > SMIC_MAX_ERROR_RETRIES) {
+		if (smic_debug & SMIC_DEBUG_ENABLE) {
+			printk(KERN_WARNING
+			       "ipmi_smic_drv: smic hosed: %s\n", reason);
+		}	
+		smic->state = SMIC_HOSED;
+	} else {
+		smic->write_count = smic->orig_write_count;
+		smic->write_pos = 0;
+		smic->read_pos = 0;
+		smic->state = SMIC_START_OP;
+		smic->smic_timeout = SMIC_RETRY_TIMEOUT;
+	}
+}
+
+static inline void write_next_byte(struct si_sm_data *smic)
+{
+	write_si_sm_data(smic, smic->write_data[smic->write_pos]);
+	(smic->write_pos)++;
+	(smic->write_count)--;
+}
+
+static inline void read_next_byte (struct si_sm_data *smic)
+{
+	if (smic->read_pos >= MAX_SMIC_READ_SIZE) {
+		read_smic_data (smic);
+		smic->truncated = 1;
+	} else {
+		smic->read_data[smic->read_pos] = read_smic_data(smic);	
+		(smic->read_pos)++;
+	}
+}
+
+/*  SMIC Control/Status Code Components */
+#define	SMIC_GET_STATUS		0x00	/* Control form's name */
+#define	SMIC_READY		0x00	/* Status  form's name */
+#define	SMIC_WR_START		0x01	/* Unified Control/Status names... */
+#define	SMIC_WR_NEXT		0x02
+#define	SMIC_WR_END		0x03
+#define	SMIC_RD_START		0x04
+#define	SMIC_RD_NEXT		0x05
+#define	SMIC_RD_END		0x06
+#define	SMIC_CODE_MASK		0x0f
+
+#define	SMIC_CONTROL		0x00
+#define	SMIC_STATUS		0x80
+#define	SMIC_CS_MASK		0x80
+
+#define	SMIC_SMS		0x40
+#define	SMIC_SMM		0x60
+#define	SMIC_STREAM_MASK	0x60
+
+/*  SMIC Control Codes */
+#define	SMIC_CC_SMS_GET_STATUS	(SMIC_CONTROL|SMIC_SMS|SMIC_GET_STATUS)
+#define	SMIC_CC_SMS_WR_START	(SMIC_CONTROL|SMIC_SMS|SMIC_WR_START)
+#define	SMIC_CC_SMS_WR_NEXT	(SMIC_CONTROL|SMIC_SMS|SMIC_WR_NEXT)
+#define	SMIC_CC_SMS_WR_END	(SMIC_CONTROL|SMIC_SMS|SMIC_WR_END)
+#define	SMIC_CC_SMS_RD_START	(SMIC_CONTROL|SMIC_SMS|SMIC_RD_START)
+#define	SMIC_CC_SMS_RD_NEXT	(SMIC_CONTROL|SMIC_SMS|SMIC_RD_NEXT)
+#define	SMIC_CC_SMS_RD_END	(SMIC_CONTROL|SMIC_SMS|SMIC_RD_END)
+
+#define	SMIC_CC_SMM_GET_STATUS	(SMIC_CONTROL|SMIC_SMM|SMIC_GET_STATUS)
+#define	SMIC_CC_SMM_WR_START	(SMIC_CONTROL|SMIC_SMM|SMIC_WR_START)
+#define	SMIC_CC_SMM_WR_NEXT	(SMIC_CONTROL|SMIC_SMM|SMIC_WR_NEXT)
+#define	SMIC_CC_SMM_WR_END	(SMIC_CONTROL|SMIC_SMM|SMIC_WR_END)
+#define	SMIC_CC_SMM_RD_START	(SMIC_CONTROL|SMIC_SMM|SMIC_RD_START)
+#define	SMIC_CC_SMM_RD_NEXT	(SMIC_CONTROL|SMIC_SMM|SMIC_RD_NEXT)
+#define	SMIC_CC_SMM_RD_END	(SMIC_CONTROL|SMIC_SMM|SMIC_RD_END)
+
+/*  SMIC Status Codes */
+#define	SMIC_SC_SMS_READY	(SMIC_STATUS|SMIC_SMS|SMIC_READY)
+#define	SMIC_SC_SMS_WR_START	(SMIC_STATUS|SMIC_SMS|SMIC_WR_START)
+#define	SMIC_SC_SMS_WR_NEXT	(SMIC_STATUS|SMIC_SMS|SMIC_WR_NEXT)
+#define	SMIC_SC_SMS_WR_END	(SMIC_STATUS|SMIC_SMS|SMIC_WR_END)
+#define	SMIC_SC_SMS_RD_START	(SMIC_STATUS|SMIC_SMS|SMIC_RD_START)
+#define	SMIC_SC_SMS_RD_NEXT	(SMIC_STATUS|SMIC_SMS|SMIC_RD_NEXT)
+#define	SMIC_SC_SMS_RD_END	(SMIC_STATUS|SMIC_SMS|SMIC_RD_END)
+
+#define	SMIC_SC_SMM_READY	(SMIC_STATUS|SMIC_SMM|SMIC_READY)
+#define	SMIC_SC_SMM_WR_START	(SMIC_STATUS|SMIC_SMM|SMIC_WR_START)
+#define	SMIC_SC_SMM_WR_NEXT	(SMIC_STATUS|SMIC_SMM|SMIC_WR_NEXT)
+#define	SMIC_SC_SMM_WR_END	(SMIC_STATUS|SMIC_SMM|SMIC_WR_END)
+#define	SMIC_SC_SMM_RD_START	(SMIC_STATUS|SMIC_SMM|SMIC_RD_START)
+#define	SMIC_SC_SMM_RD_NEXT	(SMIC_STATUS|SMIC_SMM|SMIC_RD_NEXT)
+#define	SMIC_SC_SMM_RD_END	(SMIC_STATUS|SMIC_SMM|SMIC_RD_END)
+
+/* these are the control/status codes we actually use
+	SMIC_CC_SMS_GET_STATUS	0x40
+	SMIC_CC_SMS_WR_START	0x41
+	SMIC_CC_SMS_WR_NEXT	0x42
+	SMIC_CC_SMS_WR_END	0x43
+	SMIC_CC_SMS_RD_START	0x44
+	SMIC_CC_SMS_RD_NEXT	0x45
+	SMIC_CC_SMS_RD_END	0x46
+
+	SMIC_SC_SMS_READY	0xC0
+	SMIC_SC_SMS_WR_START	0xC1
+	SMIC_SC_SMS_WR_NEXT	0xC2
+	SMIC_SC_SMS_WR_END	0xC3
+	SMIC_SC_SMS_RD_START	0xC4
+	SMIC_SC_SMS_RD_NEXT	0xC5
+	SMIC_SC_SMS_RD_END	0xC6
+*/
+
+static enum si_sm_result smic_event (struct si_sm_data *smic, long time)
+{
+	unsigned char status;
+	unsigned char flags;
+	unsigned char data;
+
+	if (smic->state == SMIC_HOSED) {
+		init_smic_data(smic, smic->io);
+		return SI_SM_HOSED;
+	}
+	if (smic->state != SMIC_IDLE) {
+		if (smic_debug & SMIC_DEBUG_STATES) {
+			printk(KERN_INFO
+			       "smic_event - smic->smic_timeout = %ld,"
+			       " time = %ld\n",
+			       smic->smic_timeout, time);
+		}
+/* FIXME: smic_event is sometimes called with time > SMIC_RETRY_TIMEOUT */
+		if (time < SMIC_RETRY_TIMEOUT) {
+			smic->smic_timeout -= time;
+			if (smic->smic_timeout < 0) {
+				start_error_recovery(smic, "smic timed out.");
+				return SI_SM_CALL_WITH_DELAY;
+			}
+		}
+	}
+	flags = read_smic_flags(smic);
+	if (flags & SMIC_FLAG_BSY)
+		return SI_SM_CALL_WITH_DELAY;
+
+	status = read_smic_status (smic);
+	if (smic_debug & SMIC_DEBUG_STATES)
+		printk(KERN_INFO
+		       "smic_event - state = %d, flags = 0x%02x,"
+		       " status = 0x%02x\n",
+		       smic->state, flags, status);
+
+	switch (smic->state) {
+	case SMIC_IDLE:
+		/* in IDLE we check for available messages */
+		if (flags & (SMIC_SMI |
+			     SMIC_EVM_DATA_AVAIL | SMIC_SMS_DATA_AVAIL))
+		{
+			return SI_SM_ATTN;
+		}
+		return SI_SM_IDLE;
+
+	case SMIC_START_OP:
+		/* sanity check whether smic is really idle */
+		write_smic_control(smic, SMIC_CC_SMS_GET_STATUS);
+		write_smic_flags(smic, flags | SMIC_FLAG_BSY);
+		smic->state = SMIC_OP_OK;
+		break;
+
+	case SMIC_OP_OK:
+		if (status != SMIC_SC_SMS_READY) {
+				/* this should not happen */
+			start_error_recovery(smic,
+					     "state = SMIC_OP_OK,"
+					     " status != SMIC_SC_SMS_READY");
+			return SI_SM_CALL_WITH_DELAY;
+		}
+		/* OK so far; smic is idle let us start ... */
+		write_smic_control(smic, SMIC_CC_SMS_WR_START);
+		write_next_byte(smic);
+		write_smic_flags(smic, flags | SMIC_FLAG_BSY);
+		smic->state = SMIC_WRITE_START;
+		break;
+
+	case SMIC_WRITE_START:
+		if (status != SMIC_SC_SMS_WR_START) {
+			start_error_recovery(smic,
+					     "state = SMIC_WRITE_START, "
+					     "status != SMIC_SC_SMS_WR_START");
+			return SI_SM_CALL_WITH_DELAY;
+		}
+		/* we must not issue WR_(NEXT|END) unless
+                   TX_DATA_READY is set */
+		if (flags & SMIC_TX_DATA_READY) {
+			if (smic->write_count == 1) {
+				/* last byte */
+				write_smic_control(smic, SMIC_CC_SMS_WR_END);
+				smic->state = SMIC_WRITE_END;
+			} else {
+				write_smic_control(smic, SMIC_CC_SMS_WR_NEXT);
+				smic->state = SMIC_WRITE_NEXT;
+			}
+			write_next_byte(smic);
+			write_smic_flags(smic, flags | SMIC_FLAG_BSY);
+		}
+		else {
+			return SI_SM_CALL_WITH_DELAY;
+		}
+		break;
+
+	case SMIC_WRITE_NEXT:
+		if (status != SMIC_SC_SMS_WR_NEXT) {
+			start_error_recovery(smic,
+					     "state = SMIC_WRITE_NEXT, "
+					     "status != SMIC_SC_SMS_WR_NEXT");
+			return SI_SM_CALL_WITH_DELAY;
+		}
+		/* this is the same code as in SMIC_WRITE_START */
+		if (flags & SMIC_TX_DATA_READY) {
+			if (smic->write_count == 1) {
+				write_smic_control(smic, SMIC_CC_SMS_WR_END);
+				smic->state = SMIC_WRITE_END;
+			}
+			else {
+				write_smic_control(smic, SMIC_CC_SMS_WR_NEXT);
+				smic->state = SMIC_WRITE_NEXT;
+			}
+			write_next_byte(smic);
+			write_smic_flags(smic, flags | SMIC_FLAG_BSY);
+		}
+		else {
+			return SI_SM_CALL_WITH_DELAY;
+		}
+		break;
+
+	case SMIC_WRITE_END:
+		if (status != SMIC_SC_SMS_WR_END) {
+			start_error_recovery (smic,
+					      "state = SMIC_WRITE_END, "
+					      "status != SMIC_SC_SMS_WR_END");
+			return SI_SM_CALL_WITH_DELAY;
+		}
+		/* data register holds an error code */
+		data = read_smic_data(smic);
+		if (data != 0) {
+			if (smic_debug & SMIC_DEBUG_ENABLE) {
+				printk(KERN_INFO
+				       "SMIC_WRITE_END: data = %02x\n", data);
+			}
+			start_error_recovery(smic,
+					     "state = SMIC_WRITE_END, "
+					     "data != SUCCESS");
+			return SI_SM_CALL_WITH_DELAY;
+		} else {
+			smic->state = SMIC_WRITE2READ;
+		}
+		break;
+
+	case SMIC_WRITE2READ:
+		/* we must wait for RX_DATA_READY to be set before we
+                   can continue */
+		if (flags & SMIC_RX_DATA_READY) {
+			write_smic_control(smic, SMIC_CC_SMS_RD_START);
+			write_smic_flags(smic, flags | SMIC_FLAG_BSY);
+			smic->state = SMIC_READ_START;
+		} else {
+			return SI_SM_CALL_WITH_DELAY;
+		}
+		break;
+
+	case SMIC_READ_START:
+		if (status != SMIC_SC_SMS_RD_START) {
+			start_error_recovery(smic,
+					     "state = SMIC_READ_START, "
+					     "status != SMIC_SC_SMS_RD_START");
+			return SI_SM_CALL_WITH_DELAY;
+		}
+		if (flags & SMIC_RX_DATA_READY) {
+			read_next_byte(smic);
+			write_smic_control(smic, SMIC_CC_SMS_RD_NEXT);
+			write_smic_flags(smic, flags | SMIC_FLAG_BSY);
+			smic->state = SMIC_READ_NEXT;
+		} else {
+			return SI_SM_CALL_WITH_DELAY;
+		}
+		break;
+
+	case SMIC_READ_NEXT:
+		switch (status) {
+		/* smic tells us that this is the last byte to be read
+                   --> clean up */
+		case SMIC_SC_SMS_RD_END:
+			read_next_byte(smic);
+			write_smic_control(smic, SMIC_CC_SMS_RD_END);
+			write_smic_flags(smic, flags | SMIC_FLAG_BSY);
+			smic->state = SMIC_READ_END;
+			break;
+		case SMIC_SC_SMS_RD_NEXT:
+			if (flags & SMIC_RX_DATA_READY) {
+				read_next_byte(smic);
+				write_smic_control(smic, SMIC_CC_SMS_RD_NEXT);
+				write_smic_flags(smic, flags | SMIC_FLAG_BSY);
+				smic->state = SMIC_READ_NEXT;
+			} else {
+				return SI_SM_CALL_WITH_DELAY;
+			}
+			break;
+		default:
+			start_error_recovery(
+				smic,
+				"state = SMIC_READ_NEXT, "
+				"status != SMIC_SC_SMS_RD_(NEXT|END)");
+			return SI_SM_CALL_WITH_DELAY;
+		}
+		break;
+
+	case SMIC_READ_END:
+		if (status != SMIC_SC_SMS_READY) {
+			start_error_recovery(smic,
+					     "state = SMIC_READ_END, "
+					     "status != SMIC_SC_SMS_READY");
+			return SI_SM_CALL_WITH_DELAY;
+		}
+		data = read_smic_data(smic);
+		/* data register holds an error code */
+		if (data != 0) {
+			if (smic_debug & SMIC_DEBUG_ENABLE) {
+				printk(KERN_INFO
+				       "SMIC_READ_END: data = %02x\n", data);
+			}
+			start_error_recovery(smic,
+					     "state = SMIC_READ_END, "
+					     "data != SUCCESS");
+			return SI_SM_CALL_WITH_DELAY;
+		} else {
+			smic->state = SMIC_IDLE;
+			return SI_SM_TRANSACTION_COMPLETE;
+		}
+
+	case SMIC_HOSED:
+		init_smic_data(smic, smic->io);
+		return SI_SM_HOSED;
+
+	default:
+		if (smic_debug & SMIC_DEBUG_ENABLE) {
+			printk(KERN_WARNING "smic->state = %d\n", smic->state);
+			start_error_recovery(smic, "state = UNKNOWN");
+			return SI_SM_CALL_WITH_DELAY;
+		}
+	}
+	smic->smic_timeout = SMIC_RETRY_TIMEOUT;
+	return SI_SM_CALL_WITHOUT_DELAY;
+}
+
+static int smic_detect(struct si_sm_data *smic)
+{
+	/* It's impossible for the SMIC fnags register to be all 1's,
+	   (assuming a properly functioning, self-initialized BMC)
+	   but that's what you get from reading a bogus address, so we
+	   test that first. */
+	if (read_smic_flags(smic) == 0xff)
+		return 1; 
+
+	return 0;
+}
+
+static void smic_cleanup(struct si_sm_data *kcs)
+{
+}
+
+static int smic_size(void)
+{
+	return sizeof(struct si_sm_data);
+}
+
+struct si_sm_handlers smic_smi_handlers =
+{
+	.version           = IPMI_SMIC_VERSION,
+	.init_data         = init_smic_data,
+	.start_transaction = start_smic_transaction,
+	.get_result        = smic_get_result,
+	.event             = smic_event,
+	.detect            = smic_detect,
+	.cleanup           = smic_cleanup,
+	.size              = smic_size,
+};
Index: pplinux/linuxnew/drivers/hotplug/Config.in
diff -u pplinux/linuxnew/drivers/hotplug/Config.in:1.1.323.1 pplinux/linuxnew/drivers/hotplug/Config.in:1.2
--- pplinux/linuxnew/drivers/hotplug/Config.in:1.1.323.1	Thu Feb  3 10:00:44 2005
+++ pplinux/linuxnew/drivers/hotplug/Config.in	Fri Apr 29 10:43:28 2005
@@ -6,6 +6,7 @@
 
 dep_tristate 'Support for PCI Hotplug (EXPERIMENTAL)' CONFIG_HOTPLUG_PCI $CONFIG_EXPERIMENTAL $CONFIG_PCI
 
+dep_tristate "  Dummy PCI Hotplug driver" CONFIG_HOTPLUG_PCI_DUMMY $CONFIG_HOTPLUG_PCI
 dep_tristate '  Compaq PCI Hotplug driver' CONFIG_HOTPLUG_PCI_COMPAQ $CONFIG_HOTPLUG_PCI $CONFIG_X86
 dep_mbool '    Save configuration into NVRAM on Compaq servers' CONFIG_HOTPLUG_PCI_COMPAQ_NVRAM $CONFIG_HOTPLUG_PCI_COMPAQ
 if [ "$CONFIG_X86_IO_APIC" = "y" ]; then
Index: pplinux/linuxnew/drivers/hotplug/Makefile
diff -u pplinux/linuxnew/drivers/hotplug/Makefile:1.1.323.1 pplinux/linuxnew/drivers/hotplug/Makefile:1.2
--- pplinux/linuxnew/drivers/hotplug/Makefile:1.1.323.1	Thu Feb  3 10:00:44 2005
+++ pplinux/linuxnew/drivers/hotplug/Makefile	Fri Apr 29 10:43:28 2005
@@ -4,11 +4,12 @@
 
 O_TARGET	:= vmlinux-obj.o
 
-list-multi	:= cpqphp.o pci_hotplug.o ibmphp.o acpiphp.o 
+list-multi	:= cpqphp.o pci_hotplug.o ibmphp.o acpiphp.o dummyphp.o
 
 export-objs	:= pci_hotplug_core.o pci_hotplug_util.o
 
 obj-$(CONFIG_HOTPLUG_PCI)		+= pci_hotplug.o
+obj-$(CONFIG_HOTPLUG_PCI_DUMMY)		+= dummyphp.o
 obj-$(CONFIG_HOTPLUG_PCI_COMPAQ)	+= cpqphp.o
 obj-$(CONFIG_HOTPLUG_PCI_IBM)		+= ibmphp.o
 obj-$(CONFIG_HOTPLUG_PCI_ACPI)		+= acpiphp.o
@@ -32,6 +33,8 @@
 				acpiphp_pci.o	\
 				acpiphp_res.o
 
+dummyphp_objs		:=	dummyphp_core.o
+
 ifeq ($(CONFIG_HOTPLUG_PCI_COMPAQ_NVRAM),y)
 	cpqphp-objs += cpqphp_nvram.o
 endif
@@ -50,3 +53,6 @@
 
 acpiphp.o: $(acpiphp_objs)
 	$(LD) -r -o $@ $(acpiphp_objs)
+
+dummyphp.o: $(dummyphp_objs)
+	$(LD) -r -o $@ $(dummyphp_objs)
Index: pplinux/linuxnew/drivers/hotplug/dummyphp_core.c
diff -u /dev/null pplinux/linuxnew/drivers/hotplug/dummyphp_core.c:1.1
--- /dev/null	Tue May 24 10:37:58 2005
+++ pplinux/linuxnew/drivers/hotplug/dummyphp_core.c	Fri Apr 29 10:43:28 2005
@@ -0,0 +1,438 @@
+/*
+ * Dummy PCI Hot Plug Controller Driver
+ *
+ * Copyright (c) 2003 Rolf Eike Beer <eike-kernel@sf...>
+ *
+ * Based on code from:
+ *	Vladimir Kondratiev <vladimir.kondratiev@in...>
+ *	Greg Kroah-Hartman <greg@kr...>
+ *
+ * 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, version 2 of the License.
+ *
+ * Send feedback to <eike-kernel@sf...>
+ */
+
+/*
+ *
+ * This driver will "emulate" removing PCI devices from the system.  If
+ * the "power" file is written to with "0" then the specified PCI device
+ * will be completely removed from the kernel.
+ *
+ * WARNING, this does NOT turn off the power to the PCI device.  This is
+ * a "logical" removal, not a physical or electrical removal.
+ *
+ * Use this module at your own risk, you have been warned!
+ *
+ */
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include "pci_hotplug.h"
+
+#define dbg(format, arg...)					\
+	do {							\
+	    if (debug)						\
+			printk(KERN_DEBUG "%s: " format,	\
+				MY_NAME , ## arg); 		\
+	} while (0)
+#define err(format, arg...) printk(KERN_ERR "%s: " format, MY_NAME , ## arg)
+#define info(format, arg...) printk(KERN_INFO "%s: " format, MY_NAME , ## arg)
+
+/* name size which is used for entries in pcihpfs */
+#define SLOT_NAME_SIZE	16		/* DUMMY-{BUS}:{DEV} */
+
+struct dummy_slot {
+	struct list_head node;
+	struct pci_bus	*bus;
+	int		devfn;
+	struct pci_dev	*dev;
+	struct hotplug_slot *slot;
+};
+
+#ifndef CONFIG_HOTPLUG_PCI_DUMMY_MODULE
+	#define MY_NAME	"dummyphp"
+#else
+	#define MY_NAME	THIS_MODULE->name
+#endif
+
+static int debug;
+static LIST_HEAD(slot_list);
+
+#define DRIVER_VERSION	"0.1"
+#define DRIVER_AUTHOR	"Rolf Eike Beer <eike-kernel@sf...>"
+#define DRIVER_DESC	"Dummy Hot Plug PCI Controller Driver"
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
+MODULE_PARM(debug, "i");
+MODULE_PARM_DESC(debug, "Debugging mode enabled or not");
+
+static int enable_slot (struct hotplug_slot *slot);
+static int disable_slot (struct hotplug_slot *slot);
+static int configure_device(struct pci_bus* bus, struct pci_dev* dev);
+
+static struct hotplug_slot_ops dummy_hotplug_slot_ops = {
+	.owner			= THIS_MODULE,
+	.enable_slot		= enable_slot,
+	.disable_slot		= disable_slot,
+};
+
+static int
+configure_device(struct pci_bus* bus, struct pci_dev* dev)
+{
+    u8 irq_pin;
+    int r;
+
+    dbg("%s - enter\n", __FUNCTION__);
+
+    /* Assign resources */
+    dbg("assigning resources for %02x:%02x.%x\n",
+	dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn));
+    for (r = 0; r < 6; r++) {
+	struct resource *res = dev->resource + r;
+	if(res->flags)
+	    pci_assign_resource(dev, r);
+    }
+    dbg("finished assigning resources for %02x:%02x.%x\n",
+	dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn));
+    
+    /* Does this function have an interrupt at all? */
+    dbg("checking for function interrupt\n");
+    pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &irq_pin);
+    if(irq_pin) {
+	dbg("function uses interrupt pin %d\n", irq_pin);
+    }
+    
+    /*
+     * Need to explicitly set irq field to 0 so that it'll get assigned
+     * by the pcibios platform dependent code called by pci_enable_device.
+     */
+    dev->irq = 0;
+    
+    dbg("enabling device\n");
+    pci_enable_device(dev);	/* XXX check return */
+    dbg("now dev->irq = %d\n", dev->irq);
+    if(irq_pin && dev->irq) {
+	pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq);
+    }
+    
+    /* Can't use pci_insert_device at the moment, do it manually for now */
+    pci_proc_attach_device(dev);
+    dbg("notifying drivers\n");
+    pci_announce_device_to_drivers(dev);
+    dbg("%s - exit\n", __FUNCTION__);
+    return 0;       
+}
+
+/**
+ * configure_visit_pci_dev - callback to configure new discovered devices
+ * @wrapped_dev: the device
+ * @wrapped_bus: the bus of the device
+ */
+static int configure_visit_pci_dev (struct pci_dev_wrapped *wrapped_dev,
+				    struct pci_bus_wrapped *wrapped_bus)
+{
+	struct pci_dev* dev = wrapped_dev->dev;
+	struct pci_bus *bus = wrapped_bus->bus;
+	int ret = -1;	
+	
+	/* Create /proc/bus/pci proc entry for this device and bus device is on
+	   Notify the drivers of the change */
+	dbg("%s - starting\n", __FUNCTION__);
+	if (dev) {
+	    ret = configure_device(bus, dev);
+	    if (ret) goto bail;    
+	}
+
+	ret = 0;
+ bail:
+	return ret;
+}
+
+static struct pci_visit configure_functions = {
+	visit_pci_dev:		configure_visit_pci_dev,
+};
+
+/**
+ * enable_slot - power on and enable a slot
+ * @hotplug_slot: slot to enable
+ */
+static int
+enable_slot(struct hotplug_slot *hotplug_slot)
+{
+	struct pci_dev dev0;
+	struct dummy_slot *slot;
+	struct pci_bus *child;
+	unsigned char bus;
+	struct pci_dev_wrapped wrapped_dev;
+	struct pci_bus_wrapped wrapped_bus;
+	int rc = 0;
+
+	if (!hotplug_slot)
+		return -ENODEV;
+
+	dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
+
+	/* enable the specified slot */
+	slot = (struct dummy_slot *) hotplug_slot->private;
+	slot->dev = pci_find_slot(slot->bus->number, slot->devfn);
+
+	/* Still NULL ? Well then scan for it ! */
+	if (slot->dev == NULL) {
+		dbg("INFO: pci_dev still null\n");
+		memset(&dev0, 0, sizeof(struct pci_dev));
+		dev0.bus = slot->bus;
+		dev0.devfn = slot->devfn;
+		dev0.sysdata = slot->bus->sysdata;
+
+		/* this will generate pci_dev structures for all functions,
+		   but we will only call this case when lookup fails */
+		slot->dev = pci_scan_slot(&dev0);
+		if (slot->dev == NULL) {
+			dbg("ERROR: pci_dev still null\n");
+			return -ENODEV;
+		}
+	}
+
+	if (slot->dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) {
+		pci_read_config_byte(slot->dev, PCI_SECONDARY_BUS, &bus);
+		child = (struct pci_bus*) pci_add_new_bus(slot->dev->bus,
+						(slot->dev), bus);
+		pci_do_scan_bus(child);
+
+	}
+
+	if (slot->dev) {
+		memset(&wrapped_dev, 0, sizeof(struct pci_dev_wrapped));
+		memset(&wrapped_bus, 0, sizeof(struct pci_bus_wrapped));
+		wrapped_dev.dev = slot->dev;
+		wrapped_bus.bus = slot->dev->bus;
+		rc = pci_visit_dev(&configure_functions, &wrapped_dev,
+				   &wrapped_bus);
+	}
+	return rc;
+}
+
+/**
+ * is_pci_dev_in_use - check if a driver uses a pci device
+ * @dev: the device to check
+ */
+static int
+is_pci_dev_in_use(struct pci_dev* dev) 
+{
+	/* 
+	 * dev->driver will be set if the device is in use by a new-style 
+	 * driver -- otherwise, check the device"s regions to see if any
+	 * driver has claimed them
+	 */
+
+	int i, inuse = 0;
+
+	if (dev->driver)
+		return 1; /* assume driver feels responsible */
+
+	for (i = 0; !dev->driver && !inuse && (i < 6); i++) {
+		if (!pci_resource_start(dev, i))
+			continue;
+
+		if (pci_resource_flags(dev, i) & IORESOURCE_IO)
+			inuse = check_region(pci_resource_start(dev, i),
+					     pci_resource_len(dev, i));
+		else if (pci_resource_flags(dev, i) & IORESOURCE_MEM)
+			inuse = check_mem_region(pci_resource_start(dev, i),
+						 pci_resource_len(dev, i));
+	}
+
+	return inuse;
+
+}
+
+/**
+ * disable_slot - disable any adapter in this slot
+ * @hotplug_slot: slot to disable
+ */
+static int
+disable_slot(struct hotplug_slot *hotplug_slot)
+{
+	struct pci_dev* old_dev;
+	int func;
+	struct dummy_slot *slot;
+
+	if (!hotplug_slot)
+		return -ENODEV;
+
+	slot = (struct dummy_slot *) hotplug_slot->private;
+
+	dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
+
+	if (slot->dev == NULL) {
+	    dbg("%s - no device here yet\n", __FUNCTION__);
+	    return -ENODEV;
+	}
+	
+	/* assume the driver feels responsible if dev->driver is set */
+	if (is_pci_dev_in_use(slot->dev)) {
+		if (slot->dev->driver) {
+			err("Can't disable slot %x:%x, driver %s still holds reference to it!",
+				slot->bus->number, PCI_SLOT(slot->devfn),
+				slot->dev->driver->name);
+		} else {
+			err("Can't disable slot %x:%x, a driver still holds reference to it!",
+				slot->bus->number, PCI_SLOT(slot->devfn));
+		}
+		return -EBUSY;
+	}
+
+	/* disable the specified slot */
+
+	for (func = 0; func < 8; func++) {
+		old_dev = pci_find_slot(slot->bus->number, slot->devfn+func);
+		if (old_dev) {
+			printk(KERN_INFO "Slot %s Removed <%s>\n",
+					old_dev->slot_name, old_dev->name);
+			pci_remove_device(old_dev);
+		}
+	}
+	hotplug_slot->info->power_status = 0;
+	slot->dev = NULL;
+
+	return 0;
+}
+
+/**
+ * scan_pci_bus - add an entry for every slot on this bus
+ * @bus: bus to scan
+ */
+static int __init
+scan_pci_bus(const struct pci_bus *bus)
+{
+	struct dummy_slot *dslot;
+	struct hotplug_slot *hp;
+	int retval = -ENOMEM;
+	unsigned int devfn;
+	struct pci_dev dev0;
+
+	dbg("%s scanning\n", __FUNCTION__);
+	memset(&dev0, 0, sizeof(dev0));
+	dev0.bus = (struct pci_bus*)bus;
+	dev0.sysdata = bus->sysdata;
+	for (devfn = 0; devfn < 0x100; devfn += 8) {
+		hp = kmalloc(sizeof(struct hotplug_slot), GFP_KERNEL);
+		if (!hp)
+			goto error;
+
+		memset(hp, 0, sizeof(struct hotplug_slot));
+
+		hp->info = kmalloc(sizeof(struct hotplug_slot_info),
+					GFP_KERNEL);
+		if (!hp->info)
+			goto error_info;
+
+		memset(hp->info, 0, sizeof(struct hotplug_slot_info));
+
+		hp->name = kmalloc(SLOT_NAME_SIZE, GFP_KERNEL);
+		if ( !hp->name )
+			goto error_name;
+
+		dslot = kmalloc(sizeof(struct dummy_slot), GFP_KERNEL);
+		if ( !dslot )
+			goto error_slot;
+
+		dslot->bus = (struct pci_bus *) bus;
+		dslot->devfn = devfn;
+		dslot->slot = hp;
+
+		hp->ops = &dummy_hotplug_slot_ops;
+		hp->private = (void *) dslot;
+
+		dslot->dev = pci_find_slot(dslot->bus->number, dslot->devfn);
+		hp->info->power_status = (dslot->dev != NULL);
+
+		hp->info->cur_bus_speed = PCI_SPEED_UNKNOWN;
+		hp->info->max_bus_speed = PCI_SPEED_UNKNOWN;
+
+		snprintf(hp->name, SLOT_NAME_SIZE, "DUMMY-%02x:%02x",
+			dslot->bus->number, PCI_SLOT(dslot->devfn));
+	        dbg("Registering %s\n", hp->name);
+
+		retval = pci_hp_register(hp);
+		if (retval) {
+			err("pci_hp_register failed with error %d\n", retval);
+			goto error_register;
+		}
+		list_add(&dslot->node, &slot_list);
+	}
+	return 0;
+
+error_register:
+	kfree(dslot);
+error_slot:
+	kfree(hp->name);
+error_name:
+	kfree(hp->info);
+error_info:
+	kfree(hp);
+error:
+	return retval;
+}
+
+/**
+ * scan_pci_buses - scan this bus and all child buses for slots
+ * @list: list of buses to scan
+ */
+static int __init
+pci_scan_buses(const struct list_head *list)
+{
+	int retval;
+	const struct list_head *l;
+
+	list_for_each(l,list) {
+	        const struct pci_bus *b = pci_bus_b(l);
+		retval = scan_pci_bus(b);
+		if (retval)
+			return retval;
+		retval = pci_scan_buses(&b->children);
+		if (retval)
+			return retval;
+	}
+	return 0;
+}
+
+static void __exit
+cleanup_slots (void)
+{
+	struct list_head *tmp;
+	struct list_head *next;
+	struct dummy_slot *dslot;
+
+	list_for_each_safe (tmp, next, &slot_list) {
+		dslot = list_entry (tmp, struct dummy_slot, node);
+		pci_hp_deregister(dslot->slot);
+	}
+}
+
+
+static int __init
+dummyphp_init(void)
+{
+	info(DRIVER_DESC " version: " DRIVER_VERSION "\n");
+
+	return pci_scan_buses(&pci_root_buses);
+}
+
+
+static void __exit
+dummyphp_exit(void)
+{
+	cleanup_slots();
+}
+
+module_init(dummyphp_init);
+module_exit(dummyphp_exit);
Index: pplinux/linuxnew/drivers/i2c/Config.in
diff -u pplinux/linuxnew/drivers/i2c/Config.in:1.1.323.1 pplinux/linuxnew/drivers/i2c/Config.in:1.3
--- pplinux/linuxnew/drivers/i2c/Config.in:1.1.323.1	Thu Feb  3 10:00:38 2005
+++ pplinux/linuxnew/drivers/i2c/Config.in	Tue Feb 15 12:19:53 2005
@@ -7,6 +7,8 @@
 tristate 'I2C support' CONFIG_I2C
 
 if [ "$CONFIG_I2C" != "n" ]; then
+   dep_tristate 'I2C Slave Mode implementation' CONFIG_I2C_SLAVE $CONFIG_I2C
+
    dep_tristate 'I2C bit-banging interfaces'  CONFIG_I2C_ALGOBIT $CONFIG_I2C
    if [ "$CONFIG_I2C_ALGOBIT" != "n" ]; then
       dep_tristate '  Philips style parallel port adapter' CONFIG_I2C_PHILIPSPAR $CONFIG_I2C_ALGOBIT $CONFIG_PARPORT
@@ -38,14 +40,8 @@
          dep_tristate '  Embedded Planet RPX Lite/Classic support' CONFIG_I2C_RPXLITE $CONFIG_I2C_ALGO8XX
       fi
    fi
-   if [ "$CONFIG_405" = "y" ]; then
-      dep_tristate 'PPC 405 I2C Algorithm' CONFIG_I2C_PPC405_ALGO $CONFIG_I2C
-      if [ "$CONFIG_I2C_PPC405_ALGO" != "n" ]; then
-         dep_tristate '  PPC 405 I2C Adapter' CONFIG_I2C_PPC405_ADAP $CONFIG_I2C_PPC405_ALGO
-      fi
-      if [ "$CONFIG_XILINX_OCP" = "y" ]; then
-         dep_tristate 'Xilinx on-chip I2C' CONFIG_I2C_XILINX $CONFIG_I2C
-      fi
+   if [ "$CONFIG_IBM_OCP" = "y" ]; then
+      dep_tristate 'IBM IIC I2C interface' CONFIG_I2C_IBM_IIC $CONFIG_I2C
    fi
 
    if [ "$CONFIG_ALL_PPC" = "y" ] ; then
@@ -60,7 +56,9 @@
    if [ "$CONFIG_SGI_IP22" = "y" ]; then
       dep_tristate 'I2C SGI interfaces' CONFIG_I2C_ALGO_SGI $CONFIG_I2C
    fi
- 
+
+   dep_tristate "Asics I2C Master/Slave Adapter" CONFIG_I2C_ASICSMS $CONFIG_I2C
+    
 # This is needed for automatic patch generation: sensors code starts here
 # This is needed for automatic patch generation: sensors code ends here
 
Index: pplinux/linuxnew/drivers/i2c/Makefile
diff -u pplinux/linuxnew/drivers/i2c/Makefile:1.1.323.1 pplinux/linuxnew/drivers/i2c/Makefile:1.3
--- pplinux/linuxnew/drivers/i2c/Makefile:1.1.323.1	Thu Feb  3 10:00:39 2005
+++ pplinux/linuxnew/drivers/i2c/Makefile	Tue Feb 15 12:19:53 2005
@@ -6,10 +6,12 @@
 
 export-objs	:= i2c-core.o i2c-algo-bit.o i2c-algo-pcf.o \
 		   i2c-algo-ite.o i2c-algo-sibyte.o i2c-algo-sgi.o \
-		   i2c-proc.o i2c-ibm_iic.o i2c-algo-8xx.o
+		   i2c-proc.o i2c-ibm_iic.o i2c-algo-8xx.o \
+		   i2c-slave.o i2c-algo-asics.o
 mod-subdirs     := xilinx_iic
 
 obj-$(CONFIG_I2C)		+= i2c-core.o
+obj-$(CONFIG_I2C_SLAVE)		+= i2c-slave.o
 obj-$(CONFIG_I2C_CHARDEV)	+= i2c-dev.o
 obj-$(CONFIG_I2C_ALGOBIT)	+= i2c-algo-bit.o
 obj-$(CONFIG_I2C_PHILIPSPAR)	+= i2c-philips-par.o
@@ -24,6 +26,7 @@
 obj-$(CONFIG_SCx200_ACB)	+= scx200_acb.o
 obj-$(CONFIG_I2C_KEYWEST)	+= i2c-keywest.o
 obj-$(CONFIG_I2C_ALGO_SIBYTE)	+= i2c-algo-sibyte.o i2c-sibyte.o
+obj-$(CONFIG_I2C_ASICSMS)	+= i2c-algo-asics.o i2c-asics.o
 obj-$(CONFIG_I2C_MAX1617)	+= i2c-max1617.o
 obj-$(CONFIG_I2C_ALGO_SGI)	+= i2c-algo-sgi.o
 obj-$(CONFIG_I2C_ALGO8XX)	+= i2c-algo-8xx.o i2c-rpx.o
@@ -31,6 +34,7 @@
 subdir-$(CONFIG_I2C_XILINX)	+= xilinx_iic
 obj-$(CONFIG_I2C_XILINX)	+= xilinx_iic/xilinx_iic.o
 
+
 # This is needed for automatic patch generation: sensors code starts here
 # This is needed for automatic patch generation: sensors code ends here
 
Index: pplinux/linuxnew/drivers/i2c/i2c-algo-asics.c
diff -u /dev/null pplinux/linuxnew/drivers/i2c/i2c-algo-asics.c:1.4
--- /dev/null	Tue May 24 10:37:58 2005
+++ pplinux/linuxnew/drivers/i2c/i2c-algo-asics.c	Thu May 19 15:14:39 2005
@@ -0,0 +1,818 @@
+/*
+    i2c-algo-asics.c i2c driver algorithms for Asics I2C controllers
+
+    Copyright (C) 2004 Microtronix Datacom Ltd
+    Written by Wentao Xu <wentao@microtronix.com>
+    
+    This file was highly leveraged from i2c-algo-pcf.c, which was  
+
+	--------------------------------------------------------------------
+    Copyright (C) 1995-1997 Simon G. Vogl
+                   1998-2000 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 
+   Frodo Looijaard <frodol@dds.nl> ,and also from Martin Bailey
+   <mbailey@littlefeet-inc.com> 
+
+   Partially rewriten by Oleg I. Vdovikin <vdovikin@jscc.ru> to handle multiple
+   messages, proper stop/repstart signaling during receive,
+   added detect code
+   --------------------------------------------------------------------
+*/
+
+#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/i2c.h>
+#include <linux/i2c-algo-asics.h>
+#include "i2c-asics.h"
+
+MODULE_AUTHOR("Peppercon AG");
+MODULE_DESCRIPTION("I2C-Bus Asics algorithm");
+MODULE_LICENSE("GPL");
+
+/* debug level: - 0 off; 1 normal; 2,3 more verbose; 9 asics-protocol */
+#define DEBUG_LEVEL	0
+        
+/* ----- global defines ----------------------------------------------- */
+#if DEBUG_LEVEL >= 1
+#define DEB(x)	{ x }
+#else
+#define DEB(x)	{   }
+#endif
+#if DEBUG_LEVEL >= 2
+#define DEB2(x)	{ x }
+#else
+#define DEB2(x)	{   }
+#endif
+#if DEBUG_LEVEL >= 3
+#define DEB3(x)	{ x }
+#else
+#define DEB3(x)	{   }
+#endif
+#if DEBUG_LEVEL >= 4
+#define DEB4(x)	{ x }
+#else
+#define DEB4(x)	{   }
+#endif
+#if DEBUG_LEVEL >= 9
+#define DEBPROTO(x)	{ x }
+#else
+#define DEBPROTO(x)	{   }
+#endif
+
+#define DBG(fmt, x...)		printk(/*KERN_DEBUG*/KERN_INFO "i2c-algo-asics: " fmt, ##x)
+#define INFO(fmt, x...)		printk(KERN_INFO  "i2c-algo-asics: " fmt, ##x)
+#define WARN(fmt, x...)		printk(KERN_WARNING  "i2c-algo-asics: " fmt, ##x)
+#define CRIT(fmt, x...)		printk(KERN_CRIT  "i2c-algo-asics: " fmt, ##x)
+#define ERR(fmt, x...)		printk(KERN_ERR   "i2c-algo-asics: " fmt, ##x)
+
+#define BUS_WAIT_TIME		100
+#define BUS_WAIT_RETRIES	100
+#define ADDRESS_RETRIES		10
+
+/* --- setting states on the bus with the right timing: ---------------	*/
+#define get_ctl_cmd(adap) adap->getreg(adap->hw, REG_ASICSI2C_CCR)
+#define set_ctl_cmd_force(adap, val) adap->setreg(adap->hw, REG_ASICSI2C_CCR, val)
+#define set_ctl_cmd_control(adap, val) \
+	adap->setreg(adap->hw, REG_ASICSI2C_CCR, val | (get_ctl_cmd(adap) & (BIT_ASICSI2C_CC_ENA | BIT_ASICSI2C_CC_IEN)))
+#define set_ctl_cmd(adap, val) \
+	adap->setreg(adap->hw, REG_ASICSI2C_CCR, val | (get_ctl_cmd(adap) & (BIT_ASICSI2C_CC_MS | BIT_ASICSI2C_CC_ENA | BIT_ASICSI2C_CC_IEN)))
+	/* don't touch the MS bit here! */
+
+#define get_sts(adap) adap->getreg(adap->hw, REG_ASICSI2C_SR)
+#define set_sts(adap, val) adap->setreg(adap->hw, REG_ASICSI2C_SR, val)
+
+#define get_data(adap) adap->getreg(adap->hw, REG_ASICSI2C_DR)
+#define set_data(adap, val) adap->setreg(adap->hw, REG_ASICSI2C_DR, val)
+
+#define asics_set_bit(adap, register, bit) \
+	adap->setreg(adap->hw, register, adap->getreg(adap->hw, register) | bit)
+#define asics_clear_bit(adap, register, bit) \
+	adap->setreg(adap->hw, register, adap->getreg(adap->hw, register) & ~bit)
+
+#define wait_for_tdone(adap) adap->wait_for_tdone(adap->hw)
+
+/* --- other auxiliary functions --------------------------------------	*/
+
+static void i2c_start(struct i2c_algo_asics_data *adap) 
+{
+	DEB4(DBG("Sending start condition.\n"););
+	/* don't use set_ctl_cmd() here because it does not set the MS bit */
+	adap->current_state = I2C_ASICS_MODE_MASTER;
+	set_ctl_cmd_control(adap, BIT_ASICSI2C_CC_MS | BIT_ASICSI2C_CC_WR) ;
+}
+
+static void i2c_repstart(struct i2c_algo_asics_data *adap) 
+{
+	DEB4(DBG("Sending repeated start condition.\n"););
+	set_ctl_cmd(adap, BIT_ASICSI2C_CC_RSTA | BIT_ASICSI2C_CC_WR); 
+}
+
+static void i2c_stop(struct i2c_algo_asics_data *adap) 
+{
+	DEB4(DBG("Sending stop condition.\n"););
+	/* don't use set_ctl_cmd() here because it does not clear the MS bit */
+	set_ctl_cmd_control(adap, 0);
+}
+
+
+static int wait_for_bb(struct i2c_algo_asics_data *adap) {
+
+	int timeout = BUS_WAIT_RETRIES;
+	int status;
+
+	DEB4(DBG("waiting for bus to become free.\n");)
+
+	status = get_sts(adap);
+#ifndef STUB_I2C
+	while (timeout-- && (status & BIT_ASICSI2C_SR_BSY)) {
+		udelay(BUS_WAIT_TIME); /* wait for 100 us */
+		status = get_sts(adap);
+	}
+#endif
+	if (timeout <= 0) {
+		ERR("Timeout waiting for Bus Busy\n");
+	}
+	
+	return (timeout<=0);
+}
+
+/* ----- Utility functions
+ */
+
+static int wait_for_tdone_or_arbitration_lost(struct i2c_algo_asics_data *adap, char* function)
+{
+	int timeout = wait_for_tdone(adap);
+	struct iic_asics_hw *hw = adap->hw;
+	
+	if (timeout) {
+		i2c_stop(adap);
+		ERR("%s: time out waiting for transfer done.\n", function);
+		return (-1);
+	}
+
+#ifndef STUB_I2C
+	if (hw->arbitration_lost) {
+		DBG("%s: arbitration lost.\n", function);
+		return (-1);
+	}
+#endif
+	return 0;
+}
+
+static inline int try_address(struct i2c_algo_asics_data *adap,
+		       unsigned char addr, int retries, int rep_start)
+{
+	int i, status, ret = -1;
+	for (i=0;i<retries;i++) {
+		set_data(adap, addr);
+		if (rep_start) i2c_repstart(adap);
+		else i2c_start(adap);
+		rep_start = 1;
+		if (wait_for_tdone(adap) >= 0) {
+			status=get_sts(adap);
+			if (!(status & BIT_ASICSI2C_SR_R_NO_ACK)) {
+				ret=1;
+				break;	/* success! */
+			}
+		}
+		i2c_stop(adap);
+		udelay(adap->udelay);
+	}
+	DEB2(if (i) DBG("needed %d retries for %d\n",i, addr);)
+	return ret;
+}
+
+static int asics_sendbytes(struct i2c_adapter *i2c_adap, const char *buf, int count)
+{
+	struct i2c_algo_asics_data *adap = i2c_adap->algo_data;
+	int wrcount, status, timeout;
+    
+	for (wrcount=0; wrcount<count; ++wrcount) {
+		DEB2(DBG("asics_sendbytes: writing %2.2X\n", buf[wrcount]&0xff);)
+		/* send a byte*/
+		set_data(adap, buf[wrcount]);
+		set_ctl_cmd(adap, BIT_ASICSI2C_CC_WR);
+
+		timeout = wait_for_tdone_or_arbitration_lost(adap, "asics_sendbytes");
+		status = get_sts(adap);
+		if (timeout) {
+			return -EREMOTEIO; /* got a better one ?? */
+		}
+#ifndef STUB_I2C
+		if (status & BIT_ASICSI2C_SR_R_NO_ACK) {
+			i2c_stop(adap);
+			ERR("asics_sendbytes: error - no ack.\n");
+			return -EREMOTEIO; /* got a better one ?? */
+		}
+#endif
+	}
+
+	return (wrcount);
+}
+
+
+
+static int asics_readbytes(struct i2c_adapter *i2c_adap, char *buf, int count)
+{
+	int i;
+	struct i2c_algo_asics_data *adap = i2c_adap->algo_data;
+
+	for (i = 0; i < count; i++) {
+		if (i == count - 1) {
+			set_ctl_cmd(adap, BIT_ASICSI2C_CC_RD | BIT_ASICSI2C_CC_T_NO_ACK);
+		}
+		else {
+			set_ctl_cmd(adap, BIT_ASICSI2C_CC_RD);
+		}
+
+		if (wait_for_tdone_or_arbitration_lost(adap, "asics_readbytes")) {
+			return -EREMOTEIO;
+		}
+
+		buf[i] = get_data(adap);
+		
+	}
+
+	return (i);
+}
+
+static inline int asics_doAddress(struct i2c_algo_asics_data *adap,
+                                struct i2c_msg *msg, int retries, int rep_start) 
+{
+	unsigned short flags = msg->flags;
+	unsigned char addr;
+	int ret;
+	
+	if ( (flags & I2C_M_TEN)  ) { 
+		/* a ten bit address */
+		addr = 0xf0 | (( msg->addr >> 7) & 0x03);
+		DEB2(DBG("Addressing i2c slave at address 0x%03x\n", msg->addr);)
+		/* try extended address code...*/
+		ret = try_address(adap, addr, retries, rep_start);
+		rep_start = 1;
+		if (ret!=1) {
+			ERR("died at extended address code.\n");
+			return -EREMOTEIO;
+		}
+		/* the remaining 8 bit address */
+		set_data(adap,msg->addr & 0x7f);
+		set_ctl_cmd(adap, BIT_ASICSI2C_CC_WR);
+		if (wait_for_tdone(adap)) {
+			i2c_stop(adap);
+			ERR("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, rep_start);
+			if (ret!=1) {
+				ERR("died at extended address code.\n");
+				return -EREMOTEIO;
+			}
+		}
+	} else {		/* normal 7bit address	*/
+		int status;
+		int i=retries;
+		while (i--) {
+			addr = ( msg->addr << 1 );
+			DEB2(DBG("Addressing i2c slave at address 0x%02x\n", msg->addr);)
+			if (flags & I2C_M_RD )
+				addr |= 1;
+			if (flags & I2C_M_REV_DIR_ADDR )
+				addr ^= 1;
+			set_data(adap, addr);
+			if (rep_start) i2c_repstart(adap);
+			else i2c_start(adap);
+			rep_start = 1;
+			/* waiting for TDONE */
+			if (wait_for_tdone_or_arbitration_lost(adap, "asics_doAddress")) {
+				return -EREMOTEIO;
+			}
+
+			/* check ACK */
+			status=get_sts(adap);
+			if (!(status & BIT_ASICSI2C_SR_R_NO_ACK))
+				return 0; /* success */
+			
+			/* wait a while */
+			i2c_stop(adap);
+			rep_start = 0;
+			if (i>0) mdelay(adap->mdelay);
+	
+		}
+		/* we tried enough times, failed to write address */		
+		DBG("failed to address slave at %x\n", msg->addr);
+		return -EREMOTEIO;
+
+	}
+	return 0;
+}
+
+static int asics_xfer(struct i2c_adapter *i2c_adap,
+		    struct i2c_msg msgs[], 
+		    int num)
+{
+	struct i2c_algo_asics_data *adap = i2c_adap->algo_data;
+	struct i2c_msg *pmsg;
+	int i;
+	int ret=0, timeout, status;
+	int sent = 0;
+    
+	DEB3(DBG("asics_xfer: adapter %s, num=%d\n", i2c_adap->name, num);)
+	
+	/* Check for bus busy */
+	timeout = wait_for_bb(adap);
+	if (timeout) {
+		DEB2(ERR("Timeout waiting for BB in asics_xfer\n");)
+		return -EIO;
+	}
+	
+	for (i = 0;ret >= 0 && i < num; i++) {
+		pmsg = &msgs[i];
+
+		DEB2(DBG("%s %d bytes %s 0x%02x - %d of %d messages\n",
+		     pmsg->flags & I2C_M_RD ? "Reading" : "Writing",
+                     pmsg->len,
+                     pmsg->flags & I2C_M_RD ? "from" : "to",
+                     pmsg->addr, i + 1, num);)
+    
+		ret = asics_doAddress(adap, pmsg, i2c_adap->retries, i != 0);
+		if (ret < 0) {
+			DEB2(ERR("Could not send slave address\n");)
+			continue;
+		}
+
+
+		/* Wait for TIP to negate */
+		timeout = wait_for_tdone(adap);
+		if (timeout) {
+			DEB2(ERR("Timeout waiting for TIP to negate in asics_xfer\n");)
+			i2c_stop(adap);
+			return (-EREMOTEIO);
+		}
+    
+		/* Check RxACK (last rcvd bit - slave ack) */
+		status=get_sts(adap);
+		if (status & BIT_ASICSI2C_SR_R_NO_ACK) {
+			i2c_stop(adap);
+			DEB2(DBG("No RxACK(1) in asics_xfer\n");)
+			return (-EREMOTEIO);
+		}
+    
+		DEB3(DBG("Msg %d, addr=0x%x, flags=0x%x, len=%d\n", i, msgs[i].addr, msgs[i].flags, msgs[i].len);)
+    
+		/* Read */
+		if (pmsg->flags & I2C_M_RD) {
+			/* read bytes into buffer*/
+			ret = asics_readbytes(i2c_adap, pmsg->buf, pmsg->len);
+        
+			if (ret != pmsg->len) {
+				DEB2(DBG("fail: only read %d bytes.\n",ret);)
+			} else {
+				DEB2(DBG("read %d bytes.\n",ret);)
+			}
+		} else { /* Write */
+			ret = asics_sendbytes(i2c_adap, pmsg->buf, pmsg->len);
+        
+			if (ret != pmsg->len) {
+				DEB2(DBG("fail: only wrote %d bytes.\n",ret);)
+			} else {
+				DEB2(DBG("wrote %d bytes.\n",ret);)
+			}
+		}
+		
+		++sent;
+	}
+	
+	i2c_stop(adap);
+
+	/* SMBUS Quick, return an error if no message has been sent */
+	if (num == 1 && !msgs[0].len && sent == 0){
+		return (-EREMOTEIO);
+	}
+	
+	return (sent);
+}
+
+/* set own slave address */
+int i2c_asics_slave_set_address(struct i2c_adapter *i2c_adap, unsigned int address)
+{
+	struct i2c_algo_asics_data *adap = i2c_adap->algo_data;
+
+	/* disable the core */
+	adap->setreg(adap->hw, REG_ASICSI2C_CCR, 0);
+	
+	adap->setreg(adap->hw, REG_ASICSI2C_ESAR, 0);
+	adap->setreg(adap->hw, REG_ASICSI2C_SAR, (address & 0x7f) << 1);
+	DEB(DBG("set i2c slave address to 0x%x\n", address);)
+	
+	/* re-enable the core */
+	adap->setreg(adap->hw, REG_ASICSI2C_CCR, BIT_ASICSI2C_CC_ENA | BIT_ASICSI2C_CC_IEN);
+	
+	return 0;
+}
+
+static u32 asics_func(struct i2c_adapter *adap)
+{
+	return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_10BIT_ADDR | 
+	       I2C_FUNC_PROTOCOL_MANGLING; 
+}
+
+static int asics_algo_control(struct i2c_adapter *adap, 
+			      unsigned int cmd, unsigned long arg)
+{
+	switch (cmd) {
+	    case I2C_SLAVE_SET_ADDRESS:
+		i2c_asics_slave_set_address(adap, (unsigned int) arg);
+		break;
+	    default:
+		return -1;
+	}
+	return 0;
+}
+
+/* -----slave mode functions: ----------------------------------------	*/
+
+static void block_next_slave_transfer(struct i2c_algo_asics_slave_data *slave_data)
+{
+	DEB(DBG("cannot put data to i2c-slave layer, next operation will be blocked.\n");)
+	slave_data->block_next_slave_operation = 1;
+}
+
+static int i2c_asics_slave_write_complete(struct i2c_adapter *i2c_adap)
+{
+	struct i2c_algo_asics_data *adap = i2c_adap->algo_data;
+	struct i2c_algo_asics_slave_data *slave_data = adap->slave_data;
+	
+	int ret = 0;
+	int written_bytes;
+
+	DEB3(DBG("Slave write operation complete.\n");)
+
+	slave_data->last_slave_op = I2C_ASICS_SLAVE_OP_NONE;
+
+	if (slave_data->slave_write_count <= 0) {
+		return slave_data->slave_write_count;
+	}
+	
+	/* copy the written data to the upper I2C slave layer */
+	written_bytes = iic_slave_write(i2c_adap, slave_data->slave_write_buffer,
+		slave_data->slave_write_count);
+	if (written_bytes < 0) {
+		DEB(WARN("i2c_asics_slave_write_complete: error exporting data to i2c-slave layer: %d!\n",
+			written_bytes);)
+		ret = -ENOMEM;
+	}
+	else if (written_bytes == 0) {
+		DEB2(DBG("i2c_asics_slave_write_complete: 0 bytes to i2c-slave layer exported!\n");)
+	}
+	else if (written_bytes >= slave_data->slave_write_count) {
+		DEB2(DBG("i2c_asics_slave_write_complete: moved %d bytes to i2c-slave layer.\n",
+			written_bytes);)
+		slave_data->slave_write_ptr = slave_data->slave_write_buffer;
+		slave_data->slave_write_count = 0;
+	}
+	else {
+		/* only a partial copy */
+		DEB2(DBG("i2c_asics_slave_write_complete: moved %d bytes to i2c-slave layer, %d bytes requested.\n",
+			written_bytes, slave_data->slave_write_count);)
+		slave_data->slave_write_ptr -= written_bytes;
+		slave_data->slave_write_count -= written_bytes;
+	}
+	
+	return ret;
+}
+
+static int i2c_asics_slave_read_complete(struct i2c_adapter *i2c_adap)
+{
+	struct i2c_algo_asics_data *adap = i2c_adap->algo_data;
+	struct i2c_algo_asics_slave_data *slave_data = adap->slave_data;
+
+	DEB3(DBG("Slave read operation complete.\n");)
+
+	slave_data->last_slave_op = I2C_ASICS_SLAVE_OP_NONE;
+
+	if (slave_data->slave_read_ptr < slave_data->slave_read_buffer + slave_data->slave_read_count) {
+		DEB2(DBG("i2c_asics_slave_read_complete: not all data was read! amount: %d, read: %d\n",
+			slave_data->slave_read_count, slave_data->slave_read_ptr - slave_data->slave_read_buffer);)
+	}
+        else {
+		DEB2(DBG("i2c_asics_slave_read_complete: read %d bytes\n",
+			slave_data->slave_read_ptr - slave_data->slave_read_buffer);)
+	}
+	
+	slave_data->slave_read_ptr = slave_data->slave_read_buffer;
+	slave_data->slave_read_count = 0;
+	
+	return 0;
+}
+
+int i2c_asics_slave_restart_xfer(struct i2c_adapter *i2c_adap)
+{
+	struct i2c_algo_asics_data *adap = i2c_adap->algo_data;
+	struct i2c_algo_asics_slave_data *slave_data = adap->slave_data;
+	
+	int ret = 0;
+
+	unsigned long flags;
+	
+        spin_lock_irqsave(&slave_data->slave_lock, flags);
+        
+        /* the next message shall be blocked, but no blocked message read yet
+           --> just deliver the last message */
+        if (slave_data->block_next_slave_operation) {
+        	slave_data->block_next_slave_operation = 0;
+		if (i2c_asics_slave_write_complete(i2c_adap) < 0) {
+			block_next_slave_transfer(slave_data);
+			goto bail;
+		}
+        }
+        
+ bail:
+        spin_unlock_irqrestore(&slave_data->slave_lock, flags);
+	return ret;
+}
+
+static uint8_t finish_last_transfer(struct i2c_adapter *i2c_adap, slave_op_t last_slave_op)
+{
+	struct i2c_algo_asics_data *adap = i2c_adap->algo_data;
+	struct i2c_algo_asics_slave_data *slave_data = adap->slave_data;
+	int ret = 0;
+	
+	if (last_slave_op == I2C_ASICS_SLAVE_OP_WRITE) {
+		DEB2(DBG("finish_last_transfer: finishing write operation.\n");)
+		if (slave_data->slave_write_count > 0) {
+			if (i2c_asics_slave_write_complete(i2c_adap) != 0) {
+				block_next_slave_transfer(slave_data);
+				ret = BIT_ASICSI2C_CC_T_NO_ACK;
+				goto bail;
+			}
+		}
+		else {
+			DEB2(DBG("finish_last_transfer: no bytes received in write operation (%d).\n",
+				slave_data->slave_write_count);)
+		}
+	}
+	else if (last_slave_op == I2C_ASICS_SLAVE_OP_READ) {
+		DEB2(DBG("finish_last_transfer: finishing read operation.\n");)
+		if (i2c_asics_slave_read_complete(i2c_adap) != 0) {
+			block_next_slave_transfer(slave_data);
+			ret = BIT_ASICSI2C_CC_T_NO_ACK;
+			goto bail;
+		}
+	}
+	else {
+		DEB4(DBG("finish_last_transfer: no operation to finish (%d)!\n", last_slave_op);)
+	}
+ bail:
+	return ret;
+}
+
+static int i2c_asics_handle_slave_read(struct i2c_adapter *i2c_adap, uint8_t sr)
+{
+	int ret = -1;
+	uint8_t cr = 0, res;
+
+	struct i2c_algo_asics_data *adap = i2c_adap->algo_data;
+	struct i2c_algo_asics_slave_data *slave_data = adap->slave_data;
+
+	int is_first_slave_byte = sr & BIT_ASICSI2C_SR_CAS;
+	slave_op_t last_slave_op = slave_data->last_slave_op;
+	
+	uint8_t data;
+	
+	slave_data->last_slave_op = I2C_ASICS_SLAVE_OP_READ;
+
+	/* we cannot detect the end of a message when a repeated start
+	   is driven, so assume that the last message is finished when
+	   a new message starts */
+	if (is_first_slave_byte && (res = finish_last_transfer(i2c_adap, last_slave_op)) != 0) {
+		cr |= res;
+		ret = cr;
+		goto bail;
+	}
+	
+	/* no ack from other side on last byte? */
+	if (!is_first_slave_byte && (get_sts(adap) & BIT_ASICSI2C_SR_R_NO_ACK)) {
+		goto bail;
+	}
+	
+	/* write a byte */
+	if (slave_data->slave_read_count > 0) {
+		/* avoid buffer overrun here */
+		if (slave_data->slave_read_ptr < slave_data->slave_read_buffer + slave_data->slave_read_count) {
+			data = *(slave_data->slave_read_ptr);
+			(slave_data->slave_read_ptr)++;
+		}
+		else {
+			/* better error handline here? */
+			data = 0;
+			DEB(DBG("i2c_asics_handle_slave_read: no data!\n");)
+		}
+	}
+	else {
+		/* FIXME: signal that we are not ready by not sending data */
+		data = 0;
+		DEB(DBG("i2c_asics_handle_slave_read: not ready, sending no byte\n");)
+	}
+	
+	DEB2(DBG("i2c_asics_handle_slave_read: sending byte 0x%02x\n", data);)
+
+	set_data(adap, data);
+	ret = BIT_ASICSI2C_CC_WR;
+	
+ bail:
+	return ret;
+}
+
+static int i2c_asics_handle_slave_write(struct i2c_adapter *i2c_adap, uint8_t sr)
+{
+	int ret = -1;
+	uint8_t cr = 0, res;
+	
+	struct i2c_algo_asics_data *adap = i2c_adap->algo_data;
+	struct i2c_algo_asics_slave_data *slave_data = adap->slave_data;
+
+	int is_first_slave_byte = sr & BIT_ASICSI2C_SR_CAS;
+	slave_op_t last_slave_op = slave_data->last_slave_op;
+
+	slave_data->last_slave_op = I2C_ASICS_SLAVE_OP_WRITE;
+
+	/* we cannot detect the end of a message when a repeated start
+	   is driven, so assume that the last message is finished when
+	   a new message starts */
+	if (is_first_slave_byte && (res = finish_last_transfer(i2c_adap, last_slave_op)) != 0) {
+		cr |= res;
+		goto bail;
+	}
+	
+	/* read the byte */
+	if (!is_first_slave_byte) {
+		slave_data->slave_write_count++;
+
+		*(slave_data->slave_write_ptr) = get_data(adap);;
+
+		DEB2(DBG("i2c_asics_handle_slave_write: putting byte 0x%02x\n",
+			*slave_data->slave_write_ptr);)
+
+		/* avoid buffer overrun here */
+		if (slave_data->slave_write_ptr < slave_data->slave_write_buffer + SLAVE_BUF_SIZE) {
+			(slave_data->slave_write_ptr)++;
+		}
+	}
+	
+	ret = BIT_ASICSI2C_CC_RD;
+	
+ bail:
+	DEB2(DBG("i2c_asics_handle_slave_write: ret=0x%x.\n", ret);)
+	return ret;
+}
+
+int i2c_asics_handle_slave_request(struct i2c_adapter *i2c_adap)
+{
+	struct i2c_algo_asics_data *adap = i2c_adap->algo_data;
+	struct i2c_algo_asics_slave_data *slave_data = adap->slave_data;
+	
+	uint8_t sr = get_sts(adap);
+	/*
+	uint8_t bla1 = adap->getreg(adap->hw, 11);
+	uint8_t bla2 = adap->getreg(adap->hw, 7);
+	uint8_t bla3 = adap->getreg(adap->hw, 8);
+	*/
+	uint8_t cr = BIT_ASICSI2C_CC_ENA | BIT_ASICSI2C_CC_IEN, res;
+	int op_ret = 0;
+	
+	int is_slave_write_request = 0;
+	int is_slave_read_request = 0;
+	int is_slave_operation_complete = 0;
+		
+	unsigned long flags;
+	
+        spin_lock_irqsave(&slave_data->slave_lock, flags);
+        DEB3(DBG("handling slave request.\n");)
+        
+        if (adap->current_state != I2C_ASICS_MODE_SLAVE) {
+        	DEB3(DBG("We are not in slave mode, probably we detected another transmission.\n");)
+        	goto bail;
+        }
+        
+	/* parse the request */
+	is_slave_write_request = !(sr & BIT_ASICSI2C_SR_SRW);
+	is_slave_read_request = !is_slave_write_request;
+	is_slave_operation_complete = (sr & BIT_ASICSI2C_SR_DSP);
+	
+	/* if a request is finished (stop condition), finish the operation */
+	if (is_slave_operation_complete) {
+		DEB3(DBG("Slave operation complete.\n");)
+		if ((res = finish_last_transfer(i2c_adap, slave_data->last_slave_op)) != 0) {
+			cr |= res;
+			block_next_slave_transfer(slave_data);
+		}
+		goto bail;
+	}	
+
+	/* if operation should be blocked, don't accept it */
+	if (slave_data->block_next_slave_operation) {
+		DEB(INFO("This operation is being blocked.\n");)
+		cr |= BIT_ASICSI2C_CC_T_NO_ACK;
+		goto bail;
+	}
+	
+	/* process the read or write operation */
+	if (is_slave_write_request) {
+		DEB3(DBG("Slave write request.\n");)
+		op_ret = i2c_asics_handle_slave_write(i2c_adap, sr);
+	}
+	else if (is_slave_read_request) {
+		DEB3(DBG("Slave read request.\n");)
+		op_ret = i2c_asics_handle_slave_read(i2c_adap, sr);
+	}
+
+	if (op_ret > 0) {
+		cr |= (op_ret & 0xff);
+	}
+	
+ bail:
+        DEB3(DBG("slave request handling done.\n");)
+        spin_unlock_irqrestore(&slave_data->slave_lock, flags);
+        
+        return cr;
+}
+
+/* -----exported algorithm data: -------------------------------------	*/
+
+static struct i2c_algorithm asics_algo = {
+	.name		= "Asics algorithm",
+	.id		= I2C_ALGO_ASICS,
+	.master_xfer	= asics_xfer,
+	.algo_control	= asics_algo_control,
+	.functionality	= asics_func,
+};
+
+/* 
+ * registering functions to load algorithms at runtime 
+ */
+
+int i2c_asics_add_bus(struct i2c_adapter *adap)
+{
+	DEB2(DBG("hw routines of %s registered.\n", adap->name);)
+
+	/* register new adapter to i2c module... */
+
+	adap->id |= asics_algo.id;
+	adap->algo = &asics_algo;
+
+	adap->timeout = BUS_WAIT_TIME;
+	adap->retries = ADDRESS_RETRIES;
+
+	i2c_add_adapter(adap);
+	return 0;
+}
+
+
+int i2c_asics_del_bus(struct i2c_adapter *adap)
+{
+	return i2c_del_adapter(adap);
+}
+
+int __init i2c_algo_asics_init (void)
+{
+	INFO("Asics i2c algorithm module\n");
+	return 0;
+}
+
+
+void i2c_algo_asics_exit(void)
+{
+	return;
+}
+
+EXPORT_SYMBOL(i2c_asics_add_bus);
+EXPORT_SYMBOL(i2c_asics_del_bus);
+EXPORT_SYMBOL(i2c_asics_slave_restart_xfer);
+EXPORT_SYMBOL(i2c_asics_handle_slave_request);
+EXPORT_SYMBOL(i2c_asics_slave_set_address);
+
+module_init(i2c_algo_asics_init);
+module_exit(i2c_algo_asics_exit);
Index: pplinux/linuxnew/drivers/i2c/i2c-asics-debug.c
diff -u /dev/null pplinux/linuxnew/drivers/i2c/i2c-asics-debug.c:1.1
--- /dev/null	Tue May 24 10:37:58 2005
+++ pplinux/linuxnew/drivers/i2c/i2c-asics-debug.c	Tue Feb 15 12:19:53 2005
@@ -0,0 +1,140 @@
+#define TEST_MASTER_WRITE	0
+#define TEST_MASTER_READ	0
+#define TEST_SMBUS_READ_BYTE	1
+
+#if TEST_MASTER_WRITE
+static int asicsi2c_master_send(struct i2c_adapter *adap, const char *buf, int count, unsigned int addr)
+{
+	int ret;
+	struct i2c_msg msg;
+
+	if (adap->algo->master_xfer) {
+		msg.addr   = addr;
+		msg.flags = 0;
+		msg.len = count;
+		msg.buf = (char *)buf;
+	
+		DBG("master_send: writing %d bytes.\n",	count);
+	
+		down(&adap->bus_lock);
+		ret = adap->algo->master_xfer(adap,&msg,1);
+		up(&adap->bus_lock);
+
+		/* if everything went ok (i.e. 1 msg transmitted), return #bytes
+		 * transmitted, else error code.
+		 */
+		return (ret == 1) ? count : ret;
+	} else {
+		ERR("I2C level transfers not supported\n");
+		return -ENOSYS;
+	}
+}
+#endif
+
+#if TEST_MASTER_READ
+static int asicsi2c_master_recv(struct i2c_adapter *adap, char *buf, int count, unsigned int addr)
+{
+	struct i2c_msg msg;
+	int ret;
+	if (adap->algo->master_xfer) {
+		msg.addr   = addr;
+		msg.flags = 0;
+		msg.flags |= I2C_M_RD;
+		msg.len = count;
+		msg.buf = buf;
+
+		DBG("master_recv: reading %d bytes.\n", count);
+	
+		down(&adap->bus_lock);
+		ret = adap->algo->master_xfer(adap,&msg,1);
+		up(&adap->bus_lock);
+	
+		DBG("master_recv: return:%d (count:%d, addr:0x%02x)\n",
+			ret, count, addr);
+	
+		/* if everything went ok (i.e. 1 msg transmitted), return #bytes
+	 	* transmitted, else error code.
+	 	*/
+		return (ret == 1) ? count : ret;
+	} else {
+		ERR("I2C level transfers not supported\n");
+		return -ENOSYS;
+	}
+}
+#endif
+
+#if TEST_SMBUS_READ_BYTE
+static int asicsi2c_smbus_read_byte(struct i2c_adapter *adap, unsigned char io_addr, unsigned int addr)
+{
+	struct i2c_msg msg[2];
+	int ret;
+	unsigned char read;
+	if (adap->algo->master_xfer) {
+		msg[0].addr   = addr;
+		msg[0].flags = 0;
+		msg[0].len = 1;
+		msg[0].buf = (char *)&io_addr;
+		
+		msg[1].addr   = addr;
+		msg[1].flags = 0;
+		msg[1].flags |= I2C_M_RD;
+		msg[1].len = 1;
+		msg[1].buf = &read;
+
+		DBG("smbus_read_byte: reading one byte from 0x%02x.\n", io_addr);
+	
+		down(&adap->bus_lock);
+		ret = adap->algo->master_xfer(adap,msg,2);
+		up(&adap->bus_lock);
+	
+		DBG("smbus_read_byte: return:%d (addr:0x%02x)\n", ret, addr);
+	
+		/* if everything went ok (i.e. 1 msg transmitted), return #bytes
+	 	* transmitted, else error code.
+	 	*/
+		return (ret == 2) ? (read & 0xff) : ret;
+	} else {
+		ERR("I2C level transfers not supported\n");
+		return -ENOSYS;
+	}
+}
+#endif
+
+static void send_some_messages(struct i2c_adapter *adap)
+{
+	int ret;
+	char buf;
+	
+	DBG("\nSending some messages to debug the driver.\n\n");
+	
+#if TEST_MASTER_WRITE
+	DBG("Sending one byte to the PowerPC.\n\n");
+	ret = asicsi2c_master_send(adap, "xxxxxxx", 1, 0x55);
+	if (ret < 0) {
+		DBG("Error sending one byte to the PowerPC.\n\n");
+		return;
+	}
+#endif
+
+#if TEST_MASTER_READ
+	DBG("Reading one byte from the PowerPC.\n\n");
+	ret = asicsi2c_master_recv(adap, &buf, 1, 0x55);
+	if (ret < 0) {
+		DBG("Error sending one byte to the PowerPC.\n\n");
+		return;
+	} else {
+		DBG("Read byte 0x%02x from PowerPC.\n\n", buf & 0xff);
+	}
+#endif
+
+#if TEST_SMBUS_READ_BYTE
+	DBG("Reading one byte from the ADC (SM-Bus.\n\n");
+	ret = asicsi2c_smbus_read_byte(adap, 1, 0x4C);
+	if (ret < 0) {
+		DBG("Error sending one byte to the ADC.\n\n");
+		return;
+	} else {
+		DBG("Read byte 0x%02x from ADC.\n\n", ret & 0xff);
+	}
+#endif
+}
Index: pplinux/linuxnew/drivers/i2c/i2c-asics.c
diff -u /dev/null pplinux/linuxnew/drivers/i2c/i2c-asics.c:1.8
--- /dev/null	Tue May 24 10:37:58 2005
+++ pplinux/linuxnew/drivers/i2c/i2c-asics.c	Thu May 19 15:14:39 2005
@@ -0,0 +1,716 @@
+/*  /drivers/i2c/busses/i2c-asics.c
+	Support of the Asics i2c bus
+	
+	Copyright (C) 2004 Microtronix Datacom 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
+    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.
+   
+    Written by Wentao Xu <wentao@microtronix.com>
+*/
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/ioport.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/wait.h>
+#include <linux/pci.h>
+#include <linux/i2c.h>
+#include <linux/i2c-slave.h>
+#include <linux/i2c-algo-asics.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include "i2c-asics.h"
+
+MODULE_AUTHOR("Peppercon AG");
+MODULE_DESCRIPTION("I2C-Bus adapter routines for Asics i2c controller");
+MODULE_LICENSE("GPL");
+
+#define ASICSI2C_IO_SIZE 	32
+#define ASICSI2C_CLOCK_DEFAULT	66  /* MHz */
+#define ASICSI2C_SCL_DEFAULT	100 /* kHz */
+#define ASICSI2C_IRQ_NO_INTMUX	-1
+
+#if defined(LARA_KIMMSI) || defined (LARA_KIMAMD)
+# define ASICS_USE_PCI
+# define ASICS_USE_INTMUX
+# define ASICS_PCI_VENDOR_ID	0x1743	
+# define ASICS_PCI_DEVICE_ID	0x1003
+# define ASICS_PCI_BAR_NO	1
+# define INTMUX_OFFSET		0x9A0000
+# define INTMUX_SIZE		4
+#else
+# define ASICS_BASE		0x81000000
+#endif
+
+#define ASICS_I2C_IRQ		27 /* common irq for all cores */
+
+#define I2C_0_BASE_OFFSET	0x900000
+#define I2C_0_INTMUX		1
+
+#define I2C_1_BASE_OFFSET	0x910000
+#define I2C_1_INTMUX		2
+
+#define I2C_2_BASE_OFFSET	0x920000
+#define I2C_2_INTMUX		3
+
+#define I2C_3_BASE_OFFSET	0x930000
+#define I2C_3_INTMUX		4
+
+#define I2C_4_BASE_OFFSET	0x940000
+#define I2C_4_INTMUX		5
+
+#define I2C_DDC_BASE_OFFSET	0x9C0000
+#define I2C_DDC_INTMUX		15
+
+#define I2C_LAN_BASE_OFFSET	0x9D0000
+#define I2C_LAN_INTMUX		16
+
+/******************************************************************************
+* debugging                                                                   *
+******************************************************************************/
+
+/*
+  DBG_LEVEL == 0 --> no debugging
+  DBG_LEVEL < 0  --> short debugging
+  DBG_LEVEL > 0  --> full debugging
+*/
+
+#define DBG_LEVEL 0
+
+#if DBG_LEVEL > 0
+#  define DBG(fmt, x...)	printk(/*KERN_DEBUG*/KERN_INFO "i2c-asics: " fmt, ##x)
+#else
+#  define DBG(fmt, x...)	((void)0)
+#endif
+#if DBG_LEVEL > 1
+#  define DBG2(fmt, x...) 	DBG( fmt, ##x )
+#else
+#  define DBG2(fmt, x...) 	((void)0)
+#endif
+#if DBG_LEVEL > 2
+#  define DBG3(fmt, x...) 	DBG( fmt, ##x )
+#else
+#  define DBG3(fmt, x...) 	((void)0)
+#endif
+
+#if DBG_LEVEL < 0
+#  define SDBG(fmt, x...) 	printk(/*KERN_DEBUG*/KERN_INFO fmt, ##x)
+#else
+#  define SDBG(fmt, x...) 	((void)0)
+#endif
+
+#define INFO(fmt, x...)		printk(KERN_INFO    "i2c-asics: " fmt, ##x)
+#define WARN(fmt, x...)		printk(KERN_WARNING "i2c-asics: " fmt, ##x)
+#define CRIT(fmt, x...)		printk(KERN_CRIT    "i2c-asics: " fmt, ##x)
+#define ERR(fmt, x...)		printk(KERN_ERR     "i2c-asics: " fmt, ##x)
+
+#define DBG_SEND_MESSAGES_ON_LOAD	0
+
+#if DBG_SEND_MESSAGES_ON_LOAD
+#include "i2c-asics-debug.c"
+#endif
+
+/******************************************************************************
+ * debugging via debug pin                                                    *
+ ******************************************************************************/
+
+#define noGPIO_DEBUG
+
+#ifdef GPIO_DEBUG
+
+#define PPC405_GPIO_REGS_ADDR		((u32)0xEF600700)
+#define PPC405_GPIO_REGS_SIZE		((size_t)0x20)
+
+static volatile u32 * gpio_regs = NULL;
+
+static void
+gpio_init(void) {
+	gpio_regs = ioremap_nocache(PPC405_GPIO_REGS_ADDR,
+				    PPC405_GPIO_REGS_SIZE);
+	
+	if (gpio_regs) {
+		INFO("GPIO debugging enabled.\n");
+	} else {
+		WARN("Could not map GPIO registers!\n");
+	}
+}
+
+static void
+gpio_cleanup(void) {
+	if (gpio_regs) {
+		iounmap((void *)gpio_regs);
+		INFO("GPIO debugging disabled.\n");
+	} else {
+		INFO("Could not unmap GPIO registers, not mapped.\n");
+	}
+}
+
+static void
+gpio_bit_set(unsigned int value)
+{
+	if (gpio_regs) {
+		int bitnum = 31 - 9;
+		if (value) {
+			set_bit(bitnum, &gpio_regs[0]);
+		} else {
+			clear_bit(bitnum, &gpio_regs[0]);
+		}
+	}
+}
+
+#else
+
+static void gpio_bit_set(unsigned int value) { }
+static void gpio_init(void) { }
+static void gpio_cleanup(void) { }
+
+#endif
+
+/******************************************************************************
+* board configuration                                                         *
+******************************************************************************/
+
+#define ASICS_NUM_INTERFACES	1
+
+struct i2c_asics_interface_configuration {
+    int used;
+    int base_offset;
+    int irq;
+    int irq_mux;
+    int scl;
+    int clock;
+    uint8_t slave_address; /* currently only 7 bit slave address supported */
+};
+
+#warning i2c ctrl hardcoded to FPGA - I2C2 (SMB_ICH on MSI-card)
+static struct i2c_asics_interface_configuration i2c_asics_interfaces[ASICS_NUM_INTERFACES] = {
+//    { 1, I2C_0_BASE_OFFSET, ASICS_I2C_IRQ, I2C_0_INTMUX, 100, 0, 0x33 },
+//    { 1, I2C_1_BASE_OFFSET, ASICS_I2C_IRQ, I2C_1_INTMUX, 100, 0, 0x33 },
+//    { 1, I2C_2_BASE_OFFSET, ASICS_I2C_IRQ, I2C_2_INTMUX, 100, 0, 0x33 },
+//    { 1, I2C_3_BASE_OFFSET, ASICS_I2C_IRQ, I2C_3_INTMUX, 100, 0, 0x33 },
+//    { 1, I2C_4_BASE_OFFSET, ASICS_I2C_IRQ, I2C_4_INTMUX, 100, 0, 0x33 },
+    { 1, I2C_DDC_BASE_OFFSET, ASICS_I2C_IRQ, I2C_DDC_INTMUX, 100, 33, 0x33 },
+//    { 1, I2C_LAN_BASE_OFFSET, ASICS_I2C_IRQ, I2C_LAN_INTMUX, 100, 0, 0x33 },
+};
+
+/*
+static struct i2c_asics_interface_configuration i2c_asics_interfaces[ASICS_NUM_INTERFACES] = {
+    { 1, ASICS_BASE + I2C_DDC_BASE_OFFSET, ASICS_I2C_IRQ, I2C_DDC_INTMUX, 100, 0, 0x33 },
+};
+*/
+
+/******************************************************************************
+* function prototypes                                                         *
+******************************************************************************/
+
+static int asicsi2c_wait_for_tdone(struct iic_asics_hw *hw);
+static irqreturn_t asics_handler(int this_irq, void *dev_id, struct pt_regs *regs);
+static int asics_hw_init(struct iic_asics_hw *hw);
+static void asics_slave_init(struct i2c_algo_asics_slave_data * slave_data);
+static int asics_slave_init_adapter(struct i2c_slave_adapter *slave, struct i2c_adapter *adap);
+static int i2c_asics_adapter_init(struct i2c_adapter *i2c_adap, unsigned int slave_address);
+static void asics_hw_exit(struct iic_asics_hw* hw);
+static int asics_slave_cleanup_adapter(struct i2c_slave_adapter *slave);
+static void i2c_asics_adapter_cleanup(struct i2c_adapter *i2c_adap);
+static struct i2c_adapter* i2c_asics_get_adapter_from_hw(struct iic_asics_hw *hw);
+
+/******************************************************************************
+* helper functions                                                            *
+******************************************************************************/
+
+static char* num_to_bin(uint8_t num)
+{
+	static char bin[9];
+	int i;
+	
+	for (i = 0; i < 8; i++) {
+		bin[i] = (num & (1 << (7 - i))) ? '1' : '0';
+	}
+	bin[8] = '\0';
+	
+	return bin;
+}
+
+static void asicsi2c_setreg(struct iic_asics_hw *hw, int regno, int val)
+{
+	DBG3("asicsi2c_setreg: regno %02x (%s), value 0x%02x (%s)\n",
+		regno,
+		regno == 0 ? "PRERL" : regno == 1 ? "PRERH" : regno == 2 ? "CCR" :
+			regno == 3 ? "SR" : regno == 4 ? "DR" : regno == 5 ? "SAR" :
+			regno == 6 ? "ESAR" : "unknown",
+		val, num_to_bin(val));
+	writeb(val, &hw->asics_regs[regno]);
+}
+
+static int asicsi2c_getreg_nodbg(struct iic_asics_hw *hw, int regno)
+{
+	return readb(&hw->asics_regs[regno]);
+}
+
+#if DBG_LEVEL > 2
+static int asicsi2c_getreg(struct iic_asics_hw *hw, int regno)
+{
+	int ret = asicsi2c_getreg_nodbg(hw, regno);
+	
+	DBG3("asicsi2c_getreg: regno %02x (%s), value 0x%02x (%s)\n",
+		regno,
+		regno == 0 ? "PRERL" : regno == 1 ? "PRERH" : regno == 2 ? "CCR" :
+			regno == 3 ? "SR" : regno == 4 ? "DR" : regno == 5 ? "SAR" :
+			regno == 6 ? "ESAR" : "unknown",
+		ret, num_to_bin(ret));
+	
+	return ret;
+}
+#else /* DBG_LEVEL > 2 */
+//#define asicsi2c_setreg asicsi2c_setreg_nodbg
+#define asicsi2c_getreg asicsi2c_getreg_nodbg
+#endif /* DBG_LEVEL > 2 */
+
+#define asics_set_bit(hw, register, bit) \
+	asicsi2c_setreg(hw, register, asicsi2c_getreg_nodbg(hw, register) | bit)
+#define asics_clear_bit(hw, register, bit) \
+	asicsi2c_setreg(hw, register, asicsi2c_getreg_nodbg(hw, register) & ~bit)
+
+
+static int asicsi2c_wait_for_tdone(struct iic_asics_hw *hw)
+{
+	int timeout = 2;
+
+	if (hw->irq > 0) {
+		DBG("Waiting for transfer to end (interrupt)...\n");
+		wait_event_interruptible_timeout(hw->wait, 
+					((asicsi2c_getreg(hw, REG_ASICSI2C_SR) & BIT_ASICSI2C_SR_TDONE) != 0) || hw->arbitration_lost, 
+					timeout*HZ);
+		DBG("...Waiting finished.\n");
+	} else {
+		DBG("Waiting for transfer to end (polling).\n");
+		udelay(100);
+	}
+	
+	if (!(asicsi2c_getreg(hw, REG_ASICSI2C_SR) & BIT_ASICSI2C_SR_TDONE) && !hw->arbitration_lost)
+		return -1;
+	return 0;
+}
+
+/******************************************************************************
+* interrupt handler                                                           *
+******************************************************************************/
+
+static irqreturn_t asics_handler(int this_irq, void *dev_id, struct pt_regs *regs) 
+{
+	struct iic_asics_hw *hw= (struct iic_asics_hw *)dev_id;
+	struct i2c_adapter *i2c_adap = i2c_asics_get_adapter_from_hw(hw);
+	struct i2c_algo_asics_data *adap = (struct i2c_algo_asics_data *) i2c_adap->algo_data;
+
+	uint8_t cr = asicsi2c_getreg_nodbg(hw, REG_ASICSI2C_CCR);
+	uint8_t sr = asicsi2c_getreg_nodbg(hw, REG_ASICSI2C_SR);
+	
+	int arbitration_lost = 0;
+	
+	gpio_bit_set(1);
+
+	DBG2("---- asics_handler start\n");
+
+	SDBG("\n+\n");
+#ifdef ASICS_USE_INTMUX
+	if (hw->irq_mux != ASICSI2C_IRQ_NO_INTMUX) {
+	    u_long mux = readl(&hw->intmux_reg[0]);
+	    if (!test_bit(hw->irq_mux, &mux)) {
+		// this is not our IRQ
+		DBG2("---- asics_handler: not our irq\n");
+		SDBG("-\n");
+		gpio_bit_set(0);
+		return;
+	    }
+	}
+#endif
+	
+	DBG2("---- asics_handler our irq\n");
+
+	DBG2("asics_handler: CCR=0x%02x (%s)\n", cr, num_to_bin(cr));
+	DBG2("asics_handler: SR=0x%02x (%s)\n", sr, num_to_bin(sr));
+	DBG2("asics_handler: DR=0x%02x (%s)\n", asicsi2c_getreg_nodbg(hw, REG_ASICSI2C_DR), num_to_bin(asicsi2c_getreg_nodbg(hw, REG_ASICSI2C_DR)));
+	SDBG("%x %x\n", cr, sr);
+	DBG3("asics_handler: SAR=0x%02x (%s)\n", asicsi2c_getreg_nodbg(hw, REG_ASICSI2C_SAR), num_to_bin(asicsi2c_getreg_nodbg(hw, REG_ASICSI2C_SAR)));
+	DBG3("asics_handler: ESAR=0x%02x (%s)\n", asicsi2c_getreg_nodbg(hw, REG_ASICSI2C_ESAR), num_to_bin(asicsi2c_getreg_nodbg(hw, REG_ASICSI2C_ESAR)));
+	DBG3("asics_handler: PRERL=0x%02x (%s)\n", asicsi2c_getreg_nodbg(hw, REG_ASICSI2C_PRERL), num_to_bin(asicsi2c_getreg_nodbg(hw, REG_ASICSI2C_PRERL)));
+	DBG3("asics_handler: PRERH=0x%02x (%s)\n", asicsi2c_getreg_nodbg(hw, REG_ASICSI2C_PRERH), num_to_bin(asicsi2c_getreg_nodbg(hw, REG_ASICSI2C_PRERH)));
+	
+	/* check for arbitration lost */
+	if (sr & BIT_ASICSI2C_SR_AL) {
+		DBG2("lost arbitration\n");
+		arbitration_lost = hw->arbitration_lost = 1;
+		adap->current_state = I2C_ASICS_MODE_IDLE;
+		asics_clear_bit(hw, REG_ASICSI2C_SR, BIT_ASICSI2C_SR_AL);
+	} else {
+		arbitration_lost = hw->arbitration_lost = 0;
+	}
+	
+	/* check for slave mode */
+	if (sr & BIT_ASICSI2C_SR_CAS) {
+	    DBG2("switching to slave mode\n");
+	    if (adap->current_state != I2C_ASICS_MODE_SLAVE) {
+		    /* clear old stop condition, if any */
+		    if (sr & BIT_ASICSI2C_SR_DSP) {
+			DBG2("clear unknown stop cond\n");
+			adap->current_state = I2C_ASICS_MODE_IDLE;
+			asics_clear_bit(hw, REG_ASICSI2C_SR, BIT_ASICSI2C_SR_DSP);
+			sr &= ~BIT_ASICSI2C_SR_DSP;
+		    }
+	    }
+	    adap->current_state = I2C_ASICS_MODE_SLAVE;
+	}
+
+	if (!(cr & BIT_ASICSI2C_CC_MS) && !arbitration_lost) {
+		DBG3("got slave request, found adapter %s.\n", i2c_adap->name);
+		cr = i2c_asics_handle_slave_request(i2c_adap);
+		SDBG("%x\n", cr);
+		asicsi2c_setreg(hw, REG_ASICSI2C_CCR, cr);
+	}
+	
+	/* check for stop condition */
+	if (sr & BIT_ASICSI2C_SR_DSP) {
+		DBG2("switching to idle mode\n");
+		adap->current_state = I2C_ASICS_MODE_IDLE;
+		asics_clear_bit(hw, REG_ASICSI2C_SR, BIT_ASICSI2C_SR_DSP);
+	}
+	
+	/* ack this interrupt */
+	asics_clear_bit(hw, REG_ASICSI2C_SR, BIT_ASICSI2C_SR_IF);
+
+	wake_up_interruptible(&hw->wait);
+	
+	DBG2("---- asics_handler finished\n");
+	SDBG("-\n");
+	gpio_bit_set(0);
+
+	return IRQ_HANDLED;
+}
+
+
+/******************************************************************************
+* initialization functions                                                    *
+******************************************************************************/
+
+static int asics_hw_init(struct iic_asics_hw *hw)
+{
+	int prescale;
+	int dev_base;
+#ifdef ASICS_USE_PCI
+	struct pci_dev *pci_dev;
+#endif
+	
+#ifdef ASICS_USE_PCI
+	pci_dev = pci_find_device(ASICS_PCI_VENDOR_ID, ASICS_PCI_DEVICE_ID, NULL);
+	if (pci_dev == NULL) {
+	    ERR("PCI device not detected\n");
+	    return -ENODEV;
+	}
+	dev_base = pci_resource_start(pci_dev, ASICS_PCI_BAR_NO);
+#else
+	dev_base = ASICS_BASE;
+#endif
+	hw->base = dev_base + hw->base_offset;
+	DBG("using physical base address 0x%08x\n", hw->base);
+	
+#ifdef ASICS_USE_INTMUX
+	hw->intmux_reg = ioremap_nocache(dev_base + INTMUX_OFFSET, INTMUX_SIZE);
+	if (hw->intmux_reg == NULL) {
+	    ERR("failed to map IRQ multiplexer\n");
+	    return -ENODEV;
+	}
+	DBG("mapped IRQ multiplexer from 0x%08x to 0x%p (%d Byte)\n", dev_base + INTMUX_OFFSET,
+	    hw->intmux_reg, INTMUX_SIZE);
+#endif
+	
+	if (!request_mem_region(hw->base, ASICSI2C_IO_SIZE, "i2c (bus adapter)")) {
+		ERR("requested MMIO region (0x%X:2) is in use.\n", hw->base);
+		return -ENODEV;
+	}
+
+	/* map asics regs */
+	hw->asics_regs = ioremap_nocache(hw->base, ASICSI2C_IO_SIZE);
+	if (hw->asics_regs == NULL) {
+	    ERR("failed to map ASICS regs\n");
+	    return -ENOMEM;
+	}
+	DBG("mapped ASICS regs from 0x%08x to 0x%p (%d Byte)\n", hw->base,
+	    hw->asics_regs, ASICSI2C_IO_SIZE);
+	
+	/* clear EN and MS bit */
+	asicsi2c_setreg(hw, REG_ASICSI2C_CCR, 0);
+	
+	/* compute prescale */
+	prescale = hw->clock * 1000 / (4 * hw->scl) - 1;
+	DBG("scl=%d, clock=%d -> prescale=%d\n", hw->scl, hw->clock, prescale);
+	if (prescale < 0) {
+	    ERR("prescale error clk_i %d scl %d\n", hw->clock, hw->scl);
+	    return -ENODEV;
+	}
+	
+	/* set prescale */
+	asicsi2c_setreg(hw, REG_ASICSI2C_PRERL, prescale & 0xff);
+	asicsi2c_setreg(hw, REG_ASICSI2C_PRERH, prescale >> 8);
+	
+	/* error debugging */
+	asicsi2c_setreg(hw, REG_ASICSI2C_SR, 8);
+	asicsi2c_setreg(hw, REG_ASICSI2C_DR, 0x20);
+
+	if (hw->irq > 0) {
+		if (request_irq(hw->irq, asics_handler, SA_SHIRQ | SA_SAMPLE_RANDOM, "Asics I2C", hw) < 0) {
+			ERR("Request irq%d failed\n", hw->irq);
+			hw->irq = 0;
+
+			/* set EN bit */
+			asicsi2c_setreg(hw, REG_ASICSI2C_CCR, BIT_ASICSI2C_CC_ENA);
+		} else {
+			DBG("Requested irq %d.\n", hw->irq);
+
+			/* set EN bit */
+			asicsi2c_setreg(hw, REG_ASICSI2C_CCR, BIT_ASICSI2C_CC_ENA | BIT_ASICSI2C_CC_IEN);
+		}
+	}
+	
+	hw->arbitration_lost = 0;
+
+	DBG2("asics_hw_init successful\n");
+	return 0;
+}
+
+static void asics_slave_init(struct i2c_algo_asics_slave_data * slave_data)
+{
+	spin_lock_init(slave_data->slave_lock);
+	
+	slave_data->block_next_slave_operation = 0;
+	slave_data->last_slave_op = I2C_ASICS_SLAVE_OP_NONE;
+	
+        slave_data->slave_write_ptr = slave_data->slave_write_buffer;
+        slave_data->slave_write_count = 0;
+        slave_data->slave_read_ptr = slave_data->slave_read_buffer;
+        slave_data->slave_read_count = 0;
+}
+
+/* register adapter in slave layer */
+static int asics_slave_init_adapter(struct i2c_slave_adapter *slave, struct i2c_adapter *adap)
+{
+	int ret = 0;
+
+	slave->adapter = adap;
+	slave->reactivate = i2c_asics_slave_restart_xfer;
+	if ((ret = i2c_slave_add_adapter(slave)) != 0){
+		CRIT("failed to register i2c slave adapter\n");
+		return ret;
+	}
+	
+	return 0;
+}
+
+static int i2c_asics_adapter_init(struct i2c_adapter *i2c_adap, unsigned int slave_address)
+{
+	struct i2c_algo_asics_data *adap = (struct i2c_algo_asics_data *) i2c_adap->algo_data;
+	struct iic_asics_hw *hw = adap->hw;
+	struct i2c_algo_asics_slave_data *slave_data = adap->slave_data;
+	struct i2c_slave_adapter *slave_adapter = adap->slave_adapter;
+	
+	DBG3("Initializing hardware for %s.\n", i2c_adap->name);
+	
+	init_waitqueue_head(&hw->wait);
+	if (asics_hw_init(hw) == 0) {
+		if (i2c_asics_add_bus(i2c_adap) < 0) {
+			asics_hw_exit(hw);
+			return -1;
+		}
+		if (asics_slave_init_adapter(slave_adapter, i2c_adap) < 0) {
+			asics_hw_exit(hw);
+			return -1;
+		}
+	}
+	
+	asics_slave_init(slave_data);
+	i2c_asics_slave_set_address(i2c_adap, slave_address);
+	
+	return 0;
+}
+
+/******************************************************************************
+* cleanup functions                                                           *
+******************************************************************************/
+
+static void asics_hw_exit(struct iic_asics_hw* hw)
+{
+	/* free irq */
+	if (hw->irq > 0) {
+		free_irq(hw->irq, hw);
+	}
+
+	/* free register mapping */
+	if (hw->asics_regs != NULL) {
+	    iounmap((void*)hw->asics_regs);
+	    hw->asics_regs = NULL;
+	}
+	
+	/* free mem region */
+	release_mem_region(hw->base, ASICSI2C_IO_SIZE);
+	
+#ifdef ASICS_USE_INTMUX
+    if (hw->intmux_reg != NULL) {
+	iounmap((void *)hw->intmux_reg);
+	hw->intmux_reg = NULL;
+    }    
+#endif
+}
+
+/* deregister */
+static int asics_slave_cleanup_adapter(struct i2c_slave_adapter *slave)
+{
+	int ret;
+	
+	if ((ret = i2c_slave_remove_adapter(slave)) != 0) {
+		CRIT("failed to deregister i2c slave adapter\n");
+		return ret;
+	}
+	
+	return 0;
+}
+
+static void i2c_asics_adapter_cleanup(struct i2c_adapter *i2c_adap)
+{
+	struct i2c_algo_asics_data *data = (struct i2c_algo_asics_data *) i2c_adap->algo_data;
+	struct iic_asics_hw *hw = data->hw;
+	struct i2c_slave_adapter *slave_adapter = data->slave_adapter;
+
+	i2c_asics_del_bus(i2c_adap);
+	asics_hw_exit(hw);
+	asics_slave_cleanup_adapter(slave_adapter);
+}
+
+/******************************************************************************
+* module data                                                                 *
+******************************************************************************/
+
+/* there are several adapters on the board */
+
+static char* asics_names[ASICS_NUM_INTERFACES] = {
+	"Asics i2c 0",
+};
+
+static struct i2c_algo_asics_slave_data asics_slave[ASICS_NUM_INTERFACES];
+
+static struct i2c_slave_adapter asics_slave_adapt[ASICS_NUM_INTERFACES];
+
+static struct iic_asics_hw asics_hw[ASICS_NUM_INTERFACES];
+
+static struct i2c_algo_asics_data asics_data[ASICS_NUM_INTERFACES];
+
+static struct i2c_adapter asics_ops[ASICS_NUM_INTERFACES];
+
+
+static struct i2c_adapter* i2c_asics_get_adapter_from_hw(struct iic_asics_hw *hw)
+{
+	int i;
+	
+	for (i = 0; i < ASICS_NUM_INTERFACES; i++) {
+		if (hw == ((struct i2c_algo_asics_data *) asics_ops[i].algo_data)->hw) return &asics_ops[i];
+	}
+	
+	return NULL;
+}
+
+static void i2c_asics_init_adapters(void) {
+	int i;
+	
+	memset(asics_ops, 0, sizeof(asics_ops));
+	memset(asics_data, 0, sizeof(asics_data));
+	memset(asics_hw, 0, sizeof(asics_hw));
+	memset(asics_slave_adapt, 0, sizeof(asics_slave_adapt));
+	memset(asics_slave, 0, sizeof(asics_slave));
+
+	for (i = 0; i < ASICS_NUM_INTERFACES; i++) {
+		if (!i2c_asics_interfaces[i].used) {
+			continue;
+		}
+		
+		/* fill i2c_adapter struct */
+#warning owner n/a for 2.4
+		//asics_ops[i].owner		= THIS_MODULE;
+		asics_ops[i].id			= I2C_HW_ASICS_UKIT;
+		asics_ops[i].algo_data		= &asics_data[i];
+		strncpy(asics_ops[i].name, asics_names[i], sizeof(asics_ops[i].name));
+		
+		/* fill i2c_algo_asics_data struct */
+		asics_data[i].hw		= &asics_hw[i];
+		asics_data[i].slave_data	= &asics_slave[i];
+		asics_data[i].slave_adapter	= &asics_slave_adapt[i];
+		asics_data[i].setreg		= asicsi2c_setreg;
+		asics_data[i].getreg		= asicsi2c_getreg;
+		asics_data[i].wait_for_tdone	= asicsi2c_wait_for_tdone;
+		asics_data[i].udelay		= 10,
+		asics_data[i].mdelay		= 10,
+		asics_data[i].timeout		= 100,
+		asics_data[i].current_state	= I2C_ASICS_MODE_IDLE,
+		
+		/* fill iic_asics_hw struct */
+		asics_hw[i].base_offset		= i2c_asics_interfaces[i].base_offset ? i2c_asics_interfaces[i].base_offset : 0;
+		asics_hw[i].irq			= i2c_asics_interfaces[i].irq ? i2c_asics_interfaces[i].irq : 0;
+		asics_hw[i].irq_mux		= i2c_asics_interfaces[i].irq_mux ? i2c_asics_interfaces[i].irq_mux : 0;
+		asics_hw[i].clock		= i2c_asics_interfaces[i].clock ? i2c_asics_interfaces[i].clock : ASICSI2C_CLOCK_DEFAULT;
+		asics_hw[i].scl			= i2c_asics_interfaces[i].scl ? i2c_asics_interfaces[i].scl : ASICSI2C_SCL_DEFAULT;
+	}
+}
+
+/******************************************************************************
+* module stuff                                                                *
+******************************************************************************/
+
+static int __init i2c_asics_init(void) 
+{
+	int i;
+	
+	INFO("i2c Asics adapter driver\n");
+
+	gpio_init();
+	mdelay(500);
+
+	/* parameters */
+	i2c_asics_init_adapters();
+	
+	for (i = 0; i < ASICS_NUM_INTERFACES; i++) {
+		i2c_asics_adapter_init(&asics_ops[i], i2c_asics_interfaces[i].slave_address);
+	}
+	
+#if DBG_SEND_MESSAGES_ON_LOAD
+	send_some_messages(&asics_ops[0]);
+#endif
+	return 0;
+}
+
+static void i2c_asics_exit(void)
+{
+	int i;
+
+	for (i = 0; i < ASICS_NUM_INTERFACES; i++) {
+		i2c_asics_adapter_cleanup(&asics_ops[i]);
+	}
+	
+	gpio_cleanup();
+}
+
+module_init(i2c_asics_init);
+module_exit(i2c_asics_exit);
Index: pplinux/linuxnew/drivers/i2c/i2c-asics.h
diff -u /dev/null pplinux/linuxnew/drivers/i2c/i2c-asics.h:1.1
--- /dev/null	Tue May 24 10:37:58 2005
+++ pplinux/linuxnew/drivers/i2c/i2c-asics.h	Tue Feb 15 12:19:53 2005
@@ -0,0 +1,49 @@
+/*   Copyright (C) 2004 Microtronix Datacom 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
+    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 I2C_ASICS_H
+#define I2C_ASICS_H 1
+
+/* Register map */
+#define REG_ASICSI2C_PRERL		0	/* prescale low register */
+#define REG_ASICSI2C_PRERH		1	/* prescale high register */
+#define REG_ASICSI2C_CCR		2	/* control/command register */
+#define REG_ASICSI2C_SR			3	/* status register */
+#define REG_ASICSI2C_DR			4	/* data register */
+#define REG_ASICSI2C_SAR		5	/* slave address register */
+#define REG_ASICSI2C_ESAR		6	/* extended address register */
+
+/* control/command register */
+#define BIT_ASICSI2C_CC_ENA		(1<<7)	/* core enabled */
+#define BIT_ASICSI2C_CC_IEN		(1<<6)	/* interrupt enabled */
+#define BIT_ASICSI2C_CC_MS		(1<<5)	/* master/slave select */
+#define BIT_ASICSI2C_CC_RSTA		(1<<4)	/* repeated start condition */
+#define BIT_ASICSI2C_CC_RD		(1<<3)	/* read */
+#define BIT_ASICSI2C_CC_WR		(1<<2)	/* write */
+#define BIT_ASICSI2C_CC_T_NO_ACK	(1<<1)	/* transmit acknowledge */
+
+/* status register */
+#define BIT_ASICSI2C_SR_TDONE		(1<<7)	/* transfer done */
+#define BIT_ASICSI2C_SR_BSY		(1<<6)	/* bus busy */
+#define BIT_ASICSI2C_SR_AL		(1<<5)	/* arbitration lost */
+#define BIT_ASICSI2C_SR_CAS		(1<<4)	/* called as slave */
+#define BIT_ASICSI2C_SR_DSP		(1<<3)	/* detected stop condition */
+#define BIT_ASICSI2C_SR_SRW		(1<<2)	/* slave read/write */
+#define BIT_ASICSI2C_SR_R_NO_ACK	(1<<1)	/* received ack */
+#define BIT_ASICSI2C_SR_IF		1	/* interrupt flag */
+
+
+#endif /* I2C_ASICS_H */
Index: pplinux/linuxnew/drivers/i2c/i2c-core.c
diff -u pplinux/linuxnew/drivers/i2c/i2c-core.c:1.1.323.1 pplinux/linuxnew/drivers/i2c/i2c-core.c:1.4
--- pplinux/linuxnew/drivers/i2c/i2c-core.c:1.1.323.1	Thu Feb  3 10:00:38 2005
+++ pplinux/linuxnew/drivers/i2c/i2c-core.c	Tue Feb 15 12:19:53 2005
@@ -390,12 +390,12 @@
 	return 0;
 }
 
-int i2c_attach_client(struct i2c_client *client)
+int i2c_attach_client_internal(struct i2c_client *client, int force)
 {
 	struct i2c_adapter *adapter = client->adapter;
 	int i;
 
-	if (i2c_check_addr(client->adapter,client->addr))
+	if (!force && i2c_check_addr(client->adapter,client->addr))
 		return -EBUSY;
 
 	for (i = 0; i < I2C_CLIENT_MAX; i++)
@@ -425,6 +425,16 @@
 	return 0;
 }
 
+int i2c_attach_client(struct i2c_client *client)
+{
+	return i2c_attach_client_internal(client, 0);
+}
+
+int i2c_attach_client_force(struct i2c_client *client)
+{
+	return i2c_attach_client_internal(client, 1);
+}
+
 
 int i2c_detach_client(struct i2c_client *client)
 {
@@ -803,6 +813,53 @@
 	}
 }
 
+int i2c_slave_send(struct i2c_client *client, char* buf, int count)
+{
+	struct i2c_adapter *adap=client->adapter;
+	int ret = 0;
+
+	if (client->adapter->algo->slave_send) {
+               
+		DEB2(printk("i2c-core.o: slave_send: trying to send %d bytes on %s.\n",
+			    count,client->adapter->name));
+
+		I2C_LOCK(adap);
+		ret = adap->algo->slave_send(adap, buf, count);
+		I2C_UNLOCK(adap);
+
+		return (ret == 0)? count : ret;    
+	} else {
+		printk("i2c-core.o: I2C adapter %04x: I2C slave send not supported\n",
+		       client->adapter->id);
+		return -ENOSYS;
+	}
+
+}
+
+int i2c_slave_recv(struct i2c_client *client, char* buf, int count)
+{
+	struct i2c_adapter *adap=client->adapter;
+	int ret = 0;
+
+	if (client->adapter->algo->slave_recv) {
+
+		DEB2(printk("i2c-core.o: slave_recv: trying to receive %d bytes on %s.\n",
+			    count,client->adapter->name));
+
+		I2C_LOCK(adap);
+		ret = adap->algo->slave_recv(adap, buf, count);
+		I2C_UNLOCK(adap);
+
+		DEB2(printk("i2c-core.o: slave_recv: return:%d (count:%d, addr:0x%02x)\n",
+			    ret, count, client->addr));
+
+		return ret;
+	} else {
+		printk("i2c-core.o: I2C adapter %04x: I2C slave receive not supported\n",
+		       client->adapter->id);
+		return -ENOSYS;
+	}
+}
 
 int i2c_control(struct i2c_client *client,
 	unsigned int cmd, unsigned long arg)
@@ -830,9 +887,10 @@
  * Will not work for 10-bit addresses!
  * ----------------------------------------------------
  */
-int i2c_probe(struct i2c_adapter *adapter,
+int i2c_probe_internal(struct i2c_adapter *adapter,
                    struct i2c_client_address_data *address_data,
-                   i2c_client_found_addr_proc *found_proc)
+                   i2c_client_found_addr_proc *found_proc,
+                   int force)
 {
 	int addr,i,found,err;
 	int adap_id = i2c_adapter_id(adapter);
@@ -844,7 +902,7 @@
 	for (addr = 0x00; addr <= 0x7f; addr++) {
 
 		/* Skip if already in use */
-		if (i2c_check_addr(adapter,addr))
+		if (!force && i2c_check_addr(adapter,addr))
 			continue;
 
 		/* If it is in one of the force entries, we don't do any detection
@@ -951,6 +1009,20 @@
 	return 0;
 }
 
+int i2c_probe(struct i2c_adapter *adapter,
+                   struct i2c_client_address_data *address_data,
+                   i2c_client_found_addr_proc *found_proc)
+{
+	return i2c_probe_internal(adapter, address_data, found_proc, 0);
+}
+
+int i2c_probe_force(struct i2c_adapter *adapter,
+                   struct i2c_client_address_data *address_data,
+                   i2c_client_found_addr_proc *found_proc)
+{
+	return i2c_probe_internal(adapter, address_data, found_proc, 1);
+}
+
 /*
  * return id number for a specific adapter
  */
@@ -1350,6 +1422,7 @@
 EXPORT_SYMBOL(i2c_add_driver);
 EXPORT_SYMBOL(i2c_del_driver);
 EXPORT_SYMBOL(i2c_attach_client);
+EXPORT_SYMBOL(i2c_attach_client_force);
 EXPORT_SYMBOL(i2c_detach_client);
 EXPORT_SYMBOL(i2c_inc_use_client);
 EXPORT_SYMBOL(i2c_dec_use_client);
@@ -1365,6 +1438,10 @@
 EXPORT_SYMBOL(i2c_transfer);
 EXPORT_SYMBOL(i2c_adapter_id);
 EXPORT_SYMBOL(i2c_probe);
+EXPORT_SYMBOL(i2c_probe_force);
+
+EXPORT_SYMBOL(i2c_slave_recv);
+EXPORT_SYMBOL(i2c_slave_send);
 
 EXPORT_SYMBOL(i2c_smbus_xfer);
 EXPORT_SYMBOL(i2c_smbus_write_quick);
Index: pplinux/linuxnew/drivers/i2c/i2c-dev.c
diff -u pplinux/linuxnew/drivers/i2c/i2c-dev.c:1.1.323.1 pplinux/linuxnew/drivers/i2c/i2c-dev.c:1.3
--- pplinux/linuxnew/drivers/i2c/i2c-dev.c:1.1.323.1	Thu Feb  3 10:00:38 2005
+++ pplinux/linuxnew/drivers/i2c/i2c-dev.c	Tue Feb 15 12:19:53 2005
@@ -42,7 +42,7 @@
 
 
 /* If you want debugging uncomment: */
-/* #define DEBUG */
+#define DEBUG
 
 #include <linux/init.h>
 #include <asm/uaccess.h>
@@ -146,7 +146,11 @@
 	       count);
 #endif
 
-	ret = i2c_master_recv(client,tmp,count);
+	if (client->flags & I2C_CLIENT_RECV_SLAVE) {
+		ret = i2c_slave_recv(client,tmp,count);
+	} else {
+		ret = i2c_master_recv(client,tmp,count);
+	}
 	if (ret >= 0)
 		ret = copy_to_user(buf,tmp,count)?-EFAULT:ret;
 	kfree(tmp);
@@ -379,6 +383,14 @@
 		}
 		return res;
 
+	case I2C_SLAVE_MODE_ENABLE:
+		client->flags |= I2C_CLIENT_RECV_SLAVE;
+		break;
+
+	case I2C_SLAVE_MODE_DISABLE:
+		client->flags &= ~I2C_CLIENT_RECV_SLAVE;
+		break;
+
 	default:
 		return i2c_control(client,cmd,arg);
 	}
Index: pplinux/linuxnew/drivers/i2c/i2c-ibm_iic.c
diff -u pplinux/linuxnew/drivers/i2c/i2c-ibm_iic.c:1.1.323.1 pplinux/linuxnew/drivers/i2c/i2c-ibm_iic.c:1.3
--- pplinux/linuxnew/drivers/i2c/i2c-ibm_iic.c:1.1.323.1	Thu Feb  3 10:00:38 2005
+++ pplinux/linuxnew/drivers/i2c/i2c-ibm_iic.c	Fri Apr 29 10:43:29 2005
@@ -37,11 +37,16 @@
 #include <asm/io.h>
 #include <linux/i2c.h>
 #include <linux/i2c-id.h>
+#include <linux/i2c-slave.h>
 #include <asm/ocp.h>
+#include <asm/errno.h>
+#include <asm/uaccess.h>
 
 #include "i2c-ibm_iic.h"
 
-#define DRIVER_VERSION "2.0"
+#define BUS_TIMEOUT	1
+
+#define DRIVER_VERSION "2.1"
 
 MODULE_DESCRIPTION("IBM IIC driver v" DRIVER_VERSION);
 MODULE_LICENSE("GPL");
@@ -56,19 +61,36 @@
 
 static int iic_force_fast = 0;
 MODULE_PARM(iic_force_fast, "i");
-MODULE_PARM_DESC(iic_fast_poll, "Force fast mode (400 kHz)");
+MODULE_PARM_DESC(iic_force_fast, "Force fast mode (400 kHz)");
+
+static int iic_own_addr = 0x55;
+MODULE_PARM(iic_own_addr, "i");
+MODULE_PARM_DESC(iic_own_addr, "Our own slave address");
+
+/* slave mode */
+static void iic_slave_init(void);
+static void iic_handle_slave(struct ibm_iic_private* dev,
+			     unsigned char status,
+			     unsigned char ext_status,
+			     unsigned char slave_status,
+			     unsigned char xfer_cnt);
+static int iic_slave_set_address(struct i2c_adapter *adap,
+                                 unsigned int address);
+static int iic_slave_restart_xfer(struct i2c_adapter* adapter);
+static int iic_slave_init_adapter(struct i2c_adapter* adapter);
+static int iic_slave_cleanup_adapter(void);
 
 #define DBG_LEVEL 0
 
 #if DBG_LEVEL > 0
-#  define DBG(x...)	printk(KERN_DEBUG "ibm-iic" ##x)
+#  define DBG(fmt, x...)	printk(KERN_DEBUG "ibm-iic" fmt, ##x)
 #else
-#  define DBG(x...)	((void)0)
+#  define DBG(fmt, x...)	((void)0)
 #endif
 #if DBG_LEVEL > 1
-#  define DBG2(x...) 	DBG( ##x )
+#  define DBG2(fmt, x...) 	DBG( fmt, ##x )
 #else
-#  define DBG2(x...) 	((void)0)
+#  define DBG2(fmt, x...) 	((void)0)
 #endif
 #if DBG_LEVEL > 2
 static void dump_iic_regs(const char* header, struct ibm_iic_private* dev)
@@ -78,20 +100,60 @@
 	printk(KERN_DEBUG "  cntl     = 0x%02x, mdcntl = 0x%02x\n"
 	       KERN_DEBUG "  sts      = 0x%02x, extsts = 0x%02x\n"
 	       KERN_DEBUG "  clkdiv   = 0x%02x, xfrcnt = 0x%02x\n"
-	       KERN_DEBUG "  xtcntlss = 0x%02x, directcntl = 0x%02x\n",
+	       KERN_DEBUG "  xtcntlss = 0x%02x, directcntl = 0x%02x\n"
+#if DBG_LEVEL > 3
+	       KERN_DEBUG "  lmadr    = 0x%02x, hmadr  = 0x%02x\n"
+	       KERN_DEBUG "  lsadr    = 0x%02x, hsadr  = 0x%02x\n"
+	       KERN_DEBUG "  intmsk   = 0x%02x\n"
+#endif
+	       ,
 		in_8(&iic->cntl), in_8(&iic->mdcntl), in_8(&iic->sts), 
 		in_8(&iic->extsts), in_8(&iic->clkdiv), in_8(&iic->xfrcnt), 
-		in_8(&iic->xtcntlss), in_8(&iic->directcntl));
+		in_8(&iic->xtcntlss), in_8(&iic->directcntl)
+#if DBG_LEVEL > 3
+		,
+		in_8(&iic->lmadr), in_8(&iic->hmadr),
+		in_8(&iic->lsadr), in_8(&iic->hsadr),
+		in_8(&iic->intmsk)
+#endif
+		);
 }
 #  define DUMP_REGS(h,dev)	dump_iic_regs((h),(dev))
 #else
 #  define DUMP_REGS(h,dev)	((void)0)
 #endif
 
+#define WARN(fmt, x...)	printk(KERN_WARNING "ibm-iic" fmt, ##x)
+
+/* Bus timings (in ns) for bit-banging */
+static struct i2c_timings {
+	unsigned int hd_sta;
+	unsigned int su_sto;
+	unsigned int low;
+	unsigned int high;
+	unsigned int buf;
+} timings [] = {
+/* Standard mode (100 KHz) */
+{
+	.hd_sta= 4000,
+	.su_sto= 4000,
+	.low= 4700,
+	.high= 4000,
+	.buf= 4700,
+},
+/* Fast mode (400 KHz) */
+{
+	.hd_sta = 600,
+	.su_sto= 600,
+	.low = 1300,
+	.high = 600,
+	.buf= 1300,
+}};
+
 /* Enable/disable interrupt generation */
 static inline void iic_interrupt_mode(struct ibm_iic_private* dev, int enable)
 {
-	out_8(&dev->vaddr->intmsk, enable ? INTRMSK_EIMTC : 0);
+	out_8(&dev->vaddr->intmsk, enable ? INTRMSK_EIRC | INTRMSK_EIRS | INTRMSK_EIMTC | INTRMSK_EIWC | INTRMSK_EIWS : 0);
 }
  
 /*
@@ -102,13 +164,13 @@
 	volatile struct iic_regs *iic = dev->vaddr;
 
 	DBG("%d: init\n", dev->idx);
-	
+
 	/* Clear master address */
 	out_8(&iic->lmadr, 0);
 	out_8(&iic->hmadr, 0);
 
-	/* Clear slave address */
-	out_8(&iic->lsadr, 0);
+	/* Set slave address */
+	out_8(&iic->lsadr, iic_own_addr << 1);
 	out_8(&iic->hsadr, 0);
 
 	/* Clear status & extended status */
@@ -133,8 +195,9 @@
 	iic_interrupt_mode(dev, dev->irq >= 0);
 
 	/* Set mode control */
-	out_8(&iic->mdcntl, MDCNTL_FMDB | MDCNTL_EINT | MDCNTL_EUBS
-			    | (dev->fast_mode ? MDCNTL_FSM : 0));
+	out_8(&iic->mdcntl, MDCNTL_FSDB | MDCNTL_FMDB | MDCNTL_ESM
+	      | MDCNTL_EINT | MDCNTL_EUBS | MDCNTL_HSCL
+	      | (dev->fast_mode ? MDCNTL_FSM : 0));
 
 	DUMP_REGS("iic_init", dev);
 }
@@ -189,18 +252,135 @@
 }
 
 /*
+ * Do 0-length transaction using bit-banging through IIC_DIRECTCNTL register.
+ */
+
+/* Wait for SCL and/or SDA to be high */
+static int iic_dc_wait(volatile struct iic_regs *iic, u8 mask)
+{
+	unsigned long x = jiffies + HZ / 28 + 2;
+	while ((in_8(&iic->directcntl) & mask) != mask){
+		if (unlikely(time_after(jiffies, x)))
+			return -1;
+		cond_resched();
+	}
+	return 0;
+}
+
+static int iic_smbus_quick(struct ibm_iic_private* dev, const struct i2c_msg* p)
+{
+	volatile struct iic_regs* iic = dev->vaddr;
+	const struct i2c_timings* t = &timings[dev->fast_mode ? 1 : 0];
+	u8 mask, v, sda;
+	int i, res;
+
+	/* Only 7-bit addresses are supported */
+	if (unlikely(p->flags & I2C_M_TEN)){
+		DBG("%d: smbus_quick - 10 bit addresses are not supported\n",
+			dev->idx);
+		return -EINVAL;
+	}
+
+	DBG("%d: smbus_quick(0x%02x)\n", dev->idx, p->addr);
+	
+	/* Reset IIC interface */
+	out_8(&iic->xtcntlss, XTCNTLSS_SRST);
+
+	/* Wait for bus to become free */
+	out_8(&iic->directcntl, DIRCNTL_SDAC | DIRCNTL_SCC);
+	if (unlikely(iic_dc_wait(iic, DIRCNTL_MSDA | DIRCNTL_MSC)))
+		goto err;
+	ndelay(t->buf);
+
+	/* START */
+	out_8(&iic->directcntl, DIRCNTL_SCC);
+	sda = 0;
+	ndelay(t->hd_sta);
+
+	/* Send address */
+	v = (u8)((p->addr << 1) | ((p->flags & I2C_M_RD) ? 1 : 0));
+	for (i = 0, mask = 0x80; i < 8; ++i, mask >>= 1){
+		out_8(&iic->directcntl, sda);
+		ndelay(t->low / 2);
+		sda = (v & mask) ? DIRCNTL_SDAC : 0;
+		out_8(&iic->directcntl, sda);
+		ndelay(t->low / 2);
+
+		out_8(&iic->directcntl, DIRCNTL_SCC | sda);
+		if (unlikely(iic_dc_wait(iic, DIRCNTL_MSC)))
+			goto err;
+		ndelay(t->high);
+	}
+
+	/* ACK */
+	out_8(&iic->directcntl, sda);
+	ndelay(t->low / 2);
+	out_8(&iic->directcntl, DIRCNTL_SDAC);
+	ndelay(t->low / 2);
+	out_8(&iic->directcntl, DIRCNTL_SDAC | DIRCNTL_SCC);
+	if (unlikely(iic_dc_wait(iic, DIRCNTL_MSC)))
+		goto err;
+	res = (in_8(&iic->directcntl) & DIRCNTL_MSDA) ? -EREMOTEIO : 1;
+	ndelay(t->high);
+
+	/* STOP */
+	out_8(&iic->directcntl, 0);
+	ndelay(t->low);
+	out_8(&iic->directcntl, DIRCNTL_SCC);
+	if (unlikely(iic_dc_wait(iic, DIRCNTL_MSC)))
+		goto err;
+	ndelay(t->su_sto);
+	out_8(&iic->directcntl, DIRCNTL_SDAC | DIRCNTL_SCC);
+
+	ndelay(t->buf);
+
+	DBG("%d: smbus_quick -> %s\n", dev->idx, res < 0 ? "NACK" : "ACK");
+out:
+	/* Remove reset */
+	out_8(&iic->xtcntlss, 0);
+
+	/* Reinitialize interface */
+	iic_dev_init(dev);
+
+	return res;
+err:
+	DBG("%d: smbus_quick - bus is stuck\n", dev->idx);
+	res = -EREMOTEIO;
+	goto out;
+}
+
+/*
  * IIC interrupt handler
  */
 static void iic_handler(int irq, void *dev_id, struct pt_regs *regs)
 {
 	struct ibm_iic_private* dev = (struct ibm_iic_private*)dev_id;
 	volatile struct iic_regs* iic = dev->vaddr;
+	unsigned char status, ext_status, slave_status, xfer_cnt;
+
+	status = in_8(&iic->sts);
+	ext_status = in_8(&iic->extsts);
+	slave_status = in_8(&iic->xtcntlss);
+	xfer_cnt = in_8(&iic->xfrcnt);
+
+	DBG2("%d: irq handler, STS = 0x%02x, EXTSTS = 0x%02x, XTCNTLSS = 0x%02x\n", 
+	     dev->idx, status, ext_status, slave_status);
+#if DBG_LEVEL > 2
+	DBG2("%d: irq handler, CNTL = 0x%02x, MDCNTL = 0x%02x, DIRECTCNTL = 0x%02x, XFRCNT = 0x%02x\n",
+	     dev->idx, in_8(&iic->cntl), in_8(&iic->mdcntl),
+	     in_8(&iic->directcntl), xfer_cnt);
+#endif
 	
-	DBG2("%d: irq handler, STS = 0x%02x, EXTSTS = 0x%02x\n", 
-	     dev->idx, in_8(&iic->sts), in_8(&iic->extsts));
+
+	/* look if we got a slave related irq */
+	if (slave_status & (XTCNTLSS_SWC | XTCNTLSS_SWS | XTCNTLSS_SRS | XTCNTLSS_SRC)) {
+		iic_handle_slave(dev, status, ext_status, slave_status, xfer_cnt);
+	}
 	
 	/* Acknowledge IRQ and wakeup iic_wait_for_tc */
-	out_8(&iic->sts, STS_IRQA | STS_SCMP);
+	out_8(&iic->extsts, ext_status);
+	out_8(&iic->sts, status);
+
 	wake_up_interruptible(&dev->wq);
 }
 
@@ -273,6 +453,7 @@
  * It puts current process to sleep until we get interrupt or timeout expires.
  * Returns the number of transferred bytes or error (<0)
  */
+
 static int iic_wait_for_tc(struct ibm_iic_private* dev){
 	
 	volatile struct iic_regs *iic = dev->vaddr;
@@ -425,11 +606,16 @@
  * Generic master transfer entrypoint. 
  * Returns the number of processed messages or error (<0)
  */
+
+#define BUS_WAIT_TIME		100
+#define BUS_WAIT_RETRIES	1000
+
 static int iic_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
 {
     	struct ibm_iic_private* dev = (struct ibm_iic_private*)(adap->data);
 	volatile struct iic_regs *iic = dev->vaddr;
 	int i, ret = 0;
+	u8 extsts;
 	
 	DBG2("%d: iic_xfer, %d msg(s)\n", dev->idx, num);
 	
@@ -446,6 +632,13 @@
 	}		
 	for (i = 0; i < num; ++i){
 		if (unlikely(msgs[i].len <= 0)){
+			if (num == 1 && !msgs[0].len){
+				/* Special case for I2C_SMBUS_QUICK emulation.
+				 * IBM IIC doesn't support 0-length transactions
+				 * so we have to emulate them using bit-banging.
+				 */
+				return iic_smbus_quick(dev, &msgs[0]);
+			}
 			DBG("%d: invalid len %d in msg[%d]\n", dev->idx, 
 				msgs[i].len, i);
 			return -EINVAL;
@@ -457,21 +650,28 @@
 	}
 	
 	/* Check bus state */
-	if (unlikely((in_8(&iic->extsts) & EXTSTS_BCS_MASK) != EXTSTS_BCS_FREE)){
+	if (unlikely(((extsts = in_8(&iic->extsts)) & EXTSTS_BCS_MASK) != EXTSTS_BCS_FREE)){
+		int retries = 0;
 		DBG("%d: iic_xfer, bus is not free\n", dev->idx);
 		
-		/* Usually it means something serious has happend.
-		 * We *cannot* have unfinished previous transfer
-		 * so it doesn't make any sense to try to stop it.
-		 * Probably we were not able to recover from the 
-		 * previous error.
-		 * The only *reasonable* thing I can think of here
-		 * is soft reset.  --ebs
+		/* There might be another operation in progress,
+		 * (slave operation). Wait for it to end.
+		 */
+		do {
+			udelay(BUS_WAIT_TIME);
+			retries++;
+			extsts = in_8(&iic->extsts);
+		} while (((extsts & EXTSTS_BCS_MASK) != EXTSTS_BCS_FREE) && retries < BUS_WAIT_RETRIES);
+		
+		/* If the bus is still not free, reset the i2c interface
 		 */
-		iic_dev_reset(dev);
+		if ((extsts & EXTSTS_BCS_MASK) != EXTSTS_BCS_FREE) {
+			WARN("%d: iic_xfer, bus is still not free, resetting\n", dev->idx);
+			iic_dev_reset(dev);
+		}
 		
 		if ((in_8(&iic->extsts) & EXTSTS_BCS_MASK) != EXTSTS_BCS_FREE){
-			DBG("%d: iic_xfer, bus is still not free\n", dev->idx);
+			WARN("%d: iic_xfer, bus is still not free\n", dev->idx);
 			return -EREMOTEIO;
 		}
 	} 
@@ -479,7 +679,7 @@
 		/* Flush master data buffer (just in case) */
 		out_8(&iic->mdcntl, in_8(&iic->mdcntl) | MDCNTL_FMDB);
 	}
-	
+		
 	/* Load slave address */
 	iic_address(dev, &msgs[0]);
 	
@@ -490,6 +690,22 @@
 	return ret < 0 ? ret : num;
 }
 
+static int iic_algo_control(struct i2c_adapter *adap, 
+			    unsigned int cmd, unsigned long arg)
+{
+	switch (cmd) {
+	  case I2C_SLAVE_SET_ADDRESS:
+		iic_slave_set_address(adap, (unsigned int) arg);
+		break;
+	  case I2C_SLAVE_FLUSH_BUFFER:
+		iic_slave_restart_xfer(adap);
+		break;
+	  default:
+		return -1;
+	}
+	return 0;
+}
+
 static u32 iic_func(struct i2c_adapter *adap)
 {
 	return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_10BIT_ADDR;
@@ -502,10 +718,12 @@
 	.smbus_xfer	= NULL,
 	.slave_send	= NULL,
 	.slave_recv	= NULL,
-	.algo_control	= NULL,
+	.algo_control	= iic_algo_control,
 	.functionality	= iic_func
 };
 
+
+
 /*
  * Scan bus for valid 7-bit addresses (ie things that ACK on 1 byte read)
  * We only scan range [0x08 - 0x77], all other addresses are reserved anyway
@@ -625,11 +843,11 @@
 	/* clckdiv is the same for *all* IIC interfaces, 
 	 * but I'd rather make a copy than introduce another global. --ebs
 	 */
-	dev->clckdiv = iic_clckdiv(bd->bi_opbfreq);
+	dev->clckdiv = iic_clckdiv(bd->bi_opb_busfreq);
 	DBG("%d: clckdiv = %d\n", dev->idx, dev->clckdiv);
 	
-	/* Initialize IIC interface */
-	iic_dev_init(dev);
+	/* Reset and reinitialize IIC interface */
+	iic_dev_reset(dev);
 	
 	/* Register it with i2c layer */
 	adap = &dev->adap;
@@ -641,7 +859,7 @@
 	adap->dec_use = iic_dec_use;
 	adap->client_register = NULL;
 	adap->client_unregister = NULL;
-	adap->timeout = 1;
+	adap->timeout = BUS_TIMEOUT;
 	adap->retries = 1;
 
 	if ((ret = i2c_add_adapter(adap)) != 0){
@@ -657,6 +875,11 @@
 	if (iic_scan)
 		iic_scan_bus(dev);
 
+	/* register slave mode */
+	if (iic_slave_init_adapter(adap) != 0) {
+		goto fail;
+	}
+	
 	return 0;
 
 fail:	
@@ -696,6 +919,9 @@
 		iounmap((void*)dev->vaddr);
 		kfree(dev);
 	}
+	
+	/* register slave mode */
+	iic_slave_cleanup_adapter();
 }
 
 static struct ocp_device_id ibm_iic_ids[] =
@@ -721,6 +947,10 @@
 		ocp_unregister_driver(&ibm_iic_driver);
 		return -ENODEV;
 	}
+	
+	/* Initialize slave mode */
+	iic_slave_init();
+
 	return 0;
 }
 
@@ -729,5 +959,458 @@
 	ocp_unregister_driver(&ibm_iic_driver);
 }
 
+/*****************************************************************************
+ * slave mode functions
+ ****************************************************************************/
+
+#define SLAVE_BUF_SIZE 512
+
+/* slave lock object */
+static spinlock_t      slave_lock = SPIN_LOCK_UNLOCKED;
+
+/* slave write buffer */
+static unsigned char * slave_write_ptr;
+static unsigned int    slave_write_count;
+static unsigned char   slave_write_buffer[SLAVE_BUF_SIZE];
+
+/* slave read buffer */
+static unsigned char * slave_read_ptr;
+static unsigned int    slave_read_count;
+static unsigned char   slave_read_buffer[SLAVE_BUF_SIZE];
+
+/* status flags */
+static int block_next_slave_operation = 0;
+static int slave_write_was_blocked = 0;
+static int blocked_write_msg_complete = 0;
+static int slave_read_was_blocked = 0;
+static int blocked_read_msg_read_cmd = 0;
+
+/* function prototypes */
+static unsigned char iic_handle_slave_write(struct ibm_iic_private* dev,
+                                            unsigned char slave_status);
+static int iic_handle_slave_write_complete(struct ibm_iic_private* dev);
+static unsigned char iic_handle_slave_read(struct ibm_iic_private* dev,
+                                           unsigned char slave_status,
+                                           int read_command);
+
+/* Initialize slave buffers */
+static void iic_slave_init()
+{
+	unsigned long flags;
+
+        spin_lock_irqsave(&slave_lock, flags);
+        slave_write_ptr = slave_write_buffer;
+        slave_write_count = 0;
+        slave_read_ptr = slave_read_buffer;
+        slave_read_count = 0;
+        spin_unlock_irqrestore(&slave_lock, flags);
+}
+
+struct i2c_slave_adapter slave_adapt;
+
+/* register adapter in slave layer */
+static int iic_slave_init_adapter(struct i2c_adapter *adap)
+{
+	struct ibm_iic_private* dev = (struct ibm_iic_private*)(adap->data);
+	int ret = 0;
+
+	slave_adapt.adapter = adap;
+	slave_adapt.reactivate = iic_slave_restart_xfer;
+	if ((ret = i2c_slave_add_adapter(&slave_adapt)) != 0){
+		printk(KERN_CRIT "ibm-iic%d: failed to register i2c slave adapter\n",
+			dev->idx);
+		return ret;
+	}
+	
+	return 0;
+}
+
+/* deregister */
+static int iic_slave_cleanup_adapter()
+{
+	struct ibm_iic_private* dev;
+	struct i2c_adapter *adap;
+	int ret;
+	
+	adap = slave_adapt.adapter;
+	dev = (struct ibm_iic_private*)(adap->data);
+	
+	if ((ret = i2c_slave_remove_adapter(&slave_adapt)) != 0){
+		printk(KERN_CRIT "ibm-iic%d: failed to deregister i2c slave adapter\n",
+			dev->idx);
+		return ret;
+	}
+	
+	return 0;
+}
+
+/* set own slave address */
+static int iic_slave_set_address(struct i2c_adapter *adap, unsigned int address)
+{
+	struct ibm_iic_private* dev = (struct ibm_iic_private*)(adap->data);
+	volatile struct iic_regs *iic = dev->vaddr;
+	unsigned char reg;
+
+	reg = in_8(&iic->mdcntl);
+	out_8(&iic->mdcntl, reg & ~MDCNTL_ESM);
+	out_8(&iic->lsadr, (address & 0x7f) << 1);
+	out_8(&iic->hsadr, 0);
+	out_8(&iic->mdcntl, reg | (MDCNTL_FSDB | MDCNTL_ESM));
+	DBG ("%d: set i2c slave address to 0x%x\n", dev->idx, address);
+	reg = in_8(&iic->lsadr);
+	if (((reg >> 1) & 0x7f) != address) {
+		printk(KERN_WARNING "ibm-iic%d: could not set i2c slave address, result is 0x%02x",
+			dev->idx, reg);
+	}
+	DBG ("%d: verify slave address: 0x%02x\n", dev->idx, reg);
+	
+	return 0;
+}
+
+/* after the bus is gone down, reactivate transfer */
+static int iic_slave_restart_xfer(struct i2c_adapter* adapter)
+{
+    	struct ibm_iic_private* dev = (struct ibm_iic_private*)(adapter->data);
+	volatile struct iic_regs *iic = dev->vaddr;	
+	unsigned char slave_status;
+	unsigned long flags;
+	
+        spin_lock_irqsave(&slave_lock, flags);
+        
+        /* the next message shall be blocked, but no blocked message read yet
+           --> just deliver the last message */
+        if (block_next_slave_operation && !slave_write_was_blocked && !slave_read_was_blocked) {
+        	block_next_slave_operation = 0;
+		if (iic_handle_slave_write_complete(dev) < 0) {
+			DBG("%d: cannot put data to i2c-slave layer, next operation will be blocked.\n",
+				dev->idx);
+			block_next_slave_operation = 1;
+			
+			goto bail;
+		}
+        }
+        else {
+        	block_next_slave_operation = 0;
+        }
+        
+        if (slave_write_was_blocked) {
+        	/* deliver the last message */
+		if (iic_handle_slave_write_complete(dev) < 0) {
+			DBG("%d: cannot put data to i2c-slave layer, next operation will be blocked.\n",
+				dev->idx);
+			block_next_slave_operation = 1;
+			
+			goto bail;
+		}
+		
+		/* read the next message, if the flush of the first message succeeded */
+		slave_status = in_8(&iic->xtcntlss);
+		
+		slave_status = iic_handle_slave_write(dev, slave_status);
+		
+		/* deliver the next message if complete */
+		if (blocked_write_msg_complete) {
+			if (iic_handle_slave_write_complete(dev) < 0) {
+				DBG("%d: cannot put data to i2c-slave layer, next operation will be blocked.\n",
+					dev->idx);
+				block_next_slave_operation = 1;
+			}
+		}
+		
+		DUMP_REGS("iic_slave_restart_xfer", dev);
+		
+		out_8(&iic->xtcntlss, slave_status);
+        }
+        
+        if (slave_read_was_blocked) {
+		slave_status = in_8(&iic->xtcntlss);
+		
+		/* don't handle the read request here, no master will read data */
+		/* slave_status = iic_handle_slave_read(dev, slave_status, blocked_read_msg_read_cmd); */
+
+		out_8(&iic->xtcntlss, slave_status);
+        }
+
+bail:
+        spin_unlock_irqrestore(&slave_lock, flags);
+        
+        return 0;
+}
+
+/* handle i2c slave write requests */
+static unsigned char iic_handle_slave_write(struct ibm_iic_private* dev,
+                                            unsigned char slave_status)
+{
+	volatile struct iic_regs *iic = dev->vaddr;	
+
+	/* write bytes received to buffer */
+	while (slave_status & XTCNTLSS_SBDD) {
+		slave_write_count++;
+
+		*slave_write_ptr = in_8((volatile u8 *)&iic->sbbuf);
+
+		DBG2("%d: iic_handle_slave_write: putting byte 0x%02x (slave_status=0x%02x)\n",
+			dev->idx, *slave_write_ptr, slave_status);
+
+		/* avoid buffer overrun here */
+		if (slave_write_ptr < slave_write_buffer + SLAVE_BUF_SIZE) {
+			slave_write_ptr++;
+		}
+
+		slave_status = in_8(&iic->xtcntlss);
+	}
+
+	return slave_status;
+}
+
+/* if a slave write is complete, push the data up
+   to the upper i2c-slave level */
+static int iic_handle_slave_write_complete(struct ibm_iic_private* dev)
+{
+	int ret = 0;
+	struct i2c_adapter *adap = &dev->adap;
+	
+	if (slave_write_count <= 0) {
+		return slave_write_count;
+	}
+	
+	/* copy the written data to the upper I2C slave layer */
+	int written_bytes = iic_slave_write(adap, slave_write_buffer, slave_write_count);
+	if (written_bytes < 0) {
+		printk(KERN_WARNING "ibm-iic%d: iic_handle_slave_write_complete: error exporting data to i2c-slave layer: %d!\n",
+			dev->idx, written_bytes);
+		ret = -ENOMEM;
+	}
+	else if (written_bytes == 0) {
+		DBG2("%d: iic_handle_slave_write_complete: 0 bytes to i2c-slave layer exported!\n",
+			dev->idx);
+	}
+	else if (written_bytes >= slave_write_count) {
+		DBG2("%d: iic_handle_slave_write_complete: moved %d bytes to i2c-slave layer.\n",
+			dev->idx, written_bytes);
+		slave_write_ptr = slave_write_buffer;
+		slave_write_count = 0;
+	}
+	else {
+		// only a partial copy
+		DBG2("%d: iic_handle_slave_write_complete: moved %d bytes to i2c-slave layer, %d bytes requested.\n",
+			dev->idx, written_bytes, slave_write_count);
+		slave_write_ptr -= written_bytes;
+		slave_write_count -= written_bytes;
+	}
+	
+	return ret;
+}
+
+/* handle first slave read interrupt of an i2c message
+   fetches data from upper i2c slave level */
+static void iic_handle_slave_first_read(struct ibm_iic_private* dev,
+                                        int command)
+{
+	struct i2c_adapter *adap = &dev->adap;
+
+	DBG2("%d: iic_handle_slave_first_read: Fetching slave read data from i2c-slave layer.\n", dev->idx);
+	
+        slave_read_ptr = slave_read_buffer;
+        slave_read_count = iic_slave_read(adap, slave_read_buffer, SLAVE_BUF_SIZE, command);
+        
+        if (slave_read_count > 0) {
+        	DBG2("%d: iic_handle_slave_first_read: Got %d bytes.\n", dev->idx, slave_read_count);
+        }
+        else {
+        	DBG("%d: iic_handle_slave_first_read: cannot read bytes.\n", dev->idx);
+        }
+}
+
+/* handle an i2c slave read request */
+static unsigned char iic_handle_slave_read(struct ibm_iic_private* dev,
+                                           unsigned char slave_status,
+                                           int read_command)
+{
+	volatile struct iic_regs *iic = dev->vaddr;	
+
+	int command_read = 0;
+	int command = 0;
+	unsigned char data = 0;
+	
+	while (read_command && (slave_status & XTCNTLSS_SBDD)) {
+		command_read = 1;
+		command <<= 8;
+		command |= in_8((volatile u8 *)&iic->sbbuf) & 0xff;
+		DBG2("%d: iic_handle_slave_read: read command 0x%02x\n",
+			dev->idx, command);
+		slave_status = in_8(&iic->xtcntlss);
+	}
+	
+	if (!command_read) {
+		command = -1;
+	}
+	
+	if (slave_read_count <= 0) {
+		iic_handle_slave_first_read(dev, command);
+	}
+	
+	if (slave_read_count > 0) {
+		/* avoid buffer overrun here */
+		if (slave_read_ptr < slave_read_buffer + slave_read_count) {
+			data = *slave_read_ptr;
+			slave_read_ptr++;
+		}
+		else {
+			/* TODO: error handline here */
+			data = 0;
+			DBG("%d: iic_handle_slave_read: no data!\n", dev->idx);
+		}
+		
+		DBG2("%d: iic_handle_slave_read: sending byte 0x%02x\n", dev->idx, data);
+		
+		out_8((volatile u8 *)&iic->sbbuf, data);
+	}
+	else {
+		/* TODO: signal that we are not ready by not sending data */
+		out_8((volatile u8 *)&iic->sbbuf, 0);
+		DBG2("%d: iic_handle_slave_read: not ready, sending no byte\n", dev->idx);
+	}
+	
+	slave_status = in_8(&iic->xtcntlss);
+
+	return slave_status;
+}
+
+/* slave read completed */
+static void iic_handle_slave_read_complete(struct ibm_iic_private* dev)
+{
+	if (slave_read_ptr < slave_read_buffer + slave_read_count) {
+		DBG2("%d: iic_handle_slave_read_complete: not all data was read! amount: %d, read: %d\n",
+			dev->idx, slave_read_count, slave_read_ptr - slave_read_buffer);
+	}
+        else {
+		DBG2("%d: iic_handle_slave_read_complete: read %d bytes\n", dev->idx, slave_read_ptr - slave_read_buffer);
+	}
+	
+	slave_read_ptr = slave_read_buffer;
+	slave_read_count = 0;
+}
+
+/* handle iic slave interrupt */
+static void iic_handle_slave(struct ibm_iic_private* dev,
+			     unsigned char status,
+			     unsigned char ext_status,
+			     unsigned char slave_status,
+			     unsigned char xfer_cnt)
+{
+	volatile struct iic_regs *iic = dev->vaddr;	
+	unsigned char count;
+	unsigned long flags;
+	
+	int is_slave_write_request = 0;
+	int is_slave_write_complete = 0;
+	int is_slave_read_request = 0;
+	int is_slave_read_complete = 0;
+	int slave_read_get_command = 0;
+
+	spin_lock_irqsave(&slave_lock, flags);
+
+	count = xfer_cnt;
+	count = count >> 4;
+	DBG2("%d: iic_handle_slave: slave count=0x%02x\n", dev->idx, count);
+	
+	/* find out which slave operation is to be performed */
+	
+	if (slave_status & XTCNTLSS_SWS) {
+		is_slave_write_request = 1;
+	}
+	if (slave_status & XTCNTLSS_SWC) {
+#if 1
+		/* I don't know how to savely detect a slave read operation,
+		   so we don't use it. So we assume that a slave write indeed
+		   is a slave write. */
+		is_slave_write_complete = 1;
+#else
+		if (!(slave_status & XTCNTLSS_SDBF) && (ext_status & EXTSTS_BCS_MASK) == EXTSTS_BCS_SLAVESEL) {
+#warning This works, but I do not think it is supposed to work this way!
+			/* This is a very ugly hack, but is the only way
+			 * to determine a slave read operation with an
+			 * address byte before the read request. The
+			 * driver doesn't get a "slave read needs service"
+			 * interrupt in that case. Instead, a "slave write
+			 * complete" interrupt occurs (with a bus in slave
+			 * selected state according to EXTSTS).
+			 * So if the slave buffer is not full (meaning no
+			 * write transfer pending) and the bus is in
+			 * slave selected state, we assume a slave read
+			 * operation here.
+			 */
+			is_slave_read_request = 1;
+			slave_read_get_command = 1;
+		}
+		else {
+			is_slave_write_complete = 1;
+		}
+#endif
+	}
+	if (slave_status & XTCNTLSS_SRS) {
+		is_slave_read_request = 1;
+	}
+	if (slave_status & XTCNTLSS_SRC) {
+		is_slave_read_complete = 1;
+	}
+	
+	/* reset the flags */
+	slave_write_was_blocked = 0;
+	blocked_write_msg_complete = 0;
+	slave_read_was_blocked = 0;
+	blocked_read_msg_read_cmd = 0;
+	
+	/* performe the requested operation */
+	
+	if (block_next_slave_operation) {
+		/* we block the slave operation by not reading data
+		   and not resetting the slave status */
+		if (is_slave_write_request) {
+			slave_write_was_blocked = 1;
+		}
+		
+		if (is_slave_write_complete) {
+			slave_write_was_blocked = 1;
+			blocked_write_msg_complete = 1;
+		}
+		
+		if (is_slave_read_request) {
+			slave_read_was_blocked = 1;
+			blocked_read_msg_read_cmd = slave_read_get_command;
+		}
+
+		slave_status &= ~(XTCNTLSS_SWC | XTCNTLSS_SWS | XTCNTLSS_SRC | XTCNTLSS_SRS);
+	}
+	else {
+		if (is_slave_write_request || is_slave_write_complete) {
+			slave_status = iic_handle_slave_write(dev, slave_status);
+			if (slave_status & XTCNTLSS_SWC) {
+				if (iic_handle_slave_write_complete(dev) < 0) {
+					DBG("%d: cannot put data to i2c-slave layer, next operation will be blocked.\n",
+						dev->idx);
+					block_next_slave_operation = 1;
+				}
+			}
+		}
+		
+		if (is_slave_read_request) {
+			slave_status = iic_handle_slave_read(dev, slave_status, slave_read_get_command);
+		}
+		
+		if (slave_status & XTCNTLSS_SRC) {
+			iic_handle_slave_read_complete(dev);
+		}
+	}
+
+	out_8(&iic->xtcntlss, slave_status);
+
+	DBG2("%d: iic_handle_slave: done (slave_status=0x%02x)\n", dev->idx, slave_status);
+
+	spin_unlock_irqrestore(&slave_lock, flags);
+}
+
+
 module_init(iic_init);
 module_exit(iic_exit);
Index: pplinux/linuxnew/drivers/i2c/i2c-ibm_iic.h
diff -u pplinux/linuxnew/drivers/i2c/i2c-ibm_iic.h:1.1.323.1 pplinux/linuxnew/drivers/i2c/i2c-ibm_iic.h:1.2
--- pplinux/linuxnew/drivers/i2c/i2c-ibm_iic.h:1.1.323.1	Thu Feb  3 10:00:38 2005
+++ pplinux/linuxnew/drivers/i2c/i2c-ibm_iic.h	Thu Feb  3 11:35:37 2005
@@ -61,7 +61,12 @@
 /* IICx_EXTSTS register */
 #define EXTSTS_IRQP	0x80
 #define EXTSTS_BCS_MASK	0x70
-#define   EXTSTS_BCS_FREE  0x40
+#define   EXTSTS_BCS_SLAVESEL    0x10
+#define   EXTSTS_BCS_SLAVEXFER   0x20
+#define   EXTSTS_BCS_MASTERXFER  0x30
+#define   EXTSTS_BCS_FREE        0x40
+#define   EXTSTS_BCS_BUSYBUS     0x50
+#define   EXTSTS_BCS_UNKNOWN     0x60
 #define EXTSTS_IRQD	0x08
 #define EXTSTS_LA	0x04
 #define EXTSTS_ICT	0x02
@@ -85,6 +90,9 @@
 #define XTCNTLSS_SRS	0x40
 #define XTCNTLSS_SWC	0x20
 #define XTCNTLSS_SWS	0x10
+#define XTCNTLSS_SBDD	0x08
+#define XTCNTLSS_SDBF	0x04
+#define XTCNTLSS_EPI	0x02
 #define XTCNTLSS_SRST	0x01
 
 /* IICx_DIRECTCNTL register */
Index: pplinux/linuxnew/drivers/i2c/i2c-slave.c
diff -u /dev/null pplinux/linuxnew/drivers/i2c/i2c-slave.c:1.1
--- /dev/null	Tue May 24 10:37:59 2005
+++ pplinux/linuxnew/drivers/i2c/i2c-slave.c	Thu Feb  3 11:35:37 2005
@@ -0,0 +1,381 @@
+#include <linux/version.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/i2c-slave.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/config.h>
+#include <asm/io.h>
+
+/* ------------------------------------------------------------------------- *
+ * Module debugging and output stuff
+ * ------------------------------------------------------------------------- */
+
+#define DBG_LEVEL 1
+
+#if DBG_LEVEL > 0
+#  define DBG(fmt, x...)	printk(KERN_DEBUG "i2c-slave: " fmt, ##x)
+#else
+#  define DBG(fmt, x...)	((void)0)
+#endif
+#if DBG_LEVEL > 1
+#  define DBG2(fmt, x...) 	DBG( fmt, ##x )
+#else
+#  define DBG2(fmt, x...) 	((void)0)
+#endif
+#if DBG_LEVEL > 2
+static void
+dump_iic_buf(const char* string, const char* buf, int len)
+{
+	int i;
+	printk(KERN_DEBUG"%s: Bytes:\n", string);
+	for (i = 0; i < len; i++) {
+		printk(KERN_DEBUG"0x%02x ", buf[i] & 0xff);
+	}
+	printk(KERN_DEBUG"\n");
+}
+#  define DUMP_BUF(s, buf,len)	dump_iic_buf((s),(buf),(len))
+#else
+#  define DUMP_BUF(s, buf,len)	((void)0)
+#endif
+
+#define WARN(fmt, x...)		printk(KERN_WARNING "i2c-slave: " fmt, ##x)
+
+/* ------------------------------------------------------------------------- *
+ * Global constants and variables
+ * ------------------------------------------------------------------------- */
+
+/* the max. number of I2C adapters and logical devices */
+#define MAX_NO_ADAPTERS	16
+#define MAX_NO_DEVICES	16
+
+/* the I2C adapters list */
+static struct i2c_slave_adapter* adapters[MAX_NO_DEVICES];
+
+/* the I2C devices list */
+static struct i2c_slave_device* devices[MAX_NO_DEVICES];
+
+/* spinlocks for access to the adapters and devices list */
+static spinlock_t adapters_lock = SPIN_LOCK_UNLOCKED;
+static spinlock_t devices_lock = SPIN_LOCK_UNLOCKED;
+
+/* ------------------------------------------------------------------------- *
+ * Initailization stuff
+ * ------------------------------------------------------------------------- */
+
+static __init int
+i2c_slave_init(void)
+{
+	unsigned long flags;
+	
+	DBG("module init.\n");
+	
+	/* initialize the adapter and device lists */
+	spin_lock_irqsave(&adapters_lock, flags);
+	memset(adapters, 0, sizeof(adapters));
+	spin_unlock_irqrestore(&adapters_lock, flags);
+	
+	spin_lock_irqsave(&devices_lock, flags);
+	memset(devices, 0, sizeof(adapters));
+	spin_unlock_irqrestore(&devices_lock, flags);
+	
+	DBG("module initialization finished.\n");
+	return 0;
+}
+
+static __exit void
+i2c_slave_cleanup(void)
+{
+	DBG("module cleanup.\n");
+	
+	/* nothing to do at the moment */
+	
+	DBG("module cleanup finished.\n");
+}
+
+/* ------------------------------------------------------------------------- *
+ * Adapter and Device managing functions
+ * ------------------------------------------------------------------------- */
+
+int
+i2c_slave_add_adapter(struct i2c_slave_adapter* adapter)
+{
+	unsigned long flags;
+	int i, ret = 0;
+
+	spin_lock_irqsave(&adapters_lock, flags);
+
+	for (i = 0; i < MAX_NO_ADAPTERS; i++)
+		if (adapters[i] == NULL)
+			break;
+	
+	if (i == MAX_NO_ADAPTERS) {
+		WARN("i2c_slave_add_adapter(%s) - enlarge MAX_NO_ADAPTERS.\n",
+			adapter->adapter->name);
+		ret = -ENOMEM;
+		goto bail;
+	}
+
+	adapters[i] = adapter;
+	
+	DBG("added adapter %s\n", adapter->adapter->name);
+
+bail:
+	spin_unlock_irqrestore(&adapters_lock, flags);
+	return ret;
+}
+
+int
+i2c_slave_remove_adapter(struct i2c_slave_adapter* adapter)
+{
+	unsigned long flags;
+	int i, ret = 0;
+
+	spin_lock_irqsave(&adapters_lock, flags);
+
+	for (i = 0; i < I2C_ADAP_MAX; i++)
+		if (adapters[i] == adapter)
+			break;
+	
+	if (MAX_NO_ADAPTERS == i) {
+		WARN("i2c_slave_remove_adapter adapter [%s] not found.\n",
+			adapter->adapter->name);
+		ret = -ENODEV;
+		goto bail;
+	}
+	
+	adapters[i] = NULL;
+
+	DBG("removed adapter %s\n", adapter->adapter->name);
+
+bail:
+	spin_unlock_irqrestore(&adapters_lock, flags);
+	return ret;
+}
+
+int
+i2c_slave_add_device(struct i2c_slave_device* device)
+{
+	unsigned long flags;
+	int i, ret = 0;
+
+	spin_lock_irqsave(&devices_lock, flags);
+
+	for (i = 0; i < MAX_NO_DEVICES; i++)
+		if (devices[i] == NULL)
+			break;
+	
+	if (i == MAX_NO_DEVICES) {
+		WARN("i2c-slave.o: i2c_slave_add_device(%s) - enlarge MAX_NO_DEVICES.\n",
+			device->name);
+		ret = -ENOMEM;
+		goto bail;
+	}
+
+	devices[i] = device;
+
+	DBG("added device %s\n", device->name);
+
+bail:
+	spin_unlock_irqrestore(&devices_lock, flags);
+	return ret;
+}
+
+int
+i2c_slave_remove_device(struct i2c_slave_device* device)
+{
+	unsigned long flags;
+	int i, ret = 0;
+
+	spin_lock_irqsave(&devices_lock, flags);
+
+	for (i = 0; i < I2C_ADAP_MAX; i++)
+		if (devices[i] == device)
+			break;
+	
+	if (MAX_NO_DEVICES == i) {
+		WARN("i2c_slave_remove_device device [%s] not found.\n",
+			device->name);
+		ret = -ENODEV;
+		goto bail;
+	}
+	
+	devices[i] = NULL;
+
+	DBG("removed device %s\n", device->name);
+
+bail:
+	spin_unlock_irqrestore(&devices_lock, flags);
+	return ret;
+}
+
+/* ------------------------------------------------------------------------- *
+ * Unblock functions
+ * ------------------------------------------------------------------------- */
+
+void
+unblock_adapter(struct i2c_adapter* adapter)
+{
+	struct i2c_slave_adapter* adap = NULL;
+	int i;
+	unsigned long flags;
+	
+	/* search the correct adapter */
+	spin_lock_irqsave(&adapters_lock, flags);
+
+	for (i = 0; i < I2C_ADAP_MAX; i++) {
+		if (adapters[i]->adapter == adapter) {
+			adap = adapters[i];
+			break;
+		}
+	}
+	
+	if (adap != NULL) {
+		DBG2("Unblock apapter %s.\n", adapter->name);
+		adap->reactivate(adapter);
+	}
+	else {
+		WARN("%s: No adapter to unblock!\n", adapter->name);
+	}
+	
+	spin_unlock_irqrestore(&adapters_lock, flags);
+}
+
+/* ------------------------------------------------------------------------- *
+ * Read and write functions
+ * ------------------------------------------------------------------------- */
+
+static struct i2c_slave_device* responsible_device = NULL;
+
+static void
+iic_slave_search_responsible_device(struct i2c_adapter* adapter, char* buf, int len)
+{
+	int i;
+	
+	responsible_device = NULL;
+	
+	for (i = 0; i < MAX_NO_DEVICES; i++) {
+		if (!devices[i]) continue;
+		
+		DBG2("Probing device %s\n", devices[i]->name);
+		if (devices[i]->adapter &&
+		    devices[i]->adapter == adapter &&
+		    devices[i]->is_responsible &&
+		    devices[i]->is_responsible(buf, len)) {
+			responsible_device = devices[i];
+			DBG2("Device %s responsible.\n", devices[i]->name);
+			break;
+		}
+#if DBG_LEVEL > 2
+		else if (devices[i]->adapter != adapter) {
+			DBG2("Device %s not responsible, adapters do not match.\n", devices[i]->name);
+		}
+		else {
+			DBG2("Device %s not responsible, refused data.\n", devices[i]->name);
+		}
+#endif
+	}
+}
+
+int
+iic_slave_write(struct i2c_adapter* adapter, char* buf, int len)
+{
+	int ret = 0;
+	unsigned long flags;
+	
+	DBG2("iic_slave_write: writing %d bytes.\n", len);
+
+	spin_lock_irqsave(&devices_lock, flags);
+	
+	/* find the device responsible for the current data transfer */
+	iic_slave_search_responsible_device(adapter, buf, len);
+	
+	if (responsible_device && responsible_device->slave_write) {
+		ret = responsible_device->slave_write(buf, len);
+		if (ret < 0) {
+			DBG("iic_slave_write: error writing bytes.\n");
+		}
+		else {
+			DBG2("iic_slave_write: %d bytes written.\n", len);
+		}
+	}
+	else {
+		WARN("iic_slave_write: no responsible device, discarding data!\n");
+		DUMP_BUF("iic_slave_write", buf, len);
+		
+		/* we fake the return value for the driver,
+		   it must not assume that an error occured */
+		ret = len;
+	}
+			
+	spin_unlock_irqrestore(&devices_lock, flags);
+	
+	return ret;
+}
+
+int
+iic_slave_read(struct i2c_adapter* adapter, char* buf, int len, int command)
+{
+	int i = 0;
+	int ret = 0;
+	static int start = 0;
+	
+	DBG2("iic_slave_read: %d reading bytes.\n", len);
+	
+	/* find the device responsible for the current data transfer */
+	if (command >= 0) {
+		unsigned char dev_buf = command & 0xff;
+		iic_slave_search_responsible_device(adapter, &dev_buf, 1);
+	}
+	
+	if (responsible_device && responsible_device->slave_read) {
+		ret = responsible_device->slave_read(buf, len);
+		if (ret < 0) {
+			DBG("iic_slave_read: error reading bytes.\n");
+		}
+		else {
+			DBG2("iic_slave_read: %d bytes read.\n", len);
+		}
+	}
+	else {
+		WARN("iic_slave_read: no responsible device!\n");
+		
+		ret = len;
+		
+		/* write dummy bytes */
+		for (i = 0; i < len; i++) {
+			buf[i] = i + start;
+		}
+		
+		DUMP_BUF("iic_slave_read", buf, len);
+			
+		start++;
+	}
+
+	return ret;
+}
+
+/* ------------------------------------------------------------------------- *
+ * Linux kernel module stuff
+ * ------------------------------------------------------------------------- */
+
+#ifdef MODULE
+
+MODULE_AUTHOR("thre@peppercon.de");
+MODULE_DESCRIPTION("Linux kernel module for I2C slave operations");
+
+module_init(i2c_slave_init);
+module_exit(i2c_slave_cleanup);
+
+#endif	/* MODULE */
+
+EXPORT_SYMBOL(i2c_slave_add_adapter);
+EXPORT_SYMBOL(i2c_slave_remove_adapter);
+EXPORT_SYMBOL(i2c_slave_add_device);
+EXPORT_SYMBOL(i2c_slave_remove_device);
+
+EXPORT_SYMBOL(iic_slave_write);
+EXPORT_SYMBOL(iic_slave_read);
+
+EXPORT_SYMBOL(unblock_adapter);
Index: pplinux/linuxnew/drivers/isdn/isdn_common.c
diff -u pplinux/linuxnew/drivers/isdn/isdn_common.c:1.1.323.1 pplinux/linuxnew/drivers/isdn/isdn_common.c:1.2
--- pplinux/linuxnew/drivers/isdn/isdn_common.c:1.1.323.1	Thu Feb  3 10:00:49 2005
+++ pplinux/linuxnew/drivers/isdn/isdn_common.c	Thu Feb  3 11:35:37 2005
@@ -485,6 +485,10 @@
 				isdn_command(&cmd);
 				return 0;
 			}
+			if (c->arg >= 0 && c->arg < ISDN_MAX_CHANNELS) {
+				memcpy(dev->last_caller[c->arg], c->parm.setup.phone, ISDN_MSNLEN);
+				memcpy(dev->last_called[c->arg], c->parm.setup.eazmsn, ISDN_MSNLEN);
+			}
 			/* Try to find a network-interface which will accept incoming call */
 			r = ((c->command == ISDN_STAT_ICALLW) ? 0 : isdn_net_find_icall(di, c->arg, i, &c->parm.setup));
 			switch (r) {
@@ -1575,6 +1579,22 @@
 					return 0;
 				} else
 					return -EINVAL;
+			case IIOCLASTCALLER:
+				if (arg) {
+					if (copy_to_user((char *) arg, dev->last_caller, sizeof(dev->last_caller)))
+						return -EFAULT;
+					return 0;
+				} else
+					return -EINVAL;
+				break;
+			case IIOCLASTCALLED:
+				if (arg) {
+					if (copy_to_user((char *) arg, dev->last_called, sizeof(dev->last_called)))
+						return -EFAULT;
+					return 0;
+				} else
+					return -EINVAL;
+				break;
 			case IIOCDBGVAR:
 				if (arg) {
 					if (copy_to_user((char *) arg, (char *) &dev, sizeof(ulong)))
Index: pplinux/linuxnew/drivers/isdn/hisax/config.c
diff -u pplinux/linuxnew/drivers/isdn/hisax/config.c:1.1.323.1 pplinux/linuxnew/drivers/isdn/hisax/config.c:1.2
--- pplinux/linuxnew/drivers/isdn/hisax/config.c:1.1.323.1	Thu Feb  3 10:00:49 2005
+++ pplinux/linuxnew/drivers/isdn/hisax/config.c	Thu Feb  3 11:35:38 2005
@@ -864,7 +864,7 @@
 	irq_cnt = kstat_irqs(cs->irq);
 	printk(KERN_INFO "%s: IRQ %d count %d\n", CardType[cs->typ],
 	       cs->irq, irq_cnt);
-	if (request_irq(cs->irq, cs->irq_func, cs->irq_flags, "HiSax", cs)) {
+	if (request_irq(cs->irq, cs->irq_func, cs->irq_flags|SA_SAMPLE_RANDOM, "HiSax", cs)) {
 		printk(KERN_WARNING "HiSax: couldn't get interrupt %d\n",
 		       cs->irq);
 		restore_flags(flags);
Index: pplinux/linuxnew/drivers/isdn/hisax/hfc_pci.c
diff -u pplinux/linuxnew/drivers/isdn/hisax/hfc_pci.c:1.1.323.1 pplinux/linuxnew/drivers/isdn/hisax/hfc_pci.c:1.2
--- pplinux/linuxnew/drivers/isdn/hisax/hfc_pci.c:1.1.323.1	Thu Feb  3 10:00:50 2005
+++ pplinux/linuxnew/drivers/isdn/hisax/hfc_pci.c	Thu Feb  3 11:35:38 2005
@@ -24,6 +24,33 @@
 #include <linux/pci.h>
 #include <linux/interrupt.h>
 
+#include <asm/ppc405_pcimcs.h>
+
+#ifdef CONFIG_PEPPERCON
+
+#define DEBUG
+#ifdef DEBUG
+# define DBG(fmt, args...)	{ printk(fmt, ##args); }
+#else
+# define DBG(fmt, args...)	{ }
+#endif
+
+#include <asm/io.h>
+#include <asm/uaccess.h>
+
+#define PPC405_PCI_BRIDGE_REGS_ADDR	((u32)0xEF400000)
+#define PPC405_PCI_BRIDGE_REGS_SIZE	((size_t)0x40)
+#define PPC_PCI_SLOT                    0
+#define PPC_PCI_FUNC                    0
+#define HFC_PCI_SLOT                    8
+#define HFC_PCI_FUNC                    0
+#define HFC_ADDR			((u32)0x90000000)
+#define HFC_SIZE			((size_t)0x00001000)
+#define HFC_REGS_SIZE			((size_t)0x00000100)
+#define HFC_IRQ				29
+
+#endif /* CONFIG_PEPPERCON */
+
 extern const char *CardType[];
 
 static const char *hfcpci_revision = "$Revision: 1.1.4.1 $";
@@ -68,6 +95,34 @@
 
 #if CONFIG_PCI
 
+#ifdef CONFIG_PEPPERCON
+
+void
+Write_hfc(struct IsdnCardState * cs, u_int offset, u8 data)
+{
+    int err;
+
+    writeb(data, ((u_char *)cs->hw.hfcpci.pci_io) + offset);
+    /*
+     * This is neccessary on ppc405 to flush the write on the PCI bus.
+     * --> no harm on other architectures
+     */
+    readb(((u_char *)cs->hw.hfcpci.pci_io) + HFCPCI_CHIP_ID);
+}
+
+u8
+Read_hfc(struct IsdnCardState * cs, u_int offset)
+{
+    u8 data;
+    int err;
+
+    data = readb(((u_char *)cs->hw.hfcpci.pci_io) + offset);
+
+    return data;
+}
+
+#endif /* CONFIG_PEPPERCON */
+
 /******************************************/
 /* free hardware resources used by driver */
 /******************************************/
@@ -88,11 +143,27 @@
 	set_current_state(TASK_UNINTERRUPTIBLE);
 	schedule_timeout((30 * HZ) / 1000);	/* Timeout 30ms */
 	Write_hfc(cs, HFCPCI_CIRM, 0);	/* Reset Off */
-	pcibios_write_config_word(cs->hw.hfcpci.pci_bus, cs->hw.hfcpci.pci_device_fn, PCI_COMMAND, 0);	/* disable memory mapped ports + busmaster */
+	/* disable memory mapped ports + busmaster */
+	mcs_pci_write_config_word(cs->hw.hfcpci.pci_dev, PCI_COMMAND, 0);
 	del_timer(&cs->hw.hfcpci.timer);
+#ifdef CONFIG_PEPPERCON
+	/* clear signature and free communication buffer */
+	if (cs->hw.hfcpci.share_start) {
+		pci_free_consistent(NULL, 32768, cs->hw.hfcpci.share_start,
+				    cs->hw.hfcpci.fifo_bus_addr);
+	}
+#else
 	kfree(cs->hw.hfcpci.share_start);
+#endif
 	cs->hw.hfcpci.share_start = NULL;
-	iounmap((void *)cs->hw.hfcpci.pci_io);
+
+	if (cs->hw.hfcpci.pci_io) {
+		iounmap((void *)cs->hw.hfcpci.pci_io);
+	}
+
+	if (cs->hw.hfcpci.ppc405_pci_bridge_regs) {
+		iounmap((void *)cs->hw.hfcpci.ppc405_pci_bridge_regs);
+	}
 }
 
 /********************************************************************************/
@@ -106,12 +177,16 @@
 
 	save_flags(flags);
 	cli();
-	pcibios_write_config_word(cs->hw.hfcpci.pci_bus, cs->hw.hfcpci.pci_device_fn, PCI_COMMAND, PCI_ENA_MEMIO);	/* enable memory mapped ports, disable busmaster */
+	/* enable memory mapped ports, disable busmaster */
+	mcs_pci_write_config_word(cs->hw.hfcpci.pci_dev,
+				  PCI_COMMAND, PCI_ENA_MEMIO);
 	cs->hw.hfcpci.int_m2 = 0;	/* interrupt output off ! */
 	Write_hfc(cs, HFCPCI_INT_M2, cs->hw.hfcpci.int_m2);
 
-	printk(KERN_INFO "HFC_PCI: resetting card\n");
-	pcibios_write_config_word(cs->hw.hfcpci.pci_bus, cs->hw.hfcpci.pci_device_fn, PCI_COMMAND, PCI_ENA_MEMIO + PCI_ENA_MASTER);	/* enable memory ports + busmaster */
+	printk(KERN_INFO "HFC_PCI: soft resetting chip\n");
+	/* enable memory ports + busmaster */
+	mcs_pci_write_config_word(cs->hw.hfcpci.pci_dev,
+				  PCI_COMMAND, PCI_ENA_MEMIO | PCI_ENA_MASTER);
 	Write_hfc(cs, HFCPCI_CIRM, HFCPCI_RESET);	/* Reset On */
 	sti();
 	set_current_state(TASK_UNINTERRUPTIBLE);
@@ -244,7 +319,7 @@
 	        cs->hw.hfcpci.fifo_en ^= fifo_state;
 	Write_hfc(cs, HFCPCI_FIFO_EN, cs->hw.hfcpci.fifo_en);
 	cs->hw.hfcpci.last_bfifo_cnt[fifo] = 0;
-	bzr->za[MAX_B_FRAMES].z1 = B_FIFO_SIZE + B_SUB_VAL - 1;
+	bzr->za[MAX_B_FRAMES].z1 = cpu_to_le16(B_FIFO_SIZE + B_SUB_VAL - 1);
 	bzr->za[MAX_B_FRAMES].z2 = bzr->za[MAX_B_FRAMES].z1;
 	bzr->f1 = MAX_B_FRAMES;
 	bzr->f2 = bzr->f1;	/* init F pointers to remain constant */
@@ -270,7 +345,7 @@
 	if (fifo_state)
 	        cs->hw.hfcpci.fifo_en ^= fifo_state;
 	Write_hfc(cs, HFCPCI_FIFO_EN, cs->hw.hfcpci.fifo_en);
-	bzt->za[MAX_B_FRAMES].z1 = B_FIFO_SIZE + B_SUB_VAL - 1;
+	bzt->za[MAX_B_FRAMES].z1 = cpu_to_le16(B_FIFO_SIZE + B_SUB_VAL - 1);
 	bzt->za[MAX_B_FRAMES].z2 = bzt->za[MAX_B_FRAMES].z1;
 	bzt->f1 = MAX_B_FRAMES;
 	bzt->f2 = bzt->f1;	/* init F pointers to remain constant */
@@ -298,18 +373,18 @@
 	if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO))
 		debugl1(cs, "hfcpci_empty_fifo");
 	zp = &bz->za[bz->f2];	/* point to Z-Regs */
-	new_z2 = zp->z2 + count;	/* new position in fifo */
+	new_z2 = le16_to_cpu(zp->z2) + count;	/* new position in fifo */
 	if (new_z2 >= (B_FIFO_SIZE + B_SUB_VAL))
 		new_z2 -= B_FIFO_SIZE;	/* buffer wrap */
 	new_f2 = (bz->f2 + 1) & MAX_B_FRAMES;
 	if ((count > HSCX_BUFMAX + 3) || (count < 4) ||
-	    (*(bdata + (zp->z1 - B_SUB_VAL)))) {
+	    (*(bdata + (le16_to_cpu(zp->z1) - B_SUB_VAL)))) {
 		if (cs->debug & L1_DEB_WARN)
 			debugl1(cs, "hfcpci_empty_fifo: incoming packet invalid length %d or crc", count);
 #ifdef ERROR_STATISTIC
 		bcs->err_inv++;
 #endif
-		bz->za[new_f2].z2 = new_z2;
+		bz->za[new_f2].z2 = cpu_to_le16(new_z2);
 		bz->f2 = new_f2;	/* next buffer */
 		skb = NULL;
 	} else if (!(skb = dev_alloc_skb(count - 3)))
@@ -319,12 +394,12 @@
 		count -= 3;
 		ptr = skb_put(skb, count);
 
-		if (zp->z2 + count <= B_FIFO_SIZE + B_SUB_VAL)
+		if (le16_to_cpu(zp->z2) + count <= B_FIFO_SIZE + B_SUB_VAL)
 			maxlen = count;		/* complete transfer */
 		else
-			maxlen = B_FIFO_SIZE + B_SUB_VAL - zp->z2;	/* maximum */
+			maxlen = B_FIFO_SIZE + B_SUB_VAL - le16_to_cpu(zp->z2);	/* maximum */
 
-		ptr1 = bdata + (zp->z2 - B_SUB_VAL);	/* start of data */
+		ptr1 = bdata + (le16_to_cpu(zp->z2) - B_SUB_VAL);	/* start of data */
 		memcpy(ptr, ptr1, maxlen);	/* copy data */
 		count -= maxlen;
 
@@ -333,7 +408,7 @@
 			ptr1 = bdata;	/* start of buffer */
 			memcpy(ptr, ptr1, count);	/* rest */
 		}
-		bz->za[new_f2].z2 = new_z2;
+		bz->za[new_f2].z2 = cpu_to_le16(new_z2);
 		bz->f2 = new_f2;	/* next buffer */
 
 	}
@@ -363,34 +438,34 @@
 	}
 	while (((df->f1 & D_FREG_MASK) != (df->f2 & D_FREG_MASK)) && count--) {
 		zp = &df->za[df->f2 & D_FREG_MASK];
-		rcnt = zp->z1 - zp->z2;
+		rcnt = le16_to_cpu(zp->z1) - le16_to_cpu(zp->z2);
 		if (rcnt < 0)
 			rcnt += D_FIFO_SIZE;
 		rcnt++;
 		if (cs->debug & L1_DEB_ISAC)
 			debugl1(cs, "hfcpci recd f1(%d) f2(%d) z1(%x) z2(%x) cnt(%d)",
-				df->f1, df->f2, zp->z1, zp->z2, rcnt);
+				df->f1, df->f2, le16_to_cpu(zp->z1), le16_to_cpu(zp->z2), rcnt);
 
 		if ((rcnt > MAX_DFRAME_LEN + 3) || (rcnt < 4) ||
-		    (df->data[zp->z1])) {
+		    (df->data[le16_to_cpu(zp->z1)])) {
 			if (cs->debug & L1_DEB_WARN)
-				debugl1(cs, "empty_fifo hfcpci paket inv. len %d or crc %d", rcnt, df->data[zp->z1]);
+				debugl1(cs, "empty_fifo hfcpci paket inv. len %d or crc %d", rcnt, df->data[le16_to_cpu(zp->z1)]);
 #ifdef ERROR_STATISTIC
 			cs->err_rx++;
 #endif
 			df->f2 = ((df->f2 + 1) & MAX_D_FRAMES) | (MAX_D_FRAMES + 1);	/* next buffer */
-			df->za[df->f2 & D_FREG_MASK].z2 = (zp->z2 + rcnt) & (D_FIFO_SIZE - 1);
+			df->za[df->f2 & D_FREG_MASK].z2 = cpu_to_le16((le16_to_cpu(zp->z2) + rcnt) & (D_FIFO_SIZE - 1));
 		} else if ((skb = dev_alloc_skb(rcnt - 3))) {
 			total = rcnt;
 			rcnt -= 3;
 			ptr = skb_put(skb, rcnt);
 
-			if (zp->z2 + rcnt <= D_FIFO_SIZE)
+			if (le16_to_cpu(zp->z2) + rcnt <= D_FIFO_SIZE)
 				maxlen = rcnt;	/* complete transfer */
 			else
-				maxlen = D_FIFO_SIZE - zp->z2;	/* maximum */
+				maxlen = D_FIFO_SIZE - le16_to_cpu(zp->z2);	/* maximum */
 
-			ptr1 = df->data + zp->z2;	/* start of data */
+			ptr1 = df->data + le16_to_cpu(zp->z2);	/* start of data */
 			memcpy(ptr, ptr1, maxlen);	/* copy data */
 			rcnt -= maxlen;
 
@@ -400,7 +475,7 @@
 				memcpy(ptr, ptr1, rcnt);	/* rest */
 			}
 			df->f2 = ((df->f2 + 1) & MAX_D_FRAMES) | (MAX_D_FRAMES + 1);	/* next buffer */
-			df->za[df->f2 & D_FREG_MASK].z2 = (zp->z2 + total) & (D_FIFO_SIZE - 1);
+			df->za[df->f2 & D_FREG_MASK].z2 = cpu_to_le16((le16_to_cpu(zp->z2) + total) & (D_FIFO_SIZE - 1));
 
 			skb_queue_tail(&cs->rq, skb);
 			sched_event_D_pci(cs, D_RCVBUFREADY);
@@ -425,7 +500,7 @@
 	z1r = &bz->za[MAX_B_FRAMES].z1;		/* pointer to z reg */
 	z2r = z1r + 1;
 
-	if (!(fcnt = *z1r - *z2r))
+	if (!(fcnt = le16_to_cpu(*z1r) - le16_to_cpu(*z2r)))
 		return (0);	/* no data avail */
 
 	if (fcnt <= 0)
@@ -433,7 +508,7 @@
 	if (fcnt > HFCPCI_BTRANS_THRESHOLD)
 		fcnt = HFCPCI_BTRANS_THRESHOLD;		/* limit size */
 
-	new_z2 = *z2r + fcnt;	/* new position in fifo */
+	new_z2 = le16_to_cpu(*z2r) + fcnt;	/* new position in fifo */
 	if (new_z2 >= (B_FIFO_SIZE + B_SUB_VAL))
 		new_z2 -= B_FIFO_SIZE;	/* buffer wrap */
 
@@ -441,12 +516,12 @@
 		printk(KERN_WARNING "HFCPCI: receive out of memory\n");
 	else {
 		ptr = skb_put(skb, fcnt);
-		if (*z2r + fcnt <= B_FIFO_SIZE + B_SUB_VAL)
+		if (le16_to_cpu(*z2r) + fcnt <= B_FIFO_SIZE + B_SUB_VAL)
 			maxlen = fcnt;	/* complete transfer */
 		else
-			maxlen = B_FIFO_SIZE + B_SUB_VAL - *z2r;	/* maximum */
+			maxlen = B_FIFO_SIZE + B_SUB_VAL - le16_to_cpu(*z2r);	/* maximum */
 
-		ptr1 = bdata + (*z2r - B_SUB_VAL);	/* start of data */
+		ptr1 = bdata + (le16_to_cpu(*z2r) - B_SUB_VAL);	/* start of data */
 		memcpy(ptr, ptr1, maxlen);	/* copy data */
 		fcnt -= maxlen;
 
@@ -461,7 +536,7 @@
 		hfcpci_sched_event(bcs, B_RCVBUFREADY);
 	}
 
-	*z2r = new_z2;		/* new position */
+	*z2r = cpu_to_le16(new_z2);		/* new position */
 	return (1);
 }				/* hfcpci_empty_fifo_trans */
 
@@ -506,13 +581,13 @@
 				bcs->channel, bz->f1, bz->f2);
 		zp = &bz->za[bz->f2];
 
-		rcnt = zp->z1 - zp->z2;
+		rcnt = le16_to_cpu(zp->z1) - le16_to_cpu(zp->z2);
 		if (rcnt < 0)
 			rcnt += B_FIFO_SIZE;
 		rcnt++;
 		if (cs->debug & L1_DEB_HSCX)
 			debugl1(cs, "hfcpci rec %d z1(%x) z2(%x) cnt(%d)",
-				bcs->channel, zp->z1, zp->z2, rcnt);
+				bcs->channel, le16_to_cpu(zp->z1), le16_to_cpu(zp->z2), rcnt);
 		if ((skb = hfcpci_empty_fifo(bcs, bz, bdata, rcnt))) {
 			cli();
 			skb_queue_tail(&bcs->rqueue, skb);
@@ -564,7 +639,7 @@
 	if (cs->debug & L1_DEB_ISAC)
 		debugl1(cs, "hfcpci_fill_Dfifo f1(%d) f2(%d) z1(f1)(%x)",
 			df->f1, df->f2,
-			df->za[df->f1 & D_FREG_MASK].z1);
+			le16_to_cpu(df->za[df->f1 & D_FREG_MASK].z1));
 	fcnt = df->f1 - df->f2;	/* frame count actually buffered */
 	if (fcnt < 0)
 		fcnt += (MAX_D_FRAMES + 1);	/* if wrap around */
@@ -577,7 +652,7 @@
 		return;
 	}
 	/* now determine free bytes in FIFO buffer */
-	count = df->za[df->f1 & D_FREG_MASK].z2 - df->za[df->f1 & D_FREG_MASK].z1;
+	count = le16_to_cpu(df->za[df->f1 & D_FREG_MASK].z2) - le16_to_cpu(df->za[df->f1 & D_FREG_MASK].z1);
 	if (count <= 0)
 		count += D_FIFO_SIZE;	/* count now contains available bytes */
 
@@ -590,11 +665,11 @@
 		return;
 	}
 	count = cs->tx_skb->len;	/* get frame len */
-	new_z1 = (df->za[df->f1 & D_FREG_MASK].z1 + count) & (D_FIFO_SIZE - 1);
+	new_z1 = (le16_to_cpu(df->za[df->f1 & D_FREG_MASK].z1) + count) & (D_FIFO_SIZE - 1);
 	new_f1 = ((df->f1 + 1) & D_FREG_MASK) | (D_FREG_MASK + 1);
 	src = cs->tx_skb->data;	/* source pointer */
-	dst = df->data + df->za[df->f1 & D_FREG_MASK].z1;
-	maxlen = D_FIFO_SIZE - df->za[df->f1 & D_FREG_MASK].z1;		/* end fifo */
+	dst = df->data + le16_to_cpu(df->za[df->f1 & D_FREG_MASK].z1);
+	maxlen = D_FIFO_SIZE - le16_to_cpu(df->za[df->f1 & D_FREG_MASK].z1);		/* end fifo */
 	if (maxlen > count)
 		maxlen = count;	/* limit size */
 	memcpy(dst, src, maxlen);	/* first copy */
@@ -607,8 +682,8 @@
 	}
 	save_flags(flags);
 	cli();
-	df->za[new_f1 & D_FREG_MASK].z1 = new_z1;	/* for next buffer */
-	df->za[df->f1 & D_FREG_MASK].z1 = new_z1;	/* new pos actual buffer */
+	df->za[new_f1 & D_FREG_MASK].z1 = cpu_to_le16(new_z1);	/* for next buffer */
+	df->za[df->f1 & D_FREG_MASK].z1 = cpu_to_le16(new_z1);	/* new pos actual buffer */
 	df->f1 = new_f1;	/* next frame */
 	restore_flags(flags);
 
@@ -653,8 +728,8 @@
 		z2t = z1t + 1;
 		if (cs->debug & L1_DEB_HSCX)
 			debugl1(cs, "hfcpci_fill_fifo_trans %d z1(%x) z2(%x)",
-				bcs->channel, *z1t, *z2t);
-		fcnt = *z2t - *z1t;
+				bcs->channel, le16_to_cpu(*z1t), le16_to_cpu(*z2t));
+		fcnt = le16_to_cpu(*z2t) - le16_to_cpu(*z1t);
 		if (fcnt <= 0)
 			fcnt += B_FIFO_SIZE;	/* fcnt contains available bytes in fifo */
 		fcnt = B_FIFO_SIZE - fcnt;	/* remaining bytes to send */
@@ -664,12 +739,12 @@
 				/* data is suitable for fifo */
 				count = bcs->tx_skb->len;
 
-				new_z1 = *z1t + count;	/* new buffer Position */
+				new_z1 = le16_to_cpu(*z1t) + count;	/* new buffer Position */
 				if (new_z1 >= (B_FIFO_SIZE + B_SUB_VAL))
 					new_z1 -= B_FIFO_SIZE;	/* buffer wrap */
 				src = bcs->tx_skb->data;	/* source pointer */
-				dst = bdata + (*z1t - B_SUB_VAL);
-				maxlen = (B_FIFO_SIZE + B_SUB_VAL) - *z1t;	/* end of fifo */
+				dst = bdata + (le16_to_cpu(*z1t) - B_SUB_VAL);
+				maxlen = (B_FIFO_SIZE + B_SUB_VAL) - le16_to_cpu(*z1t);	/* end of fifo */
 				if (maxlen > count)
 					maxlen = count;		/* limit size */
 				memcpy(dst, src, maxlen);	/* first copy */
@@ -682,7 +757,7 @@
 				}
 				bcs->tx_cnt -= bcs->tx_skb->len;
 				fcnt += bcs->tx_skb->len;
-				*z1t = new_z1;	/* now send data */
+				*z1t = cpu_to_le16(new_z1);	/* now send data */
 			} else if (cs->debug & L1_DEB_HSCX)
 				debugl1(cs, "hfcpci_fill_fifo_trans %d frame length %d discarded",
 					bcs->channel, bcs->tx_skb->len);
@@ -703,7 +778,7 @@
 	if (cs->debug & L1_DEB_HSCX)
 		debugl1(cs, "hfcpci_fill_fifo_hdlc %d f1(%d) f2(%d) z1(f1)(%x)",
 			bcs->channel, bz->f1, bz->f2,
-			bz->za[bz->f1].z1);
+			le16_to_cpu(bz->za[bz->f1].z1));
 
 	fcnt = bz->f1 - bz->f2;	/* frame count actually buffered */
 	if (fcnt < 0)
@@ -715,7 +790,7 @@
 		return;
 	}
 	/* now determine free bytes in FIFO buffer */
-	count = bz->za[bz->f1].z2 - bz->za[bz->f1].z1;
+	count = le16_to_cpu(bz->za[bz->f1].z2) - le16_to_cpu(bz->za[bz->f1].z1);
 	if (count <= 0)
 		count += B_FIFO_SIZE;	/* count now contains available bytes */
 
@@ -731,14 +806,14 @@
 		return;
 	}
 	count = bcs->tx_skb->len;	/* get frame len */
-	new_z1 = bz->za[bz->f1].z1 + count;	/* new buffer Position */
+	new_z1 = le16_to_cpu(bz->za[bz->f1].z1) + count;	/* new buffer Position */
 	if (new_z1 >= (B_FIFO_SIZE + B_SUB_VAL))
 		new_z1 -= B_FIFO_SIZE;	/* buffer wrap */
 
 	new_f1 = ((bz->f1 + 1) & MAX_B_FRAMES);
 	src = bcs->tx_skb->data;	/* source pointer */
-	dst = bdata + (bz->za[bz->f1].z1 - B_SUB_VAL);
-	maxlen = (B_FIFO_SIZE + B_SUB_VAL) - bz->za[bz->f1].z1;		/* end fifo */
+	dst = bdata + (le16_to_cpu(bz->za[bz->f1].z1) - B_SUB_VAL);
+	maxlen = (B_FIFO_SIZE + B_SUB_VAL) - le16_to_cpu(bz->za[bz->f1].z1);		/* end fifo */
 	if (maxlen > count)
 		maxlen = count;	/* limit size */
 	memcpy(dst, src, maxlen);	/* first copy */
@@ -755,7 +830,7 @@
 		bcs->st->lli.l1writewakeup(bcs->st, bcs->tx_skb->len);
 
 	cli();
-	bz->za[new_f1].z1 = new_z1;	/* for next buffer */
+	bz->za[new_f1].z1 = cpu_to_le16(new_z1);	/* for next buffer */
 	bz->f1 = new_f1;	/* next frame */
 	restore_flags(flags);
 
@@ -896,34 +971,34 @@
 				bz->f1, bz->f2);
 		zp = &bz->za[bz->f2];
 
-		rcnt = zp->z1 - zp->z2;
+		rcnt = le16_to_cpu(zp->z1) - le16_to_cpu(zp->z2);
 		if (rcnt < 0)
 			rcnt += B_FIFO_SIZE;
 		rcnt++;
 		if (cs->debug & L1_DEB_ISAC)
 			debugl1(cs, "hfcpci e_rec z1(%x) z2(%x) cnt(%d)",
-				zp->z1, zp->z2, rcnt);
-		new_z2 = zp->z2 + rcnt;		/* new position in fifo */
+				le16_to_cpu(zp->z1), le16_to_cpu(zp->z2), rcnt);
+		new_z2 = le16_to_cpu(zp->z2) + rcnt;		/* new position in fifo */
 		if (new_z2 >= (B_FIFO_SIZE + B_SUB_VAL))
 			new_z2 -= B_FIFO_SIZE;	/* buffer wrap */
 		new_f2 = (bz->f2 + 1) & MAX_B_FRAMES;
 		if ((rcnt > 256 + 3) || (count < 4) ||
-		    (*(bdata + (zp->z1 - B_SUB_VAL)))) {
+		    (*(bdata + (le16_to_cpu(zp->z1) - B_SUB_VAL)))) {
 			if (cs->debug & L1_DEB_WARN)
 				debugl1(cs, "hfcpci_empty_echan: incoming packet invalid length %d or crc", rcnt);
-			bz->za[new_f2].z2 = new_z2;
+			bz->za[new_f2].z2 = cpu_to_le16(new_z2);
 			bz->f2 = new_f2;	/* next buffer */
 		} else {
 			total = rcnt;
 			rcnt -= 3;
 			ptr = e_buffer;
 
-			if (zp->z2 <= B_FIFO_SIZE + B_SUB_VAL)
+			if (le16_to_cpu(zp->z2) <= B_FIFO_SIZE + B_SUB_VAL)
 				maxlen = rcnt;	/* complete transfer */
 			else
-				maxlen = B_FIFO_SIZE + B_SUB_VAL - zp->z2;	/* maximum */
+				maxlen = B_FIFO_SIZE + B_SUB_VAL - le16_to_cpu(zp->z2);	/* maximum */
 
-			ptr1 = bdata + (zp->z2 - B_SUB_VAL);	/* start of data */
+			ptr1 = bdata + (le16_to_cpu(zp->z2) - B_SUB_VAL);	/* start of data */
 			memcpy(ptr, ptr1, maxlen);	/* copy data */
 			rcnt -= maxlen;
 
@@ -932,7 +1007,7 @@
 				ptr1 = bdata;	/* start of buffer */
 				memcpy(ptr, ptr1, rcnt);	/* rest */
 			}
-			bz->za[new_f2].z2 = new_z2;
+			bz->za[new_f2].z2 = cpu_to_le16(new_z2);
 			bz->f2 = new_f2;	/* next buffer */
 			if (cs->debug & DEB_DLOG_HEX) {
 				ptr = cs->dlog;
@@ -1678,11 +1753,12 @@
 	return (0);
 }
 
-
+#ifndef CONFIG_PEPPERCON
 /* this variable is used as card index when more than one cards are present */
 static struct pci_dev *dev_hfcpci __initdata = NULL;
+#endif
 
-#endif				/* CONFIG_PCI */
+#endif /* CONFIG_PCI */
 
 int __init
 setup_hfcpci(struct IsdnCard *card)
@@ -1690,11 +1766,13 @@
 	struct IsdnCardState *cs = card->cs;
 	char tmp[64];
 	int i;
+#ifdef CONFIG_PEPPERCON
+	u32 val;
+	struct pci_dev * ppc_pci_dev;
+#else
 	struct pci_dev *tmp_hfcpci = NULL;
-
-#ifdef __BIG_ENDIAN
-#error "not running on big endian machines now"
 #endif
+
 	strcpy(tmp, hfcpci_revision);
 	printk(KERN_INFO "HiSax: HFC-PCI driver Rev. %s\n", HiSax_getrev(tmp));
 #if CONFIG_PCI
@@ -1702,6 +1780,148 @@
 	cs->dc.hfcpci.ph_state = 0;
 	cs->hw.hfcpci.fifo = 255;
 	if (cs->typ == ISDN_CTYPE_HFC_PCI) {
+#ifdef CONFIG_PEPPERCON
+		/* ---- find the PPC PCI device ---------------------------- */
+
+		ppc_pci_dev =
+			pci_find_slot(0, PCI_DEVFN(PPC_PCI_SLOT, PPC_PCI_FUNC));
+		if (ppc_pci_dev == NULL) {
+			printk("HFC-PCI: PPC PCI device not detected\n");
+			return 0;
+		}
+
+		/* ---- find the HFC PCI device ---------------------------- */
+
+		cs->hw.hfcpci.pci_dev =
+			pci_find_slot(0, PCI_DEVFN(HFC_PCI_SLOT, HFC_PCI_FUNC));
+		if (cs->hw.hfcpci.pci_dev == NULL) {
+			printk(KERN_WARNING "HFC-PCI: No PCI card found\n");
+			return 0;
+		}
+
+		cs->irq = HFC_IRQ;
+		printk(KERN_INFO "HiSax: HFC-PCI card manufacturer: "
+		       "%s card name: %s\n", id_list[0].vendor_name,
+		       id_list[0].card_name);
+
+		/* ---- if PPC or HFC got no PCI resources - bail out ------ */
+
+		mcs_pci_read_config_dword(ppc_pci_dev, PCI_BASE_ADDRESS_2,
+					  &val);
+
+		printk(KERN_INFO "HFC-PCI: PPC PCIBAR2 = 0x%08x\n", val);
+
+		if ((val & 0xFFFFFF00) == 0) {
+			printk(KERN_WARNING "HFC-PCI: PPC got no PCI resources\n");
+			return 0;
+		}
+
+		mcs_pci_read_config_dword(cs->hw.hfcpci.pci_dev,
+					  PCI_BASE_ADDRESS_1, &val);
+
+		printk(KERN_INFO "HFC-PCI: HFC PCIBAR1 = 0x%08x\n", val);
+
+		if ((val & 0xFFFFFF00) == 0) {
+			printk(KERN_WARNING "HFC-PCI: HFC got no PCI resources\n");
+			return 0;
+		}
+
+		/* ---- map PCI bridge registers --------------------------- */
+
+		cs->hw.hfcpci.ppc405_pci_bridge_regs =
+		       ioremap_nocache(PPC405_PCI_BRIDGE_REGS_ADDR,
+				       PPC405_PCI_BRIDGE_REGS_SIZE);
+		if (cs->hw.hfcpci.ppc405_pci_bridge_regs == NULL) {
+			printk(KERN_WARNING "HFC-PCI: failed to map PCI "
+			       "bridge registers of PPC405\n");
+			return 0;
+		}
+
+		/*
+		 * ISDN FIFO buffer allocation:
+		 *   - HFCs is PCI bus master and need pointer to 405GP memory
+		 *   - 405GP allocates 2 PCI bus ranches HOST -> 405GP memory
+		 * 	* base addresses PCIBAR1 and PCIBAR2 are in 405GP
+		 * 	  PCI CFG space offset 0x14 and 0x18
+		 * 	* these pointers are initiated from HOST during BIOS
+		 * 	  start
+		 *   - this HFC driver use pointer PCIBAR2 and write it as FIFO
+		 *     pointer to HFC PCI CFG offset 0x80
+		 *   - then the driver allocates 32kByte FIFO memory and write
+		 *     the pointer to the PCIBAR2 -> 405GP LOCALMEM mapping
+		 *     register
+		 *   - every access to the phys memory location in PCIBAR2 is
+		 *     now transfered to the allocated ISDN FIFO memory
+		 *     independent, if PCI initiator is before or behind
+		 *     PCI2PCI bridge
+		 *     Problem: 405GP PCIBAR2 and PCI2PCI bridge must
+		 *              be initialized
+		 */
+
+  		cs->hw.hfcpci.share_start = cs->hw.hfcpci.fifos =
+			pci_alloc_consistent(NULL, 32768,
+					     &cs->hw.hfcpci.fifo_bus_addr);
+  		if (cs->hw.hfcpci.share_start == NULL) {
+	  		printk(KERN_ALERT "HFC-PCI: pci_alloc_consistent "
+			       "failed\n");
+	  		return 0;
+  		}
+		DBG("HFC-PCI: fifo mem @ 0x%p (virtual) / 0x%08x (bus)\n",
+		    cs->hw.hfcpci.share_start,
+		    (u32)cs->hw.hfcpci.fifo_bus_addr);
+
+		/* write FIFO pointer to ISDN chip CFG space offset 0x80 */
+		mcs_pci_read_config_dword(ppc_pci_dev, PCI_BASE_ADDRESS_2,
+					  &val);
+		mcs_pci_write_config_dword(cs->hw.hfcpci.pci_dev, 0x80, val);
+
+		/*
+		 * map PCI memory to 405 memory; use allocated FIFO memory
+		 * for ISDN PCI bus mastering
+		 */
+		
+		writel(cs->hw.hfcpci.fifo_bus_addr,
+		       &cs->hw.hfcpci.ppc405_pci_bridge_regs[0xf]);
+		writel(0xFFFF8000 | 1,
+		       &cs->hw.hfcpci.ppc405_pci_bridge_regs[0xe]);
+
+		/* ---- map ISDN register memory into PLB space ------------ */
+
+		mcs_pci_read_config_dword(cs->hw.hfcpci.pci_dev,
+					  PCI_BASE_ADDRESS_1,
+					  &cs->hw.hfcpci.pci_io_bus);
+		if (cs->hw.hfcpci.pci_io_bus != 0 &&
+		    cs->hw.hfcpci.pci_io_bus != 0xFFFFFFFF) {
+			writel(HFC_ADDR,
+			       &cs->hw.hfcpci.ppc405_pci_bridge_regs[0x4]);
+			writel(~(HFC_SIZE - 1) | 1,
+			       &cs->hw.hfcpci.ppc405_pci_bridge_regs[0x5]);
+			writel(cs->hw.hfcpci.pci_io_bus,
+			       &cs->hw.hfcpci.ppc405_pci_bridge_regs[0x6]);
+			writel(0x00000000,
+			       &cs->hw.hfcpci.ppc405_pci_bridge_regs[0x7]);
+			cs->hw.hfcpci.pci_io_valid = 1;
+		}
+
+		/* set ISDN register pointer to PLB */
+		cs->hw.hfcpci.pci_io =
+			ioremap_nocache(HFC_ADDR +
+					(cs->hw.hfcpci.pci_io_bus & 0xFFF),
+					HFC_REGS_SIZE);
+#if 0
+		for (i = 0; i <= 0xf; i++) {
+			DBG("HFC-PCI: pci bridge reg %02x: %08x\n", i,
+			    readl(&cs->hw.hfcpci.ppc405_pci_bridge_regs[i]));
+		}
+
+		for (i = 0; i <= 0x100; i += 4) {
+			DBG("%02x ", Read_hfc(cs, i));
+			if (((i + 4) % 16) == 0) DBG("\n");
+		}
+#endif
+		
+#else /* !CONFIG_PEPPERCON */
+
 		i = 0;
 		while (id_list[i].vendor_id) {
 			tmp_hfcpci = pci_find_device(id_list[i].vendor_id,
@@ -1722,20 +1942,18 @@
 		if (tmp_hfcpci) {
 			i--;
 			dev_hfcpci = tmp_hfcpci;	/* old device */
-			cs->hw.hfcpci.pci_bus = dev_hfcpci->bus->number;
-			cs->hw.hfcpci.pci_device_fn = dev_hfcpci->devfn;
+			cs->hw.hfcpci.pci_dev = tmp_hfcpci;
 			cs->irq = dev_hfcpci->irq;
 			if (!cs->irq) {
 				printk(KERN_WARNING "HFC-PCI: No IRQ for PCI card found\n");
 				return (0);
 			}
-			cs->hw.hfcpci.pci_io = (char *) dev_hfcpci->resource[ 1].start;
 			printk(KERN_INFO "HiSax: HFC-PCI card manufacturer: %s card name: %s\n", id_list[i].vendor_name, id_list[i].card_name);
 		} else {
 			printk(KERN_WARNING "HFC-PCI: No PCI card found\n");
 			return (0);
 		}
-		if (!cs->hw.hfcpci.pci_io) {
+		if (!cs->hw.hfcpci.pci_dev->resource[1].start) {
 			printk(KERN_WARNING "HFC-PCI: No IO-Mem for PCI card found\n");
 			return (0);
 		}
@@ -1751,14 +1969,17 @@
 		pcibios_write_config_dword(cs->hw.hfcpci.pci_bus,
 				       cs->hw.hfcpci.pci_device_fn, 0x80,
 			       (u_int) virt_to_bus(cs->hw.hfcpci.fifos));
-		cs->hw.hfcpci.pci_io = ioremap((ulong) cs->hw.hfcpci.pci_io, 256);
+		cs->hw.hfcpci.pci_io = ioremap(dev_hfcpci->resource[1].start, 256);
+#endif /* !CONFIG_PEPPERCON */
 		printk(KERN_INFO
 		       "HFC-PCI: defined at mem %#x fifo %#x(%#x) IRQ %d HZ %d\n",
 		       (u_int) cs->hw.hfcpci.pci_io,
 		       (u_int) cs->hw.hfcpci.fifos,
 		       (u_int) virt_to_bus(cs->hw.hfcpci.fifos),
 		       cs->irq, HZ);
-		pcibios_write_config_word(cs->hw.hfcpci.pci_bus, cs->hw.hfcpci.pci_device_fn, PCI_COMMAND, PCI_ENA_MEMIO);	/* enable memory mapped ports, disable busmaster */
+		/* enable memory mapped ports, disable busmaster */
+		mcs_pci_write_config_word(cs->hw.hfcpci.pci_dev,
+					  PCI_COMMAND, PCI_ENA_MEMIO);
 		cs->hw.hfcpci.int_m2 = 0;	/* disable alle interrupts */
 		cs->hw.hfcpci.int_m1 = 0;
 		Write_hfc(cs, HFCPCI_INT_M1, cs->hw.hfcpci.int_m1);
Index: pplinux/linuxnew/drivers/isdn/hisax/hfc_pci.h
diff -u pplinux/linuxnew/drivers/isdn/hisax/hfc_pci.h:1.1.323.1 pplinux/linuxnew/drivers/isdn/hisax/hfc_pci.h:1.2
--- pplinux/linuxnew/drivers/isdn/hisax/hfc_pci.h:1.1.323.1	Thu Feb  3 10:00:49 2005
+++ pplinux/linuxnew/drivers/isdn/hisax/hfc_pci.h	Thu Feb  3 11:35:38 2005
@@ -227,9 +227,13 @@
     u_char fill[32768]; 
   } fifo_area;
 
-
-#define Write_hfc(a,b,c) (*(((u_char *)a->hw.hfcpci.pci_io)+b) = c) 
-#define Read_hfc(a,b) (*(((u_char *)a->hw.hfcpci.pci_io)+b))
+#ifdef CONFIG_PEPPERCON
+extern void Write_hfc(struct IsdnCardState * cs, u_int offset, u8 data);
+extern u8 Read_hfc(struct IsdnCardState * cs, u_int offset);
+#else /* !CONFIG_PEPPERCON */
+# define Write_hfc(a,b,c) (*(((u_char *)a->hw.hfcpci.pci_io)+b) = c) 
+# define Read_hfc(a,b) (*(((u_char *)a->hw.hfcpci.pci_io)+b))
+#endif /* !CONFIG_PEPPERCON */
 
 extern void main_irq_hcpci(struct BCState *bcs);
 extern void inithfcpci(struct IsdnCardState *cs);
Index: pplinux/linuxnew/drivers/isdn/hisax/hisax.h
diff -u pplinux/linuxnew/drivers/isdn/hisax/hisax.h:1.1.323.1 pplinux/linuxnew/drivers/isdn/hisax/hisax.h:1.2
--- pplinux/linuxnew/drivers/isdn/hisax/hisax.h:1.1.323.1	Thu Feb  3 10:00:50 2005
+++ pplinux/linuxnew/drivers/isdn/hisax/hisax.h	Thu Feb  3 11:35:38 2005
@@ -148,8 +148,8 @@
 #define MAX_DLOG_SPACE	2048
 #define MAX_BLOG_SPACE	256
 
-/* #define I4L_IRQ_FLAG SA_INTERRUPT */
-#define I4L_IRQ_FLAG    0
+#define I4L_IRQ_FLAG SA_INTERRUPT
+/* #define I4L_IRQ_FLAG    0 */
 
 /*
  * Statemachine
@@ -686,13 +686,19 @@
         unsigned char bswapped;
         unsigned char nt_mode;
         int nt_timer;
-	unsigned char pci_bus;
-        unsigned char pci_device_fn;
+	struct pci_dev * pci_dev;
         unsigned char *pci_io; /* start of PCI IO memory */
         void *share_start; /* shared memory for Fifos start */
         void *fifos; /* FIFO memory */ 
         int last_bfifo_cnt[2]; /* marker saving last b-fifo frame count */
 	struct timer_list timer;
+#ifdef CONFIG_PEPPERCON
+	volatile u32 * ppc405_pci_bridge_regs;
+	struct timer_list check_timer;
+	u32 pci_io_bus;
+	volatile int pci_io_valid;
+	dma_addr_t fifo_bus_addr;
+#endif /* CONFIG_PEPPERCON */
 };
 
 struct hfcSX_hw {
Index: pplinux/linuxnew/drivers/mtd/cmdlinepart.c
diff -u pplinux/linuxnew/drivers/mtd/cmdlinepart.c:1.1.323.1 pplinux/linuxnew/drivers/mtd/cmdlinepart.c:1.2
--- pplinux/linuxnew/drivers/mtd/cmdlinepart.c:1.1.323.1	Thu Feb  3 10:00:34 2005
+++ pplinux/linuxnew/drivers/mtd/cmdlinepart.c	Thu Feb  3 11:35:38 2005
@@ -31,6 +31,10 @@
 #include <asm/setup.h>
 #include <linux/bootmem.h>
 
+#if defined(MODULE)
+#define cmdline mtdparts
+#endif
+
 /* error message prefix */
 #define ERRP "mtd: "
 
@@ -56,7 +60,7 @@
 static struct cmdline_mtd_partition *partitions;
 
 /* the command line passed to mtdpart_setupd() */
-static char *cmdline;
+static char *cmdline = NULL;
 static int cmdline_parsed = 0;
 
 /*
@@ -335,7 +339,10 @@
 	return -EINVAL;
 }
 
-
+#if defined(MODULE)
+MODULE_PARM(mtdparts, "s");
+MODULE_PARM_DESC(mtdparts, "Partition table description");
+#else
 /* 
  * This is the handler for our kernel parameter, called from 
  * main.c::checksetup(). Note that we can not yet kmalloc() anything,
@@ -348,6 +355,7 @@
 }
 
 __setup("mtdparts=", mtdpart_setup);
+#endif
 
 EXPORT_SYMBOL(parse_cmdline_partitions);
 
Index: pplinux/linuxnew/drivers/mtd/mtdchar.c
diff -u pplinux/linuxnew/drivers/mtd/mtdchar.c:1.1.323.1 pplinux/linuxnew/drivers/mtd/mtdchar.c:1.2
--- pplinux/linuxnew/drivers/mtd/mtdchar.c:1.1.323.1	Thu Feb  3 10:00:34 2005
+++ pplinux/linuxnew/drivers/mtd/mtdchar.c	Wed Apr  6 11:53:11 2005
@@ -5,7 +5,6 @@
  * Pure 2.4 version - compatibility cruft removed to mtdchar-compat.c
  *
  */
-
 #include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
@@ -515,8 +514,14 @@
 		kfree(databuf);
 		break;
 	}
-
-		
+#if defined(PRODUCT_FLASHX4)	
+	case MEMREADSIZE:
+	{	    	    
+	    if (copy_to_user((int *) arg, &mtd->chip_size, sizeof(int)))
+	      return -EFAULT;
+	    break;	    
+	}
+#endif	
 	default:
 		DEBUG(MTD_DEBUG_LEVEL0, "Invalid ioctl %x (MEMGETINFO = %x)\n", cmd, MEMGETINFO);
 		ret = -ENOTTY;
Index: pplinux/linuxnew/drivers/mtd/mtdcore.c
diff -u pplinux/linuxnew/drivers/mtd/mtdcore.c:1.1.323.1 pplinux/linuxnew/drivers/mtd/mtdcore.c:1.3
--- pplinux/linuxnew/drivers/mtd/mtdcore.c:1.1.323.1	Thu Feb  3 10:00:34 2005
+++ pplinux/linuxnew/drivers/mtd/mtdcore.c	Wed Apr  6 11:53:11 2005
@@ -21,6 +21,9 @@
 #ifdef CONFIG_PROC_FS
 #include <linux/proc_fs.h>
 #endif
+#ifdef CONFIG_PEPPERCON
+# include "asm/ibm4xx.h"
+#endif
 
 #include <linux/mtd/mtd.h>
 
@@ -362,6 +365,160 @@
         return ((count < begin+len-off) ? count : begin+len-off);
 }
 
+#ifdef CONFIG_PEPPERCON
+static int mtd_read_proc_size( char *page, char **start, off_t off,int count,
+			       int *eof, void *data_unused)
+{
+	int len;
+
+	bd_t * bd = (bd_t *)__res;
+	len = sprintf(page, "%ld\n", bd->bi_flashsize / (1024 * 1024));
+	
+        *eof = 1;
+
+	*start = NULL;
+        return len;
+}
+
+static int mtd_read_proc_prot_fact( char *page, char **start, off_t off, int count,
+				    int *eof, void *data_unused)
+{
+#if defined(PRODUCT_FLASHX4)
+    struct mtd_info *mtd = get_mtd_device(NULL, 6);
+#else
+    struct mtd_info *mtd = get_mtd_device(NULL, 0);
+#endif
+	int len = 0, i, ret;
+	u_char buf[8]; size_t retlen;
+
+	if (mtd == NULL) {
+	    goto done;
+	}
+
+	memset(buf, 0, sizeof(buf));
+	ret = mtd->read_fact_prot_reg(mtd, 0, 8, &retlen, buf);
+	for (i=0; i<8; i++) {
+	    len += sprintf(&page[len], "%02X", buf[i]);
+	}
+	
+	put_mtd_device(mtd);
+done:
+	*eof = 1;
+	len += sprintf(&page[len], "\n");
+	*start = NULL;
+        return len;
+}
+
+static int mtd_read_proc_prot_user( char *page, char **start, off_t off, int count,
+				    int *eof, void *data_unused)
+{
+#if defined(PRODUCT_FLASHX4)
+    struct mtd_info *mtd = get_mtd_device(NULL, 6);
+#else
+    struct mtd_info *mtd = get_mtd_device(NULL, 0);
+#endif
+	int len = 0, i, ret;
+	u_char buf[8]; size_t retlen;
+
+	if (mtd == NULL) {
+	    goto done;
+	}
+
+	memset(buf, 0, sizeof(buf));
+	ret = mtd->read_user_prot_reg(mtd, 0, 8, &retlen, buf);
+	for (i=0; i<8; i++) {
+	    len += sprintf(&page[len], "%02X", buf[i]);
+	}
+	
+	put_mtd_device(mtd);
+done:
+        *eof = 1;
+	len += sprintf(&page[len], "\n");
+	*start = NULL;
+        return len;
+}
+
+static int mtd_write_proc_prot_user(struct file *file, const char *buffer,
+				    unsigned long count, void *data)
+{
+#if defined(PRODUCT_FLASHX4)
+    struct mtd_info *mtd = get_mtd_device(NULL, 6);
+#else
+    struct mtd_info *mtd = get_mtd_device(NULL, 0);
+#endif
+	int i;
+	u_char buf[8], number[2];
+	size_t retlen, len = count;
+
+	if (mtd == NULL || count == 0) {
+	    goto done;
+	}
+
+	if (buffer[count - 1] == '\n') {
+	    len = count - 1;
+	}
+
+	for (i = 0; i < len / 2; i++) {
+	    memcpy(number, &buffer[2 * i], 2);
+	    buf[i] = simple_strtol(number, NULL, 16);
+	}
+
+	mtd->write_user_prot_reg(mtd, 0, len / 2, &retlen, buf);
+
+	put_mtd_device(mtd);
+ done:
+	return count;
+}
+
+static int mtd_read_proc_prot_lock(char *page, char **start, off_t off, int count,
+				   int *eof, void *data_unused)
+{
+#if defined(PRODUCT_FLASHX4)
+    struct mtd_info *mtd = get_mtd_device(NULL, 6);
+#else
+    struct mtd_info *mtd = get_mtd_device(NULL, 0);
+#endif
+    int len = 0;
+
+    if (mtd == NULL) {
+	goto done;
+    }
+    
+    len += sprintf(&page[len], "%d", mtd->is_user_prot_reg_locked(mtd));
+
+    put_mtd_device(mtd);
+ done:
+    *eof = 1;
+    len += sprintf(&page[len], "\n");
+    *start = NULL;
+    return len;
+}
+
+static int mtd_write_proc_prot_lock(struct file *file, const char *buffer,
+				    unsigned long count, void *data)
+{
+#if defined(PRODUCT_FLASHX4)
+    struct mtd_info *mtd = get_mtd_device(NULL, 6);
+#else
+    struct mtd_info *mtd = get_mtd_device(NULL, 0);
+#endif
+    int lock;
+
+    if (mtd == NULL || count == 0) {
+	goto done;
+    }
+
+    lock = simple_strtol(buffer, NULL, 10);
+    if (lock) {
+	mtd->lock_user_prot_reg(mtd);
+    }	
+    
+    put_mtd_device(mtd);
+ done:
+    return count;
+}
+#endif
+
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,2,0)
 struct proc_dir_entry mtd_proc_entry = {
         0,                 /* low_ino: the inode -- dynamic */
@@ -385,6 +542,25 @@
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
 	if ((proc_mtd = create_proc_entry( "mtd", 0, 0 )))
 	  proc_mtd->read_proc = mtd_read_proc;
+# ifdef CONFIG_PEPPERCON
+	if ((proc_mtd = create_proc_entry( "mtd_size_mb", 0, 0 ))) {
+	  proc_mtd->read_proc = mtd_read_proc_size;
+	}
+
+	if ((proc_mtd = create_proc_entry( "mtd_prot_fact", 0, 0 ))) {
+	    proc_mtd->read_proc = mtd_read_proc_prot_fact;
+	}
+	
+	if ((proc_mtd = create_proc_entry( "mtd_prot_user", 0, 0 ))) {
+	    proc_mtd->read_proc = mtd_read_proc_prot_user;
+	    proc_mtd->write_proc = mtd_write_proc_prot_user;
+	}
+	
+	if ((proc_mtd = create_proc_entry( "mtd_prot_lock", 0, 0 ))) {
+	    proc_mtd->read_proc = mtd_read_proc_prot_lock;
+	    proc_mtd->write_proc = mtd_write_proc_prot_lock;
+	}
+# endif
 #else
         proc_register_dynamic(&proc_root,&mtd_proc_entry);
 #endif
Index: pplinux/linuxnew/drivers/mtd/mtdpart.c
diff -u pplinux/linuxnew/drivers/mtd/mtdpart.c:1.1.323.1 pplinux/linuxnew/drivers/mtd/mtdpart.c:1.3
--- pplinux/linuxnew/drivers/mtd/mtdpart.c:1.1.323.1	Thu Feb  3 10:00:34 2005
+++ pplinux/linuxnew/drivers/mtd/mtdpart.c	Wed Apr  6 11:53:11 2005
@@ -113,10 +113,22 @@
 			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);
 }
 
+static int part_lock_user_prot_reg (struct mtd_info *mtd)
+{
+	struct mtd_part *part = PART(mtd);
+	return part->master->lock_user_prot_reg (part->master);
+}
+
+static int part_is_user_prot_reg_locked (struct mtd_info *mtd)
+{
+	struct mtd_part *part = PART(mtd);
+	return part->master->is_user_prot_reg_locked (part->master);
+}
+
 static int part_write (struct mtd_info *mtd, loff_t to, size_t len,
 			size_t *retlen, const u_char *buf)
 {
@@ -319,6 +331,10 @@
 		slave->mtd.ecctype = master->ecctype;
 		slave->mtd.eccsize = master->eccsize;
 
+#if defined(PRODUCT_FLASHX4)		
+		slave->mtd.chip_size = master->chip_size;
+#endif		
+		
 		slave->mtd.name = parts[i].name;
 		slave->mtd.bank_size = master->bank_size;
 		slave->mtd.module = master->module;
@@ -345,6 +361,11 @@
 			slave->mtd.read_fact_prot_reg = part_read_fact_prot_reg;
 		if(master->write_user_prot_reg)
 			slave->mtd.write_user_prot_reg = part_write_user_prot_reg;
+		if(master->lock_user_prot_reg)
+			slave->mtd.lock_user_prot_reg = part_lock_user_prot_reg;
+		if(master->is_user_prot_reg_locked)
+			slave->mtd.is_user_prot_reg_locked = part_is_user_prot_reg_locked;
+
 		if (master->sync)
 			slave->mtd.sync = part_sync;
 		if (!i && master->suspend && master->resume) {
Index: pplinux/linuxnew/drivers/mtd/chips/cfi_cmdset_0001.c
diff -u pplinux/linuxnew/drivers/mtd/chips/cfi_cmdset_0001.c:1.1.323.1 pplinux/linuxnew/drivers/mtd/chips/cfi_cmdset_0001.c:1.3
--- pplinux/linuxnew/drivers/mtd/chips/cfi_cmdset_0001.c:1.1.323.1	Thu Feb  3 10:00:34 2005
+++ pplinux/linuxnew/drivers/mtd/chips/cfi_cmdset_0001.c	Wed Apr  6 11:53:11 2005
@@ -15,7 +15,7 @@
  *	- optimized write buffer method
  * 02/05/2002	Christopher Hoover <ch@hpl.hp.com>/<ch@murgatroid.com>
  *	- reworked lock/unlock/erase support for var size flash
- */
+*/
 
 #include <linux/module.h>
 #include <linux/types.h>
@@ -32,11 +32,21 @@
 #include <linux/mtd/cfi.h>
 #include <linux/mtd/compatmac.h>
 
+typedef enum {
+    PROT_REGOP_READ,
+    PROT_REGOP_WRITE
+} prot_regop_t;
+
 // debugging, turns off buffer write mode #define FORCE_WORD_WRITE
 
 static int cfi_intelext_read (struct mtd_info *, loff_t, size_t, size_t *, u_char *);
+static int cfi_intelext_prot_regop(struct mtd_info *mtd, prot_regop_t regop, loff_t from, size_t len,
+				   size_t *retlen, u_char *buf, int base_offst, int reg_sz);
 static int cfi_intelext_read_user_prot_reg (struct mtd_info *, loff_t, size_t, size_t *, u_char *);
 static int cfi_intelext_read_fact_prot_reg (struct mtd_info *, loff_t, size_t, size_t *, u_char *);
+static int cfi_intelext_write_user_prot_reg (struct mtd_info *, loff_t, size_t, size_t *, u_char *);
+static int cfi_intelext_lock_user_prot_reg (struct mtd_info *);
+static int cfi_intelext_is_user_prot_reg_locked (struct mtd_info *);
 static int cfi_intelext_write_words(struct mtd_info *, loff_t, size_t, size_t *, const u_char *);
 static int cfi_intelext_write_buffers(struct mtd_info *, loff_t, size_t, size_t *, const u_char *);
 static int cfi_intelext_erase_varsize(struct mtd_info *, struct erase_info *);
@@ -106,6 +116,14 @@
 	if (extp->VppOptimal)
 		printk("  Vpp Programming Supply Optimum Program/Erase Voltage: %d.%d V\n", 
 		       extp->VppOptimal >> 8, extp->VppOptimal & 0xf);
+
+	if (extp->FeatureSupport&64) {
+	    printk("  Protection Description\n");
+	    printk("     - NumProtectionFields: %d\n", extp->NumProtectionFields);
+	    printk("     - ProtRegAddr:         %d\n", extp->ProtRegAddr);
+	    printk("     - FactProtRegSize:     %d\n", 1 << extp->FactProtRegSize);
+	    printk("     - UserProtRegSize:     %d\n", 1 << extp->UserProtRegSize);
+	}
 }
 #endif
 
@@ -120,6 +138,10 @@
 {
 	struct cfi_private *cfi = map->fldrv_priv;
 	int i;
+#if defined(PRODUCT_FLASHX4)
+	int b;
+#endif	
+	
 	__u32 base = cfi->chips[0].start;
 
 	if (cfi->cfi_mode == CFI_MODE_CFI) {
@@ -164,7 +186,19 @@
 		extp->FeatureSupport = le32_to_cpu(extp->FeatureSupport);
 		extp->BlkStatusRegMask = le16_to_cpu(extp->BlkStatusRegMask);
 		extp->ProtRegAddr = le16_to_cpu(extp->ProtRegAddr);
-			
+
+#ifdef CONFIG_PEPPERCON
+# warning Hard coded protection description fields!
+		/*
+		  not sure yet why the flash returns 0 to the extended CFI Query
+		  in the protection description fields, replacing manually
+		  for now
+		 */
+		extp->ProtRegAddr = 0x0080;
+		extp->FactProtRegSize = 3;
+		extp->UserProtRegSize = 3;
+#endif
+
 #ifdef DEBUG_CFI_FEATURES
 		/* Tell the user about it in lots of lovely detail */
 		cfi_tell_features(extp);
@@ -193,7 +227,14 @@
 	}		
 
 	map->fldrv = &cfi_intelext_chipdrv;
-	
+
+#if defined(PRODUCT_FLASHX4)	
+	cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL);
+	cfi_send_gen_cmd(0x90, 0, base, map, cfi, cfi->device_type, NULL);
+	b = cfi_read(map,0x2);	
+	map->chip_size = b;
+#endif	
+		
 	/* 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);
@@ -209,7 +250,7 @@
 
 	mtd = kmalloc(sizeof(*mtd), GFP_KERNEL);
 	//printk(KERN_DEBUG "number of CFI chips: %d\n", cfi->numchips);
-
+	
 	if (!mtd) {
 		printk(KERN_ERR "Failed to allocate memory for MTD device\n");
 		goto setup_err;
@@ -218,7 +259,7 @@
 	memset(mtd, 0, sizeof(*mtd));
 	mtd->priv = map;
 	mtd->type = MTD_NORFLASH;
-	mtd->size = devsize * cfi->numchips;
+	mtd->size = devsize * cfi->numchips;	
 
 	mtd->numeraseregions = cfi->cfiq->NumEraseRegions * cfi->numchips;
 	mtd->eraseregions = kmalloc(sizeof(struct mtd_erase_region_info) 
@@ -277,8 +318,14 @@
 		printk("Using word write method\n" );
 		mtd->write = cfi_intelext_write_words;
 	}
+
+	/* protection register access */
 	mtd->read_user_prot_reg = cfi_intelext_read_user_prot_reg;
 	mtd->read_fact_prot_reg = cfi_intelext_read_fact_prot_reg;
+	mtd->write_user_prot_reg = cfi_intelext_write_user_prot_reg;
+	mtd->lock_user_prot_reg = cfi_intelext_lock_user_prot_reg;
+	mtd->is_user_prot_reg_locked = cfi_intelext_is_user_prot_reg_locked;
+	
 	mtd->sync = cfi_intelext_sync;
 	mtd->lock = cfi_intelext_lock;
 	mtd->unlock = cfi_intelext_unlock;
@@ -288,6 +335,9 @@
 	map->fldrv = &cfi_intelext_chipdrv;
 	MOD_INC_USE_COUNT;
 	mtd->name = map->name;
+#if defined(PRODUCT_FLASHX4)	
+	mtd->chip_size = map->chip_size;
+#endif
 	return mtd;
 
  setup_err:
@@ -636,7 +686,8 @@
 	return ret;
 }
 
-static int cfi_intelext_read_prot_reg (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf, int base_offst, int reg_sz)
+ static int cfi_intelext_prot_regop(struct mtd_info *mtd, prot_regop_t regop, loff_t from,
+				    size_t len, size_t *retlen, u_char *buf, int base_offst, int reg_sz)
 {
 	struct map_info *map = mtd->priv;
 	struct cfi_private *cfi = map->fldrv_priv;
@@ -648,12 +699,24 @@
 	unsigned long timeo;
 	DECLARE_WAITQUEUE(wait, current);
 
+	/* Check that we actually have some protection registers */
+	if(!(extp->FeatureSupport & 64)){
+	    printk(KERN_WARNING "%s: This flash device has no protection data to read!\n",map->name);
+	    return 0;
+	}
+
+	if (regop != PROT_REGOP_READ &&
+	    regop != PROT_REGOP_WRITE) {
+	    printk("Unknown protection regop!\n");
+	    goto out;    
+	}
+
 	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;
 
-	while(count){
+	while (count >= 0) {
 		
 		if(chip_num>=cfi->numchips)
 			goto out;
@@ -683,23 +746,60 @@
 			timeo = jiffies + HZ;
 			goto retry;
 		}
-			
-		/* Now read the data required from this flash */
-       
-		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));
+
+		/* Now access the appropriate protection register data */
+		if (regop == PROT_REGOP_READ) {
+		    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*ofs_factor)+offst));
+			//printk("Read %02x from %04x\n", *buf, (chip->start+(extp->ProtRegAddr*ofs_factor)+offst));
 			buf++;
 			offst++;
 			count--;
+		    }
+
+		} else {
+		    int s;
+		    
+		    while(count && ((offst-base_offst)<reg_sz)) {
+			u_int16_t val;
+			unsigned long timeo;
+
+			if (count == 1) {
+			    // its the last byte, zero the other
+			    val = (u_int16_t) *buf;
+			} else {
+			    val = *((u_int16_t*)buf);
+			}
+
+			//printk("Writing %04x to %04x\n", val, (chip->start+(extp->ProtRegAddr*ofs_factor)+offst));
+			
+			map->write8(map, CMD(0xC0), 0x55);
+			map->write16(map, val, (chip->start+(extp->ProtRegAddr*ofs_factor)+offst));
+
+			timeo = jiffies + HZ;
+			map->write8(map, CMD(0x70), 0x55);
+			while (((s = map->read8(map, 0x55)) & 0x80) == 0) {
+			    if (time_after(jiffies, timeo)) {
+				spin_unlock(chip->mutex);
+				printk(KERN_ERR "waiting for chip to be ready timed out during write\n");
+				goto out;
+			    }
+			}
+			
+			buf   +=2;
+			offst +=2;
+			count -=2;
+		    }
 		}
-	       
+
 		chip->state=FL_CFI_QUERY;
 		spin_unlock(chip->mutex);
+		
 		/* Move on to the next chip */
 		chip_num++;
-		offst=base_offst;
-	
+		offst=base_offst;	
 	}
 	
  out:	
@@ -713,17 +813,11 @@
 	struct cfi_private *cfi = map->fldrv_priv;
 	struct cfi_pri_intelext *extp=cfi->cmdset_priv;
 	int base_offst,reg_sz;
-	
-	/* Check that we actually have some protection registers */
-	if(!(extp->FeatureSupport&64)){
-		printk(KERN_WARNING "%s: This flash device has no protection data to read!\n",map->name);
-		return 0;
-	}
-
-	base_offst=(1<<extp->FactProtRegSize);
+	       
+	base_offst=(1<<extp->FactProtRegSize) + 2;
 	reg_sz=(1<<extp->UserProtRegSize);
 
-	return cfi_intelext_read_prot_reg(mtd, from, len, retlen, buf, base_offst, reg_sz);
+	return cfi_intelext_prot_regop(mtd, PROT_REGOP_READ, from, len, retlen, buf, base_offst, reg_sz);
 }
 
 static int cfi_intelext_read_fact_prot_reg (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf)
@@ -733,20 +827,57 @@
 	struct cfi_pri_intelext *extp=cfi->cmdset_priv;
 	int base_offst,reg_sz;
 	
-	/* Check that we actually have some protection registers */
-	if(!(extp->FeatureSupport&64)){
-		printk(KERN_WARNING "%s: This flash device has no protection data to read!\n",map->name);
-		return 0;
+	base_offst=2;
+	reg_sz=(1<<extp->FactProtRegSize);
+
+	return cfi_intelext_prot_regop(mtd, PROT_REGOP_READ, from, len, retlen, buf, base_offst, reg_sz);
+}
+
+static int cfi_intelext_write_user_prot_reg (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf)
+{
+	struct map_info *map = mtd->priv;
+	struct cfi_private *cfi = map->fldrv_priv;
+	struct cfi_pri_intelext *extp=cfi->cmdset_priv;
+	int base_offst,reg_sz;
+	
+	if (len % 2) {
+	    printk("User protection reg only writable in 16bit increments (Len=%d)\n", len);
+	    return 0;
 	}
 
-	base_offst=0;
-	reg_sz=(1<<extp->FactProtRegSize);
+	base_offst=(1<<extp->FactProtRegSize) + 2;
+	reg_sz=(1<<extp->UserProtRegSize);
 
-	return cfi_intelext_read_prot_reg(mtd, from, len, retlen, buf, base_offst, reg_sz);
+	return cfi_intelext_prot_regop(mtd, PROT_REGOP_WRITE, from, len, retlen, buf, base_offst, reg_sz);
 }
 
+static int cfi_intelext_lock_user_prot_reg (struct mtd_info *mtd)
+{
+    int base_offst, reg_sz, retlen;
+    unsigned short lock = 0xFFFC; 
+
+    base_offst=0;
+    reg_sz=2;
+
+    cfi_intelext_prot_regop(mtd, PROT_REGOP_WRITE, 0, sizeof(lock), &retlen, (u_char*)&lock, base_offst, reg_sz);
+    
+    return 0;
+}
+
+static int cfi_intelext_is_user_prot_reg_locked (struct mtd_info *mtd)
+{
+    int base_offst,reg_sz, retlen;
+    unsigned short lock = 0;
+    
+    base_offst=0;
+    reg_sz=2;
+
+    cfi_intelext_prot_regop(mtd, PROT_REGOP_READ, 0, sizeof(lock), &retlen, (u_char*)&lock, base_offst, reg_sz);
+
+    return (lock == 0xFFFC) ? 1 : 0;
+}
 
-static int do_write_oneword(struct map_info *map, struct flchip *chip, unsigned long adr, cfi_word datum)
+ 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;
Index: pplinux/linuxnew/drivers/mtd/maps/Config.in
diff -u pplinux/linuxnew/drivers/mtd/maps/Config.in:1.1.323.1 pplinux/linuxnew/drivers/mtd/maps/Config.in:1.2
--- pplinux/linuxnew/drivers/mtd/maps/Config.in:1.1.323.1	Thu Feb  3 10:00:34 2005
+++ pplinux/linuxnew/drivers/mtd/maps/Config.in	Thu Feb  3 11:35:38 2005
@@ -8,8 +8,10 @@
 
 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
+  if [ "$CONFIG_PEPPERCON" != "y" ]; then
    hex '    Physical start address of flash mapping' CONFIG_MTD_PHYSMAP_START 0x8000000
    hex '    Physical length of flash mapping' CONFIG_MTD_PHYSMAP_LEN 0x4000000
+  fi
    int '    Bus width in octets' CONFIG_MTD_PHYSMAP_BUSWIDTH 2
 fi
 
Index: pplinux/linuxnew/drivers/mtd/maps/Makefile
diff -u pplinux/linuxnew/drivers/mtd/maps/Makefile:1.1.323.1 pplinux/linuxnew/drivers/mtd/maps/Makefile:1.3
--- pplinux/linuxnew/drivers/mtd/maps/Makefile:1.1.323.1	Thu Feb  3 10:00:34 2005
+++ pplinux/linuxnew/drivers/mtd/maps/Makefile	Wed Apr  6 11:53:11 2005
@@ -32,9 +32,12 @@
   ifeq ($(CONFIG_MTD_PHYSMAP_BUSWIDTH),8)
     obj-$(CONFIG_MTD_PHYSMAP)	+= physmap64.o 
   else
-    obj-$(CONFIG_MTD_PHYSMAP)	+= physmap.o 
+    obj-$(CONFIG_MTD_PHYSMAP)	+= physmap.o
   endif
 endif
+ifeq ($(PP_PRODUCT), flashx4)
+obj-$(CONFIG_MTD_PHYSMAP)	+= physmap_fp.o	
+endif
 obj-$(CONFIG_MTD_PNC2000)	+= pnc2000.o
 obj-$(CONFIG_MTD_PCMCIA)	+= pcmciamtd.o
 obj-$(CONFIG_MTD_RPXLITE)	+= rpxlite.o
Index: pplinux/linuxnew/drivers/mtd/maps/physmap.c
diff -u pplinux/linuxnew/drivers/mtd/maps/physmap.c:1.1.323.1 pplinux/linuxnew/drivers/mtd/maps/physmap.c:1.2
--- pplinux/linuxnew/drivers/mtd/maps/physmap.c:1.1.323.1	Thu Feb  3 10:00:34 2005
+++ pplinux/linuxnew/drivers/mtd/maps/physmap.c	Thu Feb  3 11:35:38 2005
@@ -12,14 +12,22 @@
 #include <linux/mtd/map.h>
 #include <linux/config.h>
 
-#ifdef CONFIG_MTD_PARTITIONS
+#if defined(CONFIG_MTD_PARTITIONS) || defined(CONFIG_MTD_PARTITIONS_MODULE)
 #include <linux/mtd/partitions.h>
 #endif
 
-#define WINDOW_ADDR CONFIG_MTD_PHYSMAP_START
-#define WINDOW_SIZE CONFIG_MTD_PHYSMAP_LEN
+#ifdef CONFIG_PEPPERCON
+# include "asm/ibm4xx.h"
+# define WINDOW_ADDR bd->bi_flashstart
+# define WINDOW_SIZE bd->bi_flashsize
+#else
+# define WINDOW_ADDR CONFIG_MTD_PHYSMAP_START
+# define WINDOW_SIZE CONFIG_MTD_PHYSMAP_LEN
+#endif
+
 #define BUSWIDTH CONFIG_MTD_PHYSMAP_BUSWIDTH
 
+static char * mtd_id = "phys";
 static struct mtd_info *mymtd;
 
 __u8 physmap_read8(struct map_info *map, unsigned long ofs)
@@ -67,7 +75,6 @@
 
 struct map_info physmap_map = {
 	name: "Physically mapped flash",
-	size: WINDOW_SIZE,
 	buswidth: BUSWIDTH,
 	read8: physmap_read8,
 	read16: physmap_read16,
@@ -76,11 +83,14 @@
 	write8: physmap_write8,
 	write16: physmap_write16,
 	write32: physmap_write32,
-	copy_to: physmap_copy_to
+	copy_to: physmap_copy_to,
+#ifndef CONFIG_PEPPERCON
+	size: WINDOW_SIZE,
+#endif
 };
 
-#ifdef CONFIG_MTD_PARTITIONS
-#ifdef CONFIG_MTD_CMDLINE_PARTS
+#if defined(CONFIG_MTD_PARTITIONS) || defined(CONFIG_MTD_PARTITIONS_MODULE)
+#if defined(CONFIG_MTD_CMDLINE_PARTS) || defined(CONFIG_MTD_CMDLINE_PARTS_MODULE)
 static struct mtd_partition *mtd_parts = 0;
 static int                   mtd_parts_nb = 0;
 #else
@@ -120,7 +130,14 @@
 	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);
+#ifdef CONFIG_PEPPERCON
+	/* we determine flash address and size
+	   dynamically from board info */
+	bd_t * bd = (bd_t *)__res;
+	physmap_map.size = WINDOW_SIZE;
+#endif	
+	
+       	printk(KERN_NOTICE "physmap flash device: %lx at %lx\n", WINDOW_SIZE, WINDOW_ADDR);
 	physmap_map.map_priv_1 = (unsigned long)ioremap(WINDOW_ADDR, WINDOW_SIZE);
 
 	if (!physmap_map.map_priv_1) {
@@ -136,11 +153,10 @@
 	if (mymtd) {
 		mymtd->module = THIS_MODULE;
 
-		add_mtd_device(mymtd);
-#ifdef CONFIG_MTD_PARTITIONS
-#ifdef CONFIG_MTD_CMDLINE_PARTS
+#if defined(CONFIG_MTD_PARTITIONS) || defined(CONFIG_MTD_PARTITIONS_MODULE)
+#if defined(CONFIG_MTD_CMDLINE_PARTS) || defined(CONFIG_MTD_CMDLINE_PARTS_MODULE)
 		mtd_parts_nb = parse_cmdline_partitions(mymtd, &mtd_parts, 
-							"phys");
+							mtd_id);
 		if (mtd_parts_nb > 0)
 		{
 			printk(KERN_NOTICE 
@@ -156,6 +172,8 @@
 		}
 
 #endif
+#else
+		add_mtd_device(mymtd);
 #endif
 		return 0;
 	}
@@ -167,7 +185,11 @@
 static void __exit cleanup_physmap(void)
 {
 	if (mymtd) {
+#if defined(CONFIG_MTD_PARTITIONS) || defined(CONFIG_MTD_PARTITIONS_MODULE)
+		del_mtd_partitions(mymtd);
+#else
 		del_mtd_device(mymtd);
+#endif
 		map_destroy(mymtd);
 	}
 	if (physmap_map.map_priv_1) {
@@ -179,6 +201,10 @@
 module_init(init_physmap);
 module_exit(cleanup_physmap);
 
+#if defined(CONFIG_MTD_PARTITIONS_MODULE) && defined(CONFIG_MTD_CMDLINE_PARTS_MODULE)
+MODULE_PARM(mtd_id, "s");
+MODULE_PARM_DESC(mtd_id, "Select mtd_id");
+#endif
 
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>");
Index: pplinux/linuxnew/drivers/mtd/maps/physmap_fp.c
diff -u /dev/null pplinux/linuxnew/drivers/mtd/maps/physmap_fp.c:1.1
--- /dev/null	Tue May 24 10:37:59 2005
+++ pplinux/linuxnew/drivers/mtd/maps/physmap_fp.c	Wed Apr  6 11:53:11 2005
@@ -0,0 +1,218 @@
+/*
+ * $Id: physmap_fp.c,v 1.1 2005/04/06 09:53:11 rwa Exp $
+ *
+ * Normal mappings of chips in physical memory
+ */
+
+#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/config.h>
+
+#if defined(CONFIG_MTD_PARTITIONS) || defined(CONFIG_MTD_PARTITIONS_MODULE)
+#include <linux/mtd/partitions.h>
+#endif
+
+#ifdef CONFIG_PEPPERCON
+# include "asm/ibm4xx.h"
+# define WINDOW_ADDR 0xf1000000
+# define WINDOW_SIZE mtd_size
+#else
+# define WINDOW_ADDR CONFIG_MTD_PHYSMAP_START
+# define WINDOW_SIZE CONFIG_MTD_PHYSMAP_LEN
+#endif
+
+#define BUSWIDTH CONFIG_MTD_PHYSMAP_BUSWIDTH
+
+static char * mtd_id = "phys";
+static long   mtd_size = 0x800000;
+
+static struct mtd_info *mymtd;
+
+__u8 physmap_fp_read8(struct map_info *map, unsigned long ofs)
+{
+    return __raw_readb(map->map_priv_1 + ofs);
+}
+
+__u16 physmap_fp_read16(struct map_info *map, unsigned long ofs)
+{ 
+    return __raw_readw(map->map_priv_1 + ofs);
+}
+
+__u32 physmap_fp_read32(struct map_info *map, unsigned long ofs)
+{
+    return __raw_readl(map->map_priv_1 + ofs);
+}
+
+void physmap_fp_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
+{
+    memcpy_fromio(to, map->map_priv_1 + from, len);
+}
+
+void physmap_fp_write8(struct map_info *map, __u8 d, unsigned long adr)
+{
+    __raw_writeb(d, map->map_priv_1 + adr);
+    mb();
+}
+
+void physmap_fp_write16(struct map_info *map, __u16 d, unsigned long adr)
+{
+    __raw_writew(d, map->map_priv_1 + adr);
+    mb();
+}
+
+void physmap_fp_write32(struct map_info *map, __u32 d, unsigned long adr)
+{
+    __raw_writel(d, map->map_priv_1 + adr);
+    mb();
+}
+
+void physmap_fp_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 physmap_fp_map = {
+	name: "Physically mapped flash",
+	buswidth: BUSWIDTH,
+	read8: physmap_fp_read8,
+	read16: physmap_fp_read16,
+	read32: physmap_fp_read32,
+	copy_from: physmap_fp_copy_from,
+	write8: physmap_fp_write8,
+	write16: physmap_fp_write16,
+	write32: physmap_fp_write32,
+	copy_to: physmap_fp_copy_to,
+#ifndef CONFIG_PEPPERCON
+	size: WINDOW_SIZE,
+#endif
+};
+
+#if defined(CONFIG_MTD_PARTITIONS) || defined(CONFIG_MTD_PARTITIONS_MODULE)
+#if defined(CONFIG_MTD_CMDLINE_PARTS) || defined(CONFIG_MTD_CMDLINE_PARTS_MODULE)
+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
+
+int __init init_physmap_fp(void)
+{
+	static const char *rom_probe_types[] = { "cfi_probe", "jedec_probe", "map_rom", 0 };
+	const char **type;
+
+#ifdef CONFIG_PEPPERCON
+	/* we determine flash address and size
+	   dynamically from board info */
+	//bd_t * bd = (bd_t *)__res;
+	physmap_fp_map.size = mtd_size;
+#endif	
+	
+       	printk(KERN_NOTICE "physmap flash device: %lx at %lx\n", mtd_size, WINDOW_ADDR);
+	physmap_fp_map.map_priv_1 = (unsigned long)ioremap(WINDOW_ADDR, mtd_size);
+
+	if (!physmap_fp_map.map_priv_1) {
+		printk("Failed to ioremap\n");
+		return -EIO;
+	}
+
+	mymtd = 0;
+	type = rom_probe_types;
+	for(; !mymtd && *type; type++) {
+		mymtd = do_map_probe(*type, &physmap_fp_map);
+	}
+
+	if (mymtd) {
+		mymtd->module = THIS_MODULE;
+
+#if defined(CONFIG_MTD_PARTITIONS) || defined(CONFIG_MTD_PARTITIONS_MODULE)
+#if defined(CONFIG_MTD_CMDLINE_PARTS) || defined(CONFIG_MTD_CMDLINE_PARTS_MODULE)
+		mtd_parts_nb = parse_cmdline_partitions(mymtd, &mtd_parts, 
+							mtd_id);
+
+		if (mtd_parts_nb > 0)
+		{
+			printk(KERN_NOTICE 
+			       "Using command line partition definition\n");
+			
+			add_mtd_partitions (mymtd, mtd_parts, mtd_parts_nb);
+		}
+#else
+		if (NUM_PARTITIONS != 0) 
+		{
+			printk(KERN_NOTICE 
+			       "Using physmap partition definition\n");
+			add_mtd_partitions (mymtd, physmap_partitions, NUM_PARTITIONS);
+		}
+
+#endif
+#else
+		add_mtd_device(mymtd);
+#endif
+		return 0;
+	}
+	iounmap((void *)physmap_fp_map.map_priv_1);
+	return -ENXIO;
+}
+
+static void __exit cleanup_physmap_fp(void)
+{
+	if (mymtd) {
+#if defined(CONFIG_MTD_PARTITIONS) || defined(CONFIG_MTD_PARTITIONS_MODULE)
+		del_mtd_partitions(mymtd);
+#else
+		del_mtd_device(mymtd);
+#endif
+		map_destroy(mymtd);
+	}
+	if (physmap_fp_map.map_priv_1) {
+		iounmap((void *)physmap_fp_map.map_priv_1);
+		physmap_fp_map.map_priv_1 = 0;
+	}
+}
+
+module_init(init_physmap_fp);
+module_exit(cleanup_physmap_fp);
+
+#if defined(CONFIG_MTD_PARTITIONS_MODULE) && defined(CONFIG_MTD_CMDLINE_PARTS_MODULE)
+MODULE_PARM(mtd_id, "s");
+MODULE_PARM_DESC(mtd_id, "Select mtd_id");
+MODULE_PARM(mtd_size, "l");
+MODULE_PARM_DESC(mtd_size, "Select flash size");
+#endif
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>");
+MODULE_DESCRIPTION("Generic configurable MTD map driver");
+
Index: pplinux/linuxnew/drivers/net/8139too.c
diff -u pplinux/linuxnew/drivers/net/8139too.c:1.1.323.1 pplinux/linuxnew/drivers/net/8139too.c:1.2
--- pplinux/linuxnew/drivers/net/8139too.c:1.1.323.1	Thu Feb  3 10:00:52 2005
+++ pplinux/linuxnew/drivers/net/8139too.c	Thu Feb  3 11:35:38 2005
@@ -124,7 +124,7 @@
 
 /* enable PIO instead of MMIO, if CONFIG_8139TOO_PIO is selected */
 #ifdef CONFIG_8139TOO_PIO
-#define USE_IO_OPS 1
+#error PIO is not possible, only the pci memory is mapped (powerpc - pci bus)
 #endif
 
 /* use a 16K rx ring buffer instead of the default 32K */
Index: pplinux/linuxnew/drivers/net/ibm_emac/ibm_ocp_enet.c
diff -u pplinux/linuxnew/drivers/net/ibm_emac/ibm_ocp_enet.c:1.1.323.1 pplinux/linuxnew/drivers/net/ibm_emac/ibm_ocp_enet.c:1.3
--- pplinux/linuxnew/drivers/net/ibm_emac/ibm_ocp_enet.c:1.1.323.1	Thu Feb  3 10:00:54 2005
+++ pplinux/linuxnew/drivers/net/ibm_emac/ibm_ocp_enet.c	Wed Apr  6 11:53:12 2005
@@ -68,6 +68,8 @@
 #include <linux/skbuff.h>
 #include <linux/crc32.h>
 
+/* to get the EMAC0_BASE for the PHYs */
+#include <platforms/ibm405ep.h>
 #include "ibm_ocp_enet.h"
 
 //#define MDIO_DEBUG(fmt) printk fmt
@@ -116,7 +118,13 @@
  * to avoid re-using the same PHY ID in cases where the arch didn't
  * setup precise emac_phy_map entries
  */
+#if 0
 static u32 busy_phy_map = 0;
+#endif
+
+int ignore_phy[2] = { 0, 0};
+
+static volatile emac_t *phy_emacp;
 
 static struct net_device_stats *
 emac_stats(struct net_device *dev)
@@ -228,19 +236,25 @@
 	register int i;
 	uint32_t stacr;
 	struct ocp_enet_private *fep = dev->priv;
+#if 0
 	volatile emac_t *emacp = fep->emacp;
+#else
+	volatile emac_t *emacp = phy_emacp;
+#endif
 
-	MDIO_DEBUG(("%s: phy_read, id: 0x%x, reg: 0x%x\n", dev->name, mii_id, reg));
+	MDIO_DEBUG(("%s: phy_read, id: 0x%x, reg: 0x%x, %p\n", dev->name, mii_id, reg, &emacp->em0stacr));
 
 	/* Enable proper ZMII port */
 	if (fep->zmii_dev)
 		emac_enable_zmii_port(fep->zmii_dev, fep->zmii_input);
+#if 0
 	/* Use the EMAC that has the MDIO port */
 	if (fep->mdio_dev) {
 		dev = fep->mdio_dev;
 		fep = dev->priv;
 	}
-	
+#endif
+
 	/* Wait for data transfer complete bit */
 	for (i = 0; i < OCP_RESET_DELAY; ++i) {
 		if (emacp->em0stacr & EMAC_STACR_OC)
@@ -287,19 +301,25 @@
 	register int i = 0;
 	uint32_t stacr;
 	struct ocp_enet_private *fep = dev->priv;
+#if 0
 	volatile emac_t *emacp = fep->emacp;
+#else
+	volatile emac_t *emacp = phy_emacp;
+#endif
 
-	MDIO_DEBUG(("%s phy_write, id: 0x%x, reg: 0x%x, data: 0x%x\n",
-            dev->name, mii_id, reg, data));
+	MDIO_DEBUG(("%s phy_write, id: 0x%x, reg: 0x%x, data: 0x%x, reg: %p\n",
+            dev->name, mii_id, reg, data, &emacp->em0stacr));
 
 	/* Enable proper ZMII port */
 	if (fep->zmii_dev)
 		emac_enable_zmii_port(fep->zmii_dev, fep->zmii_input);
+#if 0
 	/* Use the EMAC that has the MDIO port */
 	if (fep->mdio_dev) {
 		dev = fep->mdio_dev;
 		fep = dev->priv;
 	}
+#endif
 
 	/* Wait for data transfer complete bit */
 	for (i = 0; i < OCP_RESET_DELAY; ++i) {
@@ -334,6 +354,7 @@
         }
 }
 
+#if 0
 static void
 emac_wakeup_irq(int irq, void *param, struct pt_regs *regs)
 {
@@ -344,6 +365,7 @@
 	 */
 	printk(KERN_INFO "%s: WakeUp interrupt !\n", dev->name);
 }
+#endif
 
 static void
 emac_txeob_dev(void *param, u32 chanmask)
@@ -914,8 +936,7 @@
 	int forced_duplex;
 
 	/* Default advertise */
-	advertise = ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full |
-		    ADVERTISED_100baseT_Half | ADVERTISED_100baseT_Full;
+	advertise = fep->advertising;
 	autoneg = fep->want_autoneg;
 	forced_speed = fep->phy_mii.speed;
 	forced_duplex = fep->phy_mii.duplex;
@@ -924,6 +945,7 @@
 	if (ep) {
 	    if (ep->autoneg == AUTONEG_ENABLE) {
 		advertise = ep->advertising;
+		fep->advertising = advertise;
 		autoneg = 1;
 	    } else {
 		autoneg = 0;
@@ -1024,7 +1046,8 @@
         case ETHTOOL_GSET:
                 ecmd.supported = features;
                 ecmd.port = PORT_MII;
-                ecmd.transceiver = XCVR_EXTERNAL;
+		/* rwa-hack: XCVR_DUMMY1 means no PHY! */ 
+                ecmd.transceiver = ignore_phy[fep->phy_mii.mii_id] ? XCVR_DUMMY1 : XCVR_EXTERNAL;
                 ecmd.phy_address = fep->mii_phy_addr;
                 spin_lock_irq(&fep->lock);
                 ecmd.autoneg = fep->want_autoneg;
@@ -1101,7 +1124,7 @@
 emac_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
 {
 	struct ocp_enet_private *fep = dev->priv;
-	uint *data = (uint *) & rq->ifr_data;
+	ushort *data = (ushort *) & rq->ifr_data;
 
 	switch (cmd) {
         case SIOCETHTOOL:
@@ -1135,8 +1158,8 @@
 	spin_lock_irq(&fep->lock);
 
 	fep->opened = 1;
-        
-        /* Reset & configure the chip */
+ 
+	/* Reset & configure the chip */
         emac_reset_configure(fep);
 
 	spin_unlock_irq(&fep->lock);
@@ -1145,11 +1168,16 @@
 	rc = request_irq(dev->irq, emac_mac_irq, 0, "OCP EMAC MAC", dev);
 	if (rc != 0)
 		goto bail;
+	/* look into emac_wakeup_irc function for reason of commenting
+	 * this out */
+#if 0
+
 	rc = request_irq(fep->wol_irq, emac_wakeup_irq, 0, "OCP EMAC Wakeup", dev);
 	if (rc != 0) {
 		free_irq(dev->irq, dev);
 		goto bail;
 	}
+#endif
         /* Kick the chip rx & tx channels into life */ 
 	spin_lock_irq(&fep->lock);
         emac_kick(fep);
@@ -1230,7 +1258,10 @@
 	struct ocp_device *mdiodev;
 	struct net_device *mdio_ndev = NULL;
 	int commac_reg = 0;
+#if 0
 	u32 phy_map;
+#endif
+	int phy_addr;
 	
 	emacdata = (struct ocp_func_emac_data *)ocpdev->def->additions;
 	if (emacdata == NULL) {
@@ -1250,11 +1281,15 @@
 	/* If we depend on another EMAC for MDIO, wait for it to show up */
 	if (emacdata->mdio_idx >= 0 && emacdata->mdio_idx != ocpdev->def->index) {
 		mdiodev = ocp_find_device(OCP_ANY_ID, OCP_FUNC_EMAC, emacdata->mdio_idx);
-		if (mdiodev == NULL)
+		if (mdiodev == NULL) {
+			printk("didn't found other mdio if\n");
 			return -EAGAIN;
+		}
 		mdio_ndev = (struct net_device *)ocp_get_drvdata(mdiodev);
-		if (mdio_ndev == NULL)
+		if (mdio_ndev == NULL) {
+			printk("didn't found other mdio if2\n");
 			return -EAGAIN;
+		}
 	}
 
 	/* Allocate our net_device structure */
@@ -1328,6 +1363,7 @@
 	ep->phy_mii.mdio_write = emac_phy_write;
 
 	/* Find PHY */
+#if 0
 	phy_map = emac_phy_map[ocpdev->def->index] | busy_phy_map;
 	for (i = 0; i <= 0x1f; i++, phy_map >>= 1) {
 		if ((phy_map & 0x1) == 0) {
@@ -1336,14 +1372,38 @@
 			        break;
 		}
 	}
+#else
+	/* the phy address is static: emac0: 1, emac1: 0 */
+	phy_addr = ocpdev->def->index ? 0 : 1;
+	int  val = emac_phy_read(ndev, phy_addr, MII_BMCR);
+	if (ignore_phy[phy_addr]) {
+		val = 0;
+	}
+	if (val != 0xffff && val != -1) {
+		//i = ocpdev->def->index;
+		i = 0;
+	} else {
+# ifdef PP_FEAT_ETH_MAC_DIRECT_CONNECT
+		i = 0;
+		ignore_phy[phy_addr] = 1;
+# else
+		i = 0x20;
+# endif
+	}
+#endif
 	if (i == 0x20) {
 	        printk(KERN_WARNING "emac%d: Can't find PHY.\n", ocpdev->def->index);
 		rc = -ENODEV;
 		goto bail;
 	}
+#if 0
 	busy_phy_map |= 1 << i;
 	ep->mii_phy_addr = i;
 	rc = mii_phy_probe(&ep->phy_mii, i);
+#else
+	ep->mii_phy_addr = phy_addr;
+	rc = mii_phy_probe(&ep->phy_mii, phy_addr);
+#endif
 	if (rc) {
 	        printk(KERN_WARNING "emac%d: Failed to probe PHY type.\n", ocpdev->def->index);
 		rc = -ENODEV;
@@ -1354,15 +1414,25 @@
 	if (ep->phy_mii.def->ops->init)
 	        ep->phy_mii.def->ops->init(&ep->phy_mii);
 	netif_carrier_off(ndev);
-        if (ep->phy_mii.def->features & SUPPORTED_Autoneg)
+        if (ep->phy_mii.def->features & SUPPORTED_Autoneg) {
                 ep->want_autoneg = 1;
+		ep->advertising =
+			ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full |
+			ADVERTISED_100baseT_Half | ADVERTISED_100baseT_Full;
+	}
 	emac_start_link(ep, NULL);
 
 
 	/* read the MAC Address */
 	bd = (bd_t *) __res;
-	for (i = 0; i < 6; i++)
-		ndev->dev_addr[i] = bd->BD_EMAC_ADDR(ocpdev->def->index, i);	/* Marco to disques array */
+	for (i = 0; i < 6; i++) {
+#if 0
+		ndev->dev_addr[i] = bd->BD_EMAC_ADDR(ocpdev->def->index, i);
+#else
+		// use always addr 0
+		ndev->dev_addr[i] = bd->BD_EMAC_ADDR(0, i);
+#endif
+	}
 
 	/* Fill in the driver function table */
 	ndev->open = &emac_open;
@@ -1412,6 +1482,31 @@
 	.remove		= emac_remove,
 };
 
+static int __init ibm_ocp_enet_ignore_phy(char *str)
+{
+	int i;
+	
+	for (i = 0; i < 2; i++) {
+		int retval;
+		int ignore;
+
+		retval = get_option(&str, &ignore);
+
+		if (!retval)
+			break; /* no number found */
+
+		if (ignore) {
+			ignore_phy[i] = 1;
+			printk("ibm_ocp_net ignores phy on interface: %i\n", i);
+		}
+
+		if (retval != 2)
+			break; /* no next number */
+	}
+	return 1;
+}
+__setup("ibm_ocp_enet_ignore_phy=", ibm_ocp_enet_ignore_phy);
+
 static int __init
 emac_init(void)
 {
@@ -1419,11 +1514,13 @@
 	
         printk(KERN_INFO DRV_NAME ": " DRV_DESC ", version " DRV_VERSION "\n");
         printk(KERN_INFO "Maintained by " DRV_AUTHOR "\n");
-
+	printk(KERN_INFO "ignore_phy: %d, %d\n", ignore_phy[0], ignore_phy[1]);
 	if (skb_res > 2) {
 	    printk(KERN_WARNING "Invalid skb_res: %d, cropping to 2\n", skb_res);
 	    skb_res = 2;
 	}
+	phy_emacp = (volatile emac_t *)ioremap(EMAC0_BASE, sizeof (emac_t));
+
 	rc = ocp_register_driver(&emac_driver);
 	if (rc == 0) {
 		ocp_unregister_driver(&emac_driver);
@@ -1439,6 +1536,9 @@
 emac_exit(void)
 {
 	ocp_unregister_driver(&emac_driver);
+	iounmap((void*)phy_emacp);
+	/* sanity */
+	phy_emacp = NULL;
 }
 
 module_init(emac_init);
Index: pplinux/linuxnew/drivers/net/ibm_emac/ibm_ocp_enet.h
diff -u pplinux/linuxnew/drivers/net/ibm_emac/ibm_ocp_enet.h:1.1.323.1 pplinux/linuxnew/drivers/net/ibm_emac/ibm_ocp_enet.h:1.2
--- pplinux/linuxnew/drivers/net/ibm_emac/ibm_ocp_enet.h:1.1.323.1	Thu Feb  3 10:00:54 2005
+++ pplinux/linuxnew/drivers/net/ibm_emac/ibm_ocp_enet.h	Thu Feb  3 11:35:38 2005
@@ -136,6 +136,7 @@
 	struct mii_phy phy_mii;
         int mii_phy_addr;
         int want_autoneg;
+	u32 advertising;
         int timer_ticks;
 	struct timer_list link_timer;
 	struct net_device *mdio_dev;
Index: pplinux/linuxnew/drivers/net/ibm_emac/ibm_ocp_phy.c
diff -u pplinux/linuxnew/drivers/net/ibm_emac/ibm_ocp_phy.c:1.1.323.1 pplinux/linuxnew/drivers/net/ibm_emac/ibm_ocp_phy.c:1.3
--- pplinux/linuxnew/drivers/net/ibm_emac/ibm_ocp_phy.c:1.1.323.1	Thu Feb  3 10:00:54 2005
+++ pplinux/linuxnew/drivers/net/ibm_emac/ibm_ocp_phy.c	Wed Apr  6 11:53:12 2005
@@ -27,7 +27,11 @@
 
 #include "ibm_ocp_phy.h"
 
+// debug
+//#define PRINTK(fmt, args...) printk(KERN_INFO "%s: " fmt, __FUNCTION__ , ## args)
+#define PRINTK(fmt, args...)
 
+extern int ignore_phy[2];
 static inline int __phy_read(struct mii_phy* phy, int id, int reg)
 {
 	return phy->mdio_read(phy->dev, id, reg);
@@ -53,6 +57,10 @@
 	u16 val;
 	int limit = 10000;
 	
+#ifdef CONFIG_PEPPERCON
+	/* save LED configuration */
+	u16 led_cfg = __phy_read(phy, phy_id, 0x14);
+#endif
 	val = __phy_read(phy, phy_id, MII_BMCR);
 	val &= ~BMCR_ISOLATE;
 	val |= BMCR_RESET;
@@ -68,6 +76,14 @@
 	}
 	if ((val & BMCR_ISOLATE) && limit > 0)
 		__phy_write(phy, phy_id, MII_BMCR, val & ~BMCR_ISOLATE);
+#ifdef CONFIG_PEPPERCON
+	/* clear the CRS Select bit - this solves problems with 10BaseT */
+	val = __phy_read(phy, phy_id, 0x10);
+	val &= ~0x80DD; // clear CRS Select and reserved bits
+	__phy_write(phy, phy_id, 0x10, val);
+	/* restore LED configuration */
+	__phy_write(phy, phy_id, 0x14, led_cfg);
+#endif
 	
 	return (limit <= 0);
 }
@@ -75,12 +91,16 @@
 static int genmii_setup_aneg(struct mii_phy *phy, u32 advertise)
 {
 	u16 ctl, adv;
-	
 	phy->autoneg = 1;
 	phy->speed = SPEED_10;
 	phy->duplex = DUPLEX_HALF;
 	phy->pause = 0;
 	phy->advertising = advertise;
+	
+	if (phy && ignore_phy[phy->mii_id]) {
+		PRINTK("ignore phy: %d\n", phy->mii_id);
+		return 0;
+	}
 
 	/* Setup standard advertise */
 	adv = phy_read(phy, MII_ADVERTISE);
@@ -106,12 +126,16 @@
 static int genmii_setup_forced(struct mii_phy *phy, int speed, int fd)
 {
 	u16 ctl;
-	
 	phy->autoneg = 0;
 	phy->speed = speed;
 	phy->duplex = fd;
 	phy->pause = 0;
 
+	if (phy && ignore_phy[phy->mii_id]) {
+		PRINTK("ignore phy: %d\n", phy->mii_id);
+		return 0;
+	}
+
 	ctl = phy_read(phy, MII_BMCR);
 	ctl &= ~(BMCR_FULLDPLX|BMCR_SPEED100|BMCR_ANENABLE);
 
@@ -131,7 +155,11 @@
 	}
 	if (fd == DUPLEX_FULL)
 		ctl |= BMCR_FULLDPLX;
-	phy_write(phy, MII_BMCR, ctl);
+
+	/* reset recovery delay */
+	udelay(300);
+	
+	phy_write(phy, MII_BMCR, ctl); 
 
 	return 0;
 }
@@ -140,6 +168,11 @@
 {
 	u16 status;
 	
+	if ((phy && ignore_phy[phy->mii_id])) {
+		//PRINTK("not ignore phy: %d\n", phy->mii_id);
+		return 1;
+	}
+	
 	(void)phy_read(phy, MII_BMSR);
 	status = phy_read(phy, MII_BMSR);
 	if ((status & BMSR_LSTATUS) == 0)
@@ -151,16 +184,24 @@
 
 static int genmii_read_link(struct mii_phy *phy)
 {
-	u16 lpa;
+	u16 adv, lpa;
+
+	if (phy && ignore_phy[phy->mii_id]) {
+		PRINTK("ignore phy: %d\n", phy->mii_id);
+		phy->speed = SPEED_100;
+		phy->duplex = DUPLEX_FULL;
+		return 0;
+	}
 
 	if (phy->autoneg) {
+		adv = phy_read(phy, MII_ADVERTISE);
 		lpa = phy_read(phy, MII_LPA);
 
-		if (lpa & (LPA_10FULL | LPA_100FULL))
+		if ((lpa & adv) & (LPA_10FULL | LPA_100FULL))
 			phy->duplex = DUPLEX_FULL;
 		else
 			phy->duplex = DUPLEX_HALF;
-		if (lpa & (LPA_100FULL | LPA_100HALF))
+		if ((lpa & adv) & (LPA_100FULL | LPA_100HALF))
 			phy->speed = SPEED_100;
 		else
 			phy->speed = SPEED_10;
@@ -209,13 +250,21 @@
 	u32 id;
 	struct mii_phy_def* def;
 	int i;
-	
 	phy->autoneg = 0;
 	phy->advertising = 0;
 	phy->mii_id = mii_id;
 	phy->speed = 0;
 	phy->duplex = 0;
 	phy->pause = 0;
+
+	PRINTK("mii_phy_probe: %d\n", mii_id);	
+	if (ignore_phy[mii_id]) {
+		PRINTK("ignore phy: %d\n", mii_id);
+		// set some defaults, phy is not used
+		phy->def = mii_phy_table[0];
+		phy->advertising = phy->def->features;
+		return 0;
+	}
 	
 	/* Take PHY out of isloate mode and reset it. */
 	rc = reset_one_mii_phy(phy, mii_id);
Index: pplinux/linuxnew/drivers/pci/pci.c
diff -u pplinux/linuxnew/drivers/pci/pci.c:1.1.323.1 pplinux/linuxnew/drivers/pci/pci.c:1.2
--- pplinux/linuxnew/drivers/pci/pci.c:1.1.323.1	Thu Feb  3 10:00:51 2005
+++ pplinux/linuxnew/drivers/pci/pci.c	Thu Feb  3 11:35:38 2005
@@ -28,7 +28,7 @@
 #include <asm/page.h>
 #include <asm/dma.h>	/* isa_dma_bridge_buggy */
 
-#undef DEBUG
+#define DEBUG
 
 #ifdef DEBUG
 #define DBG(x...) printk(x)
Index: pplinux/linuxnew/include/asm-ppc/dma.h
diff -u pplinux/linuxnew/include/asm-ppc/dma.h:1.1.323.1 pplinux/linuxnew/include/asm-ppc/dma.h:1.2
--- pplinux/linuxnew/include/asm-ppc/dma.h:1.1.323.1	Thu Feb  3 10:00:13 2005
+++ pplinux/linuxnew/include/asm-ppc/dma.h	Thu Feb  3 11:35:38 2005
@@ -188,6 +188,8 @@
 	spin_unlock_irqrestore(&dma_spin_lock, flags);
 }
 
+#if !defined(CONFIG_PEPPERCON)
+
 /* enable/disable a specific DMA channel */
 static __inline__ void
 enable_dma(unsigned int dmanr)
@@ -370,6 +372,8 @@
 /* release it again */
 extern void free_dma(unsigned int dmanr);
 
+#endif /* !CONFIG_PEPPERCON */
+
 #ifndef MAX_DMA_CHANNELS
 #define MAX_DMA_CHANNELS	8
 #endif
Index: pplinux/linuxnew/include/asm-ppc/ibm4xx.h
diff -u pplinux/linuxnew/include/asm-ppc/ibm4xx.h:1.1.323.1 pplinux/linuxnew/include/asm-ppc/ibm4xx.h:1.2
--- pplinux/linuxnew/include/asm-ppc/ibm4xx.h:1.1.323.1	Thu Feb  3 10:00:14 2005
+++ pplinux/linuxnew/include/asm-ppc/ibm4xx.h	Thu Feb  3 11:35:38 2005
@@ -126,6 +126,10 @@
 #include <platforms/evb405ep.h>
 #endif
 
+#if defined(CONFIG_PEPPERCON)
+#include <platforms/peppercon.h>
+#endif
+
 #ifndef PPC4xx_MACHINE_NAME
 #define PPC4xx_MACHINE_NAME	"Unidentified 4xx class"
 #endif
Index: pplinux/linuxnew/include/asm-ppc/posix_types.h
diff -u pplinux/linuxnew/include/asm-ppc/posix_types.h:1.1.323.1 pplinux/linuxnew/include/asm-ppc/posix_types.h:1.2
--- pplinux/linuxnew/include/asm-ppc/posix_types.h:1.1.323.1	Thu Feb  3 10:00:13 2005
+++ pplinux/linuxnew/include/asm-ppc/posix_types.h	Thu Feb  3 11:35:38 2005
@@ -50,8 +50,7 @@
 
 #else /* __GNUC__ */
 
-#if defined(__KERNEL__) || !defined(__GLIBC__) || (__GLIBC__ < 2) \
-    || (__GLIBC__ == 2 && __GLIBC_MINOR__ == 0)
+#if defined(__KERNEL__) || !defined(__GLIBC__) || (__GLIBC__ < 2)
 /* With GNU C, use inline functions instead so args are evaluated only once: */
 
 #undef __FD_SET
Index: pplinux/linuxnew/include/asm-ppc/ppc405_pcimcs.h
diff -u /dev/null pplinux/linuxnew/include/asm-ppc/ppc405_pcimcs.h:1.1
--- /dev/null	Tue May 24 10:37:59 2005
+++ pplinux/linuxnew/include/asm-ppc/ppc405_pcimcs.h	Thu Feb  3 11:35:38 2005
@@ -0,0 +1,75 @@
+/*
+ * FILE NAME: ppc405_pcimcs.h
+ *
+ * BRIEF MODULE DESCRIPTION:
+ * machine check save pci access and configuration routines.
+ * These routines may also be used in case a certain PCI
+ * resource is physically not present. The according functions
+ * will return an error code.
+ *
+ * Author: Peppercon AG
+ *         Thomas Breitfeld <thomas@peppercon.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  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.
+ */
+
+#ifdef __KERNEL__
+#ifndef __ASMPPC_405_PCIMCS_H
+#define __ASMPPC_405_PCIMCS_H
+
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <asm/io.h>
+#include <asm/system.h>
+#include <asm/ibm4xx.h>
+
+/*
+ * machine check save I/O routines,
+ * an occured machine check will be signaled to the caller
+ * by setting the error flag to true
+ */
+u8 mcs_in_8(volatile u8 * addr, int * error);
+u16 mcs_in_le16(volatile u16 * addr, int * error);
+u32 mcs_in_le32(volatile u32 * addr, int * error);
+void mcs_out_8(u32 data, volatile u8 * addr, int * error);
+void mcs_out_le16(u32 data, volatile u16 * addr, int * error);
+void mcs_out_le32(u32 data, volatile u32 * addr, int * error);
+
+int mcs_pci_read_config_byte(struct pci_dev *dev, int offset, u8* value);
+int mcs_pci_read_config_word(struct pci_dev *dev, int offset, u16* value);
+int mcs_pci_read_config_dword(struct pci_dev *dev, int offset, u32* value);
+#define mcs_pci_read_config_long mcs_pci_read_config_dword
+int mcs_pci_write_config_byte(struct pci_dev *dev, int offset, u8 value);
+int mcs_pci_write_config_word(struct pci_dev *dev, int offset, u16 value);
+int mcs_pci_write_config_dword(struct pci_dev *dev, int offset, u32 value);
+#define mcs_pci_write_config_long mcs_pci_write_config_dword
+
+void fix_pci_read_config_byte(u32 cfg_addr, u32 cfg_date, int off, u8* v);
+void fix_pci_read_config_word(u32 cfg_addr, u32 cfg_date, int off, u16* v);
+void fix_pci_read_config_dword(u32 cfg_addr, u32 cfg_date, int off, u32* v);
+#define fix_pci_read_config_long fix_pci_read_config_dword
+void fix_pci_write_config_byte(u32 cfg_addr, u32 cfg_date, int off, u8 v);
+void fix_pci_write_config_word(u32 cfg_addr, u32 cfg_date, int off, u16 v);
+void fix_pci_write_config_dword(u32 cfg_addr, u32 cfg_date, int off, u32 v);
+#define fix_pci_write_config_long fix_pci_write_config_dword
+
+#endif /* __ASMPPC_405_PCIMCS_H */
+#endif /* __KERNEL__ */
Index: pplinux/linuxnew/include/asm-ppc/ppc4xx_dma.h
diff -u pplinux/linuxnew/include/asm-ppc/ppc4xx_dma.h:1.1.323.1 pplinux/linuxnew/include/asm-ppc/ppc4xx_dma.h:1.2
--- pplinux/linuxnew/include/asm-ppc/ppc4xx_dma.h:1.1.323.1	Thu Feb  3 10:00:13 2005
+++ pplinux/linuxnew/include/asm-ppc/ppc4xx_dma.h	Thu Feb  3 11:35:38 2005
@@ -583,6 +583,17 @@
 extern int ppc4xx_disable_dma_port(unsigned int dmanr, unsigned int ocp_dma,short dma_chan);
 extern int ppc4xx_set_dma_mode(unsigned int dmanr, unsigned int mode);
 
+extern void ppc4xx_set_sg_addr(int dmanr, phys_addr_t sg_addr);
+extern int  ppc4xx_add_dma_sgl(sgl_handle_t handle, phys_addr_t src_addr, phys_addr_t dst_addr,
+			       unsigned int count);
+extern void ppc4xx_enable_dma_sgl(sgl_handle_t handle);
+extern void ppc4xx_disable_dma_sgl(sgl_handle_t handle);
+extern int  ppc4xx_get_dma_sgl_residue(sgl_handle_t handle, phys_addr_t * src_addr,
+				       phys_addr_t * dst_addr);
+extern int  ppc4xx_delete_dma_sgl_element(sgl_handle_t handle, phys_addr_t * src_dma_addr,
+					  phys_addr_t * dst_dma_addr);
+extern int ppc4xx_clear_dma_sgl(sgl_handle_t handle);
+			    
 /* These are in kernel/dma.c: */
 
 /* reserve a DMA channel */
Index: pplinux/linuxnew/include/asm-ppc/ppc4xx_i2c.h
diff -u /dev/null pplinux/linuxnew/include/asm-ppc/ppc4xx_i2c.h:1.1
--- /dev/null	Tue May 24 10:37:59 2005
+++ pplinux/linuxnew/include/asm-ppc/ppc4xx_i2c.h	Thu Feb  3 11:35:38 2005
@@ -0,0 +1,123 @@
+/*
+** I2C interface
+** =============
+** (C) 2000 by Paolo Scaffardi (arsenio@tin.it)
+** AIRVENT SAM s.p.a - RIMINI(ITALY)
+**
+*/
+
+#ifndef	__PPC4XX_I2C_H__
+#define	__PPC4XX_I2C_H__
+
+#include <linux/config.h>
+
+#define CONFIG_I2C_X                    /* 16 bit access */
+#define CONFIG_RTC_X1240        1	/* we have a Xicor X1240 RTC */
+#define CFG_I2C_RTC_ADDR	0x6F    /*				  and one for RTC */
+#define CFG_I2C_EEPROM_ADDR     0x57	/* X1240 has two I2C slave addresses, one for EEPROM */
+
+#define X1240_SC			0x30
+#define X1240_MIN			0x31
+#define X1240_HR			0x32
+#define X1240_DT			0x33
+#define X1240_MO			0x34
+#define X1240_YR			0x35
+#define X1240_DW			0x36
+#define X1240_Y2K			0x37
+
+#define X1240_CONTROL			0x10
+#define X1240_STATUS			0x3F
+
+#define X1240_HR_MIL			0x80
+#define X1240_STATUS_BATTERY_FLAG  	0x20 /* not documented */
+#define X1240_STATUS_RWEL		0x04
+#define X1240_STATUS_WEL		0x02
+#define X1240_STATUS_RTCF		0x01
+
+
+#define IIC_OK		0
+#define IIC_NOK		1
+#define IIC_NOK_LA	2 /* Lost arbitration */
+#define IIC_NOK_ICT	3 /* Incomplete transfer */
+#define IIC_NOK_XFRA	4 /* Transfer aborted */
+#define IIC_NOK_DATA	5 /* No data in buffer */
+#define IIC_NOK_TOUT	6 /* Transfer timeout */
+
+#define IIC_TIMEOUT 1 /* 1 seconde */
+
+/* Registers */
+#define IICMDBUF	0x0
+#define IICSDBUF	0x2
+#define IICLMADR	0x4
+#define IICHMADR	0x5
+#define IICCNTL		0x6
+#define IICMDCNTL	0x7
+#define IICSTS		0x8
+#define IICEXTSTS	0x9
+#define IICLSADR	0xa
+#define IICHSADR	0xb
+#define IICCLKDIV	0xc
+#define IICINTRMSK	0xd
+#define IICXFRCNT	0xe
+#define IICXTCNTLSS	0xf
+#define IICDIRECTCNTL	0x10
+
+#define	   I2C_REGISTERS_BASE_ADDRESS 0xEF600500
+#define    IIC_MDBUF	((void *)(I2C_REGISTERS_BASE_ADDRESS+IICMDBUF))
+#define    IIC_SDBUF	((void *)(I2C_REGISTERS_BASE_ADDRESS+IICSDBUF))
+#define    IIC_LMADR	((void *)(I2C_REGISTERS_BASE_ADDRESS+IICLMADR))
+#define    IIC_HMADR	((void *)(I2C_REGISTERS_BASE_ADDRESS+IICHMADR))
+#define    IIC_CNTL	((void *)(I2C_REGISTERS_BASE_ADDRESS+IICCNTL))
+#define    IIC_MDCNTL	((void *)(I2C_REGISTERS_BASE_ADDRESS+IICMDCNTL))
+#define    IIC_STS	((void *)(I2C_REGISTERS_BASE_ADDRESS+IICSTS))
+#define    IIC_EXTSTS	((void *)(I2C_REGISTERS_BASE_ADDRESS+IICEXTSTS))
+#define    IIC_LSADR	((void *)(I2C_REGISTERS_BASE_ADDRESS+IICLSADR))
+#define    IIC_HSADR	((void *)(I2C_REGISTERS_BASE_ADDRESS+IICHSADR))
+#define    IIC_CLKDIV	((void *)(I2C_REGISTERS_BASE_ADDRESS+IICCLKDIV))
+#define    IIC_INTRMSK	((void *)(I2C_REGISTERS_BASE_ADDRESS+IICINTRMSK))
+#define    IIC_XFRCNT	((void *)(I2C_REGISTERS_BASE_ADDRESS+IICXFRCNT))
+#define    IIC_XTCNTLSS	((void *)(I2C_REGISTERS_BASE_ADDRESS+IICXTCNTLSS))
+#define    IIC_DIRECTCNTL ((void *)(I2C_REGISTERS_BASE_ADDRESS+IICDIRECTCNTL))
+
+/* MDCNTL Register Bit definition */
+#define    IIC_MDCNTL_HSCL 0x01
+#define    IIC_MDCNTL_EUBS 0x02
+#define    IIC_MDCNTL_FMDB 0x40
+#define    IIC_MDCNTL_FSDB 0x80
+
+/* CNTL Register Bit definition */
+#define    IIC_CNTL_PT     0x01
+#define    IIC_CNTL_READ   0x02
+#define    IIC_CNTL_CHT    0x04
+
+/* STS Register Bit definition */
+#define    IIC_STS_PT	   0x01
+#define    IIC_STS_ERR	   0x04
+#define    IIC_STS_MDBS    0x20
+
+/* EXTSTS Register Bit definition */
+#define    IIC_EXTSTS_XFRA 0x01
+#define    IIC_EXTSTS_ICT  0x02
+#define    IIC_EXTSTS_LA   0x04
+
+
+#if 0
+int  i2c_receive(unsigned char address,
+		 unsigned short size_to_expect, unsigned char datain[] );
+int  i2c_send(unsigned char address,
+		 unsigned short size_to_send, unsigned char dataout[] );
+void  i2c_read  (unsigned char *addr, int alen, unsigned char *buffer, int len);
+void  i2c_write (unsigned char *addr, int alen, unsigned char *buffer, int len);
+#endif
+void i2c_init(void);
+int rtc_read  (unsigned offset, unsigned char *buffer, unsigned cnt);
+int rtc_write (unsigned offset, unsigned char *buffer, unsigned cnt);
+
+
+#define ERROR_I2C_NONE		0
+#define ERROR_I2C_LENGTH	1
+
+#define I2C_WRITE_BIT		0x00
+#define I2C_READ_BIT		0x01
+
+#endif	/* __PPC4XX_I2C_H__ */
Index: pplinux/linuxnew/include/linux/bigphysarea.h
diff -u /dev/null pplinux/linuxnew/include/linux/bigphysarea.h:1.1
--- /dev/null	Tue May 24 10:37:59 2005
+++ pplinux/linuxnew/include/linux/bigphysarea.h	Thu Feb  3 11:35:38 2005
@@ -0,0 +1,29 @@
+/* linux/mm/bigphysarea.h, M. Welsh (mdw@cs.cornell.edu)
+ * Copyright (c) 1996 by Matt Welsh.
+ * Extended by Roger Butenuth (butenuth@uni-paderborn.de), October 1997
+ * Extended for linux-2.1.121 till 2.4.0 (June 2000)
+ *     by Pauline Middelink <middelink@polyware.nl>
+ *
+ * This is a set of routines which allow you to reserve a large (?)
+ * amount of physical memory at boot-time, which can be allocated/deallocated
+ * by drivers. This memory is intended to be used for devices such as
+ * video framegrabbers which need a lot of physical RAM (above the amount
+ * allocated by kmalloc). This is by no means efficient or recommended;
+ * to be used only in extreme circumstances.
+ *
+ */
+
+#ifndef __LINUX_BIGPHYSAREA_H
+#define __LINUX_BIGPHYSAREA_H
+
+#include <linux/types.h>
+
+/* original interface */
+extern caddr_t	bigphysarea_alloc(int size);
+extern void	bigphysarea_free(caddr_t addr, int size);
+
+/* new interface */
+extern caddr_t	bigphysarea_alloc_pages(int count, int align, int priority);
+extern void	bigphysarea_free_pages(caddr_t base);
+
+#endif // __LINUX_BIGPHYSAREA_H
Index: pplinux/linuxnew/include/linux/i2c-algo-asics.h
diff -u /dev/null pplinux/linuxnew/include/linux/i2c-algo-asics.h:1.2
--- /dev/null	Tue May 24 10:37:59 2005
+++ pplinux/linuxnew/include/linux/i2c-algo-asics.h	Mon May  9 17:11:04 2005
@@ -0,0 +1,97 @@
+/*   Copyright (C) 2004 Microtronix Datacom 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
+    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_I2C_ALGO_ASICS_H
+#define _LINUX_I2C_ALGO_ASICS_H
+
+#include <linux/spinlock.h>
+#include <linux/i2c-slave.h>
+
+struct iic_asics_hw {
+    int base;
+    int base_offset;
+    int irq;
+    int irq_mux;        
+    /* clock and speed */
+    int clock;	/* in KHZ */
+    int scl;	/* in KHZ */
+
+    volatile u32 * asics_regs;  /* mapped ASICS registers */
+    volatile u32 * intmux_reg;	/* IRQ multiplex register */
+    wait_queue_head_t wait;
+    int pending;
+    int arbitration_lost;
+};
+
+#define SLAVE_BUF_SIZE 512
+
+typedef enum {
+	I2C_ASICS_SLAVE_OP_NONE,
+	I2C_ASICS_SLAVE_OP_READ,
+	I2C_ASICS_SLAVE_OP_WRITE
+} slave_op_t;
+
+struct i2c_algo_asics_slave_data {
+	/* slave lock object */
+	spinlock_t      slave_lock;
+	
+	/* slave write buffer */
+	unsigned char * slave_write_ptr;
+	unsigned int    slave_write_count;
+	unsigned char   slave_write_buffer[SLAVE_BUF_SIZE];
+	
+	/* slave read buffer */
+	unsigned char * slave_read_ptr;
+	unsigned int    slave_read_count;
+	unsigned char   slave_read_buffer[SLAVE_BUF_SIZE];
+	
+	/* status flags */
+	int block_next_slave_operation;
+	slave_op_t last_slave_op;
+};
+
+typedef enum {
+	I2C_ASICS_MODE_IDLE,
+	I2C_ASICS_MODE_MASTER,
+	I2C_ASICS_MODE_SLAVE
+} asics_state_t;
+
+struct i2c_algo_asics_data {
+	struct iic_asics_hw *hw;
+	struct i2c_algo_asics_slave_data *slave_data;
+	struct i2c_slave_adapter *slave_adapter;
+	
+	void (*setreg) (struct iic_asics_hw *hw, int regno, int val);
+	int  (*getreg) (struct iic_asics_hw *hw, int regno);
+	int  (*wait_for_tdone) (struct iic_asics_hw *hw);
+	
+	/* local settings */
+	int udelay;
+	int mdelay;
+	int timeout;
+	
+	asics_state_t current_state;
+};
+
+#define I2C_ASICS_ADAP_MAX	16
+
+int i2c_asics_add_bus(struct i2c_adapter *);
+int i2c_asics_del_bus(struct i2c_adapter *);
+int i2c_asics_slave_restart_xfer(struct i2c_adapter *);
+int i2c_asics_slave_set_address(struct i2c_adapter *i2c_adap, unsigned int address);
+int i2c_asics_handle_slave_request(struct i2c_adapter *);
+
+#endif /* _LINUX_I2C_ALGO_ASICS_H */
Index: pplinux/linuxnew/include/linux/i2c-id.h
diff -u pplinux/linuxnew/include/linux/i2c-id.h:1.1.323.1 pplinux/linuxnew/include/linux/i2c-id.h:1.2
--- pplinux/linuxnew/include/linux/i2c-id.h:1.1.323.1	Thu Feb  3 10:00:16 2005
+++ pplinux/linuxnew/include/linux/i2c-id.h	Wed Feb 23 18:03:37 2005
@@ -157,6 +157,8 @@
 #define I2C_ALGO_SGI	0x130000	/* SGI algorithm		*/
 #define I2C_ALGO_OCP    0x140000        /* IBM or otherwise On-chip I2C algorithm */
 
+/* Opencores was here */
+#define I2C_ALGO_ASICS  0x160000
 #define I2C_ALGO_EXP	0x800000	/* experimental			*/
 
 #define I2C_ALGO_MASK	0xff0000	/* Mask for algorithms		*/
@@ -192,6 +194,12 @@
 #define I2C_HW_P_ISA	0x01	/* generic ISA Bus inteface card	*/
 #define I2C_HW_P_ELEK	0x02	/* Elektor ISA Bus inteface card	*/
 
+/* --- Opencores I2C based adaptors */
+#define I2C_HW_OC_UKIT 0x00     /* what is on Microtronix uKit */
+
+/* --- Asics I2C Master/Slave based adaptors */
+#define I2C_HW_ASICS_UKIT 0x00   /* what is on Microtronix uKit */
+
 /* --- ACPI Embedded controller algorithms                              */
 #define I2C_HW_ACPI_EC          0x00
 
Index: pplinux/linuxnew/include/linux/i2c-slave.h
diff -u /dev/null pplinux/linuxnew/include/linux/i2c-slave.h:1.1
--- /dev/null	Tue May 24 10:37:59 2005
+++ pplinux/linuxnew/include/linux/i2c-slave.h	Thu Feb  3 11:35:38 2005
@@ -0,0 +1,134 @@
+/* ------------------------------------------------------------------------- */
+/* 									     */
+/* i2c-slave.h - definitions for the i2c bus interface slave mode	     */
+/* 									     */
+/* ------------------------------------------------------------------------- */
+/* Author: Thomas Rendelmann (thre@peppercon.de)                             */
+
+/* 
+   Slave functionality is not well supported by the kernel at the moment.
+   Because I2C slave mode works differently than the master mode (the slave
+   mode is always triggered from outside, namely from the master), it doesn't
+   really fit into the kernel's I2C layer. The layer is used for master
+   tranfsers which are triggered from inside the system, mostly from an
+   application.
+   
+   In slave mode, a master simply sends data to the slave (or wants to read
+   data from it, in this case an address should be sent before anyhow to let
+   the slave know which master the data should be sent to). This normally
+   causes an interrupt in the I2C device driver. Because the driver cannot
+   know what this data is for (because no interaction from the userspace
+   preceded the slave operation), the data could not be handled properly with
+   the I2C framework.
+   
+   This is an approach to solve this problem. Within the I2C slave subsystem,
+   each device driver should register in the slave handler. This allows the
+   subsystem to start also master transfers (which are sometimes needed, a
+   lot of systems require both master and slave operations) and to
+   distinguish between several I2C adapters in the system. On the other side
+   of the system, several logical I2C devices can be found. These devices
+   also register in the slave subsystem. The i2c-slave module then can ask
+   every logical device whether it is responsible for the received I2C slave
+   data (or for the data to be sent). So the data can always be delivered
+   from or to the correct logical device. If there is no device responsible
+   for the data transfer, the incoming data is thrown away and for outgoing
+   data an error on the I2C bus should be signalled (or dummy data
+   transferred).
+*/
+
+#ifndef __I2C_SLAVE_H
+#define __I2C_SLAVE_H
+
+/* Includes ----------------------------------------------------------- */
+
+#include <linux/i2c.h>
+
+/* Constants ---------------------------------------------------------- */
+
+/* device operation modes */
+/* Take care when using the I2C_MODE_MASTER_ADDRESS mode, it results in 2
+   I2C messages. The first one transmits the sender's own I2C address
+   (only 7 bit addresses supported) in one byte, the second one transmits
+   the I2C data. This flag might only be used with devices that support
+   this!
+*/
+#define I2C_MODE_MASTER			0x04	/* device works in master mode */
+#define I2C_MODE_MASTER_ADDRESS		0x02	/* device sends its own address on op. */
+#define I2C_MODE_SLAVE			0x01	/* device works in slave mode */
+
+/* ioctl calls */
+#define I2C_DEVICE_SET_TRANSMITTER_MODE	0x0735	/* set the operation mode of the device */
+#define I2C_DEVICE_SET_RECEIVER_MODE	0x0736	/* set the operation mode of the device */
+/* to change the receiver's slave address, use I2C_SLAVE or I2C_SLAVE_FORCE */
+/* to flush the device's buffer, use I2C_SLAVE_FLUSH_BUFFER */
+
+/* For emulated SMBus operations, the I2C_DEVICE_SMBUS_TRANSFER ioctl
+   is supported. Its use results in 2 I2C messages. SMBus messages consist
+   of 2 things: a command and data. The command is always a byte, the data
+   can be a byte or a word. This is represented by the following structure.
+*/
+struct i2c_device_smbus_operation {
+	char read_write;	/* I2C_SMBUS_READ, I2C_SMBUS_WRITE */
+	int transaction;	/* I2C_SMBUS_BYTE_DATA, I2C_SMBUS_WORD_DATA, ... */
+	__u8 command;
+	union i2c_smbus_data data;
+	int length;		/* only for I2C_SMBUS_BLOCK_DATA */
+};
+#define I2C_DEVICE_SMBUS_COMMAND	0x0737	/* ioctl for smbus commands */
+
+/* Data structures ---------------------------------------------------- */
+
+#ifdef __KERNEL__
+
+/* an i2c adapter */
+struct i2c_slave_adapter {
+	/* the physical adapter */
+	struct i2c_adapter* adapter;
+	
+	/* when the adapter could not deliver its data to the device,
+	   the i2c bus is halted; this function reactivates the i2c bus */
+	int (*reactivate)(struct i2c_adapter* adapter);
+};
+
+/* a logical i2c (slave) device */
+struct i2c_slave_device {
+	/* logical name of the device */
+	char name[32];
+
+	/* the I2C adapter to be used */
+	struct i2c_adapter* adapter;
+	
+	/* is the device responsible for the current transfer */
+	/* returns nonzero if responsible and 0 otherwise */
+	int (*is_responsible)(char*, int);
+	
+	/* read and write functions */
+	/* return the actual number of written/read bytes from/to the
+	   logical I2C device or < 0 on error */
+	int (*slave_write)(char*, int);
+	int (*slave_read)(char*, int);
+};
+
+/* Functions ---------------------------------------------------------- */
+
+/* add/remove a physical I2C adapter to the subsystem */
+int i2c_slave_add_adapter(struct i2c_slave_adapter* adapter);
+int i2c_slave_remove_adapter(struct i2c_slave_adapter* adapter);
+
+/* add/remove a logical I2C device to the subsystem */
+int i2c_slave_add_device(struct i2c_slave_device* dev);
+int i2c_slave_remove_device(struct i2c_slave_device* dev);
+
+/* move the data from the locigal device into the physical driver */
+/* both functions return the number of actual written/read bytes */
+int iic_slave_write(struct i2c_adapter* adapter, char* buf, int len);
+int iic_slave_read(struct i2c_adapter* adapter, char* buf, int len, int command);
+	/* command is the i2c slave command;
+	   if command < 0, no command was transferred */
+
+/* unblock a blocked adapter */
+void unblock_adapter(struct i2c_adapter* adapter);
+
+#endif /* __KERNEL__ */
+
+#endif /* __I2C_SLAVE_H */
Index: pplinux/linuxnew/include/linux/i2c.h
diff -u pplinux/linuxnew/include/linux/i2c.h:1.1.323.1 pplinux/linuxnew/include/linux/i2c.h:1.4
--- pplinux/linuxnew/include/linux/i2c.h:1.1.323.1	Thu Feb  3 10:00:16 2005
+++ pplinux/linuxnew/include/linux/i2c.h	Tue Feb 15 12:24:33 2005
@@ -264,6 +264,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_RECV_SLAVE		0x04	/* Read operations perform slave
+						   reads */
+
 
 /* i2c_client_address_data is the struct for holding default client
  * addresses for a driver and for the parameters supplied on the
@@ -300,6 +303,7 @@
 extern int i2c_del_driver(struct i2c_driver *);
 
 extern int i2c_attach_client(struct i2c_client *);
+extern int i2c_attach_client_force(struct i2c_client *);
 extern int i2c_detach_client(struct i2c_client *);
 
 /* Only call these if you grab a resource that makes unloading the
@@ -341,6 +345,10 @@
 		struct i2c_client_address_data *address_data,
 		i2c_client_found_addr_proc *found_proc);
 
+extern int i2c_probe_force(struct i2c_adapter *adapter, 
+			struct i2c_client_address_data *address_data,
+			i2c_client_found_addr_proc *found_proc);
+
 /* An ioctl like call to set div. parameters of the adapter.
  */
 extern int i2c_control(struct i2c_client *,unsigned int, unsigned long);
@@ -466,6 +474,11 @@
 
 #define I2C_SMBUS	0x0720	/* SMBus-level access */
 
+#define I2C_SLAVE_MODE_ENABLE  0x0730	/* start slave receiving */
+#define I2C_SLAVE_MODE_DISABLE 0x0731	/* stop  slave receiving */
+#define I2C_SLAVE_FLUSH_BUFFER 0x0732	/* flush slave read buf  */
+#define I2C_SLAVE_SET_ADDRESS  0x0733	/* set slave i2c address */
+
 /* ... algo-bit.c recognizes */
 #define I2C_UDELAY	0x0705	/* set delay in microsecs between each	*/
 				/* written byte (except address)	*/
Index: pplinux/linuxnew/include/linux/inetdevice.h
diff -u pplinux/linuxnew/include/linux/inetdevice.h:1.1.323.1 pplinux/linuxnew/include/linux/inetdevice.h:1.2
--- pplinux/linuxnew/include/linux/inetdevice.h:1.1.323.1	Thu Feb  3 10:00:16 2005
+++ pplinux/linuxnew/include/linux/inetdevice.h	Wed Apr  6 11:53:12 2005
@@ -22,6 +22,12 @@
 	int	arp_ignore;
 	int	medium_id;
 	int	force_igmp_version;
+
+	/* rwa: for clustering */
+	int	pp_arp_zero_src_ip;
+	int	pp_arp_proxy_enable;
+	int	pp_arp_proxy_src_ip;
+	
 	void	*sysctl;
 };
 
@@ -74,6 +80,11 @@
 #define IN_DEV_ARP_ANNOUNCE(in_dev)	(max(ipv4_devconf.arp_announce, (in_dev)->cnf.arp_announce))
 #define IN_DEV_ARP_IGNORE(in_dev)	(max(ipv4_devconf.arp_ignore, (in_dev)->cnf.arp_ignore))
 
+/* rwa: for clustering */
+#define IN_DEV_PP_ARP_ZERO_SRC_IP(in_dev)	(ipv4_devconf.pp_arp_zero_src_ip || (in_dev)->cnf.pp_arp_zero_src_ip)
+#define IN_DEV_PP_ARP_PROXY_ENABLE(in_dev)	(ipv4_devconf.pp_arp_proxy_enable || (in_dev)->cnf.pp_arp_proxy_enable)
+#define IN_DEV_PP_ARP_PROXY_SRC_IP(in_dev)	((in_dev)->cnf.pp_arp_proxy_src_ip ? (in_dev)->cnf.pp_arp_proxy_src_ip : ipv4_devconf.pp_arp_proxy_src_ip)
+
 struct in_ifaddr
 {
 	struct in_ifaddr	*ifa_next;
Index: pplinux/linuxnew/include/linux/isdn.h
diff -u pplinux/linuxnew/include/linux/isdn.h:1.1.323.1 pplinux/linuxnew/include/linux/isdn.h:1.2
--- pplinux/linuxnew/include/linux/isdn.h:1.1.323.1	Thu Feb  3 10:00:16 2005
+++ pplinux/linuxnew/include/linux/isdn.h	Thu Feb  3 11:35:38 2005
@@ -56,6 +56,9 @@
 
 #define IIOCNETGPN  _IO('I',34)
 
+#define IIOCLASTCALLER _IO('I',125)
+#define IIOCLASTCALLED _IO('I',126)
+
 #define IIOCDBGVAR  _IO('I',127)
 
 #define IIOCDRVCTL  _IO('I',128)
@@ -631,6 +634,8 @@
 	isdn_v110_stream  *v110[ISDN_MAX_CHANNELS];  /* V.110 private data         */
 	struct semaphore  sem;                       /* serialize list access*/
 	unsigned long     global_features;
+	char last_caller[ISDN_MAX_CHANNELS][ISDN_MSNLEN];
+	char last_called[ISDN_MAX_CHANNELS][ISDN_MSNLEN];
 #ifdef CONFIG_DEVFS_FS
 	devfs_handle_t devfs_handle_isdninfo;
 	devfs_handle_t devfs_handle_isdnctrl;
Index: pplinux/linuxnew/include/linux/sched.h
diff -u pplinux/linuxnew/include/linux/sched.h:1.1.323.1 pplinux/linuxnew/include/linux/sched.h:1.2
--- pplinux/linuxnew/include/linux/sched.h:1.1.323.1	Thu Feb  3 10:00:15 2005
+++ pplinux/linuxnew/include/linux/sched.h	Wed Feb 23 18:03:37 2005
@@ -858,6 +858,40 @@
 	__ret;								\
 })
 
+/* backported from 2.6 ------------------------------------------------- */
+
+#define __wait_event_interruptible_timeout(wq, condition, ret)		\
+do {									\
+	wait_queue_t __wait;						\
+	init_waitqueue_entry(&__wait, current);				\
+									\
+	add_wait_queue(&wq, &__wait);					\
+	for (;;) {							\
+		set_current_state(TASK_INTERRUPTIBLE);			\
+		if (condition)						\
+			break;						\
+		if (!signal_pending(current)) {				\
+			ret = schedule_timeout(ret);			\
+			if (!ret)					\
+				break;					\
+			continue;					\
+		}							\
+		ret = -ERESTARTSYS;					\
+		break;							\
+	}								\
+	current->state = TASK_RUNNING;					\
+	remove_wait_queue(&wq, &__wait);				\
+} while (0)
+
+#define wait_event_interruptible_timeout(wq, condition, timeout)	\
+({									\
+	long __ret = timeout;						\
+	if (!(condition))						\
+		__wait_event_interruptible_timeout(wq, condition, __ret); \
+	__ret;								\
+})
+/* --------------------------------------------------------------------- */
+
 #define REMOVE_LINKS(p) do { \
 	(p)->next_task->prev_task = (p)->prev_task; \
 	(p)->prev_task->next_task = (p)->next_task; \
Index: pplinux/linuxnew/include/linux/sysctl.h
diff -u pplinux/linuxnew/include/linux/sysctl.h:1.1.323.1 pplinux/linuxnew/include/linux/sysctl.h:1.3
--- pplinux/linuxnew/include/linux/sysctl.h:1.1.323.1	Thu Feb  3 10:00:16 2005
+++ pplinux/linuxnew/include/linux/sysctl.h	Wed Apr  6 11:53:12 2005
@@ -84,6 +84,10 @@
 	KERN_NODENAME=7,
 	KERN_DOMAINNAME=8,
 
+	KERN_BOARDTYPE=9,
+	KERN_PRODUCTTYPE=10,
+	KERN_PRODUCTION=11,
+
 	KERN_CAP_BSET=14,	/* int: capability bounding set */
 	KERN_PANIC=15,		/* int: panic timeout */
 	KERN_REALROOTDEV=16,	/* real root device to mount after initrd */
@@ -364,6 +368,10 @@
 	NET_IPV4_CONF_FORCE_IGMP_VERSION=17,
 	NET_IPV4_CONF_ARP_ANNOUNCE=18,
 	NET_IPV4_CONF_ARP_IGNORE=19,
+	/* rwa: for clustering ... */
+	NET_IPV4_CONF_PP_ARP_ZERO_SRC_IP=100,
+	NET_IPV4_CONF_PP_ARP_PROXY_ENABLE=101,
+	NET_IPV4_CONF_PP_ARP_PROXY_SRC_IP=102,
 };
 
 /* /proc/sys/net/ipv4/netfilter */
Index: pplinux/linuxnew/include/linux/mtd/map.h
diff -u pplinux/linuxnew/include/linux/mtd/map.h:1.1.323.1 pplinux/linuxnew/include/linux/mtd/map.h:1.2
--- pplinux/linuxnew/include/linux/mtd/map.h:1.1.323.1	Thu Feb  3 10:00:17 2005
+++ pplinux/linuxnew/include/linux/mtd/map.h	Wed Apr  6 11:53:12 2005
@@ -29,6 +29,9 @@
 struct map_info {
 	char *name;
 	unsigned long size;
+#if defined(PRODUCT_FLASHX4)    
+	int chip_size;
+#endif    
 	int buswidth; /* in octets */
 	__u8 (*read8)(struct map_info *, unsigned long);
 	__u16 (*read16)(struct map_info *, unsigned long);
Index: pplinux/linuxnew/include/linux/mtd/mtd.h
diff -u pplinux/linuxnew/include/linux/mtd/mtd.h:1.1.323.1 pplinux/linuxnew/include/linux/mtd/mtd.h:1.3
--- pplinux/linuxnew/include/linux/mtd/mtd.h:1.1.323.1	Thu Feb  3 10:00:17 2005
+++ pplinux/linuxnew/include/linux/mtd/mtd.h	Wed Apr  6 11:53:12 2005
@@ -95,6 +95,7 @@
 #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 MEMREADSIZE		_IOR('M', 11, int)
 
 #ifndef __KERNEL__
 
@@ -188,12 +189,17 @@
 	 * factory data is read only. 
 	 */
 	int (*read_user_prot_reg) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf);
-
 	int (*read_fact_prot_reg) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf);
-
-	/* This function is not yet implemented */
+    
 	int (*write_user_prot_reg) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf);
 
+        int (*lock_user_prot_reg) (struct mtd_info *mtd);
+        int (*is_user_prot_reg_locked) (struct mtd_info *mtd);
+    
+#if defined(PRODUCT_FLASHX4)   
+	int chip_size;
+#endif    
+	
 	/* iovec-based read/write methods. We need these especially for NAND flash,
 	   with its limited number of write cycles per erase.
 	   NB: The 'count' parameter is the number of _vectors_, each of 
@@ -217,7 +223,7 @@
 	int (*suspend) (struct mtd_info *mtd);
 	void (*resume) (struct mtd_info *mtd);
 
-	void *priv;
+	void *priv;	
 };
 
 
Index: pplinux/linuxnew/include/linux/netfilter_ipv4/ipt_FASTNAT.h
diff -u /dev/null pplinux/linuxnew/include/linux/netfilter_ipv4/ipt_FASTNAT.h:1.2
--- /dev/null	Tue May 24 10:37:59 2005
+++ pplinux/linuxnew/include/linux/netfilter_ipv4/ipt_FASTNAT.h	Wed Apr  6 11:53:12 2005
@@ -0,0 +1,17 @@
+#ifndef _IPT_FASTNAT_H
+#define _IPT_FASTNAT_H
+
+#define	IPT_FASTNAT_SRC_ADDR (1 << 0)
+#define	IPT_FASTNAT_SRC_PORT (1 << 1)
+#define IPT_FASTNAT_DST_ADDR (1 << 2)
+#define IPT_FASTNAT_DST_PORT (1 << 3)
+
+struct ipt_fastnat_info {
+	int type;
+	struct in_addr saddr;
+	struct in_addr daddr;
+	u_short sport;
+	u_short dport;
+};
+
+#endif /*_IPT_FASTNAT_H*/
Index: pplinux/linuxnew/include/linux/netfilter_ipv4/ipt_MARK.h
diff -u pplinux/linuxnew/include/linux/netfilter_ipv4/ipt_MARK.h:1.1.323.1 pplinux/linuxnew/include/linux/netfilter_ipv4/ipt_MARK.h:1.2
--- pplinux/linuxnew/include/linux/netfilter_ipv4/ipt_MARK.h:1.1.323.1	Thu Feb  3 10:00:18 2005
+++ pplinux/linuxnew/include/linux/netfilter_ipv4/ipt_MARK.h	Wed Apr  6 11:53:12 2005
@@ -2,7 +2,8 @@
 #define _IPT_MARK_H_target
 
 struct ipt_mark_target_info {
-	unsigned long mark;
+	/* rwa: added mask */
+	unsigned long mark, mask;
 };
 
 #endif /*_IPT_MARK_H_target*/
Index: pplinux/linuxnew/include/net/ip_vs.h
diff -u pplinux/linuxnew/include/net/ip_vs.h:1.1.323.1 pplinux/linuxnew/include/net/ip_vs.h:1.2
--- pplinux/linuxnew/include/net/ip_vs.h:1.1.323.1	Thu Feb  3 10:00:18 2005
+++ pplinux/linuxnew/include/net/ip_vs.h	Wed Apr  6 11:53:12 2005
@@ -97,6 +97,8 @@
 	int             state;          /* sync daemon state */
 	char            mcast_ifn[IP_VS_IFNAME_MAXLEN];
 					/* multicast interface name */
+	u_int32_t	buildnr;	/* build number */
+	u_int64_t	syncid;		/* sync daemon id */
 
 	/* virtual service options */
 	u_int16_t	protocol;
@@ -213,8 +215,9 @@
 
 /* The argument to IP_VS_SO_GET_DAEMON */
 struct ip_vs_daemon_user {
-	int	state;				/* sync daemon state */
-	char	mcast_ifn[IP_VS_IFNAME_MAXLEN];	/* multicast interface name */
+	int	state;					/* sync daemon state */
+	char	mcast_master_ifn[IP_VS_IFNAME_MAXLEN];	/* mcast master interface name */
+	char	mcast_backup_ifn[IP_VS_IFNAME_MAXLEN];	/* mcast backup interface name */
 };
 
 
@@ -724,9 +727,10 @@
  *      (from ip_vs_sync.c)
  */
 extern volatile int ip_vs_sync_state;
-extern char ip_vs_mcast_ifn[IP_VS_IFNAME_MAXLEN];
-extern int start_sync_thread(int state, char *mcast_ifn);
-extern int stop_sync_thread(void);
+extern char ip_vs_mcast_master_ifn[IP_VS_IFNAME_MAXLEN];
+extern char ip_vs_mcast_backup_ifn[IP_VS_IFNAME_MAXLEN];
+extern int start_sync_thread(int state, char *mcast_ifn, __u32 buildnr, __u64 syncid);
+extern int stop_sync_thread(int state);
 extern void ip_vs_sync_conn(struct ip_vs_conn *cp);
 
 
Index: pplinux/linuxnew/init/version.c
diff -u pplinux/linuxnew/init/version.c:1.1.323.1 pplinux/linuxnew/init/version.c:1.2
--- pplinux/linuxnew/init/version.c:1.1.323.1	Thu Feb  3 10:00:11 2005
+++ pplinux/linuxnew/init/version.c	Thu Feb  3 11:35:39 2005
@@ -15,6 +15,9 @@
 #define version_string(a) version(a)
 
 int version_string(LINUX_VERSION_CODE);
+char sysctl_boardtype[65] = UTS_BOARDTYPE;
+char sysctl_producttype[65] = UTS_PRODUCTTYPE;
+char sysctl_production[2] = UTS_PRODUCTION;
 
 struct new_utsname system_utsname = {
 	UTS_SYSNAME, UTS_NODENAME, UTS_RELEASE, UTS_VERSION,
Index: pplinux/linuxnew/kernel/ksyms.c
diff -u pplinux/linuxnew/kernel/ksyms.c:1.1.323.1 pplinux/linuxnew/kernel/ksyms.c:1.2
--- pplinux/linuxnew/kernel/ksyms.c:1.1.323.1	Thu Feb  3 10:00:29 2005
+++ pplinux/linuxnew/kernel/ksyms.c	Thu Feb  3 11:35:39 2005
@@ -58,6 +58,9 @@
 #ifdef CONFIG_KMOD
 #include <linux/kmod.h>
 #endif
+#ifdef CONFIG_BIGPHYS_AREA
+#include <linux/bigphysarea.h>
+#endif
 
 extern void set_device_ro(kdev_t dev,int flag);
 
@@ -117,6 +120,7 @@
 EXPORT_SYMBOL(vmalloc_to_page);
 EXPORT_SYMBOL(mem_map);
 EXPORT_SYMBOL(remap_page_range);
+EXPORT_SYMBOL(zap_page_range);
 EXPORT_SYMBOL(max_mapnr);
 EXPORT_SYMBOL(high_memory);
 EXPORT_SYMBOL(vmtruncate);
@@ -131,6 +135,12 @@
 EXPORT_SYMBOL(kmap_prot);
 EXPORT_SYMBOL(kmap_pte);
 #endif
+#ifdef CONFIG_BIGPHYS_AREA
+EXPORT_SYMBOL(bigphysarea_alloc);
+EXPORT_SYMBOL(bigphysarea_free);
+EXPORT_SYMBOL(bigphysarea_alloc_pages);
+EXPORT_SYMBOL(bigphysarea_free_pages);
+#endif
 
 /* filesystem internal functions */
 EXPORT_SYMBOL(def_blk_fops);
Index: pplinux/linuxnew/kernel/printk.c
diff -u pplinux/linuxnew/kernel/printk.c:1.1.323.1 pplinux/linuxnew/kernel/printk.c:1.2
--- pplinux/linuxnew/kernel/printk.c:1.1.323.1	Thu Feb  3 10:00:29 2005
+++ pplinux/linuxnew/kernel/printk.c	Thu Feb  3 11:35:39 2005
@@ -29,6 +29,10 @@
 
 #include <asm/uaccess.h>
 
+#ifdef CONFIG_PEPPERCON
+# include "asm/ibm4xx.h"
+#endif
+
 #ifdef CONFIG_BOOTX_TEXT
 #include <asm/btext.h>
 extern int force_printk_to_btext;
@@ -138,6 +142,14 @@
 	idx = simple_strtoul(s, NULL, 10);
 	*s = 0;
 
+#ifdef CONFIG_PEPPERCON
+	{
+		bd_t * bd = (bd_t *)__res;
+
+		if (!bd->bi_debug_mode) strcpy(name, "tty2");
+	}
+#endif
+
 	/*
 	 *	See if this tty is not yet registered, and
 	 *	if we have a slot free.
Index: pplinux/linuxnew/kernel/sysctl.c
diff -u pplinux/linuxnew/kernel/sysctl.c:1.1.323.1 pplinux/linuxnew/kernel/sysctl.c:1.2
--- pplinux/linuxnew/kernel/sysctl.c:1.1.323.1	Thu Feb  3 10:00:29 2005
+++ pplinux/linuxnew/kernel/sysctl.c	Thu Feb  3 11:35:39 2005
@@ -55,6 +55,9 @@
 extern int cad_pid;
 extern int laptop_mode;
 extern int block_dump;
+extern char sysctl_boardtype[65];
+extern char sysctl_producttype[65];
+extern char sysctl_production[2];
 
 /* this is needed for the proc_dointvec_minmax for [fs_]overflow UID and GID */
 static int maxolduid = 65535;
@@ -176,6 +179,12 @@
 	 0644, NULL, &proc_doutsstring, &sysctl_string},
 	{KERN_DOMAINNAME, "domainname", system_utsname.domainname, 64,
 	 0644, NULL, &proc_doutsstring, &sysctl_string},
+	{KERN_BOARDTYPE, "boardtype", &sysctl_boardtype, 64,
+	 0644, NULL, &proc_doutsstring, &sysctl_string},
+	{KERN_PRODUCTTYPE, "producttype", &sysctl_producttype, 64,
+	 0644, NULL, &proc_doutsstring, &sysctl_string},
+	{KERN_PRODUCTION, "production", &sysctl_production, 2,
+	 0644, NULL, &proc_doutsstring, &sysctl_string},
 	{KERN_PANIC, "panic", &panic_timeout, sizeof(int),
 	 0644, NULL, &proc_dointvec},
 	{KERN_CORE_USES_PID, "core_uses_pid", &core_uses_pid, sizeof(int),
Index: pplinux/linuxnew/mm/Makefile
diff -u pplinux/linuxnew/mm/Makefile:1.1.323.1 pplinux/linuxnew/mm/Makefile:1.2
--- pplinux/linuxnew/mm/Makefile:1.1.323.1	Thu Feb  3 10:00:29 2005
+++ pplinux/linuxnew/mm/Makefile	Thu Feb  3 11:35:39 2005
@@ -18,4 +18,6 @@
 
 obj-$(CONFIG_HIGHMEM) += highmem.o
 
+obj-$(CONFIG_BIGPHYS_AREA) += bigphysarea.o
+
 include $(TOPDIR)/Rules.make
Index: pplinux/linuxnew/mm/bigphysarea.c
diff -u /dev/null pplinux/linuxnew/mm/bigphysarea.c:1.1
--- /dev/null	Tue May 24 10:37:59 2005
+++ pplinux/linuxnew/mm/bigphysarea.c	Thu Feb  3 11:35:39 2005
@@ -0,0 +1,347 @@
+/* linux/mm/bigphysarea.c, M. Welsh (mdw@cs.cornell.edu)
+ * Copyright (c) 1996 by Matt Welsh.
+ * Extended by Roger Butenuth (butenuth@uni-paderborn.de), October 1997
+ * Extended for linux-2.1.121 till 2.4.0 (June 2000)
+ *     by Pauline Middelink <middelink@polyware.nl>
+ *
+ * This is a set of routines which allow you to reserve a large (?) 
+ * amount of physical memory at boot-time, which can be allocated/deallocated
+ * by drivers. This memory is intended to be used for devices such as 
+ * video framegrabbers which need a lot of physical RAM (above the amount
+ * allocated by kmalloc). This is by no means efficient or recommended;
+ * to be used only in extreme circumstances.
+ *
+ *   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/ptrace.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/proc_fs.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/bootmem.h>
+#include <linux/errno.h>
+#include <linux/malloc.h>
+#include <linux/bigphysarea.h>
+
+static int get_info(char* buf, char**, off_t, int);
+
+typedef struct range_struct {
+	struct range_struct *next;
+	caddr_t base;			/* base of allocated block */
+	size_t  size;			/* size in bytes */
+} range_t;
+
+/*
+ * 0: nothing initialized
+ * 1: bigphysarea_pages initialized
+ * 2: free list initialized
+ */
+static int	init_level = 0;
+static int	bigphysarea_pages = 0;
+static caddr_t	bigphysarea = 0;
+static range_t	*free_list = NULL;
+static range_t	*used_list = NULL;
+static struct resource mem_resource = { "Bigphysarea", 0, 0, IORESOURCE_MEM|IORESOURCE_BUSY };
+
+static
+int __init bigphysarea_init(void)
+{
+	if (bigphysarea_pages == 0 || bigphysarea == 0)
+		return -EINVAL;
+
+	/* create to /proc entry for it */
+	if (!create_proc_info_entry("bigphysarea",0444,&proc_root,get_info)) {
+		// ohoh, no way to free the allocated memory!
+		// continue without proc support, it not fatal in itself
+//		free_bootmem((unsigned long)bigphysarea>>PAGE_SHIFT,bigphysarea_pages<<PAGE_SHIFT);
+//		bigphysarea = 0;
+//		return -ENOMEM;
+	}
+
+	init_level = 1;
+
+	printk(KERN_INFO "bigphysarea: Allocated %d pages at 0x%p.\n",
+	       bigphysarea_pages, bigphysarea);
+
+	return 0;
+}
+
+__initcall(bigphysarea_init);
+
+/*
+ * call when 'bigphysarea=' is given on the commandline.
+ *
+ * Strangely, bootmem is still active during this call, but
+ * during the processing of the initcalls it isn't anymore!
+ * So we alloc the needed memory here instead of bigphysarea_init().
+ */
+static
+int __init bigphysarea_setup(char *str)
+{
+	int par;
+	if (get_option(&str,&par)) {
+		bigphysarea_pages = par;
+		// Alloc the memory
+		bigphysarea = alloc_bootmem_low_pages(bigphysarea_pages<<PAGE_SHIFT);
+		if (!bigphysarea) {
+			printk(KERN_CRIT "bigphysarea: not enough memory for %d pages\n",bigphysarea_pages);
+			return -ENOMEM;
+		}
+
+		// register the resource for it
+		mem_resource.start = bigphysarea;
+		mem_resource.end = mem_resource.start + (bigphysarea_pages<<PAGE_SHIFT);
+		request_resource(&iomem_resource, &mem_resource);
+	}
+	return 1;
+}
+
+__setup("bigphysarea=", bigphysarea_setup);
+
+/*
+ * When we have pages but don't have a freelist, put all pages in
+ * one free list entry. Return 0 on success, 1 on error.
+ */
+static
+int init2(int priority)
+{
+	if (init_level == 1) {
+		free_list = kmalloc(sizeof(range_t), priority);
+		if (free_list != NULL) {
+			free_list->next = NULL;
+			free_list->base = bigphysarea;
+			free_list->size = bigphysarea_pages * PAGE_SIZE;
+			init_level = 2;
+			return 0;
+		}
+	}
+	return 1;
+}
+
+
+/*
+ * Allocate `count' pages from the big physical area. Pages are aligned to
+ * a multiple of `align'. `priority' has the same meaning in kmalloc, it
+ * is needed for management information.
+ * This function may not be called from an interrupt!
+ */
+caddr_t bigphysarea_alloc_pages(int count, int align, int priority)
+{
+	range_t *range, **range_ptr, *new_range, *align_range;
+	caddr_t aligned_base;
+
+	if (init_level < 2)
+		if (init2(priority))
+			return 0;
+	new_range   = NULL;
+	align_range = NULL;
+
+	if (align == 0)
+		align = PAGE_SIZE;
+	else
+		align = align * PAGE_SIZE;
+	/*
+	 * Search a free block which is large enough, even with alignment.
+	 */
+	range_ptr = &free_list;
+	while (*range_ptr != NULL) {
+		range = *range_ptr;
+		aligned_base =
+		  (caddr_t)((((unsigned long)range->base + align - 1) / align) * align);
+		if (aligned_base + count * PAGE_SIZE <= 
+		    range->base + range->size)
+			break;
+	     range_ptr = &range->next;
+	}
+	if (*range_ptr == NULL)
+		return 0;
+	range = *range_ptr;
+	/*
+	 * When we have to align, the pages needed for alignment can
+	 * be put back to the free pool.
+	 * We check here if we need a second range data structure later
+	 * and allocate it now, so that we don't have to check for a
+	 * failed kmalloc later.
+	 */
+	if (aligned_base - range->base + count * PAGE_SIZE < range->size) {
+		new_range = kmalloc(sizeof(range_t), priority);
+		if (new_range == NULL)
+			return NULL;
+	}
+	if (aligned_base != range->base) {
+		align_range = kmalloc(sizeof(range_t), priority);
+		if (align_range == NULL) {
+			if (new_range != NULL)
+				kfree(new_range);
+			return NULL;
+		}
+		align_range->base = range->base;
+		align_range->size = aligned_base - range->base;
+		range->base = aligned_base;
+		range->size -= align_range->size;
+		align_range->next = range;
+		*range_ptr = align_range;
+		range_ptr = &align_range->next;
+	}
+	if (new_range != NULL) {
+		/*
+		 * Range is larger than needed, create a new list element for
+		 * the used list and shrink the element in the free list.
+		 */
+		new_range->base        = range->base;
+		new_range->size        = count * PAGE_SIZE;
+		range->base = new_range->base + new_range->size;
+		range->size = range->size - new_range->size;
+	} else {
+		/*
+		 * Range fits perfectly, remove it from free list.
+		 */
+		*range_ptr = range->next;
+		new_range = range;
+	}
+	/*
+	 * Insert block into used list
+	 */
+	new_range->next = used_list;
+	used_list = new_range;
+
+	return new_range->base;
+}
+
+/*
+ * Free pages allocated with `bigphysarea_alloc_pages'. `base' must be an
+ * address returned by `bigphysarea_alloc_pages'.
+ * This function my not be called from an interrupt!
+ */
+void bigphysarea_free_pages(caddr_t base)
+{
+	range_t *prev, *next, *range, **range_ptr;
+  
+	/*
+	 * Search the block in the used list.
+	 */
+	for (range_ptr = &used_list;
+	     *range_ptr != NULL;
+	     range_ptr = &(*range_ptr)->next)
+		if ((*range_ptr)->base == base)
+			break;
+	if (*range_ptr == NULL) {
+		printk("bigphysarea_free_pages(0x%08x), not allocated!\n",
+		       (unsigned)base);
+		return;
+	}
+	range = *range_ptr;
+	/*
+	 * Remove range from the used list:
+	 */
+	*range_ptr = (*range_ptr)->next;
+	/*
+	 * The free-list is sorted by address, search insertion point
+	 * and insert block in free list.
+	 */
+	for (range_ptr = &free_list, prev = NULL;
+	     *range_ptr != NULL;
+	     prev = *range_ptr, range_ptr = &(*range_ptr)->next)
+		if ((*range_ptr)->base >= base)
+			break;
+	range->next  = *range_ptr;
+	*range_ptr   = range;
+	/*
+	 * Concatenate free range with neighbors, if possible.
+	 * Try for upper neighbor (next in list) first, then
+	 * for lower neighbor (predecessor in list).
+	 */
+	if (range->next != NULL &&
+	    range->base + range->size == range->next->base) {
+		next = range->next;
+		range->size += range->next->size;
+		range->next = next->next;
+		kfree(next);
+	}
+	if (prev != NULL &&
+	    prev->base + prev->size == range->base) {
+		prev->size += prev->next->size;
+		prev->next = range->next;
+		kfree(range);
+	}
+}
+
+caddr_t bigphysarea_alloc(int size)
+{
+	int pages = (size + PAGE_SIZE - 1) / PAGE_SIZE;
+
+	return bigphysarea_alloc_pages(pages, 1, GFP_KERNEL);
+}
+
+void bigphysarea_free(caddr_t addr, int size)
+{
+	(void)size;
+	bigphysarea_free_pages(addr);
+}
+
+static
+int get_info(char *buf, char **a, off_t b, int c)
+{
+	char    *p = buf;
+	range_t *ptr;
+	int     free_count, free_total, free_max;
+	int     used_count, used_total, used_max;
+
+	if (init_level == 1)
+	  init2(GFP_KERNEL);
+
+	free_count = 0;
+	free_total = 0;
+	free_max   = 0;
+	for (ptr = free_list; ptr != NULL; ptr = ptr->next) {
+		free_count++;
+		free_total += ptr->size;
+		if (ptr->size > free_max)
+			free_max = ptr->size;
+	}
+
+	used_count = 0;
+	used_total = 0;
+	used_max   = 0;
+	for (ptr = used_list; ptr != NULL; ptr = ptr->next) {
+		used_count++;
+		used_total += ptr->size;
+		if (ptr->size > used_max)
+			used_max = ptr->size;
+	}
+
+	if (bigphysarea_pages == 0) {
+		p += sprintf(p, "No big physical area allocated!\n");
+		return  p - buf;
+	}
+	  
+	p += sprintf(p, "Big physical area, size %ld kB\n",
+		     bigphysarea_pages * PAGE_SIZE / 1024);
+	p += sprintf(p, "                       free list:             used list:\n");
+	p += sprintf(p, "number of blocks:      %8d               %8d\n",
+		     free_count, used_count);
+	p += sprintf(p, "size of largest block: %8d kB            %8d kB\n",
+		     free_max / 1024, used_max / 1024);
+	p += sprintf(p, "total:                 %8d kB            %8d kB\n",
+		     free_total / 1024, used_total /1024);
+
+	return  p - buf;
+}
Index: pplinux/linuxnew/net/bridge/br.c
diff -u pplinux/linuxnew/net/bridge/br.c:1.1.323.1 pplinux/linuxnew/net/bridge/br.c:1.2
--- pplinux/linuxnew/net/bridge/br.c:1.1.323.1	Thu Feb  3 10:01:00 2005
+++ pplinux/linuxnew/net/bridge/br.c	Wed Apr  6 11:53:13 2005
@@ -22,6 +22,7 @@
 #include <linux/init.h>
 #include <linux/if_bridge.h>
 #include <linux/brlock.h>
+#include <linux/rtnetlink.h>
 #include <asm/uaccess.h>
 #include "br_private.h"
 
@@ -54,15 +55,13 @@
 	return 0;
 }
 
-static void __br_clear_ioctl_hook(void)
-{
-	br_ioctl_hook = NULL;
-}
-
 static void __exit br_deinit(void)
 {
 	unregister_netdevice_notifier(&br_device_notifier);
-	br_call_ioctl_atomic(__br_clear_ioctl_hook);
+
+	rtnl_lock();
+	br_ioctl_hook = NULL;
+	rtnl_unlock();
 
 	br_write_lock_bh(BR_NETPROTO_LOCK);
 	br_handle_frame_hook = NULL;
Index: pplinux/linuxnew/net/bridge/br_if.c
diff -u pplinux/linuxnew/net/bridge/br_if.c:1.1.323.1 pplinux/linuxnew/net/bridge/br_if.c:1.2
--- pplinux/linuxnew/net/bridge/br_if.c:1.1.323.1	Thu Feb  3 10:01:00 2005
+++ pplinux/linuxnew/net/bridge/br_if.c	Wed Apr  6 11:53:13 2005
@@ -19,11 +19,10 @@
 #include <linux/inetdevice.h>
 #include <linux/rtnetlink.h>
 #include <linux/brlock.h>
+#include <linux/etherdevice.h>
 #include <asm/uaccess.h>
 #include "br_private.h"
 
-static struct net_bridge *bridge_list;
-
 static int br_initial_port_cost(struct net_device *dev)
 {
 	if (!strncmp(dev->name, "lec", 3))
@@ -44,7 +43,7 @@
 	struct net_bridge_port *p;
 	struct net_bridge_port **pptr;
 
-	if ((p = dev->br_port) == NULL)
+	if ((p = dev->br_port) == NULL || p->br != br)
 		return -EINVAL;
 
 	br_stp_disable_port(p);
@@ -69,22 +68,6 @@
 	return 0;
 }
 
-static struct net_bridge **__find_br(char *name)
-{
-	struct net_bridge **b;
-	struct net_bridge *br;
-
-	b = &bridge_list;
-	while ((br = *b) != NULL) {
-		if (!strncmp(br->dev.name, name, IFNAMSIZ))
-			return b;
-
-		b = &(br->next);
-	}
-
-	return NULL;
-}
-
 static void del_ifs(struct net_bridge *br)
 {
 	br_write_lock_bh(BR_NETPROTO_LOCK);
@@ -177,42 +160,48 @@
 int br_add_bridge(char *name)
 {
 	struct net_bridge *br;
+	struct net_device *dev;
+	int err;
 
 	if ((br = new_nb(name)) == NULL)
 		return -ENOMEM;
 
-	if (__dev_get_by_name(name) != NULL) {
-		kfree(br);
-		return -EEXIST;
+	dev = &br->dev;
+	if (strchr(dev->name, '%')) {
+		err = dev_alloc_name(dev, dev->name);
+		if (err < 0)
+			goto  out;
 	}
 
-	br->next = bridge_list;
-	bridge_list = br;
+	err = register_netdevice(dev);
+	if (err == 0)
+		br_inc_use_count();
 
-	br_inc_use_count();
-	register_netdev(&br->dev);
-
-	return 0;
+ out:
+	return err;
 }
 
 int br_del_bridge(char *name)
 {
-	struct net_bridge **b;
+	struct net_device *dev;
 	struct net_bridge *br;
 
-	if ((b = __find_br(name)) == NULL)
+	dev = __dev_get_by_name(name);
+	if (!dev)
 		return -ENXIO;
 
-	br = *b;
+	if (dev->hard_start_xmit != br_dev_xmit)
+		return -EPERM;
 
-	if (br->dev.flags & IFF_UP)
+	if (dev->flags & IFF_UP)
 		return -EBUSY;
 
-	del_ifs(br);
+	br = dev->priv;
+	BUG_ON(&br->dev != dev);
 
-	*b = br->next;
+	del_ifs(br);
 
-	unregister_netdev(&br->dev);
+	unregister_netdevice(dev);
 	kfree(br);
 	br_dec_use_count();
 
@@ -232,6 +221,9 @@
 	if (dev->hard_start_xmit == br_dev_xmit)
 		return -ELOOP;
 
+	if (!is_valid_ether_addr(dev->dev_addr))
+		return -EADDRNOTAVAIL;
+
 	dev_hold(dev);
 	write_lock_bh(&br->lock);
 	if ((p = new_nbp(br, dev)) == NULL) {
@@ -267,16 +259,12 @@
 
 int br_get_bridge_ifindices(int *indices, int num)
 {
-	struct net_bridge *br;
-	int i;
-
-	br = bridge_list;
-	for (i=0;i<num;i++) {
-		if (br == NULL)
-			break;
+	struct net_device *dev;
+	int i = 0;
 
-		indices[i] = br->dev.ifindex;
-		br = br->next;
+	for (dev = dev_base; i < num && dev != NULL; dev = dev->next) {
+		if (dev->hard_start_xmit == br_dev_xmit)
+			indices[i++] = dev->ifindex;
 	}
 
 	return i;
Index: pplinux/linuxnew/net/bridge/br_ioctl.c
diff -u pplinux/linuxnew/net/bridge/br_ioctl.c:1.1.323.1 pplinux/linuxnew/net/bridge/br_ioctl.c:1.2
--- pplinux/linuxnew/net/bridge/br_ioctl.c:1.1.323.1	Thu Feb  3 10:01:00 2005
+++ pplinux/linuxnew/net/bridge/br_ioctl.c	Wed Apr  6 11:53:13 2005
@@ -16,6 +16,7 @@
 #include <linux/kernel.h>
 #include <linux/if_bridge.h>
 #include <linux/inetdevice.h>
+#include <linux/rtnetlink.h>
 #include <asm/uaccess.h>
 #include "br_private.h"
 
@@ -230,12 +231,10 @@
 	return -EOPNOTSUPP;
 }
 
-static DECLARE_MUTEX(ioctl_mutex);
-
 int br_ioctl_deviceless_stub(unsigned long arg)
 {
-	int err;
 	unsigned long i[3];
+	int err;
 
 	if (!capable(CAP_NET_ADMIN))
 		return -EPERM;
@@ -243,32 +242,17 @@
 	if (copy_from_user(i, (void *)arg, 3*sizeof(unsigned long)))
 		return -EFAULT;
 
-	down(&ioctl_mutex);
-	err = br_ioctl_deviceless(i[0], i[1], i[2]);
-	up(&ioctl_mutex);
-
+	rtnl_lock();
+	err =  br_ioctl_deviceless(i[0], i[1], i[2]);
+	rtnl_unlock();
 	return err;
 }
 
 int br_ioctl(struct net_bridge *br, unsigned int cmd, unsigned long arg0, unsigned long arg1, unsigned long arg2)
 {
-	int err;
-
 	if (!capable(CAP_NET_ADMIN))
 		return -EPERM;
 
-	down(&ioctl_mutex);
-	err = br_ioctl_deviceless(cmd, arg0, arg1);
-	if (err == -EOPNOTSUPP)
-		err = br_ioctl_device(br, cmd, arg0, arg1, arg2);
-	up(&ioctl_mutex);
-
-	return err;
-}
-
-void br_call_ioctl_atomic(void (*fn)(void))
-{
-	down(&ioctl_mutex);
-	fn();
-	up(&ioctl_mutex);
+	ASSERT_RTNL();
+	return br_ioctl_device(br, cmd, arg0, arg1, arg2);
 }
Index: pplinux/linuxnew/net/bridge/br_private.h
diff -u pplinux/linuxnew/net/bridge/br_private.h:1.1.323.1 pplinux/linuxnew/net/bridge/br_private.h:1.2
--- pplinux/linuxnew/net/bridge/br_private.h:1.1.323.1	Thu Feb  3 10:01:00 2005
+++ pplinux/linuxnew/net/bridge/br_private.h	Wed Apr  6 11:53:13 2005
@@ -79,7 +79,6 @@
 
 struct net_bridge
 {
-	struct net_bridge		*next;
 	rwlock_t			lock;
 	struct net_bridge_port		*port_list;
 	struct net_device		dev;
@@ -169,7 +168,6 @@
 extern void br_handle_frame(struct sk_buff *skb);
 
 /* br_ioctl.c */
-extern void br_call_ioctl_atomic(void (*fn)(void));
 extern int br_ioctl(struct net_bridge *br,
 	     unsigned int cmd,
 	     unsigned long arg0,
Index: pplinux/linuxnew/net/bridge/br_stp.c
diff -u pplinux/linuxnew/net/bridge/br_stp.c:1.1.323.1 pplinux/linuxnew/net/bridge/br_stp.c:1.2
--- pplinux/linuxnew/net/bridge/br_stp.c:1.1.323.1	Thu Feb  3 10:01:00 2005
+++ pplinux/linuxnew/net/bridge/br_stp.c	Wed Apr  6 11:53:13 2005
@@ -20,7 +20,10 @@
 #include "br_private.h"
 #include "br_private_stp.h"
 
-
+/* since time values in bpdu are in jiffies and then scaled (1/256)
+ * before sending, make sure that is at least one.
+ */
+#define MESSAGE_AGE_INCR	((HZ < 256) ? 1 : (HZ/256))
 
 /* called under ioctl_lock or bridge lock */
 int br_is_root_bridge(struct net_bridge *br)
@@ -160,24 +163,26 @@
 	bpdu.root_path_cost = br->root_path_cost;
 	bpdu.bridge_id = br->bridge_id;
 	bpdu.port_id = p->port_id;
-	bpdu.message_age = 0;
-	if (!br_is_root_bridge(br)) {
+	if (br_is_root_bridge(br)) 
+		bpdu.message_age = 0;
+	else {
 		struct net_bridge_port *root;
-		unsigned long age;
 
 		root = br_get_port(br, br->root_port);
-		age = br_timer_get_residue(&root->message_age_timer) + 1;
-		bpdu.message_age = age;
+		bpdu.message_age =  br_timer_get_residue(&root->message_age_timer)
+			+ MESSAGE_AGE_INCR;
 	}
 	bpdu.max_age = br->max_age;
 	bpdu.hello_time = br->hello_time;
 	bpdu.forward_delay = br->forward_delay;
 
-	br_send_config_bpdu(p, &bpdu);
+	if (bpdu.message_age < br->max_age) {
+		br_send_config_bpdu(p, &bpdu);
 
-	p->topology_change_ack = 0;
-	p->config_pending = 0;
-	br_timer_set(&p->hold_timer, jiffies);
+		p->topology_change_ack = 0;
+		p->config_pending = 0;
+		br_timer_set(&p->hold_timer, jiffies);
+	}
 }
 
 /* called under bridge lock */
Index: pplinux/linuxnew/net/core/pktgen.c
diff -u pplinux/linuxnew/net/core/pktgen.c:1.1.323.1 pplinux/linuxnew/net/core/pktgen.c:1.2
--- pplinux/linuxnew/net/core/pktgen.c:1.1.323.1	Tue Feb 22 09:49:30 2005
+++ pplinux/linuxnew/net/core/pktgen.c	Wed Feb 23 18:03:37 2005
@@ -1,5 +1,5 @@
 /* -*-linux-c-*-
- * $Id: pktgen.c,v 1.1 2005/02/21 17:28:41 jim Exp $
+ * $Id: pktgen.c,v 1.8 2002/07/15 19:30:17 robert Exp $
  * pktgen.c: Packet Generator for performance evaluation.
  *
  * Copyright 2001, 2002 by Robert Olsson <robert.olsson@its.uu.se>
Index: pplinux/linuxnew/net/core/skbuff.c
diff -u pplinux/linuxnew/net/core/skbuff.c:1.1.323.1 pplinux/linuxnew/net/core/skbuff.c:1.2
--- pplinux/linuxnew/net/core/skbuff.c:1.1.323.1	Tue Feb 22 09:49:30 2005
+++ pplinux/linuxnew/net/core/skbuff.c	Wed Feb 23 18:03:37 2005
@@ -4,7 +4,7 @@
  *	Authors:	Alan Cox <iiitac@pyr.swan.ac.uk>
  *			Florian La Roche <rzsfl@rz.uni-sb.de>
  *
- *	Version:	$Id: skbuff.c,v 1.1 2005/02/21 17:28:41 jim Exp $
+ *	Version:	$Id: skbuff.c,v 1.90 2001/11/07 05:56:19 davem Exp $
  *
  *	Fixes:	
  *		Alan Cox	:	Fixed the worst of the load balancer bugs.
Index: pplinux/linuxnew/net/core/sock.c
diff -u pplinux/linuxnew/net/core/sock.c:1.1.323.1 pplinux/linuxnew/net/core/sock.c:1.2
--- pplinux/linuxnew/net/core/sock.c:1.1.323.1	Tue Feb 22 09:49:30 2005
+++ pplinux/linuxnew/net/core/sock.c	Wed Feb 23 18:03:37 2005
@@ -7,7 +7,7 @@
  *		handler for protocols to use and generic option handler.
  *
  *
- * Version:	$Id: sock.c,v 1.1 2005/02/21 17:28:41 jim Exp $
+ * Version:	$Id: sock.c,v 1.116 2001/11/08 04:20:06 davem Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
Index: pplinux/linuxnew/net/ipv4/arp.c
diff -u pplinux/linuxnew/net/ipv4/arp.c:1.1.323.1 pplinux/linuxnew/net/ipv4/arp.c:1.2
--- pplinux/linuxnew/net/ipv4/arp.c:1.1.323.1	Thu Feb  3 10:00:59 2005
+++ pplinux/linuxnew/net/ipv4/arp.c	Wed Apr  6 11:53:13 2005
@@ -669,6 +669,7 @@
 	      unsigned char *dest_hw, unsigned char *src_hw,
 	      unsigned char *target_hw)
 {
+	struct in_device *in_dev = in_dev_get(dev);
 	struct sk_buff *skb;
 
 	/*
@@ -678,7 +679,8 @@
 	if (dev->flags&IFF_NOARP)
 		return;
 
-	skb = arp_create(type, ptype, dest_ip, dev, src_ip,
+	skb = arp_create(type, ptype, dest_ip, dev,
+			 (htonl(IN_DEV_PP_ARP_PROXY_SRC_IP(in_dev)) == src_ip && IN_DEV_PP_ARP_ZERO_SRC_IP(in_dev)) ? 0 : src_ip,
 			 dest_hw, src_hw, target_hw);
 	if (skb == NULL) {
 		return;
@@ -846,11 +848,38 @@
 
 	/* Special case: IPv4 duplicate address detection packet (RFC2131) */
 	if (sip == 0) {
-		if (arp->ar_op == htons(ARPOP_REQUEST) &&
-		    inet_addr_type(tip) == RTN_LOCAL &&
-		    !arp_ignore(in_dev,dev,sip,tip))
+	    /*
+	     * rwa: code modified to allow ARP requests with src ip == 0.0.0.0
+	     *      If the requested MAC is in the cache then we return it. Otherwise
+	     *	    forward the request with a valid source ip (set via /proc).
+	     */
+	    if (arp->ar_op == htons(ARPOP_REQUEST)) {
+		if (inet_addr_type(tip) == RTN_LOCAL) {
+		    if (!arp_ignore(in_dev,dev,sip,tip)) {
 			arp_send(ARPOP_REPLY,ETH_P_ARP,tip,dev,tip,sha,dev->dev_addr,dev->dev_addr);
-		goto out;
+		    }
+		} else if (IN_DEV_PP_ARP_PROXY_ENABLE(in_dev)) {
+		    n = __neigh_lookup(&arp_tbl, &tip, dev, 1);
+		    if (n) {
+			sip = htonl(IN_DEV_PP_ARP_PROXY_SRC_IP(in_dev));
+			if (n->nud_state & NUD_VALID) {
+			    char haddr[6];
+			    if (dev->addr_len <= sizeof(haddr)) {
+				read_lock_bh(&n->lock);
+				if (dev->addr_len) {
+				    memcpy(haddr, n->ha, dev->addr_len);
+				    read_unlock_bh(&n->lock);
+				    arp_send(ARPOP_REPLY,ETH_P_ARP,sip,dev,tip,sha,haddr,haddr);
+				}
+			    }
+			    neigh_release(n);
+			} else {
+			    arp_send(ARPOP_REQUEST,ETH_P_ARP,tip,dev,sip,tha,dev->dev_addr,NULL);
+			}
+		    }
+		}
+	    }
+	    goto out;
 	}
 
 	if (arp->ar_op == htons(ARPOP_REQUEST) &&
Index: pplinux/linuxnew/net/ipv4/devinet.c
diff -u pplinux/linuxnew/net/ipv4/devinet.c:1.1.323.1 pplinux/linuxnew/net/ipv4/devinet.c:1.2
--- pplinux/linuxnew/net/ipv4/devinet.c:1.1.323.1	Thu Feb  3 10:00:59 2005
+++ pplinux/linuxnew/net/ipv4/devinet.c	Wed Apr  6 11:53:13 2005
@@ -280,11 +280,15 @@
 				inet_free_ifa(ifa);
 				return -EEXIST;
 			}
+#if 0 /* kimble + devel firmware triggers this check */
 			if (ifa1->ifa_scope != ifa->ifa_scope) {
 				inet_free_ifa(ifa);
 				return -EINVAL;
 			}
-			ifa->ifa_flags |= IFA_F_SECONDARY;
+#else
+			if (ifa1->ifa_scope == ifa->ifa_scope)
+#endif
+				ifa->ifa_flags |= IFA_F_SECONDARY;
 		}
 	}
 
@@ -371,7 +375,9 @@
 	__in_dev_put(in_dev);
 
 	for (ifap=&in_dev->ifa_list; (ifa=*ifap)!=NULL; ifap=&ifa->ifa_next) {
-		if ((rta[IFA_LOCAL-1] && memcmp(RTA_DATA(rta[IFA_LOCAL-1]), &ifa->ifa_local, 4)) ||
+		/* rwa: added the scope check vor kimble */
+		if (ifm->ifa_scope != ifa->ifa_scope ||
+		    (rta[IFA_LOCAL-1] && memcmp(RTA_DATA(rta[IFA_LOCAL-1]), &ifa->ifa_local, 4)) ||
 		    (rta[IFA_LABEL-1] && strcmp(RTA_DATA(rta[IFA_LABEL-1]), ifa->ifa_label)) ||
 		    (rta[IFA_ADDRESS-1] &&
 		     (ifm->ifa_prefixlen != ifa->ifa_prefixlen ||
@@ -1135,7 +1141,7 @@
 static struct devinet_sysctl_table
 {
 	struct ctl_table_header *sysctl_header;
-	ctl_table devinet_vars[20];
+	ctl_table devinet_vars[23];
 	ctl_table devinet_dev[2];
 	ctl_table devinet_conf_dir[2];
 	ctl_table devinet_proto_dir[2];
@@ -1193,6 +1199,15 @@
 	{NET_IPV4_CONF_FORCE_IGMP_VERSION, "force_igmp_version",
 	 &ipv4_devconf.force_igmp_version, sizeof(int), 0644, NULL,
 	 &proc_dointvec},
+	{NET_IPV4_CONF_PP_ARP_ZERO_SRC_IP, "pp_arp_zero_src_ip",
+	 &ipv4_devconf.pp_arp_zero_src_ip, sizeof(int), 0644, NULL,
+	 &proc_dointvec},
+	{NET_IPV4_CONF_PP_ARP_PROXY_ENABLE, "pp_arp_proxy_enable",
+	 &ipv4_devconf.pp_arp_proxy_enable, sizeof(int), 0644, NULL,
+	 &proc_dointvec},
+	{NET_IPV4_CONF_PP_ARP_PROXY_SRC_IP, "pp_arp_proxy_src_ip",
+	 &ipv4_devconf.pp_arp_proxy_src_ip, sizeof(int), 0644, NULL,
+	 &proc_dointvec},
 	 {0}},
 
 	{{NET_PROTO_CONF_ALL, "all", NULL, 0, 0555, devinet_sysctl.devinet_vars},{0}},
Index: pplinux/linuxnew/net/ipv4/route.c
diff -u pplinux/linuxnew/net/ipv4/route.c:1.1.323.1 pplinux/linuxnew/net/ipv4/route.c:1.2
--- pplinux/linuxnew/net/ipv4/route.c:1.1.323.1	Thu Feb  3 10:00:59 2005
+++ pplinux/linuxnew/net/ipv4/route.c	Wed Apr  6 11:53:13 2005
@@ -1315,7 +1315,12 @@
 	if (in_dev == NULL)
 		return -EINVAL;
 
+#ifdef CONFIG_PEPPERCON
+	/* rwa: we receive multicast packets with 127.1.x.x as source */
+	if (MULTICAST(saddr) || BADCLASS(saddr) ||
+#else
 	if (MULTICAST(saddr) || BADCLASS(saddr) || LOOPBACK(saddr) ||
+#endif
 	    skb->protocol != htons(ETH_P_IP))
 		goto e_inval;
 
@@ -1429,7 +1434,12 @@
 	   by fib_lookup.
 	 */
 
+#ifdef CONFIG_PEPPERCON
+	/* rwa: we send packets with 127.1.x.x as source on ethX */
+	if (MULTICAST(saddr) || BADCLASS(saddr))
+#else
 	if (MULTICAST(saddr) || BADCLASS(saddr) || LOOPBACK(saddr))
+#endif
 		goto martian_source;
 
 	if (daddr == 0xFFFFFFFF || (saddr == 0 && daddr == 0))
Index: pplinux/linuxnew/net/ipv4/ipvs/ip_vs_conn.c
diff -u pplinux/linuxnew/net/ipv4/ipvs/ip_vs_conn.c:1.1.323.1 pplinux/linuxnew/net/ipv4/ipvs/ip_vs_conn.c:1.2
--- pplinux/linuxnew/net/ipv4/ipvs/ip_vs_conn.c:1.1.323.1	Thu Feb  3 10:00:59 2005
+++ pplinux/linuxnew/net/ipv4/ipvs/ip_vs_conn.c	Wed Apr  6 11:53:13 2005
@@ -980,7 +980,7 @@
 	/* update checksum because skb might be defragmented */
 	ip_send_check(iph);
 
-	if (unlikely(skb_headroom(skb) < rt->u.dst.dev->hard_header_len)) {
+	if (unlikely(skb_headroom(skb) < ((rt->u.dst.dev->hard_header_len + 15) & ~15))) {
 		if (skb_cow(skb, rt->u.dst.dev->hard_header_len)) {
 			ip_rt_put(rt);
 			IP_VS_ERR_RL("ip_vs_dr_xmit(): no memory\n");
Index: pplinux/linuxnew/net/ipv4/ipvs/ip_vs_core.c
diff -u pplinux/linuxnew/net/ipv4/ipvs/ip_vs_core.c:1.1.323.1 pplinux/linuxnew/net/ipv4/ipvs/ip_vs_core.c:1.2
--- pplinux/linuxnew/net/ipv4/ipvs/ip_vs_core.c:1.1.323.1	Thu Feb  3 10:00:59 2005
+++ pplinux/linuxnew/net/ipv4/ipvs/ip_vs_core.c	Wed Apr  6 11:53:13 2005
@@ -1035,8 +1035,15 @@
 	/*
 	 *	Big tappo: only PACKET_HOST (nor loopback neither mcasts)
 	 *	... don't know why 1st test DOES NOT include 2nd (?)
+	 *	rwa: ignore packets with loopback source addresses and packets
+	 *	     with (nfmark & 0x80000000)=1 (LVS-routed already).
 	 */
+#ifdef CONFIG_PEPPERCON
+	if (skb->pkt_type != PACKET_HOST || skb->dev == &loopback_dev
+	    || (skb->nfmark & 0x80000000) || LOOPBACK(iph->saddr)) {
+#else
 	if (skb->pkt_type != PACKET_HOST || skb->dev == &loopback_dev) {
+#endif
 		IP_VS_DBG(12, "packet type=%d proto=%d daddr=%d.%d.%d.%d ignored\n",
 			  skb->pkt_type,
 			  iph->protocol,
@@ -1131,7 +1138,7 @@
 	/* increase its packet counter and check if it is needed
 	   to be synchronized */
 	atomic_inc(&cp->in_pkts);
-	if (ip_vs_sync_state == IP_VS_STATE_MASTER &&
+	if (ip_vs_sync_state & IP_VS_STATE_MASTER &&
 	    (cp->protocol != IPPROTO_TCP ||
 	     cp->state == IP_VS_S_ESTABLISHED) &&
 	    (atomic_read(&cp->in_pkts) % 50 == sysctl_ip_vs_sync_threshold))
Index: pplinux/linuxnew/net/ipv4/ipvs/ip_vs_ctl.c
diff -u pplinux/linuxnew/net/ipv4/ipvs/ip_vs_ctl.c:1.1.323.1 pplinux/linuxnew/net/ipv4/ipvs/ip_vs_ctl.c:1.2
--- pplinux/linuxnew/net/ipv4/ipvs/ip_vs_ctl.c:1.1.323.1	Thu Feb  3 10:00:59 2005
+++ pplinux/linuxnew/net/ipv4/ipvs/ip_vs_ctl.c	Wed Apr  6 11:53:13 2005
@@ -1727,10 +1727,11 @@
 		ret = ip_vs_set_timeouts(urule);
 		goto out_unlock;
 	} else if (cmd == IP_VS_SO_SET_STARTDAEMON) {
-		ret = start_sync_thread(urule->state, urule->mcast_ifn);
+		ret = start_sync_thread(urule->state, urule->mcast_ifn,
+					urule->buildnr, urule->syncid);
 		goto out_unlock;
 	} else if (cmd == IP_VS_SO_SET_STOPDAEMON) {
-		ret = stop_sync_thread();
+		ret = stop_sync_thread(urule->state);
 		goto out_unlock;
 	} else if (cmd == IP_VS_SO_SET_ZERO) {
 		/* if no service address is set, zero counters in all */
@@ -2078,7 +2079,10 @@
 			goto out;
 		}
 		u.state = ip_vs_sync_state;
-		strcpy(u.mcast_ifn, ip_vs_mcast_ifn);
+		if (ip_vs_sync_state & IP_VS_STATE_MASTER)
+			strcpy(u.mcast_master_ifn, ip_vs_mcast_master_ifn);
+		if (ip_vs_sync_state & IP_VS_STATE_BACKUP)
+			strcpy(u.mcast_backup_ifn, ip_vs_mcast_backup_ifn);
 		if (copy_to_user(user, &u, sizeof(u)) != 0)
 			ret = -EFAULT;
 	}
Index: pplinux/linuxnew/net/ipv4/ipvs/ip_vs_sync.c
diff -u pplinux/linuxnew/net/ipv4/ipvs/ip_vs_sync.c:1.1.323.1 pplinux/linuxnew/net/ipv4/ipvs/ip_vs_sync.c:1.2
--- pplinux/linuxnew/net/ipv4/ipvs/ip_vs_sync.c:1.1.323.1	Thu Feb  3 10:01:00 2005
+++ pplinux/linuxnew/net/ipv4/ipvs/ip_vs_sync.c	Wed Apr  6 11:53:13 2005
@@ -11,11 +11,18 @@
  *
  * ip_vs_sync:  sync connection info from master load balancer to backups
  *              through multicast
+ *
+ * Changes:
+ *	Alexandre Cassen	:	Added master & backup support at a time.
+ *	Alexandre Cassen	:	Added SyncID support for incoming sync
+ *					messages filtering.
  */
 
+#define __KERNEL_SYSCALLS__            /*  for waitpid */
+
 #include <linux/module.h>
 #include <linux/slab.h>
-#include <linux/net.h>
+#include <linux/unistd.h>
 
 #include <linux/skbuff.h>
 #include <linux/in.h>
@@ -28,7 +35,7 @@
 #include <net/ip_vs.h>
 
 #define IP_VS_SYNC_GROUP 0xe0000051    /* multicast addr - 224.0.0.81 */
-#define IP_VS_SYNC_PORT  8848          /* multicast port */
+#define IP_VS_SYNC_PORT  2210 /*8848*/ /* multicast port */
 
 
 /*
@@ -66,29 +73,40 @@
 
 /*
   The master mulitcasts messages to the backup load balancers in the
-  following format.
+  following format. (changed by rwa)
 
        0                   1                   2                   3
        0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-      |  Count Conns  |   Reserved    |            Size               |
+      |  Count Conns  |    Sync ID    |            Size               |
+      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+      |                          Build Number                         |
+      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+      +                         Sync ID (high)                        |
+      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+      +                         Sync ID (low)                         |
       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-      |                                                               |
       |                    IPVS Sync Connection (1)                   |
       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
       |                            .                                  |
       |                            .                                  |
       |                            .                                  |
       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-      |                                                               |
       |                    IPVS Sync Connection (n)                   |
       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+  Count Conns : Number of IPVS sync Connection entries.
+  Sync ID     : IPVS sync group we belong to.
+  Size        : Size of packet.
+
 */
-#define SYNC_MESG_MAX_SIZE      (24*50+4)
+#define SYNC_MESG_MAX_SIZE      (24*50+16)
 struct ip_vs_sync_mesg {
 	__u8                    nr_conns;
 	__u8                    reserved;
 	__u16                   size;
+	__u32			buildnr;
+	__u64			syncid;
 
 	/* ip_vs_sync_conn entries start here */
 };
@@ -113,6 +131,21 @@
 static struct ip_vs_sync_buff   *curr_sb = NULL;
 static spinlock_t curr_sb_lock = SPIN_LOCK_UNLOCKED;
 
+/* build number */
+static u32 ip_vs_buildnr = 0;
+
+/* ipvs sync daemon state */
+volatile int ip_vs_sync_state = IP_VS_STATE_NONE;
+volatile u64 ip_vs_master_syncid = 0;
+volatile u64 ip_vs_backup_syncid = 0;
+
+/* multicast interface name */
+char ip_vs_mcast_master_ifn[IP_VS_IFNAME_MAXLEN];
+char ip_vs_mcast_backup_ifn[IP_VS_IFNAME_MAXLEN];
+
+/* multicast addr */
+static struct sockaddr_in mcast_addr;
+
 static inline void sb_queue_tail(struct ip_vs_sync_buff *sb)
 {
 	spin_lock(&ip_vs_sync_lock);
@@ -150,8 +183,10 @@
 		return NULL;
 	}
 	sb->mesg->nr_conns = 0;
-	sb->mesg->size = 4;
-	sb->head = (unsigned char *)sb->mesg + 4;
+	sb->mesg->buildnr = ip_vs_buildnr;
+	sb->mesg->syncid = ip_vs_master_syncid;
+	sb->mesg->size = 8;
+	sb->head = (unsigned char *)sb->mesg + 8;
 	sb->end = (unsigned char *)sb->mesg + SYNC_MESG_MAX_SIZE;
 	sb->firstuse = jiffies;
 	return sb;
@@ -259,6 +294,20 @@
 		return;
 	}
 
+	/* SyncID sanity check */
+	if (ip_vs_backup_syncid != 0 && m->syncid != ip_vs_backup_syncid) {
+		IP_VS_DBG(7, "Ignoring incoming msg with syncid = 0x%llx\n",
+			  m->syncid);
+		return;
+	}
+
+	/* build number check */
+	if (m->buildnr != ip_vs_buildnr) {
+		IP_VS_DBG(7, "Ignoring incoming msg with buildnr = %u\n",
+			  m->buildnr);
+		return;
+	}
+
 	p = (char *)buffer + sizeof(struct ip_vs_sync_mesg);
 	for (i=0; i<m->nr_conns; i++) {
 		s = (struct ip_vs_sync_conn *)p;
@@ -302,16 +351,6 @@
 }
 
 
-/* ipvs sync daemon state */
-volatile int ip_vs_sync_state = IP_VS_STATE_NONE;
-
-/* multicast interface name */
-char ip_vs_mcast_ifn[IP_VS_IFNAME_MAXLEN];
-
-/* multicast addr */
-static struct sockaddr_in mcast_addr;
-
-
 /*
  *      Setup loopback of outgoing multicasts on a sending socket
  */
@@ -423,7 +462,7 @@
 		return NULL;
 	}
 
-	if (set_mcast_if(sock->sk, ip_vs_mcast_ifn) < 0) {
+	if (set_mcast_if(sock->sk, ip_vs_mcast_master_ifn) < 0) {
 		IP_VS_ERR("Error setting outbound mcast interface\n");
 		goto error;
 	}
@@ -431,7 +470,7 @@
 	set_mcast_loop(sock->sk, 0);
 	set_mcast_ttl(sock->sk, 1);
 
-	if (bind_mcastif_addr(sock, ip_vs_mcast_ifn) < 0) {
+	if (bind_mcastif_addr(sock, ip_vs_mcast_master_ifn) < 0) {
 		IP_VS_ERR("Error binding address of the mcast interface\n");
 		goto error;
 	}
@@ -477,7 +516,7 @@
 	/* join the multicast group */
 	if (join_mcast_group(sock->sk,
 			     (struct in_addr*)&mcast_addr.sin_addr,
-			     ip_vs_mcast_ifn) < 0) {
+			     ip_vs_mcast_backup_ifn) < 0) {
 		IP_VS_ERR("Error joining to the multicast group\n");
 		goto error;
 	}
@@ -550,12 +589,15 @@
 	return len;
 }
 
+static int errno;
 
 static DECLARE_WAIT_QUEUE_HEAD(sync_wait);
-static pid_t sync_pid = 0;
+static pid_t sync_master_pid = 0;
+static pid_t sync_backup_pid = 0;
 
 static DECLARE_WAIT_QUEUE_HEAD(stop_sync_wait);
-static int stop_sync = 0;
+static int stop_master_sync = 0;
+static int stop_backup_sync = 0;
 
 static void sync_master_loop(void)
 {
@@ -568,6 +610,10 @@
 	if (!sock)
 		return;
 
+	IP_VS_INFO("sync thread started: state = MASTER, mcast_ifn = %s, "
+		   "syncid = 0x%llx\n",
+		   ip_vs_mcast_master_ifn, ip_vs_master_syncid);
+
 	for (;;) {
 		while ((sb=sb_dequeue())) {
 			m = sb->mesg;
@@ -586,7 +632,7 @@
 			ip_vs_sync_buff_release(sb);
 		}
 
-		if (stop_sync)
+		if (stop_master_sync)
 			break;
 
 		__set_current_state(TASK_INTERRUPTIBLE);
@@ -625,6 +671,10 @@
 	if (!sock)
 		goto out;
 
+	IP_VS_INFO("sync thread started: state = BACKUP, mcast_ifn = %s, "
+		   "syncid = 0x%llx\n",
+		   ip_vs_mcast_backup_ifn, ip_vs_backup_syncid);
+
 	for (;;) {
 		/* do you have data now? */
 		while (!skb_queue_empty(&(sock->sk->receive_queue))) {
@@ -640,7 +690,7 @@
 			local_bh_enable();
 		}
 
-		if (stop_sync)
+		if (stop_backup_sync)
 			break;
 
 		__set_current_state(TASK_INTERRUPTIBLE);
@@ -655,12 +705,31 @@
 	kfree(buf);
 }
 
+static void sync_pid_set(int sync_state, pid_t sync_pid)
+{
+	if (sync_state == IP_VS_STATE_MASTER)
+		sync_master_pid = sync_pid;
+	else if (sync_state == IP_VS_STATE_BACKUP)
+		sync_backup_pid = sync_pid;
+}
+
+static void sync_stop_set(int sync_state, int set)
+{
+	if (sync_state == IP_VS_STATE_MASTER)
+		stop_master_sync = set;
+	else if (sync_state == IP_VS_STATE_BACKUP)
+		stop_backup_sync = set;
+	else {
+		stop_master_sync = set;
+		stop_backup_sync = set;
+	}
+}
 
 static int sync_thread(void *startup)
 {
 	DECLARE_WAITQUEUE(wait, current);
 	mm_segment_t oldmm;
-	int state;
+	int state = IP_VS_STATE_NONE;
 
 	MOD_INC_USE_COUNT;
 	daemonize();
@@ -668,12 +737,15 @@
 	oldmm = get_fs();
 	set_fs(KERNEL_DS);
 
-	if (ip_vs_sync_state == IP_VS_STATE_MASTER)
+	if (ip_vs_sync_state & IP_VS_STATE_MASTER && !sync_master_pid) {
+		state = IP_VS_STATE_MASTER;
 		sprintf(current->comm, "ipvs_syncmaster");
-	else if (ip_vs_sync_state == IP_VS_STATE_BACKUP)
+	} else if (ip_vs_sync_state & IP_VS_STATE_BACKUP && !sync_backup_pid) {
+		state = IP_VS_STATE_BACKUP;
 		sprintf(current->comm, "ipvs_syncbackup");
-	else IP_VS_BUG();
+	} else IP_VS_BUG();
 
+	/* Block all signals */
 	spin_lock_irq(&current->sigmask_lock);
 	siginitsetinv(&current->blocked, 0);
 	recalc_sigpending(current);
@@ -686,9 +758,7 @@
 
 	add_wait_queue(&sync_wait, &wait);
 
-	state = ip_vs_sync_state;
-	sync_pid = current->pid;
-	IP_VS_INFO("sync thread started.\n");
+	sync_pid_set(state, current->pid);
 	complete((struct completion *)startup);
 
 	/* processing master/backup loop here */
@@ -701,13 +771,13 @@
 	remove_wait_queue(&sync_wait, &wait);
 
 	/* thread exits */
-	sync_pid = 0;
+	sync_pid_set(state, 0);
 	IP_VS_INFO("sync thread stopped!\n");
 
 	set_fs(oldmm);
 	MOD_DEC_USE_COUNT;
 
-	stop_sync = 0;
+	sync_stop_set(state, 0);
 	wake_up(&stop_sync_wait);
 
 	return 0;
@@ -733,20 +803,29 @@
 }
 
 
-int start_sync_thread(int state, char *mcast_ifn)
+int start_sync_thread(int state, char *mcast_ifn, __u32 buildnr, __u64 syncid)
 {
 	DECLARE_COMPLETION(startup);
+	int waitpid_result;
 	pid_t pid;
 
-	if (sync_pid)
+	if ((state == IP_VS_STATE_MASTER && sync_master_pid) ||
+	    (state == IP_VS_STATE_BACKUP && sync_backup_pid))
 		return -EEXIST;
 
 	IP_VS_DBG(7, "%s: pid %d\n", __FUNCTION__, current->pid);
 	IP_VS_DBG(7, "Each ip_vs_sync_conn entry need %d bytes\n",
 		  sizeof(struct ip_vs_sync_conn));
 
-	ip_vs_sync_state = state;
-	strcpy(ip_vs_mcast_ifn, mcast_ifn);
+	ip_vs_buildnr = buildnr;
+	ip_vs_sync_state |= state;
+	if (state == IP_VS_STATE_MASTER) {
+		strcpy(ip_vs_mcast_master_ifn, mcast_ifn);
+		ip_vs_master_syncid = syncid;
+	} else {
+		strcpy(ip_vs_mcast_backup_ifn, mcast_ifn);
+		ip_vs_backup_syncid = syncid;
+	}
 
   repeat:
 	if ((pid = kernel_thread(fork_sync_thread, &startup, 0)) < 0) {
@@ -757,26 +836,37 @@
 		goto repeat;
 	}
 
+	/*
+	 * We must reap the fork_sync_thread here. Really needed to not
+	 * produce zombies while returning.
+	 */
+	if ((waitpid_result = waitpid(pid, NULL, __WCLONE)) != pid) {
+		IP_VS_ERR("%s: waitpid(%d,...) failed, errno %d\n",
+			  __FUNCTION__, pid, -waitpid_result);
+	}
+
 	wait_for_completion(&startup);
 
 	return 0;
 }
 
 
-int stop_sync_thread(void)
+int stop_sync_thread(int state)
 {
 	DECLARE_WAITQUEUE(wait, current);
 
-	if (!sync_pid)
+	if ((state == IP_VS_STATE_MASTER && !sync_master_pid) ||
+	    (state == IP_VS_STATE_BACKUP && !sync_backup_pid))
 		return -ESRCH;
 
 	IP_VS_DBG(7, "%s: pid %d\n", __FUNCTION__, current->pid);
-	IP_VS_INFO("stopping sync thread %d ...\n", sync_pid);
+	IP_VS_INFO("stopping sync thread %d ...\n",
+		   (state == IP_VS_STATE_MASTER) ? sync_master_pid : sync_backup_pid);
 
 	__set_current_state(TASK_UNINTERRUPTIBLE);
 	add_wait_queue(&stop_sync_wait, &wait);
-	ip_vs_sync_state = IP_VS_STATE_NONE;
-	stop_sync = 1;
+	sync_stop_set(state, 1);
+	ip_vs_sync_state -= state;
 	wake_up(&sync_wait);
 	schedule();
 	__set_current_state(TASK_RUNNING);
@@ -785,7 +875,8 @@
 	/* Note: no need to reap the sync thread, because its parent
 	   process is the init process */
 
-	if (stop_sync)
+	if ((state == IP_VS_STATE_MASTER && stop_master_sync) ||
+	    (state == IP_VS_STATE_BACKUP && stop_backup_sync))
 		IP_VS_BUG();
 
 	return 0;
Index: pplinux/linuxnew/net/ipv4/netfilter/Config.in
diff -u pplinux/linuxnew/net/ipv4/netfilter/Config.in:1.1.323.1 pplinux/linuxnew/net/ipv4/netfilter/Config.in:1.2
--- pplinux/linuxnew/net/ipv4/netfilter/Config.in:1.1.323.1	Thu Feb  3 10:00:59 2005
+++ pplinux/linuxnew/net/ipv4/netfilter/Config.in	Thu Feb  3 11:35:39 2005
@@ -53,6 +53,11 @@
     fi
   fi
 
+  dep_tristate '  Fast NAT' CONFIG_IP_NF_FASTNAT $CONFIG_IP_NF_IPTABLES 
+  if [ "$CONFIG_IP_NF_FASTNAT" != "n" ]; then
+    dep_tristate '    FASTNAT target support' CONFIG_IP_NF_TARGET_FASTNAT $CONFIG_IP_NF_FASTNAT
+  fi
+
   if [ "$CONFIG_IP_NF_CONNTRACK" != "n" ]; then
     dep_tristate '  Full NAT' CONFIG_IP_NF_NAT $CONFIG_IP_NF_IPTABLES $CONFIG_IP_NF_CONNTRACK
     if [ "$CONFIG_IP_NF_NAT" != "n" ]; then
Index: pplinux/linuxnew/net/ipv4/netfilter/Makefile
diff -u pplinux/linuxnew/net/ipv4/netfilter/Makefile:1.1.323.1 pplinux/linuxnew/net/ipv4/netfilter/Makefile:1.2
--- pplinux/linuxnew/net/ipv4/netfilter/Makefile:1.1.323.1	Thu Feb  3 10:00:59 2005
+++ pplinux/linuxnew/net/ipv4/netfilter/Makefile	Thu Feb  3 11:35:39 2005
@@ -61,6 +61,7 @@
 obj-$(CONFIG_IP_NF_FILTER) += iptable_filter.o
 obj-$(CONFIG_IP_NF_MANGLE) += iptable_mangle.o
 obj-$(CONFIG_IP_NF_NAT) += iptable_nat.o
+obj-$(CONFIG_IP_NF_FASTNAT) += iptable_fastnat.o
 
 # matches
 obj-$(CONFIG_IP_NF_MATCH_HELPER) += ipt_helper.o
@@ -100,6 +101,7 @@
 obj-$(CONFIG_IP_NF_TARGET_LOG) += ipt_LOG.o
 obj-$(CONFIG_IP_NF_TARGET_ULOG) += ipt_ULOG.o
 obj-$(CONFIG_IP_NF_TARGET_TCPMSS) += ipt_TCPMSS.o
+obj-$(CONFIG_IP_NF_TARGET_FASTNAT) += ipt_FASTNAT.o
 
 # generic ARP tables
 obj-$(CONFIG_IP_NF_ARPTABLES) += arp_tables.o
Index: pplinux/linuxnew/net/ipv4/netfilter/ipt_FASTNAT.c
diff -u /dev/null pplinux/linuxnew/net/ipv4/netfilter/ipt_FASTNAT.c:1.2
--- /dev/null	Tue May 24 10:37:59 2005
+++ pplinux/linuxnew/net/ipv4/netfilter/ipt_FASTNAT.c	Wed Apr  6 11:53:13 2005
@@ -0,0 +1,138 @@
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <linux/ip.h>
+#include <linux/udp.h>
+#include <linux/tcp.h>
+#include <net/ip.h>
+#include <net/checksum.h>
+#include <linux/netfilter_ipv4/ip_tables.h>
+#include <linux/netfilter_ipv4/ipt_FASTNAT.h>
+#include <linux/netdevice.h>
+#include <linux/route.h>
+struct in_device;
+#include <net/route.h>
+
+#if 0
+#define DEBUGP printk
+#else
+#define DEBUGP(format, args...)
+#endif
+
+/* (this is stolen from ip_nat_core.c)
+ * We do checksum mangling, so if they were wrong before they're still
+ * wrong.  Also works for incomplete packets (eg. ICMP dest
+ * unreachables.) */
+static u_int16_t
+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 unsigned int ipt_fastnat_target(struct sk_buff **pskb,
+				       unsigned int hooknum,
+				       const struct net_device *in,
+				       const struct net_device *out,
+				       const void *targinfo,
+				       void *userinfo)
+{
+	const struct ipt_fastnat_info *fi = targinfo;
+	struct iphdr *iph = (*pskb)->nh.iph;
+	struct udphdr *udphdr;
+	struct tcphdr *tcphdr;
+
+	/* Rewrite IP header */
+	(*pskb)->nfcache |= NFC_ALTERED;
+	switch (iph->protocol) {
+	  case IPPROTO_UDP:
+	      udphdr = (struct udphdr *)((u_int32_t *)iph + iph->ihl);
+	      if (fi->type & IPT_FASTNAT_SRC_ADDR) {
+		  udphdr->check = cheat_check(~iph->saddr, fi->saddr.s_addr,
+					      udphdr->check);
+	      }
+	      if (fi->type & IPT_FASTNAT_SRC_PORT) {
+		  udphdr->check = cheat_check(~udphdr->source, fi->sport,
+					      udphdr->check);
+		  udphdr->source = fi->sport;
+	      }
+	      if (fi->type & IPT_FASTNAT_DST_ADDR) {
+		  udphdr->check = cheat_check(~iph->daddr, fi->daddr.s_addr,
+					      udphdr->check);
+	      }
+	      if (fi->type & IPT_FASTNAT_DST_PORT) {
+		  udphdr->check = cheat_check(~udphdr->dest, fi->dport,
+					      udphdr->check);
+		  udphdr->dest = fi->dport;
+	      }
+	      break;
+	  case IPPROTO_TCP:
+	      tcphdr = (struct tcphdr *)((u_int32_t *)iph + iph->ihl);
+	      if (fi->type & IPT_FASTNAT_SRC_ADDR) {
+		  tcphdr->check = cheat_check(~iph->saddr, fi->saddr.s_addr,
+					      tcphdr->check);
+	      }
+	      if (fi->type & IPT_FASTNAT_SRC_PORT) {
+		  tcphdr->check = cheat_check(~tcphdr->source, fi->sport,
+					      tcphdr->check);
+		  tcphdr->source = fi->sport;
+	      }
+	      if (fi->type & IPT_FASTNAT_DST_ADDR) {
+		  tcphdr->check = cheat_check(~iph->daddr, fi->daddr.s_addr,
+					      tcphdr->check);
+	      }
+	      if (fi->type & IPT_FASTNAT_DST_PORT) {
+		  tcphdr->check = cheat_check(~tcphdr->dest, fi->dport,
+					      tcphdr->check);
+		  tcphdr->dest = fi->dport;
+	      }
+	}
+
+	if (fi->type & IPT_FASTNAT_SRC_ADDR) {
+	    iph->check = cheat_check(~iph->saddr, fi->saddr.s_addr,iph->check);
+	    DEBUGP("FASTNAT: src to %u.%u.%u.%u\n", NIPQUAD(fi->saddr.s_addr));
+	    iph->saddr = fi->saddr.s_addr;
+	}
+	if (fi->type & IPT_FASTNAT_DST_ADDR) {
+	    iph->check = cheat_check(~iph->daddr, fi->daddr.s_addr,iph->check);
+	    DEBUGP("FASTNAT: dst to %u.%u.%u.%u\n", NIPQUAD(fi->daddr.s_addr));
+	    iph->daddr = fi->daddr.s_addr;
+	}
+
+	return IPT_CONTINUE;
+}
+
+static int ipt_fastnat_checkentry(const char *tablename,
+				  const struct ipt_entry *e,
+				  void *targinfo,
+				  unsigned int targinfosize,
+				  unsigned int hook_mask)
+{
+	if (hook_mask & ~((1 << NF_IP_LOCAL_IN)
+			  | (1 << NF_IP_PRE_ROUTING)
+			  | (1 << NF_IP_LOCAL_OUT)
+			  | (1 << NF_IP_POST_ROUTING))) {
+		DEBUGP("FASTNAT: bad hook\n");
+		return 0;
+	}
+
+	return 1;
+}
+
+static struct ipt_target ipt_fastnat_reg
+= { { NULL, NULL }, "FASTNAT", ipt_fastnat_target, ipt_fastnat_checkentry,
+    NULL, THIS_MODULE };
+
+static int __init init(void)
+{
+	return ipt_register_target(&ipt_fastnat_reg);
+}
+
+static void __exit fini(void)
+{
+	ipt_unregister_target(&ipt_fastnat_reg);
+}
+
+module_init(init);
+module_exit(fini);
Index: pplinux/linuxnew/net/ipv4/netfilter/ipt_MARK.c
diff -u pplinux/linuxnew/net/ipv4/netfilter/ipt_MARK.c:1.1.323.1 pplinux/linuxnew/net/ipv4/netfilter/ipt_MARK.c:1.2
--- pplinux/linuxnew/net/ipv4/netfilter/ipt_MARK.c:1.1.323.1	Thu Feb  3 10:00:59 2005
+++ pplinux/linuxnew/net/ipv4/netfilter/ipt_MARK.c	Wed Apr  6 11:53:13 2005
@@ -17,8 +17,9 @@
 {
 	const struct ipt_mark_target_info *markinfo = targinfo;
 
-	if((*pskb)->nfmark != markinfo->mark) {
-		(*pskb)->nfmark = markinfo->mark;
+	if(((*pskb)->nfmark & markinfo->mask) != (markinfo->mark & markinfo->mask)) {
+		(*pskb)->nfmark &= ~markinfo->mask;
+		(*pskb)->nfmark |= markinfo->mark & markinfo->mask;
 		(*pskb)->nfcache |= NFC_ALTERED;
 	}
 	return IPT_CONTINUE;
Index: pplinux/linuxnew/net/ipv4/netfilter/iptable_fastnat.c
diff -u /dev/null pplinux/linuxnew/net/ipv4/netfilter/iptable_fastnat.c:1.1
--- /dev/null	Tue May 24 10:37:59 2005
+++ pplinux/linuxnew/net/ipv4/netfilter/iptable_fastnat.c	Thu Feb  3 11:35:39 2005
@@ -0,0 +1,184 @@
+#include <linux/module.h>
+#include <linux/netfilter_ipv4/ip_tables.h>
+
+#define FASTNAT_VALID_HOOKS ((1 << NF_IP_LOCAL_IN) | (1 << NF_IP_PRE_ROUTING) |(1 << NF_IP_LOCAL_OUT) | (1 << NF_IP_POST_ROUTING))
+
+/* Standard entry. */
+struct ipt_standard
+{
+	struct ipt_entry entry;
+	struct ipt_standard_target target;
+};
+
+struct ipt_error_target
+{
+	struct ipt_entry_target target;
+	char errorname[IPT_FUNCTION_MAXNAMELEN];
+};
+
+struct ipt_error
+{
+	struct ipt_entry entry;
+	struct ipt_error_target target;
+};
+
+static struct
+{
+	struct ipt_replace repl;
+	struct ipt_standard entries[4];
+	struct ipt_error term;
+} initial_table __initdata
+= { { "fastnat", FASTNAT_VALID_HOOKS, 5,
+      sizeof(struct ipt_standard) * 4 + sizeof(struct ipt_error),
+      { [NF_IP_LOCAL_IN] 0,
+	[NF_IP_PRE_ROUTING] sizeof(struct ipt_standard),
+	[NF_IP_LOCAL_OUT] sizeof(struct ipt_standard) * 2,
+	[NF_IP_POST_ROUTING] sizeof(struct ipt_standard) * 3 },
+      { [NF_IP_LOCAL_IN] 0,
+	[NF_IP_PRE_ROUTING] sizeof(struct ipt_standard),
+	[NF_IP_LOCAL_OUT] sizeof(struct ipt_standard) * 2,
+	[NF_IP_POST_ROUTING] sizeof(struct ipt_standard) * 3 },
+      0, NULL, { } },
+    {
+	    /* LOCAL_IN */
+	    { { { { 0 }, { 0 }, { 0 }, { 0 }, "", "", { 0 }, { 0 }, 0, 0, 0 },
+		0,
+		sizeof(struct ipt_entry),
+		sizeof(struct ipt_standard),
+		0, { 0, 0 }, { } },
+	      { { { { IPT_ALIGN(sizeof(struct ipt_standard_target)), "" } }, { } },
+		-NF_ACCEPT - 1 } },
+	    /* PRE_ROUTING */
+	    { { { { 0 }, { 0 }, { 0 }, { 0 }, "", "", { 0 }, { 0 }, 0, 0, 0 },
+		0,
+		sizeof(struct ipt_entry),
+		sizeof(struct ipt_standard),
+		0, { 0, 0 }, { } },
+	      { { { { IPT_ALIGN(sizeof(struct ipt_standard_target)), "" } }, { } },
+		-NF_ACCEPT - 1 } },
+	    /* LOCAL_OUT */
+	    { { { { 0 }, { 0 }, { 0 }, { 0 }, "", "", { 0 }, { 0 }, 0, 0, 0 },
+		0,
+		sizeof(struct ipt_entry),
+		sizeof(struct ipt_standard),
+		0, { 0, 0 }, { } },
+	      { { { { IPT_ALIGN(sizeof(struct ipt_standard_target)), "" } }, { } },
+		-NF_ACCEPT - 1 } },
+	    /* POST_ROUTING */
+	    { { { { 0 }, { 0 }, { 0 }, { 0 }, "", "", { 0 }, { 0 }, 0, 0, 0 },
+		0,
+		sizeof(struct ipt_entry),
+		sizeof(struct ipt_standard),
+		0, { 0, 0 }, { } },
+	      { { { { IPT_ALIGN(sizeof(struct ipt_standard_target)), "" } }, { } },
+		-NF_ACCEPT - 1 } },
+    },
+    /* ERROR */
+    { { { { 0 }, { 0 }, { 0 }, { 0 }, "", "", { 0 }, { 0 }, 0, 0, 0 },
+	0,
+	sizeof(struct ipt_entry),
+	sizeof(struct ipt_error),
+	0, { 0, 0 }, { } },
+      { { { { IPT_ALIGN(sizeof(struct ipt_error_target)), IPT_ERROR_TARGET } },
+	  { } },
+	"ERROR"
+      }
+    }
+};
+
+static struct ipt_table fastnat_table
+= { { NULL, NULL }, "fastnat", &initial_table.repl,
+    FASTNAT_VALID_HOOKS, RW_LOCK_UNLOCKED, NULL };
+
+/* The work comes in here from netfilter.c. */
+static unsigned int
+ipt_hook(unsigned int hook,
+	 struct sk_buff **pskb,
+	 const struct net_device *in,
+	 const struct net_device *out,
+	 int (*okfn)(struct sk_buff *))
+{
+	return ipt_do_table(pskb, hook, in, out, &fastnat_table, NULL);
+}
+
+static unsigned int
+ipt_local_out_hook(unsigned int hook,
+		   struct sk_buff **pskb,
+		   const struct net_device *in,
+		   const struct net_device *out,
+		   int (*okfn)(struct sk_buff *))
+{
+	/* root is playing with raw sockets. */
+	if ((*pskb)->len < sizeof(struct iphdr)
+	    || (*pskb)->nh.iph->ihl * 4 < sizeof(struct iphdr)) {
+		if (net_ratelimit())
+			printk("ipt_hook: happy cracking.\n");
+		return NF_ACCEPT;
+	}
+
+	return ipt_do_table(pskb, hook, in, out, &fastnat_table, NULL);
+}
+
+static struct nf_hook_ops ipt_ops[]
+= { { { NULL, NULL }, ipt_hook, PF_INET, NF_IP_LOCAL_IN,
+      NF_IP_PRI_FIRST },
+    { { NULL, NULL }, ipt_hook, PF_INET, NF_IP_PRE_ROUTING,
+      NF_IP_PRI_FIRST },
+    { { NULL, NULL }, ipt_local_out_hook, PF_INET, NF_IP_LOCAL_OUT,
+      NF_IP_PRI_LAST },
+    { { NULL, NULL }, ipt_hook, PF_INET, NF_IP_POST_ROUTING,
+      NF_IP_PRI_LAST }
+};
+
+static int __init init(void)
+{
+	int ret;
+
+	/* Register table */
+	ret = ipt_register_table(&fastnat_table);
+	if (ret < 0)
+		return ret;
+
+	/* Register hooks */
+	ret = nf_register_hook(&ipt_ops[0]);
+	if (ret < 0)
+		goto cleanup_table;
+
+	ret = nf_register_hook(&ipt_ops[1]);
+	if (ret < 0)
+		goto cleanup_hook0;
+
+	ret = nf_register_hook(&ipt_ops[2]);
+	if (ret < 0)
+		goto cleanup_hook1;
+
+	ret = nf_register_hook(&ipt_ops[3]);
+	if (ret < 0)
+		goto cleanup_hook2;
+
+	return ret;
+
+ cleanup_hook2:
+	nf_unregister_hook(&ipt_ops[2]);
+ cleanup_hook1:
+	nf_unregister_hook(&ipt_ops[1]);
+ cleanup_hook0:
+	nf_unregister_hook(&ipt_ops[0]);
+ cleanup_table:
+	ipt_unregister_table(&fastnat_table);
+
+	return ret;
+}
+
+static void __exit fini(void)
+{
+	unsigned int i;
+
+	for (i = 0; i < sizeof(ipt_ops)/sizeof(struct nf_hook_ops); i++)
+		nf_unregister_hook(&ipt_ops[i]);
+
+	ipt_unregister_table(&fastnat_table);
+}
+
+module_init(init);
+module_exit(fini);
Index: pplinux/linuxnew/net/ipv4/netfilter/iptable_mangle.c
diff -u pplinux/linuxnew/net/ipv4/netfilter/iptable_mangle.c:1.1.323.1 pplinux/linuxnew/net/ipv4/netfilter/iptable_mangle.c:1.2
--- pplinux/linuxnew/net/ipv4/netfilter/iptable_mangle.c:1.1.323.1	Thu Feb  3 10:00:59 2005
+++ pplinux/linuxnew/net/ipv4/netfilter/iptable_mangle.c	Wed Apr  6 11:53:13 2005
@@ -160,7 +160,9 @@
 	if (ret != NF_DROP && ret != NF_STOLEN && ret != NF_QUEUE
 	    && ((*pskb)->nh.iph->saddr != saddr
 		|| (*pskb)->nh.iph->daddr != daddr
+#ifdef CONFIG_IP_ROUTE_FWMARK
 		|| (*pskb)->nfmark != nfmark
+#endif
 		|| (*pskb)->nh.iph->tos != tos))
 		return ip_route_me_harder(pskb) == 0 ? ret : NF_DROP;
 
Index: pplinux/linuxnew/patches/Makefile
diff -u /dev/null pplinux/linuxnew/patches/Makefile:1.1
--- /dev/null	Tue May 24 10:37:59 2005
+++ pplinux/linuxnew/patches/Makefile	Thu Feb  3 11:35:39 2005
@@ -0,0 +1,38 @@
+# 
+# all target applies patches in the same order as listed in PATCHES
+# clean target removes patches by copying backup in revers order
+#
+PATCHES = \
+	linux-ipmi-2.4.27-v33-base.diff \
+	linux-ipmi-2.4.27-v33-smb.diff
+
+all: patch_done
+
+patch_done:
+	cd ..; c=0;\
+	for p in $(PATCHES); do \
+	   echo "patch -p1 -b -B patches/backup_$$c/ < patches/$$p"; \
+	   patch -p1 -b -B patches/backup_$$c/ < patches/$$p || exit 1; \
+	   let c=$$c+1; \
+        done;
+	touch patch_done
+
+clean:
+	rm -f patch_done
+	if ls -dr backup_*; then \
+	   for d in `ls -dr backup_*`; do \
+	      pushd $$d; \
+	      for i in `find . -type f`; do \
+	         if [ `stat -c %s $$i` = 0 ]; then \
+	            echo rm ../../$$i; \
+	            rm ../../$$i || exit 1; \
+	         else \
+	            echo cp $$i ../../$$i; \
+	            cp $$i ../../$$i || exit 1; \
+	         fi; \
+	      done; \
+	      popd; \
+	      rm -fr $$d; \
+	   done; \
+	fi
+
Index: pplinux/linuxnew/patches/linux-ipmi-2.4.27-v33-af_ipmi.diff
diff -u /dev/null pplinux/linuxnew/patches/linux-ipmi-2.4.27-v33-af_ipmi.diff:1.1
--- /dev/null	Tue May 24 10:37:59 2005
+++ pplinux/linuxnew/patches/linux-ipmi-2.4.27-v33-af_ipmi.diff	Thu Feb  3 11:35:39 2005
@@ -0,0 +1,791 @@
+Index: linux-ipmi/Documentation/Configure.help
+===================================================================
+--- linux-ipmi.orig/Documentation/Configure.help	2004-08-10 19:03:19.000000000 -0500
++++ linux-ipmi/Documentation/Configure.help	2004-08-10 19:03:28.000000000 -0500
+@@ -3671,6 +3671,13 @@
+ 
+   If unsure, say N.
+ 
++IPMI sockets
++CONFIG_IPMI_SOCKET
++  If you say Y here, you will include support for IPMI sockets;
++  This is the better way for establishing and accessing IPMI devices.
++  
++  If unsure, say N.
++
+ # Choice: alphatype
+ Alpha system type
+ CONFIG_ALPHA_GENERIC
+Index: linux-ipmi/include/linux/net.h
+===================================================================
+--- linux-ipmi.orig/include/linux/net.h	2004-08-10 18:49:40.000000000 -0500
++++ linux-ipmi/include/linux/net.h	2004-08-10 19:03:28.000000000 -0500
+@@ -24,7 +24,7 @@
+ 
+ struct poll_table_struct;
+ 
+-#define NPROTO		32		/* should be enough for now..	*/
++#define NPROTO		64		/* should be enough for now..	*/
+ 
+ 
+ #define SYS_SOCKET	1		/* sys_socket(2)		*/
+Index: linux-ipmi/include/linux/socket.h
+===================================================================
+--- linux-ipmi.orig/include/linux/socket.h	2004-08-10 18:49:40.000000000 -0500
++++ linux-ipmi/include/linux/socket.h	2004-08-10 19:03:28.000000000 -0500
+@@ -175,7 +175,8 @@
+ #define AF_WANPIPE	25	/* Wanpipe API Sockets */
+ #define AF_LLC		26	/* Linux LLC			*/
+ #define AF_BLUETOOTH	31	/* Bluetooth sockets 		*/
+-#define AF_MAX		32	/* For now.. */
++#define AF_IPMI		32	/* IPMI sockers 		*/
++#define AF_MAX		33	/* For now.. */
+ 
+ /* Protocol families, same as address families. */
+ #define PF_UNSPEC	AF_UNSPEC
+@@ -207,6 +208,7 @@
+ #define PF_WANPIPE	AF_WANPIPE
+ #define PF_LLC		AF_LLC
+ #define PF_BLUETOOTH	AF_BLUETOOTH
++#define PF_IPMI		AF_IPMI
+ #define PF_MAX		AF_MAX
+ 
+ /* Maximum queue length specifiable by listen.  */
+Index: linux-ipmi/include/net/af_ipmi.h
+===================================================================
+--- linux-ipmi.orig/include/net/af_ipmi.h	1969-12-31 18:00:00.000000000 -0600
++++ linux-ipmi/include/net/af_ipmi.h	2004-08-10 19:03:28.000000000 -0500
+@@ -0,0 +1,66 @@
++#ifndef _NET_IPMI_H
++#define _NET_IPMI_H
++
++#include <linux/ipmi.h>
++
++/*
++ * This is ipmi address for socket
++ */
++struct sockaddr_ipmi {
++	sa_family_t      sipmi_family; /* AF_IPMI */
++	int              if_num; /* IPMI interface number */
++	struct ipmi_addr ipmi_addr;
++};
++#define SOCKADDR_IPMI_OVERHEAD (sizeof(struct sockaddr_ipmi) \
++				- sizeof(struct ipmi_addr))
++
++/* A msg_control item, this takes a 'struct ipmi_timing_parms' */
++#define IPMI_CMSG_TIMING_PARMS	0x01
++
++/* 
++ * This is ipmi message for socket
++ */
++struct ipmi_sock_msg {
++	int                   recv_type;
++	long                  msgid;
++
++	unsigned char         netfn;
++	unsigned char         cmd;
++	int                   data_len;
++	unsigned char         data[0];
++};
++
++#define IPMI_MAX_SOCK_MSG_LENGTH (sizeof(struct ipmi_sock_msg)+IPMI_MAX_MSG_LENGTH)
++
++/* Register/unregister to receive specific commands.  Uses struct
++   ipmi_cmdspec from linux/ipmi.h */
++#define SIOCIPMIREGCMD		(SIOCPROTOPRIVATE + 0)
++#define SIOCIPMIUNREGCMD	(SIOCPROTOPRIVATE + 1)
++
++/* Register to receive events.  Takes an integer */
++#define SIOCIPMIGETEVENT	(SIOCPROTOPRIVATE + 2)
++
++/* Set the default timing parameters for the socket.  Takes a struct
++   ipmi_timing_parms from linux/ipmi.h */
++#define SIOCIPMISETTIMING	(SIOCPROTOPRIVATE + 3)
++#define SIOCIPMIGETTIMING	(SIOCPROTOPRIVATE + 4)
++
++/* Set/Get the IPMB address of the MC we are connected to, takes an
++   unsigned int. */
++#define SIOCIPMISETADDR		(SIOCPROTOPRIVATE + 5)
++#define SIOCIPMIGETADDR		(SIOCPROTOPRIVATE + 6)
++
++/* Socket information for IPMI for protinfo. */
++struct ipmi_sock {
++	ipmi_user_t user;
++	struct sockaddr_ipmi addr;
++	struct list_head msg_list;
++	
++	wait_queue_head_t wait;	
++	spinlock_t lock;
++
++	int          default_retries;
++	unsigned int default_retry_time_ms;
++};
++
++#endif/*_NET_IPMI_H*/
+Index: linux-ipmi/include/net/sock.h
+===================================================================
+--- linux-ipmi.orig/include/net/sock.h	2004-08-10 19:02:50.000000000 -0500
++++ linux-ipmi/include/net/sock.h	2004-08-10 19:03:28.000000000 -0500
+@@ -98,6 +98,10 @@
+ #include <net/irda/irda.h>
+ #endif
+ 
++#if defined(CONFIG_IPMI_SOCKET) || defined(CONFIG_IPMI_SOCKET_MODULE)
++#include <net/af_ipmi.h>
++#endif
++
+ #if defined(CONFIG_ATM) || defined(CONFIG_ATM_MODULE)
+ struct atm_vcc;
+ #endif
+@@ -720,6 +724,9 @@
+ #if defined(CONFIG_WAN_ROUTER) || defined(CONFIG_WAN_ROUTER_MODULE)
+                struct wanpipe_opt      *af_wanpipe;
+ #endif
++#if defined(CONFIG_IPMI_SOCKET) || defined(CONFIG_IPMI_SOCKET_MODULE)
++	       struct ipmi_sock        af_ipmi;
++#endif
+ 	} protinfo;  		
+ 
+ 
+Index: linux-ipmi/net/Config.in
+===================================================================
+--- linux-ipmi.orig/net/Config.in	2004-08-10 19:02:50.000000000 -0500
++++ linux-ipmi/net/Config.in	2004-08-10 19:03:28.000000000 -0500
+@@ -16,6 +16,7 @@
+ fi
+ bool 'Socket Filtering'  CONFIG_FILTER
+ tristate 'Unix domain sockets' CONFIG_UNIX
++tristate 'IPMI sockets' CONFIG_IPMI_SOCKET
+ bool 'TCP/IP networking' CONFIG_INET
+ if [ "$CONFIG_INET" = "y" ]; then
+    source net/ipv4/Config.in
+Index: linux-ipmi/net/ipmi/af_ipmi.c
+===================================================================
+--- linux-ipmi.orig/net/ipmi/af_ipmi.c	1969-12-31 18:00:00.000000000 -0600
++++ linux-ipmi/net/ipmi/af_ipmi.c	2004-08-10 19:03:28.000000000 -0500
+@@ -0,0 +1,592 @@
++/* 
++ * IPMI Socket Glue
++ *
++ * Author:	Louis Zhuang <louis.zhuang@linux.intel.com>
++ * Copyright by Intel Corp., 2003
++ */
++#include <linux/module.h>
++#include <linux/config.h>
++#include <linux/kernel.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/fcntl.h>
++#include <linux/sockios.h>
++#include <linux/net.h>
++#include <linux/in.h>
++#include <linux/fs.h>
++#include <linux/slab.h>
++#include <asm/uaccess.h>
++#include <linux/skbuff.h>
++#include <linux/tcp.h>
++#include <net/sock.h>
++#include <linux/proc_fs.h>
++#include <linux/init.h>
++#include <linux/poll.h>
++#include <linux/smp_lock.h>
++#include <linux/mount.h>
++#include <linux/ipmi.h>
++#include <net/af_ipmi.h>
++#include <linux/rtnetlink.h>
++
++#define IPMI_SOCKINTF_VERSION "v33"
++
++#ifdef CONFIG_DEBUG_KERNEL
++static int debug = 0;
++#define dbg(format, arg...)                                     \
++        do {                                                    \
++                if(debug)                                    \
++                        printk (KERN_DEBUG "%s: " format "\n",  \
++                                __FUNCTION__, ## arg);          \
++        } while(0)
++#else
++#define dbg(format, arg...)
++#endif /* CONFIG_DEBUG_KERNEL */
++
++#define err(format, arg...) \
++                printk(KERN_ERR "%s: " format "\n", \
++                       __FUNCTION__ , ## arg)
++#define info(format, arg...) \
++                printk(KERN_INFO "%s: " format "\n", \
++                       __FUNCTION__ , ## arg)
++#define warn(format, arg...) \
++                printk(KERN_WARNING "%s: " format "\n", \
++                       __FUNCTION__ , ## arg)
++#define trace(format, arg...) \
++                printk(KERN_INFO "%s(" format ")\n", \
++                       __FUNCTION__ , ## arg)
++
++static kmem_cache_t *ipmi_sk_cachep = NULL;
++
++static atomic_t ipmi_nr_socks = ATOMIC_INIT(0);
++
++
++
++/*
++ * utility functions
++ */
++static inline struct ipmi_sock *to_ipmi_sock(struct sock *sk) 
++{
++	return &sk->protinfo.af_ipmi;
++}
++
++static inline void ipmi_release_sock(struct sock *sk, int embrion)
++{
++	struct ipmi_sock *i = to_ipmi_sock(sk);
++	struct sk_buff   *skb;
++	
++	if (i->user) {
++		ipmi_destroy_user(i->user);
++		i->user = NULL;
++	}
++
++	sock_orphan(sk);
++	sk->shutdown = SHUTDOWN_MASK;
++	sk->state = TCP_CLOSE;
++
++	while((skb=skb_dequeue(&sk->receive_queue))!=NULL)
++		kfree_skb(skb);
++
++	sock_put(sk);
++}
++
++static inline long ipmi_wait_for_queue(struct ipmi_sock *i, long timeo) 
++{
++	
++	DECLARE_WAITQUEUE(wait, current);
++	
++	set_current_state(TASK_INTERRUPTIBLE);
++	add_wait_queue_exclusive(&i->wait, &wait);
++	timeo = schedule_timeout(timeo);
++	remove_wait_queue(&i->wait, &wait);
++	return timeo;
++}
++
++/*
++ * IPMI operation functions
++ */
++static void sock_receive_handler(struct ipmi_recv_msg *msg,
++				 void                 *handler_data)
++{
++	struct ipmi_sock *i = (struct ipmi_sock *)handler_data;
++	unsigned long    flags;
++	
++	spin_lock_irqsave(&i->lock, flags);
++	list_add_tail(&msg->link, &i->msg_list);
++	spin_unlock_irqrestore(&i->lock, flags);
++
++	wake_up_interruptible(&i->wait);
++}
++
++/*
++ * protocol operation functions
++ */
++static int ipmi_release(struct socket *sock)
++{
++	struct sock *sk = sock->sk;
++	
++	if (!sk)
++		return 0;
++
++	sock->sk=NULL;
++	ipmi_release_sock(sk, 0);
++	return 0;
++}
++
++static struct ipmi_user_hndl ipmi_hnd = {
++	.ipmi_recv_hndl = sock_receive_handler
++};
++
++static int ipmi_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
++{
++	struct ipmi_sock *i = to_ipmi_sock(sock->sk);
++	struct sockaddr_ipmi *addr = (struct sockaddr_ipmi *)uaddr;
++	int err = -EINVAL;
++	
++	if (i->user != NULL) {
++		dbg("Cannot bind twice: %p", i->user);
++		return -EINVAL;
++	}
++	
++	err = ipmi_create_user(addr->if_num, &ipmi_hnd, i, &i->user);
++	if (err) {
++		dbg("Cannot create user for the socket: %p", i->user);
++		return err;
++	}
++
++	memcpy(&i->addr, addr, sizeof(i->addr));
++	return 0;
++}
++
++static int ipmi_getname(struct socket *sock, struct sockaddr *uaddr, int *uaddr_len, int peer)
++{
++	struct ipmi_sock *i = to_ipmi_sock(sock->sk);
++	memcpy(uaddr, &i->addr, sizeof(i->addr));
++	return 0;
++}
++
++static unsigned int ipmi_poll(struct file * file, struct socket *sock, poll_table *wait)
++{
++	unsigned int     has_msg = 0;
++	struct ipmi_sock *i = to_ipmi_sock(sock->sk);
++	unsigned long    flags;
++	
++	poll_wait(file, &i->wait, wait);
++	spin_lock_irqsave(&i->lock, flags);
++	if (!list_empty(&i->msg_list))
++		has_msg = 1;
++	spin_unlock_irqrestore(&i->lock, flags);
++
++	if (has_msg)
++		return POLLIN | POLLRDNORM;
++	return 0;
++}
++
++static int ipmi_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
++{
++	struct ipmi_sock    *i = to_ipmi_sock(sock->sk);
++	struct ipmi_cmdspec val; 
++	int                 ival;
++	unsigned int        uival;
++	int                 err;
++	
++	dbg("cmd=%#x, arg=%#lx", cmd, arg);
++	switch(cmd) {
++	case SIOCIPMIREGCMD:
++		err = copy_from_user((void *)&val, (void *)arg,
++				     sizeof(cmd));
++		if (err) {
++			err = -EFAULT;
++			break;
++		}
++		
++		err = ipmi_register_for_cmd(i->user, val.netfn,
++					    val.cmd);
++		break;
++			
++	case SIOCIPMIUNREGCMD:
++		err = copy_from_user((void *)&val, (void *)arg,
++				     sizeof(cmd));
++		if (err) {
++			err = -EFAULT;
++			break;
++		}
++		
++		err = ipmi_unregister_for_cmd(i->user, val.netfn,
++					      val.cmd);
++		break;
++			
++	case SIOCIPMIGETEVENT:
++		err = copy_from_user((void *)&ival, (void *)arg,
++				     sizeof(ival));
++		if (err) {
++			err = -EFAULT;
++			break;
++		}
++		
++		err = ipmi_set_gets_events(i->user, ival);
++		break;
++			
++	case SIOCIPMISETADDR:
++		err = copy_from_user((void *)&uival, (void *)arg,
++				     sizeof(uival));
++		if (err) {
++			err = -EFAULT;
++			break;
++		}
++		
++		ipmi_set_my_address(i->user, uival);
++		break;
++			
++	case SIOCIPMIGETADDR:
++		uival = ipmi_get_my_address(i->user);
++
++		if (copy_to_user((void *) arg, &uival, sizeof(uival))) {
++			err = -EFAULT;
++			break;
++		}
++		err = 0;
++		break;
++			
++	case SIOCIPMISETTIMING:
++	{
++		struct ipmi_timing_parms parms;
++
++		if (copy_from_user(&parms, (void *) arg, sizeof(parms))) {
++			err = -EFAULT;
++			break;
++		}
++		
++		i->default_retries = parms.retries;
++		i->default_retry_time_ms = parms.retry_time_ms;
++		err = 0;
++		break;
++	}
++
++	case SIOCIPMIGETTIMING:
++	{
++		struct ipmi_timing_parms parms;
++
++		parms.retries = i->default_retries;
++		parms.retry_time_ms = i->default_retry_time_ms;
++
++		if (copy_to_user((void *) arg, &parms, sizeof(parms))) {
++			err = -EFAULT;
++			break;
++		}
++
++		err = 0;
++		break;
++	}
++
++	default:
++		err = dev_ioctl(cmd, (void *)arg);
++		break;
++	}
++	
++	return err;
++}
++
++static int ipmi_recvmsg(struct socket *sock, struct msghdr *msg, int size,
++			int rflags, struct scm_cookie *scm)
++{
++	struct ipmi_sock     *i = to_ipmi_sock(sock->sk);
++	long                 timeo;
++	struct ipmi_recv_msg *rcvmsg;
++	struct sockaddr_ipmi addr;
++	char                 buf[IPMI_MAX_SOCK_MSG_LENGTH];
++	struct ipmi_sock_msg *smsg = (struct ipmi_sock_msg *)buf; 
++	int                  err;
++	unsigned long        flags;
++
++	timeo = sock_rcvtimeo(sock->sk, rflags & MSG_DONTWAIT);
++
++	while (1) {
++		spin_lock_irqsave(&i->lock, flags);
++		if (!list_empty(&i->msg_list)) 
++			break;
++		spin_unlock_irqrestore(&i->lock, flags);
++		if (!timeo) {
++			return -EAGAIN;
++		} else if (signal_pending (current)) {
++			dbg("Signal pending: %d", 1);
++			return -EINTR;
++		}
++				
++		timeo = ipmi_wait_for_queue(i, timeo);
++	}
++
++	rcvmsg = list_entry(i->msg_list.next, struct ipmi_recv_msg, link);
++	list_del(&rcvmsg->link);	
++	spin_unlock_irqrestore(&i->lock, flags);
++
++	memcpy(&addr.ipmi_addr, &rcvmsg->addr, sizeof(addr.ipmi_addr));
++	addr.if_num = i->addr.if_num;
++	addr.sipmi_family = i->addr.sipmi_family;
++	memcpy(msg->msg_name, &addr, sizeof(addr));
++	msg->msg_namelen = (SOCKADDR_IPMI_OVERHEAD
++			    + ipmi_addr_length(rcvmsg->addr.addr_type));
++
++	smsg->recv_type		= rcvmsg->recv_type;
++	smsg->msgid		= rcvmsg->msgid;
++	smsg->netfn		= rcvmsg->msg.netfn;
++	smsg->cmd		= rcvmsg->msg.cmd;
++	smsg->data_len		= rcvmsg->msg.data_len;
++	memcpy(smsg->data, rcvmsg->msg.data, smsg->data_len);
++	
++	ipmi_free_recv_msg(rcvmsg);
++	
++	err = memcpy_toiovec(msg->msg_iov, (void *)smsg, 
++			     sizeof(struct ipmi_sock_msg) + smsg->data_len);
++	if (err) {
++		dbg("Cannot copy data to user: %p", i->user);
++		return err;
++	}
++	
++	dbg("user=%p", i->user);
++	dbg("addr_type=%x, channel=%x",
++	    addr.ipmi_addr.addr_type, addr.ipmi_addr.channel);
++	dbg("netfn=%#02x, cmd=%#02x, data=%p, data_len=%x", 
++	    smsg->netfn, smsg->cmd, smsg->data, smsg->data_len);
++
++	return (sizeof(struct ipmi_sock_msg) + smsg->data_len);
++}
++
++static int ipmi_sendmsg(struct socket *sock, struct msghdr *msg, int len,
++			struct scm_cookie *scm)
++{
++	struct ipmi_sock     *i = to_ipmi_sock(sock->sk);
++	struct sockaddr_ipmi *addr = (struct sockaddr_ipmi *)msg->msg_name;
++	struct ipmi_msg      imsg;
++	unsigned char        buf[IPMI_MAX_SOCK_MSG_LENGTH];
++	struct ipmi_sock_msg *smsg = (struct ipmi_sock_msg *)buf;
++	int                  err;
++	struct ipmi_timing_parms tparms;
++	struct cmsghdr           *cmsg;
++
++	err = ipmi_validate_addr(&addr->ipmi_addr,
++				 msg->msg_namelen - SOCKADDR_IPMI_OVERHEAD);
++	if (err) {
++		dbg("Invalid IPMI address: %p", i->user);
++		goto err;
++	}
++	
++	if (len > IPMI_MAX_SOCK_MSG_LENGTH) {
++		err = -EINVAL;
++		dbg("Message too long: %p", i->user);
++		goto err;
++	}
++	
++	if (len < sizeof(struct ipmi_sock_msg)) {
++		err = -EINVAL;
++		dbg("Msg data too small for header: %p", i->user);
++		goto err;
++	}
++
++	err = memcpy_fromiovec((void *)smsg, msg->msg_iov, len);
++	if (err) {
++		dbg("Cannot copy data to kernel: %p", i->user);
++		goto err;
++	}
++	
++	if (len < smsg->data_len+sizeof(struct ipmi_sock_msg)) {
++		err = -EINVAL;
++		dbg("Msg data is out of bound: %p", i->user);
++		goto err;
++	}
++	
++	/* Set defaults. */
++	tparms.retries = i->default_retries;
++	tparms.retry_time_ms = i->default_retry_time_ms;
++
++	for (cmsg=CMSG_FIRSTHDR(msg);
++	     cmsg;
++	     cmsg = CMSG_NXTHDR(msg, cmsg))
++	{
++		if (cmsg->cmsg_len < sizeof(struct cmsghdr)) {
++			err = -EINVAL;
++			dbg("cmsg length too short: %p", i->user);
++			goto err;
++		}
++
++		if (cmsg->cmsg_level != SOL_SOCKET)
++			continue;
++
++		if (cmsg->cmsg_type == IPMI_CMSG_TIMING_PARMS) {
++			struct ipmi_timing_parms *pparms;
++
++			if (cmsg->cmsg_len != CMSG_LEN(sizeof(*pparms))) {
++				err = -EINVAL;
++				dbg("timing parms cmsg not right size: %p",
++				    i->user);
++				goto err;
++			}
++			pparms = (struct ipmi_timing_parms *) CMSG_DATA(cmsg);
++			tparms.retries = pparms->retries;
++			tparms.retry_time_ms = pparms->retry_time_ms;
++		}
++	}
++
++	imsg.netfn 	= smsg->netfn;
++	imsg.cmd	= smsg->cmd;
++	imsg.data 	= smsg->data;
++	imsg.data_len 	= smsg->data_len;
++
++	dbg("user=%p", i->user);
++	dbg("addr_type=%x, channel=%x",
++	    addr->ipmi_addr.addr_type, addr->ipmi_addr.channel);
++	dbg("netfn=%#02x, cmd=%#02x, data=%p, data_len=%x", 
++	    imsg.netfn, imsg.cmd, imsg.data, imsg.data_len);
++	err = ipmi_request_settime(i->user, &addr->ipmi_addr,
++				   smsg->msgid, &imsg, NULL, 0,
++				   tparms.retries, tparms.retry_time_ms);
++	if (err) {
++		dbg("Cannot send message: %p", i->user);
++		goto err;
++	}
++	
++err:
++	return err;
++}
++
++static struct proto_ops ipmi_ops = {
++	.family =	PF_IPMI,
++	.release =	ipmi_release,
++	.bind =		ipmi_bind,
++	.connect =	sock_no_connect,
++	.socketpair =	sock_no_socketpair,
++	.accept =	sock_no_accept,
++	.getname =	ipmi_getname,
++	.poll =		ipmi_poll,
++	.ioctl =	ipmi_ioctl,
++	.listen =	sock_no_listen,
++	.shutdown =	sock_no_shutdown,
++	.setsockopt =	sock_no_setsockopt,
++	.getsockopt =	sock_no_getsockopt,
++	.sendmsg =	ipmi_sendmsg,
++	.recvmsg =	ipmi_recvmsg,
++	.mmap =		sock_no_mmap,
++	.sendpage =	sock_no_sendpage
++};
++
++
++static void ipmi_sock_destructor(struct sock *sk)
++{
++	skb_queue_purge(&sk->receive_queue);
++
++	BUG_TRAP(atomic_read(&sk->wmem_alloc) == 0);
++	BUG_TRAP(sk->socket==NULL);
++	if (sk->dead==0) {
++		printk("Attempt to release alive ipmi socket: %p\n", sk);
++		return;
++	}
++
++	atomic_dec(&ipmi_nr_socks);
++	MOD_DEC_USE_COUNT;
++}
++
++/*
++ * net protocol functions
++ */
++static struct sock *ipmi_socket_create1(struct socket *sock)
++{
++	struct sock *sk;
++
++	if (atomic_read(&ipmi_nr_socks) >= 2*files_stat.max_files)
++		return NULL;
++
++	MOD_INC_USE_COUNT;
++
++	sk = sk_alloc(PF_IPMI, GFP_KERNEL, 1);
++	if (!sk) {
++		MOD_DEC_USE_COUNT;
++		return NULL;
++	}
++	
++	sock_init_data(sock, sk);
++	sock->sk->rcvtimeo = 5*HZ;
++	sock->sk->destruct = ipmi_sock_destructor;
++	spin_lock_init(&sk->protinfo.af_ipmi.lock);
++	INIT_LIST_HEAD(&sk->protinfo.af_ipmi.msg_list);
++	init_waitqueue_head(&sk->protinfo.af_ipmi.wait);
++
++	/* Set to use default values. */
++	sk->protinfo.af_ipmi.default_retries = -1;
++	sk->protinfo.af_ipmi.default_retry_time_ms = 0;
++
++	atomic_inc(&ipmi_nr_socks);
++	return sk;
++}
++
++static int ipmi_socket_create(struct socket *sock, int protocol)
++{
++	if (!capable(CAP_NET_RAW))
++		return -EPERM;
++	if (protocol && protocol != PF_IPMI)
++		return -EPROTONOSUPPORT;
++
++	sock->state = SS_UNCONNECTED;
++
++	switch (sock->type) {
++	case SOCK_RAW:
++		sock->type=SOCK_DGRAM;	
++	case SOCK_DGRAM:
++		sock->ops = &ipmi_ops;
++		break;
++	default:
++		return -EPROTONOSUPPORT;
++	}
++	
++	return ipmi_socket_create1(sock)? 0 : -ENOMEM;
++}
++
++static struct net_proto_family ipmi_family_ops = {
++	.family = PF_IPMI,
++	.create = ipmi_socket_create,
++};
++
++
++/* 
++ * init/exit functions
++ */
++static int __init ipmi_socket_init(void)
++{
++
++	int err=0;
++	
++	printk(KERN_INFO "ipmi socket interface version "
++	       IPMI_SOCKINTF_VERSION "\n");
++
++	ipmi_sk_cachep = kmem_cache_create("ipmi_sock",
++					   sizeof(struct ipmi_sock), 0,
++					   SLAB_HWCACHE_ALIGN, 0, 0);
++	if (!ipmi_sk_cachep) {
++		printk(KERN_CRIT "%s: Unable to create ipmi_sock SLAB cache\n", __func__);
++		err = -ENOMEM;
++		goto out;
++	}
++	
++	err = sock_register(&ipmi_family_ops);
++	if (err)
++		kmem_cache_destroy(ipmi_sk_cachep);
++out:
++	return err;
++}
++
++static void __exit ipmi_socket_exit(void)
++{
++	sock_unregister(PF_IPMI);
++	kmem_cache_destroy(ipmi_sk_cachep);
++}
++
++#ifdef CONFIG_DEBUG_KERNEL
++MODULE_PARM(debug, "i");
++#endif
++module_init(ipmi_socket_init);
++module_exit(ipmi_socket_exit);
++
++MODULE_LICENSE("GPL");
+Index: linux-ipmi/net/ipmi/Makefile
+===================================================================
+--- linux-ipmi.orig/net/ipmi/Makefile	1969-12-31 18:00:00.000000000 -0600
++++ linux-ipmi/net/ipmi/Makefile	2004-08-10 19:03:28.000000000 -0500
+@@ -0,0 +1,7 @@
++
++O_TARGET = ipmi.o
++
++obj-$(CONFIG_IPMI_SOCKET) = af_ipmi.o
++
++include $(TOPDIR)/Rules.make
++
+Index: linux-ipmi/net/Makefile
+===================================================================
+--- linux-ipmi.orig/net/Makefile	2004-08-10 19:02:50.000000000 -0500
++++ linux-ipmi/net/Makefile	2004-08-10 19:03:43.000000000 -0500
+@@ -7,7 +7,7 @@
+ 
+ O_TARGET :=	network.o
+ 
+-mod-subdirs :=	ipv4/netfilter ipv6/netfilter ipx irda bluetooth atm netlink sched core sctp 802
++mod-subdirs :=	ipv4/netfilter ipv6/netfilter ipx irda bluetooth atm netlink sched core sctp 802 ipmi
+ export-objs :=	netsyms.o
+ 
+ subdir-y :=	core ethernet
+@@ -46,6 +46,7 @@
+ subdir-$(CONFIG_DECNET)		+= decnet
+ subdir-$(CONFIG_ECONET)		+= econet
+ subdir-$(CONFIG_VLAN_8021Q)           += 8021q
++subdir-$(CONFIG_IPMI_SOCKET)	+= ipmi
+ 
+ ifeq ($(CONFIG_NETFILTER),y)
+   mod-subdirs += ipv4/ipvs
Index: pplinux/linuxnew/patches/linux-ipmi-2.4.27-v33-base.diff
diff -u /dev/null pplinux/linuxnew/patches/linux-ipmi-2.4.27-v33-base.diff:1.1
--- /dev/null	Tue May 24 10:37:59 2005
+++ pplinux/linuxnew/patches/linux-ipmi-2.4.27-v33-base.diff	Thu Feb  3 11:35:39 2005
@@ -0,0 +1,8762 @@
+Index: linux-ipmi/Documentation/Configure.help
+===================================================================
+--- linux-ipmi.orig/Documentation/Configure.help	2004-08-13 08:05:37.000000000 -0500
++++ linux-ipmi/Documentation/Configure.help	2004-08-19 07:58:47.000000000 -0500
+@@ -28734,18 +28734,41 @@
+   generate an IPMI event describing the panic to each interface
+   registered with the message handler.
+ 
++Generate OEM events containing the panic string
++CONFIG_IPMI_PANIC_STRING
++  When a panic occurs, this will cause the IPMI message handler to
++  generate IPMI OEM type f0 events holding the IPMB address of the
++  panic generator (byte 4 of the event), a sequence number for the
++  string (byte 5 of the event) and part of the string (the rest of the
++  event).  Bytes 1, 2, and 3 are the normal usage for an OEM event.
++  You can fetch these events and use the sequence numbers to piece the
++  string together.
++
+ Device interface for IPMI
+ CONFIG_IPMI_DEVICE_INTERFACE
+   This provides an IOCTL interface to the IPMI message handler so
+   userland processes may use IPMI.  It supports poll() and select().
+ 
++IPMI SI handler
++CONFIG_IPMI_SI
++  Provides a driver for System Interfaces (KCS, SMIC, BT).
++  Currently, only KCS and SMIC are supported.  If
++  you are using IPMI, you should probably say "y" here.
++
+ IPMI KCS handler
+ CONFIG_IPMI_KCS
+-  Provides a driver for a KCS-style interface to a BMC.
++  Provides a driver for a KCS-style interface to a BMC.  This
++  is deprecated, please use the IPMI System Interface handler
++  instead.
+ 
+ IPMI Watchdog Timer
+ CONFIG_IPMI_WATCHDOG
+   This enables the IPMI watchdog timer.
++  
++IPMI Poweroff
++CONFIG_IPMI_POWEROFF
++  This enables a function to power off the system with IPMI if
++  the IPMI management controller is capable of this.
+ 
+ CRC32 functions
+ CONFIG_CRC32
+Index: linux-ipmi/Documentation/IPMI.txt
+===================================================================
+--- linux-ipmi.orig/Documentation/IPMI.txt	2004-08-13 08:05:37.000000000 -0500
++++ linux-ipmi/Documentation/IPMI.txt	2004-08-19 07:58:47.000000000 -0500
+@@ -22,6 +22,58 @@
+ http://www.intel.com/design/servers/ipmi/index.htm.  IPMI is a big
+ subject and I can't cover it all here!
+ 
++Configuration
++-------------
++
++The LinuxIPMI driver is modular, which means you have to pick several
++things to have it work right depending on your hardware.  Most of
++these are available in the 'Character Devices' menu.
++
++No matter what, you must pick 'IPMI top-level message handler' to use
++IPMI.  What you do beyond that depends on your needs and hardware.
++
++The message handler does not provide any user-level interfaces.
++Kernel code (like the watchdog) can still use it.  If you need access
++from userland, you need to select 'Device interface for IPMI' if you
++want access through a device driver.  Another interface is also
++available, you may select 'IPMI sockets' in the 'Networking Support'
++main menu.  This provides a socket interface to IPMI.  You may select
++both of these at the same time, they will both work together.
++
++The driver interface depends on your hardware.  If you have a board
++with a standard interface (These will generally be either "KCS",
++"SMIC", or "BT", consult your hardware manual), choose the 'IPMI SI
++handler' option.  A driver also exists for direct I2C access to the
++IPMI management controller.  Some boards support this, but it is
++unknown if it will work on every board.  For this, choose 'IPMI SMBus
++handler', but be ready to try to do some figuring to see if it will
++work.
++
++There is also a KCS-only driver interface supplied, but it is
++depracated in favor of the SI interface.
++
++You should generally enable ACPI on your system, as systems with IPMI
++should have ACPI tables describing them.
++
++If you have a standard interface and the board manufacturer has done
++their job correctly, the IPMI controller should be automatically
++detect (via ACPI or SMBIOS tables) and should just work.  Sadly, many
++boards do not have this information.  The driver attempts standard
++defaults, but they may not work.  If you fall into this situation, you
++need to read the section below named 'The SI Driver' on how to
++hand-configure your system.
++
++IPMI defines a standard watchdog timer.  You can enable this with the
++'IPMI Watchdog Timer' config option.  If you compile the driver into
++the kernel, then via a kernel command-line option you can have the
++watchdog timer start as soon as it intitializes.  It also have a lot
++of other options, see the 'Watchdog' section below for more details.
++Note that you can also have the watchdog continue to run if it is
++closed (by default it is disabled on close).  Go into the 'Watchdog
++Cards' menu, enable 'Watchdog Timer Support', and enable the option
++'Disable watchdog shutdown on close'.
++
++
+ Basic Design
+ ------------
+ 
+@@ -41,18 +93,29 @@
+ driver, each open file for this device ties in to the message handler
+ as an IPMI user.
+ 
+-ipmi_kcs_drv - A driver for the KCS SMI.  Most system have a KCS
+-interface for IPMI.
++ipmi_si_drv - A driver for various system interfaces.  This supports
++KCS, SMIC, and may support BT in the future.  Unless you have your own
++custom interface, you probably need to use this.
++
++ipmi_kcs_drv - A driver for the KCS SI.  Most systems have a KCS
++interface for IPMI.  This is deprecated, ipmi_si_drv supports KCS and
++SMIC interfaces.
++
++af_ipmi - A network socket interface to IPMI.  This doesn't take up
++a character device in your system.
+ 
+ 
+ Much documentation for the interface is in the include files.  The
+ IPMI include files are:
+ 
+-ipmi.h - Contains the user interface and IOCTL interface for IPMI.
++net/af_ipmi.h - Contains the socket interface.
++
++linux/ipmi.h - Contains the user interface and IOCTL interface for IPMI.
+ 
+-ipmi_smi.h - Contains the interface for SMI drivers to use.
++linux/ipmi_smi.h - Contains the interface for system management interfaces
++(things that interface to IPMI controllers) to use.
+ 
+-ipmi_msgdefs.h - General definitions for base IPMI messaging.
++linux/ipmi_msgdefs.h - General definitions for base IPMI messaging.
+ 
+ 
+ Addressing
+@@ -260,8 +323,98 @@
+ in the order they register, although if an SMI unregisters and then
+ another one registers, all bets are off.
+ 
+-The ipmi_smi.h defines the interface for SMIs, see that for more
+-details.
++The ipmi_smi.h defines the interface for management interfaces, see
++that for more details.
++
++
++The SI Driver
++-------------
++
++The SI driver allows up to 4 KCS or SMIC interfaces to be configured
++in the system.  By default, scan the ACPI tables for interfaces, and
++if it doesn't find any the driver will attempt to register one KCS
++interface at the spec-specified I/O port 0xca2 without interrupts.
++You can change this at module load time (for a module) with:
++
++  insmod ipmi_si_drv.o si_type=<type1>,<type2>....
++       si_ports=<port1>,<port2>... si_addrs=<addr1>,<addr2>
++       si_irqs=<irq1>,<irq2>... si_trydefaults=[0|1]
++       si_regspacings=<sp1>,<sp2>,... si_regsizes=<size1>,<size2>,...
++       si_regshifts=<shift1>,<shift2>,...
++
++Each of these except si_trydefaults is a list, the first item for the
++first interface, second item for the second interface, etc.
++
++The si_type may be either "kcs", "smic", or "bt".  If you leave it blank, it
++defaults to "kcs".
++
++If you specify si_addrs as non-zero for an interface, the driver will
++use the memory address given as the address of the device.  This
++overrides si_ports.
++
++If you specify si_ports as non-zero for an interface, the driver will
++use the I/O port given as the device address.
++
++If you specify si_irqs as non-zero for an interface, the driver will
++attempt to use the given interrupt for the device.
++
++si_trydefaults sets whether the standard IPMI interface at 0xca2 and
++any interfaces specified by ACPE are tried.  By default, the driver
++tries it, set this value to zero to turn this off.
++
++The next three parameters have to do with register layout.  The
++registers used by the interfaces may not appear at successive
++locations and they may not be in 8-bit registers.  These parameters
++allow the layout of the data in the registers to be more precisely
++specified.
++
++The regspacings parameter give the number of bytes between successive
++register start addresses.  For instance, if the regspacing is set to 4
++and the start address is 0xca2, then the address for the second
++register would be 0xca6.  This defaults to 1.
++
++The regsizes parameter gives the size of a register, in bytes.  The
++data used by IPMI is 8-bits wide, but it may be inside a larger
++register.  This parameter allows the read and write type to specified.
++It may be 1, 2, 4, or 8.  The default is 1.
++
++Since the register size may be larger than 32 bits, the IPMI data may not
++be in the lower 8 bits.  The regshifts parameter give the amount to shift
++the data to get to the actual IPMI data.
++
++When compiled into the kernel, the addresses can be specified on the
++kernel command line as:
++
++  ipmi_si=[<type>,]<bmc1>:<irq1>,[<type>,]<bmc2>:<irq2>....,[nodefault]
++
++The type is optional and may be either "kcs" for KCS, "smic" for SMIC,
++or "bt" for BT.  If not specified, it defaults to KCS.  The <bmcx>
++values is either "p<port>[#<reginfo>]" or "m<addr>[#<reginfo>]" for
++port or memory addresses.  So for instance, a KCS interface at port
++0xca2 using interrupt 9 and a SMIC memory interface at address
++0xf9827341 with no interrupt would be specified
++"ipmi_si=k,p0xca2:9,s,m0xf9827341".  If you specify zero for in irq or
++don't specify it, the driver will run polled unless the software can
++detect the interrupt to use in the ACPI tables.
++
++The #reginfo in the address specifies the register layout as described
++in the previous discussion of register layout.  See that for the
++details of the meainings of this.  The format of reginfo is:
++"#<regspacing>[.<regsizes>[.<regshift>]].  So, for instance, if you
++have a KCS system with a BMC at memory address 0xfea00000 with 32-bit
++registers that are 16 bytes apart and the IPMI info is in the top 8
++bits of the register, you would have the following:
++  ipmi_si=kcs,m0xfea00000#16.4.24
++
++By default, the driver will attempt to detect a KCS device at the
++spec-specified 0xca2 address and any address specified by ACPI.  If
++you want to turn this off, use the "nodefault" option.
++
++If you have high-res timers compiled into the kernel, the driver will
++use them to provide much better performance.  Note that if you do not
++have high-res timers enabled in the kernel and you don't have
++interrupts enabled, the driver will run VERY slowly.  Don't blame me,
++these interfaces suck.
+ 
+ 
+ The KCS Driver
+@@ -323,7 +476,10 @@
+ 
+ The timeout is the number of seconds to the action, and the pretimeout
+ is the amount of seconds before the reset that the pre-timeout panic will
+-occur (if pretimeout is zero, then pretimeout will not be enabled).
++occur (if pretimeout is zero, then pretimeout will not be enabled).  Note
++that the pretimeout is the time before the final timeout.  So if the
++timeout is 50 seconds and the pretimeout is 10 seconds, then the pretimeout
++will occur in 40 second (10 seconds before the timeout).
+ 
+ The action may be "reset", "power_cycle", or "power_off", and
+ specifies what to do when the timer times out, and defaults to
+Index: linux-ipmi/drivers/char/Config.in
+===================================================================
+--- linux-ipmi.orig/drivers/char/Config.in	2004-08-13 08:05:37.000000000 -0500
++++ linux-ipmi/drivers/char/Config.in	2004-08-19 07:58:47.000000000 -0500
+@@ -230,9 +230,12 @@
+ 
+ tristate 'IPMI top-level message handler' CONFIG_IPMI_HANDLER
+ dep_mbool '  Generate a panic event to all BMCs on a panic' CONFIG_IPMI_PANIC_EVENT $CONFIG_IPMI_HANDLER
++dep_mbool '  Generate a OEM events holding the panic string' CONFIG_IPMI_PANIC_STRING $CONFIG_IPMI_PANIC_EVENT
+ dep_tristate '  Device interface for IPMI' CONFIG_IPMI_DEVICE_INTERFACE $CONFIG_IPMI_HANDLER
++dep_tristate '  IPMI SI handler' CONFIG_IPMI_SI $CONFIG_IPMI_HANDLER
+ dep_tristate '  IPMI KCS handler' CONFIG_IPMI_KCS $CONFIG_IPMI_HANDLER
+ dep_tristate '  IPMI Watchdog Timer' CONFIG_IPMI_WATCHDOG $CONFIG_IPMI_HANDLER
++dep_tristate '  IPMI Poweroff' CONFIG_IPMI_POWEROFF $CONFIG_IPMI_HANDLER
+ 
+ mainmenu_option next_comment
+ comment 'Watchdog Cards'
+Index: linux-ipmi/drivers/char/ipmi/ipmi_bt_sm.c
+===================================================================
+--- linux-ipmi.orig/drivers/char/ipmi/ipmi_bt_sm.c	1969-12-31 18:00:00.000000000 -0600
++++ linux-ipmi/drivers/char/ipmi/ipmi_bt_sm.c	2004-08-13 08:06:49.000000000 -0500
+@@ -0,0 +1,513 @@
++/*
++ *  ipmi_bt_sm.c
++ *
++ *  The state machine for an Open IPMI BT sub-driver under ipmi_si.c, part
++ *  of the driver architecture at http://sourceforge.net/project/openipmi
++ *
++ *  Author:	Rocky Craig <first.last@hp.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/kernel.h> /* For printk. */
++#include <linux/string.h>
++#include <linux/ipmi_msgdefs.h>		/* for completion codes */
++#include "ipmi_si_sm.h"
++
++#define IPMI_BT_VERSION "v33"
++
++static int bt_debug = 0x00;	/* Production value 0, see following flags */
++
++#define	BT_DEBUG_ENABLE	1
++#define BT_DEBUG_MSG	2
++#define BT_DEBUG_STATES	4
++
++/* Typical "Get BT Capabilities" values are 2-3 retries, 5-10 seconds,
++   and 64 byte buffers.  However, one HP implementation wants 255 bytes of
++   buffer (with a documented message of 160 bytes) so go for the max. 
++   Since the Open IPMI architecture is single-message oriented at this
++   stage, the queue depth of BT is of no concern. */
++
++#define BT_NORMAL_TIMEOUT	2000000	/* seconds in microseconds */
++#define BT_RETRY_LIMIT		2
++#define BT_RESET_DELAY		6000000	/* 6 seconds after warm reset */
++
++enum bt_states {
++	BT_STATE_IDLE,
++	BT_STATE_XACTION_START,
++	BT_STATE_WRITE_BYTES,
++	BT_STATE_WRITE_END,
++	BT_STATE_WRITE_CONSUME,
++	BT_STATE_B2H_WAIT,
++	BT_STATE_READ_END,
++	BT_STATE_RESET1,		/* These must come last */
++	BT_STATE_RESET2,
++	BT_STATE_RESET3,
++	BT_STATE_RESTART,
++	BT_STATE_HOSED
++};
++
++struct si_sm_data {
++	enum bt_states	state;
++	enum bt_states	last_state;	/* assist printing and resets */
++	unsigned char	seq;		/* BT sequence number */
++	struct si_sm_io	*io;
++        unsigned char	write_data[IPMI_MAX_MSG_LENGTH];
++        int		write_count;
++        unsigned char	read_data[IPMI_MAX_MSG_LENGTH];
++        int		read_count;
++        int		truncated;
++        long		timeout;
++        unsigned int	error_retries;	/* end of "common" fields */
++	int		nonzero_status;	/* hung BMCs stay all 0 */
++};
++
++#define BT_CLR_WR_PTR	0x01	/* See IPMI 1.5 table 11.6.4 */
++#define BT_CLR_RD_PTR	0x02
++#define BT_H2B_ATN	0x04
++#define BT_B2H_ATN	0x08
++#define BT_SMS_ATN	0x10
++#define BT_OEM0		0x20
++#define BT_H_BUSY	0x40
++#define BT_B_BUSY	0x80
++
++/* Some bits are toggled on each write: write once to set it, once
++   more to clear it; writing a zero does nothing.  To absolutely
++   clear it, check its state and write if set.  This avoids the "get 
++   current then use as mask" scheme to modify one bit.  Note that the 
++   variable "bt" is hardcoded into these macros. */ 
++
++#define BT_STATUS	bt->io->inputb(bt->io, 0)
++#define BT_CONTROL(x)	bt->io->outputb(bt->io, 0, x)
++
++#define BMC2HOST	bt->io->inputb(bt->io, 1)
++#define HOST2BMC(x)	bt->io->outputb(bt->io, 1, x)
++
++#define BT_INTMASK_R	bt->io->inputb(bt->io, 2)
++#define BT_INTMASK_W(x)	bt->io->outputb(bt->io, 2, x)
++
++/* Convenience routines for debugging.  These are not multi-open safe!
++   Note the macros have hardcoded variables in them. */
++
++static char *state2txt(unsigned char state)
++{
++	switch (state) {
++		case BT_STATE_IDLE:		return("IDLE");
++		case BT_STATE_XACTION_START:	return("XACTION");
++		case BT_STATE_WRITE_BYTES:	return("WR_BYTES");
++		case BT_STATE_WRITE_END:	return("WR_END");
++		case BT_STATE_WRITE_CONSUME:	return("WR_CONSUME");
++		case BT_STATE_B2H_WAIT:		return("B2H_WAIT");
++		case BT_STATE_READ_END:		return("RD_END");
++		case BT_STATE_RESET1:		return("RESET1");
++		case BT_STATE_RESET2:		return("RESET2");
++		case BT_STATE_RESET3:		return("RESET3");
++		case BT_STATE_RESTART:		return("RESTART");
++		case BT_STATE_HOSED:		return("HOSED");
++	}
++	return("BAD STATE");
++}
++#define STATE2TXT state2txt(bt->state)
++
++static char *status2txt(unsigned char status, char *buf)
++{
++	strcpy(buf, "[ ");
++	if (status & BT_B_BUSY) strcat(buf, "B_BUSY ");
++	if (status & BT_H_BUSY) strcat(buf, "H_BUSY ");
++	if (status & BT_OEM0) strcat(buf, "OEM0 ");
++	if (status & BT_SMS_ATN) strcat(buf, "SMS ");
++	if (status & BT_B2H_ATN) strcat(buf, "B2H ");
++	if (status & BT_H2B_ATN) strcat(buf, "H2B ");
++	strcat(buf, "]");
++	return buf;
++}
++#define STATUS2TXT(buf) status2txt(status, buf)
++
++/* This will be called from within this module on a hosed condition */
++#define FIRST_SEQ	0
++static unsigned int bt_init_data(struct si_sm_data *bt, struct si_sm_io *io)
++{
++	bt->state = BT_STATE_IDLE;
++	bt->last_state = BT_STATE_IDLE;
++	bt->seq = FIRST_SEQ;
++	bt->io = io;
++	bt->write_count = 0;
++	bt->read_count = 0;
++	bt->error_retries = 0;
++	bt->nonzero_status = 0;
++	bt->truncated = 0;
++	bt->timeout = BT_NORMAL_TIMEOUT;
++	return 3; /* We claim 3 bytes of space; ought to check SPMI table */
++}
++
++static int bt_start_transaction(struct si_sm_data *bt,
++				unsigned char *data, 
++				unsigned int size)
++{
++	unsigned int i;
++
++	if ((size < 2) || (size > IPMI_MAX_MSG_LENGTH)) return -1;
++	
++	if ((bt->state != BT_STATE_IDLE) && (bt->state != BT_STATE_HOSED))
++		return -2;
++	
++	if (bt_debug & BT_DEBUG_MSG) {
++    		printk(KERN_WARNING "+++++++++++++++++++++++++++++++++++++\n");
++		printk(KERN_WARNING "BT: write seq=0x%02X:", bt->seq);
++		for (i = 0; i < size; i ++) printk (" %02x", data[i]);
++		printk("\n");
++	}
++	bt->write_data[0] = size + 1;	/* all data plus seq byte */
++	bt->write_data[1] = *data;	/* NetFn/LUN */
++	bt->write_data[2] = bt->seq;
++	memcpy(bt->write_data + 3, data + 1, size - 1);
++	bt->write_count = size + 2;
++
++	bt->error_retries = 0;
++	bt->nonzero_status = 0;
++	bt->read_count = 0;
++	bt->truncated = 0;
++	bt->state = BT_STATE_XACTION_START;
++	bt->last_state = BT_STATE_IDLE;
++	bt->timeout = BT_NORMAL_TIMEOUT;
++	return 0;
++}
++
++/* After the upper state machine has been told SI_SM_TRANSACTION_COMPLETE 
++   it calls this.  Strip out the length and seq bytes. */
++
++static int bt_get_result(struct si_sm_data *bt,
++			   unsigned char *data, 
++			   unsigned int length)
++{
++	int i, msg_len;
++
++	msg_len = bt->read_count - 2;		/* account for length & seq */
++	/* Always NetFn, Cmd, cCode */
++	if (msg_len < 3 || msg_len > IPMI_MAX_MSG_LENGTH) {
++		printk(KERN_WARNING "BT results: bad msg_len = %d\n", msg_len);
++		data[0] = bt->write_data[1] | 0x4;	/* Kludge a response */
++		data[1] = bt->write_data[3];
++		data[2] = IPMI_ERR_UNSPECIFIED;
++		msg_len = 3;
++	} else {
++		data[0] = bt->read_data[1];
++		data[1] = bt->read_data[3];
++		if (length < msg_len) bt->truncated = 1;
++		if (bt->truncated) {	/* can be set in read_all_bytes() */
++			data[2] = IPMI_ERR_MSG_TRUNCATED;
++			msg_len = 3;
++		} else memcpy(data + 2, bt->read_data + 4, msg_len - 2);
++	
++		if (bt_debug & BT_DEBUG_MSG) {
++			printk (KERN_WARNING "BT: res (raw)");
++			for (i = 0; i < msg_len; i++) printk(" %02x", data[i]);
++			printk ("\n");
++		}
++	}
++	bt->read_count = 0;	/* paranoia */
++	return msg_len;
++}
++
++/* This bit's functionality is optional */
++#define BT_BMC_HWRST	0x80
++
++static void reset_flags(struct si_sm_data *bt)
++{
++	if (BT_STATUS & BT_H_BUSY) BT_CONTROL(BT_H_BUSY);
++	if (BT_STATUS & BT_B_BUSY) BT_CONTROL(BT_B_BUSY);
++	BT_CONTROL(BT_CLR_WR_PTR);
++	BT_CONTROL(BT_SMS_ATN);
++	BT_INTMASK_W(BT_BMC_HWRST);
++#ifdef DEVELOPMENT_ONLY_NOT_FOR_PRODUCTION
++	if (BT_STATUS & BT_B2H_ATN) {
++		int i;
++		BT_CONTROL(BT_H_BUSY);
++		BT_CONTROL(BT_B2H_ATN);
++		BT_CONTROL(BT_CLR_RD_PTR);
++		for (i = 0; i < IPMI_MAX_MSG_LENGTH + 2; i++) BMC2HOST;
++		BT_CONTROL(BT_H_BUSY);
++	}
++#endif
++}
++
++static inline void write_all_bytes(struct si_sm_data *bt)
++{
++	int i;
++
++	if (bt_debug & BT_DEBUG_MSG) {
++    		printk(KERN_WARNING "BT: write %d bytes seq=0x%02X", 
++			bt->write_count, bt->seq);
++		for (i = 0; i < bt->write_count; i++) 
++			printk (" %02x", bt->write_data[i]);
++		printk ("\n");
++	}
++	for (i = 0; i < bt->write_count; i++) HOST2BMC(bt->write_data[i]);
++}
++
++static inline int read_all_bytes(struct si_sm_data *bt)
++{
++	unsigned char i;
++
++	bt->read_data[0] = BMC2HOST;	
++	bt->read_count = bt->read_data[0];
++	if (bt_debug & BT_DEBUG_MSG) 
++    		printk(KERN_WARNING "BT: read %d bytes:", bt->read_count);
++
++	/* minimum: length, NetFn, Seq, Cmd, cCode == 5 total, or 4 more 
++	   following the length byte. */
++	if (bt->read_count < 4 || bt->read_count >= IPMI_MAX_MSG_LENGTH) {
++		if (bt_debug & BT_DEBUG_MSG) 
++			printk("bad length %d\n", bt->read_count);
++		bt->truncated = 1;
++		return 1;	/* let next XACTION START clean it up */
++	}
++	for (i = 1; i <= bt->read_count; i++) bt->read_data[i] = BMC2HOST;	
++	bt->read_count++;	/* account for the length byte */
++
++	if (bt_debug & BT_DEBUG_MSG) {
++	    	for (i = 0; i < bt->read_count; i++) 
++			printk (" %02x", bt->read_data[i]);
++	    	printk ("\n");
++	}
++	if (bt->seq != bt->write_data[2])	/* idiot check */
++		printk(KERN_WARNING "BT: internal error: sequence mismatch\n");
++
++	/* per the spec, the (NetFn, Seq, Cmd) tuples should match */
++	if ((bt->read_data[3] == bt->write_data[3]) &&		/* Cmd */
++        	(bt->read_data[2] == bt->write_data[2]) &&	/* Sequence */
++        	((bt->read_data[1] & 0xF8) == (bt->write_data[1] & 0xF8))) 
++			return 1;
++
++	if (bt_debug & BT_DEBUG_MSG) printk(KERN_WARNING "BT: bad packet: "
++		"want 0x(%02X, %02X, %02X) got (%02X, %02X, %02X)\n", 
++		bt->write_data[1], bt->write_data[2], bt->write_data[3],
++		bt->read_data[1],  bt->read_data[2],  bt->read_data[3]);
++	return 0;
++}
++
++/* Modifies bt->state appropriately, need to get into the bt_event() switch */
++
++static void error_recovery(struct si_sm_data *bt, char *reason)
++{
++	unsigned char status;
++	char buf[40]; /* For getting status */
++
++	bt->timeout = BT_NORMAL_TIMEOUT; /* various places want to retry */
++
++	status = BT_STATUS;
++	printk(KERN_WARNING "BT: %s in %s %s ", reason, STATE2TXT,
++	       STATUS2TXT(buf));
++
++	(bt->error_retries)++;
++	if (bt->error_retries > BT_RETRY_LIMIT) {
++		printk("retry limit (%d) exceeded\n", BT_RETRY_LIMIT);
++		bt->state = BT_STATE_HOSED;
++		if (!bt->nonzero_status)
++			printk(KERN_ERR "IPMI: BT stuck, try power cycle\n");
++		else if (bt->seq == FIRST_SEQ + BT_RETRY_LIMIT) {
++			/* most likely during insmod */
++			printk(KERN_WARNING "IPMI: BT reset (takes 5 secs)\n");
++        		bt->state = BT_STATE_RESET1;
++		}
++	return;
++	}
++
++	/* Sometimes the BMC queues get in an "off-by-one" state...*/
++	if ((bt->state == BT_STATE_B2H_WAIT) && (status & BT_B2H_ATN)) {
++    		printk("retry B2H_WAIT\n");
++		return;
++	}
++    
++	printk("restart command\n");
++	bt->state = BT_STATE_RESTART;
++}
++
++/* Check the status and (possibly) advance the BT state machine.  The
++   default return is SI_SM_CALL_WITH_DELAY. */
++
++static enum si_sm_result bt_event(struct si_sm_data *bt, long time)
++{
++	unsigned char status;
++	char buf[40]; /* For getting status */
++	int i;
++
++	status = BT_STATUS;
++	bt->nonzero_status |= status;
++
++	if ((bt_debug & BT_DEBUG_STATES) && (bt->state != bt->last_state))
++		printk(KERN_WARNING "BT: %s %s TO=%ld - %ld \n",
++			STATE2TXT,
++			STATUS2TXT(buf), 
++			bt->timeout, 
++			time);
++	bt->last_state = bt->state;
++  
++	if (bt->state == BT_STATE_HOSED) return SI_SM_HOSED;
++    
++	if (bt->state != BT_STATE_IDLE) {	/* do timeout test */
++
++		/* Certain states, on error conditions, can lock up a CPU 
++		   because they are effectively in an infinite loop with 
++		   CALL_WITHOUT_DELAY (right back here with time == 0).  
++		   Prevent infinite lockup by ALWAYS decrementing timeout. */
++
++    	/* FIXME: bt_event is sometimes called with time > BT_NORMAL_TIMEOUT
++              (noticed in ipmi_smic_sm.c January 2004) */
++
++		if ((time <= 0) || (time >= BT_NORMAL_TIMEOUT)) time = 100;
++		bt->timeout -= time;
++		if ((bt->timeout < 0) && (bt->state < BT_STATE_RESET1)) {
++			error_recovery(bt, "timed out");
++			return SI_SM_CALL_WITHOUT_DELAY;
++		}
++	}
++
++	switch (bt->state) {
++
++    	case BT_STATE_IDLE:	/* check for asynchronous messages */
++		if (status & BT_SMS_ATN) {
++			BT_CONTROL(BT_SMS_ATN);	/* clear it */
++			return SI_SM_ATTN;
++		}
++		return SI_SM_IDLE;
++
++	case BT_STATE_XACTION_START:
++		if (status & BT_H_BUSY) { 
++			BT_CONTROL(BT_H_BUSY);
++			break;
++		}
++    		if (status & BT_B2H_ATN) break;
++		bt->state = BT_STATE_WRITE_BYTES;
++		return SI_SM_CALL_WITHOUT_DELAY;	/* for logging */
++
++	case BT_STATE_WRITE_BYTES:
++		if (status & (BT_B_BUSY | BT_H2B_ATN)) break;
++		BT_CONTROL(BT_CLR_WR_PTR);
++		write_all_bytes(bt);
++		BT_CONTROL(BT_H2B_ATN);	/* clears too fast to catch? */
++		bt->state = BT_STATE_WRITE_CONSUME;
++		return SI_SM_CALL_WITHOUT_DELAY; /* it MIGHT sail through */
++
++	case BT_STATE_WRITE_CONSUME: /* BMCs usually blow right thru here */
++        	if (status & (BT_H2B_ATN | BT_B_BUSY)) break;
++		bt->state = BT_STATE_B2H_WAIT;
++		/* fall through with status */
++
++	/* Stay in BT_STATE_B2H_WAIT until a packet matches.  However, spinning 
++	   hard here, constantly reading status, seems to hold off the 
++	   generation of B2H_ATN so ALWAYS return CALL_WITH_DELAY. */
++
++	case BT_STATE_B2H_WAIT:
++    		if (!(status & BT_B2H_ATN)) break;
++		
++		/* Assume ordered, uncached writes: no need to wait */
++		if (!(status & BT_H_BUSY)) BT_CONTROL(BT_H_BUSY); /* set */
++		BT_CONTROL(BT_B2H_ATN);		/* clear it, ACK to the BMC */
++		BT_CONTROL(BT_CLR_RD_PTR);	/* reset the queue */
++		i = read_all_bytes(bt);
++		BT_CONTROL(BT_H_BUSY);		/* clear */
++		if (!i) break;			/* Try this state again */
++		bt->state = BT_STATE_READ_END;
++		return SI_SM_CALL_WITHOUT_DELAY;	/* for logging */
++
++    	case BT_STATE_READ_END:
++
++		/* I could wait on BT_H_BUSY to go clear for a truly clean 
++		   exit.  However, this is already done in XACTION_START
++		   and the (possible) extra loop/status/possible wait affects 
++		   performance.  So, as long as it works, just ignore H_BUSY */
++
++#ifdef MAKE_THIS_TRUE_IF_NECESSARY
++
++		if (status & BT_H_BUSY) break;
++#endif
++		bt->seq++;
++		bt->state = BT_STATE_IDLE;
++		return SI_SM_TRANSACTION_COMPLETE;
++
++	case BT_STATE_RESET1:
++    		reset_flags(bt);
++    		bt->timeout = BT_RESET_DELAY;;
++		bt->state = BT_STATE_RESET2;
++		break;
++
++	case BT_STATE_RESET2:		/* Send a soft reset */
++		BT_CONTROL(BT_CLR_WR_PTR);
++		HOST2BMC(3);		/* number of bytes following */
++		HOST2BMC(0x18);		/* NetFn/LUN == Application, LUN 0 */
++		HOST2BMC(42);		/* Sequence number */
++		HOST2BMC(3);		/* Cmd == Soft reset */
++		BT_CONTROL(BT_H2B_ATN);	
++		bt->state = BT_STATE_RESET3;
++		break;
++
++	case BT_STATE_RESET3:
++		if (bt->timeout > 0) return SI_SM_CALL_WITH_DELAY;
++		bt->state = BT_STATE_RESTART;	/* printk in debug modes */
++		break;
++
++	case BT_STATE_RESTART:		/* don't reset retries! */
++		bt->write_data[2] = ++bt->seq;
++		bt->read_count = 0;
++		bt->nonzero_status = 0;
++		bt->timeout = BT_NORMAL_TIMEOUT;
++		bt->state = BT_STATE_XACTION_START;
++		break;
++
++	default:	/* HOSED is supposed to be caught much earlier */
++		error_recovery(bt, "internal logic error");
++		break;
++  	}
++  	return SI_SM_CALL_WITH_DELAY;
++}
++
++static int bt_detect(struct si_sm_data *bt)
++{
++	/* It's impossible for the BT status and interrupt registers to be 
++	   all 1's, (assuming a properly functioning, self-initialized BMC)
++	   but that's what you get from reading a bogus address, so we
++	   test that first.  The calling routine uses negative logic. */
++
++	if ((BT_STATUS == 0xFF) && (BT_INTMASK_R == 0xFF)) return 1;
++	reset_flags(bt);
++	return 0;
++}
++
++static void bt_cleanup(struct si_sm_data *bt)
++{
++}
++
++static int bt_size(void)
++{
++	return sizeof(struct si_sm_data);
++}
++
++struct si_sm_handlers bt_smi_handlers =
++{
++	.version           = IPMI_BT_VERSION,
++	.init_data         = bt_init_data,
++	.start_transaction = bt_start_transaction,
++	.get_result        = bt_get_result,
++	.event             = bt_event,
++	.detect            = bt_detect,
++	.cleanup           = bt_cleanup,
++	.size              = bt_size,
++};
+Index: linux-ipmi/drivers/char/ipmi/ipmi_devintf.c
+===================================================================
+--- linux-ipmi.orig/drivers/char/ipmi/ipmi_devintf.c	2004-08-13 08:05:37.000000000 -0500
++++ linux-ipmi/drivers/char/ipmi/ipmi_devintf.c	2004-08-13 08:06:49.000000000 -0500
+@@ -44,6 +44,8 @@
+ #include <asm/semaphore.h>
+ #include <linux/init.h>
+ 
++#define IPMI_DEVINTF_VERSION "v33"
++
+ struct ipmi_file_private
+ {
+ 	ipmi_user_t          user;
+@@ -53,6 +55,8 @@
+ 	struct fasync_struct *fasync_queue;
+ 	wait_queue_head_t    wait;
+ 	struct semaphore     recv_sem;
++	int                  default_retries;
++	unsigned int         default_retry_time_ms;
+ };
+ 
+ static void file_receive_handler(struct ipmi_recv_msg *msg,
+@@ -105,7 +109,7 @@
+ 
+ static struct ipmi_user_hndl ipmi_hndlrs =
+ {
+-	ipmi_recv_hndl : file_receive_handler
++	.ipmi_recv_hndl	= file_receive_handler,
+ };
+ 
+ static int ipmi_open(struct inode *inode, struct file *file)
+@@ -138,6 +142,10 @@
+ 	priv->fasync_queue = NULL;
+ 	sema_init(&(priv->recv_sem), 1);
+ 
++	/* Use the low-level defaults. */
++	priv->default_retries = -1;
++	priv->default_retry_time_ms = 0;
++
+ 	return 0;
+ }
+ 
+@@ -158,6 +166,63 @@
+ 	return 0;
+ }
+ 
++static int handle_send_req(ipmi_user_t     user,
++			   struct ipmi_req *req,
++			   int             retries,
++			   unsigned int    retry_time_ms)
++{
++	int              rv;
++	struct ipmi_addr addr;
++	unsigned char    *msgdata;
++	
++	if (req->addr_len > sizeof(struct ipmi_addr))
++		return -EINVAL;
++
++	if (copy_from_user(&addr, req->addr, req->addr_len))
++		return -EFAULT;
++
++	msgdata = kmalloc(IPMI_MAX_MSG_LENGTH, GFP_KERNEL);
++	if (!msgdata)
++		return -ENOMEM;
++
++	/* From here out we cannot return, we must jump to "out" for
++	   error exits to free msgdata. */
++
++	rv = ipmi_validate_addr(&addr, req->addr_len);
++	if (rv)
++		goto out;
++
++	if (req->msg.data != NULL) {
++		if (req->msg.data_len > IPMI_MAX_MSG_LENGTH) {
++			rv = -EMSGSIZE;
++			goto out;
++		}
++
++		if (copy_from_user(msgdata,
++				   req->msg.data,
++				   req->msg.data_len))
++		{
++			rv = -EFAULT;
++			goto out;
++		}
++	} else {
++		req->msg.data_len = 0;
++	}
++	req->msg.data = msgdata;
++
++	rv = ipmi_request_settime(user,
++				  &addr,
++				  req->msgid,
++				  &(req->msg),
++				  NULL,
++				  0,
++				  retries,
++				  retry_time_ms);
++ out:
++	kfree(msgdata);
++	return rv;
++}
++
+ static int ipmi_ioctl(struct inode  *inode,
+ 		      struct file   *file,
+ 		      unsigned int  cmd,
+@@ -170,54 +235,33 @@
+ 	{
+ 	case IPMICTL_SEND_COMMAND:
+ 	{
+-		struct ipmi_req    req;
+-		struct ipmi_addr   addr;
+-		unsigned char msgdata[IPMI_MAX_MSG_LENGTH];
++		struct ipmi_req req;
+ 
+ 		if (copy_from_user(&req, (void *) data, sizeof(req))) {
+ 			rv = -EFAULT;
+ 			break;
+ 		}
+ 
+-		if (req.addr_len > sizeof(struct ipmi_addr))
+-		{
+-			rv = -EINVAL;
+-			break;
+-		}
++		rv = handle_send_req(priv->user,
++				     &req,
++				     priv->default_retries,
++				     priv->default_retry_time_ms);
++		break;
++	}
+ 
+-		if (copy_from_user(&addr, req.addr, req.addr_len)) {
+-			rv = -EFAULT;
+-			break;
+-		}
++	case IPMICTL_SEND_COMMAND_SETTIME:
++	{
++		struct ipmi_req_settime req;
+ 
+-		rv = ipmi_validate_addr(&addr, req.addr_len);
+-		if (rv)
++		if (copy_from_user(&req, (void *) data, sizeof(req))) {
++			rv = -EFAULT;
+ 			break;
+-
+-		if (req.msg.data != NULL) {
+-			if (req.msg.data_len > IPMI_MAX_MSG_LENGTH) {
+-				rv = -EMSGSIZE;
+-				break;
+-			}
+-
+-			if (copy_from_user(&msgdata,
+-					   req.msg.data,
+-					   req.msg.data_len))
+-			{
+-				rv = -EFAULT;
+-				break;
+-			}
+-		} else {
+-			req.msg.data_len = 0;
+ 		}
+ 
+-		req.msg.data = msgdata;
+-
+-		rv = ipmi_request(priv->user,
+-				  &addr,
+-				  req.msgid,
+-				  &(req.msg),
+-				  0);
++		rv = handle_send_req(priv->user,
++				     &req.req,
++				     req.retries,
++				     req.retry_time_ms);
+ 		break;
+ 	}
+ 
+@@ -416,7 +460,36 @@
+ 		rv = 0;
+ 		break;
+ 	}
++	case IPMICTL_SET_TIMING_PARMS_CMD:
++	{
++		struct ipmi_timing_parms parms;
++
++		if (copy_from_user(&parms, (void *) data, sizeof(parms))) {
++			rv = -EFAULT;
++			break;
++		}
++
++		priv->default_retries = parms.retries;
++		priv->default_retry_time_ms = parms.retry_time_ms;
++		rv = 0;
++		break;
++	}
++
++	case IPMICTL_GET_TIMING_PARMS_CMD:
++	{
++		struct ipmi_timing_parms parms;
++
++		parms.retries = priv->default_retries;
++		parms.retry_time_ms = priv->default_retry_time_ms;
++
++		if (copy_to_user((void *) data, &parms, sizeof(parms))) {
++			rv = -EFAULT;
++			break;
++		}
+ 
++		rv = 0;
++		break;
++	}
+ 	}
+   
+ 	return rv;
+@@ -424,12 +497,12 @@
+ 
+ 
+ static struct file_operations ipmi_fops = {
+-	owner:   THIS_MODULE,
+-	ioctl:   ipmi_ioctl,
+-	open:    ipmi_open,
+-	release: ipmi_release,
+-	fasync:  ipmi_fasync,
+-	poll:    ipmi_poll
++	.owner		= THIS_MODULE,
++	.ioctl		= ipmi_ioctl,
++	.open		= ipmi_open,
++	.release	= ipmi_release,
++	.fasync		= ipmi_fasync,
++	.poll		= ipmi_poll,
+ };
+ 
+ #define DEVICE_NAME     "ipmidev"
+@@ -468,8 +541,9 @@
+ 
+ static struct ipmi_smi_watcher smi_watcher =
+ {
+-	new_smi  : ipmi_new_smi,
+-	smi_gone : ipmi_smi_gone
++	.owner    = THIS_MODULE,
++	.new_smi  = ipmi_new_smi,
++	.smi_gone = ipmi_smi_gone,
+ };
+ 
+ static __init int init_ipmi_devintf(void)
+@@ -479,6 +553,9 @@
+ 	if (ipmi_major < 0)
+ 		return -EINVAL;
+ 
++	printk(KERN_INFO "ipmi device interface version "
++	       IPMI_DEVINTF_VERSION "\n");
++
+ 	rv = register_chrdev(ipmi_major, DEVICE_NAME, &ipmi_fops);
+ 	if (rv < 0) {
+ 		printk(KERN_ERR "ipmi: can't get major %d\n", ipmi_major);
+@@ -498,9 +575,6 @@
+ 		return rv;
+ 	}
+ 
+-	printk(KERN_INFO "ipmi: device interface at char major %d\n",
+-	       ipmi_major);
+-
+ 	return 0;
+ }
+ module_init(init_ipmi_devintf);
+Index: linux-ipmi/drivers/char/ipmi/ipmi_kcs_intf.c
+===================================================================
+--- linux-ipmi.orig/drivers/char/ipmi/ipmi_kcs_intf.c	2004-08-13 08:05:37.000000000 -0500
++++ linux-ipmi/drivers/char/ipmi/ipmi_kcs_intf.c	2004-08-13 14:05:32.000000000 -0500
+@@ -54,7 +54,7 @@
+ #include <linux/interrupt.h>
+ #include <linux/ipmi_smi.h>
+ #include <asm/io.h>
+-#include "ipmi_kcs_sm.h"
++#include "ipmi_si_sm.h"
+ #include <linux/init.h>
+ 
+ /* Measure times between events in the driver. */
+@@ -87,7 +87,7 @@
+ struct kcs_info
+ {
+ 	ipmi_smi_t          intf;
+-	struct kcs_data     *kcs_sm;
++	struct si_sm_data   *kcs_sm;
+ 	spinlock_t          kcs_lock;
+ 	spinlock_t          msg_lock;
+ 	struct list_head    xmit_msgs;
+@@ -112,8 +112,10 @@
+ 	   out. */
+ 	int                 run_to_completion;
+ 
++	struct si_sm_io     io;
++
+ 	/* The I/O port of a KCS interface. */
+-	int                 port;
++	unsigned int        port;
+ 
+ 	/* zero if no irq; */
+ 	int                 irq;
+@@ -164,7 +166,7 @@
+ 	deliver_recv_msg(kcs_info, msg);
+ }
+ 
+-static enum kcs_result start_next_msg(struct kcs_info *kcs_info)
++static enum si_sm_result start_next_msg(struct kcs_info *kcs_info)
+ {
+ 	int              rv;
+ 	struct list_head *entry = NULL;
+@@ -185,7 +187,7 @@
+ 
+ 	if (!entry) {
+ 		kcs_info->curr_msg = NULL;
+-		rv = KCS_SM_IDLE;
++		rv = SI_SM_IDLE;
+ 	} else {
+ 		int err;
+ 
+@@ -197,14 +199,15 @@
+ 		do_gettimeofday(&t);
+ 		printk("**Start2: %d.%9.9d\n", t.tv_sec, t.tv_usec);
+ #endif
+-		err = start_kcs_transaction(kcs_info->kcs_sm,
+-					   kcs_info->curr_msg->data,
+-					   kcs_info->curr_msg->data_size);
++		err = kcs_smi_handlers.start_transaction(
++		    kcs_info->kcs_sm,
++		    kcs_info->curr_msg->data,
++		    kcs_info->curr_msg->data_size);
+ 		if (err) {
+ 			return_hosed_msg(kcs_info);
+ 		}
+ 
+-		rv = KCS_CALL_WITHOUT_DELAY;
++		rv = SI_SM_CALL_WITHOUT_DELAY;
+ 	}
+ 	spin_unlock(&(kcs_info->msg_lock));
+ 
+@@ -220,7 +223,7 @@
+ 	msg[0] = (IPMI_NETFN_APP_REQUEST << 2);
+ 	msg[1] = IPMI_GET_BMC_GLOBAL_ENABLES_CMD;
+ 
+-	start_kcs_transaction(kcs_info->kcs_sm, msg, 2);
++	kcs_smi_handlers.start_transaction(kcs_info->kcs_sm, msg, 2);
+ 	kcs_info->kcs_state = KCS_ENABLE_INTERRUPTS1;
+ }
+ 
+@@ -233,7 +236,7 @@
+ 	msg[1] = IPMI_CLEAR_MSG_FLAGS_CMD;
+ 	msg[2] = WDT_PRE_TIMEOUT_INT;
+ 
+-	start_kcs_transaction(kcs_info->kcs_sm, msg, 3);
++	kcs_smi_handlers.start_transaction(kcs_info->kcs_sm, msg, 3);
+ 	kcs_info->kcs_state = KCS_CLEARING_FLAGS;
+ }
+ 
+@@ -280,9 +283,10 @@
+ 		kcs_info->curr_msg->data[1] = IPMI_GET_MSG_CMD;
+ 		kcs_info->curr_msg->data_size = 2;
+ 
+-		start_kcs_transaction(kcs_info->kcs_sm,
+-				      kcs_info->curr_msg->data,
+-				      kcs_info->curr_msg->data_size);
++		kcs_smi_handlers.start_transaction(
++		    kcs_info->kcs_sm,
++		    kcs_info->curr_msg->data,
++		    kcs_info->curr_msg->data_size);
+ 		kcs_info->kcs_state = KCS_GETTING_MESSAGES;
+ 	} else if (kcs_info->msg_flags & EVENT_MSG_BUFFER_FULL) {
+ 		/* Events available. */
+@@ -298,9 +302,10 @@
+ 		kcs_info->curr_msg->data[1] = IPMI_READ_EVENT_MSG_BUFFER_CMD;
+ 		kcs_info->curr_msg->data_size = 2;
+ 
+-		start_kcs_transaction(kcs_info->kcs_sm,
+-				      kcs_info->curr_msg->data,
+-				      kcs_info->curr_msg->data_size);
++		kcs_smi_handlers.start_transaction(
++		    kcs_info->kcs_sm,
++		    kcs_info->curr_msg->data,
++		    kcs_info->curr_msg->data_size);
+ 		kcs_info->kcs_state = KCS_GETTING_EVENTS;
+ 	} else {
+ 		kcs_info->kcs_state = KCS_NORMAL;
+@@ -322,9 +327,10 @@
+ 			break;
+ 			
+ 		kcs_info->curr_msg->rsp_size
+-			= kcs_get_result(kcs_info->kcs_sm,
+-					 kcs_info->curr_msg->rsp,
+-					 IPMI_MAX_MSG_LENGTH);
++			= kcs_smi_handlers.get_result(
++			    kcs_info->kcs_sm,
++			    kcs_info->curr_msg->rsp,
++			    IPMI_MAX_MSG_LENGTH);
+ 		
+ 		/* Do this here becase deliver_recv_msg() releases the
+ 		   lock, and a new message can be put in during the
+@@ -340,7 +346,7 @@
+ 		unsigned int  len;
+ 
+ 		/* We got the flags from the KCS, now handle them. */
+-		len = kcs_get_result(kcs_info->kcs_sm, msg, 4);
++		len = kcs_smi_handlers.get_result(kcs_info->kcs_sm, msg, 4);
+ 		if (msg[2] != 0) {
+ 			/* Error fetching flags, just give up for
+ 			   now. */
+@@ -362,7 +368,7 @@
+ 		unsigned char msg[3];
+ 
+ 		/* We cleared the flags. */
+-		kcs_get_result(kcs_info->kcs_sm, msg, 3);
++		kcs_smi_handlers.get_result(kcs_info->kcs_sm, msg, 3);
+ 		if (msg[2] != 0) {
+ 			/* Error clearing flags */
+ 			printk(KERN_WARNING
+@@ -379,9 +385,9 @@
+ 	case KCS_GETTING_EVENTS:
+ 	{
+ 		kcs_info->curr_msg->rsp_size
+-			= kcs_get_result(kcs_info->kcs_sm,
+-					 kcs_info->curr_msg->rsp,
+-					 IPMI_MAX_MSG_LENGTH);
++			= kcs_smi_handlers.get_result(kcs_info->kcs_sm,
++						      kcs_info->curr_msg->rsp,
++						      IPMI_MAX_MSG_LENGTH);
+ 
+ 		/* Do this here becase deliver_recv_msg() releases the
+ 		   lock, and a new message can be put in during the
+@@ -394,19 +400,25 @@
+ 
+ 			/* Take off the event flag. */
+ 			kcs_info->msg_flags &= ~EVENT_MSG_BUFFER_FULL;
++			handle_flags(kcs_info);
+ 		} else {
++			/* Do this before we deliver the message
++			   because delivering the message releases the
++			   lock and something else can mess with the
++			   state. */
++			handle_flags(kcs_info);
++
+ 			deliver_recv_msg(kcs_info, msg);
+ 		}
+-		handle_flags(kcs_info);
+ 		break;
+ 	}
+ 
+ 	case KCS_GETTING_MESSAGES:
+ 	{
+ 		kcs_info->curr_msg->rsp_size
+-			= kcs_get_result(kcs_info->kcs_sm,
+-					 kcs_info->curr_msg->rsp,
+-					 IPMI_MAX_MSG_LENGTH);
++			= kcs_smi_handlers.get_result(kcs_info->kcs_sm,
++						      kcs_info->curr_msg->rsp,
++						      IPMI_MAX_MSG_LENGTH);
+ 
+ 		/* Do this here becase deliver_recv_msg() releases the
+ 		   lock, and a new message can be put in during the
+@@ -419,10 +431,16 @@
+ 
+ 			/* Take off the msg flag. */
+ 			kcs_info->msg_flags &= ~RECEIVE_MSG_AVAIL;
++			handle_flags(kcs_info);
+ 		} else {
++			/* Do this before we deliver the message
++			   because delivering the message releases the
++			   lock and something else can mess with the
++			   state. */
++			handle_flags(kcs_info);
++
+ 			deliver_recv_msg(kcs_info, msg);
+ 		}
+-		handle_flags(kcs_info);
+ 		break;
+ 	}
+ 
+@@ -431,7 +449,7 @@
+ 		unsigned char msg[4];
+ 
+ 		/* We got the flags from the KCS, now handle them. */
+-		kcs_get_result(kcs_info->kcs_sm, msg, 4);
++		kcs_smi_handlers.get_result(kcs_info->kcs_sm, msg, 4);
+ 		if (msg[2] != 0) {
+ 			printk(KERN_WARNING
+ 			       "ipmi_kcs: Could not enable interrupts"
+@@ -441,7 +459,8 @@
+ 			msg[0] = (IPMI_NETFN_APP_REQUEST << 2);
+ 			msg[1] = IPMI_SET_BMC_GLOBAL_ENABLES_CMD;
+ 			msg[2] = msg[3] | 1; /* enable msg queue int */
+-			start_kcs_transaction(kcs_info->kcs_sm, msg,3);
++			kcs_smi_handlers.start_transaction(
++			    kcs_info->kcs_sm, msg,3);
+ 			kcs_info->kcs_state = KCS_ENABLE_INTERRUPTS2;
+ 		}
+ 		break;
+@@ -452,7 +471,7 @@
+ 		unsigned char msg[4];
+ 
+ 		/* We got the flags from the KCS, now handle them. */
+-		kcs_get_result(kcs_info->kcs_sm, msg, 4);
++		kcs_smi_handlers.get_result(kcs_info->kcs_sm, msg, 4);
+ 		if (msg[2] != 0) {
+ 			printk(KERN_WARNING
+ 			       "ipmi_kcs: Could not enable interrupts"
+@@ -466,9 +485,10 @@
+ 
+ /* Called on timeouts and events.  Timeouts should pass the elapsed
+    time, interrupts should pass in zero. */
+-static enum kcs_result kcs_event_handler(struct kcs_info *kcs_info, int time)
++static enum si_sm_result kcs_event_handler(struct kcs_info *kcs_info,
++					   int time)
+ {
+-	enum kcs_result kcs_result;
++	enum si_sm_result kcs_result;
+ 
+  restart:
+ 	/* There used to be a loop here that waited a little while
+@@ -477,32 +497,34 @@
+ 	   range, which is far too long to wait in an interrupt.  So
+ 	   we just run until the state machine tells us something
+ 	   happened or it needs a delay. */
+-	kcs_result = kcs_event(kcs_info->kcs_sm, time);
++	kcs_result = kcs_smi_handlers.event(kcs_info->kcs_sm, time);
+ 	time = 0;
+-	while (kcs_result == KCS_CALL_WITHOUT_DELAY)
++	while (kcs_result == SI_SM_CALL_WITHOUT_DELAY)
+ 	{
+-		kcs_result = kcs_event(kcs_info->kcs_sm, 0);
++		kcs_result = kcs_smi_handlers.event(kcs_info->kcs_sm, 0);
+ 	}
+ 
+-	if (kcs_result == KCS_TRANSACTION_COMPLETE)
++	if (kcs_result == SI_SM_TRANSACTION_COMPLETE)
+ 	{
+ 		handle_transaction_done(kcs_info);
+-		kcs_result = kcs_event(kcs_info->kcs_sm, 0);
++		kcs_result = kcs_smi_handlers.event(kcs_info->kcs_sm, 0);
+ 	}
+-	else if (kcs_result == KCS_SM_HOSED)
++	else if (kcs_result == SI_SM_HOSED)
+ 	{
++		/* Do the before return_hosed_msg, because that
++		   releases the lock. */
++		kcs_info->kcs_state = KCS_NORMAL;
+ 		if (kcs_info->curr_msg != NULL) {
+ 			/* If we were handling a user message, format
+                            a response to send to the upper layer to
+                            tell it about the error. */
+ 			return_hosed_msg(kcs_info);
+ 		}
+-		kcs_result = kcs_event(kcs_info->kcs_sm, 0);
+-		kcs_info->kcs_state = KCS_NORMAL;
++		kcs_result = kcs_smi_handlers.event(kcs_info->kcs_sm, 0);
+ 	}
+ 
+ 	/* We prefer handling attn over new messages. */
+-	if (kcs_result == KCS_ATTN)
++	if (kcs_result == SI_SM_ATTN)
+ 	{
+ 		unsigned char msg[2];
+ 
+@@ -514,19 +536,19 @@
+ 		msg[0] = (IPMI_NETFN_APP_REQUEST << 2);
+ 		msg[1] = IPMI_GET_MSG_FLAGS_CMD;
+ 
+-		start_kcs_transaction(kcs_info->kcs_sm, msg, 2);
++		kcs_smi_handlers.start_transaction(kcs_info->kcs_sm, msg, 2);
+ 		kcs_info->kcs_state = KCS_GETTING_FLAGS;
+ 		goto restart;
+ 	}
+ 
+ 	/* If we are currently idle, try to start the next message. */
+-	if (kcs_result == KCS_SM_IDLE) {
++	if (kcs_result == SI_SM_IDLE) {
+ 		kcs_result = start_next_msg(kcs_info);
+-		if (kcs_result != KCS_SM_IDLE)
++		if (kcs_result != SI_SM_IDLE)
+ 			goto restart;
+         }
+ 
+-	if ((kcs_result == KCS_SM_IDLE)
++	if ((kcs_result == SI_SM_IDLE)
+ 	    && (atomic_read(&kcs_info->req_events)))
+ 	{
+ 		/* We are idle and the upper layer requested that I fetch
+@@ -537,7 +559,7 @@
+ 		msg[0] = (IPMI_NETFN_APP_REQUEST << 2);
+ 		msg[1] = IPMI_GET_MSG_FLAGS_CMD;
+ 
+-		start_kcs_transaction(kcs_info->kcs_sm, msg, 2);
++		kcs_smi_handlers.start_transaction(kcs_info->kcs_sm, msg, 2);
+ 		kcs_info->kcs_state = KCS_GETTING_FLAGS;
+ 		goto restart;
+ 	}
+@@ -549,11 +571,11 @@
+ 		   struct ipmi_smi_msg *msg,
+ 		   int                 priority)
+ {
+-	struct kcs_info *kcs_info = (struct kcs_info *) send_info;
+-	enum kcs_result result;
+-	unsigned long   flags;
++	struct kcs_info    *kcs_info = (struct kcs_info *) send_info;
++	enum si_sm_result  result;
++	unsigned long      flags;
+ #ifdef DEBUG_TIMING
+-	struct timeval t;
++	struct timeval     t;
+ #endif
+ 
+ 	spin_lock_irqsave(&(kcs_info->msg_lock), flags);
+@@ -574,7 +596,7 @@
+ 
+ 		spin_lock_irqsave(&(kcs_info->kcs_lock), flags);
+ 		result = kcs_event_handler(kcs_info, 0);
+-		while (result != KCS_SM_IDLE) {
++		while (result != SI_SM_IDLE) {
+ 			udelay(KCS_SHORT_TIMEOUT_USEC);
+ 			result = kcs_event_handler(kcs_info,
+ 						   KCS_SHORT_TIMEOUT_USEC);
+@@ -602,16 +624,16 @@
+ 
+ static void set_run_to_completion(void *send_info, int i_run_to_completion)
+ {
+-	struct kcs_info *kcs_info = (struct kcs_info *) send_info;
+-	enum kcs_result result;
+-	unsigned long   flags;
++	struct kcs_info    *kcs_info = (struct kcs_info *) send_info;
++	enum si_sm_result  result;
++	unsigned long      flags;
+ 
+ 	spin_lock_irqsave(&(kcs_info->kcs_lock), flags);
+ 
+ 	kcs_info->run_to_completion = i_run_to_completion;
+ 	if (i_run_to_completion) {
+ 		result = kcs_event_handler(kcs_info, 0);
+-		while (result != KCS_SM_IDLE) {
++		while (result != SI_SM_IDLE) {
+ 			udelay(KCS_SHORT_TIMEOUT_USEC);
+ 			result = kcs_event_handler(kcs_info,
+ 						   KCS_SHORT_TIMEOUT_USEC);
+@@ -621,6 +643,13 @@
+ 	spin_unlock_irqrestore(&(kcs_info->kcs_lock), flags);
+ }
+ 
++static void poll(void *send_info)
++{
++	struct kcs_info *kcs_info = (struct kcs_info *) send_info;
++
++	kcs_event_handler(kcs_info, 0);
++}
++
+ static void request_events(void *send_info)
+ {
+ 	struct kcs_info *kcs_info = (struct kcs_info *) send_info;
+@@ -676,13 +705,13 @@
+ 
+ static void kcs_timeout(unsigned long data)
+ {
+-	struct kcs_info *kcs_info = (struct kcs_info *) data;
+-	enum kcs_result kcs_result;
+-	unsigned long   flags;
+-	unsigned long   jiffies_now;
+-	unsigned long   time_diff;
++	struct kcs_info    *kcs_info = (struct kcs_info *) data;
++	enum si_sm_result  kcs_result;
++	unsigned long      flags;
++	unsigned long      jiffies_now;
++	unsigned long      time_diff;
+ #ifdef DEBUG_TIMING
+-	struct timeval t;
++	struct timeval     t;
+ #endif
+ 
+ 	if (kcs_info->stop_operation) {
+@@ -712,7 +741,7 @@
+ 	/* If the state machine asks for a short delay, then shorten
+            the timer timeout. */
+ #ifdef CONFIG_HIGH_RES_TIMERS
+-	if (kcs_result == KCS_CALL_WITH_DELAY) {
++	if (kcs_result == SI_SM_CALL_WITH_DELAY) {
+ 		kcs_info->kcs_timer.sub_expires
+ 			+= usec_to_arch_cycles(KCS_SHORT_TIMEOUT_USEC);
+ 		while (kcs_info->kcs_timer.sub_expires >= cycles_per_jiffies) {
+@@ -725,7 +754,7 @@
+ 	}
+ #else
+ 	/* If requested, take the shortest delay possible */
+-	if (kcs_result == KCS_CALL_WITH_DELAY) {
++	if (kcs_result == SI_SM_CALL_WITH_DELAY) {
+ 		kcs_info->kcs_timer.expires = jiffies + 1;
+ 	} else {
+ 		kcs_info->kcs_timer.expires = jiffies + KCS_TIMEOUT_JIFFIES;
+@@ -764,7 +793,8 @@
+ 	request_events:        request_events,
+ 	new_user:	       new_user,
+ 	user_left:	       user_left,
+-	set_run_to_completion: set_run_to_completion
++	set_run_to_completion: set_run_to_completion,
++	poll:                  poll,
+ };
+ 
+ static unsigned char ipmi_kcs_dev_rev;
+@@ -776,12 +806,13 @@
+ extern int kcs_dbg;
+ static int ipmi_kcs_detect_hardware(unsigned int port,
+ 				    unsigned char *addr,
+-				    struct kcs_data *data)
++				    struct si_sm_data *data)
+ {
+-	unsigned char   msg[2];
+-	unsigned char   resp[IPMI_MAX_MSG_LENGTH];
+-	unsigned long   resp_len;
+-	enum kcs_result kcs_result;
++	unsigned char      msg[2];
++	unsigned char      *resp;
++	unsigned long      resp_len;
++	enum si_sm_result  kcs_result;
++	int                rv = 0;
+ 
+ 	/* It's impossible for the KCS status register to be all 1's,
+ 	   (assuming a properly functioning, self-initialized BMC)
+@@ -794,40 +825,51 @@
+ 		if (readb(addr+1) == 0xff) return -ENODEV; 
+ 	}
+ 
++	resp = kmalloc(IPMI_MAX_MSG_LENGTH, GFP_KERNEL);
++	if (!resp)
++		return -ENOMEM;
++
+ 	/* Do a Get Device ID command, since it comes back with some
+ 	   useful info. */
+ 	msg[0] = IPMI_NETFN_APP_REQUEST << 2;
+ 	msg[1] = IPMI_GET_DEVICE_ID_CMD;
+-	start_kcs_transaction(data, msg, 2);
++	kcs_smi_handlers.start_transaction(data, msg, 2);
+ 	
+-	kcs_result = kcs_event(data, 0);
++	kcs_result = kcs_smi_handlers.event(data, 0);
+ 	for (;;)
+ 	{
+-		if (kcs_result == KCS_CALL_WITH_DELAY) {
+-			udelay(100);
+-			kcs_result = kcs_event(data, 100);
++		if (kcs_result == SI_SM_CALL_WITH_DELAY) {
++			set_current_state(TASK_UNINTERRUPTIBLE);
++			schedule_timeout(1);
++			kcs_result = kcs_smi_handlers.event(data, 100);
+ 		}
+-		else if (kcs_result == KCS_CALL_WITHOUT_DELAY)
++		else if (kcs_result == SI_SM_CALL_WITHOUT_DELAY)
+ 		{
+-			kcs_result = kcs_event(data, 0);
++			kcs_result = kcs_smi_handlers.event(data, 0);
+ 		}
+ 		else
+ 			break;
+ 	}
+-	if (kcs_result == KCS_SM_HOSED) {
++	if (kcs_result == SI_SM_HOSED) {
+ 		/* We couldn't get the state machine to run, so whatever's at
+ 		   the port is probably not an IPMI KCS interface. */
+-		return -ENODEV;
++		rv = -ENODEV;
++		goto out;
+ 	}
+ 	/* Otherwise, we got some data. */
+-	resp_len = kcs_get_result(data, resp, IPMI_MAX_MSG_LENGTH);
+-	if (resp_len < 6)
++	resp_len = kcs_smi_handlers.get_result(data, resp,
++					       IPMI_MAX_MSG_LENGTH);
++	if (resp_len < 6) {
+ 		/* That's odd, it should be longer. */
+-		return -EINVAL;
++		rv = -EINVAL;
++		goto out;
++	}
+ 	
+-	if ((resp[1] != IPMI_GET_DEVICE_ID_CMD) || (resp[2] != 0))
++	if ((resp[1] != IPMI_GET_DEVICE_ID_CMD) || (resp[2] != 0)) {
+ 		/* That's odd, it shouldn't be able to fail. */
+-		return -EINVAL;
++		rv = -EINVAL;
++		goto out;
++	}
+ 	
+ 	ipmi_kcs_dev_rev = resp[4] & 0xf;
+ 	ipmi_kcs_fw_rev_major = resp[5] & 0x7f;
+@@ -835,7 +877,9 @@
+ 	ipmi_version_major = resp[7] & 0xf;
+ 	ipmi_version_minor = resp[7] >> 4;
+ 
+-	return 0;
++ out:
++	kfree(resp);
++	return rv;
+ }
+ 
+ /* There can be 4 IO ports passed in (with or without IRQs), 4 addresses,
+@@ -860,6 +904,36 @@
+ MODULE_PARM(kcs_irqs, "1-4i");
+ MODULE_PARM(kcs_ports, "1-4i");
+ 
++static unsigned char port_inb(struct si_sm_io *io, unsigned int offset)
++{
++	struct kcs_info *info = io->info;
++
++	return inb(info->port+offset);
++}
++
++static void port_outb(struct si_sm_io *io, unsigned int offset,
++		      unsigned char b)
++{
++	struct kcs_info *info = io->info;
++
++	outb(b, info->port+offset);
++}
++
++static unsigned char mem_inb(struct si_sm_io *io, unsigned int offset)
++{
++	struct kcs_info *info = io->info;
++
++	return readb(info->addr+offset);
++}
++
++static void mem_outb(struct si_sm_io *io, unsigned int offset,
++		     unsigned char b)
++{
++	struct kcs_info *info = io->info;
++
++	writeb(b, info->addr+offset);
++}
++
+ /* Returns 0 if initialized, or negative on an error. */
+ static int init_one_kcs(int kcs_port, 
+ 			int irq, 
+@@ -902,6 +976,9 @@
+ 		       	       kcs_port);
+ 			return -EIO;
+ 		}
++		new_kcs->io.outputb = port_outb;
++		new_kcs->io.inputb = port_inb;
++		new_kcs->io.info = new_kcs;
+ 	} else {
+ 		if (request_mem_region(kcs_physaddr, 2, DEVICE_NAME) == NULL) {
+ 			kfree(new_kcs);
+@@ -917,15 +994,18 @@
+ 		       	       kcs_physaddr);
+ 			return -EIO;
+ 		}
++		new_kcs->io.outputb = mem_outb;
++		new_kcs->io.inputb = mem_inb;
++		new_kcs->io.info = new_kcs;
+ 	}
+ 
+-	new_kcs->kcs_sm = kmalloc(kcs_size(), GFP_KERNEL);
++	new_kcs->kcs_sm = kmalloc(kcs_smi_handlers.size(), GFP_KERNEL);
+ 	if (!new_kcs->kcs_sm) {
+ 		printk(KERN_ERR "ipmi_kcs: out of memory\n");
+ 		rv = -ENOMEM;
+ 		goto out_err;
+ 	}
+-	init_kcs_data(new_kcs->kcs_sm, kcs_port, new_kcs->addr);
++	kcs_smi_handlers.init_data(new_kcs->kcs_sm, &(new_kcs->io));
+ 	spin_lock_init(&(new_kcs->kcs_lock));
+ 	spin_lock_init(&(new_kcs->msg_lock));
+ 
+@@ -984,19 +1064,6 @@
+ 		       	       kcs_physaddr);
+ 	}
+ 
+-	rv = ipmi_register_smi(&handlers,
+-			       new_kcs,
+-			       ipmi_version_major,
+-			       ipmi_version_minor,
+-			       &(new_kcs->intf));
+-	if (rv) {
+-		free_irq(irq, new_kcs);
+-		printk(KERN_ERR 
+-		       "ipmi_kcs: Unable to register device: error %d\n",
+-		       rv);
+-		goto out_err;
+-	}
+-
+ 	new_kcs->interrupt_disabled = 0;
+ 	new_kcs->timer_stopped = 0;
+ 	new_kcs->stop_operation = 0;
+@@ -1010,6 +1077,19 @@
+ 
+ 	*kcs = new_kcs;
+ 
++	rv = ipmi_register_smi(&handlers,
++			       new_kcs,
++			       ipmi_version_major,
++			       ipmi_version_minor,
++			       &(new_kcs->intf));
++	if (rv) {
++		free_irq(irq, new_kcs);
++		printk(KERN_ERR 
++		       "ipmi_kcs: Unable to register device: error %d\n",
++		       rv);
++		goto out_err;
++	}
++
+ 	return 0;
+ 
+  out_err:
+@@ -1027,11 +1107,7 @@
+ 
+ #ifdef CONFIG_ACPI_INTERPRETER
+ 
+-/* Retrieve the base physical address from ACPI tables.  Originally
+-   from Hewlett-Packard simple bmc.c, a GPL KCS driver. */
+-
+ #include <linux/acpi.h>
+-/* A real hack, but everything's not there yet in 2.4. */
+ #include <acpi/acpi.h>
+ #include <acpi/actypes.h>
+ #include <acpi/actbl.h>
+@@ -1046,37 +1122,69 @@
+ 	s8	OEMRevision[4];
+ 	s8	CreatorID[4];
+ 	s8	CreatorRevision[4];
+-	s16	InterfaceType;
++	u8	InterfaceType[2];
+ 	s16	SpecificationRevision;
++
++	/*
++	 * Bit 0 - SCI interrupt supported
++	 * Bit 1 - I/O APIC/SAPIC
++	 */
+ 	u8	InterruptType;
++
++	/* If bit 0 of InterruptType is set, then this is the SCI
++           interrupt in the GPEx_STS register. */
+ 	u8	GPE;
++
+ 	s16	Reserved;
+-	u64	GlobalSystemInterrupt;
+-	u8	BaseAddress[12];
++
++	/* If bit 1 of InterruptType is set, then this is the I/O
++           APIC/SAPIC interrupt. */
++	u32	GlobalSystemInterrupt;
++
++	/* The actual register address. */
++	struct acpi_generic_address addr;
++
+ 	u8	UID[4];
+-} __attribute__ ((packed));
+ 
+-static unsigned long acpi_find_bmc(void)
++	s8      spmi_id[1]; /* A '\0' terminated array starts here. */
++};
++
++static int acpi_find_bmc(unsigned long *physaddr, int *port)
+ {
+ 	acpi_status       status;
+-	struct acpi_table_header *spmi;
+-	static unsigned long io_base = 0;
+-
+-	if (io_base != 0)
+-		return io_base;
++	struct SPMITable  *spmi;
+ 
+ 	status = acpi_get_firmware_table("SPMI", 1,
+-			ACPI_LOGICAL_ADDRESSING, &spmi);
++					 ACPI_LOGICAL_ADDRESSING,
++					 (struct acpi_table_header **) &spmi);
++	if (status != AE_OK)
++		goto not_found;
++
++	if (spmi->InterfaceType[0] != 1)
++		/* Not IPMI. */
++		goto not_found;
++
++	if (spmi->InterfaceType[1] != 1)
++		/* Not KCS. */
++		goto not_found;
++
++	if (spmi->addr.address_space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) {
++		*physaddr = spmi->addr.address;
++		printk("ipmi_kcs_intf: Found ACPI-specified state machine"
++		       " at memory address 0x%lx\n",
++		       (unsigned long) spmi->addr.address);
++	} else if (spmi->addr.address_space_id == ACPI_ADR_SPACE_SYSTEM_IO) {
++		*port = spmi->addr.address;
++		printk("ipmi_kcs_intf: Found ACPI-specified state machine"
++		       " at I/O address 0x%x\n",
++		       (int) spmi->addr.address);
++	} else
++		goto not_found; /* Not an address type we recognise. */
+ 
+-	if (status != AE_OK) {
+-		printk(KERN_ERR "ipmi_kcs: SPMI table not found.\n");
+-		return 0;
+-	}
++	return 0;
+ 
+-	memcpy(&io_base, ((struct SPMITable *)spmi)->BaseAddress,
+-			sizeof(io_base));
+-	
+-	return io_base;
++ not_found:
++	return -ENODEV;
+ }
+ #endif
+ 
+@@ -1087,6 +1195,7 @@
+ 	int		i = 0;
+ #ifdef CONFIG_ACPI_INTERPRETER
+ 	unsigned long	physaddr = 0;
++	int             port = 0;
+ #endif
+ 
+ 	if (initialized)
+@@ -1114,26 +1223,25 @@
+ 	/* Only try the defaults if enabled and resources are available
+ 	   (because they weren't already specified above). */
+ 
+-	if (kcs_trydefaults) {
++	if (kcs_trydefaults && (pos == 0)) {
++		rv = -EINVAL;
+ #ifdef CONFIG_ACPI_INTERPRETER
+-		if ((physaddr = acpi_find_bmc())) {
+-			if (!check_mem_region(physaddr, 2)) {
+-				rv = init_one_kcs(0, 
+-						  0, 
+-						  physaddr, 
+-						  &(kcs_infos[pos]));
+-				if (rv == 0)
+-					pos++;
+-			}
++		if (rv && (acpi_find_bmc(&physaddr, &port) == 0)) {
++			rv = init_one_kcs(port, 
++					  0, 
++					  physaddr, 
++					  &(kcs_infos[pos]));
++			if (rv == 0)
++				pos++;
+ 		}
+ #endif
+-		if (!check_region(DEFAULT_IO_PORT, 2)) {
++		if (rv) {
+ 			rv = init_one_kcs(DEFAULT_IO_PORT, 
+ 					  0, 
+ 					  0, 
+ 					  &(kcs_infos[pos]));
+ 			if (rv == 0)
+-				pos++;
++			    pos++;
+ 		}
+ 	}
+ 
+@@ -1185,8 +1293,10 @@
+ 	   conditions removing the timer here.  Hopefully this will be
+ 	   long enough to avoid problems with interrupts still
+ 	   running. */
++	set_current_state(TASK_UNINTERRUPTIBLE);
+ 	schedule_timeout(2);
+ 	while (!to_clean->timer_stopped) {
++		set_current_state(TASK_UNINTERRUPTIBLE);
+ 		schedule_timeout(1);
+ 	}
+ 
+Index: linux-ipmi/drivers/char/ipmi/ipmi_kcs_sm.c
+===================================================================
+--- linux-ipmi.orig/drivers/char/ipmi/ipmi_kcs_sm.c	2004-08-13 08:05:37.000000000 -0500
++++ linux-ipmi/drivers/char/ipmi/ipmi_kcs_sm.c	2004-08-13 08:06:49.000000000 -0500
+@@ -37,10 +37,12 @@
+  * that document.
+  */
+ 
+-#include <asm/io.h>
+-#include <asm/string.h>		/* Gets rid of memcpy warning */
++#include <linux/kernel.h> /* For printk. */
++#include <linux/string.h>
++#include <linux/ipmi_msgdefs.h>		/* for completion codes */
++#include "ipmi_si_sm.h"
+ 
+-#include "ipmi_kcs_sm.h"
++#define IPMI_KCS_VERSION "v33"
+ 
+ /* Set this if you want a printout of why the state machine was hosed
+    when it gets hosed. */
+@@ -92,32 +94,28 @@
+ #define OBF_RETRY_TIMEOUT 1000000
+ #define MAX_ERROR_RETRIES 10
+ 
+-#define IPMI_ERR_MSG_TRUNCATED	0xc6
+-#define IPMI_ERR_UNSPECIFIED	0xff
+-
+-struct kcs_data
++struct si_sm_data
+ {
+-	enum kcs_states state;
+-	unsigned int    port;
+-	unsigned char	*addr;
+-	unsigned char   write_data[MAX_KCS_WRITE_SIZE];
+-	int             write_pos;
+-	int             write_count;
+-	int             orig_write_count;
+-	unsigned char   read_data[MAX_KCS_READ_SIZE];
+-	int             read_pos;
+-	int	        truncated;
++	enum kcs_states  state;
++	struct si_sm_io *io;
++	unsigned char    write_data[MAX_KCS_WRITE_SIZE];
++	int              write_pos;
++	int              write_count;
++	int              orig_write_count;
++	unsigned char    read_data[MAX_KCS_READ_SIZE];
++	int              read_pos;
++	int	         truncated;
+ 
+ 	unsigned int  error_retries;
+ 	long          ibf_timeout;
+ 	long          obf_timeout;
+ };
+ 
+-void init_kcs_data(struct kcs_data *kcs, unsigned int port, unsigned char *addr)
++static unsigned int init_kcs_data(struct si_sm_data *kcs,
++				  struct si_sm_io *io)
+ {
+ 	kcs->state = KCS_IDLE;
+-	kcs->port = port;
+-	kcs->addr = addr;
++	kcs->io = io;
+ 	kcs->write_pos = 0;
+ 	kcs->write_count = 0;
+ 	kcs->orig_write_count = 0;
+@@ -126,40 +124,29 @@
+ 	kcs->truncated = 0;
+ 	kcs->ibf_timeout = IBF_RETRY_TIMEOUT;
+ 	kcs->obf_timeout = OBF_RETRY_TIMEOUT;
+-}
+ 
+-/* Remember, init_one_kcs() insured port and addr can't both be set */
++	/* Reserve 2 I/O bytes. */
++	return 2;
++}
+ 
+-static inline unsigned char read_status(struct kcs_data *kcs)
++static inline unsigned char read_status(struct si_sm_data *kcs)
+ {
+-        if (kcs->port)
+-		return inb(kcs->port + 1);
+-        else
+-		return readb(kcs->addr + 1);
++	return kcs->io->inputb(kcs->io, 1);
+ }
+ 
+-static inline unsigned char read_data(struct kcs_data *kcs)
++static inline unsigned char read_data(struct si_sm_data *kcs)
+ {
+-        if (kcs->port)
+-		return inb(kcs->port + 0);
+-        else
+-		return readb(kcs->addr + 0);
++	return kcs->io->inputb(kcs->io, 0);
+ }
+ 
+-static inline void write_cmd(struct kcs_data *kcs, unsigned char data)
++static inline void write_cmd(struct si_sm_data *kcs, unsigned char data)
+ {
+-        if (kcs->port)
+-		outb(data, kcs->port + 1);
+-        else
+-		writeb(data, kcs->addr + 1);
++	kcs->io->outputb(kcs->io, 1, data);
+ }
+ 
+-static inline void write_data(struct kcs_data *kcs, unsigned char data)
++static inline void write_data(struct si_sm_data *kcs, unsigned char data)
+ {
+-        if (kcs->port)
+-		outb(data, kcs->port + 0);
+-        else
+-		writeb(data, kcs->addr + 0);
++	kcs->io->outputb(kcs->io, 0, data);
+ }
+ 
+ /* Control codes. */
+@@ -179,14 +166,14 @@
+ #define GET_STATUS_OBF(status) ((status) & 0x01)
+ 
+ 
+-static inline void write_next_byte(struct kcs_data *kcs)
++static inline void write_next_byte(struct si_sm_data *kcs)
+ {
+ 	write_data(kcs, kcs->write_data[kcs->write_pos]);
+ 	(kcs->write_pos)++;
+ 	(kcs->write_count)--;
+ }
+ 
+-static inline void start_error_recovery(struct kcs_data *kcs, char *reason)
++static inline void start_error_recovery(struct si_sm_data *kcs, char *reason)
+ {
+ 	(kcs->error_retries)++;
+ 	if (kcs->error_retries > MAX_ERROR_RETRIES) {
+@@ -199,7 +186,7 @@
+ 	}
+ }
+ 
+-static inline void read_next_byte(struct kcs_data *kcs)
++static inline void read_next_byte(struct si_sm_data *kcs)
+ {
+ 	if (kcs->read_pos >= MAX_KCS_READ_SIZE) {
+ 		/* Throw the data away and mark it truncated. */
+@@ -212,9 +199,8 @@
+ 	write_data(kcs, KCS_READ_BYTE);
+ }
+ 
+-static inline int check_ibf(struct kcs_data *kcs,
+-			    unsigned char   status,
+-			    long            time)
++static inline int check_ibf(struct si_sm_data *kcs, unsigned char status,
++			    long time)
+ {
+ 	if (GET_STATUS_IBF(status)) {
+ 		kcs->ibf_timeout -= time;
+@@ -229,9 +215,8 @@
+ 	return 1;
+ }
+ 
+-static inline int check_obf(struct kcs_data *kcs,
+-			    unsigned char   status,
+-			    long            time)
++static inline int check_obf(struct si_sm_data *kcs, unsigned char status,
++			    long time)
+ {
+ 	if (! GET_STATUS_OBF(status)) {
+ 		kcs->obf_timeout -= time;
+@@ -245,13 +230,13 @@
+ 	return 1;
+ }
+ 
+-static void clear_obf(struct kcs_data *kcs, unsigned char status)
++static void clear_obf(struct si_sm_data *kcs, unsigned char status)
+ {
+ 	if (GET_STATUS_OBF(status))
+ 		read_data(kcs);
+ }
+ 
+-static void restart_kcs_transaction(struct kcs_data *kcs)
++static void restart_kcs_transaction(struct si_sm_data *kcs)
+ {
+ 	kcs->write_count = kcs->orig_write_count;
+ 	kcs->write_pos = 0;
+@@ -262,7 +247,8 @@
+ 	write_cmd(kcs, KCS_WRITE_START);
+ }
+ 
+-int start_kcs_transaction(struct kcs_data *kcs, char *data, unsigned int size)
++static int start_kcs_transaction(struct si_sm_data *kcs, unsigned char *data,
++				 unsigned int size)
+ {
+ 	if ((size < 2) || (size > MAX_KCS_WRITE_SIZE)) {
+ 		return -1;
+@@ -284,7 +270,8 @@
+ 	return 0;
+ }
+ 
+-int kcs_get_result(struct kcs_data *kcs, unsigned char *data, int length)
++static int get_kcs_result(struct si_sm_data *kcs, unsigned char *data,
++			  unsigned int length)
+ {
+ 	if (length < kcs->read_pos) {
+ 		kcs->read_pos = length;
+@@ -313,7 +300,7 @@
+ /* This implements the state machine defined in the IPMI manual, see
+    that for details on how this works.  Divide that flowchart into
+    sections delimited by "Wait for IBF" and this will become clear. */
+-enum kcs_result kcs_event(struct kcs_data *kcs, long time)
++static enum si_sm_result kcs_event(struct si_sm_data *kcs, long time)
+ {
+ 	unsigned char status;
+ 	unsigned char state;
+@@ -325,7 +312,7 @@
+ #endif
+ 	/* All states wait for ibf, so just do it here. */
+ 	if (!check_ibf(kcs, status, time))
+-		return KCS_CALL_WITH_DELAY;
++		return SI_SM_CALL_WITH_DELAY;
+ 
+ 	/* Just about everything looks at the KCS state, so grab that, too. */
+ 	state = GET_STATUS_STATE(status);
+@@ -336,9 +323,9 @@
+ 		clear_obf(kcs, status);
+ 
+ 		if (GET_STATUS_ATN(status))
+-			return KCS_ATTN;
++			return SI_SM_ATTN;
+ 		else
+-			return KCS_SM_IDLE;
++			return SI_SM_IDLE;
+ 
+ 	case KCS_START_OP:
+ 		if (state != KCS_IDLE) {
+@@ -405,7 +392,7 @@
+ 
+ 		if (state == KCS_READ_STATE) {
+ 			if (! check_obf(kcs, status, time))
+-				return KCS_CALL_WITH_DELAY;
++				return SI_SM_CALL_WITH_DELAY;
+ 			read_next_byte(kcs);
+ 		} else {
+ 			/* We don't implement this exactly like the state
+@@ -418,7 +405,7 @@
+ 			clear_obf(kcs, status);
+ 			kcs->orig_write_count = 0;
+ 			kcs->state = KCS_IDLE;
+-			return KCS_TRANSACTION_COMPLETE;
++			return SI_SM_TRANSACTION_COMPLETE;
+ 		}
+ 		break;
+ 
+@@ -441,7 +428,7 @@
+ 			break;
+ 		}
+ 		if (! check_obf(kcs, status, time))
+-			return KCS_CALL_WITH_DELAY;
++			return SI_SM_CALL_WITH_DELAY;
+ 
+ 		clear_obf(kcs, status);
+ 		write_data(kcs, KCS_READ_BYTE);
+@@ -456,14 +443,14 @@
+ 		}
+ 
+ 		if (! check_obf(kcs, status, time))
+-			return KCS_CALL_WITH_DELAY;
++			return SI_SM_CALL_WITH_DELAY;
+ 
+ 		clear_obf(kcs, status);
+ 		if (kcs->orig_write_count) {
+ 			restart_kcs_transaction(kcs);
+ 		} else {
+ 			kcs->state = KCS_IDLE;
+-			return KCS_TRANSACTION_COMPLETE;
++			return SI_SM_TRANSACTION_COMPLETE;
+ 		}
+ 		break;
+ 			
+@@ -472,14 +459,42 @@
+ 	}
+ 
+ 	if (kcs->state == KCS_HOSED) {
+-		init_kcs_data(kcs, kcs->port, kcs->addr);
+-		return KCS_SM_HOSED;
++		init_kcs_data(kcs, kcs->io);
++		return SI_SM_HOSED;
+ 	}
+ 
+-	return KCS_CALL_WITHOUT_DELAY;
++	return SI_SM_CALL_WITHOUT_DELAY;
++}
++
++static int kcs_size(void)
++{
++	return sizeof(struct si_sm_data);
++}
++
++static int kcs_detect(struct si_sm_data *kcs)
++{
++	/* It's impossible for the KCS status register to be all 1's,
++	   (assuming a properly functioning, self-initialized BMC)
++	   but that's what you get from reading a bogus address, so we
++	   test that first. */
++	if (read_status(kcs) == 0xff)
++		return 1; 
++
++	return 0;
+ }
+ 
+-int kcs_size(void)
++static void kcs_cleanup(struct si_sm_data *kcs)
+ {
+-	return sizeof(struct kcs_data);
+ }
++
++struct si_sm_handlers kcs_smi_handlers =
++{
++	.version           = IPMI_KCS_VERSION,
++	.init_data         = init_kcs_data,
++	.start_transaction = start_kcs_transaction,
++	.get_result        = get_kcs_result,
++	.event             = kcs_event,
++	.detect            = kcs_detect,
++	.cleanup           = kcs_cleanup,
++	.size              = kcs_size,
++};
+Index: linux-ipmi/drivers/char/ipmi/ipmi_kcs_sm.h
+===================================================================
+--- linux-ipmi.orig/drivers/char/ipmi/ipmi_kcs_sm.h	2004-08-13 08:05:37.000000000 -0500
++++ linux-ipmi/drivers/char/ipmi/ipmi_kcs_sm.h	1969-12-31 18:00:00.000000000 -0600
+@@ -1,70 +0,0 @@
+-/*
+- * ipmi_kcs_sm.h
+- *
+- * State machine for handling IPMI KCS interfaces.
+- *
+- * Author: MontaVista Software, Inc.
+- *         Corey Minyard <minyard@mvista.com>
+- *         source@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.
+- *
+- *
+- *  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.
+- */
+-
+-struct kcs_data;
+-
+-void init_kcs_data(struct kcs_data *kcs,
+-		   unsigned int    port,
+-		   unsigned char   *addr);
+-
+-/* Start a new transaction in the state machine.  This will return -2
+-   if the state machine is not idle, -1 if the size is invalid (to
+-   large or too small), or 0 if the transaction is successfully
+-   completed. */
+-int start_kcs_transaction(struct kcs_data *kcs, char *data, unsigned int size);
+-
+-/* Return the results after the transaction.  This will return -1 if
+-   the buffer is too small, zero if no transaction is present, or the
+-   actual length of the result data. */
+-int kcs_get_result(struct kcs_data *kcs, unsigned char *data, int length);
+-
+-enum kcs_result
+-{
+-	KCS_CALL_WITHOUT_DELAY, /* Call the driver again immediately */
+-	KCS_CALL_WITH_DELAY,	/* Delay some before calling again. */
+-	KCS_TRANSACTION_COMPLETE, /* A transaction is finished. */
+-	KCS_SM_IDLE,		/* The SM is in idle state. */
+-	KCS_SM_HOSED,		/* The hardware violated the state machine. */
+-	KCS_ATTN		/* The hardware is asserting attn and the
+-				   state machine is idle. */
+-};
+-
+-/* Call this periodically (for a polled interface) or upon receiving
+-   an interrupt (for a interrupt-driven interface).  If interrupt
+-   driven, you should probably poll this periodically when not in idle
+-   state.  This should be called with the time that passed since the
+-   last call, if it is significant.  Time is in microseconds. */
+-enum kcs_result kcs_event(struct kcs_data *kcs, long time);
+-
+-/* Return the size of the KCS structure in bytes. */
+-int kcs_size(void);
+Index: linux-ipmi/drivers/char/ipmi/ipmi_msghandler.c
+===================================================================
+--- linux-ipmi.orig/drivers/char/ipmi/ipmi_msghandler.c	2004-08-13 08:05:37.000000000 -0500
++++ linux-ipmi/drivers/char/ipmi/ipmi_msghandler.c	2004-08-13 08:06:49.000000000 -0500
+@@ -44,16 +44,31 @@
+ #include <linux/ipmi_smi.h>
+ #include <linux/notifier.h>
+ #include <linux/init.h>
++#include <linux/proc_fs.h>
++
++#define PFX "IPMI message handler: "
++#define IPMI_MSGHANDLER_VERSION "v33"
++
++/* This is a mighty handy macro backported from 2.6. */
++#ifndef list_for_each_entry_safe
++#define list_for_each_entry_safe(pos, n, head, member)			\
++	for (pos = list_entry((head)->next, typeof(*pos), member),	\
++		n = list_entry(pos->member.next, typeof(*pos), member);	\
++	     &pos->member != (head); 					\
++	     pos = n, n = list_entry(n->member.next, typeof(*n), member))
++#endif
+ 
+ struct ipmi_recv_msg *ipmi_alloc_recv_msg(void);
+ static int ipmi_init_msghandler(void);
+ 
+ static int initialized = 0;
+ 
++static struct proc_dir_entry *proc_ipmi_root = NULL;
++
+ #define MAX_EVENTS_IN_QUEUE	25
+ 
+ /* Don't let a message sit in a queue forever, always time it with at lest
+-   the max message timer. */
++   the max message timer.  This is in milliseconds. */
+ #define MAX_MSG_TIMEOUT		60000
+ 
+ struct ipmi_user
+@@ -82,7 +97,8 @@
+ 
+ struct seq_table
+ {
+-	int                  inuse : 1;
++	unsigned int         inuse : 1;
++	unsigned int         broadcast : 1;
+ 
+ 	unsigned long        timeout;
+ 	unsigned long        orig_timeout;
+@@ -111,10 +127,19 @@
+ 
+ #define NEXT_SEQID(seqid) (((seqid) + 1) & 0x3fffff)
+ 
++struct ipmi_channel
++{
++	unsigned char medium;
++	unsigned char protocol;
++};
+ 
+ #define IPMI_IPMB_NUM_SEQ	64
++#define IPMI_MAX_CHANNELS       8
+ struct ipmi_smi
+ {
++	/* What interface number are we? */
++	int intf_num;
++
+ 	/* The list of upper layers that are using me.  We read-lock
+            this when delivering messages to the upper layer to keep
+            the user from going away while we are processing the
+@@ -123,6 +148,9 @@
+ 	rwlock_t                users_lock;
+ 	struct list_head        users;
+ 
++	/* Used for wake ups at startup. */
++	wait_queue_head_t waitq;
++
+ 	/* The IPMI version of the BMC on the other end. */
+ 	unsigned char       version_major;
+ 	unsigned char       version_minor;
+@@ -169,6 +197,99 @@
+ 	/* My LUN.  This should generally stay the SMS LUN, but just in
+ 	   case... */
+ 	unsigned char my_lun;
++
++	/* The event receiver for my BMC, only really used at panic
++	   shutdown as a place to store this. */
++	unsigned char event_receiver;
++	unsigned char event_receiver_lun;
++	unsigned char local_sel_device;
++	unsigned char local_event_generator;
++
++	/* A cheap hack, if this is non-null and a message to an
++	   interface comes in with a NULL user, call this routine with
++	   it.  Note that the message will still be freed by the
++	   caller.  This only works on the system interface. */
++	void (*null_user_handler)(ipmi_smi_t intf, struct ipmi_smi_msg *msg);
++
++	/* When we are scanning the channels for an SMI, this will
++	   tell which channel we are scanning. */
++	int curr_channel;
++
++	/* Channel information */
++	struct ipmi_channel channels[IPMI_MAX_CHANNELS];
++
++	/* Proc FS stuff. */
++	struct proc_dir_entry *proc_dir;
++	char                  proc_dir_name[10];
++
++	spinlock_t   counter_lock; /* For making counters atomic. */
++
++	/* Commands we got that were invalid. */
++	unsigned int sent_invalid_commands;
++
++	/* Commands we sent to the MC. */
++	unsigned int sent_local_commands;
++	/* Responses from the MC that were delivered to a user. */
++	unsigned int handled_local_responses;
++	/* Responses from the MC that were not delivered to a user. */
++	unsigned int unhandled_local_responses;
++
++	/* Commands we sent out to the IPMB bus. */
++	unsigned int sent_ipmb_commands;
++	/* Commands sent on the IPMB that had errors on the SEND CMD */
++	unsigned int sent_ipmb_command_errs;
++	/* Each retransmit increments this count. */
++	unsigned int retransmitted_ipmb_commands;
++	/* When a message times out (runs out of retransmits) this is
++           incremented. */
++	unsigned int timed_out_ipmb_commands;
++
++	/* This is like above, but for broadcasts.  Broadcasts are
++           *not* included in the above count (they are expected to
++           time out). */
++	unsigned int timed_out_ipmb_broadcasts;
++
++	/* Responses I have sent to the IPMB bus. */
++	unsigned int sent_ipmb_responses;
++
++	/* The response was delivered to the user. */
++	unsigned int handled_ipmb_responses;
++	/* The response had invalid data in it. */
++	unsigned int invalid_ipmb_responses;
++	/* The response didn't have anyone waiting for it. */
++	unsigned int unhandled_ipmb_responses;
++
++	/* Commands we sent out to the IPMB bus. */
++	unsigned int sent_lan_commands;
++	/* Commands sent on the IPMB that had errors on the SEND CMD */
++	unsigned int sent_lan_command_errs;
++	/* Each retransmit increments this count. */
++	unsigned int retransmitted_lan_commands;
++	/* When a message times out (runs out of retransmits) this is
++           incremented. */
++	unsigned int timed_out_lan_commands;
++
++	/* Responses I have sent to the IPMB bus. */
++	unsigned int sent_lan_responses;
++
++	/* The response was delivered to the user. */
++	unsigned int handled_lan_responses;
++	/* The response had invalid data in it. */
++	unsigned int invalid_lan_responses;
++	/* The response didn't have anyone waiting for it. */
++	unsigned int unhandled_lan_responses;
++
++	/* The command was delivered to the user. */
++	unsigned int handled_commands;
++	/* The command had invalid data in it. */
++	unsigned int invalid_commands;
++	/* The command didn't have anyone waiting for it. */
++	unsigned int unhandled_commands;
++
++	/* Invalid data in an event. */
++	unsigned int invalid_events;
++	/* Events that were received with the proper format. */
++	unsigned int events;
+ };
+ 
+ int
+@@ -251,6 +372,22 @@
+ 	return 0;
+ }
+ 
++static void
++call_smi_watchers(int i)
++{
++	struct ipmi_smi_watcher *w;
++
++	down_read(&smi_watchers_sem);
++	list_for_each_entry(w, &smi_watchers, link) {
++		if (try_inc_mod_count(w->owner)) {
++			w->new_smi(i);
++			if (w->owner)
++				__MOD_DEC_USE_COUNT(w->owner);
++		}
++	}
++	up_read(&smi_watchers_sem);
++}
++
+ int
+ ipmi_addr_equal(struct ipmi_addr *addr1, struct ipmi_addr *addr2)
+ {
+@@ -280,6 +417,19 @@
+ 			&& (ipmb_addr1->lun == ipmb_addr2->lun));
+ 	}
+ 
++	if (addr1->addr_type == IPMI_LAN_ADDR_TYPE) {
++		struct ipmi_lan_addr *lan_addr1
++			= (struct ipmi_lan_addr *) addr1;
++		struct ipmi_lan_addr *lan_addr2
++		    = (struct ipmi_lan_addr *) addr2;
++
++		return ((lan_addr1->remote_SWID == lan_addr2->remote_SWID)
++			&& (lan_addr1->local_SWID == lan_addr2->local_SWID)
++			&& (lan_addr1->session_handle
++			    == lan_addr2->session_handle)
++			&& (lan_addr1->lun == lan_addr2->lun));
++	}
++
+ 	return 1;
+ }
+ 
+@@ -309,6 +459,13 @@
+ 		return 0;
+ 	}
+ 
++	if (addr->addr_type == IPMI_LAN_ADDR_TYPE) {
++		if (len < sizeof(struct ipmi_lan_addr)) {
++			return -EINVAL;
++		}
++		return 0;
++	}
++
+ 	return -EINVAL;
+ }
+ 
+@@ -328,7 +485,7 @@
+ 
+ static void deliver_response(struct ipmi_recv_msg *msg)
+ {
+-    msg->user->handler->ipmi_recv_hndl(msg, msg->user->handler_data);
++	msg->user->handler->ipmi_recv_hndl(msg, msg->user->handler_data);
+ }
+ 
+ /* Find the next sequence number not being used and add the given
+@@ -338,6 +495,7 @@
+ 			 struct ipmi_recv_msg *recv_msg,
+ 			 unsigned long        timeout,
+ 			 int                  retries,
++			 int                  broadcast,
+ 			 unsigned char        *seq,
+ 			 long                 *seqid)
+ {
+@@ -360,6 +518,7 @@
+ 		intf->seq_table[i].timeout = MAX_MSG_TIMEOUT;
+ 		intf->seq_table[i].orig_timeout = timeout;
+ 		intf->seq_table[i].retries_left = retries;
++		intf->seq_table[i].broadcast = broadcast;
+ 		intf->seq_table[i].inuse = 1;
+ 		intf->seq_table[i].seqid = NEXT_SEQID(intf->seq_table[i].seqid);
+ 		*seq = i;
+@@ -412,8 +571,8 @@
+ 
+ 
+ /* Start the timer for a specific sequence table entry. */
+-static int intf_start_seq_timer(ipmi_smi_t           intf,
+-				long                 msgid)
++static int intf_start_seq_timer(ipmi_smi_t intf,
++				long       msgid)
+ {
+ 	int           rv = -ENODEV;
+ 	unsigned long flags;
+@@ -431,12 +590,53 @@
+ 	{
+ 		struct seq_table *ent = &(intf->seq_table[seq]);
+ 		ent->timeout = ent->orig_timeout;
++		rv = 0;
+ 	}
+ 	spin_unlock_irqrestore(&(intf->seq_lock), flags);
+ 
+ 	return rv;
+ }
+ 
++/* Got an error for the send message for a specific sequence number. */
++static int intf_err_seq(ipmi_smi_t   intf,
++			long         msgid,
++			unsigned int err)
++{
++	int                  rv = -ENODEV;
++	unsigned long        flags;
++	unsigned char        seq;
++	unsigned long        seqid;
++	struct ipmi_recv_msg *msg = NULL;
++
++
++	GET_SEQ_FROM_MSGID(msgid, seq, seqid);
++
++	spin_lock_irqsave(&(intf->seq_lock), flags);
++	/* We do this verification because the user can be deleted
++           while a message is outstanding. */
++	if ((intf->seq_table[seq].inuse)
++	    && (intf->seq_table[seq].seqid == seqid))
++	{
++		struct seq_table *ent = &(intf->seq_table[seq]);
++
++		ent->inuse = 0;
++		msg = ent->recv_msg;
++		rv = 0;
++	}
++	spin_unlock_irqrestore(&(intf->seq_lock), flags);
++
++	if (msg) {
++		msg->recv_type = IPMI_RESPONSE_RECV_TYPE;
++		msg->msg_data[0] = err;
++		msg->msg.netfn |= 1; /* Convert to a response. */
++		msg->msg.data_len = 1;
++		msg->msg.data = msg->msg_data;
++		deliver_response(msg);
++	}
++
++	return rv;
++}
++
+ 
+ int ipmi_create_user(unsigned int          if_num,
+ 		     struct ipmi_user_hndl *handler,
+@@ -508,15 +708,14 @@
+ {
+ 	int              rv = -ENODEV;
+ 	ipmi_user_t      t_user;
+-	struct list_head *entry, *entry2;
++	struct cmd_rcvr  *rcvr, *rcvr2;
+ 	int              i;
+ 	unsigned long    flags;
+ 
+ 	/* Find the user and delete them from the list. */
+-	list_for_each(entry, &(user->intf->users)) {
+-		t_user = list_entry(entry, struct ipmi_user, link);
++	list_for_each_entry(t_user, &(user->intf->users), link) {
+ 		if (t_user == user) {
+-			list_del(entry);
++			list_del(&t_user->link);
+ 			rv = 0;
+ 			break;
+ 		}
+@@ -539,11 +738,9 @@
+ 
+ 	/* Remove the user from the command receiver's table. */
+ 	write_lock_irqsave(&(user->intf->cmd_rcvr_lock), flags);
+-	list_for_each_safe(entry, entry2, &(user->intf->cmd_rcvrs)) {
+-		struct cmd_rcvr *rcvr;
+-		rcvr = list_entry(entry, struct cmd_rcvr, link);
++	list_for_each_entry_safe(rcvr, rcvr2, &(user->intf->cmd_rcvrs), link) {
+ 		if (rcvr->user == user) {
+-			list_del(entry);
++			list_del(&rcvr->link);
+ 			kfree(rcvr);
+ 		}
+ 	}
+@@ -606,8 +803,7 @@
+ int ipmi_set_gets_events(ipmi_user_t user, int val)
+ {
+ 	unsigned long         flags;
+-	struct list_head      *e, *e2;
+-	struct ipmi_recv_msg  *msg;
++	struct ipmi_recv_msg  *msg, *msg2;
+ 
+ 	read_lock(&(user->intf->users_lock));
+ 	spin_lock_irqsave(&(user->intf->events_lock), flags);
+@@ -615,9 +811,8 @@
+ 
+ 	if (val) {
+ 		/* Deliver any queued events. */
+-		list_for_each_safe(e, e2, &(user->intf->waiting_events)) {
+-			msg = list_entry(e, struct ipmi_recv_msg, link);
+-			list_del(e);
++		list_for_each_entry_safe(msg, msg2, &(user->intf->waiting_events), link) {
++			list_del(&msg->link);
+ 			msg->user = user;
+ 			deliver_response(msg);
+ 		}
+@@ -633,7 +828,7 @@
+ 			  unsigned char netfn,
+ 			  unsigned char cmd)
+ {
+-	struct list_head *entry;
++	struct cmd_rcvr  *cmp;
+ 	unsigned long    flags;
+ 	struct cmd_rcvr  *rcvr;
+ 	int              rv = 0;
+@@ -651,9 +846,7 @@
+ 	}
+ 
+ 	/* Make sure the command/netfn is not already registered. */
+-	list_for_each(entry, &(user->intf->cmd_rcvrs)) {
+-		struct cmd_rcvr *cmp;
+-		cmp = list_entry(entry, struct cmd_rcvr, link);
++	list_for_each_entry(cmp, &(user->intf->cmd_rcvrs), link) {
+ 		if ((cmp->netfn == netfn) && (cmp->cmd == cmd)) {
+ 			rv = -EBUSY;
+ 			break;
+@@ -680,7 +873,6 @@
+ 			    unsigned char netfn,
+ 			    unsigned char cmd)
+ {
+-	struct list_head *entry;
+ 	unsigned long    flags;
+ 	struct cmd_rcvr  *rcvr;
+ 	int              rv = -ENOENT;
+@@ -688,11 +880,10 @@
+ 	read_lock(&(user->intf->users_lock));
+ 	write_lock_irqsave(&(user->intf->cmd_rcvr_lock), flags);
+ 	/* Make sure the command/netfn is not already registered. */
+-	list_for_each(entry, &(user->intf->cmd_rcvrs)) {
+-		rcvr = list_entry(entry, struct cmd_rcvr, link);
++	list_for_each_entry(rcvr, &(user->intf->cmd_rcvrs), link) {
+ 		if ((rcvr->netfn == netfn) && (rcvr->cmd == cmd)) {
+ 			rv = 0;
+-			list_del(entry);
++			list_del(&rcvr->link);
+ 			kfree(rcvr);
+ 			break;
+ 		}
+@@ -703,6 +894,12 @@
+ 	return rv;
+ }
+ 
++void ipmi_user_set_run_to_completion(ipmi_user_t user, int val)
++{
++	user->intf->handlers->set_run_to_completion(user->intf->send_info,
++						    val);
++}
++
+ static unsigned char
+ ipmb_checksum(unsigned char *data, int size)
+ {
+@@ -756,6 +953,43 @@
+ 	smi_msg->msgid = msgid;
+ }
+ 
++static inline void format_lan_msg(struct ipmi_smi_msg   *smi_msg,
++				  struct ipmi_msg       *msg,
++				  struct ipmi_lan_addr  *lan_addr,
++				  long                  msgid,
++				  unsigned char         ipmb_seq,
++				  unsigned char         source_lun)
++{
++	/* Format the IPMB header data. */
++	smi_msg->data[0] = (IPMI_NETFN_APP_REQUEST << 2);
++	smi_msg->data[1] = IPMI_SEND_MSG_CMD;
++	smi_msg->data[2] = lan_addr->channel;
++	smi_msg->data[3] = lan_addr->session_handle;
++	smi_msg->data[4] = lan_addr->remote_SWID;
++	smi_msg->data[5] = (msg->netfn << 2) | (lan_addr->lun & 0x3);
++	smi_msg->data[6] = ipmb_checksum(&(smi_msg->data[4]), 2);
++	smi_msg->data[7] = lan_addr->local_SWID;
++	smi_msg->data[8] = (ipmb_seq << 2) | source_lun;
++	smi_msg->data[9] = msg->cmd;
++
++	/* Now tack on the data to the message. */
++	if (msg->data_len > 0)
++		memcpy(&(smi_msg->data[10]), msg->data,
++		       msg->data_len);
++	smi_msg->data_size = msg->data_len + 10;
++
++	/* Now calculate the checksum and tack it on. */
++	smi_msg->data[smi_msg->data_size]
++		= ipmb_checksum(&(smi_msg->data[7]),
++				smi_msg->data_size-7);
++
++	/* Add on the checksum size and the offset from the
++	   broadcast. */
++	smi_msg->data_size += 1;
++
++	smi_msg->msgid = msgid;
++}
++
+ /* Separate from ipmi_request so that the user does not have to be
+    supplied in certain circumstances (mainly at panic time).  If
+    messages are supplied, they will be freed, even if an error
+@@ -765,11 +999,14 @@
+ 				 struct ipmi_addr     *addr,
+ 				 long                 msgid,
+ 				 struct ipmi_msg      *msg,
++				 void                 *user_msg_data,
+ 				 void                 *supplied_smi,
+ 				 struct ipmi_recv_msg *supplied_recv,
+ 				 int                  priority,
+ 				 unsigned char        source_address,
+-				 unsigned char        source_lun)
++				 unsigned char        source_lun,
++				 int                  retries,
++				 unsigned int         retry_time_ms)
+ {
+ 	int                  rv = 0;
+ 	struct ipmi_smi_msg  *smi_msg;
+@@ -785,6 +1022,7 @@
+ 			return -ENOMEM;
+ 		}
+ 	}
++	recv_msg->user_msg_data = user_msg_data;
+ 
+ 	if (supplied_smi) {
+ 		smi_msg = (struct ipmi_smi_msg *) supplied_smi;
+@@ -796,11 +1034,6 @@
+ 		}
+ 	}
+ 
+-	if (addr->channel > IPMI_NUM_CHANNELS) {
+-	    rv = -EINVAL;
+-	    goto out_err;
+-	}
+-
+ 	recv_msg->user = user;
+ 	recv_msg->msgid = msgid;
+ 	/* Store the message to send in the receive message so timeout
+@@ -810,10 +1043,20 @@
+ 	if (addr->addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE) {
+ 		struct ipmi_system_interface_addr *smi_addr;
+ 
++		if (msg->netfn & 1) {
++			/* Responses are not allowed to the SMI. */
++			rv = -EINVAL;
++			goto out_err;
++		}
+ 
+ 		smi_addr = (struct ipmi_system_interface_addr *) addr;
+-		if (smi_addr->lun > 3)
+-			return -EINVAL;
++		if (smi_addr->lun > 3) {
++			spin_lock_irqsave(&intf->counter_lock, flags);
++			intf->sent_invalid_commands++;
++			spin_unlock_irqrestore(&intf->counter_lock, flags);
++			rv = -EINVAL;
++			goto out_err;
++		}
+ 
+ 		memcpy(&recv_msg->addr, smi_addr, sizeof(*smi_addr));
+ 
+@@ -824,11 +1067,17 @@
+ 		{
+ 			/* We don't let the user do these, since we manage
+ 			   the sequence numbers. */
++			spin_lock_irqsave(&intf->counter_lock, flags);
++			intf->sent_invalid_commands++;
++			spin_unlock_irqrestore(&intf->counter_lock, flags);
+ 			rv = -EINVAL;
+ 			goto out_err;
+ 		}
+ 
+ 		if ((msg->data_len + 2) > IPMI_MAX_MSG_LENGTH) {
++			spin_lock_irqsave(&intf->counter_lock, flags);
++			intf->sent_invalid_commands++;
++			spin_unlock_irqrestore(&intf->counter_lock, flags);
+ 			rv = -EMSGSIZE;
+ 			goto out_err;
+ 		}
+@@ -840,41 +1089,69 @@
+ 		if (msg->data_len > 0)
+ 			memcpy(&(smi_msg->data[2]), msg->data, msg->data_len);
+ 		smi_msg->data_size = msg->data_len + 2;
++		spin_lock_irqsave(&intf->counter_lock, flags);
++		intf->sent_local_commands++;
++		spin_unlock_irqrestore(&intf->counter_lock, flags);
+ 	} else if ((addr->addr_type == IPMI_IPMB_ADDR_TYPE)
+ 		   || (addr->addr_type == IPMI_IPMB_BROADCAST_ADDR_TYPE))
+ 	{
+ 		struct ipmi_ipmb_addr *ipmb_addr;
+ 		unsigned char         ipmb_seq;
+ 		long                  seqid;
+-		int                   broadcast;
+-		int                   retries;
++		int                   broadcast = 0;
+ 
+-		if (addr == NULL) {
++		if (addr->channel > IPMI_NUM_CHANNELS) {
++			spin_lock_irqsave(&intf->counter_lock, flags);
++			intf->sent_invalid_commands++;
++			spin_unlock_irqrestore(&intf->counter_lock, flags);
+ 			rv = -EINVAL;
+ 			goto out_err;
+ 		}
+ 
++		if (intf->channels[addr->channel].medium
++		    != IPMI_CHANNEL_MEDIUM_IPMB)
++		{
++			spin_lock_irqsave(&intf->counter_lock, flags);
++			intf->sent_invalid_commands++;
++			spin_unlock_irqrestore(&intf->counter_lock, flags);
++			rv = -EINVAL;
++			goto out_err;
++		}
++
++		if (retries < 0) {
++		    if (addr->addr_type == IPMI_IPMB_BROADCAST_ADDR_TYPE)
++			retries = 0; /* Don't retry broadcasts. */
++		    else
++			retries = 4;
++		}
+ 		if (addr->addr_type == IPMI_IPMB_BROADCAST_ADDR_TYPE) {
+ 		    /* Broadcasts add a zero at the beginning of the
+ 		       message, but otherwise is the same as an IPMB
+ 		       address. */
+ 		    addr->addr_type = IPMI_IPMB_ADDR_TYPE;
+ 		    broadcast = 1;
+-		    retries = 0; /* Don't retry broadcasts. */
+-		} else {
+-		    broadcast = 0;
+-		    retries = 4;
+ 		}
+ 
++
++		/* Default to 1 second retries. */
++		if (retry_time_ms == 0)
++		    retry_time_ms = 1000;
++
+ 		/* 9 for the header and 1 for the checksum, plus
+                    possibly one for the broadcast. */
+ 		if ((msg->data_len + 10 + broadcast) > IPMI_MAX_MSG_LENGTH) {
++			spin_lock_irqsave(&intf->counter_lock, flags);
++			intf->sent_invalid_commands++;
++			spin_unlock_irqrestore(&intf->counter_lock, flags);
+ 			rv = -EMSGSIZE;
+ 			goto out_err;
+ 		}
+ 
+ 		ipmb_addr = (struct ipmi_ipmb_addr *) addr;
+ 		if (ipmb_addr->lun > 3) {
++			spin_lock_irqsave(&intf->counter_lock, flags);
++			intf->sent_invalid_commands++;
++			spin_unlock_irqrestore(&intf->counter_lock, flags);
+ 			rv = -EINVAL;
+ 			goto out_err;
+ 		}
+@@ -884,21 +1161,32 @@
+ 		if (recv_msg->msg.netfn & 0x1) {
+ 			/* It's a response, so use the user's sequence
+                            from msgid. */
++			spin_lock_irqsave(&intf->counter_lock, flags);
++			intf->sent_ipmb_responses++;
++			spin_unlock_irqrestore(&intf->counter_lock, flags);
+ 			format_ipmb_msg(smi_msg, msg, ipmb_addr, msgid,
+ 					msgid, broadcast,
+ 					source_address, source_lun);
++
++			/* Save the receive message so we can use it
++			   to deliver the response. */
++			smi_msg->user_data = recv_msg;
+ 		} else {
+ 			/* It's a command, so get a sequence for it. */
+ 
+ 			spin_lock_irqsave(&(intf->seq_lock), flags);
+ 
++			spin_lock(&intf->counter_lock);
++			intf->sent_ipmb_commands++;
++			spin_unlock(&intf->counter_lock);
++
+ 			/* Create a sequence number with a 1 second
+                            timeout and 4 retries. */
+-			/* FIXME - magic number for the timeout. */
+ 			rv = intf_next_seq(intf,
+ 					   recv_msg,
+-					   1000,
++					   retry_time_ms,
+ 					   retries,
++					   broadcast,
+ 					   &ipmb_seq,
+ 					   &seqid);
+ 			if (rv) {
+@@ -932,18 +1220,132 @@
+                            to be correct. */
+ 			spin_unlock_irqrestore(&(intf->seq_lock), flags);
+ 		}
++	} else if (addr->addr_type == IPMI_LAN_ADDR_TYPE) {
++		struct ipmi_lan_addr  *lan_addr;
++		unsigned char         ipmb_seq;
++		long                  seqid;
++
++		if (addr->channel > IPMI_NUM_CHANNELS) {
++			spin_lock_irqsave(&intf->counter_lock, flags);
++			intf->sent_invalid_commands++;
++			spin_unlock_irqrestore(&intf->counter_lock, flags);
++			rv = -EINVAL;
++			goto out_err;
++		}
++
++		if ((intf->channels[addr->channel].medium
++		    != IPMI_CHANNEL_MEDIUM_8023LAN)
++		    && (intf->channels[addr->channel].medium
++			!= IPMI_CHANNEL_MEDIUM_ASYNC))
++		{
++			spin_lock_irqsave(&intf->counter_lock, flags);
++			intf->sent_invalid_commands++;
++			spin_unlock_irqrestore(&intf->counter_lock, flags);
++			rv = -EINVAL;
++			goto out_err;
++		}
++
++		retries = 4;
++
++		/* Default to 1 second retries. */
++		if (retry_time_ms == 0)
++		    retry_time_ms = 1000;
++
++		/* 11 for the header and 1 for the checksum. */
++		if ((msg->data_len + 12) > IPMI_MAX_MSG_LENGTH) {
++			spin_lock_irqsave(&intf->counter_lock, flags);
++			intf->sent_invalid_commands++;
++			spin_unlock_irqrestore(&intf->counter_lock, flags);
++			rv = -EMSGSIZE;
++			goto out_err;
++		}
++
++		lan_addr = (struct ipmi_lan_addr *) addr;
++		if (lan_addr->lun > 3) {
++			spin_lock_irqsave(&intf->counter_lock, flags);
++			intf->sent_invalid_commands++;
++			spin_unlock_irqrestore(&intf->counter_lock, flags);
++			rv = -EINVAL;
++			goto out_err;
++		}
++
++		memcpy(&recv_msg->addr, lan_addr, sizeof(*lan_addr));
++
++		if (recv_msg->msg.netfn & 0x1) {
++			/* It's a response, so use the user's sequence
++                           from msgid. */
++			spin_lock_irqsave(&intf->counter_lock, flags);
++			intf->sent_lan_responses++;
++			spin_unlock_irqrestore(&intf->counter_lock, flags);
++			format_lan_msg(smi_msg, msg, lan_addr, msgid,
++				       msgid, source_lun);
++
++			/* Save the receive message so we can use it
++			   to deliver the response. */
++			smi_msg->user_data = recv_msg;
++		} else {
++			/* It's a command, so get a sequence for it. */
++
++			spin_lock_irqsave(&(intf->seq_lock), flags);
++
++			spin_lock(&intf->counter_lock);
++			intf->sent_lan_commands++;
++			spin_unlock(&intf->counter_lock);
++
++			/* Create a sequence number with a 1 second
++                           timeout and 4 retries. */
++			rv = intf_next_seq(intf,
++					   recv_msg,
++					   retry_time_ms,
++					   retries,
++					   0,
++					   &ipmb_seq,
++					   &seqid);
++			if (rv) {
++				/* We have used up all the sequence numbers,
++				   probably, so abort. */
++				spin_unlock_irqrestore(&(intf->seq_lock),
++						       flags);
++				goto out_err;
++			}
++
++			/* Store the sequence number in the message,
++                           so that when the send message response
++                           comes back we can start the timer. */
++			format_lan_msg(smi_msg, msg, lan_addr,
++				       STORE_SEQ_IN_MSGID(ipmb_seq, seqid),
++				       ipmb_seq, source_lun);
++
++			/* Copy the message into the recv message data, so we
++			   can retransmit it later if necessary. */
++			memcpy(recv_msg->msg_data, smi_msg->data,
++			       smi_msg->data_size);
++			recv_msg->msg.data = recv_msg->msg_data;
++			recv_msg->msg.data_len = smi_msg->data_size;
++
++			/* We don't unlock until here, because we need
++                           to copy the completed message into the
++                           recv_msg before we release the lock.
++                           Otherwise, race conditions may bite us.  I
++                           know that's pretty paranoid, but I prefer
++                           to be correct. */
++			spin_unlock_irqrestore(&(intf->seq_lock), flags);
++		}
+ 	} else {
+ 	    /* Unknown address type. */
+-	    rv = -EINVAL;
+-	    goto out_err;
++		spin_lock_irqsave(&intf->counter_lock, flags);
++		intf->sent_invalid_commands++;
++		spin_unlock_irqrestore(&intf->counter_lock, flags);
++		rv = -EINVAL;
++		goto out_err;
+ 	}
+ 
+ #if DEBUG_MSGING
+ 	{
+-	    int m;
+-	    for (m=0; m<smi_msg->data_size; m++)
+-		printk(" %2.2x", smi_msg->data[m]);
+-	    printk("\n");
++		int m;
++		for (m=0; m<smi_msg->data_size; m++)
++			printk(" %2.2x", smi_msg->data[m]);
++		printk("\n");
+ 	}
+ #endif
+ 	intf->handlers->sender(intf->send_info, smi_msg, priority);
+@@ -960,6 +1362,7 @@
+ 		 struct ipmi_addr *addr,
+ 		 long             msgid,
+ 		 struct ipmi_msg  *msg,
++		 void             *user_msg_data,
+ 		 int              priority)
+ {
+ 	return i_ipmi_request(user,
+@@ -967,16 +1370,42 @@
+ 			      addr,
+ 			      msgid,
+ 			      msg,
++			      user_msg_data,
+ 			      NULL, NULL,
+ 			      priority,
+ 			      user->intf->my_address,
+-			      user->intf->my_lun);
++			      user->intf->my_lun,
++			      -1, 0);
++}
++
++int ipmi_request_settime(ipmi_user_t      user,
++			 struct ipmi_addr *addr,
++			 long             msgid,
++			 struct ipmi_msg  *msg,
++			 void             *user_msg_data,
++			 int              priority,
++			 int              retries,
++			 unsigned int     retry_time_ms)
++{
++	return i_ipmi_request(user,
++			      user->intf,
++			      addr,
++			      msgid,
++			      msg,
++			      user_msg_data,
++			      NULL, NULL,
++			      priority,
++			      user->intf->my_address,
++			      user->intf->my_lun,
++			      retries,
++			      retry_time_ms);
+ }
+ 
+ int ipmi_request_supply_msgs(ipmi_user_t          user,
+ 			     struct ipmi_addr     *addr,
+ 			     long                 msgid,
+ 			     struct ipmi_msg      *msg,
++			     void                 *user_msg_data,
+ 			     void                 *supplied_smi,
+ 			     struct ipmi_recv_msg *supplied_recv,
+ 			     int                  priority)
+@@ -986,17 +1415,20 @@
+ 			      addr,
+ 			      msgid,
+ 			      msg,
++			      user_msg_data,
+ 			      supplied_smi,
+ 			      supplied_recv,
+ 			      priority,
+ 			      user->intf->my_address,
+-			      user->intf->my_lun);
++			      user->intf->my_lun,
++			      -1, 0);
+ }
+ 
+ int ipmi_request_with_source(ipmi_user_t      user,
+ 			     struct ipmi_addr *addr,
+ 			     long             msgid,
+ 			     struct ipmi_msg  *msg,
++			     void             *user_msg_data,
+ 			     int              priority,
+ 			     unsigned char    source_address,
+ 			     unsigned char    source_lun)
+@@ -1006,10 +1438,241 @@
+ 			      addr,
+ 			      msgid,
+ 			      msg,
++			      user_msg_data,
+ 			      NULL, NULL,
+ 			      priority,
+ 			      source_address,
+-			      source_lun);
++			      source_lun,
++			      -1, 0);
++}
++
++static int ipmb_file_read_proc(char *page, char **start, off_t off,
++			       int count, int *eof, void *data)
++{
++	char       *out = (char *) page;
++	ipmi_smi_t intf = data;
++
++	return sprintf(out, "%x\n", intf->my_address);
++}
++
++static int version_file_read_proc(char *page, char **start, off_t off,
++				  int count, int *eof, void *data)
++{
++	char       *out = (char *) page;
++	ipmi_smi_t intf = data;
++
++	return sprintf(out, "%d.%d\n",
++		       intf->version_major, intf->version_minor);
++}
++
++static int stat_file_read_proc(char *page, char **start, off_t off,
++			       int count, int *eof, void *data)
++{
++	char       *out = (char *) page;
++	ipmi_smi_t intf = data;
++
++	out += sprintf(out, "sent_invalid_commands:       %d\n",
++		       intf->sent_invalid_commands);
++	out += sprintf(out, "sent_local_commands:         %d\n",
++		       intf->sent_local_commands);
++	out += sprintf(out, "handled_local_responses:     %d\n",
++		       intf->handled_local_responses);
++	out += sprintf(out, "unhandled_local_responses:   %d\n",
++		       intf->unhandled_local_responses);
++	out += sprintf(out, "sent_ipmb_commands:          %d\n",
++		       intf->sent_ipmb_commands);
++	out += sprintf(out, "sent_ipmb_command_errs:      %d\n",
++		       intf->sent_ipmb_command_errs);
++	out += sprintf(out, "retransmitted_ipmb_commands: %d\n",
++		       intf->retransmitted_ipmb_commands);
++	out += sprintf(out, "timed_out_ipmb_commands:     %d\n",
++		       intf->timed_out_ipmb_commands);
++	out += sprintf(out, "timed_out_ipmb_broadcasts:   %d\n",
++		       intf->timed_out_ipmb_broadcasts);
++	out += sprintf(out, "sent_ipmb_responses:         %d\n",
++		       intf->sent_ipmb_responses);
++	out += sprintf(out, "handled_ipmb_responses:      %d\n",
++		       intf->handled_ipmb_responses);
++	out += sprintf(out, "invalid_ipmb_responses:      %d\n",
++		       intf->invalid_ipmb_responses);
++	out += sprintf(out, "unhandled_ipmb_responses:    %d\n",
++		       intf->unhandled_ipmb_responses);
++	out += sprintf(out, "sent_lan_commands:           %d\n",
++		       intf->sent_lan_commands);
++	out += sprintf(out, "sent_lan_command_errs:       %d\n",
++		       intf->sent_lan_command_errs);
++	out += sprintf(out, "retransmitted_lan_commands:  %d\n",
++		       intf->retransmitted_lan_commands);
++	out += sprintf(out, "timed_out_lan_commands:      %d\n",
++		       intf->timed_out_lan_commands);
++	out += sprintf(out, "sent_lan_responses:          %d\n",
++		       intf->sent_lan_responses);
++	out += sprintf(out, "handled_lan_responses:       %d\n",
++		       intf->handled_lan_responses);
++	out += sprintf(out, "invalid_lan_responses:       %d\n",
++		       intf->invalid_lan_responses);
++	out += sprintf(out, "unhandled_lan_responses:     %d\n",
++		       intf->unhandled_lan_responses);
++	out += sprintf(out, "handled_commands:            %d\n",
++		       intf->handled_commands);
++	out += sprintf(out, "invalid_commands:            %d\n",
++		       intf->invalid_commands);
++	out += sprintf(out, "unhandled_commands:          %d\n",
++		       intf->unhandled_commands);
++	out += sprintf(out, "invalid_events:              %d\n",
++		       intf->invalid_events);
++	out += sprintf(out, "events:                      %d\n",
++		       intf->events);
++
++	return (out - ((char *) page));
++}
++
++int ipmi_smi_add_proc_entry(ipmi_smi_t smi, char *name,
++			    read_proc_t *read_proc, write_proc_t *write_proc,
++			    void *data, struct module *owner)
++{
++	struct proc_dir_entry *file;
++	int                   rv = 0;
++
++	file = create_proc_entry(name, 0, smi->proc_dir);
++	if (!file)
++		rv = -ENOMEM;
++	else {
++		file->nlink = 1;
++		file->data = data;
++		file->read_proc = read_proc;
++		file->write_proc = write_proc;
++		file->owner = owner;
++	}
++
++	return rv;
++}
++
++static int add_proc_entries(ipmi_smi_t smi, int num)
++{
++	int rv = 0;
++
++	sprintf(smi->proc_dir_name, "%d", num);
++	smi->proc_dir = proc_mkdir(smi->proc_dir_name, proc_ipmi_root);
++	if (!smi->proc_dir)
++		rv = -ENOMEM;
++	else {
++		smi->proc_dir->owner = THIS_MODULE;
++	}
++
++	if (rv == 0)
++		rv = ipmi_smi_add_proc_entry(smi, "stats",
++					     stat_file_read_proc, NULL,
++					     smi, THIS_MODULE);
++
++	if (rv == 0)
++		rv = ipmi_smi_add_proc_entry(smi, "ipmb",
++					     ipmb_file_read_proc, NULL,
++					     smi, THIS_MODULE);
++
++	if (rv == 0)
++		rv = ipmi_smi_add_proc_entry(smi, "version",
++					     version_file_read_proc, NULL,
++					     smi, THIS_MODULE);
++
++	return rv;
++}
++
++static int
++send_channel_info_cmd(ipmi_smi_t intf, int chan)
++{
++	struct ipmi_msg                   msg;
++	unsigned char                     data[1];
++	struct ipmi_system_interface_addr si;
++
++	si.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
++	si.channel = IPMI_BMC_CHANNEL;
++	si.lun = 0;
++
++	msg.netfn = IPMI_NETFN_APP_REQUEST;
++	msg.cmd = IPMI_GET_CHANNEL_INFO_CMD;
++	msg.data = data;
++	msg.data_len = 1;
++	data[0] = chan;
++	return i_ipmi_request(NULL,
++			      intf,
++			      (struct ipmi_addr *) &si,
++			      0,
++			      &msg,
++			      NULL,
++			      NULL,
++			      NULL,
++			      0,
++			      intf->my_address,
++			      intf->my_lun,
++			      -1, 0);
++}
++
++static void
++channel_handler(ipmi_smi_t intf, struct ipmi_smi_msg *msg)
++{
++	int rv = 0;
++	int chan;
++
++	if ((msg->rsp[0] == (IPMI_NETFN_APP_RESPONSE << 2))
++	    && (msg->rsp[1] == IPMI_GET_CHANNEL_INFO_CMD))
++	{
++		/* It's the one we want */
++		if (msg->rsp[2] != 0) {
++			/* Got an error from the channel, just go on. */
++
++			if (msg->rsp[2] == IPMI_INVALID_COMMAND_ERR) {
++				/* If the MC does not support this
++				   command, that is legal.  We just
++				   assume it has one IPMB at channel
++				   zero. */
++				intf->channels[0].medium
++					= IPMI_CHANNEL_MEDIUM_IPMB;
++				intf->channels[0].protocol
++					= IPMI_CHANNEL_PROTOCOL_IPMB;
++				rv = -ENOSYS;
++
++				intf->curr_channel = IPMI_MAX_CHANNELS;
++				wake_up(&intf->waitq);
++				goto out;
++			}
++			goto next_channel;
++		}
++		if (msg->rsp_size < 6) {
++			/* Message not big enough, just go on. */
++			goto next_channel;
++		}
++		chan = intf->curr_channel;
++		intf->channels[chan].medium = msg->rsp[4] & 0x7f;
++		intf->channels[chan].protocol = msg->rsp[5] & 0x1f;
++
++	next_channel:
++		intf->curr_channel++;
++		if (intf->curr_channel >= IPMI_MAX_CHANNELS)
++			wake_up(&intf->waitq);
++		else
++			rv = send_channel_info_cmd(intf, intf->curr_channel);
++
++		if (rv) {
++			/* Got an error somehow, just give up. */
++			intf->curr_channel = IPMI_MAX_CHANNELS;
++			wake_up(&intf->waitq);
++
++			printk(KERN_WARNING PFX
++			       "Error sending channel information: %d\n",
++			       rv);
++		}
++	}
++ out:
++	return;
++}
++
++void ipmi_poll_interface(ipmi_user_t user)
++{
++	ipmi_smi_t intf = user->intf;
++
++	if (intf->handlers->poll)
++		intf->handlers->poll(intf->send_info);
+ }
+ 
+ int ipmi_register_smi(struct ipmi_smi_handlers *handlers,
+@@ -1021,7 +1684,6 @@
+ 	int              i, j;
+ 	int              rv;
+ 	ipmi_smi_t       new_intf;
+-	struct list_head *entry;
+ 	unsigned long    flags;
+ 
+ 
+@@ -1040,12 +1702,16 @@
+ 	new_intf = kmalloc(sizeof(*new_intf), GFP_KERNEL);
+ 	if (!new_intf)
+ 		return -ENOMEM;
++	memset(new_intf, 0, sizeof(*new_intf));
++
++	new_intf->proc_dir = NULL;
+ 
+ 	rv = -ENOMEM;
+ 
+ 	down_write(&interfaces_sem);
+ 	for (i=0; i<MAX_IPMI_INTERFACES; i++) {
+ 		if (ipmi_interfaces[i] == NULL) {
++			new_intf->intf_num = i;
+ 			new_intf->version_major = version_major;
+ 			new_intf->version_minor = version_minor;
+ 			new_intf->my_address = IPMI_BMC_SLAVE_ADDR;
+@@ -1066,9 +1732,12 @@
+ 			INIT_LIST_HEAD(&(new_intf->waiting_events));
+ 			new_intf->waiting_events_count = 0;
+ 			rwlock_init(&(new_intf->cmd_rcvr_lock));
++			init_waitqueue_head(&new_intf->waitq);
+ 			INIT_LIST_HEAD(&(new_intf->cmd_rcvrs));
+ 			new_intf->all_cmd_rcvr = NULL;
+ 
++			spin_lock_init(&(new_intf->counter_lock));
++
+ 			spin_lock_irqsave(&interfaces_lock, flags);
+ 			ipmi_interfaces[i] = new_intf;
+ 			spin_unlock_irqrestore(&interfaces_lock, flags);
+@@ -1089,47 +1758,72 @@
+ 		/* Well, it went away.  Just return. */
+ 		goto out;
+ 
++	if (rv == 0)
++		rv = add_proc_entries(*intf, i);
++
+ 	if (rv == 0) {
+-		/* Call all the watcher interfaces to tell them that a
+-		   new interface is available. */
+-		down_read(&smi_watchers_sem);
+-		list_for_each(entry, &smi_watchers) {
+-			struct ipmi_smi_watcher *w;
+-			w = list_entry(entry, struct ipmi_smi_watcher, link);
+-			w->new_smi(i);
++		if ((version_major > 1)
++		    || ((version_major == 1) && (version_minor >= 5)))
++		{
++			/* Start scanning the channels to see what is
++			   available. */
++			(*intf)->null_user_handler = channel_handler;
++			(*intf)->curr_channel = 0;
++			rv = send_channel_info_cmd(*intf, 0);
++			if (rv)
++				goto out;
++
++			/* Wait for the channel info to be read. */
++			up_read(&interfaces_sem);
++			wait_event((*intf)->waitq,
++				   ((*intf)->curr_channel>=IPMI_MAX_CHANNELS));
++			down_read(&interfaces_sem);
++
++			if (ipmi_interfaces[i] != new_intf)
++				/* Well, it went away.  Just return. */
++				goto out;
++		} else {
++			/* Assume a single IPMB channel at zero. */
++			(*intf)->channels[0].medium = IPMI_CHANNEL_MEDIUM_IPMB;
++			(*intf)->channels[0].protocol
++				= IPMI_CHANNEL_PROTOCOL_IPMB;
++
+ 		}
+-		up_read(&smi_watchers_sem);
++
++		/* Call all the watcher interfaces to tell
++		   them that a new interface is available. */
++		call_smi_watchers(i);
+ 	}
+ 
+  out:
+ 	up_read(&interfaces_sem);
+ 
+-	if (rv)
++	if (rv) {
++		if (new_intf->proc_dir)
++			remove_proc_entry(new_intf->proc_dir_name,
++					  proc_ipmi_root);
+ 		kfree(new_intf);
++	}
+ 
+ 	return rv;
+ }
+ 
+ static void free_recv_msg_list(struct list_head *q)
+ {
+-	struct list_head     *entry, *entry2;
+-	struct ipmi_recv_msg *msg;
++	struct ipmi_recv_msg *msg, *msg2;
+ 
+-	list_for_each_safe(entry, entry2, q) {
+-		msg = list_entry(entry, struct ipmi_recv_msg, link);
+-		list_del(entry);
++	list_for_each_entry_safe(msg, msg2, q, link) {
++		list_del(&msg->link);
+ 		ipmi_free_recv_msg(msg);
+ 	}
+ }
+ 
+ static void free_cmd_rcvr_list(struct list_head *q)
+ {
+-	struct list_head *entry, *entry2;
+-	struct cmd_rcvr  *rcvr;
++	struct cmd_rcvr  *rcvr, *rcvr2;
+ 
+-	list_for_each_safe(entry, entry2, q) {
+-		rcvr = list_entry(entry, struct cmd_rcvr, link);
+-		list_del(entry);
++	list_for_each_entry_safe(rcvr, rcvr2, q, link) {
++		list_del(&rcvr->link);
+ 		kfree(rcvr);
+ 	}
+ }
+@@ -1153,16 +1847,18 @@
+ 
+ int ipmi_unregister_smi(ipmi_smi_t intf)
+ {
+-	int              rv = -ENODEV;
+-	int              i;
+-	struct list_head *entry;
+-	unsigned long    flags;
++	int                     rv = -ENODEV;
++	int                     i;
++	struct ipmi_smi_watcher *w;
++	unsigned long           flags;
+ 
+ 	down_write(&interfaces_sem);
+ 	if (list_empty(&(intf->users)))
+ 	{
+ 		for (i=0; i<MAX_IPMI_INTERFACES; i++) {
+ 			if (ipmi_interfaces[i] == intf) {
++				remove_proc_entry(intf->proc_dir_name,
++						  proc_ipmi_root);
+ 				spin_lock_irqsave(&interfaces_lock, flags);
+ 				ipmi_interfaces[i] = NULL;
+ 				clean_up_interface_data(intf);
+@@ -1187,11 +1883,7 @@
+ 	/* Call all the watcher interfaces to tell them that
+ 	   an interface is gone. */
+ 	down_read(&smi_watchers_sem);
+-	list_for_each(entry, &smi_watchers) {
+-		struct ipmi_smi_watcher *w;
+-		w = list_entry(entry,
+-			       struct ipmi_smi_watcher,
+-			       link);
++	list_for_each_entry(w, &smi_watchers, link) {
+ 		w->smi_gone(i);
+ 	}
+ 	up_read(&smi_watchers_sem);
+@@ -1199,20 +1891,28 @@
+ 	return 0;
+ }
+ 
+-static int handle_get_msg_rsp(ipmi_smi_t          intf,
+-			      struct ipmi_smi_msg *msg)
++static int handle_ipmb_get_msg_rsp(ipmi_smi_t          intf,
++				   struct ipmi_smi_msg *msg)
+ {
+ 	struct ipmi_ipmb_addr ipmb_addr;
+ 	struct ipmi_recv_msg  *recv_msg;
++	unsigned long         flags;
+ 
+ 	
+-	if (msg->rsp_size < 11)
++	/* This is 11, not 10, because the response must contain a
++	 * completion code. */
++	if (msg->rsp_size < 11) {
+ 		/* Message not big enough, just ignore it. */
++		spin_lock_irqsave(&intf->counter_lock, flags);
++		intf->invalid_ipmb_responses++;
++		spin_unlock_irqrestore(&intf->counter_lock, flags);
+ 		return 0;
++	}
+ 
+-	if (msg->rsp[2] != 0)
++	if (msg->rsp[2] != 0) {
+ 		/* An error getting the response, just ignore it. */
+ 		return 0;
++	}
+ 
+ 	ipmb_addr.addr_type = IPMI_IPMB_ADDR_TYPE;
+ 	ipmb_addr.slave_addr = msg->rsp[6];
+@@ -1231,6 +1931,9 @@
+ 	{
+ 		/* We were unable to find the sequence number,
+ 		   so just nuke the message. */
++		spin_lock_irqsave(&intf->counter_lock, flags);
++		intf->unhandled_ipmb_responses++;
++		spin_unlock_irqrestore(&intf->counter_lock, flags);
+ 		return 0;
+ 	}
+ 
+@@ -1244,26 +1947,33 @@
+ 	recv_msg->msg.data = recv_msg->msg_data;
+ 	recv_msg->msg.data_len = msg->rsp_size - 10;
+ 	recv_msg->recv_type = IPMI_RESPONSE_RECV_TYPE;
++	spin_lock_irqsave(&intf->counter_lock, flags);
++	intf->handled_ipmb_responses++;
++	spin_unlock_irqrestore(&intf->counter_lock, flags);
+ 	deliver_response(recv_msg);
+ 
+ 	return 0;
+ }
+ 
+-static int handle_get_msg_cmd(ipmi_smi_t          intf,
+-			      struct ipmi_smi_msg *msg)
++static int handle_ipmb_get_msg_cmd(ipmi_smi_t          intf,
++				   struct ipmi_smi_msg *msg)
+ {
+-	struct list_head *entry;
+ 	struct cmd_rcvr       *rcvr;
+-	int              rv = 0;
+-	unsigned char    netfn;
+-	unsigned char    cmd;
+-	ipmi_user_t      user = NULL;
++	int                   rv = 0;
++	unsigned char         netfn;
++	unsigned char         cmd;
++	ipmi_user_t           user = NULL;
+ 	struct ipmi_ipmb_addr *ipmb_addr;
+ 	struct ipmi_recv_msg  *recv_msg;
++	unsigned long         flags;
+ 
+-	if (msg->rsp_size < 10)
++	if (msg->rsp_size < 10) {
+ 		/* Message not big enough, just ignore it. */
++		spin_lock_irqsave(&intf->counter_lock, flags);
++		intf->invalid_commands++;
++		spin_unlock_irqrestore(&intf->counter_lock, flags);
+ 		return 0;
++	}
+ 
+ 	if (msg->rsp[2] != 0) {
+ 		/* An error getting the response, just ignore it. */
+@@ -1279,8 +1989,7 @@
+ 		user = intf->all_cmd_rcvr;
+ 	} else {
+ 		/* Find the command/netfn. */
+-		list_for_each(entry, &(intf->cmd_rcvrs)) {
+-			rcvr = list_entry(entry, struct cmd_rcvr, link);
++		list_for_each_entry(rcvr, &(intf->cmd_rcvrs), link) {
+ 			if ((rcvr->netfn == netfn) && (rcvr->cmd == cmd)) {
+ 				user = rcvr->user;
+ 				break;
+@@ -1291,6 +2000,10 @@
+ 
+ 	if (user == NULL) {
+ 		/* We didn't find a user, deliver an error response. */
++		spin_lock_irqsave(&intf->counter_lock, flags);
++		intf->unhandled_commands++;
++		spin_unlock_irqrestore(&intf->counter_lock, flags);
++
+ 		msg->data[0] = (IPMI_NETFN_APP_REQUEST << 2);
+ 		msg->data[1] = IPMI_SEND_MSG_CMD;
+ 		msg->data[2] = msg->rsp[3];
+@@ -1311,6 +2024,10 @@
+ 			    causes it to not be freed or queued. */
+ 	} else {
+ 		/* Deliver the message to the user. */
++		spin_lock_irqsave(&intf->counter_lock, flags);
++		intf->handled_commands++;
++		spin_unlock_irqrestore(&intf->counter_lock, flags);
++
+ 		recv_msg = ipmi_alloc_recv_msg();
+ 		if (! recv_msg) {
+ 			/* We couldn't allocate memory for the
+@@ -1318,18 +2035,24 @@
+                            later. */
+ 			rv = 1;
+ 		} else {
++			/* Extract the source address from the data. */
+ 			ipmb_addr = (struct ipmi_ipmb_addr *) &recv_msg->addr;
+ 			ipmb_addr->addr_type = IPMI_IPMB_ADDR_TYPE;
+ 			ipmb_addr->slave_addr = msg->rsp[6];
+ 			ipmb_addr->lun = msg->rsp[7] & 3;
+-			ipmb_addr->channel = msg->rsp[3];
++			ipmb_addr->channel = msg->rsp[3] & 0xf;
+ 
++			/* Extract the rest of the message information
++			   from the IPMB header.*/
+ 			recv_msg->user = user;
+ 			recv_msg->recv_type = IPMI_CMD_RECV_TYPE;
+ 			recv_msg->msgid = msg->rsp[7] >> 2;
+ 			recv_msg->msg.netfn = msg->rsp[4] >> 2;
+ 			recv_msg->msg.cmd = msg->rsp[8];
+ 			recv_msg->msg.data = recv_msg->msg_data;
++
++			/* We chop off 10, not 9 bytes because the checksum
++			   at the end also needs to be removed. */
+ 			recv_msg->msg.data_len = msg->rsp_size - 10;
+ 			memcpy(recv_msg->msg_data,
+ 			       &(msg->rsp[9]),
+@@ -1341,6 +2064,169 @@
+ 	return rv;
+ }
+ 
++static int handle_lan_get_msg_rsp(ipmi_smi_t          intf,
++				  struct ipmi_smi_msg *msg)
++{
++	struct ipmi_lan_addr  lan_addr;
++	struct ipmi_recv_msg  *recv_msg;
++	unsigned long         flags;
++
++
++	/* This is 13, not 12, because the response must contain a
++	 * completion code. */
++	if (msg->rsp_size < 13) {
++		/* Message not big enough, just ignore it. */
++		spin_lock_irqsave(&intf->counter_lock, flags);
++		intf->invalid_lan_responses++;
++		spin_unlock_irqrestore(&intf->counter_lock, flags);
++		return 0;
++	}
++
++	if (msg->rsp[2] != 0) {
++		/* An error getting the response, just ignore it. */
++		return 0;
++	}
++
++	lan_addr.addr_type = IPMI_LAN_ADDR_TYPE;
++	lan_addr.session_handle = msg->rsp[4];
++	lan_addr.remote_SWID = msg->rsp[8];
++	lan_addr.local_SWID = msg->rsp[5];
++	lan_addr.channel = msg->rsp[3] & 0x0f;
++	lan_addr.privilege = msg->rsp[3] >> 4;
++	lan_addr.lun = msg->rsp[9] & 3;
++
++	/* It's a response from a remote entity.  Look up the sequence
++	   number and handle the response. */
++	if (intf_find_seq(intf,
++			  msg->rsp[9] >> 2,
++			  msg->rsp[3] & 0x0f,
++			  msg->rsp[10],
++			  (msg->rsp[6] >> 2) & (~1),
++			  (struct ipmi_addr *) &(lan_addr),
++			  &recv_msg))
++	{
++		/* We were unable to find the sequence number,
++		   so just nuke the message. */
++		spin_lock_irqsave(&intf->counter_lock, flags);
++		intf->unhandled_lan_responses++;
++		spin_unlock_irqrestore(&intf->counter_lock, flags);
++		return 0;
++	}
++
++	memcpy(recv_msg->msg_data,
++	       &(msg->rsp[11]),
++	       msg->rsp_size - 11);
++	/* The other fields matched, so no need to set them, except
++           for netfn, which needs to be the response that was
++           returned, not the request value. */
++	recv_msg->msg.netfn = msg->rsp[6] >> 2;
++	recv_msg->msg.data = recv_msg->msg_data;
++	recv_msg->msg.data_len = msg->rsp_size - 12;
++	recv_msg->recv_type = IPMI_RESPONSE_RECV_TYPE;
++	spin_lock_irqsave(&intf->counter_lock, flags);
++	intf->handled_lan_responses++;
++	spin_unlock_irqrestore(&intf->counter_lock, flags);
++	deliver_response(recv_msg);
++
++	return 0;
++}
++
++static int handle_lan_get_msg_cmd(ipmi_smi_t          intf,
++				  struct ipmi_smi_msg *msg)
++{
++	struct cmd_rcvr       *rcvr;
++	int                   rv = 0;
++	unsigned char         netfn;
++	unsigned char         cmd;
++	ipmi_user_t           user = NULL;
++	struct ipmi_lan_addr  *lan_addr;
++	struct ipmi_recv_msg  *recv_msg;
++	unsigned long         flags;
++
++	if (msg->rsp_size < 12) {
++		/* Message not big enough, just ignore it. */
++		spin_lock_irqsave(&intf->counter_lock, flags);
++		intf->invalid_commands++;
++		spin_unlock_irqrestore(&intf->counter_lock, flags);
++		return 0;
++	}
++
++	if (msg->rsp[2] != 0) {
++		/* An error getting the response, just ignore it. */
++		return 0;
++	}
++
++	netfn = msg->rsp[6] >> 2;
++	cmd = msg->rsp[10];
++
++	read_lock(&(intf->cmd_rcvr_lock));
++	
++	if (intf->all_cmd_rcvr) {
++		user = intf->all_cmd_rcvr;
++	} else {
++		/* Find the command/netfn. */
++		list_for_each_entry(rcvr, &(intf->cmd_rcvrs), link) {
++			if ((rcvr->netfn == netfn) && (rcvr->cmd == cmd)) {
++				user = rcvr->user;
++				break;
++			}
++		}
++	}
++	read_unlock(&(intf->cmd_rcvr_lock));
++
++	if (user == NULL) {
++		/* We didn't find a user, deliver an error response. */
++		spin_lock_irqsave(&intf->counter_lock, flags);
++		intf->unhandled_commands++;
++		spin_unlock_irqrestore(&intf->counter_lock, flags);
++
++		rv = 0; /* Don't do anything with these messages, just
++			   allow them to be freed. */
++	} else {
++		/* Deliver the message to the user. */
++		spin_lock_irqsave(&intf->counter_lock, flags);
++		intf->handled_commands++;
++		spin_unlock_irqrestore(&intf->counter_lock, flags);
++
++		recv_msg = ipmi_alloc_recv_msg();
++		if (! recv_msg) {
++			/* We couldn't allocate memory for the
++                           message, so requeue it for handling
++                           later. */
++			rv = 1;
++		} else {
++			/* Extract the source address from the data. */
++			lan_addr = (struct ipmi_lan_addr *) &recv_msg->addr;
++			lan_addr->addr_type = IPMI_LAN_ADDR_TYPE;
++			lan_addr->session_handle = msg->rsp[4];
++			lan_addr->remote_SWID = msg->rsp[8];
++			lan_addr->local_SWID = msg->rsp[5];
++			lan_addr->lun = msg->rsp[9] & 3;
++			lan_addr->channel = msg->rsp[3] & 0xf;
++			lan_addr->privilege = msg->rsp[3] >> 4;
++
++			/* Extract the rest of the message information
++			   from the IPMB header.*/
++			recv_msg->user = user;
++			recv_msg->recv_type = IPMI_CMD_RECV_TYPE;
++			recv_msg->msgid = msg->rsp[9] >> 2;
++			recv_msg->msg.netfn = msg->rsp[6] >> 2;
++			recv_msg->msg.cmd = msg->rsp[10];
++			recv_msg->msg.data = recv_msg->msg_data;
++
++			/* We chop off 12, not 11 bytes because the checksum
++			   at the end also needs to be removed. */
++			recv_msg->msg.data_len = msg->rsp_size - 12;
++			memcpy(recv_msg->msg_data,
++			       &(msg->rsp[11]),
++			       msg->rsp_size - 12);
++			deliver_response(recv_msg);
++		}
++	}
++
++	return rv;
++}
++
+ static void copy_event_into_recv_msg(struct ipmi_recv_msg *recv_msg,
+ 				     struct ipmi_smi_msg  *msg)
+ {
+@@ -1364,9 +2250,8 @@
+ static int handle_read_event_rsp(ipmi_smi_t          intf,
+ 				 struct ipmi_smi_msg *msg)
+ {
+-	struct ipmi_recv_msg *recv_msg;
++	struct ipmi_recv_msg *recv_msg, *recv_msg2;
+ 	struct list_head     msgs;
+-	struct list_head     *entry, *entry2;
+ 	ipmi_user_t          user;
+ 	int                  rv = 0;
+ 	int                  deliver_count = 0;
+@@ -1374,6 +2259,9 @@
+ 
+ 	if (msg->rsp_size < 19) {
+ 		/* Message is too small to be an IPMB event. */
++		spin_lock_irqsave(&intf->counter_lock, flags);
++		intf->invalid_events++;
++		spin_unlock_irqrestore(&intf->counter_lock, flags);
+ 		return 0;
+ 	}
+ 
+@@ -1386,21 +2274,20 @@
+ 
+ 	spin_lock_irqsave(&(intf->events_lock), flags);
+ 
++	spin_lock(&intf->counter_lock);
++	intf->events++;
++	spin_unlock(&intf->counter_lock);
++
+ 	/* Allocate and fill in one message for every user that is getting
+ 	   events. */
+-	list_for_each(entry, &(intf->users)) {
+-		user = list_entry(entry, struct ipmi_user, link);
+-
++	list_for_each_entry(user, &(intf->users), link) {
+ 		if (! user->gets_events)
+ 			continue;
+ 
+ 		recv_msg = ipmi_alloc_recv_msg();
+ 		if (! recv_msg) {
+-			list_for_each_safe(entry, entry2, &msgs) {
+-				recv_msg = list_entry(entry,
+-						      struct ipmi_recv_msg,
+-						      link);
+-				list_del(entry);
++			list_for_each_entry_safe(recv_msg, recv_msg2, &msgs, link) {
++				list_del(&recv_msg->link);
+ 				ipmi_free_recv_msg(recv_msg);
+ 			}
+ 			/* We couldn't allocate memory for the
+@@ -1419,11 +2306,8 @@
+ 
+ 	if (deliver_count) {
+ 		/* Now deliver all the messages. */
+-		list_for_each_safe(entry, entry2, &msgs) {
+-			recv_msg = list_entry(entry,
+-					      struct ipmi_recv_msg,
+-					      link);
+-			list_del(entry);
++		list_for_each_entry_safe(recv_msg, recv_msg2, &msgs, link) {
++			list_del(&recv_msg->link);
+ 			deliver_response(recv_msg);
+ 		}
+ 	} else if (intf->waiting_events_count < MAX_EVENTS_IN_QUEUE) {
+@@ -1443,7 +2327,7 @@
+ 	} else {
+ 		/* There's too many things in the queue, discard this
+ 		   message. */
+-		printk(KERN_WARNING "ipmi: Event queue full, discarding an"
++		printk(KERN_WARNING PFX "Event queue full, discarding an"
+ 		       " incoming event\n");
+ 	}
+ 
+@@ -1458,15 +2342,14 @@
+ {
+ 	struct ipmi_recv_msg *recv_msg;
+ 	int                  found = 0;
+-	struct list_head     *entry;
++	struct ipmi_user     *user;
++	unsigned long        flags;
+ 
+ 	recv_msg = (struct ipmi_recv_msg *) msg->user_data;
+ 
+ 	/* Make sure the user still exists. */
+-	list_for_each(entry, &(intf->users)) {
+-		if (list_entry(entry, struct ipmi_user, link)
+-		    == recv_msg->user)
+-		{
++	list_for_each_entry(user, &(intf->users), link) {
++		if (user == recv_msg->user) {
+ 			/* Found it, so we can deliver it */
+ 			found = 1;
+ 			break;
+@@ -1474,11 +2357,20 @@
+ 	}
+ 
+ 	if (!found) {
++		/* Special handling for NULL users. */
++		if (!recv_msg->user && intf->null_user_handler)
++			intf->null_user_handler(intf, msg);
+ 		/* The user for the message went away, so give up. */
++		spin_lock_irqsave(&intf->counter_lock, flags);
++		intf->unhandled_local_responses++;
++		spin_unlock_irqrestore(&intf->counter_lock, flags);
+ 		ipmi_free_recv_msg(recv_msg);
+ 	} else {
+ 		struct ipmi_system_interface_addr *smi_addr;
+ 
++		spin_lock_irqsave(&intf->counter_lock, flags);
++		intf->handled_local_responses++;
++		spin_unlock_irqrestore(&intf->counter_lock, flags);
+ 		recv_msg->recv_type = IPMI_RESPONSE_RECV_TYPE;
+ 		recv_msg->msgid = msg->msgid;
+ 		smi_addr = ((struct ipmi_system_interface_addr *)
+@@ -1506,11 +2398,64 @@
+ 			       struct ipmi_smi_msg *msg)
+ {
+ 	int requeue;
++	int chan;
+ 
+ 	if (msg->rsp_size < 2) {
+ 		/* Message is too small to be correct. */
++		printk(KERN_WARNING PFX "BMC returned to small a message"
++		       " for netfn %x cmd %x, got %d bytes\n",
++		       (msg->data[0] >> 2) | 1, msg->data[1], msg->rsp_size);
++
++		/* Generate an error response for the message. */
++		msg->rsp[0] = msg->data[0] | (1 << 2);
++		msg->rsp[1] = msg->data[1];
++		msg->rsp[2] = IPMI_ERR_UNSPECIFIED;
++		msg->rsp_size = 3;
++	} else if (((msg->rsp[0] >> 2) != ((msg->data[0] >> 2) | 1))/* Netfn */
++		   || (msg->rsp[1] != msg->data[1]))		  /* Command */
++	{
++		/* The response is not even marginally correct. */
++		printk(KERN_WARNING PFX "BMC returned incorrect response,"
++		       " expected netfn %x cmd %x, got netfn %x cmd %x\n",
++		       (msg->data[0] >> 2) | 1, msg->data[1],
++		       msg->rsp[0] >> 2, msg->rsp[1]);
++
++		/* Generate an error response for the message. */
++		msg->rsp[0] = msg->data[0] | (1 << 2);
++		msg->rsp[1] = msg->data[1];
++		msg->rsp[2] = IPMI_ERR_UNSPECIFIED;
++		msg->rsp_size = 3;
++	}
++
++	if ((msg->rsp[0] == ((IPMI_NETFN_APP_REQUEST|1) << 2))
++	    && (msg->rsp[1] == IPMI_SEND_MSG_CMD)
++	    && (msg->user_data != NULL))
++	{
++		/* It's a response to a response we sent.  For this we
++		   deliver a send message response to the user. */
++		struct ipmi_recv_msg *recv_msg = msg->user_data;
++
+ 		requeue = 0;
+-	} else if (msg->rsp[1] == IPMI_GET_MSG_CMD) {
++		if (msg->rsp_size < 2)
++			/* Message is too small to be correct. */
++			goto out;
++
++		chan = msg->data[2] & 0x0f;
++		if (chan >= IPMI_MAX_CHANNELS)
++			/* Invalid channel number */
++			goto out;
++
++		if (recv_msg) {
++			recv_msg->recv_type = IPMI_RESPONSE_RESPONSE_TYPE;
++			recv_msg->msg.data = recv_msg->msg_data;
++			recv_msg->msg.data_len = 1;
++			recv_msg->msg_data[0] = msg->rsp[2];
++			deliver_response(recv_msg);
++		}
++	} else if ((msg->rsp[0] == ((IPMI_NETFN_APP_REQUEST|1) << 2))
++		   && (msg->rsp[1] == IPMI_GET_MSG_CMD))
++	{
++		/* It's from the receive queue. */
+ #if DEBUG_MSGING
+ 		int m;
+ 		printk("Response:");
+@@ -1518,17 +2463,48 @@
+ 			printk(" %2.2x", msg->rsp[m]);
+ 		printk("\n");
+ #endif
+-		/* It's from the receive queue. */
+-		if (msg->rsp[4] & 0x04) {
+-			/* It's a response, so find the
+-			   requesting message and send it up. */
+-			requeue = handle_get_msg_rsp(intf, msg);
+-		} else {
+-			/* It's a command to the SMS from some other
+-			   entity.  Handle that. */
+-			requeue = handle_get_msg_cmd(intf, msg);
++		chan = msg->rsp[3] & 0xf;
++		if (chan >= IPMI_MAX_CHANNELS) {
++			/* Invalid channel number */
++			requeue = 0;
++			goto out;
+ 		}
+-	} else if (msg->rsp[1] == IPMI_READ_EVENT_MSG_BUFFER_CMD) {
++
++		switch (intf->channels[chan].medium) {
++		case IPMI_CHANNEL_MEDIUM_IPMB:
++			if (msg->rsp[4] & 0x04) {
++				/* It's a response, so find the
++				   requesting message and send it up. */
++				requeue = handle_ipmb_get_msg_rsp(intf, msg);
++			} else {
++				/* It's a command to the SMS from some other
++				   entity.  Handle that. */
++				requeue = handle_ipmb_get_msg_cmd(intf, msg);
++			}
++			break;
++
++		case IPMI_CHANNEL_MEDIUM_8023LAN:
++		case IPMI_CHANNEL_MEDIUM_ASYNC:
++			if (msg->rsp[6] & 0x04) {
++				/* It's a response, so find the
++				   requesting message and send it up. */
++				requeue = handle_lan_get_msg_rsp(intf, msg);
++			} else {
++				/* It's a command to the SMS from some other
++				   entity.  Handle that. */
++				requeue = handle_lan_get_msg_cmd(intf, msg);
++			}
++			break;
++
++		default:
++			/* We don't handle the channel type, so just
++			 * free the message. */
++			requeue = 0;
++		}
++
++	} else if ((msg->rsp[0] == ((IPMI_NETFN_APP_REQUEST|1) << 2))
++		   && (msg->rsp[1] == IPMI_READ_EVENT_MSG_BUFFER_CMD))
++	{
+ 		/* It's an asyncronous event. */
+ 		requeue = handle_read_event_rsp(intf, msg);
+ 	} else {
+@@ -1536,6 +2512,7 @@
+ 		requeue = handle_bmc_rsp(intf, msg);
+ 	}
+ 
++ out:
+ 	return requeue;
+ }
+ 
+@@ -1551,10 +2528,43 @@
+ 	   working on it. */
+ 	read_lock(&(intf->users_lock));
+ 
+-	if ((msg->data_size >= 2) && (msg->data[1] == IPMI_SEND_MSG_CMD)) {
+-		/* This is the local response to a send, start the
+-                   timer for these. */
+-		intf_start_seq_timer(intf, msg->msgid);
++	if ((msg->data_size >= 2)
++	    && (msg->data[0] == (IPMI_NETFN_APP_REQUEST << 2))
++	    && (msg->data[1] == IPMI_SEND_MSG_CMD)
++	    && (msg->user_data == NULL)) {
++		/* This is the local response to a command send, start
++                   the timer for these.  The user_data will not be
++                   NULL if this is a response send, and we will let
++                   response sends just go through. */
++
++		/* Check for errors, if we get certain errors (ones
++                   that mean basically we can try again later), we
++                   ignore them and start the timer.  Otherwise we
++                   report the error immediately. */
++		if ((msg->rsp_size >= 3) && (msg->rsp[2] != 0)
++		    && (msg->rsp[2] != IPMI_NODE_BUSY_ERR)
++		    && (msg->rsp[2] != IPMI_LOST_ARBITRATION_ERR))
++		{
++			int chan = msg->rsp[3] & 0xf;
++
++			/* Got an error sending the message, handle it. */
++			spin_lock_irqsave(&intf->counter_lock, flags);
++			if (chan >= IPMI_MAX_CHANNELS)
++				; /* This shouldn't happen */
++			else if ((intf->channels[chan].medium
++				  == IPMI_CHANNEL_MEDIUM_8023LAN)
++				 || (intf->channels[chan].medium
++				     == IPMI_CHANNEL_MEDIUM_ASYNC))
++				intf->sent_lan_command_errs++;
++			else
++				intf->sent_ipmb_command_errs++;
++			spin_unlock_irqrestore(&intf->counter_lock, flags);
++			intf_err_seq(intf, msg->msgid, msg->rsp[2]);
++		} else {
++			/* The message was sent, start the timer. */
++			intf_start_seq_timer(intf, msg->msgid);
++		}
++
+ 		ipmi_free_smi_msg(msg);
+ 		goto out_unlock;
+ 	}
+@@ -1586,13 +2596,10 @@
+ 
+ void ipmi_smi_watchdog_pretimeout(ipmi_smi_t intf)
+ {
+-	struct list_head *entry;
+-	ipmi_user_t      user;
++	ipmi_user_t user;
+ 
+ 	read_lock(&(intf->users_lock));
+-	list_for_each(entry, &(intf->users)) {
+-		user = list_entry(entry, struct ipmi_user, link);
+-
++	list_for_each_entry(user, &(intf->users), link) {
+ 		if (! user->handler->ipmi_watchdog_pretimeout)
+ 			continue;
+ 
+@@ -1650,10 +2657,9 @@
+ {
+ 	ipmi_smi_t           intf;
+ 	struct list_head     timeouts;
+-	struct ipmi_recv_msg *msg;
+-	struct ipmi_smi_msg  *smi_msg;
++	struct ipmi_recv_msg *msg, *msg2;
++	struct ipmi_smi_msg  *smi_msg, *smi_msg2;
+ 	unsigned long        flags;
+-	struct list_head     *entry, *entry2;
+ 	int                  i, j;
+ 
+ 	INIT_LIST_HEAD(&timeouts);
+@@ -1668,10 +2674,9 @@
+ 
+ 		/* See if any waiting messages need to be processed. */
+ 		spin_lock_irqsave(&(intf->waiting_msgs_lock), flags);
+-		list_for_each_safe(entry, entry2, &(intf->waiting_msgs)) {
+-			smi_msg = list_entry(entry, struct ipmi_smi_msg, link);
++		list_for_each_entry_safe(smi_msg, smi_msg2, &(intf->waiting_msgs), link) {
+ 			if (! handle_new_recv_msg(intf, smi_msg)) {
+-				list_del(entry);
++				list_del(&smi_msg->link);
+ 				ipmi_free_smi_msg(smi_msg);
+ 			} else {
+ 				/* To preserve message order, quit if we
+@@ -1699,6 +2704,15 @@
+ 				ent->inuse = 0;
+ 				msg = ent->recv_msg;
+ 				list_add_tail(&(msg->link), &timeouts);
++				spin_lock(&intf->counter_lock);
++				if (ent->broadcast)
++					intf->timed_out_ipmb_broadcasts++;
++				else if (ent->recv_msg->addr.addr_type
++					 == IPMI_LAN_ADDR_TYPE)
++					intf->timed_out_lan_commands++;
++				else
++					intf->timed_out_ipmb_commands++;
++				spin_unlock(&intf->counter_lock);
+ 			} else {
+ 				/* More retries, send again. */
+ 
+@@ -1708,12 +2722,18 @@
+ 				ent->retries_left--;
+ 				send_from_recv_msg(intf, ent->recv_msg, NULL,
+ 						   j, ent->seqid);
++				spin_lock(&intf->counter_lock);
++				if (ent->recv_msg->addr.addr_type
++				    == IPMI_LAN_ADDR_TYPE)
++					intf->retransmitted_lan_commands++;
++				else
++					intf->retransmitted_ipmb_commands++;
++				spin_unlock(&intf->counter_lock);
+ 			}
+ 		}
+ 		spin_unlock_irqrestore(&(intf->seq_lock), flags);
+ 
+-		list_for_each_safe(entry, entry2, &timeouts) {
+-			msg = list_entry(entry, struct ipmi_recv_msg, link);
++		list_for_each_entry_safe(msg, msg2, &timeouts, link) {
+ 			handle_msg_timeout(msg);
+ 		}
+ 
+@@ -1740,13 +2760,16 @@
+ 
+ static struct timer_list ipmi_timer;
+ 
+-/* Call every 100 ms. */
++/* Call every ~100 ms. */
+ #define IPMI_TIMEOUT_TIME	100
+-#define IPMI_TIMEOUT_JIFFIES	(IPMI_TIMEOUT_TIME/(1000/HZ))
+ 
+-/* Request events from the queue every second.  Hopefully, in the
+-   future, IPMI will add a way to know immediately if an event is
+-   in the queue. */
++/* How many jiffies does it take to get to the timeout time. */
++#define IPMI_TIMEOUT_JIFFIES	((IPMI_TIMEOUT_TIME * HZ) / 1000)
++
++/* Request events from the queue every second (this is the number of
++   IPMI_TIMEOUT_TIMES between event requests).  Hopefully, in the
++   future, IPMI will add a way to know immediately if an event is in
++   the queue and this silliness can go away. */
+ #define IPMI_REQUEST_EV_TIME	(1000 / (IPMI_TIMEOUT_TIME))
+ 
+ static volatile int stop_operation = 0;
+@@ -1789,6 +2812,7 @@
+ 	rv = kmalloc(sizeof(struct ipmi_smi_msg), GFP_ATOMIC);
+ 	if (rv) {
+ 		rv->done = free_smi_msg;
++		rv->user_data = NULL;
+ 		atomic_inc(&smi_msg_inuse_count);
+ 	}
+ 	return rv;
+@@ -1822,18 +2846,48 @@
+ {
+ }
+ 
+-static void send_panic_events(void)
++#ifdef CONFIG_IPMI_PANIC_STRING
++static void event_receiver_fetcher(ipmi_smi_t intf, struct ipmi_smi_msg *msg)
++{
++	if ((msg->rsp[0] == (IPMI_NETFN_SENSOR_EVENT_RESPONSE << 2))
++	    && (msg->rsp[1] == IPMI_GET_EVENT_RECEIVER_CMD)
++	    && (msg->rsp[2] == IPMI_CC_NO_ERROR))
++	{
++		/* A get event receiver command, save it. */
++		intf->event_receiver = msg->rsp[3];
++		intf->event_receiver_lun = msg->rsp[4] & 0x3;
++	}
++}
++
++static void device_id_fetcher(ipmi_smi_t intf, struct ipmi_smi_msg *msg)
++{
++	if ((msg->rsp[0] == (IPMI_NETFN_APP_RESPONSE << 2))
++	    && (msg->rsp[1] == IPMI_GET_DEVICE_ID_CMD)
++	    && (msg->rsp[2] == IPMI_CC_NO_ERROR))
++	{
++		/* A get device id command, save if we are an event
++		   receiver or generator. */
++		intf->local_sel_device = (msg->rsp[8] >> 2) & 1;
++		intf->local_event_generator = (msg->rsp[8] >> 5) & 1;
++	}
++}
++#endif
++
++static void send_panic_events(char *str)
+ {
+ 	struct ipmi_msg                   msg;
+ 	ipmi_smi_t                        intf;
+-	unsigned char                     data[8];
++	unsigned char                     data[16];
+ 	int                               i;
+-	struct ipmi_system_interface_addr addr;
++	struct ipmi_system_interface_addr *si;
++	struct ipmi_addr                  addr;
+ 	struct ipmi_smi_msg               smi_msg;
+ 	struct ipmi_recv_msg              recv_msg;
+ 
+-	addr.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
+-	addr.channel = IPMI_BMC_CHANNEL;
++	si = (struct ipmi_system_interface_addr *) &addr;
++	si->addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
++	si->channel = IPMI_BMC_CHANNEL;
++	si->lun = 0;
+ 
+ 	/* Fill in an event telling that we have failed. */
+ 	msg.netfn = 0x04; /* Sensor or Event. */
+@@ -1846,12 +2900,13 @@
+ 	data[4] = 0x6f; /* Sensor specific, IPMI table 36-1 */
+ 	data[5] = 0xa1; /* Runtime stop OEM bytes 2 & 3. */
+ 
+-	/* These used to have the first three bytes of the panic string,
+-	   but not only is that not terribly useful, it's not available
+-	   any more. */
+-	data[3] = 0;
+-	data[6] = 0;
+-	data[7] = 0;
++	/* Put a few breadcrumbs in.  Hopefully later we can add more things
++	   to make the panic events more useful. */
++	if (str) {
++		data[3] = str[0];
++		data[6] = str[1];
++		data[7] = str[2];
++	}
+ 
+ 	smi_msg.done = dummy_smi_done_handler;
+ 	recv_msg.done = dummy_recv_done_handler;
+@@ -1862,18 +2917,151 @@
+ 		if (intf == NULL)
+ 			continue;
+ 
++		/* Send the event announcing the panic. */
+ 		intf->handlers->set_run_to_completion(intf->send_info, 1);
+ 		i_ipmi_request(NULL,
+ 			       intf,
+-			       (struct ipmi_addr *) &addr,
++			       &addr,
+ 			       0,
+ 			       &msg,
++			       NULL,
+ 			       &smi_msg,
+ 			       &recv_msg,
+ 			       0,
+ 			       intf->my_address,
+-			       intf->my_lun);
++			       intf->my_lun,
++			       0, 1); /* Don't retry, and don't wait. */
+ 	}
++
++#ifdef CONFIG_IPMI_PANIC_STRING
++	/* On every interface, dump a bunch of OEM event holding the
++	   string. */
++	if (!str) 
++		return;
++
++	for (i=0; i<MAX_IPMI_INTERFACES; i++) {
++		char                  *p = str;
++		struct ipmi_ipmb_addr *ipmb;
++		int                   j;
++
++		intf = ipmi_interfaces[i];
++		if (intf == NULL)
++			continue;
++
++		/* First job here is to figure out where to send the
++		   OEM events.  There's no way in IPMI to send OEM
++		   events using an event send command, so we have to
++		   find the SEL to put them in and stick them in
++		   there. */
++
++		/* Get capabilities from the get device id. */
++		intf->local_sel_device = 0;
++		intf->local_event_generator = 0;
++		intf->event_receiver = 0;
++
++		/* Request the device info from the local MC. */
++		msg.netfn = IPMI_NETFN_APP_REQUEST;
++		msg.cmd = IPMI_GET_DEVICE_ID_CMD;
++		msg.data = NULL;
++		msg.data_len = 0;
++		intf->null_user_handler = device_id_fetcher;
++		i_ipmi_request(NULL,
++			       intf,
++			       &addr,
++			       0,
++			       &msg,
++			       NULL,
++			       &smi_msg,
++			       &recv_msg,
++			       0,
++			       intf->my_address,
++			       intf->my_lun,
++			       0, 1); /* Don't retry, and don't wait. */
++
++		if (intf->local_event_generator) {
++			/* Request the event receiver from the local MC. */
++			msg.netfn = IPMI_NETFN_SENSOR_EVENT_REQUEST;
++			msg.cmd = IPMI_GET_EVENT_RECEIVER_CMD;
++			msg.data = NULL;
++			msg.data_len = 0;
++			intf->null_user_handler = event_receiver_fetcher;
++			i_ipmi_request(NULL,
++				       intf,
++				       &addr,
++				       0,
++				       &msg,
++				       NULL,
++				       &smi_msg,
++				       &recv_msg,
++				       0,
++				       intf->my_address,
++				       intf->my_lun,
++				       0, 1); /* no retry, and no wait. */
++		}
++		intf->null_user_handler = NULL;
++
++		/* Validate the event receiver.  The low bit must not
++		   be 1 (it must be a valid IPMB address), it cannot
++		   be zero, and it must not be my address. */
++                if (((intf->event_receiver & 1) == 0)
++		    && (intf->event_receiver != 0)
++		    && (intf->event_receiver != intf->my_address))
++		{
++			/* The event receiver is valid, send an IPMB
++			   message. */
++			ipmb = (struct ipmi_ipmb_addr *) &addr;
++			ipmb->addr_type = IPMI_IPMB_ADDR_TYPE;
++			ipmb->channel = 0; /* FIXME - is this right? */
++			ipmb->lun = intf->event_receiver_lun;
++			ipmb->slave_addr = intf->event_receiver;
++		} else if (intf->local_sel_device) {
++			/* The event receiver was not valid (or was
++			   me), but I am an SEL device, just dump it
++			   in my SEL. */
++			si = (struct ipmi_system_interface_addr *) &addr;
++			si->addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
++			si->channel = IPMI_BMC_CHANNEL;
++			si->lun = 0;
++		} else
++			continue; /* No where to send the event. */
++
++		
++		msg.netfn = IPMI_NETFN_STORAGE_REQUEST; /* Storage. */
++		msg.cmd = IPMI_ADD_SEL_ENTRY_CMD;
++		msg.data = data;
++		msg.data_len = 16;
++
++		j = 0;
++		while (*p) {
++			int size = strlen(p);
++
++			if (size > 11)
++				size = 11;
++			data[0] = 0;
++			data[1] = 0;
++			data[2] = 0xf0; /* OEM event without timestamp. */
++			data[3] = intf->my_address;
++			data[4] = j++; /* sequence # */
++			/* Always give 11 bytes, so strncpy will fill
++			   it with zeroes for me. */
++			strncpy(data+5, p, 11);
++			p += size;
++
++			i_ipmi_request(NULL,
++				       intf,
++				       &addr,
++				       0,
++				       &msg,
++				       NULL,
++				       &smi_msg,
++				       &recv_msg,
++				       0,
++				       intf->my_address,
++				       intf->my_lun,
++				       0, 1); /* no retry, and no wait. */
++		}
++	}	
++#endif /* CONFIG_IPMI_PANIC_STRING */
+ }
+ #endif /* CONFIG_IPMI_PANIC_EVENT */
+ 
+@@ -1900,7 +3088,7 @@
+ 	}
+ 
+ #ifdef CONFIG_IPMI_PANIC_EVENT
+-	send_panic_events();
++	send_panic_events(ptr);
+ #endif
+ 
+ 	return NOTIFY_DONE;
+@@ -1912,7 +3100,6 @@
+ 	200   /* priority: INT_MAX >= x >= 0 */
+ };
+ 
+-
+ static __init int ipmi_init_msghandler(void)
+ {
+ 	int i;
+@@ -1920,10 +3107,21 @@
+ 	if (initialized)
+ 		return 0;
+ 
++	printk(KERN_INFO "ipmi message handler version "
++	       IPMI_MSGHANDLER_VERSION "\n");
++
+ 	for (i=0; i<MAX_IPMI_INTERFACES; i++) {
+ 		ipmi_interfaces[i] = NULL;
+ 	}
+ 
++	proc_ipmi_root = proc_mkdir("ipmi", 0);
++	if (!proc_ipmi_root) {
++	    printk(KERN_ERR PFX "Unable to create IPMI proc dir\n");
++	    return -ENOMEM;
++	}
++
++	proc_ipmi_root->owner = THIS_MODULE;
++
+ 	init_timer(&ipmi_timer);
+ 	ipmi_timer.data = 0;
+ 	ipmi_timer.function = ipmi_timeout;
+@@ -1934,8 +3132,6 @@
+ 
+ 	initialized = 1;
+ 
+-	printk(KERN_INFO "ipmi: message handler initialized\n");
+-
+ 	return 0;
+ }
+ 
+@@ -1955,19 +3151,22 @@
+ 	   problems with race conditions removing the timer here. */
+ 	stop_operation = 1;
+ 	while (!timer_stopped) {
++		set_current_state(TASK_UNINTERRUPTIBLE);
+ 		schedule_timeout(1);
+ 	}
+ 
++	remove_proc_entry(proc_ipmi_root->name, &proc_root);
++
+ 	initialized = 0;
+ 
+ 	/* Check for buffer leaks. */
+ 	count = atomic_read(&smi_msg_inuse_count);
+ 	if (count != 0)
+-		printk("ipmi_msghandler: SMI message count %d at exit\n",
++		printk(KERN_WARNING PFX "SMI message count %d at exit\n",
+ 		       count);
+ 	count = atomic_read(&recv_msg_inuse_count);
+ 	if (count != 0)
+-		printk("ipmi_msghandler: recv message count %d at exit\n",
++		printk(KERN_WARNING PFX "recv message count %d at exit\n",
+ 		       count);
+ }
+ module_exit(cleanup_ipmi);
+@@ -1980,8 +3179,10 @@
+ EXPORT_SYMBOL(ipmi_destroy_user);
+ EXPORT_SYMBOL(ipmi_get_version);
+ EXPORT_SYMBOL(ipmi_request);
++EXPORT_SYMBOL(ipmi_request_settime);
+ EXPORT_SYMBOL(ipmi_request_supply_msgs);
+ EXPORT_SYMBOL(ipmi_request_with_source);
++EXPORT_SYMBOL(ipmi_poll_interface);
+ EXPORT_SYMBOL(ipmi_register_smi);
+ EXPORT_SYMBOL(ipmi_unregister_smi);
+ EXPORT_SYMBOL(ipmi_register_for_cmd);
+@@ -2001,3 +3202,5 @@
+ EXPORT_SYMBOL(ipmi_get_my_address);
+ EXPORT_SYMBOL(ipmi_set_my_LUN);
+ EXPORT_SYMBOL(ipmi_get_my_LUN);
++EXPORT_SYMBOL(ipmi_smi_add_proc_entry);
++EXPORT_SYMBOL(ipmi_user_set_run_to_completion);
+Index: linux-ipmi/drivers/char/ipmi/ipmi_poweroff.c
+===================================================================
+--- linux-ipmi.orig/drivers/char/ipmi/ipmi_poweroff.c	1969-12-31 18:00:00.000000000 -0600
++++ linux-ipmi/drivers/char/ipmi/ipmi_poweroff.c	2004-08-13 08:06:49.000000000 -0500
+@@ -0,0 +1,543 @@
++/*
++ * ipmi_poweroff.c
++ *
++ * MontaVista IPMI Poweroff extension to sys_reboot
++ *
++ * Author: MontaVista Software, Inc.
++ *         Steven Dake <sdake@mvista.com>
++ *         Corey Minyard <cminyard@mvista.com>
++ *         source@mvista.com
++ *
++ * Copyright 2002,2004 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 <asm/semaphore.h>
++#include <linux/kdev_t.h>
++#include <linux/module.h>
++#include <linux/string.h>
++#include <linux/ipmi.h>
++#include <linux/ipmi_smi.h>
++
++#define PFX "IPMI poweroff: "
++#define IPMI_POWEROFF_VERSION	"v33"
++
++/* Where to we insert our poweroff function? */
++extern void (*pm_power_off)(void);
++
++/* Stuff from the get device id command. */
++unsigned int mfg_id;
++unsigned int prod_id;
++unsigned char capabilities;
++
++/* We use our own messages for this operation, we don't let the system
++   allocate them, since we may be in a panic situation.  The whole
++   thing is single-threaded, anyway, so multiple messages are not
++   required. */
++static void dummy_smi_free(struct ipmi_smi_msg *msg)
++{
++}
++static void dummy_recv_free(struct ipmi_recv_msg *msg)
++{
++}
++static struct ipmi_smi_msg halt_smi_msg =
++{
++	.done = dummy_smi_free
++};
++static struct ipmi_recv_msg halt_recv_msg =
++{
++	.done = dummy_recv_free
++};
++
++
++/*
++ * Code to send a message and wait for the reponse.
++ */
++
++static void receive_handler(struct ipmi_recv_msg *recv_msg, void *handler_data)
++{
++	struct semaphore *sem = recv_msg->user_msg_data;
++
++	if (sem)
++		up(sem);
++}
++
++static struct ipmi_user_hndl ipmi_poweroff_handler =
++{
++	ipmi_recv_hndl : receive_handler
++};
++
++
++static int ipmi_request_wait_for_response(ipmi_user_t          user,
++					  struct ipmi_addr     *addr,
++					  struct ipmi_msg      *send_msg)
++{
++	int              rv;
++	struct semaphore sem;
++
++	sema_init (&sem, 0);
++
++	rv = ipmi_request_supply_msgs(user, addr, 0, send_msg, &sem,
++				      &halt_smi_msg, &halt_recv_msg, 0);
++	if (rv)
++		return rv;
++
++	down (&sem);
++
++	return halt_recv_msg.msg.data[0];
++}
++
++/* We are in run-to-completion mode, no semaphore is desired. */
++static int ipmi_request_in_rc_mode(ipmi_user_t          user,
++				   struct ipmi_addr     *addr,
++				   struct ipmi_msg      *send_msg)
++{
++	int              rv;
++
++	rv = ipmi_request_supply_msgs(user, addr, 0, send_msg, NULL,
++				      &halt_smi_msg, &halt_recv_msg, 0);
++	if (rv)
++		return rv;
++
++	return halt_recv_msg.msg.data[0];
++}
++
++/*
++ * ATCA Support
++ */
++
++#define IPMI_NETFN_ATCA			0x2c
++#define IPMI_ATCA_SET_POWER_CMD		0x11
++#define IPMI_ATCA_GET_ADDR_INFO_CMD	0x01
++#define IPMI_PICMG_ID			0
++
++static int ipmi_atca_detect (ipmi_user_t user)
++{
++	struct ipmi_system_interface_addr smi_addr;
++	struct ipmi_msg                   send_msg;
++	int                               rv;
++	unsigned char                     data[1];
++
++        /*
++         * Configure IPMI address for local access
++         */
++        smi_addr.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
++        smi_addr.channel = IPMI_BMC_CHANNEL;
++        smi_addr.lun = 0;
++
++	/*
++	 * Use get address info to check and see if we are ATCA
++	 */
++	send_msg.netfn = IPMI_NETFN_ATCA;
++	send_msg.cmd = IPMI_ATCA_GET_ADDR_INFO_CMD;
++	data[0] = IPMI_PICMG_ID;
++	send_msg.data = data;
++	send_msg.data_len = sizeof(data);
++	rv = ipmi_request_wait_for_response(user,
++					    (struct ipmi_addr *) &smi_addr,
++					    &send_msg);
++	return !rv;
++}
++
++static void ipmi_poweroff_atca (ipmi_user_t user)
++{
++	struct ipmi_system_interface_addr smi_addr;
++	struct ipmi_msg                   send_msg;
++	int                               rv;
++	unsigned char                     data[4];
++
++        /*
++         * Configure IPMI address for local access
++         */
++        smi_addr.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
++        smi_addr.channel = IPMI_BMC_CHANNEL;
++        smi_addr.lun = 0;
++
++	printk(KERN_INFO PFX "Powering down via ATCA power command\n");
++
++	/*
++	 * Power down
++	 */
++	send_msg.netfn = IPMI_NETFN_ATCA;
++	send_msg.cmd = IPMI_ATCA_SET_POWER_CMD;
++	data[0] = IPMI_PICMG_ID;
++	data[1] = 0; /* FRU id */
++	data[2] = 0; /* Power Level */
++	data[3] = 0; /* Don't change saved presets */
++	send_msg.data = data;
++	send_msg.data_len = sizeof (data);
++	rv = ipmi_request_in_rc_mode(user,
++				     (struct ipmi_addr *) &smi_addr,
++				     &send_msg);
++	if (rv) {
++		printk(KERN_ERR PFX "Unable to send ATCA powerdown message,"
++		       " IPMI error 0x%x\n", rv);
++		goto out;
++	}
++
++ out:
++	return;
++}
++
++/*
++ * CPI1 Support
++ */
++
++#define IPMI_NETFN_OEM_1				0xf8
++#define OEM_GRP_CMD_SET_RESET_STATE		0x84
++#define OEM_GRP_CMD_SET_POWER_STATE		0x82
++#define IPMI_NETFN_OEM_8				0xf8
++#define OEM_GRP_CMD_REQUEST_HOTSWAP_CTRL	0x80
++#define OEM_GRP_CMD_GET_SLOT_GA			0xa3
++#define IPMI_NETFN_SENSOR_EVT			0x10
++#define IPMI_CMD_GET_EVENT_RECEIVER		0x01
++
++#define IPMI_CPI1_PRODUCT_ID		0x000157
++#define IPMI_CPI1_MANUFACTURER_ID	0x0108
++
++static int ipmi_cpi1_detect (ipmi_user_t user)
++{
++	return ((mfg_id == IPMI_CPI1_MANUFACTURER_ID)
++		&& (prod_id == IPMI_CPI1_PRODUCT_ID));
++}
++
++static void ipmi_poweroff_cpi1 (ipmi_user_t user)
++{
++	struct ipmi_system_interface_addr smi_addr;
++	struct ipmi_ipmb_addr             ipmb_addr;
++	struct ipmi_msg                   send_msg;
++	int                               rv;
++	unsigned char                     data[1];
++	int                               slot;
++	unsigned char                     hotswap_ipmb;
++	unsigned char                     aer_addr;
++	unsigned char                     aer_lun;
++
++        /*
++         * Configure IPMI address for local access
++         */
++        smi_addr.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
++        smi_addr.channel = IPMI_BMC_CHANNEL;
++        smi_addr.lun = 0;
++
++	printk(KERN_INFO PFX "Powering down via CPI1 power command\n");
++
++	/*
++	 * Get IPMI ipmb address
++	 */
++	send_msg.netfn = IPMI_NETFN_OEM_8 >> 2;
++	send_msg.cmd = OEM_GRP_CMD_GET_SLOT_GA;
++	send_msg.data = NULL;
++	send_msg.data_len = 0;
++	rv = ipmi_request_in_rc_mode(user,
++				     (struct ipmi_addr *) &smi_addr,
++				     &send_msg);
++	if (rv)
++		goto out;
++	slot = halt_recv_msg.msg.data[1];
++	hotswap_ipmb = (slot > 9) ? (0xb0 + 2 * slot) : (0xae + 2 * slot);
++
++	/*
++	 * Get active event receiver
++	 */
++	send_msg.netfn = IPMI_NETFN_SENSOR_EVT >> 2;
++	send_msg.cmd = IPMI_CMD_GET_EVENT_RECEIVER;
++	send_msg.data = NULL;
++	send_msg.data_len = 0;
++	rv = ipmi_request_in_rc_mode(user,
++				     (struct ipmi_addr *) &smi_addr,
++				     &send_msg);
++	if (rv)
++		goto out;
++	aer_addr = halt_recv_msg.msg.data[1];
++	aer_lun = halt_recv_msg.msg.data[2];
++
++	/*
++	 * Setup IPMB address target instead of local target
++	 */
++	ipmb_addr.addr_type = IPMI_IPMB_ADDR_TYPE;
++	ipmb_addr.channel = 0;
++	ipmb_addr.slave_addr = aer_addr;
++	ipmb_addr.lun = aer_lun;
++
++	/*
++	 * Send request hotswap control to remove blade from dpv
++	 */
++	send_msg.netfn = IPMI_NETFN_OEM_8 >> 2;
++	send_msg.cmd = OEM_GRP_CMD_REQUEST_HOTSWAP_CTRL;
++	send_msg.data = &hotswap_ipmb;
++	send_msg.data_len = 1;
++	ipmi_request_in_rc_mode(user,
++				(struct ipmi_addr *) &ipmb_addr,
++				&send_msg);
++
++	/*
++	 * Set reset asserted
++	 */
++	send_msg.netfn = IPMI_NETFN_OEM_1 >> 2;
++	send_msg.cmd = OEM_GRP_CMD_SET_RESET_STATE;
++	send_msg.data = data;
++	data[0] = 1; /* Reset asserted state */
++	send_msg.data_len = 1;
++	rv = ipmi_request_in_rc_mode(user,
++				     (struct ipmi_addr *) &smi_addr,
++				     &send_msg);
++	if (rv)
++		goto out;
++
++	/*
++	 * Power down
++	 */
++	send_msg.netfn = IPMI_NETFN_OEM_1 >> 2;
++	send_msg.cmd = OEM_GRP_CMD_SET_POWER_STATE;
++	send_msg.data = data;
++	data[0] = 1; /* Power down state */
++	send_msg.data_len = 1;
++	rv = ipmi_request_in_rc_mode(user,
++				     (struct ipmi_addr *) &smi_addr,
++				     &send_msg);
++	if (rv)
++		goto out;
++
++ out:
++	return;
++}
++
++/*
++ * Standard chassis support
++ */
++
++#define IPMI_NETFN_CHASSIS_REQUEST	0
++#define IPMI_CHASSIS_CONTROL_CMD	0x02
++
++static int ipmi_chassis_detect (ipmi_user_t user)
++{
++	/* Chassis support, use it. */
++	return (capabilities & 0x80);
++}
++
++static void ipmi_poweroff_chassis (ipmi_user_t user)
++{
++	struct ipmi_system_interface_addr smi_addr;
++	struct ipmi_msg                   send_msg;
++	int                               rv;
++	unsigned char                     data[1];
++
++        /*
++         * Configure IPMI address for local access
++         */
++        smi_addr.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
++        smi_addr.channel = IPMI_BMC_CHANNEL;
++        smi_addr.lun = 0;
++
++	printk(KERN_INFO PFX "Powering down via IPMI chassis control command\n");
++
++	/*
++	 * Power down
++	 */
++	send_msg.netfn = IPMI_NETFN_CHASSIS_REQUEST;
++	send_msg.cmd = IPMI_CHASSIS_CONTROL_CMD;
++	data[0] = 0; /* Power down */
++	send_msg.data = data;
++	send_msg.data_len = sizeof(data);
++	rv = ipmi_request_in_rc_mode(user,
++				     (struct ipmi_addr *) &smi_addr,
++				     &send_msg);
++	if (rv) {
++		printk(KERN_ERR PFX "Unable to send chassis powerdown message,"
++		       " IPMI error 0x%x\n", rv);
++		goto out;
++	}
++
++ out:
++	return;
++}
++
++
++/* Table of possible power off functions. */
++struct poweroff_function {
++	char *platform_type;
++	int  (*detect)(ipmi_user_t user);
++	void (*poweroff_func)(ipmi_user_t user);
++};
++
++static struct poweroff_function poweroff_functions[] = {
++	{ "ATCA",    ipmi_atca_detect, ipmi_poweroff_atca },
++	{ "CPI1",    ipmi_cpi1_detect, ipmi_poweroff_cpi1 },
++	/* Chassis should generally be last, other things should override
++	   it. */
++	{ "chassis", ipmi_chassis_detect, ipmi_poweroff_chassis },
++};
++#define NUM_PO_FUNCS (sizeof(poweroff_functions) \
++		      / sizeof(struct poweroff_function))
++
++
++/* Our local state. */
++static int ready = 0;
++static ipmi_user_t ipmi_user;
++static void (*specific_poweroff_func)(ipmi_user_t user) = NULL;
++
++/* Holds the old poweroff function so we can restore it on removal. */
++static void (*old_poweroff_func)(void);
++
++
++/* Called on a powerdown request. */
++static void ipmi_poweroff_function (void)
++{
++	if (!ready)
++		return;
++
++	/* Use run-to-completion mode, since interrupts may be off. */
++	ipmi_user_set_run_to_completion(ipmi_user, 1);
++	specific_poweroff_func(ipmi_user);
++	ipmi_user_set_run_to_completion(ipmi_user, 0);
++}
++
++/* Wait for an IPMI interface to be installed, the first one installed
++   will be grabbed by this code and used to perform the powerdown. */
++static void ipmi_po_new_smi(int if_num)
++{
++	struct ipmi_system_interface_addr smi_addr;
++	struct ipmi_msg                   send_msg;
++	int                               rv;
++	int                               i;
++
++	if (ready)
++		return;
++
++	rv = ipmi_create_user(if_num, &ipmi_poweroff_handler, 0, &ipmi_user);
++	if (rv) {
++		printk(KERN_ERR PFX "could not create IPMI user, error %d\n",
++		       rv);
++		return;
++	}
++
++        /*
++         * Do a get device ide and store some results, since this is
++	 * used by several functions.
++         */
++        smi_addr.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
++        smi_addr.channel = IPMI_BMC_CHANNEL;
++        smi_addr.lun = 0;
++
++	send_msg.netfn = IPMI_NETFN_APP_REQUEST;
++	send_msg.cmd = IPMI_GET_DEVICE_ID_CMD;
++	send_msg.data = NULL;
++	send_msg.data_len = 0;
++	rv = ipmi_request_wait_for_response(ipmi_user,
++					    (struct ipmi_addr *) &smi_addr,
++					    &send_msg);
++	if (rv) {
++		printk(KERN_ERR PFX "Unable to send IPMI get device id info,"
++		       " IPMI error 0x%x\n", rv);
++		goto out_err;
++	}
++
++	if (halt_recv_msg.msg.data_len < 12) {
++		printk(KERN_ERR PFX "(chassis) IPMI get device id info too,"
++		       " short, was %d bytes, needed %d bytes\n",
++		       halt_recv_msg.msg.data_len, 12);
++		goto out_err;
++	}
++
++	mfg_id = (halt_recv_msg.msg.data[7]
++		  | (halt_recv_msg.msg.data[8] << 8)
++		  | (halt_recv_msg.msg.data[9] << 16));
++	prod_id = (halt_recv_msg.msg.data[10]
++		   | (halt_recv_msg.msg.data[11] << 8));
++	capabilities = halt_recv_msg.msg.data[6];
++
++
++	/* Scan for a poweroff method */
++	for (i=0; i<NUM_PO_FUNCS; i++) {
++		if (poweroff_functions[i].detect(ipmi_user))
++			goto found;
++	}
++
++ out_err:
++	printk(KERN_ERR PFX "Unable to find a poweroff function that"
++	       " will work, giving up\n");
++	ipmi_destroy_user(ipmi_user);
++	return;
++
++ found:
++	printk(KERN_INFO PFX "Found a %s style poweroff function\n",
++	       poweroff_functions[i].platform_type);
++	specific_poweroff_func = poweroff_functions[i].poweroff_func;
++	old_poweroff_func = pm_power_off;
++	pm_power_off = ipmi_poweroff_function;
++	ready = 1;
++}
++
++static void ipmi_po_smi_gone(int if_num)
++{
++	/* This can never be called, because once poweroff driver is
++	   registered, the interface can't go away until the power
++	   driver is unregistered. */
++}
++
++static struct ipmi_smi_watcher smi_watcher =
++{
++	.owner    = THIS_MODULE,
++	.new_smi  = ipmi_po_new_smi,
++	.smi_gone = ipmi_po_smi_gone
++};
++
++
++/*
++ * Startup and shutdown functions.
++ */
++static int ipmi_poweroff_init (void)
++{
++	int rv;
++
++	printk ("Copyright (C) 2004 MontaVista Software -"
++		" IPMI Powerdown via sys_reboot version "
++		IPMI_POWEROFF_VERSION ".\n");
++
++	rv = ipmi_smi_watcher_register(&smi_watcher);
++	if (rv)
++		printk(KERN_ERR PFX "Unable to register SMI watcher: %d\n", rv);
++
++	return rv;
++}
++
++#ifdef MODULE
++static __exit void ipmi_poweroff_cleanup(void)
++{
++	int rv;
++
++	ipmi_smi_watcher_unregister(&smi_watcher);
++
++	if (ready) {
++		rv = ipmi_destroy_user(ipmi_user);
++		if (rv)
++			printk(KERN_ERR PFX "could not cleanup the IPMI"
++			       " user: 0x%x\n", rv);
++		pm_power_off = old_poweroff_func;
++	}
++}
++module_exit(ipmi_poweroff_cleanup);
++#endif
++
++module_init(ipmi_poweroff_init);
++MODULE_LICENSE("GPL");
+Index: linux-ipmi/drivers/char/ipmi/ipmi_si.c
+===================================================================
+--- linux-ipmi.orig/drivers/char/ipmi/ipmi_si.c	1969-12-31 18:00:00.000000000 -0600
++++ linux-ipmi/drivers/char/ipmi/ipmi_si.c	2004-08-19 07:58:33.000000000 -0500
+@@ -0,0 +1,2360 @@
++/*
++ * ipmi_si.c
++ *
++ * The interface to the IPMI driver for the system interfaces (KCS, SMIC,
++ * BT in the future).
++ *
++ * Author: MontaVista Software, Inc.
++ *         Corey Minyard <minyard@mvista.com>
++ *         source@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.
++ *
++ *
++ *  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.
++ */
++
++/*
++ * This file holds the "policy" for the interface to the SMI state
++ * machine.  It does the configuration, handles timers and interrupts,
++ * and drives the real SMI state machine.
++ */
++
++#include <linux/config.h>
++#include <linux/module.h>
++#include <asm/system.h>
++#include <linux/sched.h>
++#include <linux/timer.h>
++#include <linux/errno.h>
++#include <linux/spinlock.h>
++#include <linux/slab.h>
++#include <linux/delay.h>
++#include <linux/list.h>
++#include <linux/pci.h>
++#include <linux/ioport.h>
++#ifdef CONFIG_HIGH_RES_TIMERS
++#include <linux/hrtime.h>
++# if defined(schedule_next_int)
++/* Old high-res timer code, do translations. */
++#  define get_arch_cycles(a) quick_update_jiffies_sub(a) 
++#  define arch_cycles_per_jiffy cycles_per_jiffies
++# endif
++static inline void add_usec_to_timer(struct timer_list *t, long v)
++{
++	t->sub_expires += nsec_to_arch_cycle(v * 1000);
++	while (t->sub_expires >= arch_cycles_per_jiffy)
++	{
++		t->expires++;
++		t->sub_expires -= arch_cycles_per_jiffy;
++	}
++}
++#endif
++#include <linux/interrupt.h>
++#include <linux/ipmi_smi.h>
++#include <asm/io.h>
++#include "ipmi_si_sm.h"
++#include <linux/init.h>
++
++#define IPMI_SI_VERSION "v33"
++
++/* Measure times between events in the driver. */
++#undef DEBUG_TIMING
++
++/* Call every 10 ms when nothing is going on. */
++#define SI_TIMEOUT_TIME_USEC	10000
++#define SI_USEC_PER_JIFFY	(1000000/HZ)
++#define SI_TIMEOUT_JIFFIES	(SI_TIMEOUT_TIME_USEC/SI_USEC_PER_JIFFY)
++#define SI_SHORT_TIMEOUT_USEC	250 /* .25ms when the SM request a
++                                       short timeout */
++
++enum si_intf_state {
++	SI_NORMAL,
++	SI_GETTING_FLAGS,
++	SI_GETTING_EVENTS,
++	SI_CLEARING_FLAGS,
++	SI_CLEARING_FLAGS_THEN_SET_IRQ,
++	SI_GETTING_MESSAGES,
++	SI_ENABLE_INTERRUPTS1,
++	SI_ENABLE_INTERRUPTS2
++	/* FIXME - add watchdog stuff. */
++};
++
++enum si_type {
++	SI_KCS, SI_SMIC, SI_BT
++};
++
++struct smi_info
++{
++	ipmi_smi_t             intf;
++	struct si_sm_data      *si_sm;
++	struct si_sm_handlers  *handlers;
++	enum si_type           si_type;
++	spinlock_t             si_lock;
++	spinlock_t             msg_lock;
++	struct list_head       xmit_msgs;
++	struct list_head       hp_xmit_msgs;
++	struct ipmi_smi_msg    *curr_msg;
++	enum si_intf_state     si_state;
++
++	/* Used to handle the various types of I/O that can occur with
++           IPMI */
++	struct si_sm_io io;
++	int (*io_setup)(struct smi_info *info);
++	void (*io_cleanup)(struct smi_info *info);
++	int (*irq_setup)(struct smi_info *info);
++	void (*irq_cleanup)(struct smi_info *info);
++	unsigned int io_size;
++
++	/* Flags from the last GET_MSG_FLAGS command, used when an ATTN
++	   is set to hold the flags until we are done handling everything
++	   from the flags. */
++#define RECEIVE_MSG_AVAIL	0x01
++#define EVENT_MSG_BUFFER_FULL	0x02
++#define WDT_PRE_TIMEOUT_INT	0x08
++	unsigned char       msg_flags;
++
++	/* If set to true, this will request events the next time the
++	   state machine is idle. */
++	atomic_t            req_events;
++
++	/* If true, run the state machine to completion on every send
++	   call.  Generally used after a panic to make sure stuff goes
++	   out. */
++	int                 run_to_completion;
++
++	/* The I/O port of an SI interface. */
++	int                 port;
++
++	/* The space between start addresses of the two ports.  For
++	   instance, if the first port is 0xca2 and the spacing is 4, then
++	   the second port is 0xca6. */
++	unsigned int        spacing;
++
++	/* zero if no irq; */
++	int                 irq;
++
++	/* The timer for this si. */
++	struct timer_list   si_timer;
++
++	/* The time (in jiffies) the last timeout occurred at. */
++	unsigned long       last_timeout_jiffies;
++
++	/* Used to gracefully stop the timer without race conditions. */
++	volatile int        stop_operation;
++	volatile int        timer_stopped;
++
++	/* The driver will disable interrupts when it gets into a
++	   situation where it cannot handle messages due to lack of
++	   memory.  Once that situation clears up, it will re-enable
++	   interrupts. */
++	int interrupt_disabled;
++
++	unsigned char ipmi_si_dev_rev;
++	unsigned char ipmi_si_fw_rev_major;
++	unsigned char ipmi_si_fw_rev_minor;
++	unsigned char ipmi_version_major;
++	unsigned char ipmi_version_minor;
++
++	/* Counters and things for the proc filesystem. */
++	spinlock_t count_lock;
++	unsigned long short_timeouts;
++	unsigned long long_timeouts;
++	unsigned long timeout_restarts;
++	unsigned long idles;
++	unsigned long interrupts;
++	unsigned long attentions;
++	unsigned long flag_fetches;
++	unsigned long hosed_count;
++	unsigned long complete_transactions;
++	unsigned long events;
++	unsigned long watchdog_pretimeouts;
++	unsigned long incoming_messages;
++};
++
++static void si_restart_short_timer(struct smi_info *smi_info);
++
++static void deliver_recv_msg(struct smi_info *smi_info,
++			     struct ipmi_smi_msg *msg)
++{
++	/* Deliver the message to the upper layer with the lock
++           released. */
++	spin_unlock(&(smi_info->si_lock));
++	ipmi_smi_msg_received(smi_info->intf, msg);
++	spin_lock(&(smi_info->si_lock));
++}
++
++static void return_hosed_msg(struct smi_info *smi_info)
++{
++	struct ipmi_smi_msg *msg = smi_info->curr_msg;
++
++	/* Make it a reponse */
++	msg->rsp[0] = msg->data[0] | 4;
++	msg->rsp[1] = msg->data[1];
++	msg->rsp[2] = 0xFF; /* Unknown error. */
++	msg->rsp_size = 3;
++			
++	smi_info->curr_msg = NULL;
++	deliver_recv_msg(smi_info, msg);
++}
++
++static enum si_sm_result start_next_msg(struct smi_info *smi_info)
++{
++	int              rv;
++	struct list_head *entry = NULL;
++#ifdef DEBUG_TIMING
++	struct timeval t;
++#endif
++
++	/* No need to save flags, we aleady have interrupts off and we
++	   already hold the SMI lock. */
++	spin_lock(&(smi_info->msg_lock));
++	
++	/* Pick the high priority queue first. */
++	if (! list_empty(&(smi_info->hp_xmit_msgs))) {
++		entry = smi_info->hp_xmit_msgs.next;
++	} else if (! list_empty(&(smi_info->xmit_msgs))) {
++		entry = smi_info->xmit_msgs.next;
++	}
++
++	if (!entry) {
++		smi_info->curr_msg = NULL;
++		rv = SI_SM_IDLE;
++	} else {
++		int err;
++
++		list_del(entry);
++		smi_info->curr_msg = list_entry(entry,
++						struct ipmi_smi_msg,
++						link);
++#ifdef DEBUG_TIMING
++		do_gettimeofday(&t);
++		printk("**Start2: %d.%9.9d\n", t.tv_sec, t.tv_usec);
++#endif
++		err = smi_info->handlers->start_transaction(
++			smi_info->si_sm,
++			smi_info->curr_msg->data,
++			smi_info->curr_msg->data_size);
++		if (err) {
++			return_hosed_msg(smi_info);
++		}
++
++		rv = SI_SM_CALL_WITHOUT_DELAY;
++	}
++	spin_unlock(&(smi_info->msg_lock));
++
++	return rv;
++}
++
++static void start_enable_irq(struct smi_info *smi_info)
++{
++	unsigned char msg[2];
++
++	/* If we are enabling interrupts, we have to tell the
++	   BMC to use them. */
++	msg[0] = (IPMI_NETFN_APP_REQUEST << 2);
++	msg[1] = IPMI_GET_BMC_GLOBAL_ENABLES_CMD;
++
++	smi_info->handlers->start_transaction(smi_info->si_sm, msg, 2);
++	smi_info->si_state = SI_ENABLE_INTERRUPTS1;
++}
++
++static void start_clear_flags(struct smi_info *smi_info)
++{
++	unsigned char msg[3];
++
++	/* Make sure the watchdog pre-timeout flag is not set at startup. */
++	msg[0] = (IPMI_NETFN_APP_REQUEST << 2);
++	msg[1] = IPMI_CLEAR_MSG_FLAGS_CMD;
++	msg[2] = WDT_PRE_TIMEOUT_INT;
++
++	smi_info->handlers->start_transaction(smi_info->si_sm, msg, 3);
++	smi_info->si_state = SI_CLEARING_FLAGS;
++}
++
++/* When we have a situtaion where we run out of memory and cannot
++   allocate messages, we just leave them in the BMC and run the system
++   polled until we can allocate some memory.  Once we have some
++   memory, we will re-enable the interrupt. */
++static inline void disable_si_irq(struct smi_info *smi_info)
++{
++	if ((smi_info->irq) && (!smi_info->interrupt_disabled)) {
++		disable_irq_nosync(smi_info->irq);
++		smi_info->interrupt_disabled = 1;
++	}
++}
++
++static inline void enable_si_irq(struct smi_info *smi_info)
++{
++	if ((smi_info->irq) && (smi_info->interrupt_disabled)) {
++		enable_irq(smi_info->irq);
++		smi_info->interrupt_disabled = 0;
++	}
++}
++
++static void handle_flags(struct smi_info *smi_info)
++{
++	if (smi_info->msg_flags & WDT_PRE_TIMEOUT_INT) {
++		/* Watchdog pre-timeout */
++		spin_lock(&smi_info->count_lock);
++		smi_info->watchdog_pretimeouts++;
++		spin_unlock(&smi_info->count_lock);
++
++		start_clear_flags(smi_info);
++		smi_info->msg_flags &= ~WDT_PRE_TIMEOUT_INT;
++		spin_unlock(&(smi_info->si_lock));
++		ipmi_smi_watchdog_pretimeout(smi_info->intf);
++		spin_lock(&(smi_info->si_lock));
++	} else if (smi_info->msg_flags & RECEIVE_MSG_AVAIL) {
++		/* Messages available. */
++		smi_info->curr_msg = ipmi_alloc_smi_msg();
++		if (!smi_info->curr_msg) {
++			disable_si_irq(smi_info);
++			smi_info->si_state = SI_NORMAL;
++			return;
++		}
++		enable_si_irq(smi_info);
++
++		smi_info->curr_msg->data[0] = (IPMI_NETFN_APP_REQUEST << 2);
++		smi_info->curr_msg->data[1] = IPMI_GET_MSG_CMD;
++		smi_info->curr_msg->data_size = 2;
++
++		smi_info->handlers->start_transaction(
++			smi_info->si_sm,
++			smi_info->curr_msg->data,
++			smi_info->curr_msg->data_size);
++		smi_info->si_state = SI_GETTING_MESSAGES;
++	} else if (smi_info->msg_flags & EVENT_MSG_BUFFER_FULL) {
++		/* Events available. */
++		smi_info->curr_msg = ipmi_alloc_smi_msg();
++		if (!smi_info->curr_msg) {
++			disable_si_irq(smi_info);
++			smi_info->si_state = SI_NORMAL;
++			return;
++		}
++		enable_si_irq(smi_info);
++
++		smi_info->curr_msg->data[0] = (IPMI_NETFN_APP_REQUEST << 2);
++		smi_info->curr_msg->data[1] = IPMI_READ_EVENT_MSG_BUFFER_CMD;
++		smi_info->curr_msg->data_size = 2;
++
++		smi_info->handlers->start_transaction(
++			smi_info->si_sm,
++			smi_info->curr_msg->data,
++			smi_info->curr_msg->data_size);
++		smi_info->si_state = SI_GETTING_EVENTS;
++	} else {
++		smi_info->si_state = SI_NORMAL;
++	}
++}
++
++static void handle_transaction_done(struct smi_info *smi_info)
++{
++	struct ipmi_smi_msg *msg;
++#ifdef DEBUG_TIMING
++	struct timeval t;
++
++	do_gettimeofday(&t);
++	printk("**Done: %d.%9.9d\n", t.tv_sec, t.tv_usec);
++#endif
++	switch (smi_info->si_state) {
++	case SI_NORMAL:
++		if (!smi_info->curr_msg)
++			break;
++			
++		smi_info->curr_msg->rsp_size
++			= smi_info->handlers->get_result(
++				smi_info->si_sm,
++				smi_info->curr_msg->rsp,
++				IPMI_MAX_MSG_LENGTH);
++		
++		/* Do this here becase deliver_recv_msg() releases the
++		   lock, and a new message can be put in during the
++		   time the lock is released. */
++		msg = smi_info->curr_msg;
++		smi_info->curr_msg = NULL;
++		deliver_recv_msg(smi_info, msg);
++		break;
++		
++	case SI_GETTING_FLAGS:
++	{
++		unsigned char msg[4];
++		unsigned int  len;
++
++		/* We got the flags from the SMI, now handle them. */
++		len = smi_info->handlers->get_result(smi_info->si_sm, msg, 4);
++		if (msg[2] != 0) {
++			/* Error fetching flags, just give up for
++			   now. */
++			smi_info->si_state = SI_NORMAL;
++		} else if (len < 3) {
++			/* Hmm, no flags.  That's technically illegal, but
++			   don't use uninitialized data. */
++			smi_info->si_state = SI_NORMAL;
++		} else {
++			smi_info->msg_flags = msg[3];
++			handle_flags(smi_info);
++		}
++		break;
++	}
++
++	case SI_CLEARING_FLAGS:
++	case SI_CLEARING_FLAGS_THEN_SET_IRQ:
++	{
++		unsigned char msg[3];
++
++		/* We cleared the flags. */
++		smi_info->handlers->get_result(smi_info->si_sm, msg, 3);
++		if (msg[2] != 0) {
++			/* Error clearing flags */
++			printk(KERN_WARNING
++			       "ipmi_si: Error clearing flags: %2.2x\n",
++			       msg[2]);
++		}
++		if (smi_info->si_state == SI_CLEARING_FLAGS_THEN_SET_IRQ)
++			start_enable_irq(smi_info);
++		else
++			smi_info->si_state = SI_NORMAL;
++		break;
++	}
++
++	case SI_GETTING_EVENTS:
++	{
++		smi_info->curr_msg->rsp_size
++			= smi_info->handlers->get_result(
++				smi_info->si_sm,
++				smi_info->curr_msg->rsp,
++				IPMI_MAX_MSG_LENGTH);
++
++		/* Do this here becase deliver_recv_msg() releases the
++		   lock, and a new message can be put in during the
++		   time the lock is released. */
++		msg = smi_info->curr_msg;
++		smi_info->curr_msg = NULL;
++		if (msg->rsp[2] != 0) {
++			/* Error getting event, probably done. */
++			msg->done(msg);
++
++			/* Take off the event flag. */
++			smi_info->msg_flags &= ~EVENT_MSG_BUFFER_FULL;
++			handle_flags(smi_info);
++		} else {
++			spin_lock(&smi_info->count_lock);
++			smi_info->events++;
++			spin_unlock(&smi_info->count_lock);
++
++			/* Do this before we deliver the message
++			   because delivering the message releases the
++			   lock and something else can mess with the
++			   state. */
++			handle_flags(smi_info);
++
++			deliver_recv_msg(smi_info, msg);
++		}
++		break;
++	}
++
++	case SI_GETTING_MESSAGES:
++	{
++		smi_info->curr_msg->rsp_size
++			= smi_info->handlers->get_result(
++				smi_info->si_sm,
++				smi_info->curr_msg->rsp,
++				IPMI_MAX_MSG_LENGTH);
++
++		/* Do this here becase deliver_recv_msg() releases the
++		   lock, and a new message can be put in during the
++		   time the lock is released. */
++		msg = smi_info->curr_msg;
++		smi_info->curr_msg = NULL;
++		if (msg->rsp[2] != 0) {
++			/* Error getting event, probably done. */
++			msg->done(msg);
++
++			/* Take off the msg flag. */
++			smi_info->msg_flags &= ~RECEIVE_MSG_AVAIL;
++			handle_flags(smi_info);
++		} else {
++			spin_lock(&smi_info->count_lock);
++			smi_info->incoming_messages++;
++			spin_unlock(&smi_info->count_lock);
++
++			/* Do this before we deliver the message
++			   because delivering the message releases the
++			   lock and something else can mess with the
++			   state. */
++			handle_flags(smi_info);
++
++			deliver_recv_msg(smi_info, msg);
++		}
++		break;
++	}
++
++	case SI_ENABLE_INTERRUPTS1:
++	{
++		unsigned char msg[4];
++
++		/* We got the flags from the SMI, now handle them. */
++		smi_info->handlers->get_result(smi_info->si_sm, msg, 4);
++		if (msg[2] != 0) {
++			printk(KERN_WARNING
++			       "ipmi_si: Could not enable interrupts"
++			       ", failed get, using polled mode.\n");
++			smi_info->si_state = SI_NORMAL;
++		} else {
++			msg[0] = (IPMI_NETFN_APP_REQUEST << 2);
++			msg[1] = IPMI_SET_BMC_GLOBAL_ENABLES_CMD;
++			msg[2] = msg[3] | 1; /* enable msg queue int */
++			smi_info->handlers->start_transaction(
++				smi_info->si_sm, msg, 3);
++			smi_info->si_state = SI_ENABLE_INTERRUPTS2;
++		}
++		break;
++	}
++
++	case SI_ENABLE_INTERRUPTS2:
++	{
++		unsigned char msg[4];
++
++		/* We got the flags from the SMI, now handle them. */
++		smi_info->handlers->get_result(smi_info->si_sm, msg, 4);
++		if (msg[2] != 0) {
++			printk(KERN_WARNING
++			       "ipmi_si: Could not enable interrupts"
++			       ", failed set, using polled mode.\n");
++		}
++		smi_info->si_state = SI_NORMAL;
++		break;
++	}
++	}
++}
++
++/* Called on timeouts and events.  Timeouts should pass the elapsed
++   time, interrupts should pass in zero. */
++static enum si_sm_result smi_event_handler(struct smi_info *smi_info,
++					   int time)
++{
++	enum si_sm_result si_sm_result;
++
++ restart:
++	/* There used to be a loop here that waited a little while
++	   (around 25us) before giving up.  That turned out to be
++	   pointless, the minimum delays I was seeing were in the 300us
++	   range, which is far too long to wait in an interrupt.  So
++	   we just run until the state machine tells us something
++	   happened or it needs a delay. */
++	si_sm_result = smi_info->handlers->event(smi_info->si_sm, time);
++	time = 0;
++	while (si_sm_result == SI_SM_CALL_WITHOUT_DELAY)
++	{
++		si_sm_result = smi_info->handlers->event(smi_info->si_sm, 0);
++	}
++
++	if (si_sm_result == SI_SM_TRANSACTION_COMPLETE)
++	{
++		spin_lock(&smi_info->count_lock);
++		smi_info->complete_transactions++;
++		spin_unlock(&smi_info->count_lock);
++
++		handle_transaction_done(smi_info);
++		si_sm_result = smi_info->handlers->event(smi_info->si_sm, 0);
++	}
++	else if (si_sm_result == SI_SM_HOSED)
++	{
++		spin_lock(&smi_info->count_lock);
++		smi_info->hosed_count++;
++		spin_unlock(&smi_info->count_lock);
++
++		/* Do the before return_hosed_msg, because that
++		   releases the lock. */
++		smi_info->si_state = SI_NORMAL;
++		if (smi_info->curr_msg != NULL) {
++			/* If we were handling a user message, format
++                           a response to send to the upper layer to
++                           tell it about the error. */
++			return_hosed_msg(smi_info);
++		}
++		si_sm_result = smi_info->handlers->event(smi_info->si_sm, 0);
++	}
++
++	/* We prefer handling attn over new messages. */
++	if (si_sm_result == SI_SM_ATTN)
++	{
++		unsigned char msg[2];
++
++		spin_lock(&smi_info->count_lock);
++		smi_info->attentions++;
++		spin_unlock(&smi_info->count_lock);
++
++		/* Got a attn, send down a get message flags to see
++                   what's causing it.  It would be better to handle
++                   this in the upper layer, but due to the way
++                   interrupts work with the SMI, that's not really
++                   possible. */
++		msg[0] = (IPMI_NETFN_APP_REQUEST << 2);
++		msg[1] = IPMI_GET_MSG_FLAGS_CMD;
++
++		smi_info->handlers->start_transaction(
++			smi_info->si_sm, msg, 2);
++		smi_info->si_state = SI_GETTING_FLAGS;
++		goto restart;
++	}
++
++	/* If we are currently idle, try to start the next message. */
++	if (si_sm_result == SI_SM_IDLE) {
++		spin_lock(&smi_info->count_lock);
++		smi_info->idles++;
++		spin_unlock(&smi_info->count_lock);
++
++		si_sm_result = start_next_msg(smi_info);
++		if (si_sm_result != SI_SM_IDLE)
++			goto restart;
++        }
++
++	if ((si_sm_result == SI_SM_IDLE)
++	    && (atomic_read(&smi_info->req_events)))
++	{
++		/* We are idle and the upper layer requested that I fetch
++		   events, so do so. */
++		unsigned char msg[2];
++
++		spin_lock(&smi_info->count_lock);
++		smi_info->flag_fetches++;
++		spin_unlock(&smi_info->count_lock);
++
++		atomic_set(&smi_info->req_events, 0);
++		msg[0] = (IPMI_NETFN_APP_REQUEST << 2);
++		msg[1] = IPMI_GET_MSG_FLAGS_CMD;
++
++		smi_info->handlers->start_transaction(
++			smi_info->si_sm, msg, 2);
++		smi_info->si_state = SI_GETTING_FLAGS;
++		goto restart;
++	}
++
++	return si_sm_result;
++}
++
++static void sender(void                *send_info,
++		   struct ipmi_smi_msg *msg,
++		   int                 priority)
++{
++	struct smi_info   *smi_info = send_info;
++	enum si_sm_result result;
++	unsigned long     flags;
++#ifdef DEBUG_TIMING
++	struct timeval    t;
++#endif
++
++	spin_lock_irqsave(&(smi_info->msg_lock), flags);
++#ifdef DEBUG_TIMING
++	do_gettimeofday(&t);
++	printk("**Enqueue: %d.%9.9d\n", t.tv_sec, t.tv_usec);
++#endif
++
++	if (smi_info->run_to_completion) {
++		/* If we are running to completion, then throw it in
++		   the list and run transactions until everything is
++		   clear.  Priority doesn't matter here. */
++		list_add_tail(&(msg->link), &(smi_info->xmit_msgs));
++
++		/* We have to release the msg lock and claim the smi
++		   lock in this case, because of race conditions. */
++		spin_unlock_irqrestore(&(smi_info->msg_lock), flags);
++
++		spin_lock_irqsave(&(smi_info->si_lock), flags);
++		result = smi_event_handler(smi_info, 0);
++		while (result != SI_SM_IDLE) {
++			udelay(SI_SHORT_TIMEOUT_USEC);
++			result = smi_event_handler(smi_info,
++						   SI_SHORT_TIMEOUT_USEC);
++		}
++		spin_unlock_irqrestore(&(smi_info->si_lock), flags);
++		return;
++	} else {
++		if (priority > 0) {
++			list_add_tail(&(msg->link), &(smi_info->hp_xmit_msgs));
++		} else {
++			list_add_tail(&(msg->link), &(smi_info->xmit_msgs));
++		}
++	}
++	spin_unlock_irqrestore(&(smi_info->msg_lock), flags);
++
++	spin_lock_irqsave(&(smi_info->si_lock), flags);
++	if ((smi_info->si_state == SI_NORMAL)
++	    && (smi_info->curr_msg == NULL))
++	{
++		start_next_msg(smi_info);
++		si_restart_short_timer(smi_info);
++	}
++	spin_unlock_irqrestore(&(smi_info->si_lock), flags);
++}
++
++static void set_run_to_completion(void *send_info, int i_run_to_completion)
++{
++	struct smi_info   *smi_info = send_info;
++	enum si_sm_result result;
++	unsigned long     flags;
++
++	spin_lock_irqsave(&(smi_info->si_lock), flags);
++
++	smi_info->run_to_completion = i_run_to_completion;
++	if (i_run_to_completion) {
++		result = smi_event_handler(smi_info, 0);
++		while (result != SI_SM_IDLE) {
++			udelay(SI_SHORT_TIMEOUT_USEC);
++			result = smi_event_handler(smi_info,
++						   SI_SHORT_TIMEOUT_USEC);
++		}
++	}
++
++	spin_unlock_irqrestore(&(smi_info->si_lock), flags);
++}
++
++static void poll(void *send_info)
++{
++	struct smi_info *smi_info = send_info;
++
++	smi_event_handler(smi_info, 0);
++}
++
++static void request_events(void *send_info)
++{
++	struct smi_info *smi_info = send_info;
++
++	atomic_set(&smi_info->req_events, 1);
++}
++
++static int new_user(void *send_info)
++{
++	if (!try_inc_mod_count(THIS_MODULE))
++		return -EBUSY;
++	return 0;
++}
++
++static void user_left(void *send_info)
++{
++	MOD_DEC_USE_COUNT;
++}
++
++static int initialized = 0;
++
++/* Must be called with interrupts off and with the si_lock held. */
++static void si_restart_short_timer(struct smi_info *smi_info)
++{
++#if defined(CONFIG_HIGH_RES_TIMERS)
++	unsigned long flags;
++	unsigned long jiffies_now;
++
++	if (del_timer(&(smi_info->si_timer))) {
++		/* If we don't delete the timer, then it will go off
++		   immediately, anyway.  So we only process if we
++		   actually delete the timer. */
++
++		/* We already have irqsave on, so no need for it
++                   here. */
++		read_lock(&xtime_lock);
++		jiffies_now = jiffies;
++		smi_info->si_timer.expires = jiffies_now;
++		smi_info->si_timer.sub_expires = get_arch_cycles(jiffies_now);
++		read_unlock(&xtime_lock);
++
++		add_usec_to_timer(&smi_info->si_timer, SI_SHORT_TIMEOUT_USEC);
++
++		add_timer(&(smi_info->si_timer));
++		spin_lock_irqsave(&smi_info->count_lock, flags);
++		smi_info->timeout_restarts++;
++		spin_unlock_irqrestore(&smi_info->count_lock, flags);
++	}
++#endif
++}
++
++static void smi_timeout(unsigned long data)
++{
++	struct smi_info   *smi_info = (struct smi_info *) data;
++	enum si_sm_result smi_result;
++	unsigned long     flags;
++	unsigned long     jiffies_now;
++	unsigned long     time_diff;
++#ifdef DEBUG_TIMING
++	struct timeval    t;
++#endif
++
++	if (smi_info->stop_operation) {
++		smi_info->timer_stopped = 1;
++		return;
++	}
++
++	spin_lock_irqsave(&(smi_info->si_lock), flags);
++#ifdef DEBUG_TIMING
++	do_gettimeofday(&t);
++	printk("**Timer: %d.%9.9d\n", t.tv_sec, t.tv_usec);
++#endif
++	jiffies_now = jiffies;
++	time_diff = ((jiffies_now - smi_info->last_timeout_jiffies)
++		     * SI_USEC_PER_JIFFY);
++	smi_result = smi_event_handler(smi_info, time_diff);
++
++	spin_unlock_irqrestore(&(smi_info->si_lock), flags);
++
++	smi_info->last_timeout_jiffies = jiffies_now;
++
++	if ((smi_info->irq) && (! smi_info->interrupt_disabled)) {
++		/* Running with interrupts, only do long timeouts. */
++		smi_info->si_timer.expires = jiffies + SI_TIMEOUT_JIFFIES;
++		spin_lock_irqsave(&smi_info->count_lock, flags);
++		smi_info->long_timeouts++;
++		spin_unlock_irqrestore(&smi_info->count_lock, flags);
++		goto do_add_timer;
++	}
++
++	/* If the state machine asks for a short delay, then shorten
++           the timer timeout. */
++	if (smi_result == SI_SM_CALL_WITH_DELAY) {
++		spin_lock_irqsave(&smi_info->count_lock, flags);
++		smi_info->short_timeouts++;
++		spin_unlock_irqrestore(&smi_info->count_lock, flags);
++#if defined(CONFIG_HIGH_RES_TIMERS)
++		read_lock(&xtime_lock);
++                smi_info->si_timer.expires = jiffies;
++                smi_info->si_timer.sub_expires
++                        = get_arch_cycles(smi_info->si_timer.expires);
++                read_unlock(&xtime_lock);
++		add_usec_to_timer(&smi_info->si_timer, SI_SHORT_TIMEOUT_USEC);
++#else
++		smi_info->si_timer.expires = jiffies + 1;
++#endif
++	} else {
++		spin_lock_irqsave(&smi_info->count_lock, flags);
++		smi_info->long_timeouts++;
++		spin_unlock_irqrestore(&smi_info->count_lock, flags);
++		smi_info->si_timer.expires = jiffies + SI_TIMEOUT_JIFFIES;
++#if defined(CONFIG_HIGH_RES_TIMERS)
++		smi_info->si_timer.sub_expires = 0;
++#endif
++	}
++
++ do_add_timer:
++	add_timer(&(smi_info->si_timer));
++}
++
++static void si_irq_handler(int irq, void *data, struct pt_regs *regs)
++{
++	struct smi_info *smi_info = data;
++	unsigned long   flags;
++#ifdef DEBUG_TIMING
++	struct timeval  t;
++#endif
++
++	spin_lock_irqsave(&(smi_info->si_lock), flags);
++
++	spin_lock(&smi_info->count_lock);
++	smi_info->interrupts++;
++	spin_unlock(&smi_info->count_lock);
++
++	if (smi_info->stop_operation)
++		goto out;
++
++#ifdef DEBUG_TIMING
++	do_gettimeofday(&t);
++	printk("**Interrupt: %d.%9.9d\n", t.tv_sec, t.tv_usec);
++#endif
++	smi_event_handler(smi_info, 0);
++ out:
++	spin_unlock_irqrestore(&(smi_info->si_lock), flags);
++}
++
++static struct ipmi_smi_handlers handlers =
++{
++	sender:		       sender,
++	request_events:        request_events,
++	new_user:	       new_user,
++	user_left:	       user_left,
++	set_run_to_completion: set_run_to_completion,
++	poll:		       poll,
++};
++
++/* There can be 4 IO ports passed in (with or without IRQs), 4 addresses,
++   a default IO port, and 1 ACPI/SPMI address.  That sets SI_MAX_DRIVERS */
++
++#define SI_MAX_PARMS 4
++#define SI_MAX_DRIVERS ((SI_MAX_PARMS * 2) + 2)
++static struct smi_info *smi_infos[SI_MAX_DRIVERS] =
++{ NULL, NULL, NULL, NULL };
++
++#define DEVICE_NAME "ipmi_si"
++
++#define DEFAULT_KCS_IO_PORT	0xca2
++#define DEFAULT_SMIC_IO_PORT	0xca9
++#define DEFAULT_BT_IO_PORT	0xe4
++#define DEFAULT_REGSPACING	1
++
++static int           si_trydefaults = 1;
++static char          *si_type[SI_MAX_PARMS] = { NULL, NULL, NULL, NULL };
++static unsigned long si_addrs[SI_MAX_PARMS] = { 0, 0, 0, 0 };
++static unsigned int  si_ports[SI_MAX_PARMS] = { 0, 0, 0, 0 };
++static int           si_irqs[SI_MAX_PARMS] = { 0, 0, 0, 0 };
++static int           si_regspacings[SI_MAX_PARMS] = { 0, 0, 0, 0 };
++static int           si_regsizes[SI_MAX_PARMS] = { 0, 0, 0, 0 };
++static int           si_regshifts[SI_MAX_PARMS] = { 0, 0, 0, 0 };
++
++
++MODULE_PARM(si_trydefaults, "i");
++MODULE_PARM(si_type, "1-4s");
++MODULE_PARM(si_addrs, "1-4l");
++MODULE_PARM(si_irqs, "1-4i");
++MODULE_PARM(si_ports, "1-4i");
++MODULE_PARM(si_regspacings, "1-4i");
++MODULE_PARM(si_regsizes, "1-4i");
++MODULE_PARM(si_regshifts, "1-4i");
++
++
++#if defined(CONFIG_ACPI_INTERPRETER) || defined(CONFIG_X86) || defined(CONFIG_PCI)
++#define IPMI_MEM_ADDR_SPACE 1
++#define IPMI_IO_ADDR_SPACE  2
++static int is_new_interface(int intf, u8 addr_space, unsigned long base_addr)
++{
++	int i;
++
++	for (i = 0; i < SI_MAX_PARMS; ++i) {
++		/* Don't check our address. */
++		if (i == intf)
++			continue;
++		if (si_type[i] != NULL) {
++			if ((addr_space == IPMI_MEM_ADDR_SPACE && 
++			     base_addr == si_addrs[i]) ||
++			    (addr_space == IPMI_IO_ADDR_SPACE &&
++			     base_addr == si_ports[i]))
++				return 0;
++		}
++		else
++			break;
++	}
++	
++	return 1;
++}
++#endif
++ 
++static int std_irq_setup(struct smi_info *info)
++{
++	int rv;
++
++	if (!info->irq)
++		return 0;
++
++	rv = request_irq(info->irq,
++			 si_irq_handler,
++			 SA_INTERRUPT,
++			 DEVICE_NAME,
++			 info);
++	if (rv) {
++		printk(KERN_WARNING
++		       "ipmi_si: %s unable to claim interrupt %d,"
++		       " running polled\n",
++		       DEVICE_NAME, info->irq);
++		info->irq = 0;
++	} else {
++		printk("  Using irq %d\n", info->irq);
++	}
++
++	return rv;
++}
++
++static void std_irq_cleanup(struct smi_info *info)
++{
++	if (!info->irq)
++		return;
++
++	free_irq(info->irq, info);
++}
++
++static unsigned char port_inb(struct si_sm_io *io, unsigned int offset)
++{
++	unsigned int *addr = io->info;
++
++	return inb((*addr)+(offset*io->regspacing));
++}
++
++static void port_outb(struct si_sm_io *io, unsigned int offset,
++		      unsigned char b)
++{
++	unsigned int *addr = io->info;
++
++	outb(b, (*addr)+(offset * io->regspacing));
++}
++
++static unsigned char port_inw(struct si_sm_io *io, unsigned int offset)
++{
++	unsigned int *addr = io->info;
++
++	return (inw((*addr)+(offset * io->regspacing)) >> io->regshift) & 0xff;
++}
++
++static void port_outw(struct si_sm_io *io, unsigned int offset,
++		      unsigned char b)
++{
++	unsigned int *addr = io->info;
++
++	outw(b << io->regshift, (*addr)+(offset * io->regspacing));
++}
++
++static unsigned char port_inl(struct si_sm_io *io, unsigned int offset)
++{
++	unsigned int *addr = io->info;
++
++	return (inl((*addr)+(offset * io->regspacing)) >> io->regshift) & 0xff;
++}
++
++static void port_outl(struct si_sm_io *io, unsigned int offset,
++		      unsigned char b)
++{
++	unsigned int *addr = io->info;
++
++	outl(b << io->regshift, (*addr)+(offset * io->regspacing));
++}
++
++static void port_cleanup(struct smi_info *info)
++{
++	unsigned int *addr = info->io.info;
++	int           mapsize;
++
++	if (addr && (*addr)) {
++		mapsize = ((info->io_size * info->io.regspacing)
++			   - (info->io.regspacing - info->io.regsize));
++
++		release_region (*addr, mapsize);
++	}
++	kfree(info);
++}
++
++static int port_setup(struct smi_info *info)
++{
++	unsigned int *addr = info->io.info;
++	int           mapsize;
++
++	if (!addr || (!*addr))
++		return -ENODEV;
++
++	info->io_cleanup = port_cleanup;
++
++	/* Figure out the actual inb/inw/inl/etc routine to use based
++	   upon the register size. */
++	switch (info->io.regsize) {
++	case 1:
++		info->io.inputb = port_inb;
++		info->io.outputb = port_outb;
++		break;
++	case 2:
++		info->io.inputb = port_inw;
++		info->io.outputb = port_outw;
++		break;
++	case 4:
++		info->io.inputb = port_inl;
++		info->io.outputb = port_outl;
++		break;
++	default:
++		printk("ipmi_si: Invalid register size: %d\n",
++		       info->io.regsize);
++		return -EINVAL;
++	}
++
++	/* Calculate the total amount of memory to claim.  This is an
++	 * unusual looking calculation, but it avoids claiming any
++	 * more memory than it has to.  It will claim everything
++	 * between the first address to the end of the last full
++	 * register. */
++	mapsize = ((info->io_size * info->io.regspacing)
++		   - (info->io.regspacing - info->io.regsize));
++
++	if (request_region(*addr, mapsize, DEVICE_NAME) == NULL)
++		return -EIO;
++	return 0;
++}
++
++static int try_init_port(int intf_num, struct smi_info **new_info)
++{
++	struct smi_info *info;
++
++	if (!si_ports[intf_num])
++		return -ENODEV;
++
++	if (!is_new_interface(intf_num, IPMI_IO_ADDR_SPACE,
++			      si_ports[intf_num]))
++		return -ENODEV;
++
++	info = kmalloc(sizeof(*info), GFP_KERNEL);
++	if (!info) {
++		printk(KERN_ERR "ipmi_si: Could not allocate SI data (1)\n");
++		return -ENOMEM;
++	}
++	memset(info, 0, sizeof(*info));
++
++	info->io_setup = port_setup;
++	info->io.info = &(si_ports[intf_num]);
++	info->io.addr = NULL;
++	info->io.regspacing = si_regspacings[intf_num];
++	if (!info->io.regspacing)
++		info->io.regspacing = DEFAULT_REGSPACING;
++	info->io.regsize = si_regsizes[intf_num];
++	if (!info->io.regsize)
++		info->io.regsize = DEFAULT_REGSPACING;
++	info->io.regshift = si_regshifts[intf_num];
++	info->irq = 0;
++	info->irq_setup = NULL;
++	*new_info = info;
++
++	if (si_type[intf_num] == NULL)
++		si_type[intf_num] = "kcs";
++
++	printk("ipmi_si: Trying \"%s\" at I/O port 0x%x\n",
++	       si_type[intf_num], si_ports[intf_num]);
++	return 0;
++}
++
++static unsigned char mem_inb(struct si_sm_io *io, unsigned int offset)
++{
++	return readb((io->addr)+(offset * io->regspacing));
++}
++
++static void mem_outb(struct si_sm_io *io, unsigned int offset,
++		     unsigned char b)
++{
++	writeb(b, (io->addr)+(offset * io->regspacing));
++}
++
++static unsigned char mem_inw(struct si_sm_io *io, unsigned int offset)
++{
++	return (readw((io->addr)+(offset * io->regspacing)) >> io->regshift)
++		&& 0xff;
++}
++
++static void mem_outw(struct si_sm_io *io, unsigned int offset,
++		     unsigned char b)
++{
++	writeb(b << io->regshift, (io->addr)+(offset * io->regspacing));
++}
++
++static unsigned char mem_inl(struct si_sm_io *io, unsigned int offset)
++{
++	return (readl((io->addr)+(offset * io->regspacing)) >> io->regshift)
++		&& 0xff;
++}
++
++static void mem_outl(struct si_sm_io *io, unsigned int offset,
++		     unsigned char b)
++{
++	writel(b << io->regshift, (io->addr)+(offset * io->regspacing));
++}
++
++#ifdef readq
++static unsigned char mem_inq(struct si_sm_io *io, unsigned int offset)
++{
++	return (readq((io->addr)+(offset * io->regspacing)) >> io->regshift)
++		&& 0xff;
++}
++
++static void mem_outq(struct si_sm_io *io, unsigned int offset,
++		     unsigned char b)
++{
++	writeq(b << io->regshift, (io->addr)+(offset * io->regspacing));
++}
++#endif
++
++static void mem_cleanup(struct smi_info *info)
++{
++	unsigned long *addr = info->io.info;
++	int           mapsize;
++
++	if (info->io.addr) {
++		iounmap(info->io.addr);
++
++		mapsize = ((info->io_size * info->io.regspacing)
++			   - (info->io.regspacing - info->io.regsize));
++
++		release_mem_region(*addr, mapsize);
++	}
++	kfree(info);
++}
++
++static int mem_setup(struct smi_info *info)
++{
++	unsigned long *addr = info->io.info;
++	int           mapsize;
++
++	if (!addr || (!*addr))
++		return -ENODEV;
++
++	info->io_cleanup = mem_cleanup;
++
++	/* Figure out the actual readb/readw/readl/etc routine to use based
++	   upon the register size. */
++	switch (info->io.regsize) {
++	case 1:
++		info->io.inputb = mem_inb;
++		info->io.outputb = mem_outb;
++		break;
++	case 2:
++		info->io.inputb = mem_inw;
++		info->io.outputb = mem_outw;
++		break;
++	case 4:
++		info->io.inputb = mem_inl;
++		info->io.outputb = mem_outl;
++		break;
++#ifdef readq
++	case 8:
++		info->io.inputb = mem_inq;
++		info->io.outputb = mem_outq;
++		break;
++#endif
++	default:
++		printk("ipmi_si: Invalid register size: %d\n",
++		       info->io.regsize);
++		return -EINVAL;
++	}
++
++	/* Calculate the total amount of memory to claim.  This is an
++	 * unusual looking calculation, but it avoids claiming any
++	 * more memory than it has to.  It will claim everything
++	 * between the first address to the end of the last full
++	 * register. */
++	mapsize = ((info->io_size * info->io.regspacing)
++		   - (info->io.regspacing - info->io.regsize));
++
++	if (request_mem_region(*addr, mapsize, DEVICE_NAME) == NULL)
++		return -EIO;
++
++	info->io.addr = ioremap(*addr, mapsize);
++	if (info->io.addr == NULL) {
++		release_mem_region(*addr, mapsize);
++		return -EIO;
++	}
++	return 0;
++}
++
++static int try_init_mem(int intf_num, struct smi_info **new_info)
++{
++	struct smi_info *info;
++
++	if (!si_addrs[intf_num])
++		return -ENODEV;
++
++	if (!is_new_interface(intf_num, IPMI_MEM_ADDR_SPACE,
++			      si_addrs[intf_num]))
++		return -ENODEV;
++
++	info = kmalloc(sizeof(*info), GFP_KERNEL);
++	if (!info) {
++		printk(KERN_ERR "ipmi_si: Could not allocate SI data (2)\n");
++		return -ENOMEM;
++	}
++	memset(info, 0, sizeof(*info));
++
++	info->io_setup = mem_setup;
++	info->io.info = (void *) si_addrs[intf_num];
++	info->io.addr = NULL;
++	info->io.regspacing = si_regspacings[intf_num];
++	if (!info->io.regspacing)
++		info->io.regspacing = DEFAULT_REGSPACING;
++	info->io.regsize = si_regsizes[intf_num];
++	if (!info->io.regsize)
++		info->io.regsize = DEFAULT_REGSPACING;
++	info->io.regshift = si_regshifts[intf_num];
++	info->irq = 0;
++	info->irq_setup = NULL;
++	*new_info = info;
++
++	if (si_type[intf_num] == NULL)
++		si_type[intf_num] = "kcs";
++
++	printk("ipmi_si: Trying \"%s\" at memory address 0x%lx\n",
++	       si_type[intf_num], si_addrs[intf_num]);
++	return 0;
++}
++
++#ifdef CONFIG_ACPI_INTERPRETER
++
++#include <linux/acpi.h>
++#include <acpi/acpi.h>
++#include <acpi/actypes.h>
++#include <acpi/actbl.h>
++
++/* Once we get an ACPI failure, we don't try any more, because we go
++   through the tables sequentially.  Once we don't find a table, there
++   are no more. */
++static int acpi_failure = 0;
++
++/* For GPE-type interrupts. */
++void ipmi_acpi_gpe(void *context)
++{
++	struct smi_info *smi_info = context;
++	unsigned long   flags;
++#ifdef DEBUG_TIMING
++	struct timeval t;
++#endif
++
++	spin_lock_irqsave(&(smi_info->si_lock), flags);
++
++	spin_lock(&smi_info->count_lock);
++	smi_info->interrupts++;
++	spin_unlock(&smi_info->count_lock);
++
++	if (smi_info->stop_operation)
++		goto out;
++
++#ifdef DEBUG_TIMING
++	do_gettimeofday(&t);
++	printk("**ACPI_GPE: %d.%9.9d\n", t.tv_sec, t.tv_usec);
++#endif
++	smi_event_handler(smi_info, 0);
++ out:
++	spin_unlock_irqrestore(&(smi_info->si_lock), flags);
++}
++
++static int acpi_gpe_irq_setup(struct smi_info *info)
++{
++	acpi_status status;
++
++	if (!info->irq)
++		return 0;
++
++	/* FIXME - is level triggered right? */
++	status = acpi_install_gpe_handler(NULL,
++					  info->irq,
++					  ACPI_GPE_LEVEL_TRIGGERED,
++					  ipmi_acpi_gpe,
++					  info);
++	if (status != AE_OK) {
++		printk(KERN_WARNING
++		       "ipmi_si: %s unable to claim ACPI GPE %d,"
++		       " running polled\n",
++		       DEVICE_NAME, info->irq);
++		info->irq = 0;
++		return -EINVAL;
++	} else {
++		printk("  Using ACPI GPE %d\n", info->irq);
++		return 0;
++	}
++
++}
++
++static void acpi_gpe_irq_cleanup(struct smi_info *info)
++{
++	if (!info->irq)
++		return;
++
++	acpi_remove_gpe_handler(NULL, info->irq, ipmi_acpi_gpe);
++}
++
++/*
++ * Defined at
++ * http://h21007.www2.hp.com/dspp/files/unprotected/devresource/Docs/TechPapers/IA64/hpspmi.pdf
++ */
++struct SPMITable {
++	s8	Signature[4];
++	u32	Length;
++	u8	Revision;
++	u8	Checksum;
++	s8	OEMID[6];
++	s8	OEMTableID[8];
++	s8	OEMRevision[4];
++	s8	CreatorID[4];
++	s8	CreatorRevision[4];
++	u8	InterfaceType;
++	u8	IPMIlegacy;
++	s16	SpecificationRevision;
++
++	/*
++	 * Bit 0 - SCI interrupt supported
++	 * Bit 1 - I/O APIC/SAPIC
++	 */
++	u8	InterruptType;
++
++	/* If bit 0 of InterruptType is set, then this is the SCI
++           interrupt in the GPEx_STS register. */
++	u8	GPE;
++
++	s16	Reserved;
++
++	/* If bit 1 of InterruptType is set, then this is the I/O
++           APIC/SAPIC interrupt. */
++	u32	GlobalSystemInterrupt;
++
++	/* The actual register address. */
++	struct acpi_generic_address addr;
++
++	u8	UID[4];
++
++	s8      spmi_id[1]; /* A '\0' terminated array starts here. */
++};
++
++static int try_init_acpi(int intf_num, struct smi_info **new_info)
++{
++	struct smi_info  *info;
++	acpi_status      status;
++	struct SPMITable *spmi;
++	char             *io_type;
++	u8 		 addr_space;
++
++	if (acpi_failure)
++		return -ENODEV;
++
++	status = acpi_get_firmware_table("SPMI", intf_num+1,
++					 ACPI_LOGICAL_ADDRESSING,
++					 (struct acpi_table_header **) &spmi);
++	if (status != AE_OK) {
++		acpi_failure = 1;
++		return -ENODEV;
++	}
++
++	if (spmi->IPMIlegacy != 1) {
++	    printk(KERN_INFO "IPMI: Bad SPMI legacy %d\n", spmi->IPMIlegacy);
++	    return -ENODEV;
++	}
++
++	if (spmi->addr.address_space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY)
++		addr_space = IPMI_MEM_ADDR_SPACE;
++	else
++		addr_space = IPMI_IO_ADDR_SPACE;
++	if (!is_new_interface(-1, addr_space, spmi->addr.address))
++		return -ENODEV;
++
++	/* Figure out the interface type. */
++	switch (spmi->InterfaceType)
++	{
++	case 1:	/* KCS */
++		si_type[intf_num] = "kcs";
++		break;
++
++	case 2:	/* SMIC */
++		si_type[intf_num] = "smic";
++		break;
++
++	case 3:	/* BT */
++		si_type[intf_num] = "bt";
++		break;
++
++	default:
++		printk(KERN_INFO "ipmi_si: Unknown ACPI/SPMI SI type %d\n",
++			spmi->InterfaceType);
++		return -EIO;
++	} 
++
++	info = kmalloc(sizeof(*info), GFP_KERNEL);
++	if (!info) {
++		printk(KERN_ERR "ipmi_si: Could not allocate SI data (3)\n");
++		return -ENOMEM;
++	}
++	memset(info, 0, sizeof(*info));
++
++	if (spmi->InterruptType & 1) {
++		/* We've got a GPE interrupt. */
++		info->irq = spmi->GPE;
++		info->irq_setup = acpi_gpe_irq_setup;
++		info->irq_cleanup = acpi_gpe_irq_cleanup;
++	} else if (spmi->InterruptType & 2) {
++		/* We've got an APIC/SAPIC interrupt. */
++		info->irq = spmi->GlobalSystemInterrupt;
++		info->irq_setup = std_irq_setup;
++		info->irq_cleanup = std_irq_cleanup;
++	} else {
++		/* Use the default interrupt setting. */
++		info->irq = 0;
++		info->irq_setup = NULL;
++	}
++
++	si_regspacings[intf_num] = spmi->addr.register_bit_width / 8;
++	info->io.regspacing = spmi->addr.register_bit_width / 8;
++	si_regsizes[intf_num] = si_regspacings[intf_num];
++	info->io.regsize = si_regsizes[intf_num];
++	si_regshifts[intf_num] = spmi->addr.register_bit_offset;
++	info->io.regshift = si_regshifts[intf_num];
++
++	if (spmi->addr.address_space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) {
++		io_type = "memory";
++		info->io_setup = mem_setup;
++		si_addrs[intf_num] = spmi->addr.address;
++		info->io.info = &(si_addrs[intf_num]);
++	} else if (spmi->addr.address_space_id == ACPI_ADR_SPACE_SYSTEM_IO) {
++		io_type = "I/O";
++		info->io_setup = port_setup;
++		si_ports[intf_num] = spmi->addr.address;
++		info->io.info = &(si_ports[intf_num]);
++	} else {
++		kfree(info);
++		printk("ipmi_si: Unknown ACPI I/O Address type\n");
++		return -EIO;
++	}
++
++	*new_info = info;
++
++	printk("ipmi_si: ACPI/SPMI specifies \"%s\" %s SI @ 0x%lx\n",
++	       si_type[intf_num], io_type, (unsigned long) spmi->addr.address);
++	return 0;
++}
++#endif
++
++#ifdef CONFIG_X86
++
++typedef struct dmi_ipmi_data
++{
++	u8   		type;
++	u8   		addr_space;
++	unsigned long	base_addr;
++	u8   		irq;
++	u8              offset;
++}dmi_ipmi_data_t;
++
++typedef struct dmi_header
++{
++	u8	type;
++	u8	length;
++	u16	handle;
++}dmi_header_t;
++
++static int decode_dmi(dmi_header_t *dm, dmi_ipmi_data_t *ipmi_data)
++{
++	u8		*data = (u8 *)dm;
++	unsigned long  	base_addr;
++	u8		reg_spacing;
++	
++	ipmi_data->type = data[0x04];
++	
++	memcpy(&base_addr,&data[0x08],sizeof(unsigned long));
++	if (base_addr & 1) {
++		/* I/O */
++		base_addr &= 0xFFFE;
++		ipmi_data->addr_space = IPMI_IO_ADDR_SPACE;
++	}
++	else {
++		/* Memory */
++		ipmi_data->addr_space = IPMI_MEM_ADDR_SPACE;
++	}
++		
++	/* The top two bits of byte 0x10 hold the register spacing. */
++	reg_spacing = (data[0x10] & 0xC0) >> 6;
++	switch(reg_spacing){
++	case 0x00: /* Byte boundaries */
++		ipmi_data->offset = 1;
++		break;
++	case 0x01: /* 32-bit boundaries */
++		ipmi_data->offset = 4;
++		break;
++	case 0x02: /* 16-bit boundaries */
++		ipmi_data->offset = 2;
++	default:
++		printk("ipmi_si: Unknown SMBIOS IPMI Base Addr"
++		       " Modifier: 0x%x\n", reg_spacing);
++		return -EIO;
++	}
++
++	/* If bit 4 of byte 0x10 is set, then the lsb for the address
++	   is odd. */
++	ipmi_data->base_addr = base_addr | ((data[0x10] & 0x10) >> 4);
++
++	ipmi_data->irq = data[0x11];
++	
++	if (is_new_interface(-1, ipmi_data->addr_space,ipmi_data->base_addr))
++	    return 0;
++	    
++	memset(ipmi_data,0,sizeof(dmi_ipmi_data_t));
++	    
++	return -1;
++}
++
++static int dmi_table(u32 base, int len, int num, 
++	dmi_ipmi_data_t *ipmi_data)
++{
++	u8 		  *buf;
++	struct dmi_header *dm;
++	u8 		  *data;
++	int 		  i=1;
++	int		  status=-1;
++
++	buf = ioremap(base, len);
++	if(buf==NULL)
++		return -1;
++
++	data = buf;
++
++	while(i<num && (data - buf) < len)
++	{        
++		dm=(dmi_header_t *)data;
++
++		if((data-buf+dm->length) >= len)
++        		break;
++       
++		if (dm->type == 38) {
++			if (decode_dmi(dm, ipmi_data) == 0) {
++				status = 0;
++				break;
++			}
++		}
++       
++	        data+=dm->length;
++		while((data-buf) < len && (*data || data[1]))
++			data++;
++		data+=2;
++		i++;
++	}
++	iounmap(buf);
++	
++	return status;
++}
++
++inline static int dmi_checksum(u8 *buf)
++{
++	u8   sum=0;
++	int  a;
++	
++	for(a=0; a<15; a++)
++		sum+=buf[a];
++	return (sum==0);
++}
++
++static int dmi_iterator(dmi_ipmi_data_t *ipmi_data)
++{
++	u8   buf[15];
++	u32  fp=0xF0000;
++
++#ifdef CONFIG_SIMNOW
++	return -1;
++#endif
++ 	
++	while(fp < 0xFFFFF)
++	{
++		isa_memcpy_fromio(buf, fp, 15);
++		if(memcmp(buf, "_DMI_", 5)==0 && dmi_checksum(buf))
++		{
++			u16 num=buf[13]<<8|buf[12];
++			u16 len=buf[7]<<8|buf[6];
++			u32 base=buf[11]<<24|buf[10]<<16|buf[9]<<8|buf[8];
++
++			if(dmi_table(base, len, num, ipmi_data) == 0)
++				return 0;
++		}
++		fp+=16;
++	}
++	
++	return -1;
++}
++
++static int try_init_smbios(int intf_num, struct smi_info **new_info)
++{
++	struct smi_info   *info;
++	dmi_ipmi_data_t   ipmi_data;
++	char              *io_type;
++	int               status;
++
++	status = dmi_iterator(&ipmi_data);
++
++	if (status < 0)
++		return -ENODEV;
++	
++	switch(ipmi_data.type) {
++		case 0x01: /* KCS */
++			si_type[intf_num] = "kcs";
++			break;
++		case 0x02: /* SMIC */
++			si_type[intf_num] = "smic";
++			break;
++		case 0x03: /* BT */
++			si_type[intf_num] = "bt";
++			break;
++		default:
++			printk("ipmi_si: Unknown SMBIOS SI type.\n");
++			return -EIO;
++	}
++	
++	info = kmalloc(sizeof(*info), GFP_KERNEL);
++	if (!info) {
++		printk(KERN_ERR "ipmi_si: Could not allocate SI data (4)\n");
++		return -ENOMEM;
++	}
++	memset(info, 0, sizeof(*info));
++
++	if (ipmi_data.addr_space == 1) {
++		io_type = "memory";
++		info->io_setup = mem_setup;
++		si_addrs[intf_num] = ipmi_data.base_addr;
++		info->io.info = &(si_addrs[intf_num]);
++	} else if (ipmi_data.addr_space == 2) {
++		io_type = "I/O";
++		info->io_setup = port_setup;
++		si_ports[intf_num] = ipmi_data.base_addr;
++		info->io.info = &(si_ports[intf_num]);
++	} else {
++		kfree(info);
++		printk("ipmi_si: Unknown SMBIOS I/O Address type.\n");
++		return -EIO;
++	}
++
++	si_regspacings[intf_num] = ipmi_data.offset;
++	info->io.regspacing = si_regspacings[intf_num];
++	if (!info->io.regspacing)
++		info->io.regspacing = DEFAULT_REGSPACING;
++	info->io.regsize = DEFAULT_REGSPACING;
++	info->io.regshift = si_regshifts[intf_num];
++
++	si_irqs[intf_num] = ipmi_data.irq;
++
++	*new_info = info;
++
++	printk("ipmi_si: Found SMBIOS-specified state machine at %s"
++	       " address 0x%lx\n",
++	       io_type, (unsigned long)ipmi_data.base_addr);
++	return 0;
++}
++#endif /* CONFIG_X86 */
++
++#ifdef CONFIG_PCI
++
++#define PCI_ERMC_CLASSCODE  0x0C0700
++#define PCI_HP_VENDOR_ID    0x103C
++#define PCI_MMC_DEVICE_ID   0x121A
++#define PCI_MMC_ADDR_CW     0x10
++
++/* Avoid more than one attempt to probe pci smic. */
++static int pci_smic_checked = 0;
++
++static int find_pci_smic(int intf_num, struct smi_info **new_info)
++{
++	struct smi_info  *info;
++	int              error;
++	struct pci_dev   *pci_dev = NULL;
++	u16    		 base_addr;
++	int              fe_rmc = 0;
++	
++	if (!pci_present() || pci_smic_checked)
++		return -ENODEV;
++
++	pci_smic_checked = 1;
++	
++	if ((pci_dev = pci_find_device(PCI_HP_VENDOR_ID, PCI_MMC_DEVICE_ID,
++				       NULL)))
++		;
++	else if ((pci_dev = pci_find_class(PCI_ERMC_CLASSCODE, NULL)) &&
++		 pci_dev->subsystem_vendor == PCI_HP_VENDOR_ID)
++		fe_rmc = 1;
++	else
++		return -ENODEV;
++	
++	error = pci_read_config_word(pci_dev, PCI_MMC_ADDR_CW, &base_addr);
++	if (error)
++	{
++		printk(KERN_ERR
++		       "ipmi_si: pci_read_config_word() failed (%d).\n",
++		       error);
++		return -ENODEV;
++	}
++	
++	/* Bit 0: 1 specifies programmed I/O, 0 specifies memory mapped I/O */
++	if (!(base_addr & 0x0001))
++	{
++		printk(KERN_ERR
++		       "ipmi_si: memory mapped I/O not supported for PCI"
++		       " smic.\n");
++		return -ENODEV;
++	}
++	
++	base_addr &= 0xFFFE;
++	if (!fe_rmc)
++		/* Data register starts at base address + 1 in eRMC */
++		++base_addr;
++	
++	if (!is_new_interface(-1, IPMI_IO_ADDR_SPACE, base_addr))
++	    return -ENODEV;
++	
++	info = kmalloc(sizeof(*info), GFP_KERNEL);
++	if (!info) {
++		printk(KERN_ERR "ipmi_si: Could not allocate SI data (5)\n");
++		return -ENOMEM;
++	}
++	memset(info, 0, sizeof(*info));
++	
++	info->io_setup = port_setup;
++	si_ports[intf_num] = base_addr;
++	info->io.info = &(si_ports[intf_num]);
++	info->io.regspacing = si_regspacings[intf_num];
++	if (!info->io.regspacing)
++		info->io.regspacing = DEFAULT_REGSPACING;
++	info->io.regsize = DEFAULT_REGSPACING;
++	info->io.regshift = si_regshifts[intf_num];
++
++	*new_info = info;
++	
++	si_irqs[intf_num] = pci_dev->irq;
++	si_type[intf_num] = "smic";
++
++	printk("ipmi_si: Found PCI SMIC at I/O address 0x%lx\n",
++		(long unsigned int) base_addr);
++	
++	return 0;
++}
++#endif /* CONFIG_PCI */
++
++static int try_init_plug_and_play(int intf_num, struct smi_info **new_info)
++{
++#ifdef CONFIG_PCI
++	if (find_pci_smic(intf_num, new_info)==0)
++		return 0;
++#endif
++	/* Include other methods here. */
++    
++	return -ENODEV;
++}
++
++
++static int try_get_dev_id(struct smi_info *smi_info)
++{
++	unsigned char      msg[2];
++	unsigned char      *resp;
++	unsigned long      resp_len;
++	enum si_sm_result smi_result;
++	int               rv = 0;
++
++	resp = kmalloc(IPMI_MAX_MSG_LENGTH, GFP_KERNEL);
++	if (!resp)
++		return -ENOMEM;
++
++	/* Do a Get Device ID command, since it comes back with some
++	   useful info. */
++	msg[0] = IPMI_NETFN_APP_REQUEST << 2;
++	msg[1] = IPMI_GET_DEVICE_ID_CMD;
++	smi_info->handlers->start_transaction(smi_info->si_sm, msg, 2);
++	
++	smi_result = smi_info->handlers->event(smi_info->si_sm, 0);
++	for (;;)
++	{
++		if (smi_result == SI_SM_CALL_WITH_DELAY) {
++			set_current_state(TASK_UNINTERRUPTIBLE);
++			schedule_timeout(1);
++			smi_result = smi_info->handlers->event(
++				smi_info->si_sm, 100);
++		}
++		else if (smi_result == SI_SM_CALL_WITHOUT_DELAY)
++		{
++			smi_result = smi_info->handlers->event(
++				smi_info->si_sm, 0);
++		}
++		else
++			break;
++	}
++	if (smi_result == SI_SM_HOSED) {
++		/* We couldn't get the state machine to run, so whatever's at
++		   the port is probably not an IPMI SMI interface. */
++		rv = -ENODEV;
++		goto out;
++	}
++
++	/* Otherwise, we got some data. */
++	resp_len = smi_info->handlers->get_result(smi_info->si_sm,
++						  resp, IPMI_MAX_MSG_LENGTH);
++	if (resp_len < 6) {
++		/* That's odd, it should be longer. */
++		rv = -EINVAL;
++		goto out;
++	}
++	
++	if ((resp[1] != IPMI_GET_DEVICE_ID_CMD) || (resp[2] != 0)) {
++		/* That's odd, it shouldn't be able to fail. */
++		rv = -EINVAL;
++		goto out;
++	}
++
++	/* Record info from the get device id, in case we need it. */
++	smi_info->ipmi_si_dev_rev = resp[4] & 0xf;
++	smi_info->ipmi_si_fw_rev_major = resp[5] & 0x7f;
++	smi_info->ipmi_si_fw_rev_minor = resp[6];
++	smi_info->ipmi_version_major = resp[7] & 0xf;
++	smi_info->ipmi_version_minor = resp[7] >> 4;
++
++ out:
++	kfree(resp);
++	return rv;
++}
++
++static int type_file_read_proc(char *page, char **start, off_t off,
++			       int count, int *eof, void *data)
++{
++	char            *out = (char *) page;
++	struct smi_info *smi = data;
++
++	switch (smi->si_type) {
++	    case SI_KCS:
++		return sprintf(out, "kcs\n");
++	    case SI_SMIC:
++		return sprintf(out, "smic\n");
++	    case SI_BT:
++		return sprintf(out, "bt\n");
++	    default:
++		return 0;
++	}
++}
++
++static int stat_file_read_proc(char *page, char **start, off_t off,
++			       int count, int *eof, void *data)
++{
++	char            *out = (char *) page;
++	struct smi_info *smi = data;
++
++	out += sprintf(out, "interrupts_enabled:    %d\n",
++		       smi->irq && !smi->interrupt_disabled);
++	out += sprintf(out, "short_timeouts:        %ld\n",
++		       smi->short_timeouts);
++	out += sprintf(out, "long_timeouts:         %ld\n",
++		       smi->long_timeouts);
++	out += sprintf(out, "timeout_restarts:      %ld\n",
++		       smi->timeout_restarts);
++	out += sprintf(out, "idles:                 %ld\n",
++		       smi->idles);
++	out += sprintf(out, "interrupts:            %ld\n",
++		       smi->interrupts);
++	out += sprintf(out, "attentions:            %ld\n",
++		       smi->attentions);
++	out += sprintf(out, "flag_fetches:          %ld\n",
++		       smi->flag_fetches);
++	out += sprintf(out, "hosed_count:           %ld\n",
++		       smi->hosed_count);
++	out += sprintf(out, "complete_transactions: %ld\n",
++		       smi->complete_transactions);
++	out += sprintf(out, "events:                %ld\n",
++		       smi->events);
++	out += sprintf(out, "watchdog_pretimeouts:  %ld\n",
++		       smi->watchdog_pretimeouts);
++	out += sprintf(out, "incoming_messages:     %ld\n",
++		       smi->incoming_messages);
++
++	return (out - ((char *) page));
++}
++
++/* Returns 0 if initialized, or negative on an error. */
++static int init_one_smi(int intf_num, struct smi_info **smi)
++{
++	int		rv;
++	struct smi_info *new_smi;
++
++
++	rv = try_init_mem(intf_num, &new_smi);
++	if (rv)
++		rv = try_init_port(intf_num, &new_smi);
++#ifdef CONFIG_ACPI_INTERPRETER
++	if ((rv) && (si_trydefaults)) {
++		rv = try_init_acpi(intf_num, &new_smi);
++	}
++#endif
++#ifdef CONFIG_X86
++	if ((rv) && (si_trydefaults)) {
++		rv = try_init_smbios(intf_num, &new_smi);
++        }
++#endif
++	if ((rv) && (si_trydefaults)) {
++		rv = try_init_plug_and_play(intf_num, &new_smi);
++	}
++
++
++	if (rv)
++		return rv;
++
++	/* So we know not to free it unless we have allocated one. */
++	new_smi->intf = NULL;
++	new_smi->si_sm = NULL;
++	new_smi->handlers = 0;
++
++	if (!new_smi->irq_setup) {
++		new_smi->irq = si_irqs[intf_num];
++		new_smi->irq_setup = std_irq_setup;
++		new_smi->irq_cleanup = std_irq_cleanup;
++	}
++
++	/* Default to KCS if no type is specified. */
++	if (si_type[intf_num] == NULL) {
++		if (si_trydefaults)
++			si_type[intf_num] = "kcs";
++		else {
++			rv = -EINVAL;
++			goto out_err;
++		}
++	}
++
++	/* Set up the state machine to use. */
++	if (strcmp(si_type[intf_num], "kcs") == 0) {
++		new_smi->handlers = &kcs_smi_handlers;
++		new_smi->si_type = SI_KCS;
++	} else if (strcmp(si_type[intf_num], "smic") == 0) {
++		new_smi->handlers = &smic_smi_handlers;
++		new_smi->si_type = SI_SMIC;
++	} else if (strcmp(si_type[intf_num], "bt") == 0) {
++		new_smi->handlers = &bt_smi_handlers;
++		new_smi->si_type = SI_BT;
++	} else {
++		/* No support for anything else yet. */
++		rv = -EIO;
++		goto out_err;
++	}
++
++	/* Allocate the state machine's data and initialize it. */
++	new_smi->si_sm = kmalloc(new_smi->handlers->size(), GFP_KERNEL);
++	if (!new_smi->si_sm) {
++		printk(" Could not allocate state machine memory\n");
++		rv = -ENOMEM;
++		goto out_err;
++	}
++	new_smi->io_size = new_smi->handlers->init_data(new_smi->si_sm,
++							&new_smi->io);
++
++	/* Now that we know the I/O size, we can set up the I/O. */
++	rv = new_smi->io_setup(new_smi);
++	if (rv) {
++		printk(" Could not set up I/O space\n");
++		goto out_err;
++	}
++	
++	spin_lock_init(&(new_smi->si_lock));
++	spin_lock_init(&(new_smi->msg_lock));
++	spin_lock_init(&(new_smi->count_lock));
++
++	/* Do low-level detection first. */
++	if (new_smi->handlers->detect(new_smi->si_sm)) {
++		rv = -ENODEV;
++		goto out_err;
++	}
++
++	/* Attempt a get device id command.  If it fails, we probably
++           don't have a SMI here. */
++	rv = try_get_dev_id(new_smi);
++	if (rv)
++		goto out_err;
++
++	/* Try to claim any interrupts. */
++	new_smi->irq_setup(new_smi);
++
++	INIT_LIST_HEAD(&(new_smi->xmit_msgs));
++	INIT_LIST_HEAD(&(new_smi->hp_xmit_msgs));
++	new_smi->curr_msg = NULL;
++	atomic_set(&new_smi->req_events, 0);
++	new_smi->run_to_completion = 0;
++
++	new_smi->interrupt_disabled = 0;
++	new_smi->timer_stopped = 0;
++	new_smi->stop_operation = 0;
++
++	/* Start clearing the flags before we enable interrupts or the
++	   timer to avoid racing with the timer. */
++	start_clear_flags(new_smi);
++	/* IRQ is defined to be set when non-zero. */
++	if (new_smi->irq)
++		new_smi->si_state = SI_CLEARING_FLAGS_THEN_SET_IRQ;
++
++	/* The ipmi_register_smi() code does some operations to
++	   determine the channel information, so we must be ready to
++	   handle operations before it is called.  This means we have
++	   to stop the timer if we get an error after this point. */
++	init_timer(&(new_smi->si_timer));
++	new_smi->si_timer.data = (long) new_smi;
++	new_smi->si_timer.function = smi_timeout;
++	new_smi->last_timeout_jiffies = jiffies;
++	new_smi->si_timer.expires = jiffies + SI_TIMEOUT_JIFFIES;
++	add_timer(&(new_smi->si_timer));
++
++	rv = ipmi_register_smi(&handlers,
++			       new_smi,
++			       new_smi->ipmi_version_major,
++			       new_smi->ipmi_version_minor,
++			       &(new_smi->intf));
++	if (rv) {
++		printk(KERN_ERR 
++		       "ipmi_si: Unable to register device: error %d\n",
++		       rv);
++		goto out_err_stop_timer;
++	}
++
++	rv = ipmi_smi_add_proc_entry(new_smi->intf, "type",
++				     type_file_read_proc, NULL,
++				     new_smi, THIS_MODULE);
++	if (rv) {
++		printk(KERN_ERR 
++		       "ipmi_si: Unable to create proc entry: %d\n",
++		       rv);
++		goto out_err_stop_timer;
++	}
++
++	rv = ipmi_smi_add_proc_entry(new_smi->intf, "si_stats",
++				     stat_file_read_proc, NULL,
++				     new_smi, THIS_MODULE);
++	if (rv) {
++		printk(KERN_ERR 
++		       "ipmi_si: Unable to create proc entry: %d\n",
++		       rv);
++		goto out_err_stop_timer;
++	}
++
++	*smi = new_smi;
++
++	printk(" IPMI %s interface initialized\n", si_type[intf_num]);
++
++	return 0;
++
++ out_err_stop_timer:
++	new_smi->stop_operation = 1;
++
++	/* Wait for the timer to stop.  This avoids problems with race
++	   conditions removing the timer here. */
++	while (!new_smi->timer_stopped) {
++		set_current_state(TASK_UNINTERRUPTIBLE);
++		schedule_timeout(1);
++	}
++
++ out_err:
++	if (new_smi->intf)
++		ipmi_unregister_smi(new_smi->intf);
++
++	new_smi->irq_cleanup(new_smi);
++	if (new_smi->si_sm) {
++		if (new_smi->handlers)
++			new_smi->handlers->cleanup(new_smi->si_sm);
++		kfree(new_smi->si_sm);
++	}
++	new_smi->io_cleanup(new_smi);
++	return rv;
++}
++
++static __init int init_ipmi_si(void)
++{
++	int		rv = 0;
++	int		pos = 0;
++	int		i = 0;
++
++	if (initialized)
++		return 0;
++	initialized = 1;
++
++	printk(KERN_INFO "IPMI System Interface driver version "
++	       IPMI_SI_VERSION);
++	if (kcs_smi_handlers.version)
++		printk(", KCS version %s", kcs_smi_handlers.version);
++	if (smic_smi_handlers.version)
++		printk(", SMIC version %s", smic_smi_handlers.version);
++	if (bt_smi_handlers.version)
++   	        printk(", BT version %s", bt_smi_handlers.version);
++	printk("\n");
++
++	rv = init_one_smi(0, &(smi_infos[pos]));
++	if (rv && !si_ports[0] && si_trydefaults) {
++		/* If we are trying defaults and the initial port is
++                   not set, then set it. */
++		si_type[0] = "kcs";
++		si_ports[0] = DEFAULT_KCS_IO_PORT;
++		rv = init_one_smi(0, &(smi_infos[pos]));
++		if (rv) {
++			/* No KCS - try SMIC */
++			si_type[0] = "smic";
++			si_ports[0] = DEFAULT_SMIC_IO_PORT;
++			rv = init_one_smi(0, &(smi_infos[pos]));
++		}
++		if (rv) {
++			/* No SMIC - try BT */
++			si_type[0] = "bt";
++			si_ports[0] = DEFAULT_BT_IO_PORT;
++			rv = init_one_smi(0, &(smi_infos[pos]));
++		}
++	}
++	if (rv == 0)
++		pos++;
++
++	for (i=1; i < SI_MAX_PARMS; i++) {
++		rv = init_one_smi(i, &(smi_infos[pos]));
++		if (rv == 0)
++			pos++;
++	}
++
++	if (smi_infos[0] == NULL) {
++		printk("ipmi_si: Unable to find any System Interface(s)\n");
++		return -ENODEV;
++	} 
++
++	return 0;
++}
++module_init(init_ipmi_si);
++
++#ifdef MODULE
++void __exit cleanup_one_si(struct smi_info *to_clean)
++{
++	int           rv;
++	unsigned long flags;
++
++	if (! to_clean)
++		return;
++
++	/* Tell the timer and interrupt handlers that we are shutting
++	   down. */
++	spin_lock_irqsave(&(to_clean->si_lock), flags);
++	spin_lock(&(to_clean->msg_lock));
++
++	to_clean->stop_operation = 1;
++
++	to_clean->irq_cleanup(to_clean);
++
++	spin_unlock(&(to_clean->msg_lock));
++	spin_unlock_irqrestore(&(to_clean->si_lock), flags);
++
++	/* Wait for the timer to stop.  This avoids problems with race
++	   conditions removing the timer here.  Hopefully this will be
++	   long enough to avoid problems with interrupts still
++	   running. */
++	set_current_state(TASK_UNINTERRUPTIBLE);
++	schedule_timeout(2);
++	while (!to_clean->timer_stopped) {
++		set_current_state(TASK_UNINTERRUPTIBLE);
++		schedule_timeout(1);
++	}
++
++	/* Interrupts and timeouts are stopped, now make sure the
++	   interface is in a clean state. */
++	while ((to_clean->curr_msg) || (to_clean->si_state != SI_NORMAL)) {
++		poll(to_clean);
++		schedule_timeout(1);
++	}
++
++	rv = ipmi_unregister_smi(to_clean->intf);
++	if (rv) {
++		printk(KERN_ERR 
++		       "ipmi_si: Unable to unregister device: errno=%d\n",
++		       rv);
++	}
++
++	to_clean->handlers->cleanup(to_clean->si_sm);
++
++	kfree(to_clean->si_sm);
++
++	to_clean->io_cleanup(to_clean);
++}
++
++static __exit void cleanup_ipmi_si(void)
++{
++	int i;
++
++	if (!initialized)
++		return;
++
++	for (i=0; i<SI_MAX_DRIVERS; i++) {
++		cleanup_one_si(smi_infos[i]);
++	}
++}
++module_exit(cleanup_ipmi_si);
++#else
++
++/* Unfortunately, cmdline::get_options() only returns integers, not
++   longs.  Since we need ulongs (64-bit physical addresses) parse the 
++   comma-separated list manually.  Arguments can be one of these forms:
++   m0xaabbccddeeff	A physical memory address without an IRQ
++   m0xaabbccddeeff:cc	A physical memory address with an IRQ
++   p0xaabb		An IO port without an IRQ
++   p0xaabb:cc		An IO port with an IRQ
++   nodefaults		Suppress trying the default IO port or ACPI address 
++
++   For example, to pass one IO port with an IRQ, one address, and 
++   suppress the use of the default IO port and ACPI address,
++   use this option string: ipmi_smi=p0xCA2:5,m0xFF5B0022,nodefaults
++
++   Remember, ipmi_si_setup() is passed the string after the equal sign. */
++
++static int __init ipmi_si_setup(char *str)
++{
++	unsigned long val;
++	char *cur, *colon;
++	int pos;
++
++	pos = 0;
++	
++	cur = strsep(&str, ",");
++	while ((cur) && (*cur) && (pos < SI_MAX_PARMS)) {
++		switch (*cur) {
++		case 'n':
++			if (strcmp(cur, "nodefaults") == 0)
++				si_trydefaults = 0;
++			else
++				printk(KERN_INFO 
++				       "ipmi_si: bad parameter value %s\n",
++				       cur);
++			break;
++
++		case 'k': /* KCS */
++			si_type[pos] = "kcs";
++			break;
++		
++		case 's': /* SMIC */
++			si_type[pos] = "smic";
++			break;
++		
++		case 'b': /* BT */
++			si_type[pos] = "bt";
++			break;
++		
++		case 'm':
++		case 'p':
++			val = simple_strtoul(cur + 1,
++					     &colon,
++					     0);
++			if (*cur == 'p')
++				si_ports[pos] = val;
++			else
++				si_addrs[pos] = val;
++			if (*colon == '#') {
++				val = simple_strtoul(colon + 1,
++						     &colon,
++						     0);
++				si_regspacings[pos] = val;
++				if (*colon == '.') {
++					val = simple_strtoul(colon + 1,
++							     &colon,
++							     0);
++					si_regsizes[pos] = val;
++				}
++				if (*colon == '.') {
++					val = simple_strtoul(colon + 1,
++							     &colon,
++							     0);
++					si_regshifts[pos] = val;
++				}
++			}
++			if (*colon == ':') {
++				val = simple_strtoul(colon + 1,
++						     &colon,
++						     0);
++				si_irqs[pos] = val;
++			}
++			pos++;
++			break;
++
++		default:
++			printk(KERN_INFO 
++			       "ipmi_si: bad parameter value %s\n",
++			       cur);
++		}
++		cur = strsep(&str, ",");
++	}
++
++	return 1;
++}
++__setup("ipmi_si=", ipmi_si_setup);
++#endif
++
++MODULE_LICENSE("GPL");
+Index: linux-ipmi/drivers/char/ipmi/ipmi_si_sm.h
+===================================================================
+--- linux-ipmi.orig/drivers/char/ipmi/ipmi_si_sm.h	1969-12-31 18:00:00.000000000 -0600
++++ linux-ipmi/drivers/char/ipmi/ipmi_si_sm.h	2004-08-13 08:06:49.000000000 -0500
+@@ -0,0 +1,120 @@
++/*
++ * ipmi_si_sm.h
++ *
++ * State machine interface for low-level IPMI system management
++ * interface state machines.  This code is the interface between
++ * the ipmi_smi code (that handles the policy of a KCS, SMIC, or
++ * BT interface) and the actual low-level state machine.
++ *
++ * Author: MontaVista Software, Inc.
++ *         Corey Minyard <minyard@mvista.com>
++ *         source@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.
++ *
++ *
++ *  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.
++ */
++
++/* This is defined by the state machines themselves, it is an opaque
++   data type for them to use. */
++struct si_sm_data;
++
++/* The structure for doing I/O in the state machine.  The state
++   machine doesn't have the actual I/O routines, they are done through
++   this interface. */
++struct si_sm_io
++{
++	unsigned char (*inputb)(struct si_sm_io *io, unsigned int offset);
++	void (*outputb)(struct si_sm_io *io,
++			unsigned int  offset,
++			unsigned char b);
++
++	/* Generic info used by the actual handling routines, the
++           state machine shouldn't touch these. */
++	void *info;
++	void *addr;
++	int  regspacing;
++	int  regsize;
++	int  regshift;
++};
++
++/* Results of SMI events. */
++enum si_sm_result
++{
++	SI_SM_CALL_WITHOUT_DELAY, /* Call the driver again immediately */
++	SI_SM_CALL_WITH_DELAY,	/* Delay some before calling again. */
++	SI_SM_TRANSACTION_COMPLETE, /* A transaction is finished. */
++	SI_SM_IDLE,		/* The SM is in idle state. */
++	SI_SM_HOSED,		/* The hardware violated the state machine. */
++	SI_SM_ATTN		/* The hardware is asserting attn and the
++				   state machine is idle. */
++};
++
++/* Handlers for the SMI state machine. */
++struct si_sm_handlers
++{
++	/* Put the version number of the state machine here so the
++           upper layer can print it. */
++	char *version;
++
++	/* Initialize the data and return the amount of I/O space to
++           reserve for the space. */
++	unsigned int (*init_data)(struct si_sm_data *smi,
++				  struct si_sm_io   *io);
++
++	/* Start a new transaction in the state machine.  This will
++	   return -2 if the state machine is not idle, -1 if the size
++	   is invalid (to large or too small), or 0 if the transaction
++	   is successfully completed. */
++	int (*start_transaction)(struct si_sm_data *smi,
++				 unsigned char *data, unsigned int size);
++
++	/* Return the results after the transaction.  This will return
++	   -1 if the buffer is too small, zero if no transaction is
++	   present, or the actual length of the result data. */
++	int (*get_result)(struct si_sm_data *smi,
++			  unsigned char *data, unsigned int length);
++
++	/* Call this periodically (for a polled interface) or upon
++	   receiving an interrupt (for a interrupt-driven interface).
++	   If interrupt driven, you should probably poll this
++	   periodically when not in idle state.  This should be called
++	   with the time that passed since the last call, if it is
++	   significant.  Time is in microseconds. */
++	enum si_sm_result (*event)(struct si_sm_data *smi, long time);
++
++	/* Attempt to detect an SMI.  Returns 0 on success or nonzero
++           on failure. */
++	int (*detect)(struct si_sm_data *smi);
++
++	/* The interface is shutting down, so clean it up. */
++	void (*cleanup)(struct si_sm_data *smi);
++
++	/* Return the size of the SMI structure in bytes. */
++	int (*size)(void);
++};
++
++/* Current state machines that we can use. */
++extern struct si_sm_handlers kcs_smi_handlers;
++extern struct si_sm_handlers smic_smi_handlers;
++extern struct si_sm_handlers bt_smi_handlers;
++
+Index: linux-ipmi/drivers/char/ipmi/ipmi_smic_sm.c
+===================================================================
+--- linux-ipmi.orig/drivers/char/ipmi/ipmi_smic_sm.c	1969-12-31 18:00:00.000000000 -0600
++++ linux-ipmi/drivers/char/ipmi/ipmi_smic_sm.c	2004-08-13 08:06:49.000000000 -0500
+@@ -0,0 +1,599 @@
++/*
++ * ipmi_smic_sm.c
++ *
++ * The state-machine driver for an IPMI SMIC driver
++ *
++ * It started as a copy of Corey Minyard's driver for the KSC interface
++ * and the kernel patch "mmcdev-patch-245" by HP
++ *
++ * modified by:	Hannes Schulz <schulz@schwaar.com>
++ *		ipmi@schwaar.com
++ *
++ *
++ * Corey Minyard's driver for the KSC interface has the following
++ * copyright notice:
++ *   Copyright 2002 MontaVista Software Inc.
++ *
++ * the kernel patch "mmcdev-patch-245" by HP has the following
++ * copyright notice:
++ * (c) Copyright 2001 Grant Grundler (c) Copyright
++ * 2001 Hewlett-Packard Company
++ * 
++ *
++ *  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/kernel.h> /* For printk. */
++#include <linux/string.h>
++#include <linux/ipmi_msgdefs.h>		/* for completion codes */
++#include "ipmi_si_sm.h"
++
++#define IPMI_SMIC_VERSION "v33"
++
++/* smic_debug is a bit-field 
++ *	SMIC_DEBUG_ENABLE -	turned on for now 
++ *	SMIC_DEBUG_MSG -	commands and their responses
++ *	SMIC_DEBUG_STATES -	state machine
++*/
++#define SMIC_DEBUG_STATES	4
++#define SMIC_DEBUG_MSG		2
++#define	SMIC_DEBUG_ENABLE	1
++
++static int smic_debug = 1;
++
++enum smic_states {
++	SMIC_IDLE,
++	SMIC_START_OP,
++	SMIC_OP_OK,
++	SMIC_WRITE_START,
++	SMIC_WRITE_NEXT,
++	SMIC_WRITE_END,
++	SMIC_WRITE2READ,
++	SMIC_READ_START,
++	SMIC_READ_NEXT,
++	SMIC_READ_END,
++	SMIC_HOSED
++};
++
++#define MAX_SMIC_READ_SIZE 80
++#define MAX_SMIC_WRITE_SIZE 80
++#define SMIC_MAX_ERROR_RETRIES 3
++
++/* Timeouts in microseconds. */
++#define SMIC_RETRY_TIMEOUT 100000
++
++/* SMIC Flags Register Bits */
++#define SMIC_RX_DATA_READY	0x80
++#define SMIC_TX_DATA_READY	0x40
++#define SMIC_SMI		0x10
++#define SMIC_EVM_DATA_AVAIL	0x08
++#define SMIC_SMS_DATA_AVAIL	0x04
++#define SMIC_FLAG_BSY		0x01
++
++/* SMIC Error Codes */
++#define	EC_NO_ERROR		0x00
++#define	EC_ABORTED		0x01
++#define	EC_ILLEGAL_CONTROL	0x02
++#define	EC_NO_RESPONSE		0x03
++#define	EC_ILLEGAL_COMMAND	0x04
++#define	EC_BUFFER_FULL		0x05
++
++struct si_sm_data
++{
++	enum smic_states state;
++	struct si_sm_io *io;
++        unsigned char	 write_data[MAX_SMIC_WRITE_SIZE];
++        int		 write_pos;
++        int		 write_count;
++        int		 orig_write_count;
++        unsigned char	 read_data[MAX_SMIC_READ_SIZE];
++        int		 read_pos;
++        int		 truncated;
++        unsigned int	 error_retries;
++        long		 smic_timeout;
++};
++
++static unsigned int init_smic_data (struct si_sm_data *smic,
++				    struct si_sm_io *io)
++{
++	smic->state = SMIC_IDLE;
++	smic->io = io;
++	smic->write_pos = 0;
++	smic->write_count = 0;
++	smic->orig_write_count = 0;
++	smic->read_pos = 0;
++	smic->error_retries = 0;
++	smic->truncated = 0;
++	smic->smic_timeout = SMIC_RETRY_TIMEOUT;
++
++	/* We use 3 bytes of I/O. */
++	return 3;
++}
++
++static int start_smic_transaction(struct si_sm_data *smic,
++				  unsigned char *data, unsigned int size)
++{
++	unsigned int i;
++
++	if ((size < 2) || (size > MAX_SMIC_WRITE_SIZE)) {
++		return -1;
++	}
++	if ((smic->state != SMIC_IDLE) && (smic->state != SMIC_HOSED)) {
++		return -2;
++	}
++	if (smic_debug & SMIC_DEBUG_MSG) {
++		printk(KERN_INFO "start_smic_transaction -");
++		for (i = 0; i < size; i ++) {
++			printk (" %02x", (unsigned char) (data [i]));
++		}
++		printk ("\n");
++	}
++	smic->error_retries = 0;
++	memcpy(smic->write_data, data, size);
++	smic->write_count = size;
++	smic->orig_write_count = size;
++	smic->write_pos = 0;
++	smic->read_pos = 0;
++	smic->state = SMIC_START_OP;
++	smic->smic_timeout = SMIC_RETRY_TIMEOUT;
++	return 0;
++}
++
++static int smic_get_result(struct si_sm_data *smic,
++			   unsigned char *data, unsigned int length)
++{
++	int i;
++
++	if (smic_debug & SMIC_DEBUG_MSG) {
++		printk (KERN_INFO "smic_get result -");
++		for (i = 0; i < smic->read_pos; i ++) {
++			printk (" %02x", (smic->read_data [i]));
++		}
++		printk ("\n");
++	}
++	if (length < smic->read_pos) {
++		smic->read_pos = length;
++		smic->truncated = 1;
++	}
++	memcpy(data, smic->read_data, smic->read_pos);
++
++	if ((length >= 3) && (smic->read_pos < 3)) {
++		data[2] = IPMI_ERR_UNSPECIFIED;
++		smic->read_pos = 3;
++	}
++	if (smic->truncated) {
++		data[2] = IPMI_ERR_MSG_TRUNCATED;
++		smic->truncated = 0;
++	}
++	return smic->read_pos;
++}
++
++static inline unsigned char read_smic_flags(struct si_sm_data *smic)
++{
++	return smic->io->inputb(smic->io, 2);
++}
++
++static inline unsigned char read_smic_status(struct si_sm_data *smic)
++{
++	return smic->io->inputb(smic->io, 1);
++}
++
++static inline unsigned char read_smic_data(struct si_sm_data *smic)
++{
++	return smic->io->inputb(smic->io, 0);
++}
++
++static inline void write_smic_flags(struct si_sm_data *smic,
++				    unsigned char   flags)
++{
++	smic->io->outputb(smic->io, 2, flags);
++}
++
++static inline void write_smic_control(struct si_sm_data *smic,
++				      unsigned char   control)
++{
++	smic->io->outputb(smic->io, 1, control);
++}
++
++static inline void write_si_sm_data (struct si_sm_data *smic,
++				   unsigned char   data)
++{
++	smic->io->outputb(smic->io, 0, data);
++}
++
++static inline void start_error_recovery(struct si_sm_data *smic, char *reason)
++{
++	(smic->error_retries)++;
++	if (smic->error_retries > SMIC_MAX_ERROR_RETRIES) {
++		if (smic_debug & SMIC_DEBUG_ENABLE) {
++			printk(KERN_WARNING
++			       "ipmi_smic_drv: smic hosed: %s\n", reason);
++		}	
++		smic->state = SMIC_HOSED;
++	} else {
++		smic->write_count = smic->orig_write_count;
++		smic->write_pos = 0;
++		smic->read_pos = 0;
++		smic->state = SMIC_START_OP;
++		smic->smic_timeout = SMIC_RETRY_TIMEOUT;
++	}
++}
++
++static inline void write_next_byte(struct si_sm_data *smic)
++{
++	write_si_sm_data(smic, smic->write_data[smic->write_pos]);
++	(smic->write_pos)++;
++	(smic->write_count)--;
++}
++
++static inline void read_next_byte (struct si_sm_data *smic)
++{
++	if (smic->read_pos >= MAX_SMIC_READ_SIZE) {
++		read_smic_data (smic);
++		smic->truncated = 1;
++	} else {
++		smic->read_data[smic->read_pos] = read_smic_data(smic);	
++		(smic->read_pos)++;
++	}
++}
++
++/*  SMIC Control/Status Code Components */
++#define	SMIC_GET_STATUS		0x00	/* Control form's name */
++#define	SMIC_READY		0x00	/* Status  form's name */
++#define	SMIC_WR_START		0x01	/* Unified Control/Status names... */
++#define	SMIC_WR_NEXT		0x02
++#define	SMIC_WR_END		0x03
++#define	SMIC_RD_START		0x04
++#define	SMIC_RD_NEXT		0x05
++#define	SMIC_RD_END		0x06
++#define	SMIC_CODE_MASK		0x0f
++
++#define	SMIC_CONTROL		0x00
++#define	SMIC_STATUS		0x80
++#define	SMIC_CS_MASK		0x80
++
++#define	SMIC_SMS		0x40
++#define	SMIC_SMM		0x60
++#define	SMIC_STREAM_MASK	0x60
++
++/*  SMIC Control Codes */
++#define	SMIC_CC_SMS_GET_STATUS	(SMIC_CONTROL|SMIC_SMS|SMIC_GET_STATUS)
++#define	SMIC_CC_SMS_WR_START	(SMIC_CONTROL|SMIC_SMS|SMIC_WR_START)
++#define	SMIC_CC_SMS_WR_NEXT	(SMIC_CONTROL|SMIC_SMS|SMIC_WR_NEXT)
++#define	SMIC_CC_SMS_WR_END	(SMIC_CONTROL|SMIC_SMS|SMIC_WR_END)
++#define	SMIC_CC_SMS_RD_START	(SMIC_CONTROL|SMIC_SMS|SMIC_RD_START)
++#define	SMIC_CC_SMS_RD_NEXT	(SMIC_CONTROL|SMIC_SMS|SMIC_RD_NEXT)
++#define	SMIC_CC_SMS_RD_END	(SMIC_CONTROL|SMIC_SMS|SMIC_RD_END)
++
++#define	SMIC_CC_SMM_GET_STATUS	(SMIC_CONTROL|SMIC_SMM|SMIC_GET_STATUS)
++#define	SMIC_CC_SMM_WR_START	(SMIC_CONTROL|SMIC_SMM|SMIC_WR_START)
++#define	SMIC_CC_SMM_WR_NEXT	(SMIC_CONTROL|SMIC_SMM|SMIC_WR_NEXT)
++#define	SMIC_CC_SMM_WR_END	(SMIC_CONTROL|SMIC_SMM|SMIC_WR_END)
++#define	SMIC_CC_SMM_RD_START	(SMIC_CONTROL|SMIC_SMM|SMIC_RD_START)
++#define	SMIC_CC_SMM_RD_NEXT	(SMIC_CONTROL|SMIC_SMM|SMIC_RD_NEXT)
++#define	SMIC_CC_SMM_RD_END	(SMIC_CONTROL|SMIC_SMM|SMIC_RD_END)
++
++/*  SMIC Status Codes */
++#define	SMIC_SC_SMS_READY	(SMIC_STATUS|SMIC_SMS|SMIC_READY)
++#define	SMIC_SC_SMS_WR_START	(SMIC_STATUS|SMIC_SMS|SMIC_WR_START)
++#define	SMIC_SC_SMS_WR_NEXT	(SMIC_STATUS|SMIC_SMS|SMIC_WR_NEXT)
++#define	SMIC_SC_SMS_WR_END	(SMIC_STATUS|SMIC_SMS|SMIC_WR_END)
++#define	SMIC_SC_SMS_RD_START	(SMIC_STATUS|SMIC_SMS|SMIC_RD_START)
++#define	SMIC_SC_SMS_RD_NEXT	(SMIC_STATUS|SMIC_SMS|SMIC_RD_NEXT)
++#define	SMIC_SC_SMS_RD_END	(SMIC_STATUS|SMIC_SMS|SMIC_RD_END)
++
++#define	SMIC_SC_SMM_READY	(SMIC_STATUS|SMIC_SMM|SMIC_READY)
++#define	SMIC_SC_SMM_WR_START	(SMIC_STATUS|SMIC_SMM|SMIC_WR_START)
++#define	SMIC_SC_SMM_WR_NEXT	(SMIC_STATUS|SMIC_SMM|SMIC_WR_NEXT)
++#define	SMIC_SC_SMM_WR_END	(SMIC_STATUS|SMIC_SMM|SMIC_WR_END)
++#define	SMIC_SC_SMM_RD_START	(SMIC_STATUS|SMIC_SMM|SMIC_RD_START)
++#define	SMIC_SC_SMM_RD_NEXT	(SMIC_STATUS|SMIC_SMM|SMIC_RD_NEXT)
++#define	SMIC_SC_SMM_RD_END	(SMIC_STATUS|SMIC_SMM|SMIC_RD_END)
++
++/* these are the control/status codes we actually use
++	SMIC_CC_SMS_GET_STATUS	0x40
++	SMIC_CC_SMS_WR_START	0x41
++	SMIC_CC_SMS_WR_NEXT	0x42
++	SMIC_CC_SMS_WR_END	0x43
++	SMIC_CC_SMS_RD_START	0x44
++	SMIC_CC_SMS_RD_NEXT	0x45
++	SMIC_CC_SMS_RD_END	0x46
++
++	SMIC_SC_SMS_READY	0xC0
++	SMIC_SC_SMS_WR_START	0xC1
++	SMIC_SC_SMS_WR_NEXT	0xC2
++	SMIC_SC_SMS_WR_END	0xC3
++	SMIC_SC_SMS_RD_START	0xC4
++	SMIC_SC_SMS_RD_NEXT	0xC5
++	SMIC_SC_SMS_RD_END	0xC6
++*/
++
++static enum si_sm_result smic_event (struct si_sm_data *smic, long time)
++{
++	unsigned char status;
++	unsigned char flags;
++	unsigned char data;
++
++	if (smic->state == SMIC_HOSED) {
++		init_smic_data(smic, smic->io);
++		return SI_SM_HOSED;
++	}
++	if (smic->state != SMIC_IDLE) {
++		if (smic_debug & SMIC_DEBUG_STATES) {
++			printk(KERN_INFO
++			       "smic_event - smic->smic_timeout = %ld,"
++			       " time = %ld\n",
++			       smic->smic_timeout, time);
++		}
++/* FIXME: smic_event is sometimes called with time > SMIC_RETRY_TIMEOUT */
++		if (time < SMIC_RETRY_TIMEOUT) {
++			smic->smic_timeout -= time;
++			if (smic->smic_timeout < 0) {
++				start_error_recovery(smic, "smic timed out.");
++				return SI_SM_CALL_WITH_DELAY;
++			}
++		}
++	}
++	flags = read_smic_flags(smic);
++	if (flags & SMIC_FLAG_BSY)
++		return SI_SM_CALL_WITH_DELAY;
++
++	status = read_smic_status (smic);
++	if (smic_debug & SMIC_DEBUG_STATES)
++		printk(KERN_INFO
++		       "smic_event - state = %d, flags = 0x%02x,"
++		       " status = 0x%02x\n",
++		       smic->state, flags, status);
++
++	switch (smic->state) {
++	case SMIC_IDLE:
++		/* in IDLE we check for available messages */
++		if (flags & (SMIC_SMI |
++			     SMIC_EVM_DATA_AVAIL | SMIC_SMS_DATA_AVAIL))
++		{
++			return SI_SM_ATTN;
++		}
++		return SI_SM_IDLE;
++
++	case SMIC_START_OP:
++		/* sanity check whether smic is really idle */
++		write_smic_control(smic, SMIC_CC_SMS_GET_STATUS);
++		write_smic_flags(smic, flags | SMIC_FLAG_BSY);
++		smic->state = SMIC_OP_OK;
++		break;
++
++	case SMIC_OP_OK:
++		if (status != SMIC_SC_SMS_READY) {
++				/* this should not happen */
++			start_error_recovery(smic,
++					     "state = SMIC_OP_OK,"
++					     " status != SMIC_SC_SMS_READY");
++			return SI_SM_CALL_WITH_DELAY;
++		}
++		/* OK so far; smic is idle let us start ... */
++		write_smic_control(smic, SMIC_CC_SMS_WR_START);
++		write_next_byte(smic);
++		write_smic_flags(smic, flags | SMIC_FLAG_BSY);
++		smic->state = SMIC_WRITE_START;
++		break;
++
++	case SMIC_WRITE_START:
++		if (status != SMIC_SC_SMS_WR_START) {
++			start_error_recovery(smic,
++					     "state = SMIC_WRITE_START, "
++					     "status != SMIC_SC_SMS_WR_START");
++			return SI_SM_CALL_WITH_DELAY;
++		}
++		/* we must not issue WR_(NEXT|END) unless
++                   TX_DATA_READY is set */
++		if (flags & SMIC_TX_DATA_READY) {
++			if (smic->write_count == 1) {
++				/* last byte */
++				write_smic_control(smic, SMIC_CC_SMS_WR_END);
++				smic->state = SMIC_WRITE_END;
++			} else {
++				write_smic_control(smic, SMIC_CC_SMS_WR_NEXT);
++				smic->state = SMIC_WRITE_NEXT;
++			}
++			write_next_byte(smic);
++			write_smic_flags(smic, flags | SMIC_FLAG_BSY);
++		}
++		else {
++			return SI_SM_CALL_WITH_DELAY;
++		}
++		break;
++
++	case SMIC_WRITE_NEXT:
++		if (status != SMIC_SC_SMS_WR_NEXT) {
++			start_error_recovery(smic,
++					     "state = SMIC_WRITE_NEXT, "
++					     "status != SMIC_SC_SMS_WR_NEXT");
++			return SI_SM_CALL_WITH_DELAY;
++		}
++		/* this is the same code as in SMIC_WRITE_START */
++		if (flags & SMIC_TX_DATA_READY) {
++			if (smic->write_count == 1) {
++				write_smic_control(smic, SMIC_CC_SMS_WR_END);
++				smic->state = SMIC_WRITE_END;
++			}
++			else {
++				write_smic_control(smic, SMIC_CC_SMS_WR_NEXT);
++				smic->state = SMIC_WRITE_NEXT;
++			}
++			write_next_byte(smic);
++			write_smic_flags(smic, flags | SMIC_FLAG_BSY);
++		}
++		else {
++			return SI_SM_CALL_WITH_DELAY;
++		}
++		break;
++
++	case SMIC_WRITE_END:
++		if (status != SMIC_SC_SMS_WR_END) {
++			start_error_recovery (smic,
++					      "state = SMIC_WRITE_END, "
++					      "status != SMIC_SC_SMS_WR_END");
++			return SI_SM_CALL_WITH_DELAY;
++		}
++		/* data register holds an error code */
++		data = read_smic_data(smic);
++		if (data != 0) {
++			if (smic_debug & SMIC_DEBUG_ENABLE) {
++				printk(KERN_INFO
++				       "SMIC_WRITE_END: data = %02x\n", data);
++			}
++			start_error_recovery(smic,
++					     "state = SMIC_WRITE_END, "
++					     "data != SUCCESS");
++			return SI_SM_CALL_WITH_DELAY;
++		} else {
++			smic->state = SMIC_WRITE2READ;
++		}
++		break;
++
++	case SMIC_WRITE2READ:
++		/* we must wait for RX_DATA_READY to be set before we
++                   can continue */
++		if (flags & SMIC_RX_DATA_READY) {
++			write_smic_control(smic, SMIC_CC_SMS_RD_START);
++			write_smic_flags(smic, flags | SMIC_FLAG_BSY);
++			smic->state = SMIC_READ_START;
++		} else {
++			return SI_SM_CALL_WITH_DELAY;
++		}
++		break;
++
++	case SMIC_READ_START:
++		if (status != SMIC_SC_SMS_RD_START) {
++			start_error_recovery(smic,
++					     "state = SMIC_READ_START, "
++					     "status != SMIC_SC_SMS_RD_START");
++			return SI_SM_CALL_WITH_DELAY;
++		}
++		if (flags & SMIC_RX_DATA_READY) {
++			read_next_byte(smic);
++			write_smic_control(smic, SMIC_CC_SMS_RD_NEXT);
++			write_smic_flags(smic, flags | SMIC_FLAG_BSY);
++			smic->state = SMIC_READ_NEXT;
++		} else {
++			return SI_SM_CALL_WITH_DELAY;
++		}
++		break;
++
++	case SMIC_READ_NEXT:
++		switch (status) {
++		/* smic tells us that this is the last byte to be read
++                   --> clean up */
++		case SMIC_SC_SMS_RD_END:
++			read_next_byte(smic);
++			write_smic_control(smic, SMIC_CC_SMS_RD_END);
++			write_smic_flags(smic, flags | SMIC_FLAG_BSY);
++			smic->state = SMIC_READ_END;
++			break;
++		case SMIC_SC_SMS_RD_NEXT:
++			if (flags & SMIC_RX_DATA_READY) {
++				read_next_byte(smic);
++				write_smic_control(smic, SMIC_CC_SMS_RD_NEXT);
++				write_smic_flags(smic, flags | SMIC_FLAG_BSY);
++				smic->state = SMIC_READ_NEXT;
++			} else {
++				return SI_SM_CALL_WITH_DELAY;
++			}
++			break;
++		default:
++			start_error_recovery(
++				smic,
++				"state = SMIC_READ_NEXT, "
++				"status != SMIC_SC_SMS_RD_(NEXT|END)");
++			return SI_SM_CALL_WITH_DELAY;
++		}
++		break;
++
++	case SMIC_READ_END:
++		if (status != SMIC_SC_SMS_READY) {
++			start_error_recovery(smic,
++					     "state = SMIC_READ_END, "
++					     "status != SMIC_SC_SMS_READY");
++			return SI_SM_CALL_WITH_DELAY;
++		}
++		data = read_smic_data(smic);
++		/* data register holds an error code */
++		if (data != 0) {
++			if (smic_debug & SMIC_DEBUG_ENABLE) {
++				printk(KERN_INFO
++				       "SMIC_READ_END: data = %02x\n", data);
++			}
++			start_error_recovery(smic,
++					     "state = SMIC_READ_END, "
++					     "data != SUCCESS");
++			return SI_SM_CALL_WITH_DELAY;
++		} else {
++			smic->state = SMIC_IDLE;
++			return SI_SM_TRANSACTION_COMPLETE;
++		}
++
++	case SMIC_HOSED:
++		init_smic_data(smic, smic->io);
++		return SI_SM_HOSED;
++
++	default:
++		if (smic_debug & SMIC_DEBUG_ENABLE) {
++			printk(KERN_WARNING "smic->state = %d\n", smic->state);
++			start_error_recovery(smic, "state = UNKNOWN");
++			return SI_SM_CALL_WITH_DELAY;
++		}
++	}
++	smic->smic_timeout = SMIC_RETRY_TIMEOUT;
++	return SI_SM_CALL_WITHOUT_DELAY;
++}
++
++static int smic_detect(struct si_sm_data *smic)
++{
++	/* It's impossible for the SMIC fnags register to be all 1's,
++	   (assuming a properly functioning, self-initialized BMC)
++	   but that's what you get from reading a bogus address, so we
++	   test that first. */
++	if (read_smic_flags(smic) == 0xff)
++		return 1; 
++
++	return 0;
++}
++
++static void smic_cleanup(struct si_sm_data *kcs)
++{
++}
++
++static int smic_size(void)
++{
++	return sizeof(struct si_sm_data);
++}
++
++struct si_sm_handlers smic_smi_handlers =
++{
++	.version           = IPMI_SMIC_VERSION,
++	.init_data         = init_smic_data,
++	.start_transaction = start_smic_transaction,
++	.get_result        = smic_get_result,
++	.event             = smic_event,
++	.detect            = smic_detect,
++	.cleanup           = smic_cleanup,
++	.size              = smic_size,
++};
+Index: linux-ipmi/drivers/char/ipmi/ipmi_watchdog.c
+===================================================================
+--- linux-ipmi.orig/drivers/char/ipmi/ipmi_watchdog.c	2004-08-13 08:05:37.000000000 -0500
++++ linux-ipmi/drivers/char/ipmi/ipmi_watchdog.c	2004-08-13 08:06:49.000000000 -0500
+@@ -50,6 +50,8 @@
+ #include <asm/apic.h>
+ #endif
+ 
++#define IPMI_WATCHDOG_VERSION "v33"
++
+ /*
+  * The IPMI command/response information for the watchdog timer.
+  */
+@@ -153,10 +155,18 @@
+ static char pretimeout_since_last_heartbeat = 0;
+ 
+ MODULE_PARM(timeout, "i");
++MODULE_PARM_DESC(timeout, "Timeout value in seconds.");
+ MODULE_PARM(pretimeout, "i");
++MODULE_PARM_DESC(pretimeout, "Pretimeout value in seconds.");
+ MODULE_PARM(action, "s");
++MODULE_PARM_DESC(action, "Timeout action. One of: "
++		 "reset, none, power_cycle, power_off.");
+ MODULE_PARM(preaction, "s");
++MODULE_PARM_DESC(preaction, "Pretimeout action.  One of: "
++		 "pre_none, pre_smi, pre_nmi, pre_int.");
+ MODULE_PARM(preop, "s");
++MODULE_PARM_DESC(preop, "Pretimeout driver operation.  One of: "
++		 "preop_none, preop_panic, preop_give_data.");
+ 
+ /* Default state of the timer. */
+ static unsigned char ipmi_watchdog_state = WDOG_TIMEOUT_NONE;
+@@ -260,6 +270,7 @@
+ 				      (struct ipmi_addr *) &addr,
+ 				      0,
+ 				      &msg,
++				      NULL,
+ 				      smi_msg,
+ 				      recv_msg,
+ 				      1);
+@@ -435,6 +446,7 @@
+ 				      (struct ipmi_addr *) &addr,
+ 				      0,
+ 				      &msg,
++				      NULL,
+ 				      &heartbeat_smi_msg,
+ 				      &heartbeat_recv_msg,
+ 				      1);
+@@ -483,6 +495,7 @@
+ 				 (struct ipmi_addr *) &addr,
+ 				 0,
+ 				 &msg,
++				 NULL,
+ 				 &panic_halt_heartbeat_smi_msg,
+ 				 &panic_halt_heartbeat_recv_msg,
+ 				 1);
+@@ -862,14 +875,12 @@
+ 
+ 	/* On a panic, if we have a panic timeout, make sure that the thing
+ 	   reboots, even if it hangs during that panic. */
+-	if (watchdog_user && !panic_event_handled && (panic_timeout > 0)) {
++	if (watchdog_user && !panic_event_handled) {
+ 		/* Make sure the panic doesn't hang, and make sure we
+ 		   do this only once. */
+ 		panic_event_handled = 1;
+ 	    
+-		timeout = panic_timeout + 120;
+-		if (timeout > 255)
+-			timeout = 255;
++		timeout = 255;
+ 		pretimeout = 0;
+ 		ipmi_watchdog_state = WDOG_TIMEOUT_RESET;
+ 		panic_halt_ipmi_set_timeout();
+@@ -899,6 +910,7 @@
+ 
+ static struct ipmi_smi_watcher smi_watcher =
+ {
++	.owner    = THIS_MODULE,
+ 	.new_smi  = ipmi_new_smi,
+ 	.smi_gone = ipmi_smi_gone
+ };
+@@ -907,6 +919,9 @@
+ {
+ 	int rv;
+ 
++	printk(KERN_INFO "IPMI watchdog driver version "
++	       IPMI_WATCHDOG_VERSION "\n");
++
+ 	if (strcmp(action, "reset") == 0) {
+ 		action_val = WDOG_TIMEOUT_RESET;
+ 	} else if (strcmp(action, "none") == 0) {
+@@ -995,9 +1010,6 @@
+ 	register_reboot_notifier(&wdog_reboot_notifier);
+ 	notifier_chain_register(&panic_notifier_list, &wdog_panic_notifier);
+ 
+-	printk(KERN_INFO "IPMI watchdog by "
+-	       "Corey Minyard (minyard@mvista.com)\n");
+-
+ 	return 0;
+ }
+ 
+@@ -1030,6 +1042,7 @@
+ 	   pointers to our buffers, we want to make sure they are done before
+ 	   we release our memory. */
+ 	while (atomic_read(&set_timeout_tofree)) {
++		set_current_state(TASK_UNINTERRUPTIBLE);
+ 		schedule_timeout(1);
+ 	}
+ 
+Index: linux-ipmi/drivers/char/ipmi/Makefile
+===================================================================
+--- linux-ipmi.orig/drivers/char/ipmi/Makefile	2004-08-13 08:05:37.000000000 -0500
++++ linux-ipmi/drivers/char/ipmi/Makefile	2004-08-19 07:58:47.000000000 -0500
+@@ -6,15 +6,21 @@
+ 
+ export-objs	:= ipmi_msghandler.o ipmi_watchdog.o
+ 
+-list-multi := ipmi_kcs_drv.o
++list-multi := ipmi_kcs_drv.o ipmi_si_drv.o
+ ipmi_kcs_drv-objs := ipmi_kcs_sm.o ipmi_kcs_intf.o
++ipmi_si_drv-objs := ipmi_si.o ipmi_kcs_sm.o ipmi_smic_sm.o ipmi_bt_sm.o
+ 
+ obj-$(CONFIG_IPMI_HANDLER) += ipmi_msghandler.o
+ obj-$(CONFIG_IPMI_DEVICE_INTERFACE) += ipmi_devintf.o
++obj-$(CONFIG_IPMI_SI) += ipmi_si_drv.o
+ obj-$(CONFIG_IPMI_KCS) += ipmi_kcs_drv.o
+ obj-$(CONFIG_IPMI_WATCHDOG) += ipmi_watchdog.o
++obj-$(CONFIG_IPMI_POWEROFF) += ipmi_poweroff.o
+ 
+ include $(TOPDIR)/Rules.make
+ 
+ ipmi_kcs_drv.o:	$(ipmi_kcs_drv-objs)
+ 	$(LD) -r -o $@ $(ipmi_kcs_drv-objs) 
++
++ipmi_si_drv.o:	$(ipmi_si_drv-objs)
++	$(LD) -r -o $@ $(ipmi_si_drv-objs) 
+Index: linux-ipmi/include/linux/ipmi.h
+===================================================================
+--- linux-ipmi.orig/include/linux/ipmi.h	2004-08-13 08:05:37.000000000 -0500
++++ linux-ipmi/include/linux/ipmi.h	2004-08-13 08:06:49.000000000 -0500
+@@ -109,6 +109,35 @@
+ 	unsigned char lun;
+ };
+ 
++/*
++ * A LAN Address.  This is an address to/from a LAN interface bridged
++ * by the BMC, not an address actually out on the LAN.
++ *
++ * A concious decision was made here to deviate slightly from the IPMI
++ * spec.  We do not use rqSWID and rsSWID like it shows in the
++ * message.  Instead, we use remote_SWID and local_SWID.  This means
++ * that any message (a request or response) from another device will
++ * always have exactly the same address.  If you didn't do this,
++ * requests and responses from the same device would have different
++ * addresses, and that's not too cool.
++ *
++ * In this address, the remote_SWID is always the SWID the remote
++ * message came from, or the SWID we are sending the message to.
++ * local_SWID is always our SWID.  Note that having our SWID in the
++ * message is a little wierd, but this is required.
++ */
++#define IPMI_LAN_ADDR_TYPE		0x04
++struct ipmi_lan_addr
++{
++	int           addr_type;
++	short         channel;
++	unsigned char privilege;
++	unsigned char session_handle;
++	unsigned char remote_SWID;
++	unsigned char local_SWID;
++	unsigned char lun;
++};
++
+ 
+ /*
+  * Channel for talking directly with the BMC.  When using this
+@@ -145,10 +174,20 @@
+  * Receive types for messages coming from the receive interface.  This
+  * is used for the receive in-kernel interface and in the receive
+  * IOCTL.
++ *
++ * The "IPMI_RESPONSE_RESPNOSE_TYPE" is a little strange sounding, but
++ * it allows you to get the message results when you send a response
++ * message.
+  */
+ #define IPMI_RESPONSE_RECV_TYPE		1 /* A response to a command */
+ #define IPMI_ASYNC_EVENT_RECV_TYPE	2 /* Something from the event queue */
+ #define IPMI_CMD_RECV_TYPE		3 /* A command from somewhere else */
++#define IPMI_RESPONSE_RESPONSE_TYPE	4 /* The response for
++					      a sent response, giving any
++					      error status for sending the
++					      response.  When you send a
++					      response message, this will
++					      be returned. */
+ /* Note that async events and received commands do not have a completion
+    code as the first byte of the incoming data, unlike a response. */
+ 
+@@ -160,6 +199,7 @@
+  * The in-kernel interface.
+  */
+ #include <linux/list.h>
++#include <linux/module.h>
+ 
+ /* Opaque type for a IPMI message user.  One of these is needed to
+    send and receive messages. */
+@@ -185,6 +225,12 @@
+ 	long             msgid;
+ 	struct ipmi_msg  msg;
+ 
++	/* The user_msg_data is the data supplied when a message was
++	   sent, if this is a response to a sent message.  If this is
++	   not a response to a sent message, then user_msg_data will
++	   be NULL. */
++	void             *user_msg_data;
++
+ 	/* Call this when done with the message.  It will presumably free
+ 	   the message and do any other necessary cleanup. */
+ 	void (*done)(struct ipmi_recv_msg *msg);
+@@ -206,9 +252,10 @@
+         /* Routine type to call when a message needs to be routed to
+ 	   the upper layer.  This will be called with some locks held,
+ 	   the only IPMI routines that can be called are ipmi_request
+-	   and the alloc/free operations. */
++	   and the alloc/free operations.  The handler_data is the
++	   variable supplied when the receive handler was registered. */
+ 	void (*ipmi_recv_hndl)(struct ipmi_recv_msg *msg,
+-			       void                 *handler_data);
++			       void                 *user_msg_data);
+ 
+ 	/* Called when the interface detects a watchdog pre-timeout.  If
+ 	   this is NULL, it will be ignored for the user. */
+@@ -221,7 +268,12 @@
+ 		     void                  *handler_data,
+ 		     ipmi_user_t           *user);
+ 
+-/* Destroy the given user of the IPMI layer. */
++/* Destroy the given user of the IPMI layer.  Note that after this
++   function returns, the system is guaranteed to not call any
++   callbacks for the user.  Thus as long as you destroy all the users
++   before you unload a module, you will be safe.  And if you destroy
++   the users before you destroy the callback structures, it should be
++   safe, too. */
+ int ipmi_destroy_user(ipmi_user_t user);
+ 
+ /* Get the IPMI version of the BMC we are talking to. */
+@@ -253,20 +305,51 @@
+  * in the msgid field of the received command.  If the priority is >
+  * 0, the message will go into a high-priority queue and be sent
+  * first.  Otherwise, it goes into a normal-priority queue.
++ * The user_msg_data field will be returned in any response to this
++ * message.
++ *
++ * Note that if you send a response (with the netfn lower bit set),
++ * you *will* get back a SEND_MSG response telling you what happened
++ * when the response was sent.  You will not get back a response to
++ * the message itself.
+  */
+ int ipmi_request(ipmi_user_t      user,
+ 		 struct ipmi_addr *addr,
+ 		 long             msgid,
+ 		 struct ipmi_msg  *msg,
++		 void             *user_msg_data,
+ 		 int              priority);
+ 
+ /*
++ * Like ipmi_request, but lets you specify the number of retries and
++ * the retry time.  The retries is the number of times the message
++ * will be resent if no reply is received.  If set to -1, the default
++ * value will be used.  The retry time is the time in milliseconds
++ * between retries.  If set to zero, the default value will be
++ * used.
++ *
++ * Don't use this unless you *really* have to.  It's primarily for the
++ * IPMI over LAN converter; since the LAN stuff does its own retries,
++ * it makes no sense to do it here.  However, this can be used if you
++ * have unusual requirements.
++ */
++int ipmi_request_settime(ipmi_user_t      user,
++			 struct ipmi_addr *addr,
++			 long             msgid,
++			 struct ipmi_msg  *msg,
++			 void             *user_msg_data,
++			 int              priority,
++			 int              max_retries,
++			 unsigned int     retry_time_ms);
++
++/*
+  * Like ipmi_request, but lets you specify the slave return address.
+  */
+ int ipmi_request_with_source(ipmi_user_t      user,
+ 			     struct ipmi_addr *addr,
+ 			     long             msgid,
+ 			     struct ipmi_msg  *msg,
++			     void             *user_msg_data,
+ 			     int              priority,
+ 			     unsigned char    source_address,
+ 			     unsigned char    source_lun);
+@@ -284,11 +367,22 @@
+ 			     struct ipmi_addr     *addr,
+ 			     long                 msgid,
+ 			     struct ipmi_msg      *msg,
++			     void                 *user_msg_data,
+ 			     void                 *supplied_smi,
+ 			     struct ipmi_recv_msg *supplied_recv,
+ 			     int                  priority);
+ 
+ /*
++ * Do polling on the IPMI interface the user is attached to.  This
++ * causes the IPMI code to do an immediate check for information from
++ * the driver and handle anything that is immediately pending.  This
++ * will not block in anyway.  This is useful if you need to implement
++ * polling from the user like you need to send periodic watchdog pings
++ * from a crash dump, or something like that.
++ */
++void ipmi_poll_interface(ipmi_user_t user);
++
++/*
+  * When commands come in to the SMS, the user can register to receive
+  * them.  Only one user can be listening on a specific netfn/cmd pair
+  * at a time, you will get an EBUSY error if the command is already
+@@ -304,6 +398,12 @@
+ 			    unsigned char cmd);
+ 
+ /*
++ * Allow run-to-completion mode to be set for the interface of
++ * a specific user.
++ */
++void ipmi_user_set_run_to_completion(ipmi_user_t user, int val);
++
++/*
+  * When the user is created, it will not receive IPMI events by
+  * default.  The user must set this to TRUE to get incoming events.
+  * The first user that sets this to TRUE will receive all events that
+@@ -331,6 +431,10 @@
+ {
+ 	struct list_head link;
+ 
++	/* You must set the owner to the current module, if you are in
++	   a module (generally just set it to "THIS_MODULE"). */
++	struct module *owner;
++
+ 	/* These two are called with read locks held for the interface
+ 	   the watcher list.  So you can add and remove users from the
+ 	   IPMI interface, send messages, etc., but you cannot add
+@@ -422,6 +526,29 @@
+ #define IPMICTL_SEND_COMMAND		_IOR(IPMI_IOC_MAGIC, 13,	\
+ 					     struct ipmi_req)
+ 
++/* Messages sent to the interface with timing parameters are this
++   format. */
++struct ipmi_req_settime
++{
++	struct ipmi_req req;
++
++	/* See ipmi_request_settime() above for details on these
++           values. */
++	int          retries;
++	unsigned int retry_time_ms;
++};
++/*
++ * Send a message to the interfaces with timing parameters.  error values
++ * are:
++ *   - EFAULT - an address supplied was invalid.
++ *   - EINVAL - The address supplied was not valid, or the command
++ *              was not allowed.
++ *   - EMSGSIZE - The message to was too large.
++ *   - ENOMEM - Buffers could not be allocated for the command.
++ */
++#define IPMICTL_SEND_COMMAND_SETTIME	_IOR(IPMI_IOC_MAGIC, 21,	\
++					     struct ipmi_req_settime)
++
+ /* Messages received from the interface are this format. */
+ struct ipmi_recv
+ {
+@@ -513,4 +640,18 @@
+ #define IPMICTL_SET_MY_LUN_CMD		_IOR(IPMI_IOC_MAGIC, 19, unsigned int)
+ #define IPMICTL_GET_MY_LUN_CMD		_IOR(IPMI_IOC_MAGIC, 20, unsigned int)
+ 
++/*
++ * Get/set the default timing values for an interface.  You shouldn't
++ * generally mess with these.
++ */
++struct ipmi_timing_parms
++{
++	int          retries;
++	unsigned int retry_time_ms;
++};
++#define IPMICTL_SET_TIMING_PARMS_CMD	_IOR(IPMI_IOC_MAGIC, 22, \
++					     struct ipmi_timing_parms)
++#define IPMICTL_GET_TIMING_PARMS_CMD	_IOR(IPMI_IOC_MAGIC, 23, \
++					     struct ipmi_timing_parms)
++
+ #endif /* __LINUX_IPMI_H */
+Index: linux-ipmi/include/linux/ipmi_msgdefs.h
+===================================================================
+--- linux-ipmi.orig/include/linux/ipmi_msgdefs.h	2004-08-13 08:05:37.000000000 -0500
++++ linux-ipmi/include/linux/ipmi_msgdefs.h	2004-08-13 08:06:49.000000000 -0500
+@@ -37,22 +37,65 @@
+ /* Various definitions for IPMI messages used by almost everything in
+    the IPMI stack. */
+ 
+-#define IPMI_NETFN_APP_REQUEST	0x06
+-#define IPMI_NETFN_APP_RESPONSE	0x07
+-
+-#define IPMI_BMC_SLAVE_ADDR	0x20
++/* NetFNs and commands used inside the IPMI stack. */
++ 
++#define IPMI_NETFN_SENSOR_EVENT_REQUEST		0x04
++#define IPMI_NETFN_SENSOR_EVENT_RESPONSE	0x05
++#define IPMI_GET_EVENT_RECEIVER_CMD	0x01
+ 
++#define IPMI_NETFN_APP_REQUEST			0x06
++#define IPMI_NETFN_APP_RESPONSE			0x07
+ #define IPMI_GET_DEVICE_ID_CMD		0x01
+-
+ #define IPMI_CLEAR_MSG_FLAGS_CMD	0x30
+ #define IPMI_GET_MSG_FLAGS_CMD		0x31
+ #define IPMI_SEND_MSG_CMD		0x34
+ #define IPMI_GET_MSG_CMD		0x33
+-
+ #define IPMI_SET_BMC_GLOBAL_ENABLES_CMD	0x2e
+ #define IPMI_GET_BMC_GLOBAL_ENABLES_CMD	0x2f
+ #define IPMI_READ_EVENT_MSG_BUFFER_CMD	0x35
++#define IPMI_GET_CHANNEL_INFO_CMD	0x42
++
++#define IPMI_NETFN_STORAGE_REQUEST		0x0a
++#define IPMI_NETFN_STORAGE_RESPONSE		0x0b
++#define IPMI_ADD_SEL_ENTRY_CMD		0x44
++
++/* The default slave address */
++#define IPMI_BMC_SLAVE_ADDR	0x20
+ 
+-#define IPMI_MAX_MSG_LENGTH	80
++/* The BT interface on high-end HP systems supports up to 255 bytes in
++ * one transfer.  Its "virtual" BMC supports some commands that are longer
++ * than 128 bytes.  Use the full 256, plus NetFn/LUN, Cmd, cCode, plus
++ * some overhead.  It would be nice to base this on the "BT Capabilities"
++ * but that's too hard to propogate to the rest of the driver. */
++#define IPMI_MAX_MSG_LENGTH	272	/* multiple of 16 */
++
++#define IPMI_CC_NO_ERROR		0x00
++#define IPMI_NODE_BUSY_ERR		0xc0
++#define IPMI_INVALID_COMMAND_ERR	0xc1
++#define IPMI_ERR_MSG_TRUNCATED		0xc6
++#define IPMI_LOST_ARBITRATION_ERR	0x81
++#define IPMI_ERR_UNSPECIFIED		0xff
++
++#define IPMI_CHANNEL_PROTOCOL_IPMB	1
++#define IPMI_CHANNEL_PROTOCOL_ICMB	2
++#define IPMI_CHANNEL_PROTOCOL_SMBUS	4
++#define IPMI_CHANNEL_PROTOCOL_KCS	5
++#define IPMI_CHANNEL_PROTOCOL_SMIC	6
++#define IPMI_CHANNEL_PROTOCOL_BT10	7
++#define IPMI_CHANNEL_PROTOCOL_BT15	8
++#define IPMI_CHANNEL_PROTOCOL_TMODE	9
++
++#define IPMI_CHANNEL_MEDIUM_IPMB	1
++#define IPMI_CHANNEL_MEDIUM_ICMB10	2
++#define IPMI_CHANNEL_MEDIUM_ICMB09	3
++#define IPMI_CHANNEL_MEDIUM_8023LAN	4
++#define IPMI_CHANNEL_MEDIUM_ASYNC	5
++#define IPMI_CHANNEL_MEDIUM_OTHER_LAN	6
++#define IPMI_CHANNEL_MEDIUM_PCI_SMBUS	7
++#define IPMI_CHANNEL_MEDIUM_SMBUS1	8
++#define IPMI_CHANNEL_MEDIUM_SMBUS2	9
++#define IPMI_CHANNEL_MEDIUM_USB1	10
++#define IPMI_CHANNEL_MEDIUM_USB2	11
++#define IPMI_CHANNEL_MEDIUM_SYSINTF	12
+ 
+ #endif /* __LINUX_IPMI_MSGDEFS_H */
+Index: linux-ipmi/include/linux/ipmi_smi.h
+===================================================================
+--- linux-ipmi.orig/include/linux/ipmi_smi.h	2004-08-13 08:05:37.000000000 -0500
++++ linux-ipmi/include/linux/ipmi_smi.h	2004-08-13 14:05:47.000000000 -0500
+@@ -35,6 +35,8 @@
+ #define __LINUX_IPMI_SMI_H
+ 
+ #include <linux/ipmi_msgdefs.h>
++#include <linux/proc_fs.h>
++#include <linux/module.h>
+ 
+ /* This files describes the interface for IPMI system management interface
+    drivers to bind into the IPMI message handler. */
+@@ -48,7 +50,7 @@
+  * been received, it will report this same data structure back up to
+  * the upper layer.  If an error occurs, it should fill in the
+  * response with an error code in the completion code location. When
+- * asyncronous data is received, one of these is allocated, the
++ * asynchronous data is received, one of these is allocated, the
+  * data_size is set to zero and the response holds the data from the
+  * get message or get event command that the interface initiated.
+  * Note that it is the interfaces responsibility to detect
+@@ -62,9 +64,6 @@
+ 	long    msgid;
+ 	void    *user_data;
+ 
+-	/* If 0, add to the end of the queue.  If 1, add to the beginning. */
+-	int     prio;
+-
+ 	int           data_size;
+ 	unsigned char data[IPMI_MAX_MSG_LENGTH];
+ 
+@@ -108,6 +107,10 @@
+ 	   out and that none are pending, and any new requests are run
+ 	   to completion immediately. */
+ 	void (*set_run_to_completion)(void *send_info, int run_to_completion);
++
++	/* Called to poll for work to do.  This is so upper layers can
++	   poll for operations during things like crash dumps. */
++	void (*poll)(void *send_info);
+ };
+ 
+ /* Add a low-level interface to the IPMI driver. */
+@@ -141,4 +144,11 @@
+ 	msg->done(msg);
+ }
+ 
++/* Allow the lower layer to add things to the proc filesystem
++   directory for this interface.  Note that the entry will
++   automatically be dstroyed when the interface is destroyed. */
++int ipmi_smi_add_proc_entry(ipmi_smi_t smi, char *name,
++			    read_proc_t *read_proc, write_proc_t *write_proc,
++			    void *data, struct module *owner);
++
+ #endif /* __LINUX_IPMI_SMI_H */
+Index: linux-ipmi/kernel/panic.c
+===================================================================
+--- linux-ipmi.orig/kernel/panic.c	2004-08-13 08:05:37.000000000 -0500
++++ linux-ipmi/kernel/panic.c	2004-08-13 08:06:49.000000000 -0500
+@@ -74,7 +74,7 @@
+ 	smp_send_stop();
+ #endif
+ 
+-	notifier_call_chain(&panic_notifier_list, 0, NULL);
++	notifier_call_chain(&panic_notifier_list, 0, buf);
+ 
+ 	if (panic_timeout > 0)
+ 	{
Index: pplinux/linuxnew/patches/linux-ipmi-2.4.27-v33-emu.diff
diff -u /dev/null pplinux/linuxnew/patches/linux-ipmi-2.4.27-v33-emu.diff:1.1
--- /dev/null	Tue May 24 10:38:00 2005
+++ pplinux/linuxnew/patches/linux-ipmi-2.4.27-v33-emu.diff	Thu Feb  3 11:35:39 2005
@@ -0,0 +1,2140 @@
+Index: linux-ipmi/Documentation/Configure.help
+===================================================================
+--- linux-ipmi.orig/Documentation/Configure.help	2004-08-10 19:03:28.000000000 -0500
++++ linux-ipmi/Documentation/Configure.help	2004-08-10 19:03:53.000000000 -0500
+@@ -25605,6 +25605,17 @@
+   a debugging option; you probably do not want to set it unless you
+   are an S390 port maintainer.
+ 
++Emulate Radisys IPMI driver
++CONFIG_IPMI_EMULATE_RADISYS
++  This enables emulation of the Radisys IPMI device driver.
++
++Emulate Intel IBM driver
++CONFIG_IPMI_EMULATE_IMB
++  This enables emulation of the Intel IMB device driver.  Note that you
++  MUST have the IPMI watchdog timer enabled to use this.  This code
++  uses some of the watchdog code, but the dependency is not enforced
++  by config.
++
+ #
+ # ARM options
+ #
+Index: linux-ipmi/drivers/char/Config.in
+===================================================================
+--- linux-ipmi.orig/drivers/char/Config.in	2004-08-10 19:03:19.000000000 -0500
++++ linux-ipmi/drivers/char/Config.in	2004-08-10 19:03:53.000000000 -0500
+@@ -237,6 +237,8 @@
+ dep_tristate '  IPMI SMBus handler' CONFIG_IPMI_SMB $CONFIG_IPMI_HANDLER $CONFIG_I2C
+ dep_tristate '  IPMI Watchdog Timer' CONFIG_IPMI_WATCHDOG $CONFIG_IPMI_HANDLER
+ dep_tristate '  IPMI Poweroff' CONFIG_IPMI_POWEROFF $CONFIG_IPMI_HANDLER
++dep_tristate '  Emulate Radisys IPMI driver' CONFIG_IPMI_EMULATE_RADISYS $CONFIG_IPMI_HANDLER
++dep_tristate '  Emulate Intel IMB driver' CONFIG_IPMI_EMULATE_IMB $CONFIG_IPMI_WATCHDOG
+ 
+ mainmenu_option next_comment
+ comment 'Watchdog Cards'
+Index: linux-ipmi/drivers/char/ipmi/ipmi_imb.c
+===================================================================
+--- linux-ipmi.orig/drivers/char/ipmi/ipmi_imb.c	1969-12-31 18:00:00.000000000 -0600
++++ linux-ipmi/drivers/char/ipmi/ipmi_imb.c	2004-08-10 19:03:53.000000000 -0500
+@@ -0,0 +1,949 @@
++/*
++ * ipmi_imb.c
++ *
++ * Intel IMB emulation for the IPMI interface.
++ *
++ * Author: MontaVista Software, Inc.
++ *         Corey Minyard <minyard@mvista.com>
++ *         source@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.
++ *
++ *
++ *  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 <linux/module.h>
++#include <linux/errno.h>
++#include <asm/system.h>
++#include <linux/sched.h>
++#include <linux/poll.h>
++#include <linux/spinlock.h>
++#include <linux/slab.h>
++#include <linux/devfs_fs_kernel.h>
++#include <linux/ipmi.h>
++#include <linux/ipmi_imb.h>
++
++
++#define IPMI_IMB_VERSION   "v33"
++#define MAX_BUFFER_SIZE                 64
++#define BMC_SA				0x20
++
++struct waiting_rsp
++{
++	/* The message id being waited for. */
++	unsigned long     msgid;
++
++	/* Used to wake the waiting thread. */
++	wait_queue_head_t waitq;
++
++	/* The message handler puts the message here. */
++	struct ipmi_recv_msg *msg;
++
++	struct list_head link;
++};
++
++struct priv_data
++{
++	/* This is for supporting the old Imb interface. */
++	ipmi_user_t       imb_user;
++	spinlock_t        imb_lock;
++
++	unsigned long     curr_msgid;
++
++	/* A list of responses waiting in the queue, a list of struct
++	   waiting_rsp. */
++	struct list_head  imb_waiting_rsps;
++
++	/* A list of commands that have come in. */
++	struct list_head  imb_waiting_cmds;
++
++	/* First async command sequence number in list of commands that have come in.*/
++	unsigned long    FirstCmdSeqenceNo;
++	/* Last async command sequence number in list of commands that have come in.*/
++	unsigned long    LastCmdSeqenceNo;
++
++	/* A list of thing waiting for commands.  We wake them all up
++	   when a command comes in. */
++	wait_queue_head_t imb_waiting_cmd_rcvrs;
++
++	/* The registered command receiver value.  This only allows someone
++	   with the "magic number" to issue commands. */
++	unsigned long     imb_cmd_receiver;
++
++	/* Is someone already waiting for a command?  The Imb driver
++	   only allows one waiter, this enforces that. */
++	int               imb_cmd_waiting;
++
++	/* A list of IPMI events waiting to be delivered.  (not that
++           the Imb driver calls incoming commands "events", this
++           variable is actually IPMI events, not incoming commands). */
++	struct list_head  imb_waiting_events;
++
++#define IMB_EVENT_QUEUE_LIMIT	16 /* Allow up to 16 events. */
++	/* The number of events in the event queue. */
++	unsigned int      imb_waiting_event_count;
++};
++
++static devfs_handle_t devfs_handle;
++
++
++/* We cheat and use a piece of the address as the timeout. */
++static long *imb_timeout(struct ipmi_recv_msg *msg)
++{
++	char *base = (char *) &(msg->addr);
++	if(msg->addr.addr_type == IPMI_LAN_ADDR_TYPE )
++		base += sizeof(struct ipmi_lan_addr);
++	else
++		base += sizeof(struct ipmi_ipmb_addr);
++	return (long *) base;
++}
++
++static void imb_msg_recv(struct ipmi_recv_msg *msg,
++			 void                 *data)
++{
++	struct priv_data *priv = data;
++	unsigned long    flags;
++	struct list_head   *entry;
++	struct waiting_rsp *rsp;
++
++	spin_lock_irqsave(&(priv->imb_lock), flags);
++	if (msg->recv_type == IPMI_RESPONSE_RECV_TYPE ||
++	     msg->recv_type == IPMI_RESPONSE_RESPONSE_TYPE) {
++
++		list_for_each(entry, &(priv->imb_waiting_rsps)) {
++			rsp = list_entry(entry, struct waiting_rsp, link);
++			if (rsp->msgid == msg->msgid) {
++				rsp->msg = msg;
++				msg = NULL;
++				list_del(entry);
++				wake_up(&(rsp->waitq));
++				break;
++			}
++		}
++		if (msg) {
++//			printk(KERN_INFO "imb_msg_recv: DROPPING netfn %x/cmd %x/type %x/channel %x/msgid %ld\n",
++//						msg->msg.netfn, msg->msg.cmd, msg->addr.addr_type, msg->addr.channel, msg->msgid);
++			/* No waiter found, this was either a "don't
++			 * wait for the response" message or the
++			 * waiter was interrupted. */
++			ipmi_free_recv_msg(msg);
++		}
++	} else if (msg->recv_type == IPMI_CMD_RECV_TYPE) {
++		/* Leave commands in the command wait queue for 5 seconds. */
++		/* All commands in the command wait queue are left to timeout. */
++		*imb_timeout(msg) = 5000;
++		priv->LastCmdSeqenceNo += 1;
++		list_add_tail(&(msg->link), &(priv->imb_waiting_cmds));
++		wake_up_all(&(priv->imb_waiting_cmd_rcvrs));
++	
++	} else if (msg->recv_type == IPMI_ASYNC_EVENT_RECV_TYPE) {
++		if (priv->imb_waiting_event_count > IMB_EVENT_QUEUE_LIMIT) {
++			ipmi_free_recv_msg(msg);
++		} else {
++			list_add_tail(&(msg->link),&(priv->imb_waiting_events));
++			(priv->imb_waiting_event_count)++;
++		}
++	} else {
++		ipmi_free_recv_msg(msg);
++	}
++	spin_unlock_irqrestore(&(priv->imb_lock), flags);
++}
++
++/* We emulate the event queue in the driver for the imb emulation. */
++static int imb_handle_event_request(struct priv_data     *priv,
++				    struct ipmi_recv_msg **rsp)
++{
++	struct list_head     *entry;
++	unsigned long        flags;
++	struct ipmi_recv_msg *msg = NULL;
++	int                  rv = 0;
++
++	spin_lock_irqsave(&(priv->imb_lock), flags);
++	if (list_empty(&(priv->imb_waiting_events))) {
++		/* Nothing in the event queue, just return an error. */
++		msg = ipmi_alloc_recv_msg();
++		if (msg == NULL) {
++			rv = -EAGAIN;
++			goto out_err;
++		}
++		msg->addr.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
++		msg->addr.channel = IPMI_BMC_CHANNEL;
++		msg->msg.cmd = IPMI_READ_EVENT_MSG_BUFFER_CMD;
++		msg->msgid = 0;
++		msg->recv_type = IPMI_ASYNC_EVENT_RECV_TYPE;
++		msg->msg.netfn = IPMI_NETFN_APP_RESPONSE;
++		msg->msg.data = msg->msg_data;
++		msg->msg.data[0] = 0x80; /* Data not available. */
++		msg->msg.data_len = 1;
++	} else {
++		/* Pull an item from the event queue . */
++		entry = priv->imb_waiting_events.next;
++		list_del(entry);
++		msg = list_entry(entry, struct ipmi_recv_msg, link);
++		(priv->imb_waiting_event_count)--;
++	}
++
++	*rsp = msg;
++
++ out_err:
++	spin_unlock_irqrestore(&(priv->imb_lock), flags);
++	return rv;
++}
++
++static struct priv_data *ipmi_user;
++static unsigned int user_count = 0; /* How many users have this open. */
++static spinlock_t dev_lock = SPIN_LOCK_UNLOCKED;
++
++static int ipmi_imb_open(struct inode *inode, struct file *file)
++{
++	int rv;
++
++	if (user_count == 0) {
++		rv = ipmi_register_all_cmd_rcvr(ipmi_user->imb_user);
++		if (rv)	{
++			return rv;
++		}
++	}
++
++	file->private_data = ipmi_user;
++	spin_lock(&dev_lock);
++	if (user_count == 0)
++		ipmi_set_gets_events(ipmi_user->imb_user, 1);
++	user_count++;
++	spin_unlock(&dev_lock);
++
++	return 0;
++}
++
++static int ipmi_imb_release(struct inode *inode, struct file *file)
++{
++	spin_lock(&dev_lock);
++	user_count--;
++	if (user_count == 0) {
++		ipmi_set_gets_events(ipmi_user->imb_user, 0);
++		ipmi_unregister_all_cmd_rcvr(ipmi_user->imb_user);
++	}
++	spin_unlock(&dev_lock);
++	return 0;
++}
++
++static unsigned char
++ipmb_checksum(unsigned char *data, int size)
++{
++	unsigned char csum = 0;
++
++	for (; size > 0; size--, data++)
++		csum += *data;
++
++	return -csum;
++}
++
++extern void ipmi_delayed_shutdown(long delay, int power_off);
++
++static int ipmi_imb_ioctl(struct inode  *inode,
++			  struct file   *file,
++			  unsigned int  cmd,
++			  unsigned long data)
++{
++	struct priv_data *priv = file->private_data;
++	int              rv = -EINVAL;
++	struct smi       smi;
++	unsigned long    flags;
++
++	if (copy_from_user((caddr_t)&smi, (caddr_t)data, sizeof(smi))) {
++		return -EFAULT;
++	}
++
++	switch(cmd) {
++	case IOCTL_IMB_POLL_ASYNC:
++		/*
++		 * No-op for this, the low-level driver polls.
++		 * Successful return is needed, though.
++		 */
++		rv = 0;
++		break;
++
++	case IOCTL_IMB_GET_ASYNC_MSG:
++	{
++		unsigned char        req[MAX_ASYNC_RESP_SIZE];
++		unsigned char        resp[MAX_ASYNC_RESP_SIZE];
++		unsigned long	     seq = 0;
++		struct ipmi_recv_msg *msg = NULL;
++		ImbAsyncRequest      *pAsyncReq = (ImbAsyncRequest *) req;
++		ImbAsyncResponse     *pAsyncResp = (ImbAsyncResponse *) resp;
++		unsigned long        length = 0;
++
++		if (smi.cbInBuffer < sizeof(ImbAsyncRequest))
++			return -EINVAL;
++		if (smi.cbOutBuffer < MIN_ASYNC_RESP_SIZE)
++			return -EINVAL;
++
++		if (copy_from_user( pAsyncReq, smi.lpvInBuffer,
++					sizeof(ImbAsyncRequest)) == -1) {
++			return(-EFAULT);
++		}
++
++		spin_lock_irqsave(&(priv->imb_lock), flags);
++		while (msg == NULL) {
++			wait_queue_t wait;
++			if( (! list_empty(&(priv->imb_waiting_cmds)))  &&
++			    (pAsyncReq->lastSeq < priv->LastCmdSeqenceNo) ) {
++				struct list_head *entry, *entry2;
++				unsigned long inc = priv->FirstCmdSeqenceNo+1;
++
++				seq = pAsyncReq->lastSeq;
++				if (seq < priv->FirstCmdSeqenceNo)
++					seq = priv->FirstCmdSeqenceNo;
++				seq ++;
++				list_for_each_safe(entry, entry2, &(priv->imb_waiting_cmds)) {
++					if (seq == inc) {
++						msg = list_entry(entry, struct ipmi_recv_msg, link);
++						break;
++					}
++					inc ++ ;
++				}
++				if (msg != NULL)
++					break;
++			}
++			// AsyncReq->timeOut is not used anymore
++			// remove the following line to reenable timeouts
++			pAsyncReq->timeOut = 0;
++			if (pAsyncReq->timeOut == 0) {
++				/* No command waiting, just return an error. */
++				rv = IMB_NO_ASYNC_MSG;
++				break;
++			}
++
++			init_waitqueue_entry(&wait, current);
++			add_wait_queue(&(priv->imb_waiting_cmd_rcvrs),
++			       &wait);
++			set_current_state(TASK_INTERRUPTIBLE);
++			if (!signal_pending(current)) {
++				spin_unlock_irqrestore
++					(&(priv->imb_lock), flags);
++				schedule();
++				spin_lock_irqsave
++					(&(priv->imb_lock), flags);
++			} else {
++				rv = -ERESTARTSYS;
++			}
++			remove_wait_queue(&(priv->imb_waiting_cmd_rcvrs),
++					  &wait);
++			if (rv ==  -ERESTARTSYS)
++				break;
++			// decrement timeOut Usec by 1/10 second or 100000 usec
++			if (pAsyncReq->timeOut < 100000 )
++				pAsyncReq->timeOut = 0;
++			else
++				pAsyncReq->timeOut -= 100000;
++		}
++		spin_unlock_irqrestore(&(priv->imb_lock), flags);
++
++		if (msg != NULL) {
++			pAsyncResp->thisSeq = seq;
++
++//			pAsyncResp->data[0] = IPMI_NETFN_APP_REQUEST << 2;
++//			pAsyncResp->data[1] = IPMI_GET_MSG_CMD;
++//			pAsyncResp->data[2] = 0;
++			if (msg->addr.addr_type == IPMI_IPMB_ADDR_TYPE) {
++				struct ipmi_ipmb_addr *ipmb_addr;
++				ipmb_addr = (struct ipmi_ipmb_addr *) &(msg->addr);
++				pAsyncResp->data[0] = msg->addr.channel;
++				pAsyncResp->data[1] = ((msg->msg.netfn << 2)
++						     | 2);
++				pAsyncResp->data[2]
++					= ipmb_checksum(&(pAsyncResp->data[1]),
++							1);
++				pAsyncResp->data[3] = ipmb_addr->slave_addr;
++				pAsyncResp->data[4] = ((msg->msgid << 2)
++						     | ipmb_addr->lun);
++				pAsyncResp->data[5] = msg->msg.cmd;
++
++				memcpy(&(pAsyncResp->data[6]),
++				       &(msg->msg.data[0]),
++				       msg->msg.data_len);
++
++				length = sizeof(pAsyncResp->thisSeq) +
++					msg->msg.data_len + 7; //MIN_ASYNC_RESP_SIZE;
++
++				pAsyncResp->data[length-1]
++					= ipmb_checksum(&(pAsyncResp->data[1]),
++							length-2);
++			} else  if (msg->addr.addr_type == IPMI_LAN_ADDR_TYPE) {
++				struct ipmi_lan_addr *lan_addr;
++				lan_addr = (struct ipmi_lan_addr *) &(msg->addr);
++
++				pAsyncResp->data[0] = (lan_addr->privilege<<4) | lan_addr->channel;
++				pAsyncResp->data[1] = lan_addr->session_handle;
++				pAsyncResp->data[2] = lan_addr->local_SWID;
++				pAsyncResp->data[3] = ((msg->msg.netfn << 2)
++						     | 2);
++				pAsyncResp->data[4]
++					= ipmb_checksum(&(pAsyncResp->data[2]),
++							2);
++				pAsyncResp->data[5] = lan_addr->remote_SWID;
++				pAsyncResp->data[6] = ((msg->msgid << 2)
++						     | lan_addr->lun);
++				pAsyncResp->data[7] = msg->msg.cmd;
++
++				memcpy(&(pAsyncResp->data[8]),
++				       &(msg->msg.data[0]),
++				       msg->msg.data_len);
++
++				length = msg->msg.data_len + 8; //MIN_ASYNC_RESP_SIZE;
++
++				pAsyncResp->data[length]
++					= ipmb_checksum(&(pAsyncResp->data[5]),
++							length-5);
++				length += sizeof(pAsyncResp->thisSeq) + 1;
++			}
++
++			if (copy_to_user(smi.lpvOutBuffer, pAsyncResp, length))
++			{
++				return -EFAULT;
++			}
++			rv = STATUS_SUCCESS;
++		}
++		if (copy_to_user(smi.lpcbBytesReturned,
++				 &length,
++				 sizeof(length)))
++		{
++			return -EFAULT;
++		}
++		break;
++	}
++		
++	case IOCTL_IMB_SEND_MESSAGE:
++	{
++		unsigned char        imbReqBuffer[MAX_IMB_RESPONSE_SIZE + 8];
++		unsigned char        imbRespBuffer[MAX_IMB_RESPONSE_SIZE + 8];
++		ImbRequestBuffer     *pImbReq=(ImbRequestBuffer *)imbReqBuffer;
++		ImbResponseBuffer    *pImbResp=(ImbResponseBuffer*)imbRespBuffer;
++		struct ipmi_addr     addr;
++		struct ipmi_msg      msg;
++		unsigned long        msgid = 0;
++		     unsigned char    source_address = 0;
++		     unsigned char    source_lun = 0;
++		struct ipmi_recv_msg *rsp = NULL;
++		unsigned long        length;
++		wait_queue_t         wait;
++		struct waiting_rsp   waiter;
++
++
++		if ((smi.cbInBuffer < MIN_IMB_REQ_BUF_SIZE)
++		    || (smi.cbOutBuffer < MIN_IMB_RESP_BUF_SIZE))
++		{
++			return -EINVAL;
++		}
++
++		if (smi.cbInBuffer > MAX_BUFFER_SIZE) {
++			/* Input buffer is too large */
++			return -EINVAL;
++		}
++
++		if (copy_from_user(pImbReq, smi.lpvInBuffer, smi.cbInBuffer)) {
++			return -EFAULT;
++		}
++		if ((pImbReq->req.dataLength + MIN_IMB_REQ_BUF_SIZE)
++		    > smi.cbInBuffer)
++		{
++			return -EINVAL;
++		}
++		if (pImbReq->req.dataLength > MAX_BUFFER_SIZE) {
++			return -EINVAL;
++		}
++
++		if (pImbReq->req.cmd == IPMI_SEND_MSG_CMD) {
++			struct ipmi_lan_addr  *lan_addr
++				= (struct ipmi_lan_addr *) &addr;
++
++			lan_addr->addr_type = IPMI_LAN_ADDR_TYPE;
++			lan_addr->channel = pImbReq->req.data[0];
++			lan_addr->session_handle = pImbReq->req.data[1];
++			lan_addr->remote_SWID = pImbReq->req.data[2];
++			lan_addr->local_SWID = pImbReq->req.data[5];
++			lan_addr->lun = pImbReq->req.data[3] & 0x3;
++			msgid = pImbReq->req.data[6] >> 2;
++			source_lun = pImbReq->req.data[6] & 0x3;
++
++			msg.netfn = pImbReq->req.data[3] >> 2;
++			msg.cmd = pImbReq->req.data[7];
++			msg.data = &pImbReq->req.data[8];
++			msg.data_len = pImbReq->req.dataLength-9;
++		} else if (pImbReq->req.rsSa == BMC_SA) {
++			struct ipmi_system_interface_addr *smi_addr
++				= (struct ipmi_system_interface_addr *) &addr;
++
++			if ((pImbReq->req.netFn
++			     == (IPMI_NETFN_APP_REQUEST << 2))
++			    && (pImbReq->req.cmd
++				== IPMI_READ_EVENT_MSG_BUFFER_CMD))
++			{
++				/* The driver gets event messages
++                                   automatically, so we emulate
++                                   this. */
++				rv = imb_handle_event_request(priv, &rsp);
++				goto copy_resp;
++			} else {
++				smi_addr->addr_type
++				    = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
++				smi_addr->channel = IPMI_BMC_CHANNEL;
++				smi_addr->lun = 0;
++			}
++			msg.netfn = pImbReq->req.netFn;
++			msg.cmd = pImbReq->req.cmd;
++			msg.data = pImbReq->req.data;
++			msg.data_len = pImbReq->req.dataLength;
++		} else {
++			struct ipmi_ipmb_addr *ipmb_addr =
++				(struct ipmi_ipmb_addr *) &addr;
++
++			ipmb_addr->addr_type = IPMI_IPMB_ADDR_TYPE;
++			ipmb_addr->slave_addr = pImbReq->req.rsSa;
++			ipmb_addr->lun = pImbReq->req.rsLun;
++			ipmb_addr->channel = 0;
++			msg.netfn = pImbReq->req.netFn;
++			msg.cmd = pImbReq->req.cmd;
++			msg.data = pImbReq->req.data;
++			msg.data_len = pImbReq->req.dataLength;
++		}
++
++		if (pImbReq->flags & NO_RESPONSE_EXPECTED) {
++			msgid = 0;
++		} else {
++			if( msgid == 0 ) {
++				spin_lock(&priv->imb_lock);
++				msgid = priv->curr_msgid;
++				(priv->curr_msgid)++;
++				if (priv->curr_msgid == 0)
++					(priv->curr_msgid)++;
++				spin_unlock(&priv->imb_lock);
++			}
++			waiter.msgid = msgid;
++			init_waitqueue_head(&waiter.waitq);
++			waiter.msg = NULL;
++			spin_lock_irqsave(&priv->imb_lock, flags);
++			list_add_tail(&waiter.link, &priv->imb_waiting_rsps);
++			spin_unlock_irqrestore(&priv->imb_lock, flags);
++		}
++
++		if (pImbReq->req.cmd == IPMI_SEND_MSG_CMD) {
++			rv = ipmi_request_with_source(priv->imb_user,
++						  &addr,
++						  msgid,
++						  &msg,
++						  NULL,
++						  0,
++						source_address,
++						source_lun);
++		} else {
++			rv = ipmi_request_settime(priv->imb_user,
++						  &addr,
++						  msgid,
++						  &msg,
++						  NULL,
++						  0,
++						  1,
++						  pImbReq->timeOut);
++		}
++		if (rv) {
++			rv = IMB_SEND_REQUEST_FAILED;
++			if (!(pImbReq->flags & NO_RESPONSE_EXPECTED)) {
++				spin_lock_irqsave(&(priv->imb_lock), flags);
++				list_del(&waiter.link);
++				spin_unlock_irqrestore(&priv->imb_lock, flags);
++			}
++			goto no_response;
++		}
++
++		if (pImbReq->flags & NO_RESPONSE_EXPECTED)
++			goto no_response;
++
++		/* Now wait for the response to come back. */
++		spin_lock_irqsave(&(priv->imb_lock), flags);
++		if (!waiter.msg) {
++			/* No message yet, wait for it. */
++			init_waitqueue_entry(&wait, current);
++			add_wait_queue(&waiter.waitq, &wait);
++			set_current_state(TASK_INTERRUPTIBLE);
++			if (!signal_pending(current)) {
++				spin_unlock_irqrestore
++					(&(priv->imb_lock), flags);
++				schedule();
++				spin_lock_irqsave
++					(&(priv->imb_lock), flags);
++			} else {
++				rv = -ERESTARTSYS;
++			}
++			remove_wait_queue(&waiter.waitq, &wait);
++
++			/* At this point, we are either woken by a
++			 * signal or we have a message. */
++			if (!waiter.msg) {
++				/* No message, we need to remove
++				   ourself from the queue. */
++				list_del(&waiter.link);
++			}
++		}
++		spin_unlock_irqrestore(&(priv->imb_lock), flags);
++
++		rsp = waiter.msg;
++	copy_resp:
++		if (rsp != NULL) {
++			pImbResp->cCode = rsp->msg.data[0];
++			if( rsp->msg.data_len > 1 )
++				memcpy(pImbResp->data,
++				       rsp->msg.data+1,
++				       rsp->msg.data_len-1);
++			length = (rsp->msg.data_len - 1
++				  + MIN_IMB_RESP_BUF_SIZE);
++
++			ipmi_free_recv_msg(rsp);
++
++			if (copy_to_user(smi.lpvOutBuffer, pImbResp, length)) {
++				return -EFAULT;
++			}
++
++			if (copy_to_user(smi.lpcbBytesReturned,
++					 &length,
++					 sizeof(length)))
++			{
++				return -EFAULT;
++			}
++		}
++	no_response:
++		break;
++	}
++
++	case IOCTL_IMB_SHUTDOWN_CODE:
++	{
++		ShutdownCmdBuffer shutdownCmd;
++
++		if (copy_from_user(&shutdownCmd,
++				   smi.lpvInBuffer,
++				   sizeof(ShutdownCmdBuffer)))
++		{
++			return -EFAULT;
++		}
++
++		if (smi.cbInBuffer < sizeof(ShutdownCmdBuffer))
++		{
++			return -EINVAL;
++		}
++
++		rv = 0;
++		switch (shutdownCmd.code) {
++		case SD_POWER_OFF:
++			ipmi_delayed_shutdown(shutdownCmd.delayTime / 10, 1);
++			break;
++
++		case SD_RESET:
++			ipmi_delayed_shutdown(shutdownCmd.delayTime / 10, 0);
++			break;
++
++		case SD_NO_ACTION:
++			break;
++
++		default:
++			rv = INVALID_ARGUMENTS;
++		}
++		break;
++        }
++
++	case IOCTL_IMB_REGISTER_ASYNC_OBJ:
++	{
++		unsigned char     imbRespBuffer[MAX_IMB_RESPONSE_SIZE + 8];
++		unsigned long     length;
++		ImbResponseBuffer *pImbResp=(ImbResponseBuffer*)imbRespBuffer;
++		unsigned long dummy;
++
++		pImbResp->cCode = 00;
++		length = sizeof(int);
++//		++AsyncHandle;
++//		memcpy(pImbResp->data,&AsyncHandle,length);
++		//
++		//Now copy back the  a bogus imb response and length to
++		//user space since the imbapi expects it. We can use this
++		//later to return a more meaningful value if necesssary.
++		//
++		dummy = 0xbabe;
++		memcpy(pImbResp->data,&dummy,length);
++		if (copy_to_user(smi.lpvOutBuffer, pImbResp, length))
++			return -EFAULT;
++
++		if (copy_to_user(smi.lpcbBytesReturned, &length,
++				 sizeof(length)))
++			return -EFAULT;
++
++		rv = STATUS_SUCCESS;
++		break;
++	}
++
++	case IOCTL_IMB_DEREGISTER_ASYNC_OBJ:
++		rv = STATUS_SUCCESS;
++		break;
++
++	case IOCTL_IMB_CHECK_EVENT:
++	{
++		wait_queue_t wait;
++
++		rv = STATUS_SUCCESS;
++		spin_lock_irqsave(&(priv->imb_lock), flags);
++		init_waitqueue_entry(&wait, current);
++		add_wait_queue(&(priv->imb_waiting_cmd_rcvrs),
++			       &wait);
++		while (list_empty(&(priv->imb_waiting_cmds))) {
++			set_current_state(TASK_INTERRUPTIBLE);
++			if (!signal_pending(current)) {
++				spin_unlock_irqrestore
++					(&(priv->imb_lock), flags);
++				schedule();
++				spin_lock_irqsave
++					(&(priv->imb_lock), flags);
++			} else {
++				rv = -ERESTARTSYS;
++				break;
++			}
++		}
++		remove_wait_queue(&(priv->imb_waiting_cmd_rcvrs),
++				  &wait);
++		spin_unlock_irqrestore(&(priv->imb_lock), flags);
++		break;
++	}
++	default:
++		printk(KERN_ERR "ipmi_imb_ioctl: ioctl cmd  0x%x not supported\n", cmd);
++		return(-EINVAL);
++	}
++
++	return rv;
++}
++
++static int ipmi_imb_mmap(struct file *file, struct vm_area_struct *vma)
++{
++    off_t offset = vma->vm_pgoff << PAGE_SHIFT;
++
++    if (offset < 0)
++	    return -EINVAL;
++
++    if (remap_page_range( vma->vm_start, offset,
++			 vma->vm_end - vma->vm_start,
++			 vma->vm_page_prot))
++    {
++	    return -EAGAIN;
++    }
++
++    /*vma->vm_inode = what_goes_here; */
++
++    return 0;
++
++}
++
++
++static struct file_operations ipmi_fops = {
++	owner:   THIS_MODULE,
++	ioctl:   ipmi_imb_ioctl,
++	open:    ipmi_imb_open,
++	release: ipmi_imb_release,
++	mmap:    ipmi_imb_mmap
++};
++
++static struct timer_list ipmi_imb_timer;
++
++/* Call every 100 ms. */
++#define IPMI_TIMEOUT_TIME	100
++#define IPMI_TIMEOUT_JIFFIES	((IPMI_TIMEOUT_TIME * HZ) / 1000)
++
++static volatile int stop_operation = 0;
++static volatile int timer_stopped = 0;
++
++static void ipmi_imb_timeout(unsigned long data)
++{
++	struct list_head     *entry, *entry2;
++	struct priv_data     *priv = (struct priv_data *) data;
++	int                  timeout_period = IPMI_TIMEOUT_TIME;
++	struct ipmi_recv_msg *msg;
++
++	if (stop_operation) {
++		timer_stopped = 1;
++		return;
++	}
++
++	/* Now time out any messages in the Imb message queue. */
++	spin_lock(&(priv->imb_lock));
++	list_for_each_safe(entry, entry2, &(priv->imb_waiting_cmds)) {
++		long *timeout;
++		msg = list_entry(entry, struct ipmi_recv_msg, link);
++		timeout = imb_timeout(msg);
++		*timeout -= timeout_period;
++		if ((*timeout) <= 0) {
++			list_del(entry);
++			priv->FirstCmdSeqenceNo +=1;
++			ipmi_free_recv_msg(msg);
++		}
++	}
++	spin_unlock(&priv->imb_lock);
++	// remove the comment in the following line to reenable timeouts
++	//wake_up_all(&(priv->imb_waiting_cmd_rcvrs));
++
++	ipmi_imb_timer.expires += IPMI_TIMEOUT_JIFFIES;
++	add_timer(&ipmi_imb_timer);
++}
++
++#define DEVICE_NAME     "imb"
++
++static int ipmi_imb_major = 0;
++MODULE_PARM(ipmi_imb_major, "i");
++
++static struct ipmi_user_hndl ipmi_hndlrs =
++{
++	ipmi_recv_hndl : imb_msg_recv
++};
++
++static int init_ipmi_imb(void)
++{
++	int rv;
++
++	if (ipmi_imb_major < 0) {
++		printk(KERN_ERR "ipmi: bad major %d\n",
++		       ipmi_imb_major);
++		return -EINVAL;
++	}
++
++	ipmi_user = kmalloc(sizeof(*ipmi_user), GFP_KERNEL);
++	if (!ipmi_user) {
++		printk(KERN_ERR "ipmi: No Memory for major %d\n",
++		       ipmi_imb_major);
++		return -ENOMEM;
++	}
++
++	/* Create the Imb interface user. */
++	spin_lock_init(&(ipmi_user->imb_lock));
++	INIT_LIST_HEAD(&(ipmi_user->imb_waiting_rsps));
++	ipmi_user->FirstCmdSeqenceNo = ASYNC_SEQ_START;
++	ipmi_user->LastCmdSeqenceNo = ASYNC_SEQ_START;
++	INIT_LIST_HEAD(&(ipmi_user->imb_waiting_cmds));
++	init_waitqueue_head(&(ipmi_user->imb_waiting_cmd_rcvrs));
++	ipmi_user->imb_cmd_waiting = 0;
++	INIT_LIST_HEAD(&(ipmi_user->imb_waiting_events));
++
++	/* Zero is reserved. */
++	ipmi_user->curr_msgid = 1;
++
++	rv = ipmi_create_user(0,
++			      &ipmi_hndlrs,
++			      ipmi_user,
++			      &(ipmi_user->imb_user));
++	if (rv) {
++		kfree(ipmi_user);
++		ipmi_user = NULL;
++		printk(KERN_ERR "ipmi: can't create user %d\n",
++		       rv);
++		return rv;
++	}
++
++	rv = register_chrdev(ipmi_imb_major, DEVICE_NAME, &ipmi_fops);
++	if (rv < 0)
++	{
++		kfree(ipmi_user);
++		ipmi_user = NULL;
++		printk(KERN_ERR "ipmi: can't get major %d\n",
++		       ipmi_imb_major);
++		return rv;
++	}
++
++	if (ipmi_imb_major == 0)
++	{
++		ipmi_imb_major = rv;
++	}
++
++	devfs_handle = devfs_register(NULL, DEVICE_NAME, DEVFS_FL_NONE,
++				      ipmi_imb_major, 0,
++				      S_IFCHR | S_IRUSR | S_IWUSR,
++				      &ipmi_fops, NULL);
++
++	init_timer(&ipmi_imb_timer);
++	ipmi_imb_timer.data = (long) ipmi_user;
++	ipmi_imb_timer.function = ipmi_imb_timeout;
++	ipmi_imb_timer.expires = jiffies + IPMI_TIMEOUT_JIFFIES;
++	add_timer(&ipmi_imb_timer);
++
++	printk(KERN_INFO "ipmi_imb: driver initialized at char major %d\n",
++	       ipmi_imb_major);
++
++	return 0;
++}
++
++#ifdef MODULE
++static void free_recv_msg_list(struct list_head *q)
++{
++	struct list_head     *entry, *entry2;
++	struct ipmi_recv_msg *msg;
++
++	list_for_each_safe(entry, entry2, q) {
++		msg = list_entry(entry, struct ipmi_recv_msg, link);
++		list_del(entry);
++		ipmi_free_recv_msg(msg);
++	}
++}
++
++static void cleanup_ipmi_imb(void)
++{
++	devfs_unregister(devfs_handle);
++
++	/* Tell the timer to stop, then wait for it to stop.  This avoids
++	   problems with race conditions removing the timer here. */
++	stop_operation = 1;
++	while (!timer_stopped) {
++		schedule_timeout(1);
++	}
++
++	ipmi_destroy_user(ipmi_user->imb_user);
++
++	free_recv_msg_list(&(ipmi_user->imb_waiting_cmds));
++	free_recv_msg_list(&(ipmi_user->imb_waiting_events));
++
++	kfree(ipmi_user);
++	ipmi_user = NULL;
++
++	unregister_chrdev(ipmi_imb_major, DEVICE_NAME);
++}
++module_exit(cleanup_ipmi_imb);
++#else
++static int __init ipmi_imb_setup (char *str)
++{
++	int x;
++
++	if (get_option (&str, &x)) {
++		/* ipmi=x sets the major number to x. */
++		ipmi_imb_major = x;
++	} else if (!strcmp(str, "off")) {
++		ipmi_imb_major = -1;
++	}
++
++	return 1;
++}
++__setup("ipmi_imb=", ipmi_imb_setup);
++#endif
++
++module_init(init_ipmi_imb);
++MODULE_LICENSE("GPL");
+Index: linux-ipmi/drivers/char/ipmi/ipmi_radisys.c
+===================================================================
+--- linux-ipmi.orig/drivers/char/ipmi/ipmi_radisys.c	1969-12-31 18:00:00.000000000 -0600
++++ linux-ipmi/drivers/char/ipmi/ipmi_radisys.c	2004-08-10 19:03:53.000000000 -0500
+@@ -0,0 +1,849 @@
++/*
++ * ipmi_radisys.c
++ *
++ * Radisys emulation for the IPMI interface.
++ *
++ * Author: MontaVista Software, Inc.
++ *         Corey Minyard <minyard@mvista.com>
++ *         source@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.
++ *
++ *
++ *  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 <linux/module.h>
++#include <linux/moduleparam.h>
++#include <linux/errno.h>
++#include <asm/system.h>
++#include <linux/sched.h>
++#include <linux/poll.h>
++#include <linux/spinlock.h>
++#include <linux/slab.h>
++#include <linux/devfs_fs_kernel.h>
++#include <linux/ipmi.h>
++#include <linux/ipmi_radisys.h>
++
++#define IPMI_RADISYS_VERSION   "v33"
++
++struct priv_data
++{
++	/* This is for supporting the old Radisys interface. */
++	ipmi_user_t       rs_user;
++	spinlock_t        rs_lock;
++
++	/* A list of responses in the queue. */
++	struct list_head  rs_waiting_rsps;
++
++	/* A list of things waiting for responses.  We wake them all up
++	   when a response comes in. */
++	wait_queue_head_t rs_waiting_rsp_rcvrs;
++
++	/* A list of commands that have come in. */
++	struct list_head  rs_waiting_cmds;
++
++	/* A list of thing waiting for commands.  We wake them all up
++	   when a command comes in. */
++	wait_queue_head_t rs_waiting_cmd_rcvrs;
++
++	/* The registered command receiver value.  This only allows someone
++	   with the "magic number" to issue commands. */
++	unsigned long     rs_cmd_receiver;
++
++	/* Is someone already waiting for a command?  The Radisys driver
++	   only allows one waiter, this enforces that. */
++	int               rs_cmd_waiting;
++
++	/* A list of IPMI events waiting to be delivered.  (not that
++           the Radisys driver calls incoming commands "events", this
++           variable is actual IPMI events, not incoming commands). */
++	struct list_head  rs_waiting_events;
++
++#define RS_EVENT_QUEUE_LIMIT	16 /* Allow up to 16 events. */
++	/* The number of events in the event queue. */
++	unsigned int      rs_waiting_event_count;
++};
++
++
++static devfs_handle_t devfs_handle;
++
++/* We cheat and use a piece of the address as the timeout. */
++static long *rs_timeout(struct ipmi_recv_msg *msg)
++{
++	char *base = (char *) &(msg->addr);
++	base += sizeof(struct ipmi_ipmb_addr);
++	return (long *) base;
++}
++
++static void rs_msg_recv(struct ipmi_recv_msg *msg,
++			void                 *data)
++{
++	struct priv_data *priv = data;
++	unsigned long    flags;
++
++	spin_lock_irqsave(&(priv->rs_lock), flags);
++	if (msg->recv_type == IPMI_RESPONSE_RECV_TYPE) {
++		*rs_timeout(msg) = 5000;
++		list_add_tail(&(msg->link), &(priv->rs_waiting_rsps));
++		wake_up_all(&(priv->rs_waiting_rsp_rcvrs));
++	} else if (msg->recv_type == IPMI_CMD_RECV_TYPE) {
++		*rs_timeout(msg) = 5000;
++		list_add_tail(&(msg->link), &(priv->rs_waiting_cmds));
++		wake_up_all(&(priv->rs_waiting_cmd_rcvrs));
++	} else if (msg->recv_type == IPMI_ASYNC_EVENT_RECV_TYPE) {
++		if (priv->rs_waiting_event_count > RS_EVENT_QUEUE_LIMIT) {
++			ipmi_free_recv_msg(msg);
++		} else {
++			list_add_tail(&(msg->link),&(priv->rs_waiting_events));
++			(priv->rs_waiting_event_count)++;
++		}
++	} else {
++		ipmi_free_recv_msg(msg);
++	}
++	spin_unlock_irqrestore(&(priv->rs_lock), flags);
++}
++
++/* We emulate the event queue in the driver for the Radisys emulation. */
++static int rs_handle_event_request(struct priv_data *priv)
++{
++	struct list_head     *entry;
++	unsigned long        flags;
++	struct ipmi_recv_msg *msg = NULL;
++	int                  rv = 0;
++
++	spin_lock_irqsave(&(priv->rs_lock), flags);
++	if (list_empty(&(priv->rs_waiting_events))) {
++		/* Nothing in the event queue, just return an error. */
++		msg = ipmi_alloc_recv_msg();
++		if (msg == NULL) {
++			rv = -EAGAIN;
++			goto out_err;
++		}
++		msg->addr.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
++		msg->addr.channel = IPMI_BMC_CHANNEL;
++		msg->msg.cmd = IPMI_READ_EVENT_MSG_BUFFER_CMD;
++		msg->msgid = 0;
++		msg->recv_type = IPMI_ASYNC_EVENT_RECV_TYPE;
++		msg->msg.netfn = IPMI_NETFN_APP_RESPONSE;
++		msg->msg.data = msg->msg_data;
++		msg->msg.data[0] = 0x80; /* Data not available. */
++		msg->msg.data_len = 1;
++	} else {
++		/* Pull an item from the event queue . */
++		entry = priv->rs_waiting_events.next;
++		list_del(entry);
++		msg = list_entry(entry, struct ipmi_recv_msg, link);
++		(priv->rs_waiting_event_count)--;
++	}
++
++	/* Put the response into the list of waiting responses and
++           wake all the response waiters up. */
++	*rs_timeout(msg) = 5000;
++	list_add_tail(&(msg->link), &(priv->rs_waiting_rsps));
++	wake_up_all(&(priv->rs_waiting_rsp_rcvrs));
++
++ out_err:
++	spin_unlock_irqrestore(&(priv->rs_lock), flags);
++	return rv;
++}
++
++static struct ipmi_recv_msg *rs_find_in_list(struct list_head *q,
++					     unsigned char    slave_addr,
++					     unsigned char    lun,
++					     unsigned char    netfn,
++					     unsigned char    cmd,
++					     unsigned char    seq)
++{
++	struct list_head      *entry;
++	struct ipmi_recv_msg  *msg;
++	struct ipmi_addr      addr;
++	unsigned char         msg_seq;
++
++	if (slave_addr == 1) {
++		struct ipmi_system_interface_addr *smi_addr;
++		smi_addr = (struct ipmi_system_interface_addr *) &addr;
++		smi_addr->addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
++		smi_addr->lun = lun;
++		/* Slave address 1 means no matching sequence in the
++                   Radisys driver. */
++	} else {
++		struct ipmi_ipmb_addr *ipmb_addr;
++		ipmb_addr = (struct ipmi_ipmb_addr *) &addr;
++		ipmb_addr->addr_type = IPMI_IPMB_ADDR_TYPE;
++		ipmb_addr->slave_addr = slave_addr;
++		ipmb_addr->lun = lun;
++	}
++
++	list_for_each(entry, q) {
++		msg = list_entry(entry, struct ipmi_recv_msg, link);
++		if (msg->addr.channel == IPMI_BMC_CHANNEL)
++			msg_seq = 0;
++		else
++			msg_seq = msg->msgid;
++
++		/* We ignore the channel for these comparisons, since the
++		   Radisys driver seems to ignore it. */
++		addr.channel = msg->addr.channel;
++
++		if ((msg_seq == seq)
++		    && (msg->msg.cmd == cmd)
++		    && (msg->msg.netfn == (netfn >> 2))
++		    && ipmi_addr_equal(&addr, &(msg->addr)))
++		{
++			list_del(entry);
++			return msg;
++		}
++	}
++
++	return NULL;
++}
++
++static struct priv_data *ipmi_user;
++static unsigned int user_count = 0; /* How many users have this open. */
++static spinlock_t dev_lock = SPIN_LOCK_UNLOCKED;
++
++static int ipmi_open(struct inode *inode, struct file *file)
++{
++	file->private_data = ipmi_user;
++	spin_lock(&dev_lock);
++	if (user_count == 0)
++		ipmi_set_gets_events(ipmi_user->rs_user, 1);
++	user_count++;
++	spin_unlock(&dev_lock);
++
++	return 0;
++}
++
++static int ipmi_release(struct inode *inode, struct file *file)
++{
++	spin_lock(&dev_lock);
++	user_count--;
++	if (user_count == 0)
++		ipmi_set_gets_events(ipmi_user->rs_user, 0);
++	spin_unlock(&dev_lock);
++	return 0;
++}
++
++static unsigned char
++ipmb_checksum(unsigned char *data, int size)
++{
++	unsigned char csum = 0;
++	
++	for (; size > 0; size--, data++)
++		csum += *data;
++
++	return -csum;
++}
++
++static int ipmi_ioctl(struct inode  *inode,
++		      struct file   *file,
++		      unsigned int  cmd,
++		      unsigned long data)
++{
++	struct priv_data *priv = file->private_data;
++	int              rv = -EINVAL;
++
++	switch(cmd) {
++	case IOCTL_IPMI_RCV:   /* get ipmi message */
++	{
++		IPMI_MSGDESC         rsp;
++		struct ipmi_recv_msg *msg;
++		unsigned long        flags;
++		long                 timeout;
++		wait_queue_t         wait;
++
++		if (copy_from_user(&rsp, (void *) data, sizeof(rsp))) {
++			rv = -EFAULT;
++			break;
++		}
++
++		rv = 0;
++
++		spin_lock_irqsave(&(priv->rs_lock), flags);
++
++		msg = rs_find_in_list(&(priv->rs_waiting_rsps),
++				      rsp.Dest.uchSlave,
++				      rsp.Dest.uchLun,
++				      rsp.uchNetFn,
++				      rsp.uchCmd,
++				      rsp.uchSeq);
++		init_waitqueue_entry(&wait, current);
++		add_wait_queue(&(priv->rs_waiting_rsp_rcvrs),
++			       &wait);
++		timeout = (5000 * HZ) / 1000;
++		while (msg == NULL) {
++			set_current_state(TASK_INTERRUPTIBLE);
++			if (!signal_pending(current)) {
++				spin_unlock_irqrestore
++					(&(priv->rs_lock), flags);
++				timeout = schedule_timeout(timeout);
++				spin_lock_irqsave
++					(&(priv->rs_lock), flags);
++			} else {
++				rv = -ERESTARTSYS;
++				break;
++			}
++			if (timeout <= 0) {
++				rsp.uchComplete = IPMI_TIMEOUT_COMPLETION_CODE;
++				break;
++			} else {
++				msg = rs_find_in_list
++					(&(priv->rs_waiting_rsps),
++					 rsp.Dest.uchSlave,
++					 rsp.Dest.uchLun,
++					 rsp.uchNetFn,
++					 rsp.uchCmd,
++					 rsp.uchSeq);
++			}
++		}
++		remove_wait_queue(&(priv->rs_waiting_rsp_rcvrs),
++				  &wait);
++		spin_unlock_irqrestore(&(priv->rs_lock), flags);
++
++		if (msg != NULL) {
++			rsp.uchComplete = msg->msg.data[0];
++			/* The Radisys driver expects all the data to
++			   be there in the data, even the stuff we
++			   already have processed for it.  So make is
++			   so. */
++			if (msg->addr.channel == IPMI_BMC_CHANNEL) {
++				struct ipmi_system_interface_addr *smi_addr;
++
++				smi_addr = ((struct ipmi_system_interface_addr *)
++					    &(msg->addr));
++				memcpy(&(rsp.auchBuffer[2]),
++				       &(msg->msg.data[0]),
++				       msg->msg.data_len);
++				rsp.ulLength = msg->msg.data_len+2;
++				rsp.auchBuffer[0] = ((msg->msg.netfn << 2)
++						     | (smi_addr->lun));
++				rsp.auchBuffer[1] = msg->msg.cmd;
++			} else {
++				struct ipmi_ipmb_addr *ipmb_addr;
++
++				ipmb_addr = (struct ipmi_ipmb_addr *) &msg->addr;
++				memcpy(&(rsp.auchBuffer[9]),
++				       &(msg->msg.data[0]),
++				       msg->msg.data_len);
++				rsp.ulLength = msg->msg.data_len+10;
++				rsp.auchBuffer[0] = IPMI_NETFN_APP_REQUEST << 2;
++				rsp.auchBuffer[1] = IPMI_GET_MSG_CMD;
++				rsp.auchBuffer[2] = 0;
++				rsp.auchBuffer[3] = msg->addr.channel;
++				rsp.auchBuffer[4] = ((msg->msg.netfn << 2)
++						     | 2);
++				rsp.auchBuffer[5]
++					= ipmb_checksum(&(rsp.auchBuffer[3]),
++							2);
++				rsp.auchBuffer[6] = ipmb_addr->slave_addr;
++				rsp.auchBuffer[7] = ((msg->msgid << 2)
++						     | ipmb_addr->lun);
++				rsp.auchBuffer[8] = msg->msg.cmd;
++				rsp.auchBuffer[msg->msg.data_len+9]
++					= ipmb_checksum(&(rsp.auchBuffer[6]),
++							msg->msg.data_len+3);
++			}
++			ipmi_free_recv_msg(msg);
++		}
++
++		if (copy_to_user((void *) data, &rsp, sizeof(rsp))) {
++			rv = -EFAULT;
++			break;
++		}
++
++		break;
++	}
++     
++	case IOCTL_IPMI_SEND: /* send ipmi message */
++	{
++		IPMI_MSGDESC     req;
++		struct ipmi_addr addr;
++		struct ipmi_msg  msg;
++		unsigned char    source_address;
++		unsigned char    source_lun;
++		unsigned int     start_offset;
++		unsigned char    seq;
++
++		if (copy_from_user(&req, (void *) data, sizeof(req))) {
++			rv = -EFAULT;
++			break;
++		}
++
++		if (((req.auchBuffer[0] >> 2) != IPMI_NETFN_APP_REQUEST)
++		    || (req.auchBuffer[1] != IPMI_SEND_MSG_CMD))
++		{
++			/* It's not a send message, so it's a message
++			   directly to the BMC. */
++			struct ipmi_system_interface_addr *smi_addr
++				= (struct ipmi_system_interface_addr *) &addr;
++			if (((req.auchBuffer[0] >> 2)
++			     == (IPMI_NETFN_APP_REQUEST << 2))
++			    && (req.auchBuffer[1]
++				== IPMI_READ_EVENT_MSG_BUFFER_CMD))
++			{
++				/* The driver gets event messages
++                                   automatically, so we emulate
++                                   this. */
++				rv = rs_handle_event_request(priv);
++				break;
++			}
++
++			smi_addr->addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
++			smi_addr->channel = IPMI_BMC_CHANNEL;
++			smi_addr->lun = req.auchBuffer[0] & 0x3;
++			msg.netfn = req.auchBuffer[0] >> 2;
++			msg.cmd = req.auchBuffer[1];
++			seq = req.uchSeq;
++			source_address = 0;
++			source_lun = 0;
++			start_offset = 2;
++		} else {
++			struct ipmi_ipmb_addr *ipmb_addr =
++				(struct ipmi_ipmb_addr *) &addr;
++			
++			ipmb_addr->addr_type = IPMI_IPMB_ADDR_TYPE;
++			ipmb_addr->channel = req.auchBuffer[2] & 0xf;
++			ipmb_addr->slave_addr = req.auchBuffer[3];
++			ipmb_addr->lun = req.auchBuffer[4] & 0x3;
++			msg.netfn = req.auchBuffer[0] >> 2;
++			msg.cmd = req.auchBuffer[8];
++			seq = req.auchBuffer[7] >> 2;
++			source_address = req.auchBuffer[6];
++			source_lun = req.auchBuffer[7] & 0x3;
++			start_offset = 9;
++			req.ulLength--; /* Remove the checksum the userland
++					   process adds. */
++		}
++
++		msg.data = req.auchBuffer + start_offset;
++		msg.data_len = req.ulLength - start_offset;
++
++		rv = ipmi_request_with_source(priv->rs_user,
++					      &addr,
++					      seq,
++					      &msg,
++					      NULL,
++					      0,
++					      source_address,
++					      source_lun);
++		if (rv)
++			req.uchComplete = IPMI_UNKNOWN_ERR_COMPLETION_CODE;
++		else
++			req.uchComplete = 0;
++		/* The Radisys driver does no error checking here. */
++		copy_to_user((void *) data, &req, sizeof(req));
++		rv = 0;
++		break;
++	}
++
++	case IOCTL_IPMI_EVENT:  /* get an incoming command.  Don't be
++                                   fooled by the name, these are
++                                   commands, not IPMI events. */
++	{
++		IPMI_MSGDESC         rsp;
++		struct ipmi_recv_msg *msg = NULL;
++		struct list_head     *entry;
++		unsigned long        flags;
++		long                 timeout;
++		unsigned long        receiver;
++		wait_queue_t         wait;
++
++		if (copy_from_user(&receiver, (void *) data, sizeof(receiver)))
++		{
++			rv = -EFAULT;
++			break;
++		}
++
++		if (copy_from_user(&timeout,
++				   (void *) (data + sizeof(receiver)),
++				   sizeof(timeout)))
++		{
++			rv = -EFAULT;
++			break;
++		}
++
++		rv = 0;
++
++		spin_lock_irqsave(&(priv->rs_lock), flags);
++
++		/* If someone else is already waiting, the Radisys driver
++		   returns EFAULT, so we do to. */
++		if (priv->rs_cmd_waiting) {
++			spin_unlock_irqrestore(&(priv->rs_lock), flags);
++			rv = -EFAULT;
++			break;
++		}
++
++		/* If the user thread doesn't match up, abort. */
++		if (receiver != priv->rs_cmd_receiver) {
++			spin_unlock_irqrestore(&(priv->rs_lock), flags);
++			rsp.uchComplete = IPMI_INVALID_CMD_COMPLETION_CODE;
++			break;
++		}
++
++		init_waitqueue_entry(&wait, current);
++		add_wait_queue(&(priv->rs_waiting_cmd_rcvrs),
++			       &wait);
++		priv->rs_cmd_waiting = 1;
++		timeout = (timeout * HZ) / 1000; /* from ms to jiffies */
++		while ((timeout > 0) &&
++		       list_empty(&(priv->rs_waiting_cmds)))
++		{
++			set_current_state(TASK_INTERRUPTIBLE);
++			if (!signal_pending(current)) {
++				spin_unlock_irqrestore
++					(&(priv->rs_lock), flags);
++				timeout = schedule_timeout(timeout);
++				spin_lock_irqsave
++					(&(priv->rs_lock), flags);
++			} else {
++				rv = -ERESTARTSYS;
++				break;
++			}
++		}
++		if (!list_empty(&(priv->rs_waiting_cmds))) {
++			entry = priv->rs_waiting_cmds.next;
++			list_del(entry);
++			msg = list_entry(entry, struct ipmi_recv_msg, link);
++		}
++		priv->rs_cmd_waiting = 0;
++		remove_wait_queue(&(priv->rs_waiting_cmd_rcvrs),
++				  &wait);
++		spin_unlock_irqrestore(&(priv->rs_lock), flags);
++
++		if (msg != NULL) {
++			/* The Radisys driver expects all the data to
++			   be there in the data, even the stuff we
++			   already have processed for it.  So make is
++			   so. */
++			struct ipmi_ipmb_addr *ipmb_addr;
++
++			ipmb_addr = (struct ipmi_ipmb_addr *) &msg->addr;
++			memcpy(&(rsp.auchBuffer[9]),
++			       &(msg->msg.data[0]),
++			       msg->msg.data_len);
++			rsp.ulLength = msg->msg.data_len+9;
++			rsp.auchBuffer[0] = IPMI_NETFN_APP_REQUEST << 2;
++			rsp.auchBuffer[1] = IPMI_SEND_MSG_CMD;
++			rsp.auchBuffer[2] = 0;
++			rsp.auchBuffer[3] = msg->addr.channel;
++			rsp.auchBuffer[4] = ((msg->msg.netfn << 2)
++					     | 2);
++			rsp.auchBuffer[5]
++				= ipmb_checksum(&(rsp.auchBuffer[3]),
++						2);
++			rsp.auchBuffer[6] = ipmb_addr->slave_addr;
++			rsp.auchBuffer[7] = ((msg->msgid << 2)
++					     | ipmb_addr->lun);
++			rsp.auchBuffer[8] = msg->msg.cmd;
++
++			rsp.uchNetFn = (msg->msg.netfn << 2);
++			rsp.uchCmd = msg->msg.cmd;
++			rsp.uchSeq = msg->msgid;
++			rsp.ulLength = msg->msg.data_len + 9;
++			ipmi_free_recv_msg(msg);
++		} else if (!rv) {
++			/* On a time out, the Radisys driver returns
++			   IPMIRC_ERROR in the completion code, for
++			   some wierd reason. */
++			rsp.uchComplete = IPMI_UNKNOWN_ERR_COMPLETION_CODE;
++		}
++
++		/* The Radisys driver does no error checking here. */
++		copy_to_user((void *) data, &rsp, sizeof(rsp));
++		rv = 0;
++		break;
++	}
++    
++	case IOCTL_IPMI_REGISTER: /* register as event receiver */
++	{
++		unsigned long receiver;
++		unsigned char rc = LOWLRC_SUCCESS;
++		unsigned long flags;
++
++		if (copy_from_user(&receiver, (void *) data, sizeof(receiver)))
++		{
++			rv = -EFAULT;
++			break;
++		}
++
++		spin_lock_irqsave(&(priv->rs_lock), flags);
++		if (priv->rs_cmd_receiver == 0) {
++			rv = ipmi_register_all_cmd_rcvr(priv->rs_user);
++			if (rv)	{
++				priv->rs_cmd_receiver = receiver;
++			} else {
++				rc = LOWLRC_ERROR;
++			}
++		} else if (priv->rs_cmd_receiver != receiver) {
++			rc = LOWLRC_ERROR;
++		}
++		spin_unlock_irqrestore(&(priv->rs_lock), flags);
++
++		/* The Radisys driver does no error checking here. */
++		copy_to_user((void *) data, &rc, sizeof(rc));
++		rv = 0;
++		break;
++	}
++    
++	case IOCTL_IPMI_UNREGISTER:   /* unregister as event receiver */
++	{
++		unsigned long receiver;
++		unsigned char rc = LOWLRC_SUCCESS;
++		unsigned long flags;
++
++		if (copy_from_user(&receiver, (void *) data, sizeof(receiver)))
++		{
++			rv = -EFAULT;
++			break;
++		}
++
++		spin_lock_irqsave(&(priv->rs_lock), flags);
++		if (priv->rs_cmd_receiver == receiver) {
++			ipmi_unregister_all_cmd_rcvr(priv->rs_user);
++			priv->rs_cmd_receiver = 0;
++		} else {
++			rc = LOWLRC_ERROR;
++		}
++		spin_unlock_irqrestore(&(priv->rs_lock), flags);
++
++		/* The Radisys driver does no error checking here. */
++		copy_to_user((void *) data, &rc, sizeof(rc));
++		rv = 0;
++		break;
++	}
++
++	case IOCTL_IPMI_CLEAR: /* clear registered event receiver */
++	{
++		unsigned char rc = LOWLRC_SUCCESS;
++		unsigned long flags;
++
++		spin_lock_irqsave(&(priv->rs_lock), flags);
++		ipmi_unregister_all_cmd_rcvr(priv->rs_user);
++		priv->rs_cmd_receiver = 0;
++		spin_unlock_irqrestore(&(priv->rs_lock), flags);
++
++		/* The Radisys driver does no error checking here. */
++		copy_to_user((void *) data, &rc, sizeof(rc));
++		rv = 0;
++		break;
++	}
++	}
++
++	return rv;
++}
++
++static struct file_operations ipmi_fops = {
++	owner:   THIS_MODULE,
++	ioctl:   ipmi_ioctl,
++	open:    ipmi_open,
++	release: ipmi_release
++};
++
++static struct timer_list ipmi_radisys_timer;
++
++/* Call every 100 ms. */
++#define IPMI_TIMEOUT_TIME	100
++#define IPMI_TIMEOUT_JIFFIES	((IPMI_TIMEOUT_TIME * HZ) / 1000)
++
++/* Request events from the queue every second.  Hopefully, in the
++   future, IPMI will add a way to know immediately if an event is
++   in the queue. */
++#define IPMI_REQUEST_EV_TIME	(1000 / (IPMI_TIMEOUT_TIME))
++
++static volatile int stop_operation = 0;
++static volatile int timer_stopped = 0;
++
++static void ipmi_radisys_timeout(unsigned long data)
++{
++	struct list_head     *entry, *entry2;
++	struct priv_data     *priv = (struct priv_data *) data;
++	int                  timeout_period = IPMI_TIMEOUT_TIME;
++	struct ipmi_recv_msg *msg;
++
++	if (stop_operation) {
++		timer_stopped = 1;
++		return;
++	}
++
++	/* Now time out any messages in the Radisys message queue. */
++	spin_lock(&(priv->rs_lock));
++	list_for_each_safe(entry, entry2, &(priv->rs_waiting_rsps)) {
++		long *timeout;
++		msg = list_entry(entry, struct ipmi_recv_msg, link);
++		timeout = rs_timeout(msg);
++		*timeout -= timeout_period;
++		if ((*timeout) <= 0) {
++			list_del(entry);
++			ipmi_free_recv_msg(msg);
++		}
++	}
++	list_for_each_safe(entry, entry2, &(priv->rs_waiting_cmds)) {
++		long *timeout;
++		msg = list_entry(entry, struct ipmi_recv_msg, link);
++		timeout = rs_timeout(msg);
++		*timeout -= timeout_period;
++		if ((*timeout) <= 0) {
++			list_del(entry);
++			ipmi_free_recv_msg(msg);
++		}
++	}
++	spin_unlock(&priv->rs_lock);
++
++	ipmi_radisys_timer.expires += IPMI_TIMEOUT_JIFFIES;
++	add_timer(&ipmi_radisys_timer);
++}
++
++#define DEVICE_NAME     "ipmi"
++
++static int ipmi_radisys_major = 0;
++module_param(ipmi_radisys_major, int, 0); 
++
++static struct ipmi_user_hndl ipmi_hndlrs =
++{
++	ipmi_recv_hndl : rs_msg_recv
++};
++
++
++static int init_ipmi_radisys(void)
++{
++	int rv;
++
++	if (ipmi_radisys_major < 0)
++		return -EINVAL;
++
++	ipmi_user = kmalloc(sizeof(*ipmi_user), GFP_KERNEL);
++	if (!ipmi_user) {
++		printk("ipmi_radisys: Unable to allocate memory\n");
++		return -ENOMEM;
++	}
++
++	/* Create the Radisys interface user. */
++	spin_lock_init(&(ipmi_user->rs_lock));
++	INIT_LIST_HEAD(&(ipmi_user->rs_waiting_rsps));
++	init_waitqueue_head(&(ipmi_user->rs_waiting_rsp_rcvrs));
++	INIT_LIST_HEAD(&(ipmi_user->rs_waiting_cmds));
++	init_waitqueue_head(&(ipmi_user->rs_waiting_cmd_rcvrs));
++	ipmi_user->rs_cmd_waiting = 0;
++	INIT_LIST_HEAD(&(ipmi_user->rs_waiting_events));
++
++	rv = ipmi_create_user(0,
++			      &ipmi_hndlrs,
++			      ipmi_user,
++			      &(ipmi_user->rs_user));
++	if (rv) {
++		printk("ipmi_radisys: Unable to create an IPMI user, probably"
++		       " no physical devices present.\n");
++		kfree(ipmi_user);
++		ipmi_user = NULL;
++		return rv;
++	}
++
++	rv = register_chrdev(ipmi_radisys_major, DEVICE_NAME, &ipmi_fops);
++	if (rv < 0) 
++	{
++		printk("ipmi_radisys: Unable to create the character device\n");
++		kfree(ipmi_user);
++		ipmi_user = NULL;
++		printk(KERN_ERR "ipmi: can't get major %d\n",
++		       ipmi_radisys_major);
++		return rv;
++	}
++
++	if (ipmi_radisys_major == 0) 
++	{
++		ipmi_radisys_major = rv;
++	}
++
++	devfs_handle = devfs_register(NULL, DEVICE_NAME, DEVFS_FL_NONE,
++				      ipmi_radisys_major, 0,
++				      S_IFCHR | S_IRUSR | S_IWUSR,
++				      &ipmi_fops, NULL);
++
++	init_timer(&ipmi_radisys_timer);
++	ipmi_radisys_timer.data = (long) ipmi_user;
++	ipmi_radisys_timer.function = ipmi_radisys_timeout;
++	ipmi_radisys_timer.expires = jiffies + IPMI_TIMEOUT_JIFFIES;
++	add_timer(&ipmi_radisys_timer);
++
++	printk(KERN_INFO "ipmi_radisys: driver initialized at char major %d\n",
++	       ipmi_radisys_major);
++
++	return 0;
++}
++
++#ifdef MODULE
++static void free_recv_msg_list(struct list_head *q)
++{
++	struct list_head     *entry, *entry2;
++	struct ipmi_recv_msg *msg;
++
++	list_for_each_safe(entry, entry2, q) {
++		msg = list_entry(entry, struct ipmi_recv_msg, link);
++		list_del(entry);
++		ipmi_free_recv_msg(msg);
++	}
++}
++
++static void cleanup_ipmi_radisys(void)
++{
++	devfs_unregister(devfs_handle);
++
++	/* Tell the timer to stop, then wait for it to stop.  This avoids
++	   problems with race conditions removing the timer here. */
++	stop_operation = 1;
++	while (!timer_stopped) {
++		schedule_timeout(1);
++	}
++
++	ipmi_destroy_user(ipmi_user->rs_user);
++
++	free_recv_msg_list(&(ipmi_user->rs_waiting_rsps));
++	free_recv_msg_list(&(ipmi_user->rs_waiting_cmds));
++	free_recv_msg_list(&(ipmi_user->rs_waiting_events));
++
++	kfree(ipmi_user);
++	ipmi_user = NULL;
++
++	unregister_chrdev(ipmi_radisys_major, DEVICE_NAME);
++}
++module_exit(cleanup_ipmi_radisys);
++#else
++static int __init ipmi_radisys_setup (char *str)
++{
++	int x;
++
++	if (get_option (&str, &x)) {
++		/* ipmi=x sets the major number to x. */
++		ipmi_radisys_major = x;
++	} else if (!strcmp(str, "off")) {
++		ipmi_radisys_major = -1;
++	}
++
++	return 1;
++}
++__setup("ipmi_radisys=", ipmi_radisys_setup);
++#endif
++
++module_init(init_ipmi_radisys);
++MODULE_LICENSE("GPL");
+Index: linux-ipmi/drivers/char/ipmi/Makefile
+===================================================================
+--- linux-ipmi.orig/drivers/char/ipmi/Makefile	2004-08-10 19:03:19.000000000 -0500
++++ linux-ipmi/drivers/char/ipmi/Makefile	2004-08-10 19:03:53.000000000 -0500
+@@ -17,6 +17,8 @@
+ obj-$(CONFIG_IPMI_SMB) += ipmi_smb_intf.o
+ obj-$(CONFIG_IPMI_WATCHDOG) += ipmi_watchdog.o
+ obj-$(CONFIG_IPMI_POWEROFF) += ipmi_poweroff.o
++obj-$(CONFIG_IPMI_EMULATE_RADISYS) += ipmi_radisys.o
++obj-$(CONFIG_IPMI_EMULATE_IMB) += ipmi_imb.o
+ 
+ include $(TOPDIR)/Rules.make
+ 
+Index: linux-ipmi/include/linux/ipmi_imb.h
+===================================================================
+--- linux-ipmi.orig/include/linux/ipmi_imb.h	1969-12-31 18:00:00.000000000 -0600
++++ linux-ipmi/include/linux/ipmi_imb.h	2004-08-10 19:03:53.000000000 -0500
+@@ -0,0 +1,146 @@
++/*
++ * ipmi_imb.h
++ *
++ * Intels IMB emulation on the MontaVista IPMI interface
++ *
++ * Author: MontaVista Software, Inc.
++ *         Corey Minyard <minyard@mvista.com>
++ *         source@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.
++ *
++ *
++ *  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.
++ */
++
++#ifndef __LINUX_IPMI_IMB_H
++#define __LINUX_IPMI_IMB_H
++
++typedef struct overlapped_s {
++    unsigned long Internal;
++    unsigned long InternalHigh;
++    unsigned long Offset;
++    unsigned long OffsetHigh;
++} overlapped_t;
++
++struct smi {
++    unsigned long smi_VersionNo;
++    unsigned long smi_Reserved1;
++    unsigned long smi_Reserved2;
++    void          *ntstatus;	      /* address of NT status block*/
++    void          *lpvInBuffer;       /* address of buffer for input data*/
++    unsigned long cbInBuffer;         /* size of input buffer*/
++    void          *lpvOutBuffer;      /* address of output buffer*/
++    unsigned long cbOutBuffer;        /* size of output buffer*/
++    unsigned long *lpcbBytesReturned; /* address of actual bytes of output*/
++    overlapped_t  *lpoOverlapped;     /* address of overlapped structure*/
++};
++
++
++#define MAX_IMB_PACKET_SIZE	33
++
++typedef struct {
++	unsigned char rsSa;
++	unsigned char cmd;
++	unsigned char netFn;
++	unsigned char rsLun;
++	unsigned char dataLength;
++	unsigned char data[1];
++} ImbRequest;
++
++typedef struct {
++	unsigned long flags;
++#define	      		NO_RESPONSE_EXPECTED	0x01
++
++	unsigned long timeOut;
++	ImbRequest    req;
++} ImbRequestBuffer;
++
++#define MIN_IMB_REQ_BUF_SIZE	13
++
++
++typedef struct {
++	unsigned char cCode;
++	unsigned char data[1];
++} ImbResponseBuffer;
++
++#define ASYNC_SEQ_START		0	// starting sequence number
++
++#define MIN_IMB_RESP_BUF_SIZE	1	// a buffer without any request data
++#define MAX_IMB_RESP_SIZE		(MIN_IMB_RESP_BUF_SIZE + MAX_IMB_RESPONSE_SIZE)
++
++#define MIN_IMB_RESPONSE_SIZE	7
++#define MAX_IMB_RESPONSE_SIZE	MAX_IMB_PACKET_SIZE
++
++typedef struct {
++	unsigned long timeOut;
++	unsigned long lastSeq;
++} ImbAsyncRequest;
++
++typedef struct {
++	unsigned long thisSeq;
++	unsigned char data[1];
++} ImbAsyncResponse;
++
++#define MIN_ASYNC_RESP_SIZE		sizeof(unsigned long)
++#define MAX_ASYNC_RESP_SIZE		(MIN_ASYNC_RESP_SIZE + MAX_IMB_PACKET_SIZE)
++
++#define STATUS_SUCCESS                  (0x00000000U)
++#define IMB_NO_ASYNC_MSG		((unsigned long)0xE0070012L)
++#define IMB_SEND_REQUEST_FAILED		((unsigned long)0xE0070013L)
++#define INVALID_ARGUMENTS		((unsigned long)0xE0070002L)
++
++
++#define FILE_DEVICE_IMB			0x00008010
++#define IOCTL_IMB_BASE			0x00000880
++
++#define CTL_CODE(DeviceType, Function, Method, Access)\
++		_IO(DeviceType & 0x00FF, Function & 0x00FF)
++
++#define FILE_DEVICE_IMB			0x00008010
++#define IOCTL_IMB_BASE			0x00000880
++#define METHOD_BUFFERED                 0
++#define FILE_ANY_ACCESS                 0
++
++
++typedef struct {
++	int	code;
++#define		SD_NO_ACTION				0
++#define		SD_RESET				1
++#define		SD_POWER_OFF				2
++
++	int	delayTime;  /* in units of 100 millisecond */
++} ShutdownCmdBuffer;
++
++
++/* BMC added parentheses around IOCTL_IMB_BASE + 2 */
++#define IOCTL_IMB_SEND_MESSAGE		CTL_CODE(FILE_DEVICE_IMB, (IOCTL_IMB_BASE + 2), METHOD_BUFFERED, FILE_ANY_ACCESS)
++#define IOCTL_IMB_GET_ASYNC_MSG		CTL_CODE(FILE_DEVICE_IMB, (IOCTL_IMB_BASE + 8), METHOD_BUFFERED, FILE_ANY_ACCESS)
++#define IOCTL_IMB_MAP_MEMORY		CTL_CODE(FILE_DEVICE_IMB, (IOCTL_IMB_BASE + 14),METHOD_BUFFERED, FILE_ANY_ACCESS)
++#define IOCTL_IMB_UNMAP_MEMORY		CTL_CODE(FILE_DEVICE_IMB, (IOCTL_IMB_BASE + 16),METHOD_BUFFERED, FILE_ANY_ACCESS)
++#define IOCTL_IMB_SHUTDOWN_CODE		CTL_CODE(FILE_DEVICE_IMB, (IOCTL_IMB_BASE + 18),METHOD_BUFFERED, FILE_ANY_ACCESS)
++#define IOCTL_IMB_REGISTER_ASYNC_OBJ	CTL_CODE(FILE_DEVICE_IMB, (IOCTL_IMB_BASE + 24),METHOD_BUFFERED, FILE_ANY_ACCESS)
++#define IOCTL_IMB_DEREGISTER_ASYNC_OBJ	CTL_CODE(FILE_DEVICE_IMB, (IOCTL_IMB_BASE + 26),METHOD_BUFFERED, FILE_ANY_ACCESS)
++#define IOCTL_IMB_CHECK_EVENT		CTL_CODE(FILE_DEVICE_IMB, (IOCTL_IMB_BASE + 28),METHOD_BUFFERED, FILE_ANY_ACCESS)
++#define IOCTL_IMB_POLL_ASYNC		CTL_CODE(FILE_DEVICE_IMB, (IOCTL_IMB_BASE + 20),METHOD_BUFFERED, FILE_ANY_ACCESS)
++
++
++#endif /* __LINUX_IPMI_IMB_H */
+Index: linux-ipmi/include/linux/ipmi_radisys.h
+===================================================================
+--- linux-ipmi.orig/include/linux/ipmi_radisys.h	1969-12-31 18:00:00.000000000 -0600
++++ linux-ipmi/include/linux/ipmi_radisys.h	2004-08-10 19:03:53.000000000 -0500
+@@ -0,0 +1,128 @@
++/*
++ * ipmi_radisys.h
++ *
++ * An emulation of the Radisys IPMI interface on top of the MontaVista
++ * interface.
++ *
++ * Author: MontaVista Software, Inc.
++ *         Corey Minyard <minyard@mvista.com>
++ *         source@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.
++ *
++ *
++ *  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.
++ */
++
++#ifndef __LINUX_IPMI_RADISYS_H
++#define __LINUX_IPMI_RADISYS_H
++
++/******************************************************************************
++ * This is the old IPMI interface defined by Radisys.  We are
++ * compliant with that.  Don't use it for new designs, though.
++ */
++#define IOCTL_IPMI_RCV          ( IPMI_IOC_MAGIC<<8 | 1 )
++#define IOCTL_IPMI_SEND         ( IPMI_IOC_MAGIC<<8 | 2 )
++#define IOCTL_IPMI_EVENT        ( IPMI_IOC_MAGIC<<8 | 3 )
++#define IOCTL_IPMI_REGISTER     ( IPMI_IOC_MAGIC<<8 | 4 )
++#define IOCTL_IPMI_UNREGISTER   ( IPMI_IOC_MAGIC<<8 | 5 )
++#define IOCTL_IPMI_CLEAR        ( IPMI_IOC_MAGIC<<8 | 9 )
++
++/* These don't seem to be implemented in the Radisys driver.
++#define IOCTL_IPMI_RESET_BMC    ( IPMI_IOC_MAGIC<<8 | 6 )
++#define IOCTL_IPMI_GET_BMC_ADDR ( IPMI_IOC_MAGIC<<8 | 7 )
++#define IOCTL_IPMI_SET_BMC_ADDR ( IPMI_IOC_MAGIC<<8 | 8 )
++*/
++
++/* 
++ * Network Function Codes 
++ */
++#define IPMI_NETFN_CHASSIS          0x00    /* Chassis - 0x00 << 2 */
++#define IPMI_NETFN_CHASSIS_RESP     0x04    /* Chassis - 0x01 << 2 */
++
++#define IPMI_NETFN_BRIDGE           0x08    /* Bridge - 0x02 << 2 */
++#define IPMI_NETFN_BRIDGE_RESP      0x0c    /* Bridge - 0x03 << 2 */
++
++#define IPMI_NETFN_SENSOR_EVT       0x10    /* Sensor/Event - 0x04 << 2 */
++#define IPMI_NETFN_SENSOR_EVT_RESP  0x14    /* Sensor/Event - 0x05 << 2 */
++
++#define IPMI_NETFN_APP              0x18    /* Application - 0x06 << 2 */
++#define IPMI_NETFN_APP_RESP         0x1c    /* Application - 0x07 << 2 */
++
++#define IPMI_NETFN_FIRMWARE         0x20    /* Firmware - 0x08 << 2 */
++#define IPMI_NETFN_FIRMWARE_RESP    0x24    /* Firmware - 0x09 << 2 */
++
++#define IPMI_NETFN_STORAGE          0x28    /* Storage - 0x0a << 2 */
++#define IPMI_NETFN_STORAGE_RESP     0x2c    /* Storage - 0x0b << 2 */
++
++#define IPMI_NETFN_OEM_1            0xC0    /* Storage - 0x30 << 2 */
++#define IPMI_NETFN_OEM_1_RESP       0xC4    /* Storage - 0x31 << 2 */
++
++/* there are 15 other OEM netfn pairs (OEM - 0x30-0x3f) */
++
++typedef struct _IPMI_LIST_ENTRY {
++   struct _IPMI_LIST_ENTRY * volatile Flink;
++   struct _IPMI_LIST_ENTRY * volatile Blink;
++} IPMI_LIST_ENTRY, *PIPMI_LIST_ENTRY;
++
++typedef struct IPMI_semaphore   IPMI_KSEMAPHORE;
++typedef struct IPMI_semaphore * IPMI_PKSEMAPHORE;
++
++/* IPMI Address structure */
++typedef struct _IPMI_ADDR {
++    unsigned char uchSlave;                /* Slave Address */
++    unsigned char uchLun;                  /* Logical Unit Number */
++} IPMI_ADDR, *PIPMI_ADDR;
++
++#define IPMI_MAX_MSG_SIZE	36
++
++/* IPMI Message Descriptor structure */
++typedef struct _IPMI_MSGDESC {
++                                         /************************************/
++                                         /* Device Driver Specific Elements  */
++                                         /************************************/
++    IPMI_LIST_ENTRY  Entry;                  /* Linked list element */
++    void             *pIRPacket;             /* Pointer to IRP object */
++    IPMI_PKSEMAPHORE pSema;                  /* Semaphore Object */
++    long             lTimeout;               /* Timeout value */
++                                         /************************************/
++                                         /* Shared elements                  */
++                                         /************************************/
++    unsigned char   auchBuffer[IPMI_MAX_MSG_SIZE]; /* Message buffer */
++    unsigned long   ulLength;               /* Length of message in bytes */
++    int             fDefer;                 /* TRUE - Defer I/O
++					       operation, doesn't seem
++					       to be used in the
++					       Radisys driver. */
++    IPMI_ADDR       Dest;                   /* Destination IPM Address */
++    unsigned char   uchNetFn;               /* Network Function */
++    unsigned char   uchCmd;                 /* Command */
++    unsigned char   uchSeq;                 /* Sequence Number */
++    unsigned char   uchComplete;            /* Completion Code */
++} IPMI_MSGDESC, *PIPMI_MSGDESC;
++
++/* Byte return codes for some things. */
++#define LOWLRC_SUCCESS              0x00 /* routine completed successfully */
++#define LOWLRC_ERROR                0xff /* routine did not complete */
++#define LOWLRC_INVALID_PARAMETERS   0xfe /* invalid parameters */
++#define LOWLRC_INVALID_REQUEST_DATA 0xfd /* invalid request data */
++
++#endif /* __LINUX_IPMI_RADISYS_H */
Index: pplinux/linuxnew/patches/linux-ipmi-2.4.27-v33-smb.diff
diff -u /dev/null pplinux/linuxnew/patches/linux-ipmi-2.4.27-v33-smb.diff:1.1
--- /dev/null	Tue May 24 10:38:00 2005
+++ pplinux/linuxnew/patches/linux-ipmi-2.4.27-v33-smb.diff	Thu Feb  3 11:35:39 2005
@@ -0,0 +1,1555 @@
+Index: linux-ipmi/Documentation/Configure.help
+===================================================================
+--- linux-ipmi.orig/Documentation/Configure.help	2004-08-13 08:06:49.000000000 -0500
++++ linux-ipmi/Documentation/Configure.help	2004-08-13 14:03:56.000000000 -0500
+@@ -28761,6 +28761,15 @@
+   is deprecated, please use the IPMI System Interface handler
+   instead.
+ 
++IPMI SMBus handler
++CONFIG_IPMI_SMB
++  Provides a driver for a SMBus interface to a BMC, meaning that you
++  have a driver that must be accessed over an I2C bus instead of a
++  standard interface.  This module requires I2C support.  Note that
++  you might need some I2C changes if CONFIG_IPMI_PANIC_EVENT is
++  enabled along with this, so the I2C driver knows to run to
++  completion during sending a panic event.
++
+ IPMI Watchdog Timer
+ CONFIG_IPMI_WATCHDOG
+   This enables the IPMI watchdog timer.
+Index: linux-ipmi/Documentation/IPMI.txt
+===================================================================
+--- linux-ipmi.orig/Documentation/IPMI.txt	2004-08-13 08:06:49.000000000 -0500
++++ linux-ipmi/Documentation/IPMI.txt	2004-08-13 08:06:50.000000000 -0500
+@@ -101,6 +101,10 @@
+ interface for IPMI.  This is deprecated, ipmi_si_drv supports KCS and
+ SMIC interfaces.
+ 
++ipmi_smb_intf - A driver for accessing BMCs on the SMBus. It uses the
++I2C kernel driver's SMBus interfaces to send and receive IPMI messages
++over the SMBus.
++
+ af_ipmi - A network socket interface to IPMI.  This doesn't take up
+ a character device in your system.
+ 
+@@ -462,10 +466,64 @@
+ the KCS interface sucks.
+ 
+ 
++The SMBus Driver
++----------------
++
++The SMBus driver allows up to 4 SMBus devices to be configured in the
++system.  By default, the driver will register any SMBus interfaces it finds
++in the I2C address range of 0x20 to 0x4f on any adapter.  You can change this
++at module load time (for a module) with:
++
++  insmod ipmi_smb_intf.o
++	smb_addr=<adapter1>,<i2caddr1>[,<adapter2>,<i2caddr2>[,...]]
++	smb_dbg=<flags1>,<flags2>...
++	[smb_defaultprobe=0] [smb_dbg_probe=1]
++
++The addresses are specified in pairs, the first is the adapter ID and the
++second is the I2C address on that adapter.
++
++The debug flags are bit flags for each BMC found, they are:
++IPMI messages: 1, driver state: 2, timing: 4, I2C probe: 8
++
++Setting smb_defaultprobe to zero disabled the default probing of SMBus
++interfaces at address range 0x20 to 0x4f.  This means that only the
++BMCs specified on the smb_addr line will be detected.
++
++Setting smb_dbg_probe to 1 will enable debugging of the probing and
++detection process for BMCs on the SMBusses.
++
++Discovering the IPMI compilant BMC on the SMBus can cause devices
++on the I2C bus to fail. The SMBus driver writes a "Get Device ID" IPMI
++message as a block write to the I2C bus and waits for a response.
++This action can be detrimental to some I2C devices. It is highly recommended
++that the known I2c address be given to the SMBus driver in the smb_addr
++parameter. The default adrress range will not be used when a smb_addr
++parameter is provided.
++
++When compiled into the kernel, the addresses can be specified on the
++kernel command line as:
++
++  ipmi_smb=[<adapter1>.]<addr1>[:<debug1>],[<adapter2>.<addr2>[:<debug1>]....
++
++The [<adapterx>.]<addrx>[:<debugx>] I2C address-debug flag are value
++set for each BMC.  If the adapter is not given, then it defaults to
++zero.  The debug flag is the same as the smb_dbg flag given above.
++
++You may also specify "nodefaults" and "debug_probe", separated by
++commas, on the ipmi_smb line.  These will disable the default SMB
++probe and enable debugging of the BMC probing and detection process,
++respectively.
++
++Note that you might need some I2C changes if CONFIG_IPMI_PANIC_EVENT
++is enabled along with this, so the I2C driver knows to run to
++completion during sending a panic event.
++
++
+ Other Pieces
+ ------------
+ 
+ Watchdog
++--------
+ 
+ A watchdog timer is provided that implements the Linux-standard
+ watchdog timer interface.  It has three module parameters that can be
+Index: linux-ipmi/drivers/char/Config.in
+===================================================================
+--- linux-ipmi.orig/drivers/char/Config.in	2004-08-13 08:06:49.000000000 -0500
++++ linux-ipmi/drivers/char/Config.in	2004-08-13 14:03:50.000000000 -0500
+@@ -234,6 +234,7 @@
+ dep_tristate '  Device interface for IPMI' CONFIG_IPMI_DEVICE_INTERFACE $CONFIG_IPMI_HANDLER
+ dep_tristate '  IPMI SI handler' CONFIG_IPMI_SI $CONFIG_IPMI_HANDLER
+ dep_tristate '  IPMI KCS handler' CONFIG_IPMI_KCS $CONFIG_IPMI_HANDLER
++dep_tristate '  IPMI SMBus handler' CONFIG_IPMI_SMB $CONFIG_IPMI_HANDLER $CONFIG_I2C
+ dep_tristate '  IPMI Watchdog Timer' CONFIG_IPMI_WATCHDOG $CONFIG_IPMI_HANDLER
+ dep_tristate '  IPMI Poweroff' CONFIG_IPMI_POWEROFF $CONFIG_IPMI_HANDLER
+ 
+Index: linux-ipmi/drivers/char/ipmi/ipmi_smb_intf.c
+===================================================================
+--- linux-ipmi.orig/drivers/char/ipmi/ipmi_smb_intf.c	1969-12-31 18:00:00.000000000 -0600
++++ linux-ipmi/drivers/char/ipmi/ipmi_smb_intf.c	2004-08-13 14:04:34.000000000 -0500
+@@ -0,0 +1,1372 @@
++/*
++ * ipmi_smb_intf.c
++ *
++ * The interface to the IPMI driver for SMBus access to a SMBus compliant device.
++ *
++ * Author: Intel Corporation
++ *         Todd Davis <todd.c.davis@intel.com>
++  *
++ * Copyright 2003 Intel Corporation
++ *
++ *  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.
++ */
++
++/*
++ * This file holds the "policy" for the interface to the SMB state
++ * machine.  It does the configuration, handles timers and interrupts,
++ * and drives the real SMB state machine.
++ */
++
++#include <linux/config.h>
++#include <linux/version.h>
++#if defined(MODVERSIONS)
++#include <linux/modversions.h>
++#endif
++
++#include <linux/module.h>
++#include <asm/system.h>
++#include <linux/sched.h>
++#include <linux/timer.h>
++#include <linux/errno.h>
++#include <linux/spinlock.h>
++#include <linux/slab.h>
++#include <linux/delay.h>
++#include <linux/list.h>
++#include <linux/i2c.h>
++#include <linux/ipmi_smi.h>
++#include <linux/init.h>
++
++
++#define IPMI_SMB_VERSION "v33"
++
++/* module feature switches */
++#define	REGISTER_SMI	1
++#define	SMB_KTHREAD	1
++
++#ifdef SMB_KTHREAD
++#include <linux/kernel.h>
++#include <linux/smp_lock.h>
++
++/* a structure to store all information we need
++   for our thread */
++typedef struct kthread_struct
++{
++        /* Linux task structure of thread */
++        struct task_struct *thread;
++        /* Task queue need to launch thread */
++        struct tq_struct tq;
++       /* semaphore needed on start and creation of thread. */
++        struct semaphore startstop_sem;
++
++        /* queue thread is waiting on. Gets initialized by
++           init_kthread, can be used by thread itself.
++        */
++        wait_queue_head_t queue;
++        /* flag to tell thread whether to die or not.
++           When the thread receives a signal, it must check
++           the value of terminate and call exit_kthread and terminate
++           if set.
++        */
++	int terminate;
++} kthread_t;	/* the variable that contains the thread data */
++#endif
++
++#define	SMB_IPMI_REQUEST	2
++#define	SMB_IPMI_RESPONSE	3
++
++/* smb_debug is a bit-field
++ *	SMB_DEBUG_MSG -	commands and their responses
++ *	SMB_DEBUG_STATES -	message states
++ *	SMB_DEBUG_TIMING -	 Measure times between events in the driver
++ */
++#define SMB_DEBUG_TIMING	4
++#define SMB_DEBUG_STATE		2
++#define SMB_DEBUG_MSG		1
++#define SMB_NODEBUG		0
++#define SMB_DEFAULT_DEBUG	(SMB_NODEBUG)
++
++#ifdef CONFIG_IPMI_SMB
++/* This forces a dependency to the config file for this option. */
++#endif
++
++enum smb_intf_state {
++	SMB_NORMAL,
++	SMB_GETTING_FLAGS,
++	SMB_GETTING_EVENTS,
++	SMB_CLEARING_FLAGS,
++	SMB_CLEARING_FLAGS_THEN_SET_IRQ,
++	SMB_GETTING_MESSAGES,
++	SMB_ENABLE_INTERRUPTS1,
++	SMB_ENABLE_INTERRUPTS2
++	/* FIXME - add watchdog stuff. */
++};
++
++#define SMB_IDLE(smb)	 ((smb)->smb_state == SMB_NORMAL \
++			  && (smb)->curr_msg == NULL \
++			  && ! atomic_read(&(smb)->req_events))
++
++#define	SMB_MSG_RETRIES	10
++
++struct smb_info
++{
++	int                 pos;
++	ipmi_smi_t          intf;
++	spinlock_t          msg_lock;
++	struct list_head    xmit_msgs;
++	struct list_head    hp_xmit_msgs;
++	struct ipmi_smi_msg *curr_msg;
++	enum smb_intf_state smb_state;
++	unsigned long       smb_debug;
++
++	/* Flags from the last GET_MSG_FLAGS command, used when an ATTN
++	   is set to hold the flags until we are done handling everything
++	   from the flags. */
++#define RECEIVE_MSG_AVAIL	0x01
++#define EVENT_MSG_BUFFER_FULL	0x02
++#define WDT_PRE_TIMEOUT_INT	0x08
++	unsigned char       msg_flags;
++
++	/* If set to true, this will request events the next time the
++	   state machine is idle. */
++	atomic_t            req_events;
++
++	/* If true, run the state machine to completion on every send
++	   call.  Generally used after a panic or shutdown to make
++	   sure stuff goes out. */
++	int                 run_to_completion;
++
++#ifdef SMB_KTHREAD
++	kthread_t smb_thread;
++#endif
++	struct i2c_client client;
++	unsigned char ipmi_smb_dev_rev;
++	unsigned char ipmi_smb_fw_rev_major;
++	unsigned char ipmi_smb_fw_rev_minor;
++	unsigned char ipmi_version_major;
++	unsigned char ipmi_version_minor;
++};
++
++static int initialized = 0;
++static void return_hosed_msg(struct smb_info *smb_info);
++
++static void deliver_recv_msg(struct smb_info *smb_info,
++			     struct ipmi_smi_msg *msg)
++{
++	if (msg->rsp_size < 0) {
++		if (smb_info->curr_msg == NULL) {
++			smb_info->curr_msg = msg;
++			return_hosed_msg(smb_info);
++		} else {
++			printk(KERN_ERR
++			       "malformed message in deliver_recv_msg:"
++			       " rsp_size = %d\n", msg->rsp_size);
++			ipmi_free_smi_msg(msg);
++		}
++	} else {
++		ipmi_smi_msg_received(smb_info->intf, msg);
++	}
++}
++
++static void return_hosed_msg(struct smb_info *smb_info)
++{
++	struct ipmi_smi_msg *msg = smb_info->curr_msg;
++
++	/* Make it a reponse */
++	msg->rsp[0] = msg->data[0] | 4;
++	msg->rsp[1] = msg->data[1];
++	msg->rsp[2] = 0xFF; /* Unknown error. */
++	msg->rsp_size = 3;
++
++	smb_info->curr_msg = NULL;
++	deliver_recv_msg(smb_info, msg);
++}
++
++static s32 smbus_client_read_block_data(struct i2c_client *client, int debug,
++					u8 *values)
++{
++	s32 resp_len;
++	int retries = 0;
++
++	/* FIXME - is there a way to limit the read size?  This culd
++	 * be an overrun situation otherwise. */
++	while ((resp_len = i2c_smbus_read_block_data (client,
++						      SMB_IPMI_RESPONSE,
++						      values)) < 0)
++	{
++		if ((retries += 1) >= SMB_MSG_RETRIES) {
++			printk(KERN_ERR
++			       "smb_smbus_read_block_data failed: %d\n",
++			       resp_len);
++			break;
++		} else if (retries >= SMB_MSG_RETRIES/2 && signal_pending(current)) {
++			i2c_set_spin_delay(1); // shutting down
++		} else if (debug & (SMB_DEBUG_MSG|SMB_DEBUG_TIMING)) {
++			printk(KERN_WARNING
++			       "smb_smbus_read_block_data: retry %d\n",
++			       retries);
++		}
++	}
++
++	if (debug & SMB_DEBUG_TIMING) {
++		struct timeval t;
++		do_gettimeofday(&t);
++		printk(KERN_INFO "**Response %02x %02x %02x: %ld.%6.6ld\n",
++		       values[0], values[1], values[2], t.tv_sec, t.tv_usec);
++	}
++
++	if (debug & SMB_DEBUG_MSG) {
++		int i;
++		printk(KERN_INFO "ipmi response:");
++		for (i = 0; i < resp_len; i ++) {
++			printk (" %02x", (unsigned char) (values[i]));
++		}
++		printk ("\n");
++	}
++
++	return resp_len;
++}
++
++static s32 smb_smbus_read_block_data(struct smb_info *smb_info, u8 *values)
++{
++	return smbus_client_read_block_data(&smb_info->client,
++					    smb_info->smb_debug, values);
++}
++
++static s32 smbus_client_write_block_data(struct i2c_client *client, int debug,
++					 u8 length, u8 *values)
++{
++	s32 ret;
++	int retries = 0;
++
++	if (debug & SMB_DEBUG_MSG) {
++		int i ;
++
++		printk(KERN_INFO "ipmi request:");
++		for (i = 0; i < length; i ++) {
++			printk (" %02x", (unsigned char) (values [i]));
++		}
++		printk ("\n");
++	}
++
++	if (debug & SMB_DEBUG_TIMING) {
++		struct timeval t;
++		do_gettimeofday(&t);
++		printk(KERN_INFO "**Request %02x %02x: %ld.%6.6ld\n",
++		       values [0],values [1], t.tv_sec, t.tv_usec);
++	}
++
++	while ((ret = i2c_smbus_write_block_data (client,
++						  SMB_IPMI_REQUEST,
++						  length, values)) < 0)
++	{
++		if ((retries += 1) >= SMB_MSG_RETRIES) {
++			printk(KERN_ERR
++			       "smb_smbus_write_block_data failed: %d\n", ret);
++			break;
++		} else if (retries >= SMB_MSG_RETRIES/2 && signal_pending(current)) {
++			i2c_set_spin_delay(1); // shutting down
++		} else if (debug & (SMB_DEBUG_MSG|SMB_DEBUG_TIMING)) {
++			printk(KERN_WARNING
++			       "smb_smbus_write_block_data: retry %d\n",
++			       retries);
++		}
++	}
++	return ret;
++}
++
++static s32 smb_smbus_write_block_data(struct smb_info *smb_info,
++                                      u8 length,  u8 *values)
++{
++	return smbus_client_write_block_data(&smb_info->client,
++					     smb_info->smb_debug,
++					     length,
++					     values);
++}
++
++static int send_next_msg(struct smb_info *smb_info)
++{
++	s32              rv;
++	struct list_head *entry = NULL;
++
++	spin_lock(&(smb_info->msg_lock));
++
++	/* Pick the high priority queue first. */
++	if (! list_empty(&(smb_info->hp_xmit_msgs))) {
++		entry = smb_info->hp_xmit_msgs.next;
++	} else if (! list_empty(&(smb_info->xmit_msgs))) {
++		entry = smb_info->xmit_msgs.next;
++	}
++
++	if (!entry) {
++		spin_unlock(&(smb_info->msg_lock));
++		smb_info->curr_msg = NULL;
++		return 0;
++	}
++	list_del(entry);
++	smb_info->curr_msg = list_entry(entry,
++					struct ipmi_smi_msg,
++					link);
++	spin_unlock(&(smb_info->msg_lock));
++	rv = smb_smbus_write_block_data(
++	    smb_info,
++	    smb_info->curr_msg->data_size,
++	    smb_info->curr_msg->data);
++	if (rv) {
++		return_hosed_msg(smb_info);
++	}
++	return 1;
++}
++
++static void start_enable_irq(struct smb_info *smb_info)
++{
++	unsigned char msg[2];
++
++	/* If we are enabling interrupts, we have to tell the
++	   IPMI device to use them. */
++	msg[0] = (IPMI_NETFN_APP_REQUEST << 2);
++	msg[1] = IPMI_GET_BMC_GLOBAL_ENABLES_CMD;
++
++	if (smb_smbus_write_block_data(smb_info, 2, msg) == 0) {
++		smb_info->smb_state = SMB_ENABLE_INTERRUPTS1;
++	} else {
++		smb_info->smb_state = SMB_NORMAL;
++	}
++}
++
++static void start_clear_flags(struct smb_info *smb_info)
++{
++	unsigned char msg[3];
++
++	/* Make sure the watchdog pre-timeout flag is not set at startup. */
++	msg[0] = (IPMI_NETFN_APP_REQUEST << 2);
++	msg[1] = IPMI_CLEAR_MSG_FLAGS_CMD;
++	msg[2] = WDT_PRE_TIMEOUT_INT;
++
++	if (smb_smbus_write_block_data(smb_info, 3, msg) == 0) {
++		smb_info->smb_state = SMB_CLEARING_FLAGS;
++	} else {
++		smb_info->smb_state = SMB_NORMAL;
++	}
++}
++
++static void handle_flags(struct smb_info *smb_info)
++{
++	if (smb_info->msg_flags & WDT_PRE_TIMEOUT_INT) {
++		/* Watchdog pre-timeout */
++		start_clear_flags(smb_info);
++		smb_info->msg_flags &= ~WDT_PRE_TIMEOUT_INT;
++		ipmi_smi_watchdog_pretimeout(smb_info->intf);
++	} else if (smb_info->msg_flags & RECEIVE_MSG_AVAIL) {
++		/* Messages available. */
++		smb_info->curr_msg = ipmi_alloc_smi_msg();
++		if (!smb_info->curr_msg) {
++			smb_info->smb_state = SMB_NORMAL;
++			return;
++		}
++
++		smb_info->curr_msg->data[0] = (IPMI_NETFN_APP_REQUEST << 2);
++		smb_info->curr_msg->data[1] = IPMI_GET_MSG_CMD;
++		smb_info->curr_msg->data_size = 2;
++
++		if (smb_smbus_write_block_data(
++		    smb_info,
++		    smb_info->curr_msg->data_size,
++		    smb_info->curr_msg->data) == 0) {
++			smb_info->smb_state = SMB_GETTING_MESSAGES;
++		} else {
++			ipmi_free_smi_msg(smb_info->curr_msg);
++			smb_info->curr_msg = NULL;
++			smb_info->smb_state = SMB_NORMAL;
++			return;
++		}
++	} else if (smb_info->msg_flags & EVENT_MSG_BUFFER_FULL) {
++		/* Events available. */
++		smb_info->curr_msg = ipmi_alloc_smi_msg();
++		if (!smb_info->curr_msg) {
++			smb_info->smb_state = SMB_NORMAL;
++			return;
++		}
++
++		smb_info->curr_msg->data[0] = (IPMI_NETFN_APP_REQUEST << 2);
++		smb_info->curr_msg->data[1] = IPMI_READ_EVENT_MSG_BUFFER_CMD;
++		smb_info->curr_msg->data_size = 2;
++
++		if (smb_smbus_write_block_data(
++		    smb_info,
++		    smb_info->curr_msg->data_size,
++		    smb_info->curr_msg->data) == 0) {
++			smb_info->smb_state = SMB_GETTING_EVENTS;
++		} else {
++			ipmi_free_smi_msg(smb_info->curr_msg);
++			smb_info->curr_msg = NULL;
++			smb_info->smb_state = SMB_NORMAL;
++			return;
++		}
++	} else {
++		smb_info->smb_state = SMB_NORMAL;
++	}
++}
++
++static void handle_transaction_done(struct smb_info *smb_info)
++{
++	struct ipmi_smi_msg *msg;
++	unsigned int  len;
++
++	if (smb_info->smb_debug & SMB_DEBUG_STATE) {
++		printk(KERN_INFO "DONE 1: state = %d.\n", smb_info->smb_state);
++	}
++	switch (smb_info->smb_state) {
++	case SMB_NORMAL:
++		if (!smb_info->curr_msg)
++			break;
++
++		smb_info->curr_msg->rsp_size
++			= smb_smbus_read_block_data(
++			    smb_info,
++			    smb_info->curr_msg->rsp);
++
++		msg = smb_info->curr_msg;
++		smb_info->curr_msg = NULL;
++		deliver_recv_msg(smb_info, msg);
++		break;
++
++	case SMB_GETTING_FLAGS:
++	{
++		unsigned char msg[4];
++
++		/* We got the flags from the SMB, now handle them. */
++		len = smb_smbus_read_block_data(smb_info, msg);
++		if (len < 0) {
++			/* Error fetching flags, just give up for  now. */
++			smb_info->smb_state = SMB_NORMAL;
++		} else if (msg[2] != 0) {
++			/* Error fetching flags, just give up for  now. */
++			smb_info->smb_state = SMB_NORMAL;
++		} else if (len < 3) {
++			/* Hmm, no flags.  That's technically illegal, but
++			   don't use uninitialized data. */
++			smb_info->smb_state = SMB_NORMAL;
++		} else {
++			smb_info->msg_flags = msg[3];
++			handle_flags(smb_info);
++		}
++		break;
++	}
++
++	case SMB_CLEARING_FLAGS:
++	case SMB_CLEARING_FLAGS_THEN_SET_IRQ:
++	{
++		unsigned char msg[3];
++
++		/* We cleared the flags. */
++		len = smb_smbus_read_block_data(smb_info, msg);
++		if (len < 0 || msg[2] != 0) {
++			/* Error clearing flags */
++			printk(KERN_WARNING
++			       "ipmi_smb: Error clearing flags: %2.2x\n",
++			       msg[2]);
++		}
++		if (smb_info->smb_state == SMB_CLEARING_FLAGS_THEN_SET_IRQ)
++			start_enable_irq(smb_info);
++		else
++			smb_info->smb_state = SMB_NORMAL;
++		break;
++	}
++
++	case SMB_GETTING_EVENTS:
++	{
++		smb_info->curr_msg->rsp_size
++			= smb_smbus_read_block_data(smb_info,
++						    smb_info->curr_msg->rsp);
++
++		msg = smb_info->curr_msg;
++		smb_info->curr_msg = NULL;
++		if (msg->rsp_size < 0 || msg->rsp[2] != 0) {
++			/* Error getting event, probably done. */
++			msg->done(msg);
++
++			/* Take off the event flag. */
++			smb_info->msg_flags &= ~EVENT_MSG_BUFFER_FULL;
++		} else {
++			deliver_recv_msg(smb_info, msg);
++		}
++		handle_flags(smb_info);
++		break;
++	}
++
++	case SMB_GETTING_MESSAGES:
++	{
++		smb_info->curr_msg->rsp_size
++			= smb_smbus_read_block_data(smb_info,
++						      smb_info->curr_msg->rsp);
++
++		msg = smb_info->curr_msg;
++		smb_info->curr_msg = NULL;
++		if (msg->rsp_size < 0 || msg->rsp[2] != 0) {
++			/* Error getting event, probably done. */
++			msg->done(msg);
++
++			/* Take off the msg flag. */
++			smb_info->msg_flags &= ~RECEIVE_MSG_AVAIL;
++		} else {
++			deliver_recv_msg(smb_info, msg);
++		}
++		handle_flags(smb_info);
++		break;
++	}
++
++	case SMB_ENABLE_INTERRUPTS1:
++	{
++		unsigned char msg[4];
++
++		/* We got the flags from the SMB, now handle them. */
++		len = smb_smbus_read_block_data(smb_info, msg);
++		if (len < 0 || msg[2] != 0) {
++			printk(KERN_WARNING
++			       "ipmi_smb: Could not enable interrupts"
++			       ", failed get, using polled mode.\n");
++			smb_info->smb_state = SMB_NORMAL;
++		} else {
++			msg[0] = (IPMI_NETFN_APP_REQUEST << 2);
++			msg[1] = IPMI_SET_BMC_GLOBAL_ENABLES_CMD;
++			msg[2] = msg[3] | 1; /* enable msg queue int */
++			if (smb_smbus_write_block_data(
++			    smb_info,3, msg) == 0) {
++				smb_info->smb_state = SMB_ENABLE_INTERRUPTS2;
++			} else
++				smb_info->smb_state = SMB_NORMAL;
++		}
++		break;
++	}
++
++	case SMB_ENABLE_INTERRUPTS2:
++	{
++		unsigned char msg[4];
++
++		/* We got the flags from the SMB, now handle them. */
++		len = smb_smbus_read_block_data(smb_info, msg);
++		if (len < 0 || msg[2] != 0) {
++			printk(KERN_WARNING
++			       "ipmi_smb: Could not enable interrupts"
++			       ", failed set, using polled mode.\n");
++		}
++		smb_info->smb_state = SMB_NORMAL;
++		break;
++	}
++	}
++	if (smb_info->smb_debug & SMB_DEBUG_STATE) {
++		printk(KERN_INFO "DONE 2: state = %d.\n", smb_info->smb_state);
++	}
++}
++
++/*
++ * smb_event_handler must have a user context for calls to lm_sensors'
++ * SMBus interface
++ */
++static void smb_event_handler(struct smb_info *smb_info)
++{
++	s32 rv;
++	if (smb_info->smb_debug & SMB_DEBUG_STATE) {
++		printk(KERN_INFO "smb_event_handler: state = %d.\n",
++		       smb_info->smb_state);
++	}
++	handle_transaction_done(smb_info);
++
++	if (smb_info->smb_state == SMB_NORMAL &&
++	    smb_info->curr_msg == NULL) {
++			/* If we are currently idle, try to start the
++			 * next message. */
++			send_next_msg(smb_info);
++	}
++
++	if (smb_info->smb_state == SMB_NORMAL &&
++	    smb_info->curr_msg == NULL &&
++	     atomic_read(&smb_info->req_events))
++	{
++		/* We are idle and the upper layer requested that I fetch
++		   events, so do so. */
++		unsigned char msg[2];
++
++		atomic_set(&smb_info->req_events, 0);
++		msg[0] = (IPMI_NETFN_APP_REQUEST << 2);
++		msg[1] = IPMI_GET_MSG_FLAGS_CMD;
++
++		rv = smb_smbus_write_block_data(smb_info, 2, msg);
++		if(rv == 0) {
++			smb_info->smb_state = SMB_GETTING_FLAGS;
++		}
++	}
++}
++
++#ifdef REGISTER_SMI
++static void sender(void                *send_info,
++		   struct ipmi_smi_msg *msg,
++		   int                 priority)
++{
++	struct smb_info *smb_info = (struct smb_info *) send_info;
++
++	if (smb_info->run_to_completion) {
++		/* If we are running to completion, then throw it in
++		   the list and run transactions until everything is
++		   clear.  Priority doesn't matter here. */
++		list_add_tail(&(msg->link), &(smb_info->xmit_msgs));
++
++		smb_event_handler(smb_info);
++		while  (! SMB_IDLE(smb_info)) {
++			smb_event_handler(smb_info);
++		}
++		return;
++	}
++	if (smb_info->smb_debug & SMB_DEBUG_TIMING) {
++		struct timeval     t;
++		do_gettimeofday(&t);
++		printk(KERN_INFO
++		       "**Enqueue %02x %02x: %ld.%6.6ld\n",
++		       msg->data[0], msg->data[1], t.tv_sec, t.tv_usec);
++	}
++
++	spin_lock(&(smb_info->msg_lock));
++	if (priority > 0) {
++		list_add_tail(&(msg->link), &(smb_info->hp_xmit_msgs));
++	} else {
++		list_add_tail(&(msg->link), &(smb_info->xmit_msgs));
++	}
++	spin_unlock(&(smb_info->msg_lock));
++
++#ifdef SMB_KTHREAD
++	wake_up_interruptible(&smb_info->smb_thread.queue);
++#endif
++}
++
++static void poll(void *send_info)
++{
++	struct smb_info *smb_info = (struct smb_info *) send_info;
++
++	i2c_set_spin_delay(1);
++	smb_event_handler(smb_info);
++	i2c_set_spin_delay(smb_info->run_to_completion);
++}
++
++static void request_events(void *send_info)
++{
++	struct smb_info *smb_info = (struct smb_info *) send_info;
++	static int throttle = 0;
++
++	if (smb_info->smb_debug & SMB_DEBUG_TIMING) {
++		struct timeval t;
++		do_gettimeofday(&t);
++		printk(KERN_INFO "**request_events: %ld.%6.6ld\n",
++		       t.tv_sec, t.tv_usec);
++	}
++	if( throttle <= 0 ) {
++		throttle = 2;	// throttle request due to slow mBMC
++		atomic_set(&smb_info->req_events, 1);
++#ifdef SMB_KTHREAD
++		wake_up_interruptible(&smb_info->smb_thread.queue);
++#endif
++	} else {
++		throttle -= 1;
++	}
++}
++
++static int new_user(void *send_info)
++{
++	if (!try_inc_mod_count(THIS_MODULE))
++		return -EBUSY;
++	return 0;
++}
++
++static void user_left(void *send_info)
++{
++	MOD_DEC_USE_COUNT;
++}
++
++static void set_run_to_completion(void *send_info, int i_run_to_completion)
++{
++	struct smb_info *smb_info = (struct smb_info *) send_info;
++
++	smb_info->run_to_completion = i_run_to_completion;
++	/* Note that if this does not compile, there are some I2C
++	   changes that you need to handle this properly. */
++	i2c_set_spin_delay(i_run_to_completion);
++	if (i_run_to_completion) {
++		smb_event_handler(smb_info);
++		while  (! SMB_IDLE(smb_info)) {
++			smb_event_handler(smb_info);
++		}
++	}
++}
++
++static struct ipmi_smi_handlers handlers =
++{
++	sender:		       sender,
++	request_events:        request_events,
++	new_user:	       new_user,
++	user_left:	       user_left,
++	set_run_to_completion: set_run_to_completion,
++	poll:                  poll,
++};
++#endif	/* REGISTER_SMI */
++
++#ifdef SMB_KTHREAD
++/* initialize new created thread. Called by the new thread. */
++static void init_kthread(kthread_t *kthread, char *name)
++{
++        /* lock the kernel. A new kernel thread starts without
++           the big kernel lock, regardless of the lock state
++           of the creator (the lock level is *not* inheritated)
++        */
++        lock_kernel();
++
++        /* fill in thread structure */
++        kthread->thread = current;
++
++        /* set signal mask to what we want to respond */
++        siginitsetinv(&current->blocked,
++		      sigmask(SIGKILL)|sigmask(SIGINT)|sigmask(SIGTERM));
++
++        /* initialise wait queue */
++        init_waitqueue_head(&kthread->queue);
++
++        /* initialise termination flag */
++        kthread->terminate = 0;
++
++        /* set name of this process (max 15 chars + 0 !) */
++        sprintf(current->comm, name);
++
++        /* let others run */
++        unlock_kernel();
++
++        /* tell the creator that we are ready and let him continue */
++        up(&kthread->startstop_sem);
++
++}
++
++/* cleanup of thread. Called by the exiting thread. */
++static void exit_kthread(kthread_t *kthread)
++{
++        /* we are terminating */
++
++	/* lock the kernel, the exit will unlock it */
++        lock_kernel();
++        kthread->thread = NULL;
++        mb();
++
++        /* notify the stop_kthread() routine that we are terminating. */
++	up(&kthread->startstop_sem);
++	/* the kernel_thread that called clone() does a do_exit here. */
++
++	/* there is no race here between execution of the "killer" and
++	   real termination of the thread (race window between up and
++	   do_exit), since both the thread and the "killer" function
++	   are running with the kernel lock held.  The kernel lock
++	   will be freed after the thread exited, so the code is
++	   really not executed anymore as soon as the unload functions
++	   gets the kernel lock back.  The init process may not have
++	   made the cleanup of the process here, but the cleanup can
++	   be done safely with the module unloaded.
++ 	*/
++
++}
++
++/* this is the thread function for making SMBus function calls into
++ * the lm_sensors' i2c-core module */
++static void smb_thread(struct smb_info *smb_info)
++{
++        kthread_t *kthread = &smb_info->smb_thread;
++	/* setup the thread environment */
++        init_kthread(kthread, "IPMI SMBus thread");
++
++        /* an endless loop in which we are doing our work */
++        for(;;)
++        {
++		do {
++			smb_event_handler(smb_info);
++		} while  (! SMB_IDLE(smb_info));
++
++                interruptible_sleep_on(&kthread->queue);
++
++                /* We need to do a memory barrier here to be sure that
++                   the flags are visible on all CPUs.
++                */
++                 mb();
++
++                /* here we are back from sleep, either due to the timeout
++                   (one second), or because we caught a signal.
++                */
++                if (kthread->terminate)
++                {
++                        /* we received a request to terminate ourself */
++                        break;
++                }
++         }
++        /* cleanup the thread, leave */
++        exit_kthread(kthread);
++
++	/* returning from the thread here calls the exit functions */
++}
++
++static void kthread_launcher(void *data)
++{
++        kernel_thread((int (*)(void *))smb_thread, data, 0);
++}
++
++/* create a new kernel thread. Called by the creator. */
++static void start_kthread(struct smb_info *smb_info)
++{
++       kthread_t *kthread = &smb_info->smb_thread;
++        /* initialize the semaphore:
++           we start with the semaphore locked. The new kernel
++           thread will setup its stuff and unlock it. This
++           control flow (the one that creates the thread) blocks
++           in the down operation below until the thread has reached
++           the up() operation.
++         */
++        init_MUTEX_LOCKED(&kthread->startstop_sem);
++
++        /* create the new thread my running a task through keventd */
++
++        /* initialize the task queue structure */
++        kthread->tq.sync = 0;
++        INIT_LIST_HEAD(&kthread->tq.list);
++        kthread->tq.routine =  kthread_launcher;
++        kthread->tq.data = smb_info;
++
++        /* and schedule it for execution */
++        schedule_task(&kthread->tq);
++
++        /* wait till it has reached the setup_thread routine */
++        down(&kthread->startstop_sem);
++
++}
++
++/* stop a kernel thread. Called by the removing instance */
++static void stop_kthread(kthread_t *kthread)
++{
++        if (kthread->thread == NULL)
++        {
++                printk(KERN_WARNING
++		       "stop_kthread: killing non existing thread!\n");
++                return;
++        }
++
++        /* this function needs to be protected with the big
++	   kernel lock (lock_kernel()). The lock must be
++           grabbed before changing the terminate
++	   flag and released after the down() call. */
++        lock_kernel();
++
++        /* initialize the semaphore. We lock it here, the
++           leave_thread call of the thread to be terminated
++           will unlock it. As soon as we see the semaphore
++           unlocked, we know that the thread has exited.
++	*/
++        init_MUTEX_LOCKED(&kthread->startstop_sem);
++
++        /* We need to do a memory barrier here to be sure that
++           the flags are visible on all CPUs.
++        */
++        mb();
++
++        /* set flag to request thread termination */
++        kthread->terminate = 1;
++	wake_up_interruptible(&kthread->queue);
++
++        /* We need to do a memory barrier here to be sure that
++           the flags are visible on all CPUs.
++        */
++        mb();
++        kill_proc(kthread->thread->pid, SIGKILL, 1);
++
++        /* block till thread terminated */
++        down(&kthread->startstop_sem);
++
++        /* release the big kernel lock */
++        unlock_kernel();
++
++        /* now we are sure the thread is in zombie state. We
++           notify keventd to clean the process up.
++        */
++        kill_proc(2, SIGCHLD, 1);
++
++}
++#endif
++
++static int ipmi_smb_detect_hardware(struct i2c_client *client, int debug,
++				    struct smb_info **smb_info)
++{
++	unsigned char   msg[2];
++	unsigned char   *resp;
++	unsigned long   resp_len;
++	s32             ret;
++	struct smb_info *info;
++	int             rv = 0;
++
++	resp = kmalloc(IPMI_MAX_MSG_LENGTH, GFP_KERNEL);
++	if (!resp)
++		return -ENOMEM;
++
++	/* Do a Get Device ID command, since it comes back with some
++	   useful info. */
++	msg[0] = IPMI_NETFN_APP_REQUEST << 2;
++	msg[1] = IPMI_GET_DEVICE_ID_CMD;
++
++	ret = smbus_client_write_block_data(client, debug, 2, msg);
++	if (ret) {
++		rv = -ENODEV;
++		goto out;
++	}
++
++	/* Otherwise, we got some data. */
++	resp_len = smbus_client_read_block_data(client, debug, resp);
++	if (resp_len < 6) {
++		/* That's odd, it should be longer. */
++		rv = -EINVAL;
++		goto out;
++	}
++
++	if ((resp[1] != IPMI_GET_DEVICE_ID_CMD) || (resp[2] != 0)) {
++		/* That's odd, it shouldn't be able to fail. */
++		rv = -EINVAL;
++		goto out;
++	}
++
++	info = kmalloc(sizeof(*info), GFP_KERNEL);
++	if (!info) {
++		rv = -ENOMEM;
++		goto out;
++	}
++	memset(info, 0, sizeof(*info));
++
++	info->ipmi_smb_dev_rev = resp[4] & 0xf;
++	info->ipmi_smb_fw_rev_major = resp[5] & 0x7f;
++	info->ipmi_smb_fw_rev_minor = resp[6];
++	info->ipmi_version_major = resp[7] & 0xf;
++	info->ipmi_version_minor = resp[7] >> 4;
++	info->client = *client;
++	info->client.data = info;
++	info->smb_debug = debug;
++
++	*smb_info = info;
++
++ out:
++	kfree(resp);
++	return rv;
++}
++
++#define MAX_SMB_BMCS 4
++/* no expressions allowed in __MODULE_STRING */
++#define MAX_SMB_ADDR_PAIRS	8
++
++/* An array of SMB interfaces. */
++static struct smb_info *smb_infos[MAX_SMB_BMCS];
++
++/*
++ * An array of pairs of numbers to specify where specific BMCs exist.
++ * Each pair specifies the adapter number and address on the adapter.
++ * A BMC will be forced at that position.
++ *
++ * Always provide the i2c address if it is known.
++ */
++/* force list has 3 entries - 0:bus/adapter no 1: i2c addr 2: unknown/unused */
++#define	FORCE_LIST_ENTRIES	3
++static unsigned short smb_addr[MAX_SMB_BMCS*2];
++static unsigned short smb_force_list[MAX_SMB_BMCS*FORCE_LIST_ENTRIES + FORCE_LIST_ENTRIES];
++
++MODULE_PARM(smb_addr, "1-"__MODULE_STRING(MAX_SMB_ADDR_PAIRS)"h");
++
++/*
++ * If this is sent, don't probe for adapters anywhere but where the
++ * smb_addr array gives.
++ */
++static int smb_defaultprobe = 0; // off by default, probing is dangerous to hardware
++MODULE_PARM(smb_defaultprobe, "i");
++
++/*
++ * Turn debugging on for specific BMCs.  This array is indexed by
++ * BMC number.
++ *
++ * Debug bit flags: IPMI messages: 1, driver state: 2, msg timing: 4
++ */
++static int smb_dbg[MAX_SMB_BMCS];
++MODULE_PARM(smb_dbg, "1-"__MODULE_STRING(MAX_SMB_BMCS)"i");
++
++/*
++ * Debug the probing of adapters.
++ */
++static int smb_dbg_probe = 0;
++MODULE_PARM(smb_dbg_probe, "i");
++
++#define SMB_I2C_START_ADDR	0x20
++#define SMB_I2C_END_ADDR	0x4f
++static unsigned short normal_i2c[] = { I2C_CLIENT_END, I2C_CLIENT_END };
++static unsigned short normal_i2c_range[] = { SMB_I2C_START_ADDR,
++					     SMB_I2C_END_ADDR,
++					     I2C_CLIENT_END };
++/*
++static unsigned int normal_isa[] = { SENSORS_ISA_END };
++static unsigned int normal_isa_range[] = { SENSORS_ISA_END };
++*/
++static unsigned short reserved[] =
++{
++/* As defined by SMBus Spec. Appendix C */
++	0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x28,
++	0x37,
++/* As defined by SMBus Spec. Sect. 5.2 */
++	0x01, 0x02, 0x03, 0x04, 0x05,
++	0x06, 0x07, 0x78, 0x79, 0x7a, 0x7b,
++	0x7c, 0x7d, 0x7e, 0x7f,
++/* Common PC addresses (bad idea) */
++	0x2d, 0x48, 0x49, /* sensors */
++	0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* eeproms */
++	0x69, /* clock chips */
++
++	I2C_CLIENT_END
++};
++
++static unsigned short smb_empty_list[] = { I2C_CLIENT_END, I2C_CLIENT_END };
++
++static struct i2c_client_address_data smb_address_data = {
++	.normal_i2c 		= normal_i2c,
++	.normal_i2c_range	= normal_i2c_range,
++	.probe			= smb_empty_list,
++	.probe_range		= smb_empty_list,
++	.ignore			= reserved,
++	.ignore_range		= smb_empty_list,
++	.force			= smb_force_list,
++};
++
++static unsigned int pos_reserved_as(int pos)
++{
++	if (smb_addr[pos*2+1] != 0)
++		return (smb_addr[pos*2] << 16) | smb_addr[pos*2+1];
++
++	return 0;
++}
++
++static struct i2c_driver smb_i2c_driver;
++
++static int smb_found_addr_proc(struct i2c_adapter *adapter, int addr,
++			       unsigned short flags, int kind)
++{
++	int id = i2c_adapter_id(adapter);
++	int debug = smb_dbg[id];
++	int rv;
++	int i;
++	int next_pos;
++	struct i2c_client client;
++	struct smb_info *smb_info;
++
++	if( id >= MAX_SMB_BMCS )
++		return 0;
++	memset(&client, 0, sizeof(client));
++	strcpy(client.name, "IPMI");
++	client.addr = addr;
++	client.adapter = adapter;
++	client.driver = &smb_i2c_driver;
++
++	rv = ipmi_smb_detect_hardware(&client, debug, &smb_info);
++	if (rv) {
++		if (smb_dbg_probe) {
++			printk(KERN_INFO
++			       "smb_found_addr_proc:No IPMI client 0x%x: %d\n",
++			       addr, rv);
++		}
++		return 0;
++	}
++
++	if (smb_dbg_probe) {
++		printk(KERN_INFO
++		       "smb_found_addr_proc: i2c_probe found device at"
++		       " i2c address %x\n", addr);
++	}
++
++	spin_lock_init(&(smb_info->msg_lock));
++	INIT_LIST_HEAD(&(smb_info->xmit_msgs));
++	INIT_LIST_HEAD(&(smb_info->hp_xmit_msgs));
++	smb_info->curr_msg = NULL;
++	atomic_set(&smb_info->req_events, 0);
++	smb_info->run_to_completion = 0;
++	smb_info->smb_state = SMB_NORMAL;
++
++	next_pos = -1;
++	for (i=0; i < MAX_SMB_BMCS; i++) {
++		unsigned int res = pos_reserved_as(i);
++
++		if (res == ((id << 16) | addr)) {
++			/* We have a reserved position, use it. */
++			next_pos = i;
++			break;
++		}
++
++		/* Claim the first unused position */
++		if (!res && (next_pos == -1) && (smb_infos[next_pos] == NULL))
++			next_pos = i;
++	}
++	if (next_pos == -1) {
++		rv = -EBUSY;
++		goto out_err;
++	}
++
++	rv = i2c_attach_client(&smb_info->client);
++	if (rv) {
++		printk(KERN_ERR
++		       "smb_found_one_addr_proc:"
++		       " Unable to attach i2c client: error %d\n",
++		       rv);
++		goto out_err;
++	}
++
++	if( adapter->inc_use != NULL )
++		(*adapter->inc_use)(adapter);
++
++	smb_info->pos = next_pos;
++	smb_infos[next_pos] = smb_info;
++
++#ifdef SMB_KTHREAD
++	start_kthread(smb_info);
++#endif
++
++#ifdef REGISTER_SMI
++	rv = ipmi_register_smi(&handlers,
++			       smb_info,
++			       smb_info->ipmi_version_major,
++			       smb_info->ipmi_version_minor,
++			       &(smb_info->intf));
++	if (rv) {
++		if( adapter->dec_use != NULL )
++			(*adapter->dec_use)(adapter);
++
++		i2c_detach_client(&smb_info->client);
++		smb_infos[next_pos] = NULL;
++		printk(KERN_ERR
++		       "ipmi_smb: Unable to register device: error %d\n",
++		       rv);
++		goto out_err;
++	}
++#endif
++
++	start_clear_flags(smb_info);
++	smb_event_handler(smb_info);
++
++	return addr;
++
++ out_err:
++	kfree(smb_info);
++	return 0;
++}
++
++static int attach_adapter(struct i2c_adapter *adapter)
++{
++	int id = i2c_adapter_id(adapter);
++
++	if (smb_dbg_probe) {
++		printk(KERN_INFO "smb_attach_adapter: Checking SMBus adapter %d:"
++		       " %s\n", id, adapter->name);
++	}
++	if ((i2c_get_functionality(adapter) & (I2C_FUNC_SMBUS_BLOCK_DATA))
++	    == (I2C_FUNC_SMBUS_BLOCK_DATA))
++	{
++		if (smb_addr[id*2+1] != 0) {
++			printk(KERN_INFO "smb_attach_adapter: probing i2c addr %02x\n",
++				smb_addr[id*2+1]);
++			normal_i2c[0] = smb_addr[id*2+1];
++		} else
++			normal_i2c[0] = I2C_CLIENT_END;
++		i2c_probe(adapter, &smb_address_data, smb_found_addr_proc);
++	}
++
++	return 0;
++}
++
++void cleanup_one_smb(struct smb_info *to_clean)
++{
++	int rv;
++
++	if (! to_clean)
++		return;
++
++#ifdef SMB_KTHREAD
++	stop_kthread(&to_clean->smb_thread);
++#endif
++
++#ifdef REGISTER_SMI
++	rv = ipmi_unregister_smi(to_clean->intf);
++	if (rv) {
++		printk(KERN_ERR
++		       "ipmi_smb: Unable to unregister device: errno=%d\n",
++		       rv);
++	}
++#endif
++
++	(*to_clean->client.adapter->dec_use)(to_clean->client.adapter);
++
++	rv = i2c_detach_client(&to_clean->client);
++	if (rv) {
++		printk(KERN_ERR
++		       "ipmi_smb: Unable to detach SMBUS client: errno=%d\n",
++		       rv);
++	}
++
++	smb_infos[to_clean->pos] = NULL;
++	kfree(to_clean);
++}
++
++static int detach_client(struct i2c_client *client)
++{
++	struct smb_info *smb_info = client->data;
++
++	cleanup_one_smb(smb_info);
++
++	return(0);
++}
++
++static struct i2c_driver smb_i2c_driver =
++{
++	.name = "IPMI",
++	.flags = I2C_DF_NOTIFY,
++	.attach_adapter = attach_adapter,
++	.detach_client = detach_client,
++	.command = NULL,
++	.inc_use = NULL,
++	.dec_use = NULL,
++};
++
++static __init int init_ipmi_smb(void)
++{
++	int i;
++	int rv;
++
++	if (initialized)
++		return 0;
++
++	printk(KERN_INFO "IPMI SMB Interface driver version "
++	       IPMI_SMB_VERSION "\n");
++
++	/* build force list from smb_addr list */
++	for (i=0; i<MAX_SMB_BMCS; i++) {
++		if (smb_addr[i*2+1] == 0)
++			break;
++		smb_force_list[i*FORCE_LIST_ENTRIES] = smb_addr[i*2];
++		smb_force_list[i*FORCE_LIST_ENTRIES+1] = smb_addr[i*2+1];
++	}
++	smb_force_list[i*FORCE_LIST_ENTRIES] = I2C_CLIENT_END;
++	smb_force_list[i*FORCE_LIST_ENTRIES+1] = I2C_CLIENT_END;
++
++	/* If the default probing is turned off, then disable the
++	 * range scanning. */
++	if (!smb_defaultprobe)
++		normal_i2c_range[0] = I2C_CLIENT_END;
++
++	rv = i2c_add_driver(&smb_i2c_driver);
++	if (!rv)
++		initialized = 1;
++
++	return rv;
++}
++module_init(init_ipmi_smb);
++
++#ifdef MODULE
++static __exit void cleanup_ipmi_smb(void)
++{
++	int i;
++	int rv;
++
++	if (!initialized)
++		return;
++
++	for (i=0; i<MAX_SMB_BMCS; i++) {
++		cleanup_one_smb(smb_infos[i]);
++	}
++
++	initialized = 0;
++
++	rv = i2c_del_driver(&smb_i2c_driver);
++	if (!rv)
++		initialized = 0;
++}
++module_exit(cleanup_ipmi_smb);
++#else
++
++/* [<adapter>.]addr[:debug]  Force a BMC at the given address on the
++			given adapter (or adapter 0 if not given).  If
++			the debug portion is given, this this is the
++			debug bits as explained in the definition of
++			smb_dbg above.
++   nodefaults		Suppress trying the default address range
++   debug_probe		Debug probing of adapters
++
++   For example, to pass one IO port with an IRQ, one address, and
++   suppress the use of the default IO port and ACPI address,
++   use this option string: ipmi_kcs=p0xCA2:5,m0xFF5B0022,nodefaults
++
++   Remember, ipmi_smb_setup() is passed the string after the equal sign. */
++
++static int __init ipmi_smb_setup(char *str)
++{
++	unsigned long val;
++	char *cur, *sep;
++	int pos;
++
++	pos = 0;
++
++	cur = strsep(&str, ",");
++	while ((cur) && (*cur) && (pos < MAX_SMB_BMCS)) {
++		if (strcmp(cur, "nodefaults") == 0) {
++			smb_defaultprobe = 0;
++			goto next_parm;
++		}
++		if (strcmp(cur, "debug_probe") == 0) {
++			smb_dbg_probe = 1;
++			goto next_parm;
++		}
++		val = simple_strtoul(cur,
++				     &sep,
++				     0);
++		if (*sep == '.') {
++			smb_addr[pos*2] = val;
++			val = simple_strtoul(sep + 1,
++					     &sep,
++					     0);
++		} else
++			smb_addr[pos*2] = 0;
++
++		smb_addr[pos*2+1] = val;
++
++		if (*sep == ':') {
++			val = simple_strtoul(sep + 1,
++					     &sep,
++					     0);
++			smb_dbg[pos] = val;
++		}
++		pos++;
++	next_parm:
++		cur = strsep(&str, ",");
++	}
++	return 1;
++}
++__setup("ipmi_smb=", ipmi_smb_setup);
++#endif
++
++MODULE_AUTHOR("Todd C Davis <todd.c.davis@intel.com>");
++MODULE_DESCRIPTION("IPMI system interface driver for management controllers on a SMBus");
++MODULE_LICENSE("GPL");
+Index: linux-ipmi/drivers/char/ipmi/Makefile
+===================================================================
+--- linux-ipmi.orig/drivers/char/ipmi/Makefile	2004-08-13 08:06:49.000000000 -0500
++++ linux-ipmi/drivers/char/ipmi/Makefile	2004-08-13 14:03:50.000000000 -0500
+@@ -14,6 +14,7 @@
+ obj-$(CONFIG_IPMI_DEVICE_INTERFACE) += ipmi_devintf.o
+ obj-$(CONFIG_IPMI_SI) += ipmi_si_drv.o
+ obj-$(CONFIG_IPMI_KCS) += ipmi_kcs_drv.o
++obj-$(CONFIG_IPMI_SMB) += ipmi_smb_intf.o
+ obj-$(CONFIG_IPMI_WATCHDOG) += ipmi_watchdog.o
+ obj-$(CONFIG_IPMI_POWEROFF) += ipmi_poweroff.o
+ 
+Index: linux-ipmi/drivers/i2c/i2c-core.c
+===================================================================
+--- linux-ipmi.orig/drivers/i2c/i2c-core.c	2004-08-13 08:05:34.000000000 -0500
++++ linux-ipmi/drivers/i2c/i2c-core.c	2004-08-13 08:06:50.000000000 -0500
+@@ -1347,6 +1347,11 @@
+ 
+ #endif
+ 
++int i2c_spin_delay;
++void i2c_set_spin_delay(int val)
++{
++	i2c_spin_delay = val;
++}
+ 
+ 
+ EXPORT_SYMBOL(i2c_add_adapter);
+@@ -1384,6 +1389,8 @@
+ 
+ EXPORT_SYMBOL(i2c_get_functionality);
+ EXPORT_SYMBOL(i2c_check_functionality);
++EXPORT_SYMBOL(i2c_set_spin_delay);
++EXPORT_SYMBOL(i2c_spin_delay);
+ 
+ #ifdef MODULE
+ MODULE_AUTHOR("Simon G. Vogl <simon@tk.uni-linz.ac.at>");
+Index: linux-ipmi/include/linux/i2c.h
+===================================================================
+--- linux-ipmi.orig/include/linux/i2c.h	2004-08-13 08:05:34.000000000 -0500
++++ linux-ipmi/include/linux/i2c.h	2004-08-13 08:06:50.000000000 -0500
+@@ -546,5 +546,24 @@
+ #define i2c_is_isa_adapter(adapptr) \
+         ((adapptr)->algo->id == I2C_ALGO_ISA)
+ 
++extern void i2c_set_spin_delay(int val);
++extern int i2c_spin_delay;
++#include <asm/delay.h>
++#include <linux/sched.h>
++static inline void i2c_delay(signed long timeout)
++{
++	if( i2c_spin_delay ) {
++		/* spin delay is needed for panic threads and
++		   shutdowns to avoid processing switching so IPMI
++		   messages can be sent to the Baseboard Management
++		   Controllers on the SMBus*/
++		int i;
++		for( i=0 ; i<100 ; i++ )
++			udelay(timeout*(1000000/HZ/100));
++	} else {
++		set_current_state(TASK_INTERRUPTIBLE);
++		schedule_timeout(timeout);
++	}
++}
+ #endif /* def __KERNEL__ */
+ #endif /* I2C_H */
