r1332 - in trunk: . linux

jim at linuxfromscratch.org jim at linuxfromscratch.org
Mon Jan 9 15:21:23 PST 2006


Author: jim
Date: 2006-01-09 16:21:14 -0700 (Mon, 09 Jan 2006)
New Revision: 1332

Added:
   trunk/linux/linux-2.6.15-mips-1.patch
Modified:
   trunk/
Log:
 r1652 at server:  jim | 2006-01-09 15:20:07 -0800
 Added: linux-2.6.15-mips-1.patch



Property changes on: trunk
___________________________________________________________________
Name: svk:merge
   - cc2644d5-6cf8-0310-b111-c40428001e49:/patches:1651
   + cc2644d5-6cf8-0310-b111-c40428001e49:/patches:1652

Added: trunk/linux/linux-2.6.15-mips-1.patch
===================================================================
--- trunk/linux/linux-2.6.15-mips-1.patch	2006-01-09 23:20:29 UTC (rev 1331)
+++ trunk/linux/linux-2.6.15-mips-1.patch	2006-01-09 23:21:14 UTC (rev 1332)
@@ -0,0 +1,24387 @@
+Submitted By: Jim Gifford (patches at jg555 dot com)
+Date: 2006-01-09
+Initial Package Version: 2.6.15
+Origin: Jim Gifford
+Upstream Status: Unknown
+Description: Merges Linux-MIPS and Kernel.org Tree's
+ 
+diff -Naur linux-2.6.15.orig/Documentation/mips/AU1xxx_IDE.README linux-2.6.15/Documentation/mips/AU1xxx_IDE.README
+--- linux-2.6.15.orig/Documentation/mips/AU1xxx_IDE.README	2006-01-03 03:21:10.000000000 +0000
++++ linux-2.6.15/Documentation/mips/AU1xxx_IDE.README	2006-01-09 19:54:12.000000000 +0000
+@@ -95,11 +95,13 @@
+ CONFIG_IDEDMA_PCI_AUTO=y
+ CONFIG_BLK_DEV_IDE_AU1XXX=y
+ CONFIG_BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA=y
+-CONFIG_BLK_DEV_IDE_AU1XXX_BURSTABLE_ON=y
+ CONFIG_BLK_DEV_IDE_AU1XXX_SEQTS_PER_RQ=128
+ CONFIG_BLK_DEV_IDEDMA=y
+ CONFIG_IDEDMA_AUTO=y
+ 
++Also define 'IDE_AU1XXX_BURSTMODE' in 'drivers/ide/mips/au1xxx-ide.c' to enable
++the burst support on DBDMA controller.
++ 
+ If the used system need the USB support enable the following kernel configs for
+ high IDE to USB throughput.
+ 
+@@ -115,6 +117,8 @@
+ CONFIG_BLK_DEV_IDEDMA=y
+ CONFIG_IDEDMA_AUTO=y
+ 
++Also undefine 'IDE_AU1XXX_BURSTMODE' in 'drivers/ide/mips/au1xxx-ide.c' to 
++disable the burst support on DBDMA controller.
+ 
+ ADD NEW HARD DISC TO WHITE OR BLACK LIST
+ ----------------------------------------
+diff -Naur linux-2.6.15.orig/Makefile linux-2.6.15/Makefile
+--- linux-2.6.15.orig/Makefile	2006-01-03 03:21:10.000000000 +0000
++++ linux-2.6.15/Makefile	2006-01-09 19:55:01.000000000 +0000
+@@ -169,7 +169,7 @@
+ SUBARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ \
+ 				  -e s/arm.*/arm/ -e s/sa110/arm/ \
+ 				  -e s/s390x/s390/ -e s/parisc64/parisc/ \
+-				  -e s/ppc64/powerpc/ )
++				  -e s/mips64/mips/ -e s/ppc64/powerpc/ )
+ 
+ # Cross compiling and selecting different set of gcc/bin-utils
+ # ---------------------------------------------------------------------------
+diff -Naur linux-2.6.15.orig/arch/mips/Kconfig linux-2.6.15/arch/mips/Kconfig
+--- linux-2.6.15.orig/arch/mips/Kconfig	2006-01-03 03:21:10.000000000 +0000
++++ linux-2.6.15/arch/mips/Kconfig	2006-01-09 19:54:12.000000000 +0000
+@@ -503,10 +503,7 @@
+ 	  ether port USB, AC97, PCI, etc.
+ 
+ config MACH_VR41XX
+-	bool "Support for NEC VR4100 series based machines"
+-	select SYS_HAS_CPU_VR41XX
+-	select SYS_SUPPORTS_32BIT_KERNEL
+-	select SYS_SUPPORTS_64BIT_KERNEL if EXPERIMENTAL
++	bool "Support for NEC VR41XX-based machines"
+ 
+ config PMC_YOSEMITE
+ 	bool "Support for PMC-Sierra Yosemite eval board"
+@@ -1018,6 +1015,9 @@
+ config HAVE_STD_PC_SERIAL_PORT
+ 	bool
+ 
++config VR4181
++	bool
++
+ config ARC_CONSOLE
+ 	bool "ARC console support"
+ 	depends on SGI_IP22 || SNI_RM200_PCI
+@@ -1129,7 +1129,7 @@
+ 	select CPU_SUPPORTS_32BIT_KERNEL
+ 	select CPU_SUPPORTS_64BIT_KERNEL
+ 	help
+-	  The options selects support for the NEC VR4100 series of processors.
++	  The options selects support for the NEC VR41xx series of processors.
+ 	  Only choose this option if you have one of these processors as a
+ 	  kernel built with this option will not run on any other type of
+ 	  processor or vice versa.
+@@ -1471,7 +1471,7 @@
+ 
+ config 64BIT_PHYS_ADDR
+ 	bool "Support for 64-bit physical address space"
+-	depends on (CPU_R4X00 || CPU_R5000 || CPU_RM7000 || CPU_RM9000 || CPU_R10000 || CPU_SB1 || CPU_MIPS32_R1 || CPU_MIPS64_R1) && 32BIT
++	depends on (CPU_R4X00 || CPU_R5000 || CPU_RM7000 || CPU_RM9000 || CPU_R10000 || CPU_SB1 || CPU_MIPS32 || CPU_MIPS64) && 32BIT
+ 
+ config CPU_ADVANCED
+ 	bool "Override CPU Options"
+@@ -1492,14 +1492,6 @@
+ 	  for better performance, N if you don't know.  You must say Y here
+ 	  for multiprocessor machines.
+ 
+-config CPU_HAS_LLDSCD
+-	bool "lld/scd Instructions available" if CPU_ADVANCED
+-	default y if !CPU_ADVANCED && !CPU_R3000 && !CPU_VR41XX && !CPU_TX39XX && !CPU_MIPS32_R1
+-	help
+-	  Say Y here if your CPU has the lld and scd instructions, the 64-bit
+-	  equivalents of ll and sc.  Say Y here for better performance, N if
+-	  you don't know.  You must say Y here for multiprocessor machines.
+-
+ config CPU_HAS_WB
+ 	bool "Writeback Buffer available" if CPU_ADVANCED
+ 	default y if !CPU_ADVANCED && CPU_R3000 && MACH_DECSTATION
+diff -Naur linux-2.6.15.orig/arch/mips/Makefile linux-2.6.15/arch/mips/Makefile
+--- linux-2.6.15.orig/arch/mips/Makefile	2006-01-03 03:21:10.000000000 +0000
++++ linux-2.6.15/arch/mips/Makefile	2006-01-09 19:54:12.000000000 +0000
+@@ -93,7 +93,6 @@
+ #
+ cflags-y			+= -I $(TOPDIR)/include/asm/gcc
+ cflags-y			+= -G 0 -mno-abicalls -fno-pic -pipe
+-cflags-y			+= $(call cc-option, -finline-limit=100000)
+ LDFLAGS_vmlinux			+= -G 0 -static -n -nostdlib
+ MODFLAGS			+= -mlong-calls
+ 
+@@ -106,7 +105,8 @@
+ cflags-$(CONFIG_CPU_BIG_ENDIAN)		+= $(shell $(CC) -dumpmachine |grep -q 'mips.*el-.*' && echo -EB)
+ cflags-$(CONFIG_CPU_LITTLE_ENDIAN)	+= $(shell $(CC) -dumpmachine |grep -q 'mips.*el-.*' || echo -EL)
+ 
+-cflags-$(CONFIG_SB1XXX_CORELIS)	+= -mno-sched-prolog -fno-omit-frame-pointer
++cflags-$(CONFIG_SB1XXX_CORELIS)	+= $(call cc-option,-mno-sched-prolog) \
++				   -fno-omit-frame-pointer
+ 
+ #
+ # Use: $(call set_gccflags,<cpu0>,<isa0>,<cpu1>,<isa1>,<isa2>)
+@@ -478,6 +478,7 @@
+ cflags-$(CONFIG_PMC_YOSEMITE)	+= -Iinclude/asm-mips/mach-yosemite
+ load-$(CONFIG_PMC_YOSEMITE)	+= 0xffffffff80100000
+ 
++#
+ # Qemu simulating MIPS32 4Kc
+ #
+ core-$(CONFIG_QEMU)		+= arch/mips/qemu/
+@@ -564,7 +565,7 @@
+ load-$(CONFIG_CASIO_E55)	+= 0xffffffff80004000
+ 
+ #
+-# TANBAC VR4131 multichip module(TB0225) and TANBAC VR4131DIMM(TB0229) (VR4131)
++# TANBAC TB0225 VR4131 Multi-chip module/TB0229 VR4131DIMM (VR4131)
+ #
+ load-$(CONFIG_TANBAC_TB022X)	+= 0xffffffff80000000
+ 
+@@ -762,7 +763,7 @@
+ 
+ ifdef CONFIG_LASAT
+ rom.bin rom.sw: vmlinux
+-	$(Q)$(MAKE) $(build)=arch/mips/lasat/image $@
++	$(call descend,arch/mips/lasat/image,$@)
+ endif
+ 
+ #
+diff -Naur linux-2.6.15.orig/arch/mips/configs/atlas_defconfig linux-2.6.15/arch/mips/configs/atlas_defconfig
+--- linux-2.6.15.orig/arch/mips/configs/atlas_defconfig	2006-01-03 03:21:10.000000000 +0000
++++ linux-2.6.15/arch/mips/configs/atlas_defconfig	2006-01-09 19:54:12.000000000 +0000
+@@ -1,7 +1,7 @@
+ #
+ # Automatically generated make config: don't edit
+-# Linux kernel version: 2.6.15-rc2
+-# Thu Nov 24 01:05:52 2005
++# Linux kernel version: 2.6.15-rc5
++# Sat Dec 17 18:02:16 2005
+ #
+ CONFIG_MIPS=y
+ 
+@@ -168,6 +168,7 @@
+ CONFIG_KOBJECT_UEVENT=y
+ # CONFIG_IKCONFIG is not set
+ CONFIG_INITRAMFS_SOURCE=""
++# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+ CONFIG_EMBEDDED=y
+ CONFIG_KALLSYMS=y
+ # CONFIG_KALLSYMS_EXTRA_PASS is not set
+@@ -176,7 +177,6 @@
+ CONFIG_BASE_FULL=y
+ CONFIG_FUTEX=y
+ CONFIG_EPOLL=y
+-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+ CONFIG_SHMEM=y
+ CONFIG_CC_ALIGN_FUNCTIONS=0
+ CONFIG_CC_ALIGN_LABELS=0
+@@ -553,7 +553,6 @@
+ # CONFIG_IEEE80211_DEBUG is not set
+ CONFIG_IEEE80211_CRYPT_WEP=m
+ CONFIG_IEEE80211_CRYPT_CCMP=m
+-CONFIG_IEEE80211_CRYPT_TKIP=m
+ 
+ #
+ # Device Drivers
+diff -Naur linux-2.6.15.orig/arch/mips/configs/bigsur_defconfig linux-2.6.15/arch/mips/configs/bigsur_defconfig
+--- linux-2.6.15.orig/arch/mips/configs/bigsur_defconfig	2006-01-03 03:21:10.000000000 +0000
++++ linux-2.6.15/arch/mips/configs/bigsur_defconfig	2006-01-09 19:54:12.000000000 +0000
+@@ -1,7 +1,7 @@
+ #
+ # Automatically generated make config: don't edit
+-# Linux kernel version: 2.6.15-rc2
+-# Thu Nov 24 01:05:54 2005
++# Linux kernel version: 2.6.15-rc5
++# Sat Dec 17 18:02:20 2005
+ #
+ CONFIG_MIPS=y
+ 
+@@ -130,7 +130,6 @@
+ # CONFIG_SIBYTE_DMA_PAGEOPS is not set
+ # CONFIG_MIPS_MT is not set
+ CONFIG_CPU_HAS_LLSC=y
+-CONFIG_CPU_HAS_LLDSCD=y
+ CONFIG_CPU_HAS_SYNC=y
+ CONFIG_GENERIC_HARDIRQS=y
+ CONFIG_GENERIC_IRQ_PROBE=y
+@@ -176,6 +175,7 @@
+ CONFIG_IKCONFIG_PROC=y
+ # CONFIG_CPUSETS is not set
+ CONFIG_INITRAMFS_SOURCE=""
++# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+ CONFIG_EMBEDDED=y
+ CONFIG_KALLSYMS=y
+ # CONFIG_KALLSYMS_ALL is not set
+@@ -185,7 +185,6 @@
+ CONFIG_BASE_FULL=y
+ CONFIG_FUTEX=y
+ CONFIG_EPOLL=y
+-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+ CONFIG_SHMEM=y
+ CONFIG_CC_ALIGN_FUNCTIONS=0
+ CONFIG_CC_ALIGN_LABELS=0
+diff -Naur linux-2.6.15.orig/arch/mips/configs/capcella_defconfig linux-2.6.15/arch/mips/configs/capcella_defconfig
+--- linux-2.6.15.orig/arch/mips/configs/capcella_defconfig	2006-01-03 03:21:10.000000000 +0000
++++ linux-2.6.15/arch/mips/configs/capcella_defconfig	2006-01-09 19:54:12.000000000 +0000
+@@ -1,7 +1,7 @@
+ #
+ # Automatically generated make config: don't edit
+-# Linux kernel version: 2.6.15-rc2
+-# Thu Nov 24 01:05:55 2005
++# Linux kernel version: 2.6.15-rc5
++# Sat Dec 17 18:02:23 2005
+ #
+ CONFIG_MIPS=y
+ 
+@@ -159,6 +159,7 @@
+ CONFIG_KOBJECT_UEVENT=y
+ # CONFIG_IKCONFIG is not set
+ CONFIG_INITRAMFS_SOURCE=""
++# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+ CONFIG_EMBEDDED=y
+ CONFIG_KALLSYMS=y
+ # CONFIG_KALLSYMS_EXTRA_PASS is not set
+@@ -167,7 +168,6 @@
+ CONFIG_BASE_FULL=y
+ CONFIG_FUTEX=y
+ CONFIG_EPOLL=y
+-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+ CONFIG_SHMEM=y
+ CONFIG_CC_ALIGN_FUNCTIONS=0
+ CONFIG_CC_ALIGN_LABELS=0
+@@ -306,7 +306,6 @@
+ # CONFIG_IEEE80211_DEBUG is not set
+ CONFIG_IEEE80211_CRYPT_WEP=m
+ CONFIG_IEEE80211_CRYPT_CCMP=m
+-CONFIG_IEEE80211_CRYPT_TKIP=m
+ 
+ #
+ # Device Drivers
+diff -Naur linux-2.6.15.orig/arch/mips/configs/cobalt_defconfig linux-2.6.15/arch/mips/configs/cobalt_defconfig
+--- linux-2.6.15.orig/arch/mips/configs/cobalt_defconfig	2006-01-03 03:21:10.000000000 +0000
++++ linux-2.6.15/arch/mips/configs/cobalt_defconfig	2006-01-09 19:54:12.000000000 +0000
+@@ -1,7 +1,7 @@
+ #
+ # Automatically generated make config: don't edit
+-# Linux kernel version: 2.6.15-rc2
+-# Thu Nov 24 01:05:57 2005
++# Linux kernel version: 2.6.15-rc5
++# Sat Dec 17 18:02:25 2005
+ #
+ CONFIG_MIPS=y
+ 
+@@ -115,7 +115,6 @@
+ # CONFIG_MIPS_MT is not set
+ # CONFIG_CPU_ADVANCED is not set
+ CONFIG_CPU_HAS_LLSC=y
+-CONFIG_CPU_HAS_LLDSCD=y
+ CONFIG_CPU_HAS_SYNC=y
+ CONFIG_GENERIC_HARDIRQS=y
+ CONFIG_GENERIC_IRQ_PROBE=y
+@@ -155,6 +154,7 @@
+ CONFIG_KOBJECT_UEVENT=y
+ # CONFIG_IKCONFIG is not set
+ CONFIG_INITRAMFS_SOURCE=""
++# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+ CONFIG_EMBEDDED=y
+ CONFIG_KALLSYMS=y
+ # CONFIG_KALLSYMS_EXTRA_PASS is not set
+@@ -163,7 +163,6 @@
+ CONFIG_BASE_FULL=y
+ CONFIG_FUTEX=y
+ CONFIG_EPOLL=y
+-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+ CONFIG_SHMEM=y
+ CONFIG_CC_ALIGN_FUNCTIONS=0
+ CONFIG_CC_ALIGN_LABELS=0
+@@ -292,7 +291,6 @@
+ # CONFIG_IEEE80211_DEBUG is not set
+ CONFIG_IEEE80211_CRYPT_WEP=y
+ CONFIG_IEEE80211_CRYPT_CCMP=y
+-CONFIG_IEEE80211_CRYPT_TKIP=y
+ 
+ #
+ # Device Drivers
+diff -Naur linux-2.6.15.orig/arch/mips/configs/db1000_defconfig linux-2.6.15/arch/mips/configs/db1000_defconfig
+--- linux-2.6.15.orig/arch/mips/configs/db1000_defconfig	2006-01-03 03:21:10.000000000 +0000
++++ linux-2.6.15/arch/mips/configs/db1000_defconfig	2006-01-09 19:54:12.000000000 +0000
+@@ -1,7 +1,7 @@
+ #
+ # Automatically generated make config: don't edit
+-# Linux kernel version: 2.6.15-rc2
+-# Thu Nov 24 01:05:59 2005
++# Linux kernel version: 2.6.15-rc5
++# Sat Dec 17 18:02:27 2005
+ #
+ CONFIG_MIPS=y
+ 
+@@ -155,6 +155,7 @@
+ CONFIG_KOBJECT_UEVENT=y
+ # CONFIG_IKCONFIG is not set
+ CONFIG_INITRAMFS_SOURCE=""
++# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+ CONFIG_EMBEDDED=y
+ CONFIG_KALLSYMS=y
+ # CONFIG_KALLSYMS_EXTRA_PASS is not set
+@@ -163,7 +164,6 @@
+ CONFIG_BASE_FULL=y
+ CONFIG_FUTEX=y
+ CONFIG_EPOLL=y
+-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+ CONFIG_SHMEM=y
+ CONFIG_CC_ALIGN_FUNCTIONS=0
+ CONFIG_CC_ALIGN_LABELS=0
+@@ -332,7 +332,6 @@
+ # CONFIG_IEEE80211_DEBUG is not set
+ CONFIG_IEEE80211_CRYPT_WEP=m
+ CONFIG_IEEE80211_CRYPT_CCMP=m
+-CONFIG_IEEE80211_CRYPT_TKIP=m
+ 
+ #
+ # Device Drivers
+diff -Naur linux-2.6.15.orig/arch/mips/configs/db1100_defconfig linux-2.6.15/arch/mips/configs/db1100_defconfig
+--- linux-2.6.15.orig/arch/mips/configs/db1100_defconfig	2006-01-03 03:21:10.000000000 +0000
++++ linux-2.6.15/arch/mips/configs/db1100_defconfig	2006-01-09 19:54:12.000000000 +0000
+@@ -1,7 +1,7 @@
+ #
+ # Automatically generated make config: don't edit
+-# Linux kernel version: 2.6.15-rc2
+-# Thu Nov 24 01:06:00 2005
++# Linux kernel version: 2.6.15-rc5
++# Sat Dec 17 18:02:30 2005
+ #
+ CONFIG_MIPS=y
+ 
+@@ -155,6 +155,7 @@
+ CONFIG_KOBJECT_UEVENT=y
+ # CONFIG_IKCONFIG is not set
+ CONFIG_INITRAMFS_SOURCE=""
++# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+ CONFIG_EMBEDDED=y
+ CONFIG_KALLSYMS=y
+ # CONFIG_KALLSYMS_EXTRA_PASS is not set
+@@ -163,7 +164,6 @@
+ CONFIG_BASE_FULL=y
+ CONFIG_FUTEX=y
+ CONFIG_EPOLL=y
+-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+ CONFIG_SHMEM=y
+ CONFIG_CC_ALIGN_FUNCTIONS=0
+ CONFIG_CC_ALIGN_LABELS=0
+@@ -321,7 +321,6 @@
+ # CONFIG_IEEE80211_DEBUG is not set
+ CONFIG_IEEE80211_CRYPT_WEP=m
+ CONFIG_IEEE80211_CRYPT_CCMP=m
+-CONFIG_IEEE80211_CRYPT_TKIP=m
+ 
+ #
+ # Device Drivers
+diff -Naur linux-2.6.15.orig/arch/mips/configs/db1200_defconfig linux-2.6.15/arch/mips/configs/db1200_defconfig
+--- linux-2.6.15.orig/arch/mips/configs/db1200_defconfig	2006-01-03 03:21:10.000000000 +0000
++++ linux-2.6.15/arch/mips/configs/db1200_defconfig	2006-01-09 19:54:12.000000000 +0000
+@@ -1,7 +1,7 @@
+ #
+ # Automatically generated make config: don't edit
+-# Linux kernel version: 2.6.15-rc2
+-# Thu Nov 24 01:06:03 2005
++# Linux kernel version: 2.6.15-rc5
++# Sat Dec 17 18:02:32 2005
+ #
+ CONFIG_MIPS=y
+ 
+@@ -156,6 +156,7 @@
+ CONFIG_IKCONFIG=y
+ CONFIG_IKCONFIG_PROC=y
+ CONFIG_INITRAMFS_SOURCE=""
++# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+ CONFIG_EMBEDDED=y
+ CONFIG_KALLSYMS=y
+ # CONFIG_KALLSYMS_EXTRA_PASS is not set
+@@ -164,7 +165,6 @@
+ CONFIG_BASE_FULL=y
+ CONFIG_FUTEX=y
+ CONFIG_EPOLL=y
+-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+ CONFIG_SHMEM=y
+ CONFIG_CC_ALIGN_FUNCTIONS=0
+ CONFIG_CC_ALIGN_LABELS=0
+diff -Naur linux-2.6.15.orig/arch/mips/configs/db1500_defconfig linux-2.6.15/arch/mips/configs/db1500_defconfig
+--- linux-2.6.15.orig/arch/mips/configs/db1500_defconfig	2006-01-03 03:21:10.000000000 +0000
++++ linux-2.6.15/arch/mips/configs/db1500_defconfig	2006-01-09 19:54:12.000000000 +0000
+@@ -1,7 +1,7 @@
+ #
+ # Automatically generated make config: don't edit
+-# Linux kernel version: 2.6.15-rc2
+-# Thu Nov 24 01:06:05 2005
++# Linux kernel version: 2.6.15-rc5
++# Sat Dec 17 18:02:35 2005
+ #
+ CONFIG_MIPS=y
+ 
+@@ -157,6 +157,7 @@
+ CONFIG_KOBJECT_UEVENT=y
+ # CONFIG_IKCONFIG is not set
+ CONFIG_INITRAMFS_SOURCE=""
++# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+ CONFIG_EMBEDDED=y
+ CONFIG_KALLSYMS=y
+ # CONFIG_KALLSYMS_EXTRA_PASS is not set
+@@ -165,7 +166,6 @@
+ CONFIG_BASE_FULL=y
+ CONFIG_FUTEX=y
+ CONFIG_EPOLL=y
+-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+ CONFIG_SHMEM=y
+ CONFIG_CC_ALIGN_FUNCTIONS=0
+ CONFIG_CC_ALIGN_LABELS=0
+@@ -340,7 +340,6 @@
+ # CONFIG_IEEE80211_DEBUG is not set
+ CONFIG_IEEE80211_CRYPT_WEP=m
+ CONFIG_IEEE80211_CRYPT_CCMP=m
+-CONFIG_IEEE80211_CRYPT_TKIP=m
+ 
+ #
+ # Device Drivers
+diff -Naur linux-2.6.15.orig/arch/mips/configs/db1550_defconfig linux-2.6.15/arch/mips/configs/db1550_defconfig
+--- linux-2.6.15.orig/arch/mips/configs/db1550_defconfig	2006-01-03 03:21:10.000000000 +0000
++++ linux-2.6.15/arch/mips/configs/db1550_defconfig	2006-01-09 19:54:12.000000000 +0000
+@@ -1,7 +1,7 @@
+ #
+ # Automatically generated make config: don't edit
+-# Linux kernel version: 2.6.15-rc2
+-# Thu Nov 24 01:06:07 2005
++# Linux kernel version: 2.6.15-rc5
++# Sat Dec 17 18:02:38 2005
+ #
+ CONFIG_MIPS=y
+ 
+@@ -156,6 +156,7 @@
+ CONFIG_KOBJECT_UEVENT=y
+ # CONFIG_IKCONFIG is not set
+ CONFIG_INITRAMFS_SOURCE=""
++# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+ CONFIG_EMBEDDED=y
+ CONFIG_KALLSYMS=y
+ # CONFIG_KALLSYMS_EXTRA_PASS is not set
+@@ -164,7 +165,6 @@
+ CONFIG_BASE_FULL=y
+ CONFIG_FUTEX=y
+ CONFIG_EPOLL=y
+-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+ CONFIG_SHMEM=y
+ CONFIG_CC_ALIGN_FUNCTIONS=0
+ CONFIG_CC_ALIGN_LABELS=0
+@@ -339,7 +339,6 @@
+ # CONFIG_IEEE80211_DEBUG is not set
+ CONFIG_IEEE80211_CRYPT_WEP=m
+ CONFIG_IEEE80211_CRYPT_CCMP=m
+-CONFIG_IEEE80211_CRYPT_TKIP=m
+ 
+ #
+ # Device Drivers
+diff -Naur linux-2.6.15.orig/arch/mips/configs/ddb5476_defconfig linux-2.6.15/arch/mips/configs/ddb5476_defconfig
+--- linux-2.6.15.orig/arch/mips/configs/ddb5476_defconfig	2006-01-03 03:21:10.000000000 +0000
++++ linux-2.6.15/arch/mips/configs/ddb5476_defconfig	2006-01-09 19:54:12.000000000 +0000
+@@ -1,7 +1,7 @@
+ #
+ # Automatically generated make config: don't edit
+-# Linux kernel version: 2.6.15-rc2
+-# Thu Nov 24 01:06:09 2005
++# Linux kernel version: 2.6.15-rc5
++# Sat Dec 17 18:02:40 2005
+ #
+ CONFIG_MIPS=y
+ 
+@@ -116,7 +116,6 @@
+ # CONFIG_MIPS_MT is not set
+ # CONFIG_CPU_ADVANCED is not set
+ CONFIG_CPU_HAS_LLSC=y
+-CONFIG_CPU_HAS_LLDSCD=y
+ CONFIG_CPU_HAS_SYNC=y
+ CONFIG_GENERIC_HARDIRQS=y
+ CONFIG_GENERIC_IRQ_PROBE=y
+@@ -156,6 +155,7 @@
+ CONFIG_KOBJECT_UEVENT=y
+ # CONFIG_IKCONFIG is not set
+ CONFIG_INITRAMFS_SOURCE=""
++# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+ CONFIG_EMBEDDED=y
+ CONFIG_KALLSYMS=y
+ # CONFIG_KALLSYMS_EXTRA_PASS is not set
+@@ -164,7 +164,6 @@
+ CONFIG_BASE_FULL=y
+ CONFIG_FUTEX=y
+ CONFIG_EPOLL=y
+-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+ CONFIG_SHMEM=y
+ CONFIG_CC_ALIGN_FUNCTIONS=0
+ CONFIG_CC_ALIGN_LABELS=0
+@@ -297,7 +296,6 @@
+ # CONFIG_IEEE80211_DEBUG is not set
+ CONFIG_IEEE80211_CRYPT_WEP=y
+ CONFIG_IEEE80211_CRYPT_CCMP=y
+-CONFIG_IEEE80211_CRYPT_TKIP=y
+ 
+ #
+ # Device Drivers
+diff -Naur linux-2.6.15.orig/arch/mips/configs/ddb5477_defconfig linux-2.6.15/arch/mips/configs/ddb5477_defconfig
+--- linux-2.6.15.orig/arch/mips/configs/ddb5477_defconfig	2006-01-03 03:21:10.000000000 +0000
++++ linux-2.6.15/arch/mips/configs/ddb5477_defconfig	2006-01-09 19:54:12.000000000 +0000
+@@ -1,7 +1,7 @@
+ #
+ # Automatically generated make config: don't edit
+-# Linux kernel version: 2.6.15-rc2
+-# Thu Nov 24 01:06:11 2005
++# Linux kernel version: 2.6.15-rc5
++# Sat Dec 17 18:02:42 2005
+ #
+ CONFIG_MIPS=y
+ 
+@@ -116,7 +116,6 @@
+ # CONFIG_MIPS_MT is not set
+ # CONFIG_CPU_ADVANCED is not set
+ CONFIG_CPU_HAS_LLSC=y
+-CONFIG_CPU_HAS_LLDSCD=y
+ CONFIG_CPU_HAS_SYNC=y
+ CONFIG_GENERIC_HARDIRQS=y
+ CONFIG_GENERIC_IRQ_PROBE=y
+@@ -156,6 +155,7 @@
+ CONFIG_KOBJECT_UEVENT=y
+ # CONFIG_IKCONFIG is not set
+ CONFIG_INITRAMFS_SOURCE=""
++# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+ CONFIG_EMBEDDED=y
+ CONFIG_KALLSYMS=y
+ # CONFIG_KALLSYMS_EXTRA_PASS is not set
+@@ -164,7 +164,6 @@
+ CONFIG_BASE_FULL=y
+ CONFIG_FUTEX=y
+ CONFIG_EPOLL=y
+-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+ CONFIG_SHMEM=y
+ CONFIG_CC_ALIGN_FUNCTIONS=0
+ CONFIG_CC_ALIGN_LABELS=0
+@@ -296,7 +295,6 @@
+ # CONFIG_IEEE80211_DEBUG is not set
+ CONFIG_IEEE80211_CRYPT_WEP=y
+ CONFIG_IEEE80211_CRYPT_CCMP=y
+-CONFIG_IEEE80211_CRYPT_TKIP=y
+ 
+ #
+ # Device Drivers
+diff -Naur linux-2.6.15.orig/arch/mips/configs/decstation_defconfig linux-2.6.15/arch/mips/configs/decstation_defconfig
+--- linux-2.6.15.orig/arch/mips/configs/decstation_defconfig	2006-01-03 03:21:10.000000000 +0000
++++ linux-2.6.15/arch/mips/configs/decstation_defconfig	2006-01-09 19:54:12.000000000 +0000
+@@ -1,7 +1,7 @@
+ #
+ # Automatically generated make config: don't edit
+-# Linux kernel version: 2.6.15-rc2
+-# Thu Nov 24 01:06:13 2005
++# Linux kernel version: 2.6.15-rc5
++# Sat Dec 17 18:02:44 2005
+ #
+ CONFIG_MIPS=y
+ 
+@@ -154,6 +154,7 @@
+ CONFIG_KOBJECT_UEVENT=y
+ # CONFIG_IKCONFIG is not set
+ CONFIG_INITRAMFS_SOURCE=""
++# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+ CONFIG_EMBEDDED=y
+ CONFIG_KALLSYMS=y
+ # CONFIG_KALLSYMS_ALL is not set
+@@ -163,7 +164,6 @@
+ CONFIG_BASE_FULL=y
+ CONFIG_FUTEX=y
+ CONFIG_EPOLL=y
+-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+ CONFIG_SHMEM=y
+ CONFIG_CC_ALIGN_FUNCTIONS=0
+ CONFIG_CC_ALIGN_LABELS=0
+@@ -298,7 +298,6 @@
+ # CONFIG_IEEE80211_DEBUG is not set
+ CONFIG_IEEE80211_CRYPT_WEP=m
+ CONFIG_IEEE80211_CRYPT_CCMP=m
+-CONFIG_IEEE80211_CRYPT_TKIP=m
+ 
+ #
+ # Device Drivers
+diff -Naur linux-2.6.15.orig/arch/mips/configs/e55_defconfig linux-2.6.15/arch/mips/configs/e55_defconfig
+--- linux-2.6.15.orig/arch/mips/configs/e55_defconfig	2006-01-03 03:21:10.000000000 +0000
++++ linux-2.6.15/arch/mips/configs/e55_defconfig	2006-01-09 19:54:12.000000000 +0000
+@@ -1,7 +1,7 @@
+ #
+ # Automatically generated make config: don't edit
+-# Linux kernel version: 2.6.15-rc2
+-# Thu Nov 24 01:06:14 2005
++# Linux kernel version: 2.6.15-rc5
++# Sat Dec 17 18:02:46 2005
+ #
+ CONFIG_MIPS=y
+ 
+@@ -157,6 +157,7 @@
+ CONFIG_KOBJECT_UEVENT=y
+ # CONFIG_IKCONFIG is not set
+ CONFIG_INITRAMFS_SOURCE=""
++# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+ CONFIG_EMBEDDED=y
+ CONFIG_KALLSYMS=y
+ # CONFIG_KALLSYMS_EXTRA_PASS is not set
+@@ -165,7 +166,6 @@
+ CONFIG_BASE_FULL=y
+ CONFIG_FUTEX=y
+ CONFIG_EPOLL=y
+-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+ CONFIG_SHMEM=y
+ CONFIG_CC_ALIGN_FUNCTIONS=0
+ CONFIG_CC_ALIGN_LABELS=0
+@@ -298,7 +298,6 @@
+ # CONFIG_IEEE80211_DEBUG is not set
+ CONFIG_IEEE80211_CRYPT_WEP=m
+ CONFIG_IEEE80211_CRYPT_CCMP=m
+-CONFIG_IEEE80211_CRYPT_TKIP=m
+ 
+ #
+ # Device Drivers
+diff -Naur linux-2.6.15.orig/arch/mips/configs/ev64120_defconfig linux-2.6.15/arch/mips/configs/ev64120_defconfig
+--- linux-2.6.15.orig/arch/mips/configs/ev64120_defconfig	2006-01-03 03:21:10.000000000 +0000
++++ linux-2.6.15/arch/mips/configs/ev64120_defconfig	2006-01-09 19:54:12.000000000 +0000
+@@ -1,7 +1,7 @@
+ #
+ # Automatically generated make config: don't edit
+-# Linux kernel version: 2.6.15-rc2
+-# Thu Nov 24 01:06:16 2005
++# Linux kernel version: 2.6.15-rc5
++# Sat Dec 17 18:02:48 2005
+ #
+ CONFIG_MIPS=y
+ 
+@@ -118,7 +118,6 @@
+ # CONFIG_64BIT_PHYS_ADDR is not set
+ # CONFIG_CPU_ADVANCED is not set
+ CONFIG_CPU_HAS_LLSC=y
+-CONFIG_CPU_HAS_LLDSCD=y
+ CONFIG_CPU_HAS_SYNC=y
+ CONFIG_GENERIC_HARDIRQS=y
+ CONFIG_GENERIC_IRQ_PROBE=y
+@@ -158,6 +157,7 @@
+ CONFIG_KOBJECT_UEVENT=y
+ # CONFIG_IKCONFIG is not set
+ CONFIG_INITRAMFS_SOURCE=""
++# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+ CONFIG_EMBEDDED=y
+ CONFIG_KALLSYMS=y
+ # CONFIG_KALLSYMS_EXTRA_PASS is not set
+@@ -166,7 +166,6 @@
+ CONFIG_BASE_FULL=y
+ CONFIG_FUTEX=y
+ CONFIG_EPOLL=y
+-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+ CONFIG_SHMEM=y
+ CONFIG_CC_ALIGN_FUNCTIONS=0
+ CONFIG_CC_ALIGN_LABELS=0
+@@ -303,7 +302,6 @@
+ # CONFIG_IEEE80211_DEBUG is not set
+ CONFIG_IEEE80211_CRYPT_WEP=m
+ CONFIG_IEEE80211_CRYPT_CCMP=m
+-CONFIG_IEEE80211_CRYPT_TKIP=m
+ 
+ #
+ # Device Drivers
+diff -Naur linux-2.6.15.orig/arch/mips/configs/ev96100_defconfig linux-2.6.15/arch/mips/configs/ev96100_defconfig
+--- linux-2.6.15.orig/arch/mips/configs/ev96100_defconfig	2006-01-03 03:21:10.000000000 +0000
++++ linux-2.6.15/arch/mips/configs/ev96100_defconfig	2006-01-09 19:54:12.000000000 +0000
+@@ -1,7 +1,7 @@
+ #
+ # Automatically generated make config: don't edit
+-# Linux kernel version: 2.6.15-rc2
+-# Thu Nov 24 01:06:18 2005
++# Linux kernel version: 2.6.15-rc5
++# Sat Dec 17 18:02:50 2005
+ #
+ CONFIG_MIPS=y
+ 
+@@ -121,7 +121,6 @@
+ # CONFIG_64BIT_PHYS_ADDR is not set
+ # CONFIG_CPU_ADVANCED is not set
+ CONFIG_CPU_HAS_LLSC=y
+-CONFIG_CPU_HAS_LLDSCD=y
+ CONFIG_CPU_HAS_SYNC=y
+ CONFIG_GENERIC_HARDIRQS=y
+ CONFIG_GENERIC_IRQ_PROBE=y
+@@ -162,6 +161,7 @@
+ CONFIG_KOBJECT_UEVENT=y
+ # CONFIG_IKCONFIG is not set
+ CONFIG_INITRAMFS_SOURCE=""
++# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+ CONFIG_EMBEDDED=y
+ CONFIG_KALLSYMS=y
+ # CONFIG_KALLSYMS_EXTRA_PASS is not set
+@@ -170,7 +170,6 @@
+ CONFIG_BASE_FULL=y
+ CONFIG_FUTEX=y
+ CONFIG_EPOLL=y
+-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+ CONFIG_SHMEM=y
+ CONFIG_CC_ALIGN_FUNCTIONS=0
+ CONFIG_CC_ALIGN_LABELS=0
+@@ -305,7 +304,6 @@
+ # CONFIG_IEEE80211_DEBUG is not set
+ CONFIG_IEEE80211_CRYPT_WEP=m
+ CONFIG_IEEE80211_CRYPT_CCMP=m
+-CONFIG_IEEE80211_CRYPT_TKIP=m
+ 
+ #
+ # Device Drivers
+diff -Naur linux-2.6.15.orig/arch/mips/configs/ip22_defconfig linux-2.6.15/arch/mips/configs/ip22_defconfig
+--- linux-2.6.15.orig/arch/mips/configs/ip22_defconfig	2006-01-03 03:21:10.000000000 +0000
++++ linux-2.6.15/arch/mips/configs/ip22_defconfig	2006-01-09 19:54:12.000000000 +0000
+@@ -1,7 +1,7 @@
+ #
+ # Automatically generated make config: don't edit
+-# Linux kernel version: 2.6.15-rc2
+-# Thu Nov 24 01:06:20 2005
++# Linux kernel version: 2.6.15-rc5
++# Sat Dec 17 18:02:11 2005
+ #
+ CONFIG_MIPS=y
+ 
+@@ -123,7 +123,6 @@
+ # CONFIG_64BIT_PHYS_ADDR is not set
+ # CONFIG_CPU_ADVANCED is not set
+ CONFIG_CPU_HAS_LLSC=y
+-CONFIG_CPU_HAS_LLDSCD=y
+ CONFIG_CPU_HAS_SYNC=y
+ CONFIG_GENERIC_HARDIRQS=y
+ CONFIG_GENERIC_IRQ_PROBE=y
+@@ -164,6 +163,7 @@
+ CONFIG_IKCONFIG=y
+ CONFIG_IKCONFIG_PROC=y
+ CONFIG_INITRAMFS_SOURCE=""
++# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+ CONFIG_EMBEDDED=y
+ CONFIG_KALLSYMS=y
+ # CONFIG_KALLSYMS_EXTRA_PASS is not set
+@@ -172,7 +172,6 @@
+ CONFIG_BASE_FULL=y
+ CONFIG_FUTEX=y
+ CONFIG_EPOLL=y
+-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+ CONFIG_SHMEM=y
+ CONFIG_CC_ALIGN_FUNCTIONS=0
+ CONFIG_CC_ALIGN_LABELS=0
+@@ -505,7 +504,6 @@
+ # CONFIG_IEEE80211_DEBUG is not set
+ CONFIG_IEEE80211_CRYPT_WEP=m
+ CONFIG_IEEE80211_CRYPT_CCMP=m
+-CONFIG_IEEE80211_CRYPT_TKIP=m
+ 
+ #
+ # Device Drivers
+diff -Naur linux-2.6.15.orig/arch/mips/configs/ip27_defconfig linux-2.6.15/arch/mips/configs/ip27_defconfig
+--- linux-2.6.15.orig/arch/mips/configs/ip27_defconfig	2006-01-03 03:21:10.000000000 +0000
++++ linux-2.6.15/arch/mips/configs/ip27_defconfig	2006-01-09 19:54:12.000000000 +0000
+@@ -1,7 +1,7 @@
+ #
+ # Automatically generated make config: don't edit
+-# Linux kernel version: 2.6.15-rc2
+-# Thu Nov 24 01:06:21 2005
++# Linux kernel version: 2.6.15-rc5
++# Sat Dec 17 18:02:55 2005
+ #
+ CONFIG_MIPS=y
+ 
+@@ -119,7 +119,6 @@
+ CONFIG_CPU_HAS_PREFETCH=y
+ # CONFIG_MIPS_MT is not set
+ CONFIG_CPU_HAS_LLSC=y
+-CONFIG_CPU_HAS_LLDSCD=y
+ CONFIG_CPU_HAS_SYNC=y
+ CONFIG_GENERIC_HARDIRQS=y
+ CONFIG_GENERIC_IRQ_PROBE=y
+@@ -166,6 +165,7 @@
+ CONFIG_IKCONFIG_PROC=y
+ CONFIG_CPUSETS=y
+ CONFIG_INITRAMFS_SOURCE=""
++# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+ CONFIG_EMBEDDED=y
+ CONFIG_KALLSYMS=y
+ # CONFIG_KALLSYMS_EXTRA_PASS is not set
+@@ -174,7 +174,6 @@
+ CONFIG_BASE_FULL=y
+ CONFIG_FUTEX=y
+ CONFIG_EPOLL=y
+-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+ CONFIG_SHMEM=y
+ CONFIG_CC_ALIGN_FUNCTIONS=0
+ CONFIG_CC_ALIGN_LABELS=0
+@@ -357,7 +356,6 @@
+ # CONFIG_IEEE80211_DEBUG is not set
+ CONFIG_IEEE80211_CRYPT_WEP=m
+ CONFIG_IEEE80211_CRYPT_CCMP=m
+-CONFIG_IEEE80211_CRYPT_TKIP=m
+ 
+ #
+ # Device Drivers
+diff -Naur linux-2.6.15.orig/arch/mips/configs/ip32_defconfig linux-2.6.15/arch/mips/configs/ip32_defconfig
+--- linux-2.6.15.orig/arch/mips/configs/ip32_defconfig	2006-01-03 03:21:10.000000000 +0000
++++ linux-2.6.15/arch/mips/configs/ip32_defconfig	2006-01-09 19:54:12.000000000 +0000
+@@ -1,7 +1,7 @@
+ #
+ # Automatically generated make config: don't edit
+-# Linux kernel version: 2.6.15-rc2
+-# Thu Nov 24 01:06:24 2005
++# Linux kernel version: 2.6.15-rc5
++# Sat Dec 17 18:02:57 2005
+ #
+ CONFIG_MIPS=y
+ 
+@@ -121,7 +121,6 @@
+ CONFIG_RM7000_CPU_SCACHE=y
+ # CONFIG_MIPS_MT is not set
+ CONFIG_CPU_HAS_LLSC=y
+-CONFIG_CPU_HAS_LLDSCD=y
+ CONFIG_CPU_HAS_SYNC=y
+ CONFIG_GENERIC_HARDIRQS=y
+ CONFIG_GENERIC_IRQ_PROBE=y
+@@ -162,6 +161,7 @@
+ CONFIG_KOBJECT_UEVENT=y
+ # CONFIG_IKCONFIG is not set
+ CONFIG_INITRAMFS_SOURCE=""
++# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+ CONFIG_EMBEDDED=y
+ CONFIG_KALLSYMS=y
+ # CONFIG_KALLSYMS_EXTRA_PASS is not set
+@@ -170,7 +170,6 @@
+ CONFIG_BASE_FULL=y
+ CONFIG_FUTEX=y
+ CONFIG_EPOLL=y
+-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+ CONFIG_SHMEM=y
+ CONFIG_CC_ALIGN_FUNCTIONS=0
+ CONFIG_CC_ALIGN_LABELS=0
+@@ -306,7 +305,6 @@
+ # CONFIG_IEEE80211_DEBUG is not set
+ CONFIG_IEEE80211_CRYPT_WEP=y
+ CONFIG_IEEE80211_CRYPT_CCMP=y
+-CONFIG_IEEE80211_CRYPT_TKIP=y
+ 
+ #
+ # Device Drivers
+diff -Naur linux-2.6.15.orig/arch/mips/configs/it8172_defconfig linux-2.6.15/arch/mips/configs/it8172_defconfig
+--- linux-2.6.15.orig/arch/mips/configs/it8172_defconfig	2006-01-03 03:21:10.000000000 +0000
++++ linux-2.6.15/arch/mips/configs/it8172_defconfig	2006-01-09 19:54:12.000000000 +0000
+@@ -1,7 +1,7 @@
+ #
+ # Automatically generated make config: don't edit
+-# Linux kernel version: 2.6.15-rc2
+-# Thu Nov 24 01:06:26 2005
++# Linux kernel version: 2.6.15-rc5
++# Sat Dec 17 18:02:59 2005
+ #
+ CONFIG_MIPS=y
+ 
+@@ -117,7 +117,6 @@
+ # CONFIG_MIPS_MT is not set
+ # CONFIG_CPU_ADVANCED is not set
+ CONFIG_CPU_HAS_LLSC=y
+-CONFIG_CPU_HAS_LLDSCD=y
+ CONFIG_CPU_HAS_SYNC=y
+ CONFIG_GENERIC_HARDIRQS=y
+ CONFIG_GENERIC_IRQ_PROBE=y
+@@ -158,6 +157,7 @@
+ CONFIG_KOBJECT_UEVENT=y
+ # CONFIG_IKCONFIG is not set
+ CONFIG_INITRAMFS_SOURCE=""
++# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+ CONFIG_EMBEDDED=y
+ CONFIG_KALLSYMS=y
+ # CONFIG_KALLSYMS_EXTRA_PASS is not set
+@@ -166,7 +166,6 @@
+ CONFIG_BASE_FULL=y
+ CONFIG_FUTEX=y
+ CONFIG_EPOLL=y
+-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+ CONFIG_SHMEM=y
+ CONFIG_CC_ALIGN_FUNCTIONS=0
+ CONFIG_CC_ALIGN_LABELS=0
+@@ -302,7 +301,6 @@
+ # CONFIG_IEEE80211_DEBUG is not set
+ CONFIG_IEEE80211_CRYPT_WEP=m
+ CONFIG_IEEE80211_CRYPT_CCMP=m
+-CONFIG_IEEE80211_CRYPT_TKIP=m
+ 
+ #
+ # Device Drivers
+diff -Naur linux-2.6.15.orig/arch/mips/configs/ivr_defconfig linux-2.6.15/arch/mips/configs/ivr_defconfig
+--- linux-2.6.15.orig/arch/mips/configs/ivr_defconfig	2006-01-03 03:21:10.000000000 +0000
++++ linux-2.6.15/arch/mips/configs/ivr_defconfig	2006-01-09 19:54:12.000000000 +0000
+@@ -1,7 +1,7 @@
+ #
+ # Automatically generated make config: don't edit
+-# Linux kernel version: 2.6.15-rc2
+-# Thu Nov 24 01:06:27 2005
++# Linux kernel version: 2.6.15-rc5
++# Sat Dec 17 18:03:01 2005
+ #
+ CONFIG_MIPS=y
+ 
+@@ -114,7 +114,6 @@
+ # CONFIG_MIPS_MT is not set
+ # CONFIG_CPU_ADVANCED is not set
+ CONFIG_CPU_HAS_LLSC=y
+-CONFIG_CPU_HAS_LLDSCD=y
+ CONFIG_CPU_HAS_SYNC=y
+ CONFIG_GENERIC_HARDIRQS=y
+ CONFIG_GENERIC_IRQ_PROBE=y
+@@ -155,6 +154,7 @@
+ CONFIG_KOBJECT_UEVENT=y
+ # CONFIG_IKCONFIG is not set
+ CONFIG_INITRAMFS_SOURCE=""
++# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+ CONFIG_EMBEDDED=y
+ CONFIG_KALLSYMS=y
+ # CONFIG_KALLSYMS_EXTRA_PASS is not set
+@@ -163,7 +163,6 @@
+ CONFIG_BASE_FULL=y
+ CONFIG_FUTEX=y
+ CONFIG_EPOLL=y
+-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+ CONFIG_SHMEM=y
+ CONFIG_CC_ALIGN_FUNCTIONS=0
+ CONFIG_CC_ALIGN_LABELS=0
+@@ -301,7 +300,6 @@
+ # CONFIG_IEEE80211_DEBUG is not set
+ CONFIG_IEEE80211_CRYPT_WEP=m
+ CONFIG_IEEE80211_CRYPT_CCMP=m
+-CONFIG_IEEE80211_CRYPT_TKIP=m
+ 
+ #
+ # Device Drivers
+diff -Naur linux-2.6.15.orig/arch/mips/configs/jaguar-atx_defconfig linux-2.6.15/arch/mips/configs/jaguar-atx_defconfig
+--- linux-2.6.15.orig/arch/mips/configs/jaguar-atx_defconfig	2006-01-03 03:21:10.000000000 +0000
++++ linux-2.6.15/arch/mips/configs/jaguar-atx_defconfig	2006-01-09 19:54:12.000000000 +0000
+@@ -1,7 +1,7 @@
+ #
+ # Automatically generated make config: don't edit
+-# Linux kernel version: 2.6.15-rc2
+-# Thu Nov 24 01:06:29 2005
++# Linux kernel version: 2.6.15-rc5
++# Sat Dec 17 18:03:03 2005
+ #
+ CONFIG_MIPS=y
+ 
+@@ -124,7 +124,6 @@
+ # CONFIG_64BIT_PHYS_ADDR is not set
+ # CONFIG_CPU_ADVANCED is not set
+ CONFIG_CPU_HAS_LLSC=y
+-CONFIG_CPU_HAS_LLDSCD=y
+ CONFIG_CPU_HAS_SYNC=y
+ CONFIG_GENERIC_HARDIRQS=y
+ CONFIG_GENERIC_IRQ_PROBE=y
+@@ -172,7 +171,6 @@
+ CONFIG_BASE_FULL=y
+ CONFIG_FUTEX=y
+ CONFIG_EPOLL=y
+-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+ CONFIG_SHMEM=y
+ CONFIG_CC_ALIGN_FUNCTIONS=0
+ CONFIG_CC_ALIGN_LABELS=0
+@@ -295,7 +293,6 @@
+ # CONFIG_IEEE80211_DEBUG is not set
+ CONFIG_IEEE80211_CRYPT_WEP=m
+ CONFIG_IEEE80211_CRYPT_CCMP=m
+-CONFIG_IEEE80211_CRYPT_TKIP=m
+ 
+ #
+ # Device Drivers
+diff -Naur linux-2.6.15.orig/arch/mips/configs/jmr3927_defconfig linux-2.6.15/arch/mips/configs/jmr3927_defconfig
+--- linux-2.6.15.orig/arch/mips/configs/jmr3927_defconfig	2006-01-03 03:21:10.000000000 +0000
++++ linux-2.6.15/arch/mips/configs/jmr3927_defconfig	2006-01-09 19:54:12.000000000 +0000
+@@ -1,7 +1,7 @@
+ #
+ # Automatically generated make config: don't edit
+-# Linux kernel version: 2.6.15-rc2
+-# Thu Nov 24 01:06:31 2005
++# Linux kernel version: 2.6.15-rc5
++# Sat Dec 17 18:03:05 2005
+ #
+ CONFIG_MIPS=y
+ 
+@@ -152,6 +152,7 @@
+ CONFIG_KOBJECT_UEVENT=y
+ # CONFIG_IKCONFIG is not set
+ CONFIG_INITRAMFS_SOURCE=""
++# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+ CONFIG_EMBEDDED=y
+ CONFIG_KALLSYMS=y
+ # CONFIG_KALLSYMS_EXTRA_PASS is not set
+@@ -160,7 +161,6 @@
+ CONFIG_BASE_FULL=y
+ CONFIG_FUTEX=y
+ CONFIG_EPOLL=y
+-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+ CONFIG_SHMEM=y
+ CONFIG_CC_ALIGN_FUNCTIONS=0
+ CONFIG_CC_ALIGN_LABELS=0
+@@ -292,7 +292,6 @@
+ # CONFIG_IEEE80211_DEBUG is not set
+ CONFIG_IEEE80211_CRYPT_WEP=y
+ CONFIG_IEEE80211_CRYPT_CCMP=y
+-CONFIG_IEEE80211_CRYPT_TKIP=y
+ 
+ #
+ # Device Drivers
+diff -Naur linux-2.6.15.orig/arch/mips/configs/lasat200_defconfig linux-2.6.15/arch/mips/configs/lasat200_defconfig
+--- linux-2.6.15.orig/arch/mips/configs/lasat200_defconfig	2006-01-03 03:21:10.000000000 +0000
++++ linux-2.6.15/arch/mips/configs/lasat200_defconfig	2006-01-09 19:54:12.000000000 +0000
+@@ -1,7 +1,7 @@
+ #
+ # Automatically generated make config: don't edit
+-# Linux kernel version: 2.6.15-rc2
+-# Thu Nov 24 01:06:33 2005
++# Linux kernel version: 2.6.15-rc5
++# Sat Dec 17 18:03:07 2005
+ #
+ CONFIG_MIPS=y
+ 
+@@ -121,7 +121,6 @@
+ # CONFIG_64BIT_PHYS_ADDR is not set
+ # CONFIG_CPU_ADVANCED is not set
+ CONFIG_CPU_HAS_LLSC=y
+-CONFIG_CPU_HAS_LLDSCD=y
+ CONFIG_CPU_HAS_SYNC=y
+ CONFIG_GENERIC_HARDIRQS=y
+ CONFIG_GENERIC_IRQ_PROBE=y
+@@ -161,6 +160,7 @@
+ CONFIG_KOBJECT_UEVENT=y
+ # CONFIG_IKCONFIG is not set
+ CONFIG_INITRAMFS_SOURCE=""
++# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+ CONFIG_EMBEDDED=y
+ CONFIG_KALLSYMS=y
+ # CONFIG_KALLSYMS_EXTRA_PASS is not set
+@@ -169,7 +169,6 @@
+ CONFIG_BASE_FULL=y
+ CONFIG_FUTEX=y
+ CONFIG_EPOLL=y
+-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+ CONFIG_SHMEM=y
+ CONFIG_CC_ALIGN_FUNCTIONS=0
+ CONFIG_CC_ALIGN_LABELS=0
+@@ -303,7 +302,6 @@
+ # CONFIG_IEEE80211_DEBUG is not set
+ CONFIG_IEEE80211_CRYPT_WEP=m
+ CONFIG_IEEE80211_CRYPT_CCMP=m
+-CONFIG_IEEE80211_CRYPT_TKIP=m
+ 
+ #
+ # Device Drivers
+diff -Naur linux-2.6.15.orig/arch/mips/configs/malta_defconfig linux-2.6.15/arch/mips/configs/malta_defconfig
+--- linux-2.6.15.orig/arch/mips/configs/malta_defconfig	2006-01-03 03:21:10.000000000 +0000
++++ linux-2.6.15/arch/mips/configs/malta_defconfig	2006-01-09 19:54:12.000000000 +0000
+@@ -1,7 +1,7 @@
+ #
+ # Automatically generated make config: don't edit
+-# Linux kernel version: 2.6.15-rc2
+-# Thu Nov 24 01:06:35 2005
++# Linux kernel version: 2.6.15-rc5
++# Fri Dec 23 02:21:03 2005
+ #
+ CONFIG_MIPS=y
+ 
+@@ -87,8 +87,8 @@
+ #
+ # CPU selection
+ #
+-CONFIG_CPU_MIPS32_R1=y
+-# CONFIG_CPU_MIPS32_R2 is not set
++# CONFIG_CPU_MIPS32_R1 is not set
++CONFIG_CPU_MIPS32_R2=y
+ # CONFIG_CPU_MIPS64_R1 is not set
+ # CONFIG_CPU_MIPS64_R2 is not set
+ # CONFIG_CPU_R3000 is not set
+@@ -112,7 +112,7 @@
+ CONFIG_SYS_HAS_CPU_NEVADA=y
+ CONFIG_SYS_HAS_CPU_RM7000=y
+ CONFIG_CPU_MIPS32=y
+-CONFIG_CPU_MIPSR1=y
++CONFIG_CPU_MIPSR2=y
+ CONFIG_SYS_SUPPORTS_32BIT_KERNEL=y
+ CONFIG_SYS_SUPPORTS_64BIT_KERNEL=y
+ CONFIG_CPU_SUPPORTS_32BIT_KERNEL=y
+@@ -174,6 +174,7 @@
+ CONFIG_KOBJECT_UEVENT=y
+ # CONFIG_IKCONFIG is not set
+ CONFIG_INITRAMFS_SOURCE=""
++# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+ CONFIG_EMBEDDED=y
+ CONFIG_KALLSYMS=y
+ # CONFIG_KALLSYMS_EXTRA_PASS is not set
+@@ -182,7 +183,6 @@
+ CONFIG_BASE_FULL=y
+ CONFIG_FUTEX=y
+ CONFIG_EPOLL=y
+-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+ CONFIG_SHMEM=y
+ CONFIG_CC_ALIGN_FUNCTIONS=0
+ CONFIG_CC_ALIGN_LABELS=0
+@@ -559,7 +559,6 @@
+ # CONFIG_IEEE80211_DEBUG is not set
+ CONFIG_IEEE80211_CRYPT_WEP=m
+ CONFIG_IEEE80211_CRYPT_CCMP=m
+-CONFIG_IEEE80211_CRYPT_TKIP=m
+ 
+ #
+ # Device Drivers
+diff -Naur linux-2.6.15.orig/arch/mips/configs/mipssim_defconfig linux-2.6.15/arch/mips/configs/mipssim_defconfig
+--- linux-2.6.15.orig/arch/mips/configs/mipssim_defconfig	2006-01-03 03:21:10.000000000 +0000
++++ linux-2.6.15/arch/mips/configs/mipssim_defconfig	2006-01-09 19:54:12.000000000 +0000
+@@ -1,7 +1,7 @@
+ #
+ # Automatically generated make config: don't edit
+-# Linux kernel version: 2.6.15-rc2
+-# Thu Nov 24 01:06:37 2005
++# Linux kernel version: 2.6.15-rc5
++# Sat Dec 17 18:03:13 2005
+ #
+ CONFIG_MIPS=y
+ 
+@@ -160,6 +160,7 @@
+ CONFIG_KOBJECT_UEVENT=y
+ # CONFIG_IKCONFIG is not set
+ CONFIG_INITRAMFS_SOURCE=""
++# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+ CONFIG_EMBEDDED=y
+ CONFIG_KALLSYMS=y
+ # CONFIG_KALLSYMS_ALL is not set
+@@ -169,7 +170,6 @@
+ CONFIG_BASE_FULL=y
+ CONFIG_FUTEX=y
+ CONFIG_EPOLL=y
+-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+ CONFIG_SHMEM=y
+ CONFIG_CC_ALIGN_FUNCTIONS=0
+ CONFIG_CC_ALIGN_LABELS=0
+diff -Naur linux-2.6.15.orig/arch/mips/configs/mpc30x_defconfig linux-2.6.15/arch/mips/configs/mpc30x_defconfig
+--- linux-2.6.15.orig/arch/mips/configs/mpc30x_defconfig	2006-01-03 03:21:10.000000000 +0000
++++ linux-2.6.15/arch/mips/configs/mpc30x_defconfig	2006-01-09 19:54:12.000000000 +0000
+@@ -1,7 +1,7 @@
+ #
+ # Automatically generated make config: don't edit
+-# Linux kernel version: 2.6.15-rc2
+-# Thu Nov 24 01:06:39 2005
++# Linux kernel version: 2.6.15-rc5
++# Sat Dec 17 18:03:15 2005
+ #
+ CONFIG_MIPS=y
+ 
+@@ -159,6 +159,7 @@
+ CONFIG_KOBJECT_UEVENT=y
+ # CONFIG_IKCONFIG is not set
+ CONFIG_INITRAMFS_SOURCE=""
++# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+ CONFIG_EMBEDDED=y
+ CONFIG_KALLSYMS=y
+ # CONFIG_KALLSYMS_EXTRA_PASS is not set
+@@ -167,7 +168,6 @@
+ CONFIG_BASE_FULL=y
+ CONFIG_FUTEX=y
+ CONFIG_EPOLL=y
+-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+ CONFIG_SHMEM=y
+ CONFIG_CC_ALIGN_FUNCTIONS=0
+ CONFIG_CC_ALIGN_LABELS=0
+diff -Naur linux-2.6.15.orig/arch/mips/configs/ocelot_3_defconfig linux-2.6.15/arch/mips/configs/ocelot_3_defconfig
+--- linux-2.6.15.orig/arch/mips/configs/ocelot_3_defconfig	2006-01-03 03:21:10.000000000 +0000
++++ linux-2.6.15/arch/mips/configs/ocelot_3_defconfig	2006-01-09 19:54:12.000000000 +0000
+@@ -1,7 +1,7 @@
+ #
+ # Automatically generated make config: don't edit
+-# Linux kernel version: 2.6.15-rc2
+-# Thu Nov 24 01:06:41 2005
++# Linux kernel version: 2.6.15-rc5
++# Sat Dec 17 18:03:18 2005
+ #
+ CONFIG_MIPS=y
+ 
+@@ -122,7 +122,6 @@
+ # CONFIG_64BIT_PHYS_ADDR is not set
+ # CONFIG_CPU_ADVANCED is not set
+ CONFIG_CPU_HAS_LLSC=y
+-CONFIG_CPU_HAS_LLDSCD=y
+ CONFIG_CPU_HAS_SYNC=y
+ CONFIG_GENERIC_HARDIRQS=y
+ CONFIG_GENERIC_IRQ_PROBE=y
+@@ -165,6 +164,7 @@
+ CONFIG_IKCONFIG=y
+ CONFIG_IKCONFIG_PROC=y
+ CONFIG_INITRAMFS_SOURCE=""
++# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+ CONFIG_EMBEDDED=y
+ CONFIG_KALLSYMS=y
+ # CONFIG_KALLSYMS_EXTRA_PASS is not set
+@@ -173,7 +173,6 @@
+ CONFIG_BASE_FULL=y
+ CONFIG_FUTEX=y
+ CONFIG_EPOLL=y
+-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+ CONFIG_SHMEM=y
+ CONFIG_CC_ALIGN_FUNCTIONS=0
+ CONFIG_CC_ALIGN_LABELS=0
+@@ -345,7 +344,6 @@
+ # CONFIG_IEEE80211_DEBUG is not set
+ CONFIG_IEEE80211_CRYPT_WEP=m
+ CONFIG_IEEE80211_CRYPT_CCMP=m
+-CONFIG_IEEE80211_CRYPT_TKIP=m
+ 
+ #
+ # Device Drivers
+diff -Naur linux-2.6.15.orig/arch/mips/configs/ocelot_c_defconfig linux-2.6.15/arch/mips/configs/ocelot_c_defconfig
+--- linux-2.6.15.orig/arch/mips/configs/ocelot_c_defconfig	2006-01-03 03:21:10.000000000 +0000
++++ linux-2.6.15/arch/mips/configs/ocelot_c_defconfig	2006-01-09 19:54:12.000000000 +0000
+@@ -1,7 +1,7 @@
+ #
+ # Automatically generated make config: don't edit
+-# Linux kernel version: 2.6.15-rc2
+-# Thu Nov 24 01:06:43 2005
++# Linux kernel version: 2.6.15-rc5
++# Sat Dec 17 18:03:19 2005
+ #
+ CONFIG_MIPS=y
+ 
+@@ -118,7 +118,6 @@
+ CONFIG_CPU_HAS_PREFETCH=y
+ # CONFIG_MIPS_MT is not set
+ CONFIG_CPU_HAS_LLSC=y
+-CONFIG_CPU_HAS_LLDSCD=y
+ CONFIG_CPU_HAS_SYNC=y
+ CONFIG_GENERIC_HARDIRQS=y
+ CONFIG_GENERIC_IRQ_PROBE=y
+@@ -159,6 +158,7 @@
+ CONFIG_KOBJECT_UEVENT=y
+ # CONFIG_IKCONFIG is not set
+ CONFIG_INITRAMFS_SOURCE=""
++# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+ CONFIG_EMBEDDED=y
+ CONFIG_KALLSYMS=y
+ # CONFIG_KALLSYMS_EXTRA_PASS is not set
+@@ -167,7 +167,6 @@
+ CONFIG_BASE_FULL=y
+ CONFIG_FUTEX=y
+ CONFIG_EPOLL=y
+-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+ CONFIG_SHMEM=y
+ CONFIG_CC_ALIGN_FUNCTIONS=0
+ CONFIG_CC_ALIGN_LABELS=0
+@@ -302,7 +301,6 @@
+ # CONFIG_IEEE80211_DEBUG is not set
+ CONFIG_IEEE80211_CRYPT_WEP=y
+ CONFIG_IEEE80211_CRYPT_CCMP=y
+-CONFIG_IEEE80211_CRYPT_TKIP=y
+ 
+ #
+ # Device Drivers
+diff -Naur linux-2.6.15.orig/arch/mips/configs/ocelot_defconfig linux-2.6.15/arch/mips/configs/ocelot_defconfig
+--- linux-2.6.15.orig/arch/mips/configs/ocelot_defconfig	2006-01-03 03:21:10.000000000 +0000
++++ linux-2.6.15/arch/mips/configs/ocelot_defconfig	2006-01-09 19:54:12.000000000 +0000
+@@ -1,7 +1,7 @@
+ #
+ # Automatically generated make config: don't edit
+-# Linux kernel version: 2.6.15-rc2
+-# Thu Nov 24 01:06:44 2005
++# Linux kernel version: 2.6.15-rc5
++# Sat Dec 17 18:03:21 2005
+ #
+ CONFIG_MIPS=y
+ 
+@@ -123,7 +123,6 @@
+ # CONFIG_64BIT_PHYS_ADDR is not set
+ # CONFIG_CPU_ADVANCED is not set
+ CONFIG_CPU_HAS_LLSC=y
+-CONFIG_CPU_HAS_LLDSCD=y
+ CONFIG_CPU_HAS_SYNC=y
+ CONFIG_GENERIC_HARDIRQS=y
+ CONFIG_GENERIC_IRQ_PROBE=y
+@@ -164,6 +163,7 @@
+ CONFIG_KOBJECT_UEVENT=y
+ # CONFIG_IKCONFIG is not set
+ CONFIG_INITRAMFS_SOURCE=""
++# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+ CONFIG_EMBEDDED=y
+ CONFIG_KALLSYMS=y
+ # CONFIG_KALLSYMS_EXTRA_PASS is not set
+@@ -172,7 +172,6 @@
+ CONFIG_BASE_FULL=y
+ CONFIG_FUTEX=y
+ CONFIG_EPOLL=y
+-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+ CONFIG_SHMEM=y
+ CONFIG_CC_ALIGN_FUNCTIONS=0
+ CONFIG_CC_ALIGN_LABELS=0
+@@ -301,7 +300,6 @@
+ # CONFIG_IEEE80211_DEBUG is not set
+ CONFIG_IEEE80211_CRYPT_WEP=y
+ CONFIG_IEEE80211_CRYPT_CCMP=y
+-CONFIG_IEEE80211_CRYPT_TKIP=y
+ 
+ #
+ # Device Drivers
+diff -Naur linux-2.6.15.orig/arch/mips/configs/ocelot_g_defconfig linux-2.6.15/arch/mips/configs/ocelot_g_defconfig
+--- linux-2.6.15.orig/arch/mips/configs/ocelot_g_defconfig	2006-01-03 03:21:10.000000000 +0000
++++ linux-2.6.15/arch/mips/configs/ocelot_g_defconfig	2006-01-09 19:54:12.000000000 +0000
+@@ -1,7 +1,7 @@
+ #
+ # Automatically generated make config: don't edit
+-# Linux kernel version: 2.6.15-rc2
+-# Thu Nov 24 01:06:46 2005
++# Linux kernel version: 2.6.15-rc5
++# Sat Dec 17 18:03:23 2005
+ #
+ CONFIG_MIPS=y
+ 
+@@ -121,7 +121,6 @@
+ CONFIG_CPU_HAS_PREFETCH=y
+ # CONFIG_MIPS_MT is not set
+ CONFIG_CPU_HAS_LLSC=y
+-CONFIG_CPU_HAS_LLDSCD=y
+ CONFIG_CPU_HAS_SYNC=y
+ CONFIG_GENERIC_HARDIRQS=y
+ CONFIG_GENERIC_IRQ_PROBE=y
+@@ -162,6 +161,7 @@
+ CONFIG_KOBJECT_UEVENT=y
+ # CONFIG_IKCONFIG is not set
+ CONFIG_INITRAMFS_SOURCE=""
++# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+ CONFIG_EMBEDDED=y
+ CONFIG_KALLSYMS=y
+ # CONFIG_KALLSYMS_EXTRA_PASS is not set
+@@ -170,7 +170,6 @@
+ CONFIG_BASE_FULL=y
+ CONFIG_FUTEX=y
+ CONFIG_EPOLL=y
+-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+ CONFIG_SHMEM=y
+ CONFIG_CC_ALIGN_FUNCTIONS=0
+ CONFIG_CC_ALIGN_LABELS=0
+@@ -305,7 +304,6 @@
+ # CONFIG_IEEE80211_DEBUG is not set
+ CONFIG_IEEE80211_CRYPT_WEP=y
+ CONFIG_IEEE80211_CRYPT_CCMP=y
+-CONFIG_IEEE80211_CRYPT_TKIP=y
+ 
+ #
+ # Device Drivers
+diff -Naur linux-2.6.15.orig/arch/mips/configs/pb1100_defconfig linux-2.6.15/arch/mips/configs/pb1100_defconfig
+--- linux-2.6.15.orig/arch/mips/configs/pb1100_defconfig	2006-01-03 03:21:10.000000000 +0000
++++ linux-2.6.15/arch/mips/configs/pb1100_defconfig	2006-01-09 19:54:12.000000000 +0000
+@@ -1,7 +1,7 @@
+ #
+ # Automatically generated make config: don't edit
+-# Linux kernel version: 2.6.15-rc2
+-# Thu Nov 24 01:06:48 2005
++# Linux kernel version: 2.6.15-rc5
++# Sat Dec 17 18:03:25 2005
+ #
+ CONFIG_MIPS=y
+ 
+@@ -157,6 +157,7 @@
+ CONFIG_KOBJECT_UEVENT=y
+ # CONFIG_IKCONFIG is not set
+ CONFIG_INITRAMFS_SOURCE=""
++# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+ CONFIG_EMBEDDED=y
+ CONFIG_KALLSYMS=y
+ # CONFIG_KALLSYMS_EXTRA_PASS is not set
+@@ -165,7 +166,6 @@
+ CONFIG_BASE_FULL=y
+ CONFIG_FUTEX=y
+ CONFIG_EPOLL=y
+-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+ CONFIG_SHMEM=y
+ CONFIG_CC_ALIGN_FUNCTIONS=0
+ CONFIG_CC_ALIGN_LABELS=0
+@@ -334,7 +334,6 @@
+ # CONFIG_IEEE80211_DEBUG is not set
+ CONFIG_IEEE80211_CRYPT_WEP=m
+ CONFIG_IEEE80211_CRYPT_CCMP=m
+-CONFIG_IEEE80211_CRYPT_TKIP=m
+ 
+ #
+ # Device Drivers
+diff -Naur linux-2.6.15.orig/arch/mips/configs/pb1500_defconfig linux-2.6.15/arch/mips/configs/pb1500_defconfig
+--- linux-2.6.15.orig/arch/mips/configs/pb1500_defconfig	2006-01-03 03:21:10.000000000 +0000
++++ linux-2.6.15/arch/mips/configs/pb1500_defconfig	2006-01-09 19:54:12.000000000 +0000
+@@ -1,7 +1,7 @@
+ #
+ # Automatically generated make config: don't edit
+-# Linux kernel version: 2.6.15-rc2
+-# Thu Nov 24 01:06:50 2005
++# Linux kernel version: 2.6.15-rc5
++# Sat Dec 17 18:03:28 2005
+ #
+ CONFIG_MIPS=y
+ 
+@@ -156,6 +156,7 @@
+ CONFIG_KOBJECT_UEVENT=y
+ # CONFIG_IKCONFIG is not set
+ CONFIG_INITRAMFS_SOURCE=""
++# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+ CONFIG_EMBEDDED=y
+ CONFIG_KALLSYMS=y
+ # CONFIG_KALLSYMS_EXTRA_PASS is not set
+@@ -164,7 +165,6 @@
+ CONFIG_BASE_FULL=y
+ CONFIG_FUTEX=y
+ CONFIG_EPOLL=y
+-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+ CONFIG_SHMEM=y
+ CONFIG_CC_ALIGN_FUNCTIONS=0
+ CONFIG_CC_ALIGN_LABELS=0
+@@ -340,7 +340,6 @@
+ # CONFIG_IEEE80211_DEBUG is not set
+ CONFIG_IEEE80211_CRYPT_WEP=m
+ CONFIG_IEEE80211_CRYPT_CCMP=m
+-CONFIG_IEEE80211_CRYPT_TKIP=m
+ 
+ #
+ # Device Drivers
+diff -Naur linux-2.6.15.orig/arch/mips/configs/pb1550_defconfig linux-2.6.15/arch/mips/configs/pb1550_defconfig
+--- linux-2.6.15.orig/arch/mips/configs/pb1550_defconfig	2006-01-03 03:21:10.000000000 +0000
++++ linux-2.6.15/arch/mips/configs/pb1550_defconfig	2006-01-09 19:54:12.000000000 +0000
+@@ -1,7 +1,7 @@
+ #
+ # Automatically generated make config: don't edit
+-# Linux kernel version: 2.6.15-rc2
+-# Thu Nov 24 01:06:52 2005
++# Linux kernel version: 2.6.15-rc5
++# Sat Dec 17 18:03:31 2005
+ #
+ CONFIG_MIPS=y
+ 
+@@ -156,6 +156,7 @@
+ CONFIG_KOBJECT_UEVENT=y
+ # CONFIG_IKCONFIG is not set
+ CONFIG_INITRAMFS_SOURCE=""
++# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+ CONFIG_EMBEDDED=y
+ CONFIG_KALLSYMS=y
+ # CONFIG_KALLSYMS_EXTRA_PASS is not set
+@@ -164,7 +165,6 @@
+ CONFIG_BASE_FULL=y
+ CONFIG_FUTEX=y
+ CONFIG_EPOLL=y
+-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+ CONFIG_SHMEM=y
+ CONFIG_CC_ALIGN_FUNCTIONS=0
+ CONFIG_CC_ALIGN_LABELS=0
+@@ -340,7 +340,6 @@
+ # CONFIG_IEEE80211_DEBUG is not set
+ CONFIG_IEEE80211_CRYPT_WEP=m
+ CONFIG_IEEE80211_CRYPT_CCMP=m
+-CONFIG_IEEE80211_CRYPT_TKIP=m
+ 
+ #
+ # Device Drivers
+diff -Naur linux-2.6.15.orig/arch/mips/configs/pnx8550-jbs_defconfig linux-2.6.15/arch/mips/configs/pnx8550-jbs_defconfig
+--- linux-2.6.15.orig/arch/mips/configs/pnx8550-jbs_defconfig	2006-01-03 03:21:10.000000000 +0000
++++ linux-2.6.15/arch/mips/configs/pnx8550-jbs_defconfig	2006-01-09 19:54:12.000000000 +0000
+@@ -1,7 +1,7 @@
+ #
+ # Automatically generated make config: don't edit
+-# Linux kernel version: 2.6.15-rc2
+-# Thu Nov 24 01:06:54 2005
++# Linux kernel version: 2.6.15-rc5
++# Sat Dec 17 18:03:33 2005
+ #
+ CONFIG_MIPS=y
+ 
+@@ -156,6 +156,7 @@
+ CONFIG_IKCONFIG=y
+ CONFIG_IKCONFIG_PROC=y
+ CONFIG_INITRAMFS_SOURCE=""
++# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+ CONFIG_EMBEDDED=y
+ CONFIG_KALLSYMS=y
+ # CONFIG_KALLSYMS_ALL is not set
+@@ -165,7 +166,6 @@
+ CONFIG_BASE_FULL=y
+ CONFIG_FUTEX=y
+ CONFIG_EPOLL=y
+-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+ CONFIG_SHMEM=y
+ CONFIG_CC_ALIGN_FUNCTIONS=0
+ CONFIG_CC_ALIGN_LABELS=0
+diff -Naur linux-2.6.15.orig/arch/mips/configs/pnx8550-v2pci_defconfig linux-2.6.15/arch/mips/configs/pnx8550-v2pci_defconfig
+--- linux-2.6.15.orig/arch/mips/configs/pnx8550-v2pci_defconfig	2006-01-03 03:21:10.000000000 +0000
++++ linux-2.6.15/arch/mips/configs/pnx8550-v2pci_defconfig	2006-01-09 19:54:12.000000000 +0000
+@@ -1,7 +1,7 @@
+ #
+ # Automatically generated make config: don't edit
+-# Linux kernel version: 2.6.15-rc2
+-# Thu Nov 24 01:06:58 2005
++# Linux kernel version: 2.6.15-rc5
++# Sat Dec 17 18:03:36 2005
+ #
+ CONFIG_MIPS=y
+ 
+@@ -116,7 +116,6 @@
+ # CONFIG_64BIT_PHYS_ADDR is not set
+ CONFIG_CPU_ADVANCED=y
+ CONFIG_CPU_HAS_LLSC=y
+-# CONFIG_CPU_HAS_LLDSCD is not set
+ # CONFIG_CPU_HAS_WB is not set
+ CONFIG_CPU_HAS_SYNC=y
+ CONFIG_GENERIC_HARDIRQS=y
+@@ -158,6 +157,7 @@
+ CONFIG_IKCONFIG=y
+ CONFIG_IKCONFIG_PROC=y
+ CONFIG_INITRAMFS_SOURCE=""
++# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+ CONFIG_EMBEDDED=y
+ CONFIG_KALLSYMS=y
+ # CONFIG_KALLSYMS_EXTRA_PASS is not set
+@@ -166,7 +166,6 @@
+ CONFIG_BASE_FULL=y
+ CONFIG_FUTEX=y
+ CONFIG_EPOLL=y
+-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+ CONFIG_SHMEM=y
+ CONFIG_CC_ALIGN_FUNCTIONS=0
+ CONFIG_CC_ALIGN_LABELS=0
+diff -Naur linux-2.6.15.orig/arch/mips/configs/qemu_defconfig linux-2.6.15/arch/mips/configs/qemu_defconfig
+--- linux-2.6.15.orig/arch/mips/configs/qemu_defconfig	2006-01-03 03:21:10.000000000 +0000
++++ linux-2.6.15/arch/mips/configs/qemu_defconfig	2006-01-09 19:54:12.000000000 +0000
+@@ -1,7 +1,7 @@
+ #
+ # Automatically generated make config: don't edit
+-# Linux kernel version: 2.6.15-rc2
+-# Thu Nov 24 01:07:00 2005
++# Linux kernel version: 2.6.15-rc5
++# Sat Dec 17 18:03:38 2005
+ #
+ CONFIG_MIPS=y
+ 
+@@ -159,7 +159,6 @@
+ # CONFIG_BASE_FULL is not set
+ # CONFIG_FUTEX is not set
+ # CONFIG_EPOLL is not set
+-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+ # CONFIG_SHMEM is not set
+ CONFIG_CC_ALIGN_FUNCTIONS=0
+ CONFIG_CC_ALIGN_LABELS=0
+@@ -270,7 +269,6 @@
+ # CONFIG_IEEE80211_DEBUG is not set
+ CONFIG_IEEE80211_CRYPT_WEP=y
+ CONFIG_IEEE80211_CRYPT_CCMP=y
+-CONFIG_IEEE80211_CRYPT_TKIP=y
+ 
+ #
+ # Device Drivers
+diff -Naur linux-2.6.15.orig/arch/mips/configs/rbhma4500_defconfig linux-2.6.15/arch/mips/configs/rbhma4500_defconfig
+--- linux-2.6.15.orig/arch/mips/configs/rbhma4500_defconfig	2006-01-03 03:21:10.000000000 +0000
++++ linux-2.6.15/arch/mips/configs/rbhma4500_defconfig	2006-01-09 19:54:12.000000000 +0000
+@@ -1,7 +1,7 @@
+ #
+ # Automatically generated make config: don't edit
+-# Linux kernel version: 2.6.15-rc2
+-# Thu Nov 24 01:07:03 2005
++# Linux kernel version: 2.6.15-rc5
++# Sat Dec 17 18:03:42 2005
+ #
+ CONFIG_MIPS=y
+ 
+@@ -124,7 +124,6 @@
+ # CONFIG_MIPS_MT is not set
+ CONFIG_CPU_ADVANCED=y
+ CONFIG_CPU_HAS_LLSC=y
+-CONFIG_CPU_HAS_LLDSCD=y
+ CONFIG_CPU_HAS_WB=y
+ CONFIG_CPU_HAS_SYNC=y
+ CONFIG_GENERIC_HARDIRQS=y
+@@ -166,6 +165,7 @@
+ CONFIG_IKCONFIG=y
+ CONFIG_IKCONFIG_PROC=y
+ CONFIG_INITRAMFS_SOURCE=""
++# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+ CONFIG_EMBEDDED=y
+ CONFIG_KALLSYMS=y
+ # CONFIG_KALLSYMS_EXTRA_PASS is not set
+@@ -174,7 +174,6 @@
+ CONFIG_BASE_FULL=y
+ # CONFIG_FUTEX is not set
+ # CONFIG_EPOLL is not set
+-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+ CONFIG_SHMEM=y
+ CONFIG_CC_ALIGN_FUNCTIONS=0
+ CONFIG_CC_ALIGN_LABELS=0
+diff -Naur linux-2.6.15.orig/arch/mips/configs/rm200_defconfig linux-2.6.15/arch/mips/configs/rm200_defconfig
+--- linux-2.6.15.orig/arch/mips/configs/rm200_defconfig	2006-01-03 03:21:10.000000000 +0000
++++ linux-2.6.15/arch/mips/configs/rm200_defconfig	2006-01-09 19:54:12.000000000 +0000
+@@ -1,7 +1,7 @@
+ #
+ # Automatically generated make config: don't edit
+-# Linux kernel version: 2.6.15-rc2
+-# Thu Nov 24 01:07:06 2005
++# Linux kernel version: 2.6.15-rc5
++# Sat Dec 17 18:03:45 2005
+ #
+ CONFIG_MIPS=y
+ 
+@@ -124,7 +124,6 @@
+ # CONFIG_64BIT_PHYS_ADDR is not set
+ # CONFIG_CPU_ADVANCED is not set
+ CONFIG_CPU_HAS_LLSC=y
+-CONFIG_CPU_HAS_LLDSCD=y
+ CONFIG_CPU_HAS_SYNC=y
+ CONFIG_GENERIC_HARDIRQS=y
+ CONFIG_GENERIC_IRQ_PROBE=y
+@@ -167,6 +166,7 @@
+ CONFIG_IKCONFIG=y
+ CONFIG_IKCONFIG_PROC=y
+ CONFIG_INITRAMFS_SOURCE=""
++# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+ CONFIG_EMBEDDED=y
+ CONFIG_KALLSYMS=y
+ # CONFIG_KALLSYMS_EXTRA_PASS is not set
+@@ -175,7 +175,6 @@
+ CONFIG_BASE_FULL=y
+ CONFIG_FUTEX=y
+ CONFIG_EPOLL=y
+-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+ CONFIG_SHMEM=y
+ CONFIG_CC_ALIGN_FUNCTIONS=0
+ CONFIG_CC_ALIGN_LABELS=0
+@@ -531,7 +530,6 @@
+ # CONFIG_IEEE80211_DEBUG is not set
+ CONFIG_IEEE80211_CRYPT_WEP=m
+ CONFIG_IEEE80211_CRYPT_CCMP=m
+-CONFIG_IEEE80211_CRYPT_TKIP=m
+ 
+ #
+ # Device Drivers
+diff -Naur linux-2.6.15.orig/arch/mips/configs/sb1250-swarm_defconfig linux-2.6.15/arch/mips/configs/sb1250-swarm_defconfig
+--- linux-2.6.15.orig/arch/mips/configs/sb1250-swarm_defconfig	2006-01-03 03:21:10.000000000 +0000
++++ linux-2.6.15/arch/mips/configs/sb1250-swarm_defconfig	2006-01-09 19:54:12.000000000 +0000
+@@ -1,7 +1,7 @@
+ #
+ # Automatically generated make config: don't edit
+-# Linux kernel version: 2.6.15-rc2
+-# Thu Nov 24 01:07:09 2005
++# Linux kernel version: 2.6.15-rc5
++# Sat Dec 17 18:03:47 2005
+ #
+ CONFIG_MIPS=y
+ 
+@@ -133,7 +133,6 @@
+ # CONFIG_MIPS_MT is not set
+ CONFIG_SB1_PASS_1_WORKAROUNDS=y
+ CONFIG_CPU_HAS_LLSC=y
+-CONFIG_CPU_HAS_LLDSCD=y
+ CONFIG_CPU_HAS_SYNC=y
+ CONFIG_GENERIC_HARDIRQS=y
+ CONFIG_GENERIC_IRQ_PROBE=y
+@@ -179,6 +178,7 @@
+ # CONFIG_IKCONFIG is not set
+ CONFIG_CPUSETS=y
+ CONFIG_INITRAMFS_SOURCE=""
++# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+ CONFIG_EMBEDDED=y
+ CONFIG_KALLSYMS=y
+ # CONFIG_KALLSYMS_EXTRA_PASS is not set
+@@ -187,7 +187,6 @@
+ CONFIG_BASE_FULL=y
+ CONFIG_FUTEX=y
+ CONFIG_EPOLL=y
+-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+ CONFIG_SHMEM=y
+ CONFIG_CC_ALIGN_FUNCTIONS=0
+ CONFIG_CC_ALIGN_LABELS=0
+@@ -330,7 +329,6 @@
+ # CONFIG_IEEE80211_DEBUG is not set
+ CONFIG_IEEE80211_CRYPT_WEP=m
+ CONFIG_IEEE80211_CRYPT_CCMP=m
+-CONFIG_IEEE80211_CRYPT_TKIP=m
+ 
+ #
+ # Device Drivers
+diff -Naur linux-2.6.15.orig/arch/mips/configs/sead_defconfig linux-2.6.15/arch/mips/configs/sead_defconfig
+--- linux-2.6.15.orig/arch/mips/configs/sead_defconfig	2006-01-03 03:21:10.000000000 +0000
++++ linux-2.6.15/arch/mips/configs/sead_defconfig	2006-01-09 19:54:12.000000000 +0000
+@@ -1,7 +1,7 @@
+ #
+ # Automatically generated make config: don't edit
+-# Linux kernel version: 2.6.15-rc2
+-# Thu Nov 24 01:07:10 2005
++# Linux kernel version: 2.6.15-rc5
++# Sat Dec 17 18:03:49 2005
+ #
+ CONFIG_MIPS=y
+ 
+@@ -156,6 +156,7 @@
+ # CONFIG_HOTPLUG is not set
+ # CONFIG_IKCONFIG is not set
+ CONFIG_INITRAMFS_SOURCE=""
++# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+ CONFIG_EMBEDDED=y
+ CONFIG_KALLSYMS=y
+ # CONFIG_KALLSYMS_EXTRA_PASS is not set
+@@ -164,7 +165,6 @@
+ CONFIG_BASE_FULL=y
+ CONFIG_FUTEX=y
+ CONFIG_EPOLL=y
+-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+ CONFIG_SHMEM=y
+ CONFIG_CC_ALIGN_FUNCTIONS=0
+ CONFIG_CC_ALIGN_LABELS=0
+diff -Naur linux-2.6.15.orig/arch/mips/configs/tb0226_defconfig linux-2.6.15/arch/mips/configs/tb0226_defconfig
+--- linux-2.6.15.orig/arch/mips/configs/tb0226_defconfig	2006-01-03 03:21:10.000000000 +0000
++++ linux-2.6.15/arch/mips/configs/tb0226_defconfig	2006-01-09 19:54:12.000000000 +0000
+@@ -1,7 +1,7 @@
+ #
+ # Automatically generated make config: don't edit
+-# Linux kernel version: 2.6.15-rc2
+-# Thu Nov 24 01:07:12 2005
++# Linux kernel version: 2.6.15-rc5
++# Sat Dec 17 18:03:51 2005
+ #
+ CONFIG_MIPS=y
+ 
+@@ -160,6 +160,7 @@
+ CONFIG_KOBJECT_UEVENT=y
+ # CONFIG_IKCONFIG is not set
+ CONFIG_INITRAMFS_SOURCE=""
++# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+ CONFIG_EMBEDDED=y
+ CONFIG_KALLSYMS=y
+ # CONFIG_KALLSYMS_EXTRA_PASS is not set
+@@ -168,7 +169,6 @@
+ CONFIG_BASE_FULL=y
+ CONFIG_FUTEX=y
+ CONFIG_EPOLL=y
+-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+ CONFIG_SHMEM=y
+ CONFIG_CC_ALIGN_FUNCTIONS=0
+ CONFIG_CC_ALIGN_LABELS=0
+@@ -313,7 +313,6 @@
+ # CONFIG_IEEE80211_DEBUG is not set
+ CONFIG_IEEE80211_CRYPT_WEP=m
+ CONFIG_IEEE80211_CRYPT_CCMP=m
+-CONFIG_IEEE80211_CRYPT_TKIP=m
+ 
+ #
+ # Device Drivers
+diff -Naur linux-2.6.15.orig/arch/mips/configs/tb0229_defconfig linux-2.6.15/arch/mips/configs/tb0229_defconfig
+--- linux-2.6.15.orig/arch/mips/configs/tb0229_defconfig	2006-01-03 03:21:10.000000000 +0000
++++ linux-2.6.15/arch/mips/configs/tb0229_defconfig	2006-01-09 19:54:12.000000000 +0000
+@@ -1,7 +1,7 @@
+ #
+ # Automatically generated make config: don't edit
+-# Linux kernel version: 2.6.15-rc2
+-# Thu Nov 24 01:07:15 2005
++# Linux kernel version: 2.6.15-rc5
++# Sat Dec 17 18:03:54 2005
+ #
+ CONFIG_MIPS=y
+ 
+@@ -160,6 +160,7 @@
+ CONFIG_KOBJECT_UEVENT=y
+ # CONFIG_IKCONFIG is not set
+ CONFIG_INITRAMFS_SOURCE=""
++# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+ CONFIG_EMBEDDED=y
+ CONFIG_KALLSYMS=y
+ # CONFIG_KALLSYMS_EXTRA_PASS is not set
+@@ -168,7 +169,6 @@
+ CONFIG_BASE_FULL=y
+ CONFIG_FUTEX=y
+ CONFIG_EPOLL=y
+-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+ CONFIG_SHMEM=y
+ CONFIG_CC_ALIGN_FUNCTIONS=0
+ CONFIG_CC_ALIGN_LABELS=0
+@@ -314,7 +314,6 @@
+ # CONFIG_IEEE80211_DEBUG is not set
+ CONFIG_IEEE80211_CRYPT_WEP=m
+ CONFIG_IEEE80211_CRYPT_CCMP=m
+-CONFIG_IEEE80211_CRYPT_TKIP=m
+ 
+ #
+ # Device Drivers
+diff -Naur linux-2.6.15.orig/arch/mips/configs/tb0287_defconfig linux-2.6.15/arch/mips/configs/tb0287_defconfig
+--- linux-2.6.15.orig/arch/mips/configs/tb0287_defconfig	2006-01-03 03:21:10.000000000 +0000
++++ linux-2.6.15/arch/mips/configs/tb0287_defconfig	1970-01-01 00:00:00.000000000 +0000
+@@ -1,1105 +0,0 @@
+-#
+-# Automatically generated make config: don't edit
+-# Linux kernel version: 2.6.14-rc5-mm1
+-# Tue Oct 25 00:20:22 2005
+-#
+-CONFIG_MIPS=y
+-
+-#
+-# Code maturity level options
+-#
+-CONFIG_EXPERIMENTAL=y
+-CONFIG_CLEAN_COMPILE=y
+-CONFIG_BROKEN_ON_SMP=y
+-CONFIG_INIT_ENV_ARG_LIMIT=32
+-
+-#
+-# General setup
+-#
+-CONFIG_LOCALVERSION=""
+-CONFIG_LOCALVERSION_AUTO=y
+-CONFIG_SWAP=y
+-CONFIG_SWAP_PREFETCH=y
+-CONFIG_SYSVIPC=y
+-# CONFIG_POSIX_MQUEUE is not set
+-# CONFIG_BSD_PROCESS_ACCT is not set
+-CONFIG_SYSCTL=y
+-# CONFIG_AUDIT is not set
+-# CONFIG_HOTPLUG is not set
+-CONFIG_KOBJECT_UEVENT=y
+-# CONFIG_IKCONFIG is not set
+-CONFIG_INITRAMFS_SOURCE=""
+-CONFIG_EMBEDDED=y
+-CONFIG_KALLSYMS=y
+-# CONFIG_KALLSYMS_EXTRA_PASS is not set
+-CONFIG_PRINTK=y
+-CONFIG_BUG=y
+-CONFIG_BASE_FULL=y
+-CONFIG_FUTEX=y
+-CONFIG_EPOLL=y
+-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+-CONFIG_SHMEM=y
+-CONFIG_CC_ALIGN_FUNCTIONS=0
+-CONFIG_CC_ALIGN_LABELS=0
+-CONFIG_CC_ALIGN_LOOPS=0
+-CONFIG_CC_ALIGN_JUMPS=0
+-# CONFIG_TINY_SHMEM is not set
+-CONFIG_BASE_SMALL=0
+-
+-#
+-# Loadable module support
+-#
+-CONFIG_MODULES=y
+-CONFIG_MODULE_UNLOAD=y
+-# CONFIG_MODULE_FORCE_UNLOAD is not set
+-CONFIG_OBSOLETE_MODPARM=y
+-CONFIG_MODVERSIONS=y
+-CONFIG_MODULE_SRCVERSION_ALL=y
+-CONFIG_KMOD=y
+-
+-#
+-# Machine selection
+-#
+-# CONFIG_MIPS_MTX1 is not set
+-# CONFIG_MIPS_BOSPORUS is not set
+-# CONFIG_MIPS_PB1000 is not set
+-# CONFIG_MIPS_PB1100 is not set
+-# CONFIG_MIPS_PB1500 is not set
+-# CONFIG_MIPS_PB1550 is not set
+-# CONFIG_MIPS_PB1200 is not set
+-# CONFIG_MIPS_DB1000 is not set
+-# CONFIG_MIPS_DB1100 is not set
+-# CONFIG_MIPS_DB1500 is not set
+-# CONFIG_MIPS_DB1550 is not set
+-# CONFIG_MIPS_DB1200 is not set
+-# CONFIG_MIPS_MIRAGE is not set
+-# CONFIG_MIPS_COBALT is not set
+-# CONFIG_MACH_DECSTATION is not set
+-# CONFIG_MIPS_EV64120 is not set
+-# CONFIG_MIPS_EV96100 is not set
+-# CONFIG_MIPS_IVR is not set
+-# CONFIG_MIPS_ITE8172 is not set
+-# CONFIG_MACH_JAZZ is not set
+-# CONFIG_LASAT is not set
+-# CONFIG_MIPS_ATLAS is not set
+-# CONFIG_MIPS_MALTA is not set
+-# CONFIG_MIPS_SEAD is not set
+-# CONFIG_MIPS_SIM is not set
+-# CONFIG_MOMENCO_JAGUAR_ATX is not set
+-# CONFIG_MOMENCO_OCELOT is not set
+-# CONFIG_MOMENCO_OCELOT_3 is not set
+-# CONFIG_MOMENCO_OCELOT_C is not set
+-# CONFIG_MOMENCO_OCELOT_G is not set
+-# CONFIG_MIPS_XXS1500 is not set
+-# CONFIG_PNX8550_V2PCI is not set
+-# CONFIG_PNX8550_JBS is not set
+-# CONFIG_DDB5074 is not set
+-# CONFIG_DDB5476 is not set
+-# CONFIG_DDB5477 is not set
+-CONFIG_MACH_VR41XX=y
+-# CONFIG_PMC_YOSEMITE is not set
+-# CONFIG_QEMU is not set
+-# CONFIG_SGI_IP22 is not set
+-# CONFIG_SGI_IP27 is not set
+-# CONFIG_SGI_IP32 is not set
+-# CONFIG_SIBYTE_SWARM is not set
+-# CONFIG_SIBYTE_SENTOSA is not set
+-# CONFIG_SIBYTE_RHONE is not set
+-# CONFIG_SIBYTE_CARMEL is not set
+-# CONFIG_SIBYTE_PTSWARM is not set
+-# CONFIG_SIBYTE_LITTLESUR is not set
+-# CONFIG_SIBYTE_CRHINE is not set
+-# CONFIG_SIBYTE_CRHONE is not set
+-# CONFIG_SNI_RM200_PCI is not set
+-# CONFIG_TOSHIBA_JMR3927 is not set
+-# CONFIG_TOSHIBA_RBTX4927 is not set
+-# CONFIG_TOSHIBA_RBTX4938 is not set
+-# CONFIG_CASIO_E55 is not set
+-# CONFIG_IBM_WORKPAD is not set
+-# CONFIG_NEC_CMBVR4133 is not set
+-CONFIG_TANBAC_TB022X=y
+-# CONFIG_TANBAC_TB0226 is not set
+-CONFIG_TANBAC_TB0287=y
+-# CONFIG_VICTOR_MPC30X is not set
+-# CONFIG_ZAO_CAPCELLA is not set
+-CONFIG_PCI_VR41XX=y
+-# CONFIG_VRC4173 is not set
+-CONFIG_RWSEM_GENERIC_SPINLOCK=y
+-CONFIG_GENERIC_CALIBRATE_DELAY=y
+-CONFIG_DMA_NONCOHERENT=y
+-CONFIG_DMA_NEED_PCI_MAP_STATE=y
+-# CONFIG_CPU_BIG_ENDIAN is not set
+-CONFIG_CPU_LITTLE_ENDIAN=y
+-CONFIG_SYS_SUPPORTS_LITTLE_ENDIAN=y
+-CONFIG_IRQ_CPU=y
+-CONFIG_MIPS_L1_CACHE_SHIFT=5
+-
+-#
+-# CPU selection
+-#
+-# CONFIG_CPU_MIPS32_R1 is not set
+-# CONFIG_CPU_MIPS32_R2 is not set
+-# CONFIG_CPU_MIPS64_R1 is not set
+-# CONFIG_CPU_MIPS64_R2 is not set
+-# CONFIG_CPU_R3000 is not set
+-# CONFIG_CPU_TX39XX is not set
+-CONFIG_CPU_VR41XX=y
+-# CONFIG_CPU_R4300 is not set
+-# CONFIG_CPU_R4X00 is not set
+-# CONFIG_CPU_TX49XX is not set
+-# CONFIG_CPU_R5000 is not set
+-# CONFIG_CPU_R5432 is not set
+-# CONFIG_CPU_R6000 is not set
+-# CONFIG_CPU_NEVADA is not set
+-# CONFIG_CPU_R8000 is not set
+-# CONFIG_CPU_R10000 is not set
+-# CONFIG_CPU_RM7000 is not set
+-# CONFIG_CPU_RM9000 is not set
+-# CONFIG_CPU_SB1 is not set
+-CONFIG_SYS_SUPPORTS_32BIT_KERNEL=y
+-CONFIG_SYS_SUPPORTS_64BIT_KERNEL=y
+-CONFIG_CPU_SUPPORTS_32BIT_KERNEL=y
+-CONFIG_CPU_SUPPORTS_64BIT_KERNEL=y
+-
+-#
+-# Kernel type
+-#
+-CONFIG_32BIT=y
+-# CONFIG_64BIT is not set
+-CONFIG_PAGE_SIZE_4KB=y
+-# CONFIG_PAGE_SIZE_8KB is not set
+-# CONFIG_PAGE_SIZE_16KB is not set
+-# CONFIG_PAGE_SIZE_64KB is not set
+-# CONFIG_MIPS_MT is not set
+-# CONFIG_CPU_ADVANCED is not set
+-CONFIG_CPU_HAS_SYNC=y
+-CONFIG_GENERIC_HARDIRQS=y
+-CONFIG_GENERIC_IRQ_PROBE=y
+-CONFIG_ARCH_FLATMEM_ENABLE=y
+-CONFIG_SELECT_MEMORY_MODEL=y
+-CONFIG_FLATMEM_MANUAL=y
+-# CONFIG_DISCONTIGMEM_MANUAL is not set
+-# CONFIG_SPARSEMEM_MANUAL is not set
+-CONFIG_FLATMEM=y
+-CONFIG_FLAT_NODE_MEM_MAP=y
+-# CONFIG_SPARSEMEM_STATIC is not set
+-CONFIG_SPLIT_PTLOCK_CPUS=4
+-CONFIG_PREEMPT_NONE=y
+-# CONFIG_PREEMPT_VOLUNTARY is not set
+-# CONFIG_PREEMPT is not set
+-
+-#
+-# Bus options (PCI, PCMCIA, EISA, ISA, TC)
+-#
+-CONFIG_HW_HAS_PCI=y
+-CONFIG_PCI=y
+-# CONFIG_PCI_LEGACY_PROC is not set
+-CONFIG_MMU=y
+-
+-#
+-# PCCARD (PCMCIA/CardBus) support
+-#
+-# CONFIG_PCCARD is not set
+-
+-#
+-# PCI Hotplug Support
+-#
+-# CONFIG_HOTPLUG_PCI is not set
+-
+-#
+-# Executable file formats
+-#
+-CONFIG_BINFMT_ELF=y
+-# CONFIG_BINFMT_MISC is not set
+-CONFIG_TRAD_SIGNALS=y
+-
+-#
+-# Networking
+-#
+-CONFIG_NET=y
+-
+-#
+-# Networking options
+-#
+-CONFIG_PACKET=y
+-# CONFIG_PACKET_MMAP is not set
+-CONFIG_UNIX=y
+-CONFIG_XFRM=y
+-CONFIG_XFRM_USER=m
+-# CONFIG_NET_KEY is not set
+-CONFIG_INET=y
+-CONFIG_IP_MULTICAST=y
+-CONFIG_IP_ADVANCED_ROUTER=y
+-CONFIG_ASK_IP_FIB_HASH=y
+-# CONFIG_IP_FIB_TRIE is not set
+-CONFIG_IP_FIB_HASH=y
+-CONFIG_IP_MULTIPLE_TABLES=y
+-CONFIG_IP_ROUTE_MULTIPATH=y
+-# CONFIG_IP_ROUTE_MULTIPATH_CACHED is not set
+-CONFIG_IP_ROUTE_VERBOSE=y
+-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=m
+-CONFIG_NET_IPGRE=m
+-# CONFIG_NET_IPGRE_BROADCAST is not set
+-# CONFIG_IP_MROUTE is not set
+-# CONFIG_ARPD is not set
+-CONFIG_SYN_COOKIES=y
+-# CONFIG_INET_AH is not set
+-# CONFIG_INET_ESP is not set
+-# CONFIG_INET_IPCOMP is not set
+-CONFIG_INET_TUNNEL=m
+-CONFIG_INET_DIAG=y
+-CONFIG_INET_TCP_DIAG=y
+-CONFIG_TCP_CONG_ADVANCED=y
+-
+-#
+-# TCP congestion control
+-#
+-CONFIG_TCP_CONG_BIC=y
+-CONFIG_TCP_CONG_WESTWOOD=m
+-CONFIG_TCP_CONG_HTCP=m
+-# CONFIG_TCP_CONG_HSTCP is not set
+-# CONFIG_TCP_CONG_HYBLA is not set
+-# CONFIG_TCP_CONG_VEGAS is not set
+-# CONFIG_TCP_CONG_SCALABLE is not set
+-# CONFIG_IPV6 is not set
+-# CONFIG_NETFILTER is not set
+-
+-#
+-# DCCP Configuration (EXPERIMENTAL)
+-#
+-# CONFIG_IP_DCCP is not set
+-
+-#
+-# SCTP Configuration (EXPERIMENTAL)
+-#
+-# CONFIG_IP_SCTP is not set
+-# CONFIG_ATM is not set
+-# CONFIG_BRIDGE is not set
+-# CONFIG_VLAN_8021Q is not set
+-# CONFIG_DECNET is not set
+-# CONFIG_LLC2 is not set
+-# CONFIG_IPX is not set
+-# CONFIG_ATALK is not set
+-# CONFIG_X25 is not set
+-# CONFIG_LAPB is not set
+-# CONFIG_NET_DIVERT is not set
+-# CONFIG_ECONET is not set
+-# CONFIG_WAN_ROUTER is not set
+-# CONFIG_NET_SCHED is not set
+-# CONFIG_NET_CLS_ROUTE is not set
+-
+-#
+-# Network testing
+-#
+-# CONFIG_NET_PKTGEN is not set
+-# CONFIG_HAMRADIO is not set
+-# CONFIG_IRDA is not set
+-# CONFIG_BT is not set
+-# CONFIG_IEEE80211 is not set
+-
+-#
+-# Device Drivers
+-#
+-
+-#
+-# Generic Driver Options
+-#
+-CONFIG_STANDALONE=y
+-CONFIG_PREVENT_FIRMWARE_BUILD=y
+-# CONFIG_FW_LOADER is not set
+-
+-#
+-# Connector - unified userspace <-> kernelspace linker
+-#
+-# CONFIG_CONNECTOR is not set
+-
+-#
+-# Memory Technology Devices (MTD)
+-#
+-# CONFIG_MTD is not set
+-
+-#
+-# Parallel port support
+-#
+-# CONFIG_PARPORT is not set
+-
+-#
+-# Plug and Play support
+-#
+-
+-#
+-# Block devices
+-#
+-# CONFIG_BLK_CPQ_DA is not set
+-# CONFIG_BLK_CPQ_CISS_DA is not set
+-# CONFIG_BLK_DEV_DAC960 is not set
+-# CONFIG_BLK_DEV_UMEM is not set
+-# CONFIG_BLK_DEV_COW_COMMON is not set
+-CONFIG_BLK_DEV_LOOP=m
+-# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+-CONFIG_BLK_DEV_NBD=m
+-# CONFIG_BLK_DEV_SX8 is not set
+-# CONFIG_BLK_DEV_UB is not set
+-CONFIG_BLK_DEV_RAM=y
+-CONFIG_BLK_DEV_RAM_COUNT=16
+-CONFIG_BLK_DEV_RAM_SIZE=4096
+-# CONFIG_BLK_DEV_INITRD is not set
+-# CONFIG_LBD is not set
+-# CONFIG_BLK_DEV_IO_TRACE is not set
+-# CONFIG_CDROM_PKTCDVD is not set
+-
+-#
+-# IO Schedulers
+-#
+-CONFIG_IOSCHED_NOOP=y
+-CONFIG_IOSCHED_AS=y
+-CONFIG_IOSCHED_DEADLINE=y
+-CONFIG_IOSCHED_CFQ=y
+-CONFIG_DEFAULT_AS=y
+-# CONFIG_DEFAULT_DEADLINE is not set
+-# CONFIG_DEFAULT_CFQ is not set
+-# CONFIG_DEFAULT_NOOP is not set
+-CONFIG_DEFAULT_IOSCHED="anticipatory"
+-# CONFIG_ATA_OVER_ETH is not set
+-
+-#
+-# ATA/ATAPI/MFM/RLL support
+-#
+-CONFIG_IDE=y
+-CONFIG_BLK_DEV_IDE=y
+-
+-#
+-# Please see Documentation/ide.txt for help/info on IDE drives
+-#
+-# CONFIG_BLK_DEV_IDE_SATA is not set
+-CONFIG_BLK_DEV_IDEDISK=y
+-# CONFIG_IDEDISK_MULTI_MODE is not set
+-# CONFIG_BLK_DEV_IDECD is not set
+-# CONFIG_BLK_DEV_IDETAPE is not set
+-# CONFIG_BLK_DEV_IDEFLOPPY is not set
+-# CONFIG_BLK_DEV_IDESCSI is not set
+-# CONFIG_IDE_TASK_IOCTL is not set
+-
+-#
+-# IDE chipset support/bugfixes
+-#
+-CONFIG_IDE_GENERIC=y
+-CONFIG_BLK_DEV_IDEPCI=y
+-# CONFIG_IDEPCI_SHARE_IRQ is not set
+-# CONFIG_BLK_DEV_OFFBOARD is not set
+-# CONFIG_BLK_DEV_GENERIC is not set
+-# CONFIG_BLK_DEV_OPTI621 is not set
+-CONFIG_BLK_DEV_IDEDMA_PCI=y
+-# CONFIG_BLK_DEV_IDEDMA_FORCED is not set
+-# CONFIG_IDEDMA_PCI_AUTO is not set
+-# CONFIG_BLK_DEV_AEC62XX is not set
+-# CONFIG_BLK_DEV_ALI15X3 is not set
+-# CONFIG_BLK_DEV_AMD74XX is not set
+-# CONFIG_BLK_DEV_CMD64X is not set
+-# CONFIG_BLK_DEV_TRIFLEX is not set
+-# CONFIG_BLK_DEV_CY82C693 is not set
+-# CONFIG_BLK_DEV_CS5520 is not set
+-# CONFIG_BLK_DEV_CS5530 is not set
+-# CONFIG_BLK_DEV_HPT34X is not set
+-# CONFIG_BLK_DEV_HPT366 is not set
+-# CONFIG_BLK_DEV_SC1200 is not set
+-# CONFIG_BLK_DEV_PIIX is not set
+-# CONFIG_BLK_DEV_IT821X is not set
+-# CONFIG_BLK_DEV_NS87415 is not set
+-# CONFIG_BLK_DEV_PDC202XX_OLD is not set
+-# CONFIG_BLK_DEV_PDC202XX_NEW is not set
+-# CONFIG_BLK_DEV_SVWKS is not set
+-CONFIG_BLK_DEV_SIIMAGE=y
+-# CONFIG_BLK_DEV_SLC90E66 is not set
+-# CONFIG_BLK_DEV_TRM290 is not set
+-# CONFIG_BLK_DEV_VIA82CXXX is not set
+-# CONFIG_IDE_ARM is not set
+-CONFIG_BLK_DEV_IDEDMA=y
+-# CONFIG_IDEDMA_IVB is not set
+-# CONFIG_IDEDMA_AUTO is not set
+-# CONFIG_BLK_DEV_HD is not set
+-
+-#
+-# SCSI device support
+-#
+-# CONFIG_RAID_ATTRS is not set
+-CONFIG_SCSI=y
+-CONFIG_SCSI_PROC_FS=y
+-
+-#
+-# SCSI support type (disk, tape, CD-ROM)
+-#
+-CONFIG_BLK_DEV_SD=y
+-# CONFIG_CHR_DEV_ST is not set
+-# CONFIG_CHR_DEV_OSST is not set
+-# CONFIG_BLK_DEV_SR is not set
+-# CONFIG_CHR_DEV_SG is not set
+-# CONFIG_CHR_DEV_SCH is not set
+-
+-#
+-# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+-#
+-# CONFIG_SCSI_MULTI_LUN is not set
+-# CONFIG_SCSI_CONSTANTS is not set
+-# CONFIG_SCSI_LOGGING is not set
+-
+-#
+-# SCSI Transport Attributes
+-#
+-# CONFIG_SCSI_SPI_ATTRS is not set
+-# CONFIG_SCSI_FC_ATTRS is not set
+-# CONFIG_SCSI_ISCSI_ATTRS is not set
+-# CONFIG_SCSI_SAS_ATTRS is not set
+-
+-#
+-# SCSI Transport Layers
+-#
+-# CONFIG_SAS_CLASS is not set
+-
+-#
+-# SCSI low-level drivers
+-#
+-# CONFIG_ISCSI_TCP is not set
+-# CONFIG_SCSI_ARCMSR is not set
+-# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
+-# CONFIG_SCSI_3W_9XXX is not set
+-# CONFIG_SCSI_ACARD is not set
+-# CONFIG_SCSI_AACRAID is not set
+-# CONFIG_SCSI_AIC7XXX is not set
+-# CONFIG_SCSI_AIC7XXX_OLD is not set
+-# CONFIG_SCSI_AIC79XX is not set
+-# CONFIG_SCSI_DPT_I2O is not set
+-# CONFIG_MEGARAID_NEWGEN is not set
+-# CONFIG_MEGARAID_LEGACY is not set
+-# CONFIG_MEGARAID_SAS is not set
+-# CONFIG_SCSI_SATA is not set
+-# CONFIG_SCSI_DMX3191D is not set
+-# CONFIG_SCSI_FUTURE_DOMAIN is not set
+-# CONFIG_SCSI_IPS is not set
+-# CONFIG_SCSI_INITIO is not set
+-# CONFIG_SCSI_INIA100 is not set
+-# CONFIG_SCSI_SYM53C8XX_2 is not set
+-# CONFIG_SCSI_IPR is not set
+-# CONFIG_SCSI_QLOGIC_FC is not set
+-# CONFIG_SCSI_QLOGIC_1280 is not set
+-CONFIG_SCSI_QLA2XXX=y
+-# CONFIG_SCSI_QLA21XX is not set
+-# CONFIG_SCSI_QLA22XX is not set
+-# CONFIG_SCSI_QLA2300 is not set
+-# CONFIG_SCSI_QLA2322 is not set
+-# CONFIG_SCSI_QLA6312 is not set
+-# CONFIG_SCSI_QLA24XX is not set
+-# CONFIG_SCSI_LPFC is not set
+-# CONFIG_SCSI_DC395x is not set
+-# CONFIG_SCSI_DC390T is not set
+-# CONFIG_SCSI_NSP32 is not set
+-# CONFIG_SCSI_DEBUG is not set
+-
+-#
+-# Multi-device support (RAID and LVM)
+-#
+-# CONFIG_MD is not set
+-
+-#
+-# Fusion MPT device support
+-#
+-# CONFIG_FUSION is not set
+-# CONFIG_FUSION_SPI is not set
+-# CONFIG_FUSION_FC is not set
+-# CONFIG_FUSION_SAS is not set
+-
+-#
+-# IEEE 1394 (FireWire) support
+-#
+-CONFIG_IEEE1394=m
+-
+-#
+-# Subsystem Options
+-#
+-# CONFIG_IEEE1394_VERBOSEDEBUG is not set
+-# CONFIG_IEEE1394_OUI_DB is not set
+-CONFIG_IEEE1394_EXTRA_CONFIG_ROMS=y
+-CONFIG_IEEE1394_CONFIG_ROM_IP1394=y
+-# CONFIG_IEEE1394_EXPORT_FULL_API is not set
+-
+-#
+-# Device Drivers
+-#
+-
+-#
+-# Texas Instruments PCILynx requires I2C
+-#
+-CONFIG_IEEE1394_OHCI1394=m
+-
+-#
+-# Protocol Drivers
+-#
+-CONFIG_IEEE1394_VIDEO1394=m
+-CONFIG_IEEE1394_SBP2=m
+-# CONFIG_IEEE1394_SBP2_PHYS_DMA is not set
+-CONFIG_IEEE1394_ETH1394=m
+-CONFIG_IEEE1394_DV1394=m
+-CONFIG_IEEE1394_RAWIO=m
+-CONFIG_IEEE1394_CMP=m
+-CONFIG_IEEE1394_AMDTP=m
+-
+-#
+-# I2O device support
+-#
+-# CONFIG_I2O is not set
+-
+-#
+-# Network device support
+-#
+-CONFIG_NETDEVICES=y
+-CONFIG_DUMMY=m
+-# CONFIG_BONDING is not set
+-# CONFIG_EQUALIZER is not set
+-# CONFIG_TUN is not set
+-
+-#
+-# ARCnet devices
+-#
+-# CONFIG_ARCNET is not set
+-
+-#
+-# PHY device support
+-#
+-# CONFIG_PHYLIB is not set
+-
+-#
+-# Ethernet (10 or 100Mbit)
+-#
+-CONFIG_NET_ETHERNET=y
+-CONFIG_MII=y
+-# CONFIG_HAPPYMEAL is not set
+-# CONFIG_SUNGEM is not set
+-# CONFIG_CASSINI is not set
+-# CONFIG_NET_VENDOR_3COM is not set
+-
+-#
+-# Tulip family network device support
+-#
+-# CONFIG_NET_TULIP is not set
+-# CONFIG_HP100 is not set
+-# CONFIG_NET_PCI is not set
+-
+-#
+-# Ethernet (1000 Mbit)
+-#
+-# CONFIG_ACENIC is not set
+-# CONFIG_DL2K is not set
+-# CONFIG_E1000 is not set
+-# CONFIG_NS83820 is not set
+-# CONFIG_HAMACHI is not set
+-# CONFIG_YELLOWFIN is not set
+-CONFIG_R8169=y
+-# CONFIG_R8169_NAPI is not set
+-# CONFIG_SIS190 is not set
+-# CONFIG_SKGE is not set
+-# CONFIG_SKY2 is not set
+-# CONFIG_SK98LIN is not set
+-# CONFIG_TIGON3 is not set
+-# CONFIG_BNX2 is not set
+-
+-#
+-# Ethernet (10000 Mbit)
+-#
+-# CONFIG_CHELSIO_T1 is not set
+-# CONFIG_IXGB is not set
+-# CONFIG_S2IO is not set
+-
+-#
+-# Token Ring devices
+-#
+-# CONFIG_TR is not set
+-
+-#
+-# Wireless LAN (non-hamradio)
+-#
+-# CONFIG_NET_RADIO is not set
+-# CONFIG_HOSTAP is not set
+-
+-#
+-# Wan interfaces
+-#
+-# CONFIG_WAN is not set
+-# CONFIG_FDDI is not set
+-# CONFIG_HIPPI is not set
+-# CONFIG_PPP is not set
+-# CONFIG_SLIP is not set
+-# CONFIG_NET_FC is not set
+-# CONFIG_SHAPER is not set
+-# CONFIG_NETCONSOLE is not set
+-# CONFIG_KGDBOE is not set
+-# CONFIG_NETPOLL is not set
+-# CONFIG_NETPOLL_RX is not set
+-# CONFIG_NETPOLL_TRAP is not set
+-# CONFIG_NET_POLL_CONTROLLER is not set
+-
+-#
+-# ISDN subsystem
+-#
+-# CONFIG_ISDN is not set
+-
+-#
+-# Telephony Support
+-#
+-# CONFIG_PHONE is not set
+-
+-#
+-# Input device support
+-#
+-CONFIG_INPUT=y
+-
+-#
+-# Userland interfaces
+-#
+-# CONFIG_INPUT_MOUSEDEV is not set
+-# CONFIG_INPUT_JOYDEV is not set
+-# CONFIG_INPUT_TSDEV is not set
+-# CONFIG_INPUT_EVDEV is not set
+-# CONFIG_INPUT_EVBUG is not set
+-
+-#
+-# Input Device Drivers
+-#
+-# CONFIG_INPUT_KEYBOARD is not set
+-# CONFIG_INPUT_MOUSE is not set
+-# CONFIG_INPUT_JOYSTICK is not set
+-# CONFIG_INPUT_TOUCHSCREEN is not set
+-# CONFIG_INPUT_MISC is not set
+-
+-#
+-# Hardware I/O ports
+-#
+-# CONFIG_SERIO is not set
+-# CONFIG_GAMEPORT is not set
+-
+-#
+-# Character devices
+-#
+-CONFIG_VT=y
+-CONFIG_VT_CONSOLE=y
+-CONFIG_HW_CONSOLE=y
+-# CONFIG_SERIAL_NONSTANDARD is not set
+-
+-#
+-# Serial drivers
+-#
+-# CONFIG_SERIAL_8250 is not set
+-
+-#
+-# Non-8250 serial port support
+-#
+-CONFIG_SERIAL_CORE=y
+-CONFIG_SERIAL_CORE_CONSOLE=y
+-CONFIG_SERIAL_VR41XX=y
+-CONFIG_SERIAL_VR41XX_CONSOLE=y
+-# CONFIG_SERIAL_JSM is not set
+-CONFIG_UNIX98_PTYS=y
+-CONFIG_LEGACY_PTYS=y
+-CONFIG_LEGACY_PTY_COUNT=256
+-
+-#
+-# IPMI
+-#
+-# CONFIG_IPMI_HANDLER is not set
+-
+-#
+-# Watchdog Cards
+-#
+-# CONFIG_WATCHDOG is not set
+-# CONFIG_RTC is not set
+-# CONFIG_GEN_RTC is not set
+-# CONFIG_RTC_VR41XX is not set
+-# CONFIG_DTLK is not set
+-# CONFIG_R3964 is not set
+-# CONFIG_APPLICOM is not set
+-# CONFIG_TANBAC_TB0219 is not set
+-
+-#
+-# Ftape, the floppy tape device driver
+-#
+-# CONFIG_DRM is not set
+-CONFIG_GPIO_VR41XX=y
+-# CONFIG_RAW_DRIVER is not set
+-
+-#
+-# TPM devices
+-#
+-# CONFIG_TCG_TPM is not set
+-# CONFIG_TELCLOCK is not set
+-
+-#
+-# I2C support
+-#
+-# CONFIG_I2C is not set
+-
+-#
+-# Dallas's 1-wire bus
+-#
+-# CONFIG_W1 is not set
+-
+-#
+-# Hardware Monitoring support
+-#
+-# CONFIG_HWMON is not set
+-# CONFIG_HWMON_VID is not set
+-
+-#
+-# Misc devices
+-#
+-
+-#
+-# Multimedia Capabilities Port drivers
+-#
+-
+-#
+-# Multimedia devices
+-#
+-# CONFIG_VIDEO_DEV is not set
+-
+-#
+-# Digital Video Broadcasting Devices
+-#
+-# CONFIG_DVB is not set
+-
+-#
+-# Graphics support
+-#
+-# CONFIG_FB is not set
+-
+-#
+-# Console display driver support
+-#
+-# CONFIG_VGA_CONSOLE is not set
+-CONFIG_DUMMY_CONSOLE=y
+-
+-#
+-# Speakup console speech
+-#
+-# CONFIG_SPEAKUP is not set
+-
+-#
+-# Sound
+-#
+-# CONFIG_SOUND is not set
+-
+-#
+-# USB support
+-#
+-CONFIG_USB_ARCH_HAS_HCD=y
+-CONFIG_USB_ARCH_HAS_OHCI=y
+-CONFIG_USB=m
+-# CONFIG_USB_DEBUG is not set
+-
+-#
+-# Miscellaneous USB options
+-#
+-# CONFIG_USB_DEVICEFS is not set
+-# CONFIG_USB_BANDWIDTH is not set
+-# CONFIG_USB_DYNAMIC_MINORS is not set
+-# CONFIG_USB_OTG is not set
+-
+-#
+-# USB Host Controller Drivers
+-#
+-CONFIG_USB_EHCI_HCD=m
+-# CONFIG_USB_EHCI_SPLIT_ISO is not set
+-# CONFIG_USB_EHCI_ROOT_HUB_TT is not set
+-# CONFIG_USB_ISP116X_HCD is not set
+-CONFIG_USB_OHCI_HCD=m
+-# CONFIG_USB_OHCI_BIG_ENDIAN is not set
+-CONFIG_USB_OHCI_LITTLE_ENDIAN=y
+-# CONFIG_USB_UHCI_HCD is not set
+-# CONFIG_USB_SL811_HCD is not set
+-
+-#
+-# USB Device Class drivers
+-#
+-# CONFIG_USB_ACM is not set
+-# CONFIG_USB_PRINTER is not set
+-
+-#
+-# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+-#
+-
+-#
+-# may also be needed; see USB_STORAGE Help for more information
+-#
+-CONFIG_USB_STORAGE=m
+-# CONFIG_USB_STORAGE_DEBUG is not set
+-# CONFIG_USB_STORAGE_DATAFAB is not set
+-# CONFIG_USB_STORAGE_FREECOM is not set
+-# CONFIG_USB_STORAGE_ISD200 is not set
+-# CONFIG_USB_STORAGE_DPCM is not set
+-# CONFIG_USB_STORAGE_USBAT is not set
+-# CONFIG_USB_STORAGE_SDDR09 is not set
+-# CONFIG_USB_STORAGE_SDDR55 is not set
+-# CONFIG_USB_STORAGE_JUMPSHOT is not set
+-
+-#
+-# USB Input Devices
+-#
+-CONFIG_USB_HID=m
+-CONFIG_USB_HIDINPUT=y
+-# CONFIG_HID_FF is not set
+-# CONFIG_USB_HIDDEV is not set
+-
+-#
+-# USB HID Boot Protocol drivers
+-#
+-# CONFIG_USB_KBD is not set
+-# CONFIG_USB_MOUSE is not set
+-# CONFIG_USB_AIPTEK is not set
+-# CONFIG_USB_WACOM is not set
+-# CONFIG_USB_ACECAD is not set
+-# CONFIG_USB_KBTAB is not set
+-# CONFIG_USB_POWERMATE is not set
+-# CONFIG_USB_MTOUCH is not set
+-# CONFIG_USB_ITMTOUCH is not set
+-# CONFIG_USB_EGALAX is not set
+-# CONFIG_USB_YEALINK is not set
+-# CONFIG_USB_XPAD is not set
+-# CONFIG_USB_ATI_REMOTE is not set
+-# CONFIG_USB_KEYSPAN_REMOTE is not set
+-# CONFIG_USB_APPLETOUCH is not set
+-
+-#
+-# USB Imaging devices
+-#
+-# CONFIG_USB_MDC800 is not set
+-# CONFIG_USB_MICROTEK is not set
+-
+-#
+-# USB Multimedia devices
+-#
+-# CONFIG_USB_DABUSB is not set
+-
+-#
+-# Video4Linux support is needed for USB Multimedia device support
+-#
+-
+-#
+-# USB Network Adapters
+-#
+-# CONFIG_USB_CATC is not set
+-# CONFIG_USB_KAWETH is not set
+-# CONFIG_USB_PEGASUS is not set
+-# CONFIG_USB_RTL8150 is not set
+-# CONFIG_USB_USBNET is not set
+-CONFIG_USB_MON=y
+-
+-#
+-# USB port drivers
+-#
+-
+-#
+-# USB Serial Converter support
+-#
+-# CONFIG_USB_SERIAL is not set
+-
+-#
+-# USB Miscellaneous drivers
+-#
+-# CONFIG_USB_EMI62 is not set
+-# CONFIG_USB_EMI26 is not set
+-# CONFIG_USB_AUERSWALD is not set
+-# CONFIG_USB_RIO500 is not set
+-# CONFIG_USB_LEGOTOWER is not set
+-# CONFIG_USB_LCD is not set
+-# CONFIG_USB_LED is not set
+-# CONFIG_USB_CYTHERM is not set
+-# CONFIG_USB_GOTEMP is not set
+-# CONFIG_USB_PHIDGETKIT is not set
+-# CONFIG_USB_PHIDGETSERVO is not set
+-# CONFIG_USB_IDMOUSE is not set
+-# CONFIG_USB_SISUSBVGA is not set
+-# CONFIG_USB_LD is not set
+-
+-#
+-# USB DSL modem support
+-#
+-
+-#
+-# USB Gadget Support
+-#
+-# CONFIG_USB_GADGET is not set
+-
+-#
+-# MMC/SD Card support
+-#
+-# CONFIG_MMC is not set
+-
+-#
+-# InfiniBand support
+-#
+-# CONFIG_INFINIBAND is not set
+-
+-#
+-# SN Devices
+-#
+-
+-#
+-# EDAC - error detection and reporting (RAS)
+-#
+-# CONFIG_EDAC is not set
+-
+-#
+-# Distributed Lock Manager
+-#
+-# CONFIG_DLM is not set
+-
+-#
+-# File systems
+-#
+-CONFIG_EXT2_FS=y
+-# CONFIG_EXT2_FS_XATTR is not set
+-# CONFIG_EXT2_FS_XIP is not set
+-CONFIG_EXT3_FS=y
+-CONFIG_EXT3_FS_XATTR=y
+-# CONFIG_EXT3_FS_POSIX_ACL is not set
+-# CONFIG_EXT3_FS_SECURITY is not set
+-CONFIG_JBD=y
+-# CONFIG_JBD_DEBUG is not set
+-CONFIG_FS_MBCACHE=y
+-# CONFIG_REISER4_FS is not set
+-# CONFIG_REISERFS_FS is not set
+-# CONFIG_JFS_FS is not set
+-# CONFIG_FS_POSIX_ACL is not set
+-CONFIG_XFS_FS=y
+-CONFIG_XFS_QUOTA=y
+-# CONFIG_XFS_SECURITY is not set
+-CONFIG_XFS_POSIX_ACL=y
+-# CONFIG_XFS_RT is not set
+-# CONFIG_OCFS2_FS is not set
+-# CONFIG_MINIX_FS is not set
+-CONFIG_ROMFS_FS=m
+-CONFIG_INOTIFY=y
+-# CONFIG_QUOTA is not set
+-CONFIG_QUOTACTL=y
+-# CONFIG_DNOTIFY is not set
+-# CONFIG_AUTOFS_FS is not set
+-CONFIG_AUTOFS4_FS=y
+-# CONFIG_FUSE_FS is not set
+-
+-#
+-# CD-ROM/DVD Filesystems
+-#
+-# CONFIG_ISO9660_FS is not set
+-# CONFIG_UDF_FS is not set
+-
+-#
+-# DOS/FAT/NT Filesystems
+-#
+-# CONFIG_MSDOS_FS is not set
+-# CONFIG_VFAT_FS is not set
+-# CONFIG_NTFS_FS is not set
+-
+-#
+-# Pseudo filesystems
+-#
+-CONFIG_PROC_FS=y
+-CONFIG_PROC_KCORE=y
+-CONFIG_SYSFS=y
+-CONFIG_TMPFS=y
+-# CONFIG_HUGETLB_PAGE is not set
+-CONFIG_RAMFS=y
+-# CONFIG_RELAYFS_FS is not set
+-# CONFIG_CONFIGFS_FS is not set
+-
+-#
+-# Miscellaneous filesystems
+-#
+-# CONFIG_ADFS_FS is not set
+-# CONFIG_AFFS_FS is not set
+-# CONFIG_ASFS_FS is not set
+-# CONFIG_HFS_FS is not set
+-# CONFIG_HFSPLUS_FS is not set
+-# CONFIG_BEFS_FS is not set
+-# CONFIG_BFS_FS is not set
+-# CONFIG_EFS_FS is not set
+-CONFIG_CRAMFS=m
+-# CONFIG_VXFS_FS is not set
+-# CONFIG_HPFS_FS is not set
+-# CONFIG_QNX4FS_FS is not set
+-# CONFIG_SYSV_FS is not set
+-# CONFIG_UFS_FS is not set
+-
+-#
+-# Network File Systems
+-#
+-CONFIG_NFS_FS=y
+-CONFIG_NFS_V3=y
+-# CONFIG_NFS_V3_ACL is not set
+-# CONFIG_NFS_V4 is not set
+-# CONFIG_NFS_DIRECTIO is not set
+-# CONFIG_NFSD is not set
+-CONFIG_ROOT_NFS=y
+-CONFIG_LOCKD=y
+-CONFIG_LOCKD_V4=y
+-CONFIG_NFS_COMMON=y
+-CONFIG_SUNRPC=y
+-# CONFIG_RPCSEC_GSS_KRB5 is not set
+-# CONFIG_RPCSEC_GSS_SPKM3 is not set
+-# CONFIG_SMB_FS is not set
+-# CONFIG_CIFS is not set
+-# CONFIG_NCP_FS is not set
+-# CONFIG_CODA_FS is not set
+-# CONFIG_AFS_FS is not set
+-# CONFIG_9P_FS is not set
+-
+-#
+-# Partition Types
+-#
+-# CONFIG_PARTITION_ADVANCED is not set
+-CONFIG_MSDOS_PARTITION=y
+-
+-#
+-# Native Language Support
+-#
+-# CONFIG_NLS is not set
+-
+-#
+-# Profiling support
+-#
+-# CONFIG_PROFILING is not set
+-
+-#
+-# Kernel hacking
+-#
+-# CONFIG_PRINTK_TIME is not set
+-# CONFIG_DEBUG_KERNEL is not set
+-CONFIG_LOG_BUF_SHIFT=14
+-CONFIG_CROSSCOMPILE=y
+-CONFIG_CMDLINE="mem=64M console=ttyVR0,115200 ip=any root=/dev/nfs"
+-
+-#
+-# Security options
+-#
+-CONFIG_KEYS=y
+-CONFIG_KEYS_DEBUG_PROC_KEYS=y
+-# CONFIG_SECURITY is not set
+-
+-#
+-# Cryptographic options
+-#
+-# CONFIG_CRYPTO is not set
+-
+-#
+-# Hardware crypto devices
+-#
+-
+-#
+-# Library routines
+-#
+-# CONFIG_CRC_CCITT is not set
+-# CONFIG_CRC16 is not set
+-CONFIG_CRC32=y
+-# CONFIG_LIBCRC32C is not set
+-CONFIG_ZLIB_INFLATE=m
+diff -Naur linux-2.6.15.orig/arch/mips/configs/workpad_defconfig linux-2.6.15/arch/mips/configs/workpad_defconfig
+--- linux-2.6.15.orig/arch/mips/configs/workpad_defconfig	2006-01-03 03:21:10.000000000 +0000
++++ linux-2.6.15/arch/mips/configs/workpad_defconfig	2006-01-09 19:54:12.000000000 +0000
+@@ -1,7 +1,7 @@
+ #
+ # Automatically generated make config: don't edit
+-# Linux kernel version: 2.6.15-rc2
+-# Thu Nov 24 01:07:17 2005
++# Linux kernel version: 2.6.15-rc5
++# Sat Dec 17 18:03:56 2005
+ #
+ CONFIG_MIPS=y
+ 
+@@ -157,6 +157,7 @@
+ CONFIG_KOBJECT_UEVENT=y
+ # CONFIG_IKCONFIG is not set
+ CONFIG_INITRAMFS_SOURCE=""
++# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+ CONFIG_EMBEDDED=y
+ CONFIG_KALLSYMS=y
+ # CONFIG_KALLSYMS_EXTRA_PASS is not set
+@@ -165,7 +166,6 @@
+ CONFIG_BASE_FULL=y
+ CONFIG_FUTEX=y
+ CONFIG_EPOLL=y
+-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+ CONFIG_SHMEM=y
+ CONFIG_CC_ALIGN_FUNCTIONS=0
+ CONFIG_CC_ALIGN_LABELS=0
+@@ -309,7 +309,6 @@
+ # CONFIG_IEEE80211_DEBUG is not set
+ CONFIG_IEEE80211_CRYPT_WEP=m
+ CONFIG_IEEE80211_CRYPT_CCMP=m
+-CONFIG_IEEE80211_CRYPT_TKIP=m
+ 
+ #
+ # Device Drivers
+diff -Naur linux-2.6.15.orig/arch/mips/configs/yosemite_defconfig linux-2.6.15/arch/mips/configs/yosemite_defconfig
+--- linux-2.6.15.orig/arch/mips/configs/yosemite_defconfig	2006-01-03 03:21:10.000000000 +0000
++++ linux-2.6.15/arch/mips/configs/yosemite_defconfig	2006-01-09 19:54:12.000000000 +0000
+@@ -1,7 +1,7 @@
+ #
+ # Automatically generated make config: don't edit
+-# Linux kernel version: 2.6.15-rc2
+-# Thu Nov 24 01:07:19 2005
++# Linux kernel version: 2.6.15-rc5
++# Sat Dec 17 18:03:57 2005
+ #
+ CONFIG_MIPS=y
+ 
+@@ -118,7 +118,6 @@
+ # CONFIG_64BIT_PHYS_ADDR is not set
+ # CONFIG_CPU_ADVANCED is not set
+ CONFIG_CPU_HAS_LLSC=y
+-CONFIG_CPU_HAS_LLDSCD=y
+ CONFIG_CPU_HAS_SYNC=y
+ CONFIG_GENERIC_HARDIRQS=y
+ CONFIG_GENERIC_IRQ_PROBE=y
+@@ -170,7 +169,6 @@
+ CONFIG_BASE_FULL=y
+ CONFIG_FUTEX=y
+ CONFIG_EPOLL=y
+-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+ CONFIG_SHMEM=y
+ CONFIG_CC_ALIGN_FUNCTIONS=0
+ CONFIG_CC_ALIGN_LABELS=0
+@@ -296,7 +294,6 @@
+ # CONFIG_IEEE80211_DEBUG is not set
+ CONFIG_IEEE80211_CRYPT_WEP=m
+ CONFIG_IEEE80211_CRYPT_CCMP=m
+-CONFIG_IEEE80211_CRYPT_TKIP=m
+ 
+ #
+ # Device Drivers
+diff -Naur linux-2.6.15.orig/arch/mips/defconfig linux-2.6.15/arch/mips/defconfig
+--- linux-2.6.15.orig/arch/mips/defconfig	2006-01-03 03:21:10.000000000 +0000
++++ linux-2.6.15/arch/mips/defconfig	2006-01-09 19:54:12.000000000 +0000
+@@ -1,7 +1,7 @@
+ #
+ # Automatically generated make config: don't edit
+-# Linux kernel version: 2.6.15-rc2
+-# Thu Nov 24 01:05:49 2005
++# Linux kernel version: 2.6.15-rc5
++# Sat Dec 17 18:02:11 2005
+ #
+ CONFIG_MIPS=y
+ 
+@@ -123,7 +123,6 @@
+ # CONFIG_64BIT_PHYS_ADDR is not set
+ # CONFIG_CPU_ADVANCED is not set
+ CONFIG_CPU_HAS_LLSC=y
+-CONFIG_CPU_HAS_LLDSCD=y
+ CONFIG_CPU_HAS_SYNC=y
+ CONFIG_GENERIC_HARDIRQS=y
+ CONFIG_GENERIC_IRQ_PROBE=y
+@@ -164,6 +163,7 @@
+ CONFIG_IKCONFIG=y
+ CONFIG_IKCONFIG_PROC=y
+ CONFIG_INITRAMFS_SOURCE=""
++# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+ CONFIG_EMBEDDED=y
+ CONFIG_KALLSYMS=y
+ # CONFIG_KALLSYMS_EXTRA_PASS is not set
+@@ -172,7 +172,6 @@
+ CONFIG_BASE_FULL=y
+ CONFIG_FUTEX=y
+ CONFIG_EPOLL=y
+-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+ CONFIG_SHMEM=y
+ CONFIG_CC_ALIGN_FUNCTIONS=0
+ CONFIG_CC_ALIGN_LABELS=0
+@@ -505,7 +504,6 @@
+ # CONFIG_IEEE80211_DEBUG is not set
+ CONFIG_IEEE80211_CRYPT_WEP=m
+ CONFIG_IEEE80211_CRYPT_CCMP=m
+-CONFIG_IEEE80211_CRYPT_TKIP=m
+ 
+ #
+ # Device Drivers
+diff -Naur linux-2.6.15.orig/arch/mips/kernel/cpu-probe.c linux-2.6.15/arch/mips/kernel/cpu-probe.c
+--- linux-2.6.15.orig/arch/mips/kernel/cpu-probe.c	2006-01-03 03:21:10.000000000 +0000
++++ linux-2.6.15/arch/mips/kernel/cpu-probe.c	2006-01-09 19:54:12.000000000 +0000
+@@ -242,9 +242,15 @@
+ 		break;
+ 	case PRID_IMP_VR41XX:
+ 		switch (c->processor_id & 0xf0) {
++#ifndef CONFIG_VR4181
+ 		case PRID_REV_VR4111:
+ 			c->cputype = CPU_VR4111;
+ 			break;
++#else
++		case PRID_REV_VR4181:
++			c->cputype = CPU_VR4181;
++			break;
++#endif
+ 		case PRID_REV_VR4121:
+ 			c->cputype = CPU_VR4121;
+ 			break;
+@@ -435,6 +441,9 @@
+ 	}
+ }
+ 
++static char unknown_isa[] __initdata = KERN_ERR \
++	"Unsupported ISA type, c0.config0: %d.";
++
+ static inline unsigned int decode_config0(struct cpuinfo_mips *c)
+ {
+ 	unsigned int config0;
+@@ -447,16 +456,37 @@
+ 	isa = (config0 & MIPS_CONF_AT) >> 13;
+ 	switch (isa) {
+ 	case 0:
+-		c->isa_level = MIPS_CPU_ISA_M32;
++		switch ((config0 >> 10) & 7) {
++		case 0:
++			c->isa_level = MIPS_CPU_ISA_M32R1;
++			break;
++		case 1:
++			c->isa_level = MIPS_CPU_ISA_M32R2;
++			break;
++		default:
++			goto unknown;
++		}
+ 		break;
+ 	case 2:
+-		c->isa_level = MIPS_CPU_ISA_M64;
++		switch ((config0 >> 10) & 7) {
++		case 0:
++			c->isa_level = MIPS_CPU_ISA_M64R1;
++			break;
++		case 1:
++			c->isa_level = MIPS_CPU_ISA_M64R2;
++			break;
++		default:
++			goto unknown;
++		}
+ 		break;
+ 	default:
+-		panic("Unsupported ISA type, cp0.config0.at: %d.", isa);
++		goto unknown;
+ 	}
+ 
+ 	return config0 & MIPS_CONF_M;
++
++unknown:
++	panic(unknown_isa, config0);
+ }
+ 
+ static inline unsigned int decode_config1(struct cpuinfo_mips *c)
+@@ -568,7 +598,6 @@
+ 		break;
+ 	case PRID_IMP_34K:
+ 		c->cputype = CPU_34K;
+-		c->isa_level = MIPS_CPU_ISA_M32;
+ 		break;
+ 	}
+ }
+@@ -647,7 +676,7 @@
+ 	switch (c->processor_id & 0xff00) {
+ 	case PRID_IMP_PR4450:
+ 		c->cputype = CPU_PR4450;
+-		c->isa_level = MIPS_CPU_ISA_M32;
++		c->isa_level = MIPS_CPU_ISA_M32R1;
+ 		break;
+ 	default:
+ 		panic("Unknown Philips Core!"); /* REVISIT: die? */
+@@ -690,8 +719,10 @@
+ 	if (c->options & MIPS_CPU_FPU) {
+ 		c->fpu_id = cpu_get_fpu_id();
+ 
+-		if (c->isa_level == MIPS_CPU_ISA_M32 ||
+-		    c->isa_level == MIPS_CPU_ISA_M64) {
++		if (c->isa_level == MIPS_CPU_ISA_M32R1 ||
++		    c->isa_level == MIPS_CPU_ISA_M32R2 ||
++		    c->isa_level == MIPS_CPU_ISA_M64R1 ||
++		    c->isa_level == MIPS_CPU_ISA_M64R2) {
+ 			if (c->fpu_id & MIPS_FPIR_3D)
+ 				c->ases |= MIPS_ASE_MIPS3D;
+ 		}
+diff -Naur linux-2.6.15.orig/arch/mips/kernel/process.c linux-2.6.15/arch/mips/kernel/process.c
+--- linux-2.6.15.orig/arch/mips/kernel/process.c	2006-01-03 03:21:10.000000000 +0000
++++ linux-2.6.15/arch/mips/kernel/process.c	2006-01-09 19:54:12.000000000 +0000
+@@ -205,7 +205,7 @@
+ 	return 1;
+ }
+ 
+-void dump_regs(elf_greg_t *gp, struct pt_regs *regs)
++void elf_dump_regs(elf_greg_t *gp, struct pt_regs *regs)
+ {
+ 	int i;
+ 
+@@ -231,7 +231,7 @@
+ {
+ 	struct thread_info *ti = tsk->thread_info;
+ 	long ksp = (unsigned long)ti + THREAD_SIZE - 32;
+-	dump_regs(&(*regs)[0], (struct pt_regs *) ksp - 1);
++	elf_dump_regs(&(*regs)[0], (struct pt_regs *) ksp - 1);
+ 	return 1;
+ }
+ 
+diff -Naur linux-2.6.15.orig/arch/mips/kernel/ptrace.c linux-2.6.15/arch/mips/kernel/ptrace.c
+--- linux-2.6.15.orig/arch/mips/kernel/ptrace.c	2006-01-03 03:21:10.000000000 +0000
++++ linux-2.6.15/arch/mips/kernel/ptrace.c	2006-01-09 19:54:12.000000000 +0000
+@@ -21,12 +21,12 @@
+ #include <linux/mm.h>
+ #include <linux/errno.h>
+ #include <linux/ptrace.h>
+-#include <linux/audit.h>
+ #include <linux/smp.h>
+ #include <linux/smp_lock.h>
+ #include <linux/user.h>
+ #include <linux/security.h>
+-#include <linux/signal.h>
++#include <linux/audit.h>
++#include <linux/seccomp.h>
+ 
+ #include <asm/byteorder.h>
+ #include <asm/cpu.h>
+@@ -280,12 +280,8 @@
+ 				ret = -EIO;
+ 				goto out;
+ 			}
+-			if (child->thread.dsp.used_dsp) {
+-				dregs = __get_dsp_regs(child);
+-				tmp = (unsigned long) (dregs[addr - DSP_BASE]);
+-			} else {
+-				tmp = -1;	/* DSP registers yet used  */
+-			}
++			dregs = __get_dsp_regs(child);
++			tmp = (unsigned long) (dregs[addr - DSP_BASE]);
+ 			break;
+ 		}
+ 		case DSP_CONTROL:
+@@ -476,12 +472,16 @@
+  */
+ asmlinkage void do_syscall_trace(struct pt_regs *regs, int entryexit)
+ {
++	/* do the secure computing check first */
++	secure_computing(regs->orig_eax);
++
+ 	if (unlikely(current->audit_context) && entryexit)
+ 		audit_syscall_exit(current, AUDITSC_RESULT(regs->regs[2]),
+ 		                   regs->regs[2]);
+ 
+ 	if (!(current->ptrace & PT_PTRACED))
+ 		goto out;
++
+ 	if (!test_thread_flag(TIF_SYSCALL_TRACE))
+ 		goto out;
+ 
+@@ -499,9 +499,14 @@
+ 		send_sig(current->exit_code, current, 1);
+ 		current->exit_code = 0;
+ 	}
+- out:
++
++out:
++	/* There is no ->orig_eax and that's quite intensional for now making
++	   this work will require some work in various other place before it's
++	   more than a placebo.  */
++
+ 	if (unlikely(current->audit_context) && !entryexit)
+-		audit_syscall_entry(current, audit_arch(), regs->regs[2],
+-				    regs->regs[4], regs->regs[5],
+-				    regs->regs[6], regs->regs[7]);
++		audit_syscall_entry(current, audit_arch(), regs->orig_eax,
++		                    regs->regs[4], regs->regs[5],
++		                    regs->regs[6], regs->regs[7]);
+ }
+diff -Naur linux-2.6.15.orig/arch/mips/kernel/ptrace32.c linux-2.6.15/arch/mips/kernel/ptrace32.c
+--- linux-2.6.15.orig/arch/mips/kernel/ptrace32.c	2006-01-03 03:21:10.000000000 +0000
++++ linux-2.6.15/arch/mips/kernel/ptrace32.c	2006-01-09 19:54:12.000000000 +0000
+@@ -215,12 +215,8 @@
+ 				ret = -EIO;
+ 				goto out_tsk;
+ 			}
+-			if (child->thread.dsp.used_dsp) {
+-				dspreg_t *dregs = __get_dsp_regs(child);
+-				tmp = (unsigned long) (dregs[addr - DSP_BASE]);
+-			} else {
+-				tmp = -1;	/* DSP registers yet used  */
+-			}
++			dspreg_t *dregs = __get_dsp_regs(child);
++			tmp = (unsigned long) (dregs[addr - DSP_BASE]);
+ 			break;
+ 		case DSP_CONTROL:
+ 			if (!cpu_has_dsp) {
+diff -Naur linux-2.6.15.orig/arch/mips/kernel/signal32.c linux-2.6.15/arch/mips/kernel/signal32.c
+--- linux-2.6.15.orig/arch/mips/kernel/signal32.c	2006-01-03 03:21:10.000000000 +0000
++++ linux-2.6.15/arch/mips/kernel/signal32.c	2006-01-09 19:54:12.000000000 +0000
+@@ -588,7 +588,7 @@
+ 	err |= __put_user(regs->hi, &sc->sc_mdhi);
+ 	err |= __put_user(regs->lo, &sc->sc_mdlo);
+ 	if (cpu_has_dsp) {
+-		err |= __put_user(rddsp(DSP_MASK), &sc->sc_hi1);
++		err |= __put_user(rddsp(DSP_MASK), &sc->sc_dsp);
+ 		err |= __put_user(mfhi1(), &sc->sc_hi1);
+ 		err |= __put_user(mflo1(), &sc->sc_lo1);
+ 		err |= __put_user(mfhi2(), &sc->sc_hi2);
+diff -Naur linux-2.6.15.orig/arch/mips/kernel/time.c linux-2.6.15/arch/mips/kernel/time.c
+--- linux-2.6.15.orig/arch/mips/kernel/time.c	2006-01-03 03:21:10.000000000 +0000
++++ linux-2.6.15/arch/mips/kernel/time.c	2006-01-09 19:54:12.000000000 +0000
+@@ -507,14 +507,38 @@
+ 	return IRQ_HANDLED;
+ }
+ 
++int null_perf_irq(struct pt_regs *regs)
++{
++	return 0;
++}
++
++int (*perf_irq)(struct pt_regs *regs) = null_perf_irq;
++
++EXPORT_SYMBOL(null_perf_irq);
++EXPORT_SYMBOL(perf_irq);
++
+ asmlinkage void ll_timer_interrupt(int irq, struct pt_regs *regs)
+ {
++	int r2 = cpu_has_mips_r2;
++
+ 	irq_enter();
+ 	kstat_this_cpu.irqs[irq]++;
+ 
++	/*
++	 * Suckage alert:
++	 * Before R2 of the architecture there was no way to see if a
++	 * performance counter interrupt was pending, so we have to run the
++	 * performance counter interrupt handler anyway.
++	 */
++	if (!r2 || (read_c0_cause() & (1 << 26)))
++		if (perf_irq(regs))
++			goto out;
++
+ 	/* we keep interrupt disabled all the time */
+-	timer_interrupt(irq, NULL, regs);
++	if (!r2 || (read_c0_cause() & (1 << 30)))
++		timer_interrupt(irq, NULL, regs);
+ 
++out:
+ 	irq_exit();
+ }
+ 
+@@ -628,9 +652,9 @@
+ 			mips_hpt_init = c0_hpt_init;
+ 		}
+ 
+-		if ((current_cpu_data.isa_level == MIPS_CPU_ISA_M32) ||
+-			 (current_cpu_data.isa_level == MIPS_CPU_ISA_I) ||
+-			 (current_cpu_data.isa_level == MIPS_CPU_ISA_II))
++		if (cpu_has_mips32r1 || cpu_has_mips32r2 ||
++		    (current_cpu_data.isa_level == MIPS_CPU_ISA_I) ||
++		    (current_cpu_data.isa_level == MIPS_CPU_ISA_II))
+ 			/*
+ 			 * We need to calibrate the counter but we don't have
+ 			 * 64-bit division.
+diff -Naur linux-2.6.15.orig/arch/mips/kernel/vpe.c linux-2.6.15/arch/mips/kernel/vpe.c
+--- linux-2.6.15.orig/arch/mips/kernel/vpe.c	2006-01-03 03:21:10.000000000 +0000
++++ linux-2.6.15/arch/mips/kernel/vpe.c	2006-01-09 19:54:12.000000000 +0000
+@@ -99,9 +99,9 @@
+ 
+ 	/* elfloader stuff */
+ 	void *load_addr;
+-	u32 len;
++	unsigned long len;
+ 	char *pbuffer;
+-	u32 plen;
++	unsigned long plen;
+ 
+ 	unsigned long __start;
+ 
+@@ -253,11 +253,11 @@
+ }
+ 
+ /* Find some VPE program space  */
+-static void *alloc_progmem(u32 len)
++static void *alloc_progmem(unsigned long len)
+ {
+ #ifdef CONFIG_MIPS_VPE_LOADER_TOM
+ 	/* this means you must tell linux to use less memory than you physically have */
+-	return (void *)((max_pfn * PAGE_SIZE) + KSEG0);
++	return pfn_to_kaddr(max_pfn);
+ #else
+ 	// simple grab some mem for now
+ 	return kmalloc(len, GFP_KERNEL);
+diff -Naur linux-2.6.15.orig/arch/mips/lib/Makefile linux-2.6.15/arch/mips/lib/Makefile
+--- linux-2.6.15.orig/arch/mips/lib/Makefile	2006-01-03 03:21:10.000000000 +0000
++++ linux-2.6.15/arch/mips/lib/Makefile	2006-01-09 19:54:12.000000000 +0000
+@@ -5,6 +5,4 @@
+ lib-y	+= csum_partial_copy.o memcpy.o promlib.o strlen_user.o strncpy_user.o \
+ 	   strnlen_user.o uncached.o
+ 
+-obj-y	+= iomap.o
+-
+ EXTRA_AFLAGS := $(CFLAGS)
+diff -Naur linux-2.6.15.orig/arch/mips/lib/iomap.c linux-2.6.15/arch/mips/lib/iomap.c
+--- linux-2.6.15.orig/arch/mips/lib/iomap.c	2006-01-03 03:21:10.000000000 +0000
++++ linux-2.6.15/arch/mips/lib/iomap.c	1970-01-01 00:00:00.000000000 +0000
+@@ -1,78 +0,0 @@
+-/*
+- *  iomap.c, Memory Mapped I/O routines for MIPS architecture.
+- *
+- *  This code is based on lib/iomap.c, by Linus Torvalds.
+- *
+- *  Copyright (C) 2004-2005  Yoichi Yuasa <yuasa at hh.iij4u.or.jp>
+- *
+- *  This program is free software; you can redistribute it and/or modify
+- *  it under the terms of the GNU General Public License as published by
+- *  the Free Software Foundation; either version 2 of the License, or
+- *  (at your option) any later version.
+- *
+- *  This program is distributed in the hope that it will be useful,
+- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+- *  GNU General Public License for more details.
+- *
+- *  You should have received a copy of the GNU General Public License
+- *  along with this program; if not, write to the Free Software
+- *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+- */
+-#include <linux/ioport.h>
+-#include <linux/module.h>
+-#include <linux/pci.h>
+-
+-#include <asm/io.h>
+-
+-void __iomem *ioport_map(unsigned long port, unsigned int nr)
+-{
+-	unsigned long end;
+-
+-	end = port + nr - 1UL;
+-	if (ioport_resource.start > port ||
+-	    ioport_resource.end < end || port > end)
+-		return NULL;
+-
+-	return (void __iomem *)(mips_io_port_base + port);
+-}
+-
+-void ioport_unmap(void __iomem *addr)
+-{
+-}
+-EXPORT_SYMBOL(ioport_map);
+-EXPORT_SYMBOL(ioport_unmap);
+-
+-void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long maxlen)
+-{
+-	unsigned long start, len, flags;
+-
+-	if (dev == NULL)
+-		return NULL;
+-
+-	start = pci_resource_start(dev, bar);
+-	len = pci_resource_len(dev, bar);
+-	if (!start || !len)
+-		return NULL;
+-
+-	if (maxlen != 0 && len > maxlen)
+-		len = maxlen;
+-
+-	flags = pci_resource_flags(dev, bar);
+-	if (flags & IORESOURCE_IO)
+-		return ioport_map(start, len);
+-	if (flags & IORESOURCE_MEM) {
+-		if (flags & IORESOURCE_CACHEABLE)
+-			return ioremap_cacheable_cow(start, len);
+-		return ioremap_nocache(start, len);
+-	}
+-
+-	return NULL;
+-}
+-
+-void pci_iounmap(struct pci_dev *dev, void __iomem *addr)
+-{
+-	iounmap(addr);
+-}
+-EXPORT_SYMBOL(pci_iomap);
+-EXPORT_SYMBOL(pci_iounmap);
+diff -Naur linux-2.6.15.orig/arch/mips/lib-32/dump_tlb.c linux-2.6.15/arch/mips/lib-32/dump_tlb.c
+--- linux-2.6.15.orig/arch/mips/lib-32/dump_tlb.c	2006-01-03 03:21:10.000000000 +0000
++++ linux-2.6.15/arch/mips/lib-32/dump_tlb.c	2006-01-09 19:54:12.000000000 +0000
+@@ -41,8 +41,6 @@
+ 		return "256Mb";
+ #endif
+ 	}
+-
+-	return "unknown";
+ }
+ 
+ #define BARRIER()					\
+diff -Naur linux-2.6.15.orig/arch/mips/lib-64/dump_tlb.c linux-2.6.15/arch/mips/lib-64/dump_tlb.c
+--- linux-2.6.15.orig/arch/mips/lib-64/dump_tlb.c	2006-01-03 03:21:10.000000000 +0000
++++ linux-2.6.15/arch/mips/lib-64/dump_tlb.c	2006-01-09 19:54:12.000000000 +0000
+@@ -32,8 +32,6 @@
+ 	case PM_256M:	return "256Mb";
+ #endif
+ 	}
+-
+-	return "unknown";
+ }
+ 
+ #define BARRIER()					\
+diff -Naur linux-2.6.15.orig/arch/mips/math-emu/dp_fint.c linux-2.6.15/arch/mips/math-emu/dp_fint.c
+--- linux-2.6.15.orig/arch/mips/math-emu/dp_fint.c	2006-01-03 03:21:10.000000000 +0000
++++ linux-2.6.15/arch/mips/math-emu/dp_fint.c	2006-01-09 19:54:12.000000000 +0000
+@@ -33,8 +33,6 @@
+ 
+ 	CLEARCX;
+ 
+-	xc = ( 0 ? xc : xc );
+-
+ 	if (x == 0)
+ 		return ieee754dp_zero(0);
+ 	if (x == 1 || x == -1)
+diff -Naur linux-2.6.15.orig/arch/mips/math-emu/dp_flong.c linux-2.6.15/arch/mips/math-emu/dp_flong.c
+--- linux-2.6.15.orig/arch/mips/math-emu/dp_flong.c	2006-01-03 03:21:10.000000000 +0000
++++ linux-2.6.15/arch/mips/math-emu/dp_flong.c	2006-01-09 19:54:12.000000000 +0000
+@@ -33,8 +33,6 @@
+ 
+ 	CLEARCX;
+ 
+-	xc = ( 0 ? xc : xc );
+-
+ 	if (x == 0)
+ 		return ieee754dp_zero(0);
+ 	if (x == 1 || x == -1)
+diff -Naur linux-2.6.15.orig/arch/mips/math-emu/sp_fint.c linux-2.6.15/arch/mips/math-emu/sp_fint.c
+--- linux-2.6.15.orig/arch/mips/math-emu/sp_fint.c	2006-01-03 03:21:10.000000000 +0000
++++ linux-2.6.15/arch/mips/math-emu/sp_fint.c	2006-01-09 19:54:12.000000000 +0000
+@@ -33,8 +33,6 @@
+ 
+ 	CLEARCX;
+ 
+-	xc = ( 0 ? xc : xc );
+-
+ 	if (x == 0)
+ 		return ieee754sp_zero(0);
+ 	if (x == 1 || x == -1)
+diff -Naur linux-2.6.15.orig/arch/mips/math-emu/sp_flong.c linux-2.6.15/arch/mips/math-emu/sp_flong.c
+--- linux-2.6.15.orig/arch/mips/math-emu/sp_flong.c	2006-01-03 03:21:10.000000000 +0000
++++ linux-2.6.15/arch/mips/math-emu/sp_flong.c	2006-01-09 19:54:12.000000000 +0000
+@@ -33,8 +33,6 @@
+ 
+ 	CLEARCX;
+ 
+-	xc = ( 0 ? xc : xc );
+-
+ 	if (x == 0)
+ 		return ieee754sp_zero(0);
+ 	if (x == 1 || x == -1)
+diff -Naur linux-2.6.15.orig/arch/mips/mips-boards/generic/time.c linux-2.6.15/arch/mips/mips-boards/generic/time.c
+--- linux-2.6.15.orig/arch/mips/mips-boards/generic/time.c	2006-01-03 03:21:10.000000000 +0000
++++ linux-2.6.15/arch/mips/mips-boards/generic/time.c	2006-01-09 19:54:12.000000000 +0000
+@@ -75,20 +75,31 @@
+ 	do_IRQ (mips_cpu_timer_irq, regs);
+ }
+ 
++extern int null_perf_irq(struct pt_regs *regs);
++
++extern int (*perf_irq)(struct pt_regs *regs);
++
+ irqreturn_t mips_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+ {
+-#ifdef CONFIG_SMP
++	int r2 = cpu_has_mips_r2;
+ 	int cpu = smp_processor_id();
+ 
+ 	if (cpu == 0) {
+ 		/*
+-		 * CPU 0 handles the global timer interrupt job and process accounting
+-		 * resets count/compare registers to trigger next timer int.
++		 * CPU 0 handles the global timer interrupt job and process
++		 * accounting resets count/compare registers to trigger next
++		 * timer int.
+ 		 */
+-		(void) timer_interrupt(irq, dev_id, regs);
++		if (!r2 || (read_c0_cause() & (1 << 26)))
++			if (perf_irq(regs))
++				goto out;
++
++		/* we keep interrupt disabled all the time */
++		if (!r2 || (read_c0_cause() & (1 << 30)))
++			timer_interrupt(irq, NULL, regs);
++
+ 		scroll_display_message();
+-	}
+-	else {
++	} else {
+ 		/* Everyone else needs to reset the timer int here as
+ 		   ll_local_timer_interrupt doesn't */
+ 		/*
+@@ -103,16 +114,8 @@
+ 		local_timer_interrupt (irq, dev_id, regs);
+ 	}
+ 
++out:
+ 	return IRQ_HANDLED;
+-#else
+-	irqreturn_t r;
+-
+-	r = timer_interrupt(irq, dev_id, regs);
+-
+-	scroll_display_message();
+-
+-	return r;
+-#endif
+ }
+ 
+ /*
+diff -Naur linux-2.6.15.orig/arch/mips/mm/c-r4k.c linux-2.6.15/arch/mips/mm/c-r4k.c
+--- linux-2.6.15.orig/arch/mips/mm/c-r4k.c	2006-01-03 03:21:10.000000000 +0000
++++ linux-2.6.15/arch/mips/mm/c-r4k.c	2006-01-09 19:54:12.000000000 +0000
+@@ -1183,8 +1183,8 @@
+ 	if (!sc_present)
+ 		return;
+ 
+-	if ((c->isa_level == MIPS_CPU_ISA_M32 ||
+-	     c->isa_level == MIPS_CPU_ISA_M64) &&
++	if ((c->isa_level == MIPS_CPU_ISA_M32R1 ||
++	     c->isa_level == MIPS_CPU_ISA_M64R1) &&
+ 	    !(c->scache.flags & MIPS_CACHE_NOT_PRESENT))
+ 		panic("Dunno how to handle MIPS32 / MIPS64 second level cache");
+ 
+diff -Naur linux-2.6.15.orig/arch/mips/mm/cex-sb1.S linux-2.6.15/arch/mips/mm/cex-sb1.S
+--- linux-2.6.15.orig/arch/mips/mm/cex-sb1.S	2006-01-03 03:21:10.000000000 +0000
++++ linux-2.6.15/arch/mips/mm/cex-sb1.S	2006-01-09 19:54:12.000000000 +0000
+@@ -64,7 +64,7 @@
+ 	sd	k0,0x170($0)
+ 	sd	k1,0x178($0)
+ 
+-#if CONFIG_SB1_CEX_ALWAYS_FATAL
++#ifdef CONFIG_SB1_CEX_ALWAYS_FATAL
+ 	j	handle_vec2_sb1
+ 	 nop
+ #else
+diff -Naur linux-2.6.15.orig/arch/mips/oprofile/common.c linux-2.6.15/arch/mips/oprofile/common.c
+--- linux-2.6.15.orig/arch/mips/oprofile/common.c	2006-01-03 03:21:10.000000000 +0000
++++ linux-2.6.15/arch/mips/oprofile/common.c	2006-01-09 19:54:12.000000000 +0000
+@@ -75,7 +75,10 @@
+ 	int res;
+ 
+ 	switch (current_cpu_data.cputype) {
++	case CPU_5KC:
++	case CPU_20KC:
+ 	case CPU_24K:
++	case CPU_25KF:
+ 		lmodel = &op_model_mipsxx;
+ 		break;
+ 
+diff -Naur linux-2.6.15.orig/arch/mips/oprofile/op_impl.h linux-2.6.15/arch/mips/oprofile/op_impl.h
+--- linux-2.6.15.orig/arch/mips/oprofile/op_impl.h	2006-01-03 03:21:10.000000000 +0000
++++ linux-2.6.15/arch/mips/oprofile/op_impl.h	2006-01-09 19:54:12.000000000 +0000
+@@ -12,8 +12,8 @@
+ 
+ struct pt_regs;
+ 
+-extern void null_perf_irq(struct pt_regs *regs);
+-extern void (*perf_irq)(struct pt_regs *regs);
++extern int null_perf_irq(struct pt_regs *regs);
++extern int (*perf_irq)(struct pt_regs *regs);
+ 
+ /* Per-counter configuration as set via oprofilefs.  */
+ struct op_counter_config {
+diff -Naur linux-2.6.15.orig/arch/mips/oprofile/op_model_mipsxx.c linux-2.6.15/arch/mips/oprofile/op_model_mipsxx.c
+--- linux-2.6.15.orig/arch/mips/oprofile/op_model_mipsxx.c	2006-01-03 03:21:10.000000000 +0000
++++ linux-2.6.15/arch/mips/oprofile/op_model_mipsxx.c	2006-01-09 19:54:12.000000000 +0000
+@@ -114,11 +114,12 @@
+ 	}
+ }
+ 
+-static void mipsxx_perfcount_handler(struct pt_regs *regs)
++static int mipsxx_perfcount_handler(struct pt_regs *regs)
+ {
+ 	unsigned int counters = op_model_mipsxx.num_counters;
+ 	unsigned int control;
+ 	unsigned int counter;
++	int handled = 0;
+ 
+ 	switch (counters) {
+ #define HANDLE_COUNTER(n)						\
+@@ -129,12 +130,15 @@
+ 		    (counter & M_COUNTER_OVERFLOW)) {			\
+ 			oprofile_add_sample(regs, n);			\
+ 			write_c0_perfcntr ## n(reg.counter[n]);		\
++			handled = 1;					\
+ 		}
+ 	HANDLE_COUNTER(3)
+ 	HANDLE_COUNTER(2)
+ 	HANDLE_COUNTER(1)
+ 	HANDLE_COUNTER(0)
+ 	}
++
++	return handled;
+ }
+ 
+ #define M_CONFIG1_PC	(1 << 4)
+@@ -176,17 +180,31 @@
+ 	int counters;
+ 
+ 	counters = n_counters();
+-	if (counters == 0)
++	if (counters == 0) {
++		printk(KERN_ERR "Oprofile: CPU has no performance counters\n");
+ 		return -ENODEV;
++	}
+ 
+ 	reset_counters(counters);
+ 
+ 	op_model_mipsxx.num_counters = counters;
+ 	switch (current_cpu_data.cputype) {
++	case CPU_20KC:
++		op_model_mipsxx.cpu_type = "mips/20K";
++		break;
++
+ 	case CPU_24K:
+ 		op_model_mipsxx.cpu_type = "mips/24K";
+ 		break;
+ 
++	case CPU_25KF:
++		op_model_mipsxx.cpu_type = "mips/25K";
++		break;
++
++	case CPU_5KC:
++		op_model_mipsxx.cpu_type = "mips/5K";
++		break;
++
+ 	default:
+ 		printk(KERN_ERR "Profiling unsupported for this CPU\n");
+ 
+diff -Naur linux-2.6.15.orig/arch/mips/pci/Makefile linux-2.6.15/arch/mips/pci/Makefile
+--- linux-2.6.15.orig/arch/mips/pci/Makefile	2006-01-03 03:21:10.000000000 +0000
++++ linux-2.6.15/arch/mips/pci/Makefile	2006-01-09 19:54:12.000000000 +0000
+@@ -50,7 +50,6 @@
+ obj-$(CONFIG_SNI_RM200_PCI)	+= fixup-sni.o ops-sni.o
+ obj-$(CONFIG_TANBAC_TB0219)	+= fixup-tb0219.o
+ obj-$(CONFIG_TANBAC_TB0226)	+= fixup-tb0226.o
+-obj-$(CONFIG_TANBAC_TB0287)	+= fixup-tb0287.o
+ obj-$(CONFIG_TOSHIBA_JMR3927)	+= fixup-jmr3927.o pci-jmr3927.o
+ obj-$(CONFIG_TOSHIBA_RBTX4927)	+= fixup-rbtx4927.o ops-tx4927.o
+ obj-$(CONFIG_TOSHIBA_RBTX4938)	+= fixup-tx4938.o ops-tx4938.o
+diff -Naur linux-2.6.15.orig/arch/mips/pci/fixup-tb0219.c linux-2.6.15/arch/mips/pci/fixup-tb0219.c
+--- linux-2.6.15.orig/arch/mips/pci/fixup-tb0219.c	2006-01-03 03:21:10.000000000 +0000
++++ linux-2.6.15/arch/mips/pci/fixup-tb0219.c	2006-01-09 19:54:12.000000000 +0000
+@@ -2,7 +2,7 @@
+  *  fixup-tb0219.c, The TANBAC TB0219 specific PCI fixups.
+  *
+  *  Copyright (C) 2003  Megasolution Inc. <matsu at megasolution.jp>
+- *  Copyright (C) 2004  Yoichi Yuasa <yuasa at hh.iij4u.or.jp>
++ *  Copyright (C) 2004-2005  Yoichi Yuasa <yuasa at hh.iij4u.or.jp>
+  *
+  *  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
+diff -Naur linux-2.6.15.orig/arch/mips/pci/fixup-tb0287.c linux-2.6.15/arch/mips/pci/fixup-tb0287.c
+--- linux-2.6.15.orig/arch/mips/pci/fixup-tb0287.c	2006-01-03 03:21:10.000000000 +0000
++++ linux-2.6.15/arch/mips/pci/fixup-tb0287.c	1970-01-01 00:00:00.000000000 +0000
+@@ -1,65 +0,0 @@
+-/*
+- *  fixup-tb0287.c, The TANBAC TB0287 specific PCI fixups.
+- *
+- *  Copyright (C) 2005  Yoichi Yuasa <yuasa at hh.iij4u.or.jp>
+- *
+- *  This program is free software; you can redistribute it and/or modify
+- *  it under the terms of the GNU General Public License as published by
+- *  the Free Software Foundation; either version 2 of the License, or
+- *  (at your option) any later version.
+- *
+- *  This program is distributed in the hope that it will be useful,
+- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+- *  GNU General Public License for more details.
+- *
+- *  You should have received a copy of the GNU General Public License
+- *  along with this program; if not, write to the Free Software
+- *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+- */
+-#include <linux/init.h>
+-#include <linux/pci.h>
+-
+-#include <asm/vr41xx/tb0287.h>
+-
+-int __init pcibios_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+-{
+-	unsigned char bus;
+-	int irq = -1;
+-
+-	bus = dev->bus->number;
+-	if (bus == 0) {
+-		switch (slot) {
+-		case 16:
+-			irq = TB0287_SM501_IRQ;
+-			break;
+-		case 17:
+-			irq = TB0287_SIL680A_IRQ;
+-			break;
+-		default:
+-			break;
+-		}
+-	} else if (bus == 1) {
+-		switch (PCI_SLOT(dev->devfn)) {
+-		case 0:
+-			irq = TB0287_PCI_SLOT_IRQ;
+-			break;
+-		case 2:
+-		case 3:
+-			irq = TB0287_RTL8110_IRQ;
+-			break;
+-		default:
+-			break;
+-		}
+-	} else if (bus > 1) {
+-		irq = TB0287_PCI_SLOT_IRQ;
+-	}
+-
+-	return irq;
+-}
+-
+-/* Do platform specific device initialization at pci_enable_device() time */
+-int pcibios_plat_dev_init(struct pci_dev *dev)
+-{
+-	return 0;
+-}
+diff -Naur linux-2.6.15.orig/arch/mips/pci/pci-vr41xx.c linux-2.6.15/arch/mips/pci/pci-vr41xx.c
+--- linux-2.6.15.orig/arch/mips/pci/pci-vr41xx.c	2006-01-03 03:21:10.000000000 +0000
++++ linux-2.6.15/arch/mips/pci/pci-vr41xx.c	2006-01-09 19:54:12.000000000 +0000
+@@ -123,10 +123,8 @@
+ 		return -EBUSY;
+ 
+ 	pciu_base = ioremap(PCIU_BASE, PCIU_SIZE);
+-	if (pciu_base == NULL) {
+-		release_mem_region(PCIU_BASE, PCIU_SIZE);
++	if (pciu_base == NULL)
+ 		return -EBUSY;
+-	}
+ 
+ 	/* Disable PCI interrupt */
+ 	vr41xx_disable_pciint();
+diff -Naur linux-2.6.15.orig/arch/mips/qemu/Makefile linux-2.6.15/arch/mips/qemu/Makefile
+--- linux-2.6.15.orig/arch/mips/qemu/Makefile	2006-01-03 03:21:10.000000000 +0000
++++ linux-2.6.15/arch/mips/qemu/Makefile	2006-01-09 19:54:12.000000000 +0000
+@@ -2,4 +2,4 @@
+ # Makefile for Qemu specific kernel interface routines under Linux.
+ #
+ 
+-obj-y		= q-firmware.o q-int.o q-irq.o q-mem.o q-setup.o
++obj-y		= q-firmware.o q-int.o q-irq.o q-mem.o q-setup.o q-vga.o
+diff -Naur linux-2.6.15.orig/arch/mips/qemu/q-setup.c linux-2.6.15/arch/mips/qemu/q-setup.c
+--- linux-2.6.15.orig/arch/mips/qemu/q-setup.c	2006-01-03 03:21:10.000000000 +0000
++++ linux-2.6.15/arch/mips/qemu/q-setup.c	2006-01-09 19:54:12.000000000 +0000
+@@ -2,6 +2,8 @@
+ #include <asm/io.h>
+ #include <asm/time.h>
+ 
++extern void qvga_init(void);
++
+ #define QEMU_PORT_BASE 0xb4000000
+ 
+ const char *get_system_type(void)
+@@ -21,5 +23,6 @@
+ void __init plat_setup(void)
+ {
+ 	set_io_port_base(QEMU_PORT_BASE);
++	qvga_init();
+ 	board_timer_setup = qemu_timer_setup;
+ }
+diff -Naur linux-2.6.15.orig/arch/mips/qemu/q-vga.c linux-2.6.15/arch/mips/qemu/q-vga.c
+--- linux-2.6.15.orig/arch/mips/qemu/q-vga.c	1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.15/arch/mips/qemu/q-vga.c	2006-01-09 19:54:12.000000000 +0000
+@@ -0,0 +1,188 @@
++/*
++ * This file is subject to the terms and conditions of the GNU General Public
++ * License.  See the file "COPYING" in the main directory of this archive
++ * for more details.
++ *
++ * Copyright (C) 2005 by Ralf Baechle (ralf at linux-mips.org)
++ *
++ * This will eventually go into the qemu firmware.
++ */
++#include <linux/init.h>
++#include <linux/tty.h>
++#include <asm/io.h>
++#include <video/vga.h>
++
++/*
++ * This will eventually be done by the firmware; right now Linux assumes to
++ * run on the uninitialized hardware.
++ */
++#undef LOAD_VGA_FONT
++
++static unsigned char sr[8] __initdata = {	/* Sequencer */
++	0x03, 0x00, 0x03, 0x04, 0x02, 0x00, 0x00, 0x00
++};
++
++static unsigned char gr[16] __initdata= {	/* Graphics Controller */
++	0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0e, 0x00,
++	0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
++};
++
++static unsigned char ar[21] __initdata= {	/* Attribute Controller */
++	0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
++	0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
++	0x0c, 0x01, 0x07, 0x13, 0x00
++};
++
++static unsigned char cr[32] __initdata= {	/* CRT Controller */
++	0x91, 0x4f, 0x4f, 0x95, 0x57, 0x4f, 0xc0, 0x1f,
++	0x00, 0x4f, 0x0d, 0x0e, 0x02, 0x30, 0x09, 0xb0,
++	0x90, 0x83, 0x8f, 0x28, 0x1f, 0x8f, 0xc1, 0xa3,
++	0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
++};
++
++static struct rgb {
++	unsigned char r;
++	unsigned char g;
++	unsigned char b;
++} palette[16] __initdata= {
++	[ 0] = {0x00, 0x00, 0x00},
++	[ 1] = {0x00, 0x00, 0x2a},
++	[ 2] = {0x00, 0x2a, 0x00},
++	[ 3] = {0x00, 0x2a, 0x2a},
++	[ 4] = {0x2a, 0x00, 0x00},
++	[ 5] = {0x2a, 0x00, 0x2a},
++	[ 6] = {0x2a, 0x15, 0x00},
++	[ 7] = {0x2a, 0x2a, 0x2a},
++	[ 8] = {0x15, 0x15, 0x15},
++	[ 9] = {0x15, 0x15, 0x3f},
++	[10] = {0x15, 0x3f, 0x15},
++	[11] = {0x15, 0x3f, 0x3f},
++	[12] = {0x3f, 0x15, 0x15},
++	[13] = {0x3f, 0x15, 0x3f},
++	[14] = {0x3f, 0x3f, 0x15},
++	[15] = {0x3f, 0x3f, 0x3f}
++
++};
++
++void __init qvga_init_ibm(void)
++{
++	int i;
++
++	for (i = 0; i < 8; i++) {	/* Sequencer registers */
++		outb(i, 0x3c4);
++		outb(sr[i], 0x3c5);
++	}
++
++	for (i = 0; i < 16; i++) {	/* Graphics Controller registers */
++		outb(i, 0x3ce);
++		outb(gr[i], 0x3cf);
++	}
++
++	for (i = 0; i < 21; i++) {	/* Attribute Controller registers */
++		outb(i, 0x3c0);
++		outb(ar[i], 0x3c1);
++	}
++	outb(0x20, 0x3c0);		/* enable bit in *index* register */
++
++	for (i = 0; i < 32; i++) {	/* CRT Controller registers */
++		outb(i, 0x3d4);
++		outb(cr[i], 0x3d5);
++	}
++
++	for (i = 0; i < 16; i++) {	/* palette */
++		outb(i, 0x3c8);
++		outb(palette[i].r, 0x3c9);
++		outb(palette[i].g, 0x3c9);
++		outb(palette[i].b, 0x3c9);
++	}
++
++#if 1
++	 for (i = 0; i < 0x20000; i += 2)
++		*(volatile unsigned short *) (0xb00a0000 + i) = 0xaaaa;
++#endif
++}
++
++#ifdef LOAD_VGA_FONT
++#include "/home/ralf/src/qemu/qemu-mips/vgafont.h"
++
++static void __init
++qvga_load_font(unsigned char *def, unsigned int c)
++{
++	volatile void *w = (volatile void *) 0xb00a0000;
++
++	vga_wseq(NULL, 0, 1);
++	vga_wseq(NULL, 2, 4);
++	vga_wseq(NULL, 4, 7);
++	vga_wseq(NULL, 0, 3);
++	vga_wgfx(NULL, 4, 2);
++	vga_wgfx(NULL, 5, 0);
++	vga_wgfx(NULL, 6, 0);
++
++	memcpy(w, def, c);
++
++	vga_wseq(NULL, 0, 1);
++	vga_wseq(NULL, 2, 3);
++	vga_wseq(NULL, 4, 3);
++	vga_wseq(NULL, 0, 3);
++	vga_wgfx(NULL, 4, 0);
++	vga_wgfx(NULL, 5, 0x10);
++	vga_wgfx(NULL, 6, 0xe);
++}
++#endif
++
++void __init qvga_init(void)
++{
++	struct screen_info *si = &screen_info;
++	unsigned int h;
++	int i;
++
++#if LOAD_VGA_FONT
++	qvga_load_font(vgafont16, 4096);
++#endif
++
++	vga_wgfx(NULL, 5, 0x10);	/* Set odd/even mode */
++	vga_wgfx(NULL, 6, 0x0c);	/* map to offset 0xb8000, text mode */
++	vga_wseq(NULL, 2, 3);		/* Planes 0 & 1 */
++	vga_wseq(NULL, 3, 4);		/* Font offset */
++	outb(1, VGA_MIS_W);		/* set msr to MSR_COLOR_EMULATION */
++	vga_wcrt(NULL, 1, 79);		/* 80 columns */
++	vga_wcrt(NULL, 9, 15);		/* 16 pixels per character */
++	vga_wcrt(NULL, 0x0c, 0);	/* start address high 8 bit */
++	vga_wcrt(NULL, 0x0d, 0);	/* start address low 8 bit */
++	vga_wcrt(NULL, 0x13, 0x28);	/* line offset */
++	vga_wcrt(NULL, 0x07, 0x1f);	/* line compare bit 8 */
++	vga_wcrt(NULL, 0x09, 0x4f);	/* line compare bit 9 */
++	vga_wcrt(NULL, 0x18, 0xff);	/* line compare low 8 bit */
++
++	h = (25 * 16);
++	vga_wcrt(NULL, 0x12, h);
++
++	outb(7, 0x3d4);
++	outb((inb(0x3d5) & ~0x42) | ((h >> 7) & 2) | ((h >> 3) & 0x40), 0x3d5);
++
++	for (i = 0; i < 21; i++)	/* Attribute Controller */
++		vga_wattr(NULL, i, ar[i]);
++	outb(0x20, 0x3c0);		/* Set bit 5 in Attribute Controller */
++					/* index ...  VGA is so stupid I want */
++					/* to cry all day ... */
++	outb(0, VGA_PEL_IW);
++	for (i = 0; i < 16; i++) {	/* palette */
++		outb(palette[i].r, VGA_PEL_D);
++		outb(palette[i].g, VGA_PEL_D);
++		outb(palette[i].b, VGA_PEL_D);
++	}
++
++	si->orig_x		= 0; 			/* Cursor x position */
++	si->orig_y		= 0;			/* Cursor y position */
++	si->orig_video_cols	= 80;			/* Columns */
++	si->orig_video_lines	= 25;			/* Lines */
++	si->orig_video_isVGA	= VIDEO_TYPE_VGAC;	/* Card type */
++	si->orig_video_points	= 16;
++
++#if 0
++	for (i = 0; i < 80; i += 2)
++		//*(volatile unsigned short *) (0xb00b8000 + i) = 0x0100 | 'A';
++		scr_writew(0x0100 | 'A', (volatile unsigned short *) (0xb00b8000 + i));
++	while (1);
++#endif
++}
+diff -Naur linux-2.6.15.orig/arch/mips/sibyte/Kconfig linux-2.6.15/arch/mips/sibyte/Kconfig
+--- linux-2.6.15.orig/arch/mips/sibyte/Kconfig	2006-01-03 03:21:10.000000000 +0000
++++ linux-2.6.15/arch/mips/sibyte/Kconfig	2006-01-09 19:54:12.000000000 +0000
+@@ -102,11 +102,11 @@
+ 	  Build a kernel suitable for running under the GDB simulator.
+ 	  Primarily adjusts the kernel's notion of time.
+ 
+-config CONFIG_SB1_CEX_ALWAYS_FATAL
++config SB1_CEX_ALWAYS_FATAL
+ 	bool "All cache exceptions considered fatal (no recovery attempted)"
+ 	depends on SIBYTE_SB1xxx_SOC
+ 
+-config CONFIG_SB1_CERR_STALL
++config SB1_CERR_STALL
+ 	bool "Stall (rather than panic) on fatal cache error"
+ 	depends on SIBYTE_SB1xxx_SOC
+ 
+diff -Naur linux-2.6.15.orig/arch/mips/vr41xx/Kconfig linux-2.6.15/arch/mips/vr41xx/Kconfig
+--- linux-2.6.15.orig/arch/mips/vr41xx/Kconfig	2006-01-03 03:21:10.000000000 +0000
++++ linux-2.6.15/arch/mips/vr41xx/Kconfig	2006-01-09 19:54:12.000000000 +0000
+@@ -1,9 +1,34 @@
++config NEC_CMBVR4133
++	bool "Support for NEC CMB-VR4133"
++	depends on MACH_VR41XX
++	select CPU_VR41XX
++	select DMA_NONCOHERENT
++	select IRQ_CPU
++	select HW_HAS_PCI
++	select PCI_VR41XX
++	select SYS_HAS_CPU_VR41XX
++	select SYS_SUPPORTS_32BIT_KERNEL
++	select SYS_SUPPORTS_64BIT_KERNEL if EXPERIMENTAL
++	select SYS_SUPPORTS_LITTLE_ENDIAN
++
++config ROCKHOPPER
++	bool "Support for Rockhopper baseboard"
++	depends on NEC_CMBVR4133
++	select I8259
++	select HAVE_STD_PC_SERIAL_PORT
++	select SYS_HAS_CPU_VR41XX
++	select SYS_SUPPORTS_32BIT_KERNEL
++	select SYS_SUPPORTS_64BIT_KERNEL if EXPERIMENTAL
++
+ config CASIO_E55
+ 	bool "Support for CASIO CASSIOPEIA E-10/15/55/65"
+ 	depends on MACH_VR41XX
+ 	select DMA_NONCOHERENT
+ 	select IRQ_CPU
+ 	select ISA
++	select SYS_HAS_CPU_VR41XX
++	select SYS_SUPPORTS_32BIT_KERNEL
++	select SYS_SUPPORTS_64BIT_KERNEL if EXPERIMENTAL
+ 	select SYS_SUPPORTS_LITTLE_ENDIAN
+ 
+ config IBM_WORKPAD
+@@ -12,52 +37,36 @@
+ 	select DMA_NONCOHERENT
+ 	select IRQ_CPU
+ 	select ISA
++	select SYS_HAS_CPU_VR41XX
++	select SYS_SUPPORTS_32BIT_KERNEL
++	select SYS_SUPPORTS_64BIT_KERNEL if EXPERIMENTAL
+ 	select SYS_SUPPORTS_LITTLE_ENDIAN
+ 
+-config NEC_CMBVR4133
+-	bool "Support for NEC CMB-VR4133"
+-	depends on MACH_VR41XX
+-	select CPU_VR41XX
+-	select DMA_NONCOHERENT
+-	select IRQ_CPU
+-	select HW_HAS_PCI
+-
+-config ROCKHOPPER
+-	bool "Support for Rockhopper baseboard"
+-	depends on NEC_CMBVR4133
+-	select I8259
+-	select HAVE_STD_PC_SERIAL_PORT
+-
+ config TANBAC_TB022X
+-	bool "Support for TANBAC VR4131 multichip module and TANBAC VR4131DIMM"
++	bool "Support for TANBAC TB0225 (VR4131 multichip module) and TB0229 (VR4131DIMM)"
+ 	depends on MACH_VR41XX
+ 	select DMA_NONCOHERENT
+ 	select HW_HAS_PCI
+ 	select IRQ_CPU
++	select SYS_HAS_CPU_VR41XX
++	select SYS_SUPPORTS_32BIT_KERNEL
++	select SYS_SUPPORTS_64BIT_KERNEL if EXPERIMENTAL
+ 	select SYS_SUPPORTS_LITTLE_ENDIAN
+ 	help
+-	  The TANBAC VR4131 multichip module(TB0225) and
+-	  the TANBAC VR4131DIMM(TB0229) are MIPS-based platforms
+-	  manufactured by TANBAC.
+-	  Please refer to <http://www.tanbac.co.jp/>
+-	  about VR4131 multichip module and VR4131DIMM.
++	  The TANBAC TB0225 (VR4131 multichip module) and TB0229 (VR4131DIMM)
++	  are MIPS-based platforms manufactured by TANBAC.
++	  Please refer to <http://www.tanbac.co.jp/> about
++	  VR4131 Multi-chip module and VR4131DIMM.
+ 
+ config TANBAC_TB0226
+-	bool "Support for TANBAC Mbase(TB0226)"
++	bool "Support for TANBAC TB0226 (Mbase)"
+ 	depends on TANBAC_TB022X
++	select PCI
++	select PCI_VR41XX
+ 	select GPIO_VR41XX
+ 	help
+-	  The TANBAC Mbase(TB0226) is a MIPS-based platform
+-	  manufactured by TANBAC.
+-	  Please refer to <http://www.tanbac.co.jp/> about Mbase.
+-
+-config TANBAC_TB0287
+-	bool "Support for TANBAC Mini-ITX DIMM base(TB0287)"
+-	depends on TANBAC_TB022X
+-	help
+-	  The TANBAC Mini-ITX DIMM base(TB0287) is a MIPS-based platform
+-	  manufactured by TANBAC.
+-	  Please refer to <http://www.tanbac.co.jp/> about Mini-ITX DIMM base.
++	  The TANBAC TB0226 (Mbase) is a MIPS-based platform manufactured by
++	  TANBAC.  Please refer to <http://www.tanbac.co.jp/> about Mbase.
+ 
+ config VICTOR_MPC30X
+ 	bool "Support for Victor MP-C303/304"
+@@ -65,7 +74,11 @@
+ 	select DMA_NONCOHERENT
+ 	select HW_HAS_PCI
+ 	select IRQ_CPU
++	select SYS_HAS_CPU_VR41XX
++	select SYS_SUPPORTS_32BIT_KERNEL
++	select SYS_SUPPORTS_64BIT_KERNEL if EXPERIMENTAL
+ 	select SYS_SUPPORTS_LITTLE_ENDIAN
++	depends on MACH_VR41XX
+ 
+ config ZAO_CAPCELLA
+ 	bool "Support for ZAO Networks Capcella"
+@@ -73,13 +86,14 @@
+ 	select DMA_NONCOHERENT
+ 	select HW_HAS_PCI
+ 	select IRQ_CPU
++	select SYS_HAS_CPU_VR41XX
++	select SYS_SUPPORTS_32BIT_KERNEL
++	select SYS_SUPPORTS_64BIT_KERNEL if EXPERIMENTAL
+ 	select SYS_SUPPORTS_LITTLE_ENDIAN
+ 
+ config PCI_VR41XX
+ 	bool "Add PCI control unit support of NEC VR4100 series"
+-	depends on MACH_VR41XX && HW_HAS_PCI
+-	default y
+-	select PCI
++	depends on MACH_VR41XX && PCI
+ 
+ config VRC4173
+ 	tristate "Add NEC VRC4173 companion chip support"
+diff -Naur linux-2.6.15.orig/arch/mips/vr41xx/nec-cmbvr4133/setup.c linux-2.6.15/arch/mips/vr41xx/nec-cmbvr4133/setup.c
+--- linux-2.6.15.orig/arch/mips/vr41xx/nec-cmbvr4133/setup.c	2006-01-03 03:21:10.000000000 +0000
++++ linux-2.6.15/arch/mips/vr41xx/nec-cmbvr4133/setup.c	2006-01-09 19:54:12.000000000 +0000
+@@ -16,6 +16,7 @@
+  */
+ #include <linux/config.h>
+ #include <linux/init.h>
++#include <linux/console.h>
+ #include <linux/ide.h>
+ #include <linux/ioport.h>
+ 
+diff -Naur linux-2.6.15.orig/drivers/char/Kconfig linux-2.6.15/drivers/char/Kconfig
+--- linux-2.6.15.orig/drivers/char/Kconfig	2006-01-03 03:21:10.000000000 +0000
++++ linux-2.6.15/drivers/char/Kconfig	2006-01-09 19:54:12.000000000 +0000
+@@ -331,23 +331,68 @@
+ 	  To compile this driver as a module, choose M here: the
+ 	  module will be called istallion.
+ 
+-config AU1000_UART
+-	bool "Enable Au1000 UART Support"
+-	depends on SERIAL_NONSTANDARD && MIPS
+-	help
+-	  If you have an Alchemy AU1000 processor (MIPS based) and you want
+-	  to use serial ports, say Y.  Otherwise, say N.
+-
+-config AU1000_SERIAL_CONSOLE
+-	bool "Enable Au1000 serial console"
+-	depends on AU1000_UART
++config AU1X00_GPIO
++	tristate "Alchemy Au1000 GPIO device support"
++	depends on MIPS && SOC_AU1X00
++
++config TS_AU1X00_ADS7846
++	tristate "Au1000/ADS7846 touchscreen support"
++	depends on MIPS && SOC_AU1X00
++
++config AU1X00_USB_TTY
++	tristate "Au1000 USB TTY Device support"
++	depends on MIPS && MIPS_AU1000 && AU1000_USB_DEVICE=y && AU1000_USB_DEVICE
++
++config AU1X00_USB_RAW
++	tristate "Au1000 USB Raw Device support"
++	depends on MIPS && MIPS_AU1000 && AU1000_USB_DEVICE=y && AU1000_USB_TTY!=y && AU1X00_USB_DEVICE
++
++config SIBYTE_SB1250_DUART
++	bool "Support for BCM1xxx onchip DUART"
++	depends on MIPS && SIBYTE_SB1xxx_SOC=y
++
++config SIBYTE_SB1250_DUART_CONSOLE
++	bool "Console on BCM1xxx DUART"
++	depends on SIBYTE_SB1250_DUART
++
++config SERIAL_DEC
++	bool "DECstation serial support"
++	depends on MACH_DECSTATION
++	default y
+ 	help
+-	  If you have an Alchemy AU1000 processor (MIPS based) and you want
+-	  to use a console on a serial port, say Y.  Otherwise, say N.
++	  This selects whether you want to be asked about drivers for
++	  DECstation serial ports.
++
++	  Note that the answer to this question won't directly affect the
++	  kernel: saying N will just cause the configurator to skip all
++	  the questions about DECstation serial ports.
++
++	  If unsure, say Y.
++
++config SERIAL_DEC_CONSOLE
++	bool "Support for console on a DECstation serial port"
++	depends on SERIAL_DEC
++	default y
++	help
++	  If you say Y here, it will be possible to use a serial port as the
++	  system console (the system console is the device which receives all
++	  kernel messages and warnings and which allows logins in single user
++	  mode).  Note that the firmware uses ttyS0 as the serial console on
++	  the Maxine and ttyS2 on the others.
++
++	  If unsure, say Y.
++
++config ZS
++	bool "Z85C30 Serial Support"
++	depends on SERIAL_DEC
++	default y
++	help
++	  Documentation on the Zilog 85C350 serial communications controller
++	  is downloadable at <http://www.zilog.com/pdfs/serial/z85c30.pdf>.
+ 
+ config QTRONIX_KEYBOARD
+ 	bool "Enable Qtronix 990P Keyboard Support"
+-	depends on IT8712
++	depends on MIPS && (MIPS_ITE8172 || MIPS_IVR)
+ 	help
+ 	  Images of Qtronix keyboards are at
+ 	  <http://www.qtronix.com/keyboard.html>.
+@@ -359,7 +404,7 @@
+ 
+ config IT8172_SCR0
+ 	bool "Enable Smart Card Reader 0 Support "
+-	depends on IT8712
++	depends on MIPS && (MIPS_ITE8172 || MIPS_IVR)
+ 	help
+ 	  Say Y here to support smart-card reader 0 (SCR0) on the Integrated
+ 	  Technology Express, Inc. ITE8172 SBC.  Vendor page at
+@@ -368,13 +413,17 @@
+ 
+ config IT8172_SCR1
+ 	bool "Enable Smart Card Reader 1 Support "
+-	depends on IT8712
++	depends on MIPS && (MIPS_ITE8172 || MIPS_IVR)
+ 	help
+ 	  Say Y here to support smart-card reader 1 (SCR1) on the Integrated
+ 	  Technology Express, Inc. ITE8172 SBC.  Vendor page at
+ 	  <http://www.ite.com.tw/ia/brief_it8172bsp.htm>; picture of the
+ 	  board at <http://www.mvista.com/partners/semiconductor/ite.html>.
+ 
++config ITE_GPIO
++	tristate "ITE GPIO"
++	depends on MIPS && MIPS_ITE8172
++
+ config A2232
+ 	tristate "Commodore A2232 serial support (EXPERIMENTAL)"
+ 	depends on EXPERIMENTAL && ZORRO && BROKEN_ON_SMP
+diff -Naur linux-2.6.15.orig/drivers/char/Makefile linux-2.6.15/drivers/char/Makefile
+--- linux-2.6.15.orig/drivers/char/Makefile	2006-01-03 03:21:10.000000000 +0000
++++ linux-2.6.15/drivers/char/Makefile	2006-01-09 19:54:12.000000000 +0000
+@@ -31,6 +31,7 @@
+ obj-$(CONFIG_A2232)		+= ser_a2232.o generic_serial.o
+ obj-$(CONFIG_ATARI_DSP56K)	+= dsp56k.o
+ obj-$(CONFIG_MOXA_SMARTIO)	+= mxser.o
++obj-$(CONFIG_SIBYTE_SB1250_DUART) += sb1250_duart.o
+ obj-$(CONFIG_COMPUTONE)		+= ip2.o ip2main.o
+ obj-$(CONFIG_RISCOM8)		+= riscom8.o
+ obj-$(CONFIG_ISI)		+= isicom.o
+@@ -48,6 +49,7 @@
+ obj-$(CONFIG_VIOTAPE)		+= viotape.o
+ obj-$(CONFIG_HVCS)		+= hvcs.o
+ obj-$(CONFIG_SGI_MBCS)		+= mbcs.o
++obj-$(CONFIG_SERIAL_DEC)	+= decserial.o
+ 
+ obj-$(CONFIG_PRINTER) += lp.o
+ obj-$(CONFIG_TIPAR) += tipar.o
+@@ -76,6 +78,10 @@
+ obj-$(CONFIG_HW_RANDOM) += hw_random.o
+ obj-$(CONFIG_FTAPE) += ftape/
+ obj-$(CONFIG_COBALT_LCD) += lcd.o
++obj-$(CONFIG_ITE_GPIO) += ite_gpio.o
++obj-$(CONFIG_AU1000_GPIO) += au1000_gpio.o
++obj-$(CONFIG_AU1000_USB_TTY) += au1000_usbtty.o
++obj-$(CONFIG_AU1000_USB_RAW) += au1000_usbraw.o
+ obj-$(CONFIG_PPDEV) += ppdev.o
+ obj-$(CONFIG_NWBUTTON) += nwbutton.o
+ obj-$(CONFIG_NWFLASH) += nwflash.o
+@@ -113,7 +119,8 @@
+ 
+ ifdef GENERATE_KEYMAP
+ 
+-$(obj)/defkeymap.c $(obj)/qtronixmap.c: $(obj)/%.c: $(src)/%.map
++$(obj)/defkeymap.c $(obj)/qtronixmap.c $(obj)/ibm_workpad_keymap.c: \
++		$(obj)/%.c: $(src)/%.map
+ 	loadkeys --mktable $< > $@.tmp
+ 	sed -e 's/^static *//' $@.tmp > $@
+ 	rm $@.tmp
+diff -Naur linux-2.6.15.orig/drivers/char/au1000_gpio.c linux-2.6.15/drivers/char/au1000_gpio.c
+--- linux-2.6.15.orig/drivers/char/au1000_gpio.c	1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.15/drivers/char/au1000_gpio.c	2006-01-09 19:54:12.000000000 +0000
+@@ -0,0 +1,266 @@
++/*
++ * FILE NAME au1000_gpio.c
++ *
++ * BRIEF MODULE DESCRIPTION
++ *  Driver for Alchemy Au1000 GPIO.
++ *
++ *  Author: MontaVista Software, Inc.  <source at mvista.com>
++ *          Steve Longerbeam <stevel at mvista.com>
++ *
++ * Copyright 2001 MontaVista Software Inc.
++ *
++ *  This program is free software; you can redistribute  it and/or modify it
++ *  under  the terms of  the GNU General  Public License as published by the
++ *  Free Software Foundation;  either version 2 of the  License, or (at your
++ *  option) any later version.
++ *
++ *  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/module.h>
++#include <linux/config.h>
++#include <linux/types.h>
++#include <linux/kernel.h>
++#include <linux/miscdevice.h>
++#include <linux/init.h>
++#include <asm/uaccess.h>
++#include <asm/io.h>
++#include <asm/au1000.h>
++#include <asm/au1000_gpio.h>
++
++#define VERSION "0.01"
++
++static const struct {
++	u32 active_hi;
++	u32 avail_mask;
++} pinfunc_to_avail[15] = {
++	{1,  0x7<<16},   // 0  = SSI0     / GPIO[18:16]
++	{-1, 0},         // 1  = AC97     / SSI1
++	{1,  1<<19},     // 2  = IRDA     / GPIO19
++	{1,  1<<20},     // 3  = UART0    / GPIO20
++	{1,  0x1f<<24},  // 4  = NIC2     / GPIO[28:24]
++	{1,  0x7<<29},   // 5  = I2S      / GPIO[31:29]
++	{0,  1<<8},      // 6  = I2SDI    / GPIO8
++	{0,  0x3f<<9},   // 7  = UART3    / GPIO[14:9]
++	{0,  1<<15},     // 8  = IRFIRSEL / GPIO15
++	{0,  1<<2},      // 9  = EXTCLK0 or OSC / GPIO2
++	{0,  1<<3},      // 10 = EXTCLK1  / GPIO3
++	{0,  1<<6},      // 11 = SMROMCKE / GPIO6
++	{1,  1<<21},     // 12 = UART1    / GPIO21
++	{1,  1<<22},     // 13 = UART2    / GPIO22
++	{1,  1<<23}      // 14 = UART3    / GPIO23
++};
++
++	
++u32 get_au1000_avail_gpio_mask(void)
++{
++	int i;
++	u32 pinfunc = inl(SYS_PINFUNC);
++	u32 avail_mask = 0; // start with no gpio available
++
++	// first, check for GPIO's reprogrammed as peripheral pins
++	for (i=0; i<15; i++) {
++		if (pinfunc_to_avail[i].active_hi < 0)
++			continue;
++		if (!(pinfunc_to_avail[i].active_hi ^
++		      ((pinfunc & (1<<i)) ? 1:0)))
++			avail_mask |= pinfunc_to_avail[i].avail_mask;
++	}
++
++	// check for GPIO's used as interrupt sources
++	avail_mask &= ~(inl(IC1_MASKRD) &
++			(inl(IC1_CFG0RD) | inl(IC1_CFG1RD)));
++
++#ifdef CONFIG_USB_OHCI
++	avail_mask &= ~((1<<4) | (1<<11));
++#ifndef CONFIG_AU1X00_USB_DEVICE
++	avail_mask &= ~((1<<5) | (1<<13));
++#endif
++#endif
++	
++	return avail_mask;
++}
++
++
++/*
++ * Tristate the requested GPIO pins specified in data.
++ * Only available GPIOs will be tristated.
++ */
++int au1000gpio_tristate(u32 data)
++{
++	data &= get_au1000_avail_gpio_mask();
++
++	if (data)
++		outl(data, SYS_TRIOUTCLR);
++
++	return 0;
++}
++
++
++/*
++ * Return the pin state. Pins configured as outputs will return
++ * the output state, and pins configured as inputs (tri-stated)
++ * will return input pin state.
++ */
++int au1000gpio_in(u32 *data)
++{
++	*data = inl(SYS_PINSTATERD);
++	return 0;
++}
++
++
++/*
++ * Set/clear GPIO pins. Only available GPIOs will be affected.
++ */
++int au1000gpio_set(u32 data)
++{
++	data &= get_au1000_avail_gpio_mask();
++
++	if (data)
++		outl(data, SYS_OUTPUTSET);
++	return 0;
++}
++
++int au1000gpio_clear(u32 data)
++{
++	data &= get_au1000_avail_gpio_mask();
++
++	if (data)
++		outl(data, SYS_OUTPUTCLR);
++	return 0;
++}
++
++/*
++ * Output data to GPIO pins. Only available GPIOs will be affected.
++ */
++int au1000gpio_out(u32 data)
++{
++	au1000gpio_set(data);
++	au1000gpio_clear(~data);
++	return 0;
++}
++
++
++EXPORT_SYMBOL(get_au1000_avail_gpio_mask);
++EXPORT_SYMBOL(au1000gpio_tristate);
++EXPORT_SYMBOL(au1000gpio_in);
++EXPORT_SYMBOL(au1000gpio_set);
++EXPORT_SYMBOL(au1000gpio_clear);
++EXPORT_SYMBOL(au1000gpio_out);
++
++
++static int au1000gpio_open(struct inode *inode, struct file *file)
++{
++	return 0;
++}
++
++
++static int au1000gpio_release(struct inode *inode, struct file *file)
++{
++	return 0;
++}
++
++
++static int au1000gpio_ioctl(struct inode *inode, struct file *file,
++			    unsigned int cmd, unsigned long arg)
++{
++	int status;
++	u32 val;
++	
++	switch(cmd) {
++	case AU1000GPIO_IN:
++		
++		status = au1000gpio_in(&val);
++		if (status != 0)
++			return status;
++
++		return put_user(val, (u32 *)arg);
++
++	case AU1000GPIO_OUT:
++
++		if (get_user(val, (u32 *)arg)) 
++			return -EFAULT;
++
++		return au1000gpio_out(val);
++
++	case AU1000GPIO_SET:
++
++		if (get_user(val, (u32 *)arg)) 
++			return -EFAULT;
++
++		return au1000gpio_set(val);
++		
++	case AU1000GPIO_CLEAR:
++
++		if (get_user(val, (u32 *)arg)) 
++			return -EFAULT;
++
++		return au1000gpio_clear(val);
++
++	case AU1000GPIO_TRISTATE:
++
++		if (get_user(val, (u32 *)arg)) 
++			return -EFAULT;
++
++		return au1000gpio_tristate(val);
++
++	case AU1000GPIO_AVAIL_MASK:
++		
++		return put_user(get_au1000_avail_gpio_mask(),
++				(u32 *)arg);
++		
++	default:
++		return -ENOIOCTLCMD;
++
++	}
++
++	return 0;
++}
++
++
++static struct file_operations au1000gpio_fops =
++{
++	.owner		= THIS_MODULE,
++	.ioctl		= au1000gpio_ioctl,
++	.open		= au1000gpio_open,
++	.release	= au1000gpio_release,
++};
++
++
++static struct miscdevice au1000gpio_miscdev =
++{
++	MISC_DYNAMIC_MINOR,
++	"au1000_gpio",
++	&au1000gpio_fops
++};
++
++
++int __init au1000gpio_init(void)
++{
++	misc_register(&au1000gpio_miscdev);
++	printk("Au1000 gpio driver, version %s\n", VERSION);
++	return 0;
++}	
++
++
++void __exit au1000gpio_exit(void)
++{
++	misc_deregister(&au1000gpio_miscdev);
++}
++
++
++module_init(au1000gpio_init);
++module_exit(au1000gpio_exit);
+diff -Naur linux-2.6.15.orig/drivers/char/au1000_ts.c linux-2.6.15/drivers/char/au1000_ts.c
+--- linux-2.6.15.orig/drivers/char/au1000_ts.c	1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.15/drivers/char/au1000_ts.c	2006-01-09 19:54:12.000000000 +0000
+@@ -0,0 +1,677 @@
++/*
++ *      au1000_ts.c  --  Touch screen driver for the Alchemy Au1000's
++ *                       SSI Port 0 talking to the ADS7846 touch screen
++ *                       controller.
++ *
++ * Copyright 2001 MontaVista Software Inc.
++ * Author: MontaVista Software, Inc.
++ *         	stevel at mvista.com or source at mvista.com
++ *
++ *  This program is free software; you can redistribute  it and/or modify it
++ *  under  the terms of  the GNU General  Public License as published by the
++ *  Free Software Foundation;  either version 2 of the  License, or (at your
++ *  option) any later version.
++ *
++ *  THIS  SOFTWARE  IS PROVIDED   ``AS  IS'' AND   ANY  EXPRESS OR IMPLIED
++ *  WARRANTIES,   INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
++ *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
++ *  NO  EVENT  SHALL   THE AUTHOR  BE    LIABLE FOR ANY   DIRECT, INDIRECT,
++ *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
++ *  NOT LIMITED   TO, PROCUREMENT OF  SUBSTITUTE GOODS  OR SERVICES; LOSS OF
++ *  USE, DATA,  OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
++ *  ANY THEORY OF LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT
++ *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
++ *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ *
++ *  You should have received a copy of the  GNU General Public License along
++ *  with this program; if not, write  to the Free Software Foundation, Inc.,
++ *  675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ * Notes:
++ *
++ *  Revision history
++ *    06.27.2001  Initial version
++ */
++
++#include <linux/module.h>
++#include <linux/version.h>
++
++#include <linux/init.h>
++#include <linux/fs.h>
++#include <linux/delay.h>
++#include <linux/poll.h>
++#include <linux/string.h>
++#include <linux/ioport.h>       /* request_region */
++#include <linux/interrupt.h>    /* mark_bh */
++#include <asm/uaccess.h>        /* get_user,copy_to_user */
++#include <asm/io.h>
++#include <asm/au1000.h>
++
++#define TS_NAME "au1000-ts"
++#define TS_MAJOR 11
++
++#define PFX TS_NAME
++#define AU1000_TS_DEBUG 1
++
++#ifdef AU1000_TS_DEBUG
++#define dbg(format, arg...) printk(KERN_DEBUG PFX ": " format "\n" , ## arg)
++#else
++#define dbg(format, arg...) do {} while (0)
++#endif
++#define err(format, arg...) printk(KERN_ERR PFX ": " format "\n" , ## arg)
++#define info(format, arg...) printk(KERN_INFO PFX ": " format "\n" , ## arg)
++#define warn(format, arg...) printk(KERN_WARNING PFX ": " format "\n" , ## arg)
++
++
++// SSI Status register bit defines
++#define SSISTAT_BF    (1<<4)
++#define SSISTAT_OF    (1<<3)
++#define SSISTAT_UF    (1<<2)
++#define SSISTAT_DONE  (1<<1)
++#define SSISTAT_BUSY  (1<<0)
++
++// SSI Interrupt Pending and Enable register bit defines
++#define SSIINT_OI     (1<<3)
++#define SSIINT_UI     (1<<2)
++#define SSIINT_DI     (1<<1)
++
++// SSI Address/Data register bit defines
++#define SSIADAT_D         (1<<24)
++#define SSIADAT_ADDR_BIT  16
++#define SSIADAT_ADDR_MASK (0xff<<SSIADAT_ADDR_BIT)
++#define SSIADAT_DATA_BIT  0
++#define SSIADAT_DATA_MASK (0xfff<<SSIADAT_DATA_BIT)
++
++// SSI Enable register bit defines
++#define SSIEN_CD (1<<1)
++#define SSIEN_E  (1<<0)
++
++// SSI Config register bit defines
++#define SSICFG_AO (1<<24)
++#define SSICFG_DO (1<<23)
++#define SSICFG_ALEN_BIT 20
++#define SSICFG_ALEN_MASK (0x7<<SSICFG_ALEN_BIT)
++#define SSICFG_DLEN_BIT 16
++#define SSICFG_DLEN_MASK (0xf<<SSICFG_DLEN_BIT)
++#define SSICFG_DD (1<<11)
++#define SSICFG_AD (1<<10)
++#define SSICFG_BM_BIT 8
++#define SSICFG_BM_MASK (0x3<<SSICFG_BM_BIT)
++#define SSICFG_CE (1<<7)
++#define SSICFG_DP (1<<6)
++#define SSICFG_DL (1<<5)
++#define SSICFG_EP (1<<4)
++
++// Bus Turnaround Selection
++#define SCLK_HOLD_HIGH 0
++#define SCLK_HOLD_LOW  1
++#define SCLK_CYCLE     2
++
++/*
++ * Default config for SSI0:
++ *
++ *   - transmit MSBit first
++ *   - expect MSBit first on data receive
++ *   - address length 7 bits
++ *   - expect data length 12 bits
++ *   - do not disable Direction bit
++ *   - do not disable Address bits
++ *   - SCLK held low during bus turnaround
++ *   - Address and Data bits clocked out on falling edge of SCLK
++ *   - Direction bit high is a read, low is a write
++ *   - Direction bit precedes Address bits
++ *   - Active low enable signal
++ */
++
++#define DEFAULT_SSI_CONFIG \
++    (SSICFG_AO | SSICFG_DO | (6<<SSICFG_ALEN_BIT) | (11<<SSICFG_DLEN_BIT) |\
++    (SCLK_HOLD_LOW<<SSICFG_BM_BIT) | SSICFG_DP | SSICFG_EP)
++
++
++// ADS7846 Control Byte bit defines
++#define ADS7846_ADDR_BIT  4
++#define ADS7846_ADDR_MASK (0x7<<ADS7846_ADDR_BIT)
++#define   ADS7846_MEASURE_X  (0x5<<ADS7846_ADDR_BIT)
++#define   ADS7846_MEASURE_Y  (0x1<<ADS7846_ADDR_BIT)
++#define   ADS7846_MEASURE_Z1 (0x3<<ADS7846_ADDR_BIT)
++#define   ADS7846_MEASURE_Z2 (0x4<<ADS7846_ADDR_BIT)
++#define ADS7846_8BITS     (1<<3)
++#define ADS7846_12BITS    0
++#define ADS7846_SER       (1<<2)
++#define ADS7846_DFR       0
++#define ADS7846_PWR_BIT   0
++#define   ADS7846_PD      0
++#define   ADS7846_ADC_ON  (0x1<<ADS7846_PWR_BIT)
++#define   ADS7846_REF_ON  (0x2<<ADS7846_PWR_BIT)
++#define   ADS7846_REF_ADC_ON (0x3<<ADS7846_PWR_BIT)
++
++#define MEASURE_12BIT_X \
++    (ADS7846_MEASURE_X | ADS7846_12BITS | ADS7846_DFR | ADS7846_PD)
++#define MEASURE_12BIT_Y \
++    (ADS7846_MEASURE_Y | ADS7846_12BITS | ADS7846_DFR | ADS7846_PD)
++#define MEASURE_12BIT_Z1 \
++    (ADS7846_MEASURE_Z1 | ADS7846_12BITS | ADS7846_DFR | ADS7846_PD)
++#define MEASURE_12BIT_Z2 \
++    (ADS7846_MEASURE_Z2 | ADS7846_12BITS | ADS7846_DFR | ADS7846_PD)
++
++typedef enum {
++	IDLE = 0,
++	ACQ_X,
++	ACQ_Y,
++	ACQ_Z1,
++	ACQ_Z2
++} acq_state_t;
++
++/* +++++++++++++ Lifted from include/linux/h3600_ts.h ++++++++++++++*/
++typedef struct {
++	unsigned short pressure;  // touch pressure
++	unsigned short x;         // calibrated X
++	unsigned short y;         // calibrated Y
++	unsigned short millisecs; // timestamp of this event
++} TS_EVENT;
++
++typedef struct {
++	int xscale;
++	int xtrans;
++	int yscale;
++	int ytrans;
++	int xyswap;
++} TS_CAL;
++
++/* Use 'f' as magic number */
++#define IOC_MAGIC  'f'
++
++#define TS_GET_RATE             _IO(IOC_MAGIC, 8)
++#define TS_SET_RATE             _IO(IOC_MAGIC, 9)
++#define TS_GET_CAL              _IOR(IOC_MAGIC, 10, TS_CAL)
++#define TS_SET_CAL              _IOW(IOC_MAGIC, 11, TS_CAL)
++
++/* +++++++++++++ Done lifted from include/linux/h3600_ts.h +++++++++*/
++
++
++#define EVENT_BUFSIZE 128
++
++/*
++ * Which pressure equation to use from ADS7846 datasheet.
++ * The first equation requires knowing only the X plate
++ * resistance, but needs 4 measurements (X, Y, Z1, Z2).
++ * The second equation requires knowing both X and Y plate
++ * resistance, but only needs 3 measurements (X, Y, Z1).
++ * The second equation is preferred because of the shorter
++ * acquisition time required.
++ */
++enum {
++	PRESSURE_EQN_1 = 0,
++	PRESSURE_EQN_2
++};
++
++
++/*
++ * The touch screen's X and Y plate resistances, used by
++ * pressure equations.
++ */
++#define DEFAULT_X_PLATE_OHMS 580
++#define DEFAULT_Y_PLATE_OHMS 580
++
++/*
++ * Pen up/down pressure resistance thresholds.
++ *
++ * FIXME: these are bogus and will have to be found empirically.
++ *
++ * These are hysteresis points. If pen state is up and pressure
++ * is greater than pen-down threshold, pen transitions to down.
++ * If pen state is down and pressure is less than pen-up threshold,
++ * pen transitions to up. If pressure is in-between, pen status
++ * doesn't change.
++ *
++ * This wouldn't be needed if PENIRQ* from the ADS7846 were
++ * routed to an interrupt line on the Au1000. This would issue
++ * an interrupt when the panel is touched.
++ */
++#define DEFAULT_PENDOWN_THRESH_OHMS 100
++#define DEFAULT_PENUP_THRESH_OHMS    80
++
++typedef struct {
++	int baudrate;
++	u32 clkdiv;
++	acq_state_t acq_state;            // State of acquisition state machine
++	int x_raw, y_raw, z1_raw, z2_raw; // The current raw acquisition values
++	TS_CAL cal;                       // Calibration values
++	// The X and Y plate resistance, needed to calculate pressure
++	int x_plate_ohms, y_plate_ohms;
++	// pressure resistance at which pen is considered down/up
++	int pendown_thresh_ohms;
++	int penup_thresh_ohms;
++	int pressure_eqn;                 // eqn to use for pressure calc
++	int pendown;                      // 1 = pen is down, 0 = pen is up
++	TS_EVENT event_buf[EVENT_BUFSIZE];// The event queue
++	int nextIn, nextOut;
++	int event_count;
++	struct fasync_struct *fasync;     // asynch notification
++	struct timer_list acq_timer;      // Timer for triggering acquisitions
++	wait_queue_head_t wait;           // read wait queue
++	spinlock_t lock;
++	struct tq_struct chug_tq;
++} au1000_ts_t;
++
++static au1000_ts_t au1000_ts;
++
++
++static inline u32
++calc_clkdiv(int baud)
++{
++	u32 sys_busclk =
++		(get_au1000_speed() / (int)(inl(PM_POWERUP_CONTROL)&0x03) + 2);
++	return (sys_busclk / (2 * baud)) - 1;
++}
++
++static inline int
++calc_baudrate(u32 clkdiv)
++{
++	u32 sys_busclk =
++		(get_au1000_speed() / (int)(inl(PM_POWERUP_CONTROL)&0x03) + 2);
++	return sys_busclk / (2 * (clkdiv + 1));
++}
++
++
++/*
++ * This is a bottom-half handler that is scheduled after
++ * raw X,Y,Z1,Z2 coordinates have been acquired, and does
++ * the following:
++ *
++ *   - computes touch screen pressure resistance
++ *   - if pressure is above a threshold considered to be pen-down:
++ *         - compute calibrated X and Y coordinates
++ *         - queue a new TS_EVENT
++ *         - signal asynchronously and wake up any read
++ */
++static void
++chug_raw_data(void* private)
++{
++	au1000_ts_t* ts = (au1000_ts_t*)private;
++	TS_EVENT event;
++	int Rt, Xcal, Ycal;
++	unsigned long flags;
++
++	// timestamp this new event.
++	event.millisecs = jiffies;
++
++	// Calculate touch pressure resistance
++	if (ts->pressure_eqn == PRESSURE_EQN_2) {
++		Rt = (ts->x_plate_ohms * ts->x_raw *
++		      (4096 - ts->z1_raw)) / ts->z1_raw;
++		Rt -= (ts->y_plate_ohms * ts->y_raw);
++		Rt = (Rt + 2048) >> 12; // round up to nearest ohm
++	} else {
++		Rt = (ts->x_plate_ohms * ts->x_raw *
++		      (ts->z2_raw - ts->z1_raw)) / ts->z1_raw;
++		Rt = (Rt + 2048) >> 12; // round up to nearest ohm
++	}
++
++	// hysteresis
++	if (!ts->pendown && Rt > ts->pendown_thresh_ohms)
++		ts->pendown = 1;
++	else if (ts->pendown && Rt < ts->penup_thresh_ohms)
++		ts->pendown = 0;
++
++	if (ts->pendown) {
++		// Pen is down
++		// Calculate calibrated X,Y
++		Xcal = ((ts->cal.xscale * ts->x_raw) >> 8) + ts->cal.xtrans;
++		Ycal = ((ts->cal.yscale * ts->y_raw) >> 8) + ts->cal.ytrans;
++
++		event.x = (unsigned short)Xcal;
++		event.y = (unsigned short)Ycal;
++		event.pressure = (unsigned short)Rt;
++
++		// add this event to the event queue
++		spin_lock_irqsave(&ts->lock, flags);
++		ts->event_buf[ts->nextIn++] = event;
++		if (ts->nextIn == EVENT_BUFSIZE)
++			ts->nextIn = 0;
++		if (ts->event_count < EVENT_BUFSIZE) {
++			ts->event_count++;
++		} else {
++			// throw out the oldest event
++			if (++ts->nextOut == EVENT_BUFSIZE)
++				ts->nextOut = 0;
++		}
++		spin_unlock_irqrestore(&ts->lock, flags);
++
++		// async notify
++		if (ts->fasync)
++			kill_fasync(&ts->fasync, SIGIO, POLL_IN);
++		// wake up any read call
++		if (waitqueue_active(&ts->wait))
++			wake_up_interruptible(&ts->wait);
++	}
++}
++
++
++/*
++ * Raw X,Y,pressure acquisition timer function. This triggers
++ * the start of a new acquisition. Its duration between calls
++ * is the touch screen polling rate.
++ */
++static void
++au1000_acq_timer(unsigned long data)
++{
++	au1000_ts_t* ts = (au1000_ts_t*)data;
++	unsigned long flags;
++
++	spin_lock_irqsave(&ts->lock, flags);
++
++	// start acquisition with X coordinate
++	ts->acq_state = ACQ_X;
++	// start me up
++	outl(SSIADAT_D | (MEASURE_12BIT_X << SSIADAT_ADDR_BIT), SSI0_ADATA);
++
++	// schedule next acquire
++	ts->acq_timer.expires = jiffies + HZ / 100;
++	add_timer(&ts->acq_timer);
++
++	spin_unlock_irqrestore(&ts->lock, flags);
++}
++
++static void
++ssi0_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++{
++	au1000_ts_t *ts = (au1000_ts_t*)dev_id;
++	u32 stat, int_stat, data;
++
++	spin_lock(&ts->lock);
++
++	stat = inl(SSI0_STATUS);
++	// clear sticky status bits
++	outl(stat & (SSISTAT_OF|SSISTAT_UF|SSISTAT_DONE), SSI0_STATUS);
++
++	int_stat = inl(SSI0_INT);
++	// clear sticky intr status bits
++	outl(int_stat & (SSIINT_OI|SSIINT_UI|SSIINT_DI), SSI0_INT);
++
++	if ((int_stat & (SSIINT_OI|SSIINT_UI|SSIINT_DI)) != SSIINT_DI) {
++		if (int_stat & SSIINT_OI)
++			err("overflow");
++		if (int_stat & SSIINT_UI)
++			err("underflow");
++		spin_unlock(&ts->lock);
++		return;
++	}
++
++	data = inl(SSI0_ADATA) & SSIADAT_DATA_MASK;
++
++	switch (ts->acq_state) {
++	case IDLE:
++		break;
++	case ACQ_X:
++		ts->x_raw = data;
++		ts->acq_state = ACQ_Y;
++		// trigger Y acq
++		outl(SSIADAT_D | (MEASURE_12BIT_Y << SSIADAT_ADDR_BIT),
++		     SSI0_ADATA);
++		break;
++	case ACQ_Y:
++		ts->y_raw = data;
++		ts->acq_state = ACQ_Z1;
++		// trigger Z1 acq
++		outl(SSIADAT_D | (MEASURE_12BIT_Z1 << SSIADAT_ADDR_BIT),
++		     SSI0_ADATA);
++		break;
++	case ACQ_Z1:
++		ts->z1_raw = data;
++		if (ts->pressure_eqn == PRESSURE_EQN_2) {
++			// don't acq Z2, using 2nd eqn for touch pressure
++			ts->acq_state = IDLE;
++			// got the raw stuff, now mark BH
++			queue_task(&ts->chug_tq, &tq_immediate);
++			mark_bh(IMMEDIATE_BH);
++		} else {
++			ts->acq_state = ACQ_Z2;
++			// trigger Z2 acq
++			outl(SSIADAT_D | (MEASURE_12BIT_Z2<<SSIADAT_ADDR_BIT),
++			     SSI0_ADATA);
++		}
++		break;
++	case ACQ_Z2:
++		ts->z2_raw = data;
++		ts->acq_state = IDLE;
++		// got the raw stuff, now mark BH
++		queue_task(&ts->chug_tq, &tq_immediate);
++		mark_bh(IMMEDIATE_BH);
++		break;
++	}
++
++	spin_unlock(&ts->lock);
++}
++
++
++/* +++++++++++++ File operations ++++++++++++++*/
++
++static int
++au1000_fasync(int fd, struct file *filp, int mode)
++{
++	au1000_ts_t* ts = (au1000_ts_t*)filp->private_data;
++	return fasync_helper(fd, filp, mode, &ts->fasync);
++}
++
++static int
++au1000_ioctl(struct inode * inode, struct file *filp,
++	     unsigned int cmd, unsigned long arg)
++{
++	au1000_ts_t* ts = (au1000_ts_t*)filp->private_data;
++
++	switch(cmd) {
++	case TS_GET_RATE:       /* TODO: what is this? */
++		break;
++	case TS_SET_RATE:       /* TODO: what is this? */
++		break;
++	case TS_GET_CAL:
++		copy_to_user((char *)arg, (char *)&ts->cal, sizeof(TS_CAL));
++		break;
++	case TS_SET_CAL:
++		copy_from_user((char *)&ts->cal, (char *)arg, sizeof(TS_CAL));
++		break;
++	default:
++		err("unknown cmd %04x", cmd);
++		return -EINVAL;
++	}
++
++	return 0;
++}
++
++static unsigned int
++au1000_poll(struct file * filp, poll_table * wait)
++{
++	au1000_ts_t* ts = (au1000_ts_t*)filp->private_data;
++	poll_wait(filp, &ts->wait, wait);
++	if (ts->event_count)
++		return POLLIN | POLLRDNORM;
++	return 0;
++}
++
++static ssize_t
++au1000_read(struct file * filp, char * buf, size_t count, loff_t * l)
++{
++	au1000_ts_t* ts = (au1000_ts_t*)filp->private_data;
++	unsigned long flags;
++	TS_EVENT event;
++	int i;
++
++	if (ts->event_count == 0) {
++		if (filp->f_flags & O_NONBLOCK)
++			return -EAGAIN;
++		interruptible_sleep_on(&ts->wait);
++		if (signal_pending(current))
++			return -ERESTARTSYS;
++	}
++
++	for (i = count;
++	     i >= sizeof(TS_EVENT);
++	     i -= sizeof(TS_EVENT), buf += sizeof(TS_EVENT)) {
++		if (ts->event_count == 0)
++			break;
++		spin_lock_irqsave(&ts->lock, flags);
++		event = ts->event_buf[ts->nextOut++];
++		if (ts->nextOut == EVENT_BUFSIZE)
++			ts->nextOut = 0;
++		if (ts->event_count)
++			ts->event_count--;
++		spin_unlock_irqrestore(&ts->lock, flags);
++		copy_to_user(buf, &event, sizeof(TS_EVENT));
++	}
++
++	return count - i;
++}
++
++
++static int
++au1000_open(struct inode * inode, struct file * filp)
++{
++	au1000_ts_t* ts;
++	unsigned long flags;
++
++	filp->private_data = ts = &au1000_ts;
++
++	spin_lock_irqsave(&ts->lock, flags);
++
++	// setup SSI0 config
++	outl(DEFAULT_SSI_CONFIG, SSI0_CONFIG);
++
++	// clear out SSI0 status bits
++	outl(SSISTAT_OF|SSISTAT_UF|SSISTAT_DONE, SSI0_STATUS);
++	// clear out SSI0 interrupt pending bits
++	outl(SSIINT_OI|SSIINT_UI|SSIINT_DI, SSI0_INT);
++
++	// enable SSI0 interrupts
++	outl(SSIINT_OI|SSIINT_UI|SSIINT_DI, SSI0_INT_ENABLE);
++
++	/*
++	 * init bh handler that chugs the raw data (calibrates and
++	 * calculates touch pressure).
++	 */
++	ts->chug_tq.routine = chug_raw_data;
++	ts->chug_tq.data = ts;
++	ts->pendown = 0; // pen up
++	
++	// flush event queue
++	ts->nextIn = ts->nextOut = ts->event_count = 0;
++	
++	// Start acquisition timer function
++	init_timer(&ts->acq_timer);
++	ts->acq_timer.function = au1000_acq_timer;
++	ts->acq_timer.data = (unsigned long)ts;
++	ts->acq_timer.expires = jiffies + HZ / 100;
++	add_timer(&ts->acq_timer);
++
++	spin_unlock_irqrestore(&ts->lock, flags);
++
++	return 0;
++}
++
++static int
++au1000_release(struct inode * inode, struct file * filp)
++{
++	au1000_ts_t* ts = (au1000_ts_t*)filp->private_data;
++	unsigned long flags;
++	
++	au1000_fasync(-1, filp, 0);
++	del_timer_sync(&ts->acq_timer);
++
++	spin_lock_irqsave(&ts->lock, flags);
++	// disable SSI0 interrupts
++	outl(0, SSI0_INT_ENABLE);
++	spin_unlock_irqrestore(&ts->lock, flags);
++
++	return 0;
++}
++
++
++static struct file_operations ts_fops = {
++	.read           = au1000_read,
++	.poll           = au1000_poll,
++	.ioctl		= au1000_ioctl,
++	.fasync         = au1000_fasync,
++	.open		= au1000_open,
++	.release	= au1000_release,
++};
++
++/* +++++++++++++ End File operations ++++++++++++++*/
++
++
++int __init
++au1000ts_init_module(void)
++{
++	au1000_ts_t* ts = &au1000_ts;
++	int ret;
++
++	/* register our character device */
++	if ((ret = register_chrdev(TS_MAJOR, TS_NAME, &ts_fops)) < 0) {
++		err("can't get major number");
++		return ret;
++	}
++	info("registered");
++
++	memset(ts, 0, sizeof(au1000_ts_t));
++	init_waitqueue_head(&ts->wait);
++	spin_lock_init(&ts->lock);
++
++	if (!request_region(virt_to_phys((void*)SSI0_STATUS), 0x100, TS_NAME)) {
++		err("SSI0 ports in use");
++		return -ENXIO;
++	}
++
++	if ((ret = request_irq(AU1000_SSI0_INT, ssi0_interrupt,
++			       SA_SHIRQ | SA_INTERRUPT, TS_NAME, ts))) {
++		err("could not get IRQ");
++		return ret;
++	}
++
++	// initial calibration values
++	ts->cal.xscale = -93;
++	ts->cal.xtrans = 346;
++	ts->cal.yscale = -64;
++	ts->cal.ytrans = 251;
++
++	// init pen up/down hysteresis points
++	ts->pendown_thresh_ohms = DEFAULT_PENDOWN_THRESH_OHMS;
++	ts->penup_thresh_ohms = DEFAULT_PENUP_THRESH_OHMS;
++	ts->pressure_eqn = PRESSURE_EQN_2;
++	// init X and Y plate resistances
++	ts->x_plate_ohms = DEFAULT_X_PLATE_OHMS;
++	ts->y_plate_ohms = DEFAULT_Y_PLATE_OHMS;
++
++	// set GPIO to SSI0 function
++	outl(inl(PIN_FUNCTION) & ~1, PIN_FUNCTION);
++	
++	// enable SSI0 clock and bring SSI0 out of reset
++	outl(0, SSI0_CONTROL);
++	udelay(1000);
++	outl(SSIEN_E, SSI0_CONTROL);
++	udelay(100);
++	
++	// FIXME: is this a working baudrate?
++	ts->clkdiv = 0;
++	ts->baudrate = calc_baudrate(ts->clkdiv);
++	outl(ts->clkdiv, SSI0_CLKDIV);
++
++	info("baudrate = %d Hz", ts->baudrate);
++	
++	return 0;
++}
++
++void
++au1000ts_cleanup_module(void)
++{
++	// disable clocks and hold in reset
++	outl(SSIEN_CD, SSI0_CONTROL);
++	free_irq(AU1000_SSI0_INT, &au1000_ts);
++	release_region(virt_to_phys((void*)SSI0_STATUS), 0x100);
++	unregister_chrdev(TS_MAJOR, TS_NAME);
++}
++
++/* Module information */
++MODULE_AUTHOR("Steve Longerbeam, stevel at mvista.com, www.mvista.com");
++MODULE_DESCRIPTION("Au1000/ADS7846 Touch Screen Driver");
++
++module_init(au1000ts_init_module);
++module_exit(au1000ts_cleanup_module);
+diff -Naur linux-2.6.15.orig/drivers/char/au1000_usbraw.c linux-2.6.15/drivers/char/au1000_usbraw.c
+--- linux-2.6.15.orig/drivers/char/au1000_usbraw.c	1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.15/drivers/char/au1000_usbraw.c	2006-01-09 19:54:12.000000000 +0000
+@@ -0,0 +1,573 @@
++/*
++ * BRIEF MODULE DESCRIPTION
++ *	Au1x00 USB Device-Side Raw Block Driver (function layer)
++ *
++ * Copyright 2001-2002 MontaVista Software Inc.
++ * Author: MontaVista Software, Inc.
++ *		stevel at mvista.com or source at mvista.com
++ *
++ *  This program is free software; you can redistribute	 it and/or modify it
++ *  under  the terms of	 the GNU General  Public License as published by the
++ *  Free Software Foundation;  either version 2 of the	License, or (at your
++ *  option) any later version.
++ *
++ *  THIS  SOFTWARE  IS PROVIDED	  ``AS	IS'' AND   ANY	EXPRESS OR IMPLIED
++ *  WARRANTIES,	  INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
++ *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
++ *  NO	EVENT  SHALL   THE AUTHOR  BE	 LIABLE FOR ANY	  DIRECT, INDIRECT,
++ *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
++ *  NOT LIMITED	  TO, PROCUREMENT OF  SUBSTITUTE GOODS	OR SERVICES; LOSS OF
++ *  USE, DATA,	OR PROFITS; OR	BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
++ *  ANY THEORY OF LIABILITY, WHETHER IN	 CONTRACT, STRICT LIABILITY, OR TORT
++ *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
++ *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ *
++ *  You should have received a copy of the  GNU General Public License along
++ *  with this program; if not, write  to the Free Software Foundation, Inc.,
++ *  675 Mass Ave, Cambridge, MA 02139, USA.
++ */
++
++#include <linux/config.h>
++#include <linux/kernel.h>
++#include <linux/ioport.h>
++#include <linux/sched.h>
++#include <linux/signal.h>
++#include <linux/errno.h>
++#include <linux/poll.h>
++#include <linux/init.h>
++#include <linux/slab.h>
++#include <linux/fcntl.h>
++#include <linux/module.h>
++#include <linux/spinlock.h>
++#include <linux/list.h>
++#include <linux/smp_lock.h>
++#undef DEBUG
++#include <linux/usb.h>
++
++#include <asm/io.h>
++#include <asm/uaccess.h>
++#include <asm/irq.h>
++#include <asm/au1000.h>
++#include <asm/au1000_usbdev.h>
++
++#define USBRAW_MAJOR 190 // FIXME: need a legal major
++#define USBRAW_NAME "usbraw"
++
++#define MAX_NUM_PORTS 2
++
++#define IN_MAX_PACKET_SIZE  64
++#define OUT_MAX_PACKET_SIZE 64
++
++// FIXME: when Au1x00 endpoints 3 and 5 are fixed, make NUM_PORTS=2
++#define NUM_PORTS 1
++#define NUM_EP 2*NUM_PORTS
++
++#define CONFIG_DESC_LEN \
++ USB_DT_CONFIG_SIZE + USB_DT_INTERFACE_SIZE + NUM_EP*USB_DT_ENDPOINT_SIZE
++
++/* must be power of two */
++#define READ_BUF_SIZE (1<<12)
++
++struct usb_raw_port {
++	unsigned char number;
++	spinlock_t port_lock;
++
++	struct usb_endpoint_descriptor* out_desc;
++	struct usb_endpoint_descriptor* in_desc;
++
++	int out_ep_addr; /* endpoint address of OUT endpoint */
++	int in_ep_addr;  /* endpoint address of IN endpoint */
++	
++	__u8 read_buf[READ_BUF_SIZE]; // FIXME: allocate with get_free_pages
++	int read_nextin, read_nextout;
++	int read_count;
++
++	wait_queue_head_t wait;
++	struct fasync_struct *fasync;     // asynch notification
++
++	int active;	/* someone has this device open */
++	int open_count;	/* number of times this port has been opened */
++};
++
++static struct usb_serial {
++	struct usb_device_descriptor* dev_desc;
++	struct usb_config_descriptor* config_desc;
++	struct usb_interface_descriptor* if_desc;
++	struct usb_string_descriptor * str_desc[6];
++	void* str_desc_buf;
++
++	usbdev_state_t dev_state;
++
++	struct usb_raw_port port[NUM_PORTS];
++} usbraw;
++
++static struct usb_device_descriptor dev_desc = {
++	bLength:USB_DT_DEVICE_SIZE,
++	bDescriptorType:USB_DT_DEVICE,
++	bcdUSB:USBDEV_REV,		//usb rev
++	bDeviceClass:USB_CLASS_PER_INTERFACE,	//class    (none)
++	bDeviceSubClass:0x00,	//subclass (none)
++	bDeviceProtocol:0x00,	//protocol (none)
++	bMaxPacketSize0:USBDEV_EP0_MAX_PACKET_SIZE, //max packet size for ep0
++	idVendor:0x6d04,	//vendor  id
++	idProduct:0x0bc0,	//product id
++	bcdDevice:0x0001,	//BCD rev 0.1
++	iManufacturer:0x01,	//manufactuer string index
++	iProduct:0x02,		//product string index
++	iSerialNumber:0x03,	//serial# string index
++	bNumConfigurations:0x01	//num configurations
++};
++
++static struct usb_endpoint_descriptor ep_desc[] = {
++	{
++		// Bulk IN for Port 0
++		bLength:USB_DT_ENDPOINT_SIZE,
++		bDescriptorType:USB_DT_ENDPOINT,
++		bEndpointAddress:USB_DIR_IN,
++		bmAttributes:USB_ENDPOINT_XFER_BULK,
++		wMaxPacketSize:IN_MAX_PACKET_SIZE,
++		bInterval:0x00	// ignored for bulk
++	},
++	{
++		// Bulk OUT for Port 0
++		bLength:USB_DT_ENDPOINT_SIZE,
++		bDescriptorType:USB_DT_ENDPOINT,
++		bEndpointAddress:USB_DIR_OUT,
++		bmAttributes:USB_ENDPOINT_XFER_BULK,
++		wMaxPacketSize:OUT_MAX_PACKET_SIZE,
++		bInterval:0x00	// ignored for bulk
++	},
++	{
++		// Bulk IN for Port 1
++		bLength:USB_DT_ENDPOINT_SIZE,
++		bDescriptorType:USB_DT_ENDPOINT,
++		bEndpointAddress:USB_DIR_IN,
++		bmAttributes:USB_ENDPOINT_XFER_BULK,
++		wMaxPacketSize:IN_MAX_PACKET_SIZE,
++		bInterval:0x00	// ignored for bulk
++	},
++	{
++		// Bulk OUT for Port 1
++		bLength:USB_DT_ENDPOINT_SIZE,
++		bDescriptorType:USB_DT_ENDPOINT,
++		bEndpointAddress:USB_DIR_OUT,
++		bmAttributes:USB_ENDPOINT_XFER_BULK,
++		wMaxPacketSize:OUT_MAX_PACKET_SIZE,
++		bInterval:0x00	// ignored for bulk
++	}
++};
++
++static struct usb_interface_descriptor if_desc = {
++	bLength:USB_DT_INTERFACE_SIZE,
++	bDescriptorType:USB_DT_INTERFACE,
++	bInterfaceNumber:0x00,
++	bAlternateSetting:0x00,
++	bNumEndpoints:NUM_EP,
++	bInterfaceClass:0xff,
++	bInterfaceSubClass:0xab,
++	bInterfaceProtocol:0x00,
++	iInterface:0x05
++};
++
++static struct usb_config_descriptor config_desc = {
++	bLength:USB_DT_CONFIG_SIZE,
++	bDescriptorType:USB_DT_CONFIG,
++	wTotalLength:CONFIG_DESC_LEN,
++	bNumInterfaces:0x01,
++	bConfigurationValue:0x01,
++	iConfiguration:0x04,	// configuration string
++	bmAttributes:0xc0,	// self-powered
++	MaxPower:20		// 40 mA
++};
++
++// String[0] is a list of Language IDs supported by this device
++static struct usb_string_descriptor string_desc0 = {
++	bLength:4,
++	bDescriptorType:USB_DT_STRING,
++	wData:{0x0409} // English, US
++};
++
++// These strings will be converted to Unicode in string_desc[]
++static char *strings[5] = {
++	"Alchemy Semiconductor",  // iManufacturer
++	"USB Raw Block Device",   // iProduct
++	"0.1",                    // iSerialNumber
++	"USB Raw Config",         // iConfiguration
++	"USB Raw Interface"       // iInterface
++};
++
++
++static void
++receive_callback(struct usb_raw_port *port)
++{
++	int i, pkt_size;
++	usbdev_pkt_t* pkt;
++	
++	if ((pkt_size = usbdev_receive_packet(port->out_ep_addr,
++					      &pkt)) <= 0) {
++		dbg(__FUNCTION__ ": usbdev_receive_packet returns %d",
++		    pkt_size);
++		return;
++	}
++
++	dbg(__FUNCTION__ ": ep%d, size=%d", port->out_ep_addr, pkt_size);
++
++	spin_lock(&port->port_lock);
++	for (i=0; i < pkt_size; i++) {
++		port->read_buf[port->read_nextin++] = pkt->payload[i];
++		port->read_nextin &= (READ_BUF_SIZE - 1);
++		if (++port->read_count == READ_BUF_SIZE)
++			break;
++	}
++	spin_unlock(&port->port_lock);
++
++	/* free the packet */
++	kfree(pkt);
++	
++	// async notify
++	if (port->fasync)
++		kill_fasync(&port->fasync, SIGIO, POLL_IN);
++	// wake up any read call
++	if (waitqueue_active(&port->wait))
++		wake_up_interruptible(&port->wait);
++}
++
++static void
++transmit_callback(struct usb_raw_port *port, usbdev_pkt_t* pkt)
++{
++	dbg(__FUNCTION__ ": ep%d", port->in_ep_addr);
++	/* just free the returned packet */
++	kfree(pkt);
++}
++
++
++static void
++usbraw_callback(usbdev_cb_type_t cb_type, unsigned long arg, void* data)
++{
++	usbdev_pkt_t* pkt;
++	int i;
++	
++	switch (cb_type) {
++	case CB_NEW_STATE:
++		usbraw.dev_state = (usbdev_state_t)arg;
++		break;
++	case CB_PKT_COMPLETE:
++		pkt = (usbdev_pkt_t*)arg;
++		for (i=0; i<NUM_PORTS; i++) {
++			struct usb_raw_port *port = &usbraw.port[i];
++			if (pkt->ep_addr == port->in_ep_addr) {
++				transmit_callback(port, pkt);
++				break;
++			} else if (pkt->ep_addr == port->out_ep_addr) {
++				receive_callback(port);
++				break;
++			}
++		}
++		break;
++	}
++}
++
++/*****************************************************************************
++ * Here begins the driver interface functions
++ *****************************************************************************/
++
++static unsigned int usbraw_poll(struct file * filp, poll_table * wait)
++{
++	struct usb_raw_port *port = (struct usb_raw_port *)filp->private_data;
++	unsigned long flags;
++	int count;
++	
++	poll_wait(filp, &port->wait, wait);
++
++	spin_lock_irqsave(&port->port_lock, flags);
++	count = port->read_count;
++	spin_unlock_irqrestore(&port->port_lock, flags);
++
++	if (count > 0) {
++		dbg(__FUNCTION__ ": count=%d", count);
++		return POLLIN | POLLRDNORM;
++	}
++	
++	return 0;
++}
++
++static int usbraw_fasync(int fd, struct file *filp, int mode)
++{
++	struct usb_raw_port *port = (struct usb_raw_port *)filp->private_data;
++	return fasync_helper(fd, filp, mode, &port->fasync);
++}
++
++static int usbraw_open(struct inode * inode, struct file *filp)
++{
++	int portNumber;
++	struct usb_raw_port *port;
++	unsigned long flags;
++
++	/*
++	 * the device-layer must be in the configured state before the
++	 * function layer can operate.
++	 */
++	if (usbraw.dev_state != CONFIGURED)
++		return -ENODEV;
++	
++	/* set up our port structure making the tty driver remember
++	   our port object, and us it */
++	portNumber = MINOR(inode->i_rdev);
++	port = &usbraw.port[portNumber];
++	filp->private_data = port;
++
++	dbg(__FUNCTION__ ": port %d", port->number);
++
++	spin_lock_irqsave(&port->port_lock, flags);
++
++	++port->open_count;
++
++	if (!port->active) {
++		port->active = 1;
++	}
++
++	/* flush read buffer */
++	port->read_nextin = port->read_nextout = port->read_count = 0;
++
++	spin_unlock_irqrestore(&port->port_lock, flags);
++
++	return 0;
++}
++
++static int usbraw_release(struct inode * inode, struct file * filp)
++{
++	struct usb_raw_port *port = (struct usb_raw_port *)filp->private_data;
++	unsigned long flags;
++
++	dbg(__FUNCTION__ ": port %d", port->number);
++
++	if (!port->active) {
++		err(__FUNCTION__ ": port not opened");
++		return -ENODEV;
++	}
++
++	usbraw_fasync(-1, filp, 0);
++
++	spin_lock_irqsave(&port->port_lock, flags);
++
++	--port->open_count;
++
++	if (port->open_count <= 0) {
++		port->active = 0;
++		port->open_count = 0;
++	}
++
++	spin_unlock_irqrestore(&port->port_lock, flags);
++
++	return 0;
++}
++
++
++static ssize_t usbraw_read(struct file * filp, char * buf,
++			   size_t count, loff_t * l)
++{
++	struct usb_raw_port *port = (struct usb_raw_port *)filp->private_data;
++	unsigned long flags;
++	int i, cnt;
++
++	/*
++	 * the device-layer must be in the configured state before the
++	 * function layer can operate.
++	 */
++	if (usbraw.dev_state != CONFIGURED)
++		return -ENODEV;
++
++	do { 
++		spin_lock_irqsave(&port->port_lock, flags);
++		cnt = port->read_count;
++		spin_unlock_irqrestore(&port->port_lock, flags);
++		if (cnt == 0) {
++			if (filp->f_flags & O_NONBLOCK)
++				return -EAGAIN;
++			interruptible_sleep_on(&port->wait);
++			if (signal_pending(current))
++				return -ERESTARTSYS;
++		}
++	} while (cnt == 0);
++
++	count = (count > cnt) ? cnt : count;
++
++	for (i=0; i<count; i++) {
++		put_user(port->read_buf[port->read_nextout++], &buf[i]);
++		port->read_nextout &= (READ_BUF_SIZE - 1);
++		spin_lock_irqsave(&port->port_lock, flags);
++		port->read_count--;
++		spin_unlock_irqrestore(&port->port_lock, flags);
++		if (port->read_count == 0)
++			break;
++	}
++
++	return i+1;
++}
++
++static ssize_t usbraw_write(struct file * filp, const char * buf,
++			    size_t count, loff_t *ppos)
++{
++	struct usb_raw_port *port = (struct usb_raw_port *)filp->private_data;
++	usbdev_pkt_t* pkt;
++	int ret, max_pkt_sz;
++	
++	/*
++	 * the device-layer must be in the configured state before the
++	 * function layer can operate.
++	 */
++	if (usbraw.dev_state != CONFIGURED)
++		return -ENODEV;
++
++	if (!port->active) {
++		err(__FUNCTION__ ": port not opened");
++		return -EINVAL;
++	}
++
++	if (count == 0) {
++		dbg(__FUNCTION__ ": write request of 0 bytes");
++		return (0);
++	}
++
++	max_pkt_sz = port->in_desc->wMaxPacketSize;
++	count = (count > max_pkt_sz) ? max_pkt_sz : count;
++
++	if ((ret = usbdev_alloc_packet(port->in_ep_addr, count, &pkt)) < 0)
++		return ret;
++
++	copy_from_user(pkt->payload, buf, count);
++	
++	return usbdev_send_packet(port->in_ep_addr, pkt);
++}
++
++static int usbraw_ioctl(struct inode *inode, struct file *filp,
++			unsigned int cmd, unsigned long arg)
++{
++	struct usb_raw_port *port = (struct usb_raw_port *)filp->private_data;
++
++	if (!port->active) {
++		err(__FUNCTION__ ": port not open");
++		return -ENODEV;
++	}
++	// FIXME: need any IOCTLs?
++
++	return -ENOIOCTLCMD;
++}
++
++
++static struct file_operations usbraw_fops = {
++        .owner          = THIS_MODULE,
++        .write          = usbraw_write,
++	.read           = usbraw_read,
++	.poll           = usbraw_poll,
++	.ioctl		= usbraw_ioctl,
++	.fasync         = usbraw_fasync,
++	.open		= usbraw_open,
++	.release	= usbraw_release,
++};
++
++void usbfn_raw_exit(void)
++{
++	/* kill the device layer */
++	usbdev_exit();
++
++	unregister_chrdev(USBRAW_MAJOR, USBRAW_NAME);
++
++	if (usbraw.str_desc_buf)
++		kfree(usbraw.str_desc_buf);
++}
++
++
++int usbfn_raw_init(void)
++{
++	int ret = 0, i, str_desc_len;
++
++	/* register our character device */
++	if ((ret = register_chrdev(USBRAW_MAJOR, USBRAW_NAME,
++				   &usbraw_fops)) < 0) {
++		err("can't get major number");
++		return ret;
++	}
++	info("registered");
++
++	/*
++	 * initialize pointers to descriptors
++	 */
++	usbraw.dev_desc = &dev_desc;
++	usbraw.config_desc = &config_desc;
++	usbraw.if_desc = &if_desc;
++
++	/*
++	 * initialize the string descriptors
++	 */
++
++	/* alloc buffer big enough for all string descriptors */
++	str_desc_len = string_desc0.bLength;
++	for (i = 0; i < 5; i++)
++		str_desc_len += 2 + 2 * strlen(strings[i]);
++	usbraw.str_desc_buf = (void *) kmalloc(str_desc_len, GFP_KERNEL);
++	if (!usbraw.str_desc_buf) {
++		err(__FUNCTION__ ": failed to alloc string descriptors");
++		ret = -ENOMEM;
++		goto out;
++	}
++
++	usbraw.str_desc[0] =
++		(struct usb_string_descriptor *)usbraw.str_desc_buf;
++	memcpy(usbraw.str_desc[0], &string_desc0, string_desc0.bLength);
++	usbraw.str_desc[1] = (struct usb_string_descriptor *)
++		(usbraw.str_desc_buf + string_desc0.bLength);
++	for (i = 1; i < 6; i++) {
++		struct usb_string_descriptor *desc = usbraw.str_desc[i];
++		char *str = strings[i - 1];
++		int j, str_len = strlen(str);
++
++		desc->bLength = 2 + 2 * str_len;
++		desc->bDescriptorType = USB_DT_STRING;
++		for (j = 0; j < str_len; j++) {
++			desc->wData[j] = (u16) str[j];
++		}
++		if (i < 5)
++			usbraw.str_desc[i + 1] =
++				(struct usb_string_descriptor *)
++				((u8 *) desc + desc->bLength);
++	}
++
++	/*
++	 * start the device layer. The device layer assigns us
++	 * our endpoint addresses
++	 */
++	if ((ret = usbdev_init(&dev_desc, &config_desc, &if_desc, ep_desc,
++			       usbraw.str_desc, usbraw_callback, NULL))) {
++		err(__FUNCTION__ ": device-layer init failed");
++		goto out;
++	}
++	
++	/* initialize the devfs nodes for this device and let the user
++	   know what ports we are bound to */
++	for (i = 0; i < NUM_PORTS; ++i) {
++		struct usb_raw_port *port = &usbraw.port[i];
++
++		port->number = i;
++		port->in_desc = &ep_desc[NUM_PORTS*i];
++		port->out_desc = &ep_desc[NUM_PORTS*i + 1];
++		port->in_ep_addr = port->in_desc->bEndpointAddress & 0x0f;
++		port->out_ep_addr = port->out_desc->bEndpointAddress & 0x0f;
++		init_waitqueue_head(&port->wait);
++		spin_lock_init(&port->port_lock);
++	}
++
++ out:
++	if (ret)
++		usbfn_raw_exit();
++	return ret;
++}
++
++
++/* Module information */
++MODULE_AUTHOR("Steve Longerbeam, stevel at mvista.com, www.mvista.com");
++MODULE_DESCRIPTION("Au1x00 USB Device-Side Raw Block Driver");
++MODULE_LICENSE("GPL");
++
++module_init(usbfn_raw_init);
++module_exit(usbfn_raw_exit);
+diff -Naur linux-2.6.15.orig/drivers/char/au1000_usbtty.c linux-2.6.15/drivers/char/au1000_usbtty.c
+--- linux-2.6.15.orig/drivers/char/au1000_usbtty.c	1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.15/drivers/char/au1000_usbtty.c	2006-01-09 19:54:12.000000000 +0000
+@@ -0,0 +1,761 @@
++/*
++ * BRIEF MODULE DESCRIPTION
++ *	Au1x00 USB Device-Side Serial TTY Driver (function layer)
++ *
++ * Copyright 2001-2002 MontaVista Software Inc.
++ * Author: MontaVista Software, Inc.
++ *		stevel at mvista.com or source at mvista.com
++ *
++ *  Derived from drivers/usb/serial/usbserial.c:
++ *
++ *  Copyright (C) 1999 - 2001 Greg Kroah-Hartman (greg at kroah.com)
++ *  Copyright (c) 2000 Peter Berger (pberger at brimson.com)
++ *  Copyright (c) 2000 Al Borchers (borchers at steinerpoint.com)
++ *
++ *  This program is free software; you can redistribute	 it and/or modify it
++ *  under  the terms of	 the GNU General  Public License as published by the
++ *  Free Software Foundation;  either version 2 of the	License, or (at your
++ *  option) any later version.
++ *
++ *  THIS  SOFTWARE  IS PROVIDED	  ``AS	IS'' AND   ANY	EXPRESS OR IMPLIED
++ *  WARRANTIES,	  INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
++ *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
++ *  NO	EVENT  SHALL   THE AUTHOR  BE	 LIABLE FOR ANY	  DIRECT, INDIRECT,
++ *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
++ *  NOT LIMITED	  TO, PROCUREMENT OF  SUBSTITUTE GOODS	OR SERVICES; LOSS OF
++ *  USE, DATA,	OR PROFITS; OR	BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
++ *  ANY THEORY OF LIABILITY, WHETHER IN	 CONTRACT, STRICT LIABILITY, OR TORT
++ *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
++ *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ *
++ *  You should have received a copy of the  GNU General Public License along
++ *  with this program; if not, write  to the Free Software Foundation, Inc.,
++ *  675 Mass Ave, Cambridge, MA 02139, USA.
++ */
++
++#include <linux/config.h>
++#include <linux/kernel.h>
++#include <linux/ioport.h>
++#include <linux/sched.h>
++#include <linux/signal.h>
++#include <linux/errno.h>
++#include <linux/poll.h>
++#include <linux/init.h>
++#include <linux/slab.h>
++#include <linux/fcntl.h>
++#include <linux/tty.h>
++#include <linux/tty_driver.h>
++#include <linux/tty_flip.h>
++#include <linux/module.h>
++#include <linux/spinlock.h>
++#include <linux/list.h>
++#include <linux/smp_lock.h>
++#undef DEBUG
++#include <linux/usb.h>
++
++#include <asm/io.h>
++#include <asm/uaccess.h>
++#include <asm/irq.h>
++#include <asm/au1000.h>
++#include <asm/au1000_usbdev.h>
++
++
++/* local function prototypes */
++static int serial_open(struct tty_struct *tty, struct file *filp);
++static void serial_close(struct tty_struct *tty, struct file *filp);
++static int serial_write(struct tty_struct *tty, int from_user,
++			const unsigned char *buf, int count);
++static int serial_write_room(struct tty_struct *tty);
++static int serial_chars_in_buffer(struct tty_struct *tty);
++static void serial_throttle(struct tty_struct *tty);
++static void serial_unthrottle(struct tty_struct *tty);
++static int serial_ioctl(struct tty_struct *tty, struct file *file,
++			unsigned int cmd, unsigned long arg);
++static void serial_set_termios (struct tty_struct *tty, struct termios * old);
++
++#define SERIAL_TTY_MAJOR 189 // FIXME: need a legal major
++
++#define MAX_NUM_PORTS 2
++
++#define IN_MAX_PACKET_SIZE  32
++#define OUT_MAX_PACKET_SIZE 32
++
++// FIXME: when Au1x00 endpoints 3 and 5 are fixed, make NUM_PORTS=2
++#define NUM_PORTS 2
++#define NUM_EP 2*NUM_PORTS
++
++#define CONFIG_DESC_LEN \
++ USB_DT_CONFIG_SIZE + USB_DT_INTERFACE_SIZE + NUM_EP*USB_DT_ENDPOINT_SIZE
++
++struct usb_serial_port {
++	struct tty_struct *tty;	   /* the coresponding tty for this port */
++	unsigned char number;
++	spinlock_t port_lock;
++
++	struct usb_endpoint_descriptor* out_desc;
++	struct usb_endpoint_descriptor* in_desc;
++
++	int out_ep_addr; /* endpoint address of OUT endpoint */
++	int in_ep_addr;  /* endpoint address of IN endpoint */
++	
++	/* task queue for line discipline waking up on send packet complete */
++	struct tq_struct send_complete_tq;
++	/* task queue for line discipline wakeup on receive packet complete */
++	struct tq_struct receive_complete_tq;
++
++	int active;	/* someone has this device open */
++	int writing;    /* a packet write is in progress */
++	int open_count;	/* number of times this port has been opened */
++
++};
++
++static struct usb_serial {
++	usbdev_state_t dev_state; // current state of device layer
++	struct usb_device_descriptor* dev_desc;
++	struct usb_config_descriptor* config_desc;
++	struct usb_interface_descriptor* if_desc;
++	struct usb_string_descriptor * str_desc[6];
++	void* str_desc_buf;
++
++	struct usb_serial_port port[NUM_PORTS];
++} usbtty;
++
++static int                 serial_refcount;
++static struct tty_driver   serial_tty_driver;
++static struct tty_struct * serial_tty[NUM_PORTS];
++static struct termios *    serial_termios[NUM_PORTS];
++static struct termios *    serial_termios_locked[NUM_PORTS];
++
++static struct usb_device_descriptor dev_desc = {
++	bLength:USB_DT_DEVICE_SIZE,
++	bDescriptorType:USB_DT_DEVICE,
++	bcdUSB:USBDEV_REV,		//usb rev
++	bDeviceClass:USB_CLASS_PER_INTERFACE,	//class    (none)
++	bDeviceSubClass:0x00,	//subclass (none)
++	bDeviceProtocol:0x00,	//protocol (none)
++	bMaxPacketSize0:USBDEV_EP0_MAX_PACKET_SIZE, //max packet size for ep0
++	idVendor:0x6d04,	//vendor  id
++	idProduct:0x0bc0,	//product id
++	bcdDevice:0x0001,	//BCD rev 0.1
++	iManufacturer:0x01,	//manufactuer string index
++	iProduct:0x02,		//product string index
++	iSerialNumber:0x03,	//serial# string index
++	bNumConfigurations:0x01	//num configurations
++};
++
++static struct usb_endpoint_descriptor ep_desc[] = {
++	{
++		// Bulk IN for Port 0
++		bLength:USB_DT_ENDPOINT_SIZE,
++		bDescriptorType:USB_DT_ENDPOINT,
++		bEndpointAddress:USB_DIR_IN,
++		bmAttributes:USB_ENDPOINT_XFER_BULK,
++		wMaxPacketSize:IN_MAX_PACKET_SIZE,
++		bInterval:0x00	// ignored for bulk
++	},
++	{
++		// Bulk OUT for Port 0
++		bLength:USB_DT_ENDPOINT_SIZE,
++		bDescriptorType:USB_DT_ENDPOINT,
++		bEndpointAddress:USB_DIR_OUT,
++		bmAttributes:USB_ENDPOINT_XFER_BULK,
++		wMaxPacketSize:OUT_MAX_PACKET_SIZE,
++		bInterval:0x00	// ignored for bulk
++	},
++	{
++		// Bulk IN for Port 1
++		bLength:USB_DT_ENDPOINT_SIZE,
++		bDescriptorType:USB_DT_ENDPOINT,
++		bEndpointAddress:USB_DIR_IN,
++		bmAttributes:USB_ENDPOINT_XFER_BULK,
++		wMaxPacketSize:IN_MAX_PACKET_SIZE,
++		bInterval:0x00	// ignored for bulk
++	},
++	{
++		// Bulk OUT for Port 1
++		bLength:USB_DT_ENDPOINT_SIZE,
++		bDescriptorType:USB_DT_ENDPOINT,
++		bEndpointAddress:USB_DIR_OUT,
++		bmAttributes:USB_ENDPOINT_XFER_BULK,
++		wMaxPacketSize:OUT_MAX_PACKET_SIZE,
++		bInterval:0x00	// ignored for bulk
++	}
++};
++
++static struct usb_interface_descriptor if_desc = {
++	bLength:USB_DT_INTERFACE_SIZE,
++	bDescriptorType:USB_DT_INTERFACE,
++	bInterfaceNumber:0x00,
++	bAlternateSetting:0x00,
++	bNumEndpoints:NUM_EP,
++	bInterfaceClass:0xff,
++	bInterfaceSubClass:0xab,
++	bInterfaceProtocol:0x00,
++	iInterface:0x05
++};
++
++static struct usb_config_descriptor config_desc = {
++	bLength:USB_DT_CONFIG_SIZE,
++	bDescriptorType:USB_DT_CONFIG,
++	wTotalLength:CONFIG_DESC_LEN,
++	bNumInterfaces:0x01,
++	bConfigurationValue:0x01,
++	iConfiguration:0x04,	// configuration string
++	bmAttributes:0xc0,	// self-powered
++	MaxPower:20		// 40 mA
++};
++
++// String[0] is a list of Language IDs supported by this device
++static struct usb_string_descriptor string_desc0 = {
++	bLength:4,
++	bDescriptorType:USB_DT_STRING,
++	wData:{0x0409} // English, US
++};
++
++// These strings will be converted to Unicode in string_desc[]
++static char *strings[5] = {
++	"Alchemy Semiconductor",  // iManufacturer
++	"WutzAMattaU",            // iProduct
++	"1.0.doh!",               // iSerialNumber
++	"Au1000 TTY Config",      // iConfiguration
++	"Au1000 TTY Interface"    // iInterface
++};
++
++static inline int
++port_paranoia_check(struct usb_serial_port *port, const char *function)
++{
++	if (!port) {
++		err("%s: port is NULL", function);
++		return -1;
++	}
++	if (!port->tty) {
++		err("%s: port->tty is NULL", function);
++		return -1;
++	}
++
++	return 0;
++}
++
++
++static void
++port_rx_callback(struct usb_serial_port *port)
++{
++	dbg(__FUNCTION__ ": ep%d", port->out_ep_addr);
++	// mark a bh to push this data up to the tty
++	queue_task(&port->receive_complete_tq, &tq_immediate);
++	mark_bh(IMMEDIATE_BH);
++}
++
++static void
++port_tx_callback(struct usb_serial_port *port, usbdev_pkt_t* pkt)
++{
++	dbg(__FUNCTION__ ": ep%d", port->in_ep_addr);
++	// mark a bh to wakeup any tty write system call on the port.
++	queue_task(&port->send_complete_tq, &tq_immediate);
++	mark_bh(IMMEDIATE_BH);
++
++	/* free the returned packet */
++	kfree(pkt);
++}
++
++static void
++usbtty_callback(usbdev_cb_type_t cb_type, unsigned long arg, void* data)
++{
++	usbdev_pkt_t* pkt;
++	int i;
++	
++	switch (cb_type) {
++	case CB_NEW_STATE:
++		dbg(__FUNCTION__ ": new dev_state=%d", (int)arg);
++		usbtty.dev_state = (usbdev_state_t)arg;
++		break;
++	case CB_PKT_COMPLETE:
++		pkt = (usbdev_pkt_t*)arg;
++		for (i=0; i<NUM_PORTS; i++) {
++			struct usb_serial_port *port = &usbtty.port[i];
++			if (pkt->ep_addr == port->in_ep_addr) {
++				port_tx_callback(port, pkt);
++				break;
++			} else if (pkt->ep_addr == port->out_ep_addr) {
++				port_rx_callback(port);
++				break;
++			}
++		}
++		break;
++	}
++}
++
++
++/*****************************************************************************
++ * Here begins the tty driver interface functions
++ *****************************************************************************/
++
++static int serial_open(struct tty_struct *tty, struct file *filp)
++{
++	int portNumber;
++	struct usb_serial_port *port;
++	unsigned long flags;
++
++	/* initialize the pointer incase something fails */
++	tty->driver_data = NULL;
++
++	/* set up our port structure making the tty driver remember
++	   our port object, and us it */
++	portNumber = MINOR(tty->device);
++	port = &usbtty.port[portNumber];
++	tty->driver_data = port;
++	port->tty = tty;
++
++	if (usbtty.dev_state != CONFIGURED ||
++	    port_paranoia_check(port, __FUNCTION__)) {
++		/*
++		 * the device-layer must be in the configured state before
++		 * the function layer can operate.
++		 */
++		return -ENODEV;
++	}
++	
++	dbg(__FUNCTION__ ": port %d", port->number);
++
++	spin_lock_irqsave(&port->port_lock, flags);
++
++	++port->open_count;
++
++	if (!port->active) {
++		port->active = 1;
++
++		/*
++		 * force low_latency on so that our tty_push actually forces
++		 * the data through, otherwise it is scheduled, and with high
++		 * data rates (like with OHCI) data can get lost.
++		 */
++		port->tty->low_latency = 1;
++
++	}
++
++	spin_unlock_irqrestore(&port->port_lock, flags);
++
++	return 0;
++}
++
++
++static void serial_close(struct tty_struct *tty, struct file *filp)
++{
++	struct usb_serial_port *port =
++		(struct usb_serial_port *) tty->driver_data;
++	unsigned long flags;
++
++	dbg(__FUNCTION__ ": port %d", port->number);
++
++	if (!port->active) {
++		err(__FUNCTION__ ": port not opened");
++		return;
++	}
++
++	spin_lock_irqsave(&port->port_lock, flags);
++
++	--port->open_count;
++
++	if (port->open_count <= 0) {
++		port->active = 0;
++		port->open_count = 0;
++	}
++
++	spin_unlock_irqrestore(&port->port_lock, flags);
++	MOD_DEC_USE_COUNT;
++}
++
++
++static int serial_write(struct tty_struct *tty, int from_user,
++			const unsigned char *buf, int count)
++{
++	struct usb_serial_port *port =
++		(struct usb_serial_port *) tty->driver_data;
++	usbdev_pkt_t* pkt;
++	int max_pkt_sz, ret;
++	unsigned long flags;
++	
++	/*
++	 * the device-layer must be in the configured state before the
++	 * function layer can operate.
++	 */
++	if (usbtty.dev_state != CONFIGURED)
++		return -ENODEV;
++
++	if (!port->active) {
++		err(__FUNCTION__ ": port not open");
++		return -EINVAL;
++	}
++
++	if (count == 0) {
++		dbg(__FUNCTION__ ": request of 0 bytes");
++		return (0);
++	}
++
++#if 0
++	if (port->writing) {
++		dbg(__FUNCTION__ ": already writing");
++		return 0;
++	}
++#endif
++	
++	max_pkt_sz = port->in_desc->wMaxPacketSize;
++	count = (count > max_pkt_sz) ? max_pkt_sz : count;
++
++	if ((ret = usbdev_alloc_packet(port->in_ep_addr, count, &pkt)))
++		return ret;
++
++	if (from_user)
++		copy_from_user(pkt->payload, buf, count);
++	else
++		memcpy(pkt->payload, buf, count);
++	
++	ret = usbdev_send_packet(port->in_ep_addr, pkt);
++
++	spin_lock_irqsave(&port->port_lock, flags);
++	port->writing = 1;
++	spin_unlock_irqrestore(&port->port_lock, flags);
++
++	return ret;
++}
++
++
++static int serial_write_room(struct tty_struct *tty)
++{
++	struct usb_serial_port *port =
++		(struct usb_serial_port *) tty->driver_data;
++	int room = 0;
++	
++	/*
++	 * the device-layer must be in the configured state before the
++	 * function layer can operate.
++	 */
++	if (usbtty.dev_state != CONFIGURED)
++		return -ENODEV;
++
++	if (!port->active) {
++		err(__FUNCTION__ ": port not open");
++		return -EINVAL;
++	}
++
++	//room = port->writing ? 0 : port->in_desc->wMaxPacketSize;
++	room = port->in_desc->wMaxPacketSize;
++	
++	dbg(__FUNCTION__ ": %d", room);
++	return room;
++}
++
++
++static int serial_chars_in_buffer(struct tty_struct *tty)
++{
++	struct usb_serial_port *port =
++		(struct usb_serial_port *) tty->driver_data;
++	int chars = 0;
++	
++	/*
++	 * the device-layer must be in the configured state before the
++	 * function layer can operate.
++	 */
++	if (usbtty.dev_state != CONFIGURED)
++		return -ENODEV;
++
++	if (!port->active) {
++		err(__FUNCTION__ ": port not open");
++		return -EINVAL;
++	}
++
++	//chars = port->writing ? usbdev_get_byte_count(port->in_ep_addr) : 0;
++	chars = usbdev_get_byte_count(port->in_ep_addr);
++
++	dbg(__FUNCTION__ ": %d", chars);
++	return chars;
++}
++
++
++static void serial_throttle(struct tty_struct *tty)
++{
++	struct usb_serial_port *port =
++		(struct usb_serial_port *) tty->driver_data;
++
++	if (!port->active || usbtty.dev_state != CONFIGURED) {
++		err(__FUNCTION__ ": port not open");
++		return;
++	}
++
++	// FIXME: anything to do?
++	dbg(__FUNCTION__);
++}
++
++
++static void serial_unthrottle(struct tty_struct *tty)
++{
++	struct usb_serial_port *port =
++		(struct usb_serial_port *) tty->driver_data;
++
++	if (!port->active || usbtty.dev_state != CONFIGURED) {
++		err(__FUNCTION__ ": port not open");
++		return;
++	}
++
++	// FIXME: anything to do?
++	dbg(__FUNCTION__);
++}
++
++
++static int serial_ioctl(struct tty_struct *tty, struct file *file,
++			unsigned int cmd, unsigned long arg)
++{
++	struct usb_serial_port *port =
++		(struct usb_serial_port *) tty->driver_data;
++
++	if (!port->active) {
++		err(__FUNCTION__ ": port not open");
++		return -ENODEV;
++	}
++	// FIXME: need any IOCTLs?
++	dbg(__FUNCTION__);
++
++	return -ENOIOCTLCMD;
++}
++
++
++static void serial_set_termios(struct tty_struct *tty, struct termios *old)
++{
++	struct usb_serial_port *port =
++		(struct usb_serial_port *) tty->driver_data;
++
++	if (!port->active || usbtty.dev_state != CONFIGURED)  {
++		err(__FUNCTION__ ": port not open");
++		return;
++	}
++
++	dbg(__FUNCTION__);
++	// FIXME: anything to do?
++}
++
++
++static void serial_break(struct tty_struct *tty, int break_state)
++{
++	struct usb_serial_port *port =
++		(struct usb_serial_port *) tty->driver_data;
++
++	if (!port->active || usbtty.dev_state != CONFIGURED)  {
++		err(__FUNCTION__ ": port not open");
++		return;
++	}
++
++	dbg(__FUNCTION__);
++	// FIXME: anything to do?
++}
++
++
++static void port_send_complete(void *private)
++{
++	struct usb_serial_port *port = (struct usb_serial_port *) private;
++	struct tty_struct *tty;
++	unsigned long flags;
++
++	dbg(__FUNCTION__ ": port %d, ep%d", port->number, port->in_ep_addr);
++
++	tty = port->tty;
++	if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
++	    tty->ldisc.write_wakeup) {
++		dbg(__FUNCTION__ ": write wakeup call.");
++		(tty->ldisc.write_wakeup) (tty);
++	}
++
++	wake_up_interruptible(&tty->write_wait);
++
++	spin_lock_irqsave(&port->port_lock, flags);
++	port->writing = usbdev_get_byte_count(port->in_ep_addr) <= 0 ? 0 : 1;
++	spin_unlock_irqrestore(&port->port_lock, flags);
++}
++
++
++static void port_receive_complete(void *private)
++{
++	struct usb_serial_port *port = (struct usb_serial_port *) private;
++	struct tty_struct *tty = port->tty;
++	usbdev_pkt_t* pkt = NULL;
++	int i, count;
++
++	/* while there is a packet available */
++	while ((count = usbdev_receive_packet(port->out_ep_addr,
++					      &pkt)) != -ENODATA) {
++		if (count < 0) {
++			if (pkt)
++				kfree(pkt);
++			break; /* exit if error other than ENODATA */
++		}
++		
++		dbg(__FUNCTION__ ": port %d, ep%d, size=%d",
++		    port->number, port->out_ep_addr, count);
++
++		for (i = 0; i < count; i++) {
++			/* if we insert more than TTY_FLIPBUF_SIZE characters,
++			   we drop them. */
++			if (tty->flip.count >= TTY_FLIPBUF_SIZE) {
++				tty_flip_buffer_push(tty);
++			}
++			/* this doesn't actually push the data through
++			   unless tty->low_latency is set */
++			tty_insert_flip_char(tty, pkt->payload[i], 0);
++		}
++		tty_flip_buffer_push(tty);
++
++		kfree(pkt); /* make sure we free the packet */
++	}
++
++}
++
++
++static struct tty_driver serial_tty_driver = {
++	.magic= TTY_DRIVER_MAGIC,
++	.driver_name= "usbfn-tty",
++	.name= "usb/ttsdev/%d",
++	.major= SERIAL_TTY_MAJOR,
++	.minor_start= 0,
++	.num= NUM_PORTS,
++	.type= TTY_DRIVER_TYPE_SERIAL,
++	.subtype= SERIAL_TYPE_NORMAL,
++	.flags= TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS,
++	.refcount= &serial_refcount,
++	.table= serial_tty,
++	.termios= serial_termios,
++	.termios_locked= serial_termios_locked,
++
++	.open= serial_open,
++	.close= serial_close,
++	.write= serial_write,
++	.write_room= serial_write_room,
++	.ioctl= serial_ioctl,
++	.set_termios= serial_set_termios,
++	.throttle= serial_throttle,
++	.unthrottle= serial_unthrottle,
++	.break_ctl= serial_break,
++	.chars_in_buffer= serial_chars_in_buffer,
++};
++
++
++void usbfn_tty_exit(void)
++{
++	int i;
++	
++	/* kill the device layer */
++	usbdev_exit();
++
++	for (i=0; i < NUM_PORTS; i++) {
++		tty_unregister_devfs(&serial_tty_driver, i);
++		info("usb serial converter now disconnected from ttyUSBdev%d",
++		     i);
++	}
++
++	tty_unregister_driver(&serial_tty_driver);
++
++	if (usbtty.str_desc_buf)
++		kfree(usbtty.str_desc_buf);
++}
++
++
++int usbfn_tty_init(void)
++{
++	int ret = 0, i, str_desc_len;
++
++	/* register the tty driver */
++	serial_tty_driver.init_termios = tty_std_termios;
++	serial_tty_driver.init_termios.c_cflag =
++		B9600 | CS8 | CREAD | HUPCL | CLOCAL;
++	
++	if (tty_register_driver(&serial_tty_driver)) {
++		err(__FUNCTION__ ": failed to register tty driver");
++		ret = -ENXIO;
++		goto out;
++	}
++
++	/*
++	 * initialize pointers to descriptors
++	 */
++	usbtty.dev_desc = &dev_desc;
++	usbtty.config_desc = &config_desc;
++	usbtty.if_desc = &if_desc;
++
++	/*
++	 * initialize the string descriptors
++	 */
++
++	/* alloc buffer big enough for all string descriptors */
++	str_desc_len = string_desc0.bLength;
++	for (i = 0; i < 5; i++)
++		str_desc_len += 2 + 2 * strlen(strings[i]);
++	usbtty.str_desc_buf = (void *) kmalloc(str_desc_len, GFP_KERNEL);
++	if (!usbtty.str_desc_buf) {
++		err(__FUNCTION__ ": failed to alloc string descriptors");
++		ret = -ENOMEM;
++		goto out;
++	}
++
++	usbtty.str_desc[0] =
++		(struct usb_string_descriptor *)usbtty.str_desc_buf;
++	memcpy(usbtty.str_desc[0], &string_desc0, string_desc0.bLength);
++	usbtty.str_desc[1] = (struct usb_string_descriptor *)
++		(usbtty.str_desc_buf + string_desc0.bLength);
++	for (i = 1; i < 6; i++) {
++		struct usb_string_descriptor *desc = usbtty.str_desc[i];
++		char *str = strings[i - 1];
++		int j, str_len = strlen(str);
++
++		desc->bLength = 2 + 2 * str_len;
++		desc->bDescriptorType = USB_DT_STRING;
++		for (j = 0; j < str_len; j++) {
++			desc->wData[j] = (u16) str[j];
++		}
++		if (i < 5)
++			usbtty.str_desc[i + 1] =
++				(struct usb_string_descriptor *)
++				((u8 *) desc + desc->bLength);
++	}
++
++	/*
++	 * start the device layer. The device layer assigns us
++	 * our endpoint addresses
++	 */
++	if ((ret = usbdev_init(&dev_desc, &config_desc, &if_desc, ep_desc,
++			       usbtty.str_desc, usbtty_callback, NULL))) {
++		err(__FUNCTION__ ": device-layer init failed");
++		goto out;
++	}
++	
++	/* initialize the devfs nodes for this device and let the user
++	   know what ports we are bound to */
++	for (i = 0; i < NUM_PORTS; ++i) {
++		struct usb_serial_port *port;
++		tty_register_devfs(&serial_tty_driver, 0, i);
++		info("usbdev serial attached to ttyUSBdev%d "
++		     "(or devfs usb/ttsdev/%d)", i, i);
++		port = &usbtty.port[i];
++		port->number = i;
++		port->in_desc = &ep_desc[NUM_PORTS*i];
++		port->out_desc = &ep_desc[NUM_PORTS*i + 1];
++		port->in_ep_addr = port->in_desc->bEndpointAddress & 0x0f;
++		port->out_ep_addr = port->out_desc->bEndpointAddress & 0x0f;
++		port->send_complete_tq.routine = port_send_complete;
++		port->send_complete_tq.data = port;
++		port->receive_complete_tq.routine = port_receive_complete;
++		port->receive_complete_tq.data = port;
++		spin_lock_init(&port->port_lock);
++	}
++
++ out:
++	if (ret)
++		usbfn_tty_exit();
++	return ret;
++}
++
++
++/* Module information */
++MODULE_AUTHOR("Steve Longerbeam, stevel at mvista.com, www.mvista.com");
++MODULE_DESCRIPTION("Au1x00 USB Device-Side Serial TTY Driver");
++MODULE_LICENSE("GPL");
++
++module_init(usbfn_tty_init);
++module_exit(usbfn_tty_exit);
+diff -Naur linux-2.6.15.orig/drivers/char/decserial.c linux-2.6.15/drivers/char/decserial.c
+--- linux-2.6.15.orig/drivers/char/decserial.c	2006-01-03 03:21:10.000000000 +0000
++++ linux-2.6.15/drivers/char/decserial.c	2006-01-09 19:54:12.000000000 +0000
+@@ -14,87 +14,85 @@
+  *      device. Added support for PROM console in drivers/char/tty_io.c
+  *      instead. Although it may work to enable more than one 
+  *      console device I strongly recommend to use only one.
++ *
++ *	Copyright (C) 2004  Maciej W. Rozycki
+  */
+ 
+ #include <linux/config.h>
++#include <linux/errno.h>
+ #include <linux/init.h>
+-#include <asm/dec/machtype.h>
+-
+-#ifdef CONFIG_ZS
+-extern int zs_init(void);
+-#endif
+ 
+-#ifdef CONFIG_DZ
+-extern int dz_init(void);
+-#endif
++#include <asm/dec/machtype.h>
++#include <asm/dec/serial.h>
+ 
+-#ifdef CONFIG_SERIAL_CONSOLE
++extern int register_zs_hook(unsigned int channel,
++			    struct dec_serial_hook *hook);
++extern int unregister_zs_hook(unsigned int channel);
+ 
++int register_dec_serial_hook(unsigned int channel,
++			     struct dec_serial_hook *hook)
++{
+ #ifdef CONFIG_ZS
+-extern void zs_serial_console_init(void);
+-#endif
+-
+-#ifdef CONFIG_DZ
+-extern void dz_serial_console_init(void);
++	if (IOASIC)
++		return register_zs_hook(channel, hook);
+ #endif
++	return 0;
++}
+ 
++int unregister_dec_serial_hook(unsigned int channel)
++{
++#ifdef CONFIG_ZS
++	if (IOASIC)
++		return unregister_zs_hook(channel);
+ #endif
++	return 0;
++}
+ 
+-/* rs_init - starts up the serial interface -
+-   handle normal case of starting up the serial interface */
+ 
+-#ifdef CONFIG_SERIAL
++extern int zs_init(void);
++extern int dz_init(void);
+ 
++/*
++ * rs_init - starts up the serial interface -
++ * handle normal case of starting up the serial interface
++ */
+ int __init rs_init(void)
+ {
+-
+-#if defined(CONFIG_ZS) && defined(CONFIG_DZ)
+-    if (IOASIC)
+-	return zs_init();
+-    else
+-	return dz_init();
+-#else
+-
+ #ifdef CONFIG_ZS
+-    return zs_init();
++	if (IOASIC)
++		return zs_init();
+ #endif
+-
+ #ifdef CONFIG_DZ
+-    return dz_init();
+-#endif
+-
++	if (!IOASIC)
++		return dz_init();
+ #endif
++	return -ENXIO;
+ }
+ 
+ __initcall(rs_init);
+ 
+-#endif
+ 
+-#ifdef CONFIG_SERIAL_CONSOLE
++#ifdef CONFIG_SERIAL_DEC_CONSOLE
++
++extern void zs_serial_console_init(void);
++extern void dz_serial_console_init(void);
+ 
+-/* serial_console_init handles the special case of starting
+- *   up the console on the serial port
++/*
++ * dec_serial_console_init handles the special case of starting
++ * up the console on the serial port
+  */
+-static int __init decserial_console_init(void)
++static int __init dec_serial_console_init(void)
+ {
+-#if defined(CONFIG_ZS) && defined(CONFIG_DZ)
+-    if (IOASIC)
+-	zs_serial_console_init();
+-    else
+-	dz_serial_console_init();
+-#else
+-
+ #ifdef CONFIG_ZS
+-    zs_serial_console_init();
++	if (IOASIC)
++		zs_serial_console_init();
+ #endif
+-
+ #ifdef CONFIG_DZ
+-    dz_serial_console_init();
+-#endif
+-
++	if (!IOASIC)
++		dz_serial_console_init();
+ #endif
+     return 0;
+ }
+-console_initcall(decserial_console_init);
++console_initcall(dec_serial_console_init);
+ 
+ #endif
+diff -Naur linux-2.6.15.orig/drivers/char/ibm_workpad_keymap.map linux-2.6.15/drivers/char/ibm_workpad_keymap.map
+--- linux-2.6.15.orig/drivers/char/ibm_workpad_keymap.map	1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.15/drivers/char/ibm_workpad_keymap.map	2006-01-09 19:54:12.000000000 +0000
+@@ -0,0 +1,343 @@
++# Keymap for IBM Workpad z50
++# US Mapping
++#
++# by Michael Klar <wyldfier at iname.com>
++#
++# This is a great big mess on account of how the Caps Lock key is handled as
++# LeftShift-RightShift.  Right shift key had to be broken out, so don't use
++# use this map file as a basis for other keyboards that don't do the same
++# thing with Caps Lock.
++#
++# This file is subject to the terms and conditions of the GNU General Public
++# License.  See the file "COPYING" in the main directory of this archive
++# for more details.
++
++keymaps 0-2,4-5,8,12,32-33,36-37
++strings as usual
++
++keycode 0 = F1 F11 Console_13
++	shiftr keycode 0 = F11
++	shift shiftr keycode 0 = F11
++	control keycode 0 = F1
++	alt keycode 0 = Console_1
++	control alt keycode 0 = Console_1
++keycode 1 = F3 F13 Console_15
++	shiftr keycode 1 = F13
++	shift shiftr keycode 1 = F13
++	control keycode 1 = F3
++	alt keycode 1 = Console_3
++	control alt keycode 1 = Console_3
++keycode 2 = F5 F15 Console_17
++	shiftr keycode 2 = F15
++	shift shiftr keycode 2 = F15
++	control keycode 2 = F5
++	alt keycode 2 = Console_5
++	control alt keycode 2 = Console_5
++keycode 3 = F7 F17 Console_19
++	shiftr keycode 3 = F17
++	shift shiftr keycode 3 = F17
++	control keycode 3 = F7
++	alt keycode 3 = Console_7
++	control alt keycode 3 = Console_7
++keycode 4 = F9 F19 Console_21
++	shiftr keycode 4 = F19
++	shift shiftr keycode 4 = F19
++	control keycode 4 = F9
++	alt keycode 4 = Console_9
++	control alt keycode 4 = Console_9
++#keycode 5 is contrast down
++#keycode 6 is contrast up
++keycode 7 = F11 F11 Console_23
++	shiftr keycode 7 = F11
++	shift shiftr keycode 7 = F11
++	control keycode 7 = F11
++	alt keycode 7 = Console_11
++	control alt keycode 7 = Console_11
++keycode 8 = F2 F12 Console_14
++	shiftr keycode 8 = F12
++	shift shiftr keycode 8 = F12
++	control keycode 8 = F2
++	alt keycode 8 = Console_2
++	control alt keycode 8 = Console_2
++keycode 9 = F4 F14 Console_16
++	shiftr keycode 9 = F14
++	shift shiftr keycode 9 = F14
++	control keycode 9 = F4
++	alt keycode 9 = Console_4
++	control alt keycode 9 = Console_4
++keycode 10 = F6 F16 Console_18
++	shiftr keycode 10 = F16
++	shift shiftr keycode 10 = F16
++	control keycode 10 = F6
++	alt keycode 10 = Console_6
++	control alt keycode 10 = Console_6
++keycode 11 = F8 F18 Console_20
++	shiftr keycode 11 = F18
++	shift shiftr keycode 11 = F18
++	control keycode 11 = F8
++	alt keycode 11 = Console_8
++	control alt keycode 11 = Console_8
++keycode 12 = F10 F20 Console_22
++	shiftr keycode 12 = F20
++	shift shiftr keycode 12 = F20
++	control keycode 12 = F10
++	alt keycode 12 = Console_10
++	control alt keycode 12 = Console_10
++#keycode 13 is brightness down
++#keycode 14 is brightness up
++keycode 15 = F12 F12 Console_24
++	shiftr keycode 15 = F12
++	shift shiftr keycode 15 = F12
++	control keycode 15 = F12
++	alt keycode 15 = Console_12
++	control alt keycode 15 = Console_12
++keycode 16 = apostrophe quotedbl
++	shiftr keycode 16 = quotedbl
++	shift shiftr keycode 16 = quotedbl
++	control keycode 16 = Control_g
++	alt keycode 16 = Meta_apostrophe
++keycode 17 = bracketleft braceleft
++	shiftr keycode 17 = braceleft
++	shift shiftr keycode 17 = braceleft
++	control keycode 17 = Escape
++	alt keycode 17 = Meta_bracketleft
++keycode 18 = minus underscore backslash       
++	shiftr keycode 18 = underscore
++	shift shiftr keycode 18 = underscore
++	control keycode 18 = Control_underscore
++	shift control keycode 18 = Control_underscore
++	shiftr control keycode 18 = Control_underscore
++	shift shiftr control keycode 18 = Control_underscore
++	alt keycode 18 = Meta_minus
++keycode 19 = zero parenright braceright
++	shiftr keycode 19 = parenright
++	shift shiftr keycode 19 = parenright
++	alt keycode 19 = Meta_zero
++keycode 20 = p
++	shiftr keycode 20 = +P
++	shift shiftr keycode 20 = +p
++keycode 21 = semicolon colon
++	shiftr keycode 21 = colon
++	shift shiftr keycode 21 = colon
++	alt keycode 21 = Meta_semicolon
++keycode 22 = Up Scroll_Backward
++	shiftr keycode 22 = Scroll_Backward
++	shift shiftr keycode 22 = Scroll_Backward
++	alt keycode 22 = Prior
++keycode 23 = slash question
++	shiftr keycode 23 = question
++	shift shiftr keycode 23 = question
++	control keycode 23 = Delete
++	alt keycode 23 = Meta_slash
++
++keycode 27 = nine parenleft bracketright
++	shiftr keycode 27 = parenleft
++	shift shiftr keycode 27 = parenleft
++	alt keycode 27 = Meta_nine
++keycode 28 = o
++	shiftr keycode 28 = +O
++	shift shiftr keycode 28 = +o
++keycode 29 = l
++	shiftr keycode 29 = +L
++	shift shiftr keycode 29 = +l
++keycode 30 = period greater
++	shiftr keycode 30 = greater
++	shift shiftr keycode 30 = greater
++	control keycode 30 = Compose
++	alt keycode 30 = Meta_period
++
++keycode 32 = Left Decr_Console
++	shiftr keycode 32 = Decr_Console
++	shift shiftr keycode 32 = Decr_Console
++	alt keycode 32 = Home
++keycode 33 = bracketright braceright asciitilde      
++	shiftr keycode 33 = braceright
++	shift shiftr keycode 33 = braceright
++	control keycode 33 = Control_bracketright
++	alt keycode 33 = Meta_bracketright
++keycode 34 = equal plus
++	shiftr keycode 34 = plus
++	shift shiftr keycode 34 = plus
++	alt keycode 34 = Meta_equal
++keycode 35 = eight asterisk bracketleft
++	shiftr keycode 35 = asterisk
++	shift shiftr keycode 35 = asterisk
++	control keycode 35 = Delete
++	alt keycode 35 = Meta_eight
++keycode 36 = i
++	shiftr keycode 36 = +I
++	shift shiftr keycode 36 = +i
++keycode 37 = k
++	shiftr keycode 37 = +K
++	shift shiftr keycode 37 = +k
++keycode 38 = comma less
++	shiftr keycode 38 = less
++	shift shiftr keycode 38 = less
++	alt keycode 38 = Meta_comma
++
++keycode 40 = h
++	shiftr keycode 40 = +H
++	shift shiftr keycode 40 = +h
++keycode 41 = y
++	shiftr keycode 41 = +Y
++	shift shiftr keycode 41 = +y
++keycode 42 = six asciicircum
++	shiftr keycode 42 = asciicircum
++	shift shiftr keycode 42 = asciicircum
++	control keycode 42 = Control_asciicircum
++	alt keycode 42 = Meta_six
++keycode 43 = seven ampersand braceleft
++	shiftr keycode 43 = ampersand
++	shift shiftr keycode 43 = ampersand
++	control keycode 43 = Control_underscore
++	alt keycode 43 = Meta_seven
++keycode 44 = u
++	shiftr keycode 44 = +U
++	shift shiftr keycode 44 = +u
++keycode 45 = j
++	shiftr keycode 45 = +J
++	shift shiftr keycode 45 = +j
++keycode 46 = m
++	shiftr keycode 46 = +M
++	shift shiftr keycode 46 = +m
++keycode 47 = n
++	shiftr keycode 47 = +N
++	shift shiftr keycode 47 = +n
++
++# This is the "Backspace" key:
++keycode 49 = Delete Delete
++	shiftr keycode 49 = Delete
++	shift shiftr keycode 49 = Delete
++	control keycode 49 = BackSpace
++	alt keycode 49 = Meta_Delete
++keycode 50 = Num_Lock
++	shift keycode 50 = Bare_Num_Lock
++	shiftr keycode 50 = Bare_Num_Lock
++	shift shiftr keycode 50 = Bare_Num_Lock
++# This is the "Delete" key:
++keycode 51 = Remove
++	control alt keycode 51 = Boot
++
++keycode 53 = backslash bar
++	shiftr keycode 53 = bar
++	shift shiftr keycode 53 = bar
++	control keycode 53 = Control_backslash
++	alt keycode 53 = Meta_backslash
++keycode 54 = Return
++	alt keycode 54 = Meta_Control_m
++keycode 55 = space space           
++	shiftr keycode 55 = space
++	shift shiftr keycode 55 = space
++	control keycode 55 = nul
++	alt keycode 55 = Meta_space
++keycode 56 = g
++	shiftr keycode 56 = +G
++	shift shiftr keycode 56 = +g
++keycode 57 = t
++	shiftr keycode 57 = +T
++	shift shiftr keycode 57 = +t
++keycode 58 = five percent
++	shiftr keycode 58 = percent
++	shift shiftr keycode 58 = percent
++	control keycode 58 = Control_bracketright
++	alt keycode 58 = Meta_five
++keycode 59 = four dollar dollar
++	shiftr keycode 59 = dollar
++	shift shiftr keycode 59 = dollar
++	control keycode 59 = Control_backslash
++	alt keycode 59 = Meta_four
++keycode 60 = r
++	shiftr keycode 60 = +R
++	shift shiftr keycode 60 = +r
++keycode 61 = f
++	shiftr keycode 61 = +F
++	shift shiftr keycode 61 = +f
++	altgr keycode 61 = Hex_F
++keycode 62 = v
++	shiftr keycode 62 = +V
++	shift shiftr keycode 62 = +v
++keycode 63 = b
++	shiftr keycode 63 = +B
++	shift shiftr keycode 63 = +b
++	altgr keycode 63 = Hex_B
++
++keycode 67 = three numbersign
++	shiftr keycode 67 = numbersign
++	shift shiftr keycode 67 = numbersign
++	control keycode 67 = Escape
++	alt keycode 67 = Meta_three
++keycode 68 = e
++	shiftr keycode 68 = +E
++	shift shiftr keycode 68 = +e
++	altgr keycode 68 = Hex_E
++keycode 69 = d
++	shiftr keycode 69 = +D
++	shift shiftr keycode 69 = +d
++	altgr keycode 69 = Hex_D
++keycode 70 = c
++	shiftr keycode 70 = +C
++	shift shiftr keycode 70 = +c
++	altgr keycode 70 = Hex_C
++keycode 71 = Right Incr_Console
++	shiftr keycode 71 = Incr_Console
++	shift shiftr keycode 71 = Incr_Console
++	alt keycode 71 = End
++
++keycode 75 = two at at
++	shiftr keycode 75 = at
++	shift shiftr keycode 75 = at
++	control keycode 75 = nul
++	shift control keycode 75 = nul
++	shiftr control keycode 75 = nul
++	shift shiftr control keycode 75 = nul
++	alt keycode 75 = Meta_two
++keycode 76 = w
++	shiftr keycode 76 = +W
++	shift shiftr keycode 76 = +w
++keycode 77 = s
++	shiftr keycode 77 = +S
++	shift shiftr keycode 77 = +s
++keycode 78 = x
++	shiftr keycode 78 = +X
++	shift shiftr keycode 78 = +x
++keycode 79 = Down Scroll_Forward
++	shiftr keycode 79 = Scroll_Forward
++	shift shiftr keycode 79 = Scroll_Forward
++	alt keycode 79 = Next
++keycode 80 = Escape Escape
++	shiftr keycode 80 = Escape
++	shift shiftr keycode 80 = Escape
++	alt keycode 80 = Meta_Escape
++keycode 81 = Tab Tab             
++	shiftr keycode 81 = Tab
++	shift shiftr keycode 81 = Tab
++	alt keycode 81 = Meta_Tab
++keycode 82 = grave asciitilde
++	shiftr keycode 82 = asciitilde
++	shift shiftr keycode 82 = asciitilde
++	control keycode 82 = nul
++	alt keycode 82 = Meta_grave
++keycode 83 = one exclam
++	shiftr keycode 83 = exclam
++	shift shiftr keycode 83 = exclam
++	alt keycode 83 = Meta_one
++keycode 84 = q
++	shiftr keycode 84 = +Q
++	shift shiftr keycode 84 = +q
++keycode 85 = a
++	shiftr keycode 85 = +A
++	shift shiftr keycode 85 = +a
++	altgr keycode 85 = Hex_A
++keycode 86 = z
++	shiftr keycode 86 = +Z
++	shift shiftr keycode 86 = +z
++
++# This is the windows key:
++keycode 88 = Decr_Console
++keycode 89 = Shift
++keycode 90 = Control
++keycode 91 = Control
++keycode 92 = Alt
++keycode 93 = AltGr
++keycode 94 = ShiftR
++	shift keycode 94 = Caps_Lock
+diff -Naur linux-2.6.15.orig/drivers/char/qtronix.c linux-2.6.15/drivers/char/qtronix.c
+--- linux-2.6.15.orig/drivers/char/qtronix.c	2006-01-03 03:21:10.000000000 +0000
++++ linux-2.6.15/drivers/char/qtronix.c	2006-01-09 19:54:12.000000000 +0000
+@@ -535,8 +535,7 @@
+ 		i--;
+ 	}
+ 	if (count-i) {
+-		struct inode *inode = file->f_dentry->d_inode;
+-		inode->i_atime = current_fs_time(inode->i_sb);
++		file->f_dentry->d_inode->i_atime = get_seconds();
+ 		return count-i;
+ 	}
+ 	if (signal_pending(current))
+diff -Naur linux-2.6.15.orig/drivers/char/rtc.c linux-2.6.15/drivers/char/rtc.c
+--- linux-2.6.15.orig/drivers/char/rtc.c	2006-01-03 03:21:10.000000000 +0000
++++ linux-2.6.15/drivers/char/rtc.c	2006-01-09 19:54:12.000000000 +0000
+@@ -35,23 +35,21 @@
+  *	1.09a	Pete Zaitcev: Sun SPARC
+  *	1.09b	Jeff Garzik: Modularize, init cleanup
+  *	1.09c	Jeff Garzik: SMP cleanup
+- *	1.10    Paul Barton-Davis: add support for async I/O
++ *	1.10	Paul Barton-Davis: add support for async I/O
+  *	1.10a	Andrea Arcangeli: Alpha updates
+  *	1.10b	Andrew Morton: SMP lock fix
+  *	1.10c	Cesar Barros: SMP locking fixes and cleanup
+  *	1.10d	Paul Gortmaker: delete paranoia check in rtc_exit
+  *	1.10e	Maciej W. Rozycki: Handle DECstation's year weirdness.
+- *      1.11    Takashi Iwai: Kernel access functions
++ *	1.11	Takashi Iwai: Kernel access functions
+  *			      rtc_register/rtc_unregister/rtc_control
+  *      1.11a   Daniele Bellucci: Audit create_proc_read_entry in rtc_init
+- *	1.12	Venkatesh Pallipadi: Hooks for emulating rtc on HPET base-timer
++ *	1.12    Venkatesh Pallipadi: Hooks for emulating rtc on HPET base-timer
+  *		CONFIG_HPET_EMULATE_RTC
+- *
++ *	1.12a	Maciej W. Rozycki: Handle memory-mapped chips properly.
+  */
+ 
+-#define RTC_VERSION		"1.12"
+-
+-#define RTC_IO_EXTENT	0x8
++#define RTC_VERSION		"1.12a"
+ 
+ /*
+  *	Note that *all* calls to CMOS_READ and CMOS_WRITE are done with
+@@ -338,7 +336,15 @@
+ 	if (rtc_has_irq == 0)
+ 		return -EIO;
+ 
+-	if (count < sizeof(unsigned))
++	/*
++	 * Historically this function used to assume that sizeof(unsigned long)
++	 * is the same in userspace and kernelspace.  This lead to problems
++	 * for configurations with multiple ABIs such a the MIPS o32 and 64
++	 * ABIs supported on the same kernel.  So now we support read of both
++	 * 4 and 8 bytes and assume that's the sizeof(unsigned long) in the
++	 * userspace ABI.
++	 */
++	if (count != sizeof(unsigned int) && count !=  sizeof(unsigned long))
+ 		return -EINVAL;
+ 
+ 	add_wait_queue(&rtc_wait, &wait);
+@@ -369,10 +375,12 @@
+ 		schedule();
+ 	} while (1);
+ 
+-	if (count < sizeof(unsigned long))
+-		retval = put_user(data, (unsigned int __user *)buf) ?: sizeof(int); 
++	if (count == sizeof(unsigned int))
++		retval = put_user(data, (unsigned int __user *)buf) ?: sizeof(int);
+ 	else
+ 		retval = put_user(data, (unsigned long __user *)buf) ?: sizeof(long);
++	if (!retval)
++		retval = count;
+  out:
+ 	current->state = TASK_RUNNING;
+ 	remove_wait_queue(&rtc_wait, &wait);
+@@ -924,6 +932,9 @@
+ 	struct sparc_isa_device *isa_dev;
+ #endif
+ #endif
++#ifndef __sparc__
++	void *r;
++#endif
+ 
+ #ifdef __sparc__
+ 	for_each_ebus(ebus) {
+@@ -969,8 +980,13 @@
+ 	}
+ no_irq:
+ #else
+-	if (!request_region(RTC_PORT(0), RTC_IO_EXTENT, "rtc")) {
+-		printk(KERN_ERR "rtc: I/O port %d is not free.\n", RTC_PORT (0));
++	if (RTC_IOMAPPED)
++		r = request_region(RTC_PORT(0), RTC_IO_EXTENT, "rtc");
++	else
++		r = request_mem_region(RTC_PORT(0), RTC_IO_EXTENT, "rtc");
++	if (!r) {
++		printk(KERN_ERR "rtc: I/O resource %lx is not free.\n",
++		       (long)(RTC_PORT(0)));
+ 		return -EIO;
+ 	}
+ 
+@@ -984,7 +1000,10 @@
+ 	if(request_irq(RTC_IRQ, rtc_int_handler_ptr, SA_INTERRUPT, "rtc", NULL)) {
+ 		/* Yeah right, seeing as irq 8 doesn't even hit the bus. */
+ 		printk(KERN_ERR "rtc: IRQ %d is not free.\n", RTC_IRQ);
+-		release_region(RTC_PORT(0), RTC_IO_EXTENT);
++		if (RTC_IOMAPPED)
++			release_region(RTC_PORT(0), RTC_IO_EXTENT);
++		else
++			release_mem_region(RTC_PORT(0), RTC_IO_EXTENT);
+ 		return -EIO;
+ 	}
+ 	hpet_rtc_timer_init();
+@@ -1084,7 +1103,10 @@
+ 	if (rtc_has_irq)
+ 		free_irq (rtc_irq, &rtc_port);
+ #else
+-	release_region (RTC_PORT (0), RTC_IO_EXTENT);
++	if (RTC_IOMAPPED)
++		release_region(RTC_PORT(0), RTC_IO_EXTENT);
++	else
++		release_mem_region(RTC_PORT(0), RTC_IO_EXTENT);
+ #ifdef RTC_IRQ
+ 	if (rtc_has_irq)
+ 		free_irq (RTC_IRQ, NULL);
+diff -Naur linux-2.6.15.orig/drivers/char/sb1250_duart.c linux-2.6.15/drivers/char/sb1250_duart.c
+--- linux-2.6.15.orig/drivers/char/sb1250_duart.c	1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.15/drivers/char/sb1250_duart.c	2006-01-09 19:54:12.000000000 +0000
+@@ -0,0 +1,915 @@
++/*
++ * Copyright (C) 2000,2001,2002,2003,2004 Broadcom 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 program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ * 
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
++ */
++
++/* 
++ * Driver support for the on-chip sb1250 dual-channel serial port,
++ * running in asynchronous mode.  Also, support for doing a serial console
++ * on one of those ports 
++ */
++#include <linux/config.h>
++#include <linux/types.h>
++#include <linux/kernel.h>
++#include <linux/serial.h>
++#include <linux/interrupt.h>
++#include <linux/module.h>
++#include <linux/console.h>
++#include <linux/kdev_t.h>
++#include <linux/major.h>
++#include <linux/termios.h>
++#include <linux/spinlock.h>
++#include <linux/irq.h>
++#include <linux/errno.h>
++#include <linux/tty.h>
++#include <linux/sched.h>
++#include <linux/tty_flip.h>
++#include <linux/timer.h>
++#include <linux/init.h>
++#include <linux/mm.h>
++#include <asm/delay.h>
++#include <asm/io.h>
++#include <asm/uaccess.h>
++#include <asm/sibyte/swarm.h>
++#include <asm/sibyte/sb1250.h>
++#if defined(CONFIG_SIBYTE_BCM1x55) || defined(CONFIG_SIBYTE_BCM1x80)
++#include <asm/sibyte/bcm1480_regs.h>
++#include <asm/sibyte/bcm1480_int.h>
++#elif defined(CONFIG_SIBYTE_SB1250) || defined(CONFIG_SIBYTE_BCM112X)
++#include <asm/sibyte/sb1250_regs.h>
++#include <asm/sibyte/sb1250_int.h>
++#else
++#error invalid SiByte UART configuation
++#endif
++#include <asm/sibyte/sb1250_uart.h>
++#include <asm/war.h>
++
++#if defined(CONFIG_SIBYTE_BCM1x55) || defined(CONFIG_SIBYTE_BCM1x80)
++#define UNIT_CHANREG(n,reg)	A_BCM1480_DUART_CHANREG((n),(reg))
++#define UNIT_IMRREG(n)		A_BCM1480_DUART_IMRREG(n)
++#define UNIT_INT(n)		(K_BCM1480_INT_UART_0 + (n))
++#elif defined(CONFIG_SIBYTE_SB1250) || defined(CONFIG_SIBYTE_BCM112X)
++#define UNIT_CHANREG(n,reg)	A_DUART_CHANREG((n),(reg))
++#define UNIT_IMRREG(n)		A_DUART_IMRREG(n)
++#define UNIT_INT(n)		(K_INT_UART_0 + (n))
++#else
++#error invalid SiByte UART configuation
++#endif
++
++/* Toggle spewing of debugging output */
++#undef DEBUG
++
++#define DEFAULT_CFLAGS          (CS8 | B115200)
++
++#define TX_INTEN          1
++#define DUART_INITIALIZED 2
++
++#define DUART_MAX_LINE 4
++char sb1250_duart_present[DUART_MAX_LINE];
++EXPORT_SYMBOL(sb1250_duart_present);
++
++/*
++ * Still not sure what the termios structures set up here are for, 
++ *  but we have to supply pointers to them to register the tty driver
++ */
++static struct tty_driver *sb1250_duart_driver; //, sb1250_duart_callout_driver;
++
++/*
++ * This lock protects both the open flags for all the uart states as 
++ * well as the reference count for the module
++ */
++static DEFINE_SPINLOCK(open_lock);
++
++typedef struct { 
++	unsigned char       outp_buf[SERIAL_XMIT_SIZE];
++	unsigned int        outp_head;
++	unsigned int        outp_tail;
++	unsigned int        outp_count;
++	spinlock_t          outp_lock;
++	unsigned int        open;
++	unsigned int        line;
++	unsigned int        last_cflags;
++	unsigned long       flags;
++	struct tty_struct   *tty;
++	/* CSR addresses */
++	u32		    *status;
++	u32		    *imr;
++	u32		    *tx_hold;
++	u32		    *rx_hold;
++	u32		    *mode_1;
++	u32		    *mode_2;
++	u32		    *clk_sel;
++	u32		    *cmd;
++} uart_state_t;
++
++static uart_state_t uart_states[DUART_MAX_LINE];
++
++/*
++ * Inline functions local to this module 
++ */
++
++/*
++ * In bug 1956, we get glitches that can mess up uart registers.  This
++ * "write-mode-1 after any register access" is the accepted
++ * workaround.
++ */
++#if SIBYTE_1956_WAR
++static unsigned int last_mode1[DUART_MAX_LINE];
++#endif
++
++static inline u32 READ_SERCSR(u32 *addr, int line)
++{
++	u32 val = csr_in32(addr);
++#if SIBYTE_1956_WAR
++	csr_out32(last_mode1[line], uart_states[line].mode_1);
++#endif
++	return val;
++}
++
++static inline void WRITE_SERCSR(u32 val, u32 *addr, int line)
++{
++	csr_out32(val, addr);
++#if SIBYTE_1956_WAR
++	csr_out32(last_mode1[line], uart_states[line].mode_1);
++#endif
++}
++
++static void init_duart_port(uart_state_t *port, int line)
++{
++	if (!(port->flags & DUART_INITIALIZED)) {
++		port->line = line;
++		port->status = IOADDR(UNIT_CHANREG(line, R_DUART_STATUS));
++		port->imr = IOADDR(UNIT_IMRREG(line));
++		port->tx_hold = IOADDR(UNIT_CHANREG(line, R_DUART_TX_HOLD));
++		port->rx_hold = IOADDR(UNIT_CHANREG(line, R_DUART_RX_HOLD));
++		port->mode_1 = IOADDR(UNIT_CHANREG(line, R_DUART_MODE_REG_1));
++		port->mode_2 = IOADDR(UNIT_CHANREG(line, R_DUART_MODE_REG_2));
++		port->clk_sel = IOADDR(UNIT_CHANREG(line, R_DUART_CLK_SEL));
++		port->cmd = IOADDR(UNIT_CHANREG(line, R_DUART_CMD));
++		port->flags |= DUART_INITIALIZED;
++	}
++}
++
++/*
++ * Mask out the passed interrupt lines at the duart level.  This should be
++ * called while holding the associated outp_lock.
++ */
++static inline void duart_mask_ints(unsigned int line, unsigned int mask)
++{
++	uart_state_t *port = uart_states + line;
++	u64 tmp = READ_SERCSR(port->imr, line);
++	WRITE_SERCSR(tmp & ~mask, port->imr, line);
++}
++
++	
++/* Unmask the passed interrupt lines at the duart level */
++static inline void duart_unmask_ints(unsigned int line, unsigned int mask)
++{
++	uart_state_t *port = uart_states + line;
++	u64 tmp = READ_SERCSR(port->imr, line);
++	WRITE_SERCSR(tmp | mask, port->imr, line);
++}
++
++static inline void transmit_char_pio(uart_state_t *us)
++{
++	struct tty_struct *tty = us->tty;
++	int blocked = 0;
++
++	if (spin_trylock(&us->outp_lock)) {
++		for (;;) {
++			if (!(READ_SERCSR(us->status, us->line) & M_DUART_TX_RDY))
++				break;
++			if (us->outp_count <= 0 || tty->stopped || tty->hw_stopped) {
++				break;
++			} else {
++				WRITE_SERCSR(us->outp_buf[us->outp_head],
++					     us->tx_hold, us->line);
++				us->outp_head = (us->outp_head + 1) & (SERIAL_XMIT_SIZE-1);
++				if (--us->outp_count <= 0)
++					break;
++			}
++			udelay(10);
++		}
++		spin_unlock(&us->outp_lock);
++	} else {
++		blocked = 1;
++	}
++
++	if (!us->outp_count || tty->stopped ||
++	    tty->hw_stopped || blocked) {
++		us->flags &= ~TX_INTEN;
++		duart_mask_ints(us->line, M_DUART_IMR_TX);
++	}
++
++      	if (us->open &&
++	    (us->outp_count < (SERIAL_XMIT_SIZE/2))) {
++		/*
++		 * We told the discipline at one point that we had no
++		 * space, so it went to sleep.  Wake it up when we hit
++		 * half empty
++		 */
++		if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
++		    tty->ldisc.write_wakeup)
++			tty->ldisc.write_wakeup(tty);
++		wake_up_interruptible(&tty->write_wait);
++	}
++}
++
++/* 
++ * Generic interrupt handler for both channels.  dev_id is a pointer
++ * to the proper uart_states structure, so from that we can derive 
++ * which port interrupted 
++ */
++
++static irqreturn_t duart_int(int irq, void *dev_id, struct pt_regs *regs)
++{
++	uart_state_t *us = (uart_state_t *)dev_id;
++	struct tty_struct *tty = us->tty;
++	unsigned int status = READ_SERCSR(us->status, us->line);
++
++	pr_debug("DUART INT\n");
++
++	if (status & M_DUART_RX_RDY) {
++		int counter = 2048;
++		unsigned int ch;
++
++		if (status & M_DUART_OVRUN_ERR)
++			tty_insert_flip_char(tty, 0, TTY_OVERRUN);
++		if (status & M_DUART_PARITY_ERR) {
++			printk("Parity error!\n");
++		} else if (status & M_DUART_FRM_ERR) {
++			printk("Frame error!\n");
++		}
++
++		while (counter > 0) {
++			if (!(READ_SERCSR(us->status, us->line) & M_DUART_RX_RDY))
++				break;
++			ch = READ_SERCSR(us->rx_hold, us->line);
++			if (tty->flip.count < TTY_FLIPBUF_SIZE) {
++				*tty->flip.char_buf_ptr++ = ch;
++				*tty->flip.flag_buf_ptr++ = 0;
++				tty->flip.count++;
++			}
++			udelay(1);
++			counter--;
++		}
++		tty_flip_buffer_push(tty);
++	}
++
++	if (status & M_DUART_TX_RDY) {
++		transmit_char_pio(us);
++	}
++
++	return IRQ_HANDLED;
++}
++
++/*
++ *  Actual driver functions
++ */
++
++/* Return the number of characters we can accomodate in a write at this instant */
++static int duart_write_room(struct tty_struct *tty)
++{
++	uart_state_t *us = (uart_state_t *) tty->driver_data;
++	int retval;
++
++	retval = SERIAL_XMIT_SIZE - us->outp_count;
++
++	pr_debug("duart_write_room called, returning %i\n", retval);
++
++	return retval;
++}
++
++/* memcpy the data from src to destination, but take extra care if the
++   data is coming from user space */
++static inline int copy_buf(char *dest, const char *src, int size, int from_user) 
++{
++	if (from_user) {
++		(void) copy_from_user(dest, src, size); 
++	} else {
++		memcpy(dest, src, size);
++	}
++	return size;
++}
++
++/*
++ * Buffer up to count characters from buf to be written.  If we don't have
++ * other characters buffered, enable the tx interrupt to start sending
++ */
++static int duart_write(struct tty_struct *tty, const unsigned char *buf,
++		       int count)
++{
++	uart_state_t *us;
++	int c, t, total = 0;
++	unsigned long flags;
++
++	if (!tty) return 0;
++
++	us = tty->driver_data;
++	if (!us) return 0;
++
++	pr_debug("duart_write called for %i chars by %i (%s)\n", count, current->pid, current->comm);
++
++	spin_lock_irqsave(&us->outp_lock, flags);
++
++	for (;;) {
++		c = count;
++
++		t = SERIAL_XMIT_SIZE - us->outp_tail;
++		if (t < c) c = t;
++
++		t = SERIAL_XMIT_SIZE - 1 - us->outp_count;
++		if (t < c) c = t;
++
++		if (c <= 0) break;
++
++		memcpy(us->outp_buf + us->outp_tail, buf, c);
++
++		us->outp_count += c;
++		us->outp_tail = (us->outp_tail + c) & (SERIAL_XMIT_SIZE - 1);
++		buf += c;
++		count -= c;
++		total += c;
++	}
++
++	spin_unlock_irqrestore(&us->outp_lock, flags);
++
++	if (us->outp_count && !tty->stopped && 
++	    !tty->hw_stopped && !(us->flags & TX_INTEN)) {
++		us->flags |= TX_INTEN;
++		duart_unmask_ints(us->line, M_DUART_IMR_TX);
++	}
++
++	return total;
++}
++
++
++/* Buffer one character to be written.  If there's not room for it, just drop
++   it on the floor.  This is used for echo, among other things */
++static void duart_put_char(struct tty_struct *tty, u_char ch)
++{
++	uart_state_t *us = (uart_state_t *) tty->driver_data;
++	unsigned long flags;
++
++	pr_debug("duart_put_char called.  Char is %x (%c)\n", (int)ch, ch);
++
++	spin_lock_irqsave(&us->outp_lock, flags);
++
++	if (us->outp_count == SERIAL_XMIT_SIZE) {
++		spin_unlock_irqrestore(&us->outp_lock, flags);
++		return;
++	}
++
++	us->outp_buf[us->outp_tail] = ch;
++	us->outp_tail = (us->outp_tail + 1) &(SERIAL_XMIT_SIZE-1);
++	us->outp_count++;
++
++	spin_unlock_irqrestore(&us->outp_lock, flags);
++}
++
++static void duart_flush_chars(struct tty_struct * tty)
++{
++	uart_state_t *port;
++
++	if (!tty) return;
++
++	port = tty->driver_data;
++
++	if (!port) return;
++
++	if (port->outp_count <= 0 || tty->stopped || tty->hw_stopped) {
++		return;
++	}
++
++	port->flags |= TX_INTEN;
++	duart_unmask_ints(port->line, M_DUART_IMR_TX);
++}
++
++/* Return the number of characters in the output buffer that have yet to be 
++   written */
++static int duart_chars_in_buffer(struct tty_struct *tty)
++{
++	uart_state_t *us = (uart_state_t *) tty->driver_data;
++	int retval;
++
++	retval = us->outp_count;
++
++	pr_debug("duart_chars_in_buffer returning %i\n", retval);
++
++	return retval;
++}
++
++/* Kill everything we haven't yet shoved into the FIFO.  Turn off the
++   transmit interrupt since we've nothing more to transmit */
++static void duart_flush_buffer(struct tty_struct *tty)
++{
++	uart_state_t *us = (uart_state_t *) tty->driver_data;
++	unsigned long flags;
++
++	pr_debug("duart_flush_buffer called\n");
++	spin_lock_irqsave(&us->outp_lock, flags);
++	us->outp_head = us->outp_tail = us->outp_count = 0;
++	spin_unlock_irqrestore(&us->outp_lock, flags);
++
++	wake_up_interruptible(&us->tty->write_wait);
++	if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
++	    tty->ldisc.write_wakeup)
++		tty->ldisc.write_wakeup(tty);
++}
++
++
++/* See sb1250 user manual for details on these registers */
++static inline void duart_set_cflag(unsigned int line, unsigned int cflag)
++{
++	unsigned int mode_reg1 = 0, mode_reg2 = 0;
++	unsigned int clk_divisor;
++	uart_state_t *port = uart_states + line;
++
++	switch (cflag & CSIZE) {
++	case CS7:
++		mode_reg1 |= V_DUART_BITS_PER_CHAR_7;
++		
++	default:
++		/* We don't handle CS5 or CS6...is there a way we're supposed to flag this? 
++		   right now we just force them to CS8 */
++		mode_reg1 |= 0x0;
++		break;
++	}
++	if (cflag & CSTOPB) {
++	        mode_reg2 |= M_DUART_STOP_BIT_LEN_2;
++	}
++	if (!(cflag & PARENB)) {
++	        mode_reg1 |= V_DUART_PARITY_MODE_NONE;
++	}
++	if (cflag & PARODD) {
++		mode_reg1 |= M_DUART_PARITY_TYPE_ODD;
++	}
++	
++	/* Formula for this is (5000000/baud)-1, but we saturate
++	   at 12 bits, which means we can't actually do anything less
++	   that 1200 baud */
++	switch (cflag & CBAUD) {
++	case B200:	
++	case B300:	
++	case B1200:	clk_divisor = 4095;		break;
++	case B1800:	clk_divisor = 2776;		break;
++	case B2400:	clk_divisor = 2082;		break;
++	case B4800:	clk_divisor = 1040;		break;
++	default:
++	case B9600:	clk_divisor = 519;		break;
++	case B19200:	clk_divisor = 259;		break;
++	case B38400:	clk_divisor = 129;		break;
++	case B57600:	clk_divisor = 85;		break;
++	case B115200:	clk_divisor = 42;		break;
++	}
++	WRITE_SERCSR(mode_reg1, port->mode_1, port->line);
++	WRITE_SERCSR(mode_reg2, port->mode_2, port->line);
++	WRITE_SERCSR(clk_divisor, port->clk_sel, port->line);
++	port->last_cflags = cflag;
++}
++
++
++/* Handle notification of a termios change.  */
++static void duart_set_termios(struct tty_struct *tty, struct termios *old)
++{
++	uart_state_t *us = (uart_state_t *) tty->driver_data;
++
++	pr_debug("duart_set_termios called by %i (%s)\n", current->pid, current->comm);
++	if (old && tty->termios->c_cflag == old->c_cflag)
++		return;
++	duart_set_cflag(us->line, tty->termios->c_cflag);
++}
++
++static int get_serial_info(uart_state_t *us, struct serial_struct * retinfo) {
++
++	struct serial_struct tmp;
++
++	memset(&tmp, 0, sizeof(tmp));
++
++	tmp.type=PORT_SB1250;
++	tmp.line=us->line;
++	tmp.port=UNIT_CHANREG(tmp.line,0);
++	tmp.irq=UNIT_INT(tmp.line);
++	tmp.xmit_fifo_size=16; /* fixed by hw */
++	tmp.baud_base=5000000;
++	tmp.io_type=SERIAL_IO_MEM;
++
++	if (copy_to_user(retinfo,&tmp,sizeof(*retinfo)))
++		return -EFAULT;
++
++	return 0;
++}
++
++static int duart_ioctl(struct tty_struct *tty, struct file * file,
++		       unsigned int cmd, unsigned long arg)
++{
++	uart_state_t *us = (uart_state_t *) tty->driver_data;
++
++/*	if (serial_paranoia_check(info, tty->device, "rs_ioctl"))
++	return -ENODEV;*/
++	switch (cmd) {
++	case TIOCMGET:
++		printk("Ignoring TIOCMGET\n");
++		break;
++	case TIOCMBIS:
++		printk("Ignoring TIOCMBIS\n");
++		break;
++	case TIOCMBIC:
++		printk("Ignoring TIOCMBIC\n");
++		break;
++	case TIOCMSET:
++		printk("Ignoring TIOCMSET\n");
++		break;
++	case TIOCGSERIAL:
++		return get_serial_info(us,(struct serial_struct *) arg);
++	case TIOCSSERIAL:
++		printk("Ignoring TIOCSSERIAL\n");
++		break;
++	case TIOCSERCONFIG:
++		printk("Ignoring TIOCSERCONFIG\n");
++		break;
++	case TIOCSERGETLSR: /* Get line status register */
++		printk("Ignoring TIOCSERGETLSR\n");
++		break;
++	case TIOCSERGSTRUCT:
++		printk("Ignoring TIOCSERGSTRUCT\n");
++		break;
++	case TIOCMIWAIT:
++		printk("Ignoring TIOCMIWAIT\n");
++		break;
++	case TIOCGICOUNT:
++		printk("Ignoring TIOCGICOUNT\n");
++		break;
++	case TIOCSERGWILD:
++		printk("Ignoring TIOCSERGWILD\n");
++		break;
++	case TIOCSERSWILD:
++		printk("Ignoring TIOCSERSWILD\n");
++		break;
++	default:
++		break;
++	}
++//	printk("Ignoring IOCTL %x from pid %i (%s)\n", cmd, current->pid, current->comm);
++	return -ENOIOCTLCMD;
++}
++
++/* XXXKW locking? */
++static void duart_start(struct tty_struct *tty)
++{
++	uart_state_t *us = (uart_state_t *) tty->driver_data;
++
++	pr_debug("duart_start called\n");
++
++	if (us->outp_count && !(us->flags & TX_INTEN)) {
++		us->flags |= TX_INTEN;
++		duart_unmask_ints(us->line, M_DUART_IMR_TX);
++	}
++}
++
++/* XXXKW locking? */
++static void duart_stop(struct tty_struct *tty)
++{
++	uart_state_t *us = (uart_state_t *) tty->driver_data;
++
++	pr_debug("duart_stop called\n");
++
++	if (us->outp_count && (us->flags & TX_INTEN)) {
++		us->flags &= ~TX_INTEN;
++		duart_mask_ints(us->line, M_DUART_IMR_TX);
++	}
++}
++
++/* Not sure on the semantics of this; are we supposed to wait until the stuff
++   already in the hardware FIFO drains, or are we supposed to wait until 
++   we've drained the output buffer, too?  I'm assuming the former, 'cause thats
++   what the other drivers seem to assume 
++*/
++
++static void duart_wait_until_sent(struct tty_struct *tty, int timeout)
++{
++	uart_state_t *us = (uart_state_t *) tty->driver_data;
++	unsigned long orig_jiffies;
++
++	orig_jiffies = jiffies;
++	pr_debug("duart_wait_until_sent(%d)+\n", timeout);
++	while (!(READ_SERCSR(us->status, us->line) & M_DUART_TX_EMT)) {
++		set_current_state(TASK_INTERRUPTIBLE);
++	 	schedule_timeout(1);
++		if (signal_pending(current))
++			break;
++		if (timeout && time_after(jiffies, orig_jiffies + timeout))
++			break;
++	}
++	pr_debug("duart_wait_until_sent()-\n");
++}
++
++/*
++ * duart_hangup() --- called by tty_hangup() when a hangup is signaled.
++ */
++static void duart_hangup(struct tty_struct *tty)
++{
++	uart_state_t *us = (uart_state_t *) tty->driver_data;
++
++	duart_flush_buffer(tty);
++	us->open = 0;
++	us->tty = 0;
++}
++
++/*
++ * Open a tty line.  Note that this can be called multiple times, so ->open can
++ * be >1.  Only set up the tty struct if this is a "new" open, e.g. ->open was
++ * zero
++ */
++static int duart_open(struct tty_struct *tty, struct file *filp)
++{
++	uart_state_t *us;
++	unsigned int line = tty->index;
++	unsigned long flags;
++
++	if ((line >= tty->driver->num) || !sb1250_duart_present[line])
++		return -ENODEV;
++
++	pr_debug("duart_open called by %i (%s), tty is %p, rw is %p, ww is %p\n",
++	       current->pid, current->comm, tty, tty->read_wait,
++	       tty->write_wait);
++
++	us = uart_states + line;
++	tty->driver_data = us;
++
++	spin_lock_irqsave(&open_lock, flags);
++	if (!us->open) {
++		us->tty = tty;
++		us->tty->termios->c_cflag = us->last_cflags;
++	}
++	us->open++;
++	us->flags &= ~TX_INTEN;
++	duart_unmask_ints(line, M_DUART_IMR_RX);
++	spin_unlock_irqrestore(&open_lock, flags);
++
++	return 0;
++}
++
++
++/*
++ * Close a reference count out.  If reference count hits zero, null the
++ * tty, kill the interrupts.  The tty_io driver is responsible for making
++ * sure we've cleared out our internal buffers before calling close()
++ */
++static void duart_close(struct tty_struct *tty, struct file *filp)
++{
++	uart_state_t *us = (uart_state_t *) tty->driver_data;
++	unsigned long flags;
++
++	pr_debug("duart_close called by %i (%s)\n", current->pid, current->comm);
++
++	if (!us || !us->open)
++		return;
++
++	spin_lock_irqsave(&open_lock, flags);
++	if (tty_hung_up_p(filp)) {
++		spin_unlock_irqrestore(&open_lock, flags);
++		return;
++	}
++
++	if (--us->open < 0) {
++		us->open = 0;
++		printk(KERN_ERR "duart: bad open count: %d\n", us->open);
++	}
++	if (us->open) {
++		spin_unlock_irqrestore(&open_lock, flags);
++		return;
++	}
++
++	spin_unlock_irqrestore(&open_lock, flags);
++
++	tty->closing = 1;
++
++	/* Stop accepting input */
++	duart_mask_ints(us->line, M_DUART_IMR_RX);
++	/* Wait for FIFO to drain */
++	while (!(READ_SERCSR(us->status, us->line) & M_DUART_TX_EMT))
++		;
++
++	if (tty->driver->flush_buffer)
++		tty->driver->flush_buffer(tty);
++	if (tty->ldisc.flush_buffer)
++		tty->ldisc.flush_buffer(tty);
++	tty->closing = 0;
++}
++
++
++static struct tty_operations duart_ops = {
++        .open   = duart_open,
++        .close = duart_close,
++        .write = duart_write,
++        .put_char = duart_put_char,
++        .flush_chars = duart_flush_chars,
++        .write_room = duart_write_room,
++        .chars_in_buffer = duart_chars_in_buffer,
++        .flush_buffer = duart_flush_buffer,
++        .ioctl = duart_ioctl,
++//        .throttle = duart_throttle,
++//        .unthrottle = duart_unthrottle,
++        .set_termios = duart_set_termios,
++        .stop = duart_stop,
++        .start = duart_start,
++        .hangup = duart_hangup,
++	.wait_until_sent = duart_wait_until_sent,
++};
++
++/* Initialize the sb1250_duart_present array based on SOC type.  */
++static void __init sb1250_duart_init_present_lines(void)
++{
++	int i, max_lines;
++
++	/* Set the number of available units based on the SOC type.  */
++	switch (soc_type) {
++	case K_SYS_SOC_TYPE_BCM1x55:
++	case K_SYS_SOC_TYPE_BCM1x80:
++		max_lines = 4;
++		break;
++	default:
++		/* Assume at least two serial ports at the normal address.  */
++		max_lines = 2;
++		break;
++	}
++	if (max_lines > DUART_MAX_LINE)
++		max_lines = DUART_MAX_LINE;
++
++	for (i = 0; i < max_lines; i++)
++		sb1250_duart_present[i] = 1;
++}
++
++/* Set up the driver and register it, register the UART interrupts.  This
++   is called from tty_init, or as a part of the module init */
++static int __init sb1250_duart_init(void) 
++{
++	int i;
++
++	sb1250_duart_init_present_lines();
++
++	sb1250_duart_driver = alloc_tty_driver(DUART_MAX_LINE);
++	if (!sb1250_duart_driver)
++		return -ENOMEM;
++
++	sb1250_duart_driver->owner = THIS_MODULE;
++	sb1250_duart_driver->name = "duart";
++	sb1250_duart_driver->devfs_name = "duart/";
++	sb1250_duart_driver->major = TTY_MAJOR;
++	sb1250_duart_driver->minor_start = SB1250_DUART_MINOR_BASE;
++	sb1250_duart_driver->type            = TTY_DRIVER_TYPE_SERIAL;
++	sb1250_duart_driver->subtype         = SERIAL_TYPE_NORMAL;
++	sb1250_duart_driver->init_termios    = tty_std_termios;
++	sb1250_duart_driver->flags           = TTY_DRIVER_REAL_RAW;
++	tty_set_operations(sb1250_duart_driver, &duart_ops);
++
++	for (i=0; i<DUART_MAX_LINE; i++) {
++		uart_state_t *port = uart_states + i;
++
++		if (!sb1250_duart_present[i])
++			continue;
++
++		init_duart_port(port, i);
++		spin_lock_init(&port->outp_lock);
++		duart_mask_ints(i, M_DUART_IMR_ALL);
++		if (request_irq(UNIT_INT(i), duart_int, 0, "uart", port)) {
++			panic("Couldn't get uart0 interrupt line");
++		}
++		__raw_writeq(M_DUART_RX_EN|M_DUART_TX_EN,
++			     IOADDR(UNIT_CHANREG(i, R_DUART_CMD)));
++		duart_set_cflag(i, DEFAULT_CFLAGS);
++	}
++
++	/* Interrupts are now active, our ISR can be called. */
++
++	if (tty_register_driver(sb1250_duart_driver)) {
++		printk(KERN_ERR "Couldn't register sb1250 duart serial driver\n");
++		put_tty_driver(sb1250_duart_driver);
++		return 1;
++	}
++	return 0;
++}
++
++/* Unload the driver.  Unregister stuff, get ready to go away */
++static void __exit sb1250_duart_fini(void)
++{
++	unsigned long flags;
++	int i;
++
++	local_irq_save(flags);
++	tty_unregister_driver(sb1250_duart_driver);
++	put_tty_driver(sb1250_duart_driver);
++
++	for (i=0; i<DUART_MAX_LINE; i++) {
++		if (!sb1250_duart_present[i])
++			continue;
++		free_irq(UNIT_INT(i), &uart_states[i]);
++		disable_irq(UNIT_INT(i));
++	}
++	local_irq_restore(flags);
++}
++
++module_init(sb1250_duart_init);
++module_exit(sb1250_duart_fini);
++MODULE_DESCRIPTION("SB1250 Duart serial driver");
++MODULE_AUTHOR("Broadcom Corp.");
++
++#ifdef CONFIG_SIBYTE_SB1250_DUART_CONSOLE
++
++/*
++ * Serial console stuff.  Very basic, polling driver for doing serial
++ * console output.  The console_sem is held by the caller, so we
++ * shouldn't be interrupted for more console activity.
++ * XXXKW What about getting interrupted by uart driver activity?
++ */
++
++void serial_outc(unsigned char c, int line)
++{
++	uart_state_t *port = uart_states + line;
++	while (!(READ_SERCSR(port->status, line) & M_DUART_TX_RDY)) ;
++	WRITE_SERCSR(c, port->tx_hold, line);
++	while (!(READ_SERCSR(port->status, port->line) & M_DUART_TX_EMT)) ;
++}
++
++static void ser_console_write(struct console *cons, const char *s,
++	unsigned int count)
++{
++	int line = cons->index;
++	uart_state_t *port = uart_states + line;
++	u32 imr;
++
++	imr = READ_SERCSR(port->imr, line);
++	WRITE_SERCSR(0, port->imr, line);
++	while (count--) {
++		if (*s == '\n')
++			serial_outc('\r', line);
++		serial_outc(*s++, line);
++    	}
++	WRITE_SERCSR(imr, port->imr, line);
++}
++
++static struct tty_driver *ser_console_device(struct console *c, int *index)
++{
++	*index = c->index;
++	return sb1250_duart_driver;
++}
++
++static int ser_console_setup(struct console *cons, char *str)
++{
++	int i;
++
++	sb1250_duart_init_present_lines();
++
++	for (i=0; i<DUART_MAX_LINE; i++) {
++		uart_state_t *port = uart_states + i;
++
++		if (!sb1250_duart_present[i])
++			continue;
++
++		init_duart_port(port, i);
++#if SIBYTE_1956_WAR
++		last_mode1[i] = V_DUART_PARITY_MODE_NONE|V_DUART_BITS_PER_CHAR_8;
++#endif
++		WRITE_SERCSR(V_DUART_PARITY_MODE_NONE|V_DUART_BITS_PER_CHAR_8,
++			     port->mode_1, i);
++		WRITE_SERCSR(M_DUART_STOP_BIT_LEN_1,
++			     port->mode_2, i);
++		WRITE_SERCSR(V_DUART_BAUD_RATE(115200),
++			     port->clk_sel, i);
++		WRITE_SERCSR(M_DUART_RX_EN|M_DUART_TX_EN,
++			     port->cmd, i);
++	}
++	return 0;
++}
++
++static struct console sb1250_ser_cons = {
++	.name		= "duart",
++	.write		= ser_console_write,
++	.device		= ser_console_device,
++	.setup		= ser_console_setup,
++	.flags		= CON_PRINTBUFFER,
++	.index		= -1,
++};
++
++static int __init sb1250_serial_console_init(void)
++{
++	register_console(&sb1250_ser_cons);
++	return 0;
++}
++
++console_initcall(sb1250_serial_console_init);
++
++#endif /* CONFIG_SIBYTE_SB1250_DUART_CONSOLE */
+diff -Naur linux-2.6.15.orig/drivers/ide/mips/Makefile linux-2.6.15/drivers/ide/mips/Makefile
+--- linux-2.6.15.orig/drivers/ide/mips/Makefile	2006-01-03 03:21:10.000000000 +0000
++++ linux-2.6.15/drivers/ide/mips/Makefile	2006-01-09 19:54:12.000000000 +0000
+@@ -1,4 +1,4 @@
+ obj-$(CONFIG_BLK_DEV_IDE_SWARM)		+= swarm.o
+ obj-$(CONFIG_BLK_DEV_IDE_AU1XXX)	+= au1xxx-ide.o
+ 
+-EXTRA_CFLAGS    := -Idrivers/ide
++CFLAGS_au1xxx-ide.o := -Idrivers/ide
+diff -Naur linux-2.6.15.orig/drivers/media/video/Makefile linux-2.6.15/drivers/media/video/Makefile
+--- linux-2.6.15.orig/drivers/media/video/Makefile	2006-01-03 03:21:10.000000000 +0000
++++ linux-2.6.15/drivers/media/video/Makefile	2006-01-09 19:54:12.000000000 +0000
+@@ -54,6 +54,8 @@
+ obj-$(CONFIG_VIDEO_BTCX)  += btcx-risc.o
+ obj-$(CONFIG_VIDEO_TVEEPROM) += tveeprom.o
+ 
++obj-$(CONFIG_TUNER_3036) += tuner-3036.o
++
+ obj-$(CONFIG_VIDEO_M32R_AR_M64278) += arv.o
+ 
+ obj-$(CONFIG_VIDEO_DECODER)     += saa7115.o cx25840/ saa7127.o
+diff -Naur linux-2.6.15.orig/drivers/mmc/au1xmmc.c linux-2.6.15/drivers/mmc/au1xmmc.c
+--- linux-2.6.15.orig/drivers/mmc/au1xmmc.c	2006-01-03 03:21:10.000000000 +0000
++++ linux-2.6.15/drivers/mmc/au1xmmc.c	2006-01-09 19:54:12.000000000 +0000
+@@ -1,6 +1,6 @@
+-/*
+- * linux/drivers/mmc/au1xmmc.c - AU1XX0 MMC driver
+- *
++/* 
++ * linux/drivers/mmc/au1xmmc.c - AU1XX0 MMC driver 
++ *  
+  *  Copyright (c) 2005, Advanced Micro Devices, Inc.
+  *
+  *  Developed with help from the 2.4.30 MMC AU1XXX controller including
+@@ -10,9 +10,9 @@
+  *     Copyright 2002 Hewlett-Packard Company
+ 
+  *  2.6 version of this driver inspired by:
+- *     (drivers/mmc/wbsd.c) Copyright (C) 2004-2005 Pierre Ossman,
++ *     (drivers/mmc/wbsd.c) Copyright (C) 2004-2005 Pierre Ossman, 
+  *     All Rights Reserved.
+- *     (drivers/mmc/pxa.c) Copyright (C) 2003 Russell King,
++ *     (drivers/mmc/pxa.c) Copyright (C) 2003 Russell King, 
+  *     All Rights Reserved.
+  *
+ 
+@@ -24,20 +24,20 @@
+ /* Why is a timer used to detect insert events?
+  *
+  * From the AU1100 MMC application guide:
+- * If the Au1100-based design is intended to support both MultiMediaCards
+- * and 1- or 4-data bit SecureDigital cards, then the solution is to
+- * connect a weak (560KOhm) pull-up resistor to connector pin 1.
+- * In doing so, a MMC card never enters SPI-mode communications,
++ * If the Au1100-based design is intended to support both MultiMediaCards 
++ * and 1- or 4-data bit SecureDigital cards, then the solution is to 
++ * connect a weak (560KOhm) pull-up resistor to connector pin 1. 
++ * In doing so, a MMC card never enters SPI-mode communications, 
+  * but now the SecureDigital card-detect feature of CD/DAT3 is ineffective
+  * (the low to high transition will not occur).
+  *
+- * So we use the timer to check the status manually.
++ * So we use the timer to check the status manually. 
+  */
+ 
+ #include <linux/config.h>
+ #include <linux/module.h>
+ #include <linux/init.h>
+-#include <linux/device.h>
++#include <linux/platform_device.h>
+ #include <linux/mm.h>
+ #include <linux/interrupt.h>
+ #include <linux/dma-mapping.h>
+@@ -46,7 +46,7 @@
+ #include <linux/mmc/protocol.h>
+ #include <asm/io.h>
+ #include <asm/mach-au1x00/au1000.h>
+-#include <asm/mach-au1x00/au1xxx_dbdma.h>
++#include <asm/mach-au1x00/au1xxx_dbdma.h> 
+ #include <asm/mach-au1x00/au1100_mmc.h>
+ #include <asm/scatterlist.h>
+ 
+@@ -71,10 +71,10 @@
+ 	u16 bcsrstatus;
+ 	u16 wpstatus;
+ } au1xmmc_card_table[] = {
+-	{ SD0_BASE, DSCR_CMD0_SDMS_TX0, DSCR_CMD0_SDMS_RX0,
++	{ SD0_BASE, DSCR_CMD0_SDMS_TX0, DSCR_CMD0_SDMS_RX0, 
+ 	  BCSR_BOARD_SD0PWR, BCSR_INT_SD0INSERT, BCSR_STATUS_SD0WP },
+ #ifndef CONFIG_MIPS_DB1200
+-	{ SD1_BASE, DSCR_CMD0_SDMS_TX1, DSCR_CMD0_SDMS_RX1,
++	{ SD1_BASE, DSCR_CMD0_SDMS_TX1, DSCR_CMD0_SDMS_RX1, 
+ 	  BCSR_BOARD_DS1PWR, BCSR_INT_SD1INSERT, BCSR_STATUS_SD1WP }
+ #endif
+ };
+@@ -91,7 +91,7 @@
+ MODULE_PARM_DESC(dma, "Use DMA engine for data transfers (0 = disabled)");
+ #endif
+ 
+-static inline void IRQ_ON(struct au1xmmc_host *host, u32 mask)
++static inline void IRQ_ON(struct au1xmmc_host *host, u32 mask) 
+ {
+ 	u32 val = au_readl(HOST_CONFIG(host));
+ 	val |= mask;
+@@ -99,13 +99,13 @@
+ 	au_sync();
+ }
+ 
+-static inline void FLUSH_FIFO(struct au1xmmc_host *host)
++static inline void FLUSH_FIFO(struct au1xmmc_host *host) 
+ {
+ 	u32 val = au_readl(HOST_CONFIG2(host));
+ 
+ 	au_writel(val | SD_CONFIG2_FF, HOST_CONFIG2(host));
+ 	au_sync_delay(1);
+-
++	
+ 	/* SEND_STOP will turn off clock control - this re-enables it */
+ 	val &= ~SD_CONFIG2_DF;
+ 
+@@ -113,7 +113,7 @@
+ 	au_sync();
+ }
+ 
+-static inline void IRQ_OFF(struct au1xmmc_host *host, u32 mask)
++static inline void IRQ_OFF(struct au1xmmc_host *host, u32 mask) 
+ {
+ 	u32 val = au_readl(HOST_CONFIG(host));
+ 	val &= ~mask;
+@@ -121,7 +121,7 @@
+ 	au_sync();
+ }
+ 
+-static inline void SEND_STOP(struct au1xmmc_host *host)
++static inline void SEND_STOP(struct au1xmmc_host *host) 
+ {
+ 
+ 	/* We know the value of CONFIG2, so avoid a read we don't need */
+@@ -137,36 +137,36 @@
+ 	au_writel(STOP_CMD, HOST_CMD(host));
+ }
+ 
+-static void au1xmmc_set_power(struct au1xmmc_host *host, int state)
++static void au1xmmc_set_power(struct au1xmmc_host *host, int state) 
+ {
+ 
+ 	u32 val = au1xmmc_card_table[host->id].bcsrpwr;
+ 
+ 	bcsr->board &= ~val;
+ 	if (state) bcsr->board |= val;
+-
++	
+ 	au_sync_delay(1);
+ }
+ 
+-static inline int au1xmmc_card_inserted(struct au1xmmc_host *host)
++static inline int au1xmmc_card_inserted(struct au1xmmc_host *host) 
+ {
+-	return (bcsr->sig_status & au1xmmc_card_table[host->id].bcsrstatus)
++	return (bcsr->sig_status & au1xmmc_card_table[host->id].bcsrstatus) 
+ 		? 1 : 0;
+-}
++}	
+ 
+-static inline int au1xmmc_card_readonly(struct au1xmmc_host *host)
++static inline int au1xmmc_card_readonly(struct au1xmmc_host *host) 
+ {
+-	return (bcsr->status & au1xmmc_card_table[host->id].wpstatus)
++	return (bcsr->status & au1xmmc_card_table[host->id].wpstatus) 
+ 		? 1 : 0;
+ }
+ 
+-static void au1xmmc_finish_request(struct au1xmmc_host *host)
++static void au1xmmc_finish_request(struct au1xmmc_host *host) 
+ {
+-
++  
+ 	struct mmc_request *mrq = host->mrq;
+ 
+ 	host->mrq = NULL;
+-	host->flags &= HOST_F_ACTIVE;
++	host->flags &= HOST_F_ACTIVE; 
+ 
+ 	host->dma.len = 0;
+ 	host->dma.dir = 0;
+@@ -182,14 +182,14 @@
+ 	mmc_request_done(host->mmc, mrq);
+ }
+ 
+-static void au1xmmc_tasklet_finish(unsigned long param)
++static void au1xmmc_tasklet_finish(unsigned long param) 
+ {
+ 	struct au1xmmc_host *host = (struct au1xmmc_host *) param;
+ 	au1xmmc_finish_request(host);
+ }
+ 
+-static int au1xmmc_send_command(struct au1xmmc_host *host, int wait,
+-				struct mmc_command *cmd)
++static int au1xmmc_send_command(struct au1xmmc_host *host, int wait,  
++				struct mmc_command *cmd) 
+ {
+ 
+ 	u32 mmccmd = (cmd->opcode << SD_CMD_CI_SHIFT);
+@@ -220,7 +220,7 @@
+ 	case MMC_WRITE_BLOCK:
+ 		mmccmd |= SD_CMD_CT_1;
+ 		break;
+-
++	
+ 	case MMC_WRITE_MULTIPLE_BLOCK:
+ 		mmccmd |= SD_CMD_CT_3;
+ 		break;
+@@ -228,13 +228,13 @@
+ 		mmccmd |= SD_CMD_CT_7;
+ 		break;
+ 	}
+-
++	
+ 	au_writel(cmd->arg, HOST_CMDARG(host));
+ 	au_sync();
+ 
+-	if (wait)
++	if (wait) 
+ 		IRQ_OFF(host, SD_CONFIG_CR);
+-
++	
+ 	au_writel((mmccmd | SD_CMD_GO), HOST_CMD(host));
+ 	au_sync();
+ 
+@@ -250,9 +250,9 @@
+ 	if (wait) {
+ 		u32 status = au_readl(HOST_STATUS(host));
+ 
+-		while(!(status & SD_STATUS_CR))
++		while(!(status & SD_STATUS_CR)) 
+ 			status = au_readl(HOST_STATUS(host));
+-
++		
+ 		/* Clear the CR status */
+ 		au_writel(SD_STATUS_CR, HOST_STATUS(host));
+ 
+@@ -262,7 +262,7 @@
+ 	return MMC_ERR_NONE;
+ }
+ 
+-static void au1xmmc_data_complete(struct au1xmmc_host *host, u32 status)
++static void au1xmmc_data_complete(struct au1xmmc_host *host, u32 status) 
+ {
+ 
+ 	struct mmc_request *mrq = host->mrq;
+@@ -281,7 +281,7 @@
+ 
+ 	/* The transaction is really over when the SD_STATUS_DB bit is clear */
+ 
+-	while((host->flags & HOST_F_XMIT) && (status & SD_STATUS_DB))
++	while((host->flags & HOST_F_XMIT) && (status & SD_STATUS_DB)) 
+ 		status = au_readl(HOST_STATUS(host));
+ 
+ 	data->error = MMC_ERR_NONE;
+@@ -290,10 +290,10 @@
+         /* Process any errors */
+ 
+ 	crc = (status & (SD_STATUS_WC | SD_STATUS_RC));
+-	if (host->flags & HOST_F_XMIT)
++	if (host->flags & HOST_F_XMIT) 
+ 		crc |= ((status & 0x07) == 0x02) ? 0 : 1;
+-
+-	if (crc)
++	
++	if (crc) 
+ 		data->error = MMC_ERR_BADCRC;
+ 
+ 	/* Clear the CRC bits */
+@@ -309,16 +309,16 @@
+ 			au1x_dma_chan_t *cp = c->chan_ptr;
+ 			data->bytes_xfered = cp->ddma_bytecnt;
+ 		}
+-		else
+-			data->bytes_xfered =
+-				(data->blocks * (1 << data->blksz_bits)) -
++		else 
++			data->bytes_xfered = 
++				(data->blocks * (1 << data->blksz_bits)) - 
+ 				host->pio.len;
+ 	}
+ 
+ 	au1xmmc_finish_request(host);
+ }
+ 
+-static void au1xmmc_tasklet_data(unsigned long param)
++static void au1xmmc_tasklet_data(unsigned long param) 
+ {
+ 	struct au1xmmc_host *host = (struct au1xmmc_host *) param;
+ 
+@@ -328,7 +328,7 @@
+ 
+ #define AU1XMMC_MAX_TRANSFER 8
+ 
+-static void au1xmmc_send_pio(struct au1xmmc_host *host)
++static void au1xmmc_send_pio(struct au1xmmc_host *host) 
+ {
+ 
+ 	struct mmc_data *data = 0;
+@@ -339,9 +339,9 @@
+ 
+ 	data = host->mrq->data;
+ 
+-	if (!(host->flags & HOST_F_XMIT))
++	if (!(host->flags & HOST_F_XMIT)) 
+ 		return;
+-
++	
+ 	/* This is the pointer to the data buffer */
+ 	sg = &data->sg[host->pio.index];
+ 	sg_ptr = page_address(sg->page) + sg->offset + host->pio.offset;
+@@ -357,7 +357,7 @@
+ 	for(count = 0; count < max; count++ ) {
+ 		unsigned char val;
+ 
+-		status = au_readl(HOST_STATUS(host));
++		status = au_readl(HOST_STATUS(host));		
+ 
+ 		if (!(status & SD_STATUS_TH))
+ 			break;
+@@ -381,12 +381,12 @@
+ 
+ 		if (host->flags & HOST_F_STOP)
+ 			SEND_STOP(host);
+-
++		 
+ 		tasklet_schedule(&host->data_task);
+ 	}
+ }
+ 
+-static void au1xmmc_receive_pio(struct au1xmmc_host *host)
++static void au1xmmc_receive_pio(struct au1xmmc_host *host) 
+ {
+ 
+ 	struct mmc_data *data = 0;
+@@ -397,7 +397,7 @@
+ 
+ 	data = host->mrq->data;
+ 
+-	if (!(host->flags & HOST_F_RECV))
++	if (!(host->flags & HOST_F_RECV)) 
+ 		return;
+ 
+ 	max = host->pio.len;
+@@ -405,7 +405,7 @@
+ 	if (host->pio.index < host->dma.len) {
+ 		sg = &data->sg[host->pio.index];
+ 		sg_ptr = page_address(sg->page) + sg->offset + host->pio.offset;
+-
++			
+ 		/* This is the space left inside the buffer */
+ 		sg_len = sg_dma_len(&data->sg[host->pio.index]) - host->pio.offset;
+ 
+@@ -413,10 +413,10 @@
+ 		if (sg_len < max) max = sg_len;
+ 	}
+ 
+-	if (max > AU1XMMC_MAX_TRANSFER)
++	if (max > AU1XMMC_MAX_TRANSFER) 
+ 		max = AU1XMMC_MAX_TRANSFER;
+ 
+-	for(count = 0; count < max; count++ ) {
++	for(count = 0; count < max; count++ ) { 
+ 		u32 val;
+ 		status = au_readl(HOST_STATUS(host));
+ 
+@@ -424,25 +424,25 @@
+ 			break;
+ 
+ 		if (status & SD_STATUS_RC) {
+-			DEBUG("RX CRC Error [%d + %d].\n", host->id,
++			DEBUG("RX CRC Error [%d + %d].\n", host->id, 
+ 					host->pio.len, count);
+ 			break;
+ 		}
+ 
+ 		if (status & SD_STATUS_RO) {
+-			DEBUG("RX Overrun [%d + %d]\n", host->id,
++			DEBUG("RX Overrun [%d + %d]\n", host->id, 
+ 					host->pio.len, count);
+ 			break;
+ 		}
+ 		else if (status & SD_STATUS_RU) {
+-			DEBUG("RX Underrun [%d + %d]\n", host->id,
++			DEBUG("RX Underrun [%d + %d]\n", host->id, 
+ 					host->pio.len,	count);
+ 			break;
+ 		}
+ 
+-		val = au_readl(HOST_RXPORT(host));
++		val = au_readl(HOST_RXPORT(host)); 
+ 
+-		if (sg_ptr)
++		if (sg_ptr) 
+ 			*sg_ptr++ = (unsigned char) (val & 0xFF);
+ 	}
+ 
+@@ -470,14 +470,14 @@
+    and check for errors.  Then start the data transfer if it is indicated.
+ */
+ 
+-static void au1xmmc_cmd_complete(struct au1xmmc_host *host, u32 status)
++static void au1xmmc_cmd_complete(struct au1xmmc_host *host, u32 status) 
+ {
+ 
+ 	struct mmc_request *mrq = host->mrq;
+ 	struct mmc_command *cmd;
+ 	int trans;
+ 
+-	if (!host->mrq)
++	if (!host->mrq) 
+ 		return;
+ 
+ 	cmd = mrq->cmd;
+@@ -489,7 +489,7 @@
+ 		 * (SD_RESP1 + SD_RESP2), but because our response omits the CRC,
+ 		 * our data ends up being shifted 8 bits to the right.  In this case,
+ 		 * that means that the OSR data starts at bit 31, so we can just
+-		 * read RESP0 and return that
++		 * read RESP0 and return that 
+ 		 */
+ 
+ 		cmd->resp[0] = au_readl(host->iobase + SD_RESP0);
+@@ -502,12 +502,12 @@
+ 		r[1] = au_readl(host->iobase + SD_RESP2);
+ 		r[2] = au_readl(host->iobase + SD_RESP1);
+ 		r[3] = au_readl(host->iobase + SD_RESP0);
+-
++		
+ 		/* The CRC is omitted from the response, so really we only got
+ 		 * 120 bytes, but the engine expects 128 bits, so we have to shift
+-		 * things up
++		 * things up 
+ 		 */
+-
++		
+ 		for(i = 0; i < 4; i++) {
+ 			cmd->resp[i] = (r[i] & 0x00FFFFFF) << 8;
+ 			if (i != 3) cmd->resp[i] |= (r[i + 1] & 0xFF000000) >> 24;
+@@ -538,7 +538,7 @@
+ 		if (host->flags & HOST_F_RECV) {
+ 			u32 mask = SD_STATUS_DB | SD_STATUS_NE;
+ 
+-			while((status & mask) != mask)
++			while((status & mask) != mask) 
+ 				status = au_readl(HOST_STATUS(host));
+ 		}
+ 
+@@ -546,7 +546,7 @@
+ 	}
+ }
+ 
+-static void au1xmmc_set_clock(struct au1xmmc_host *host, int rate)
++static void au1xmmc_set_clock(struct au1xmmc_host *host, int rate) 
+ {
+ 
+ 	unsigned int pbus = get_au1x00_speed();
+@@ -571,13 +571,13 @@
+ 	au_sync();
+ }
+ 
+-static int
+-au1xmmc_prepare_data(struct au1xmmc_host *host, struct mmc_data *data)
++static int 
++au1xmmc_prepare_data(struct au1xmmc_host *host, struct mmc_data *data) 
+ {
+ 
+ 	int datalen = data->blocks * (1 << data->blksz_bits);
+ 
+-	if (dma != 0)
++	if (dma != 0) 
+ 		host->flags |= HOST_F_DMA;
+ 
+ 	if (data->flags & MMC_DATA_READ)
+@@ -585,9 +585,9 @@
+ 	else
+ 		host->flags |= HOST_F_XMIT;
+ 
+-	if (host->mrq->stop)
++	if (host->mrq->stop) 
+ 		host->flags |= HOST_F_STOP;
+-
++		
+ 	host->dma.dir = DMA_BIDIRECTIONAL;
+ 
+ 	host->dma.len = dma_map_sg(mmc_dev(host->mmc), data->sg,
+@@ -596,7 +596,7 @@
+ 	if (host->dma.len == 0)
+ 		return MMC_ERR_TIMEOUT;
+ 
+-	au_writel((1 << data->blksz_bits) - 1, HOST_BLKSIZE(host));
++	au_writel((1 << data->blksz_bits) - 1, HOST_BLKSIZE(host));	
+ 
+ 	if (host->flags & HOST_F_DMA) {
+ 		int i;
+@@ -608,26 +608,26 @@
+ 			u32 ret = 0, flags = DDMA_FLAGS_NOIE;
+ 			struct scatterlist *sg = &data->sg[i];
+ 			int sg_len = sg->length;
+-
++			
+ 			int len = (datalen > sg_len) ? sg_len : datalen;
+ 
+ 			if (i == host->dma.len - 1)
+ 				flags = DDMA_FLAGS_IE;
+ 
+     			if (host->flags & HOST_F_XMIT){
+-      				ret = au1xxx_dbdma_put_source_flags(channel,
+-					(void *) (page_address(sg->page) +
+-						  sg->offset),
++      				ret = au1xxx_dbdma_put_source_flags(channel, 
++					(void *) (page_address(sg->page) + 
++						  sg->offset), 
+ 					len, flags);
+ 			}
+     			else {
+-      				ret = au1xxx_dbdma_put_dest_flags(channel,
+-					(void *) (page_address(sg->page) +
+-						  sg->offset),
++      				ret = au1xxx_dbdma_put_dest_flags(channel, 
++					(void *) (page_address(sg->page) + 
++						  sg->offset), 
+ 					len, flags);
+ 			}
+ 
+-    			if (!ret)
++    			if (!ret) 
+ 				goto dataerr;
+ 
+ 			datalen -= len;
+@@ -637,10 +637,10 @@
+ 		host->pio.index = 0;
+ 		host->pio.offset = 0;
+ 		host->pio.len = datalen;
+-
++		
+ 		if (host->flags & HOST_F_XMIT)
+ 			IRQ_ON(host, SD_CONFIG_TH);
+-		else
++		else 
+ 			IRQ_ON(host, SD_CONFIG_NE);
+ 			//IRQ_ON(host, SD_CONFIG_RA|SD_CONFIG_RF);
+ 	}
+@@ -648,15 +648,15 @@
+ 	return MMC_ERR_NONE;
+ 
+  dataerr:
+-	dma_unmap_sg(mmc_dev(host->mmc),data->sg,data->sg_len,host->dma.dir);
++	dma_unmap_sg(mmc_dev(host->mmc),data->sg,data->sg_len,host->dma.dir); 
+ 	return MMC_ERR_TIMEOUT;
+-}
++} 
+ 
+ /* static void au1xmmc_request
+    This actually starts a command or data transaction
+ */
+ 
+-static void au1xmmc_request(struct mmc_host* mmc, struct mmc_request* mrq)
++static void au1xmmc_request(struct mmc_host* mmc, struct mmc_request* mrq) 
+ {
+ 
+ 	struct au1xmmc_host *host = mmc_priv(mmc);
+@@ -684,7 +684,7 @@
+ 	}
+ }
+ 
+-static void au1xmmc_reset_controller(struct au1xmmc_host *host)
++static void au1xmmc_reset_controller(struct au1xmmc_host *host) 
+ {
+ 
+ 	/* Apply the clock */
+@@ -714,17 +714,17 @@
+ 	au_writel(AU1XMMC_INTERRUPTS, HOST_CONFIG(host));
+ 	au_sync();
+ }
++	
+ 
+-
+-static void au1xmmc_set_ios(struct mmc_host* mmc, struct mmc_ios* ios)
++static void au1xmmc_set_ios(struct mmc_host* mmc, struct mmc_ios* ios) 
+ {
+ 	struct au1xmmc_host *host = mmc_priv(mmc);
+ 
+ 	DEBUG("set_ios (power=%u, clock=%uHz, vdd=%u, mode=%u)\n",
+-	      host->id, ios->power_mode, ios->clock, ios->vdd,
++	      host->id, ios->power_mode, ios->clock, ios->vdd, 
+ 	      ios->bus_mode);
+ 
+-	if (ios->power_mode == MMC_POWER_OFF)
++	if (ios->power_mode == MMC_POWER_OFF) 
+ 		au1xmmc_set_power(host, 0);
+ 	else if (ios->power_mode == MMC_POWER_ON) {
+ 		au1xmmc_set_power(host, 1);
+@@ -736,17 +736,16 @@
+ 	}
+ }
+ 
+-static void au1xmmc_dma_callback(int irq, void *dev_id, struct pt_regs *regs)
++static void au1xmmc_dma_callback(int irq, void *dev_id, struct pt_regs *regs) 
+ {
+ 	struct au1xmmc_host *host = (struct au1xmmc_host *) dev_id;
+-	u32 status;
+ 
+ 	/* Avoid spurious interrupts */
+ 
+-	if (!host->mrq)
++	if (!host->mrq) 
+ 		return;
+ 
+-	if (host->flags & HOST_F_STOP)
++	if (host->flags & HOST_F_STOP) 
+ 		SEND_STOP(host);
+ 
+ 	tasklet_schedule(&host->data_task);
+@@ -756,27 +755,27 @@
+ #define STATUS_DATA_IN  (SD_STATUS_NE)
+ #define STATUS_DATA_OUT (SD_STATUS_TH)
+ 
+-static irqreturn_t au1xmmc_irq(int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t au1xmmc_irq(int irq, void *dev_id, struct pt_regs *regs) 
+ {
+-
++  
+ 	u32 status;
+ 	int i, ret = 0;
+ 
+ 	disable_irq(AU1100_SD_IRQ);
+ 
+-	for(i = 0; i < AU1XMMC_CONTROLLER_COUNT; i++) {
++	for(i = 0; i < AU1XMMC_CONTROLLER_COUNT; i++) {    
+ 		struct au1xmmc_host * host = au1xmmc_hosts[i];
+ 		u32 handled = 1;
+ 
+ 		status = au_readl(HOST_STATUS(host));
+ 
+ 		if (host->mrq && (status & STATUS_TIMEOUT)) {
+-			if (status & SD_STATUS_RAT)
++			if (status & SD_STATUS_RAT)  
+ 				host->mrq->cmd->error = MMC_ERR_TIMEOUT;
+-
+-			else if (status & SD_STATUS_DT)
++			
++			else if (status & SD_STATUS_DT) 
+ 				host->mrq->data->error = MMC_ERR_TIMEOUT;
+-
++		
+ 			/* In PIO mode, interrupts might still be enabled */
+ 			IRQ_OFF(host, SD_CONFIG_NE | SD_CONFIG_TH);
+ 
+@@ -788,7 +787,7 @@
+ 
+ 			/* Sometimes we get a DD before a NE in PIO mode */
+ 
+-			if (!(host->flags & HOST_F_DMA) &&
++			if (!(host->flags & HOST_F_DMA) && 
+ 					(status & SD_STATUS_NE))
+ 				au1xmmc_receive_pio(host);
+ 			else {
+@@ -801,11 +800,11 @@
+ 			if (host->status == HOST_S_CMD)
+ 				au1xmmc_cmd_complete(host,status);
+ 		}
+-		else if (!(host->flags & HOST_F_DMA)) {
+-			if ((host->flags & HOST_F_XMIT) &&
++		else if (!(host->flags & HOST_F_DMA)) { 
++			if ((host->flags & HOST_F_XMIT) && 
+ 			    (status & STATUS_DATA_OUT))
+ 				au1xmmc_send_pio(host);
+-			else if ((host->flags & HOST_F_RECV) &&
++			else if ((host->flags & HOST_F_RECV) && 
+ 			    (status & STATUS_DATA_IN))
+ 				au1xmmc_receive_pio(host);
+ 		}
+@@ -813,7 +812,7 @@
+ 			DEBUG("Unhandled status %8.8x\n", host->id, status);
+ 			handled = 0;
+ 		}
+-
++		
+ 		au_writel(status, HOST_STATUS(host));
+ 		au_sync();
+ 
+@@ -824,7 +823,7 @@
+ 	return ret;
+ }
+ 
+-static void au1xmmc_poll_event(unsigned long arg)
++static void au1xmmc_poll_event(unsigned long arg) 
+ {
+ 	struct au1xmmc_host *host = (struct au1xmmc_host *) arg;
+ 
+@@ -837,38 +836,33 @@
+ 		mmc_detect_change(host->mmc, 0);
+ 	}
+ 
+-	if (host->mrq != NULL) {
+-		u32 status = au_readl(HOST_STATUS(host));
+-		DEBUG("PENDING - %8.8x\n", host->id, status);
+-	}
+-
+ 	mod_timer(&host->timer, jiffies + AU1XMMC_DETECT_TIMEOUT);
+ }
+ 
+-static dbdev_tab_t au1xmmc_mem_dbdev =
++static dbdev_tab_t au1xmmc_mem_dbdev = 
+ {
+ 	DSCR_CMD0_ALWAYS, DEV_FLAGS_ANYUSE, 0, 8, 0x00000000, 0, 0
+ };
+ 
+-static void au1xmmc_init_dma(struct au1xmmc_host *host)
++static void au1xmmc_init_dma(struct au1xmmc_host *host) 
+ {
+-
++	
+ 	u32 rxchan, txchan;
+-
++	
+ 	int txid = au1xmmc_card_table[host->id].tx_devid;
+ 	int rxid = au1xmmc_card_table[host->id].rx_devid;
+-
++	
+ 	/* DSCR_CMD0_ALWAYS has a stride of 32 bits, we need a stride
+ 	   of 8 bits.  And since devices are shared, we need to create
+ 	   our own to avoid freaking out other devices
+ 	*/
+-
++	
+ 	int memid = au1xxx_ddma_add_device(&au1xmmc_mem_dbdev);
+-
+-	txchan = au1xxx_dbdma_chan_alloc(memid, txid,
++		
++	txchan = au1xxx_dbdma_chan_alloc(memid, txid, 
+ 					 au1xmmc_dma_callback, (void *) host);
+ 
+-	rxchan = au1xxx_dbdma_chan_alloc(rxid, memid,
++	rxchan = au1xxx_dbdma_chan_alloc(rxid, memid, 
+ 					 au1xmmc_dma_callback, (void *) host);
+ 
+ 	au1xxx_dbdma_set_devwidth(txchan, 8);
+@@ -886,16 +880,16 @@
+ 	.set_ios	= au1xmmc_set_ios,
+ };
+ 
+-static int au1xmmc_probe(struct device *dev)
++static int au1xmmc_probe(struct device *dev) 
+ {
+ 
+ 	int i, ret = 0;
+ 
+ 	/* THe interrupt is shared among all controllers */
+ 	ret = request_irq(AU1100_SD_IRQ, au1xmmc_irq, SA_INTERRUPT, "MMC", 0);
+-
++  
+ 	if (ret) {
+-		printk(DRIVER_NAME "ERROR: Couldn't get int %d: %d\n",
++		printk(DRIVER_NAME "ERROR: Couldn't get int %d: %d\n", 
+ 				AU1100_SD_IRQ, ret);
+ 		return -ENXIO;
+ 	}
+@@ -913,12 +907,12 @@
+ 		}
+ 
+ 		mmc->ops = &au1xmmc_ops;
+-
++   
+ 		mmc->f_min =   450000;
+ 		mmc->f_max = 24000000;
+ 
+ 		mmc->max_seg_size = AU1XMMC_DESCRIPTOR_SIZE;
+-		mmc->max_phys_segs = AU1XMMC_DESCRIPTOR_COUNT;
++		mmc->max_phys_segs = AU1XMMC_DESCRIPTOR_COUNT; 
+ 
+ 		mmc->ocr_avail = AU1XMMC_OCR;
+ 
+@@ -929,7 +923,7 @@
+ 		host->iobase = au1xmmc_card_table[host->id].iobase;
+ 		host->clock = 0;
+ 		host->power_mode = MMC_POWER_OFF;
+-
++		
+ 		host->flags = au1xmmc_card_inserted(host) ? HOST_F_ACTIVE : 0;
+ 		host->status = HOST_S_IDLE;
+ 
+@@ -939,10 +933,10 @@
+ 		host->timer.data = (unsigned long) host;
+ 		host->timer.expires = jiffies + AU1XMMC_DETECT_TIMEOUT;
+ 
+-		tasklet_init(&host->data_task, au1xmmc_tasklet_data,
++		tasklet_init(&host->data_task, au1xmmc_tasklet_data, 
+ 				(unsigned long) host);
+ 
+-		tasklet_init(&host->finish_task, au1xmmc_tasklet_finish,
++		tasklet_init(&host->finish_task, au1xmmc_tasklet_finish, 
+ 				(unsigned long) host);
+ 
+ 		spin_lock_init(&host->lock);
+@@ -960,19 +954,19 @@
+ 		printk(KERN_INFO DRIVER_NAME ": MMC Controller %d set up at %8.8X (mode=%s)\n",
+ 		       host->id, host->iobase, dma ? "dma" : "pio");
+ 	}
+-
++  
+ 	enable_irq(AU1100_SD_IRQ);
+ 
+ 	return 0;
+ }
+-
+-static int au1xmmc_remove(struct device *dev)
++    
++static int au1xmmc_remove(struct device *dev) 
+ {
+-
++ 
+ 	int i;
+ 
+ 	disable_irq(AU1100_SD_IRQ);
+-
++  
+ 	for(i = 0; i < AU1XMMC_CONTROLLER_COUNT; i++) {
+ 		struct au1xmmc_host *host = au1xmmc_hosts[i];
+ 		if (!host) continue;
+@@ -982,15 +976,15 @@
+ 
+ 		del_timer_sync(&host->timer);
+ 		au1xmmc_set_power(host, 0);
+-
++		
+ 		mmc_remove_host(host->mmc);
+-
++    
+ 		au1xxx_dbdma_chan_free(host->tx_chan);
+ 		au1xxx_dbdma_chan_free(host->rx_chan);
+-
++   
+ 		au_writel(0x0, HOST_ENABLE(host));
+-		au_sync();
+-	}
++		au_sync();	
++	} 
+ 
+ 	free_irq(AU1100_SD_IRQ, 0);
+ 	return 0;
+@@ -1005,12 +999,12 @@
+ 	.resume        = NULL
+ };
+ 
+-static int __init au1xmmc_init(void)
++static int __init au1xmmc_init(void) 
+ {
+ 	return driver_register(&au1xmmc_driver);
+ }
+ 
+-static void __exit au1xmmc_exit(void)
++static void __exit au1xmmc_exit(void) 
+ {
+ 	driver_unregister(&au1xmmc_driver);
+ }
+diff -Naur linux-2.6.15.orig/drivers/mtd/devices/Kconfig linux-2.6.15/drivers/mtd/devices/Kconfig
+--- linux-2.6.15.orig/drivers/mtd/devices/Kconfig	2006-01-03 03:21:10.000000000 +0000
++++ linux-2.6.15/drivers/mtd/devices/Kconfig	2006-01-09 19:54:12.000000000 +0000
+@@ -47,6 +47,11 @@
+ 	  accelerator.  Say Y here if you have a DECstation 5000/2x0 or a
+ 	  DECsystem 5900 equipped with such a module.
+ 
++	  If you want to compile this driver as a module ( = code which can be
++	  inserted in and removed from the running kernel whenever you want),
++	  say M here and read <file:Documentation/modules.txt>.  The module will
++	  be called ms02-nv.o.
++
+ config MTD_SLRAM
+ 	tristate "Uncached system RAM"
+ 	depends on MTD
+diff -Naur linux-2.6.15.orig/drivers/mtd/devices/docprobe.c linux-2.6.15/drivers/mtd/devices/docprobe.c
+--- linux-2.6.15.orig/drivers/mtd/devices/docprobe.c	2006-01-03 03:21:10.000000000 +0000
++++ linux-2.6.15/drivers/mtd/devices/docprobe.c	2006-01-09 19:54:12.000000000 +0000
+@@ -84,10 +84,10 @@
+ 	0xe4000000,
+ #elif defined(CONFIG_MOMENCO_OCELOT)
+ 	0x2f000000,
+-        0xff000000,
++	0xff000000,
+ #elif defined(CONFIG_MOMENCO_OCELOT_G) || defined (CONFIG_MOMENCO_OCELOT_C)
+-        0xff000000,
+-##else
++	0xff000000,
++#else
+ #warning Unknown architecture for DiskOnChip. No default probe locations defined
+ #endif
+ 	0xffffffff };
+diff -Naur linux-2.6.15.orig/drivers/mtd/maps/Kconfig linux-2.6.15/drivers/mtd/maps/Kconfig
+--- linux-2.6.15.orig/drivers/mtd/maps/Kconfig	2006-01-03 03:21:10.000000000 +0000
++++ linux-2.6.15/drivers/mtd/maps/Kconfig	2006-01-09 19:54:12.000000000 +0000
+@@ -200,8 +200,8 @@
+ 	  Support for the flash chip on Tsunami TIG bus.
+ 
+ config MTD_LASAT
+-	tristate "Flash chips on LASAT board"
+-	depends on LASAT
++	tristate "LASAT flash device"
++	depends on LASAT && MTD_CFI
+ 	help
+ 	  Support for the flash chips on the Lasat 100 and 200 boards.
+ 
+@@ -299,6 +299,18 @@
+ 	  Mapping for the Flaga digital module. If you don't have one, ignore
+ 	  this setting.
+ 
++config MTD_XXS1500
++	tristate "MyCable XXS1500 Flash device"
++	depends on MIPS && MIPS_XXS1500
++	help
++	  Flash memory access on MyCable XXS1500 Board
++
++config MTD_MTX1
++	tristate "4-G Systems MTX-1 Flash device"
++	depends on MIPS && MIPS_MTX1
++	help
++	  Flash memory access on 4-G Systems MTX-1 Board
++
+ config MTD_BEECH
+ 	tristate "CFI Flash device mapped on IBM 405LP Beech"
+ 	depends on MTD_CFI && BEECH
+diff -Naur linux-2.6.15.orig/drivers/mtd/maps/lasat.c linux-2.6.15/drivers/mtd/maps/lasat.c
+--- linux-2.6.15.orig/drivers/mtd/maps/lasat.c	2006-01-03 03:21:10.000000000 +0000
++++ linux-2.6.15/drivers/mtd/maps/lasat.c	2006-01-09 19:54:12.000000000 +0000
+@@ -7,7 +7,7 @@
+  * modify it under the terms of the GNU General Public License version
+  * 2 as published by the Free Software Foundation.
+  *
+- * $Id: lasat.c,v 1.9 2004/11/04 13:24:15 gleixner Exp $
++ * $Id: lasat.c,v 1.7 2004/07/12 21:59:44 dwmw2 Exp $
+  *
+  */
+ 
+@@ -50,7 +50,7 @@
+ 	ENABLE_VPP((&lasat_map));
+ 
+ 	lasat_map.phys = lasat_flash_partition_start(LASAT_MTD_BOOTLOADER);
+-	lasat_map.virt = ioremap_nocache(
++	lasat_map.virt = (unsigned long)ioremap_nocache(
+ 		        lasat_map.phys, lasat_board_info.li_flash_size);
+ 	lasat_map.size = lasat_board_info.li_flash_size;
+ 
+diff -Naur linux-2.6.15.orig/drivers/net/Kconfig linux-2.6.15/drivers/net/Kconfig
+--- linux-2.6.15.orig/drivers/net/Kconfig	2006-01-03 03:21:10.000000000 +0000
++++ linux-2.6.15/drivers/net/Kconfig	2006-01-09 19:54:13.000000000 +0000
+@@ -427,6 +427,14 @@
+ 	  This is the driver for the onboard card of MIPS Magnum 4000,
+ 	  Acer PICA, Olivetti M700-10 and a few other identical OEM systems.
+ 
++config GALILEO_64240_ETH
++	tristate "Galileo GT64240 Ethernet support"
++	depends on NET_ETHERNET && MOMENCO_OCELOT_G
++	select MII
++	help
++	  This is the driver for the ethernet interfaces integrated into
++	  the Galileo (now Marvell) GT64240 chipset.
++
+ config MIPS_GT96100ETH
+ 	bool "MIPS GT96100 Ethernet support"
+ 	depends on NET_ETHERNET && MIPS_GT96100
+@@ -441,10 +449,6 @@
+ 	  If you have an Alchemy Semi AU1X00 based system
+ 	  say Y.  Otherwise, say N.
+ 
+-config NET_SB1250_MAC
+-	tristate "SB1250 Ethernet support"
+-	depends on NET_ETHERNET && SIBYTE_SB1xxx_SOC
+-
+ config SGI_IOC3_ETH
+ 	bool "SGI IOC3 Ethernet"
+ 	depends on NET_ETHERNET && PCI && SGI_IP27
+@@ -483,6 +487,14 @@
+ 	  emulated by the MIPS Simulator.
+ 	  If you are not using a MIPSsim or are unsure, say N.
+ 
++config MIPS_SIM_NET
++	tristate "MIPS simulator Network device (EXPERIMENTAL)"
++	depends on NETDEVICES && MIPS_SIM && EXPERIMENTAL
++	help
++	  The MIPSNET device is a simple Ethernet network device which is
++	  emulated by the MIPS Simulator.
++	  If you are not using a MIPSsim or are unsure, say N.
++
+ config SGI_O2MACE_ETH
+ 	tristate "SGI O2 MACE Fast Ethernet support"
+ 	depends on NET_ETHERNET && SGI_IP32=y
+@@ -1974,6 +1986,10 @@
+ 
+ 	  If in doubt, say N.
+ 
++config NET_SB1250_MAC
++	tristate "SB1250 Ethernet support"
++	depends on SIBYTE_SB1xxx_SOC
++
+ config R8169_VLAN
+ 	bool "VLAN support"
+ 	depends on R8169 && VLAN_8021Q
+@@ -2142,8 +2158,8 @@
+ 	depends on MOMENCO_OCELOT_C || MOMENCO_JAGUAR_ATX || MV64360 || MOMENCO_OCELOT_3 || PPC_MULTIPLATFORM
+ 	help
+ 	  This driver supports the gigabit Ethernet on the Marvell MV643XX
+-	  chipset which is used in the Momenco Ocelot C and Jaguar ATX and
+-	  Pegasos II, amongst other PPC and MIPS boards.
++	  chipset which is used in the Momenco Ocelot C Ocelot, Jaguar ATX
++	  and Pegasos II, amongst other PPC and MIPS boards.
+ 
+ config MV643XX_ETH_0
+ 	bool "MV-643XX Port 0"
+@@ -2166,6 +2182,20 @@
+ 	  This enables support for Port 2 of the Marvell MV643XX Gigabit
+ 	  Ethernet.
+ 
++config BIG_SUR_FE
++	bool "PMC-Sierra TITAN Fast Ethernet Support"
++	depends on NET_ETHERNET && PMC_BIG_SUR
++	help
++	  This enables support for the the integrated ethernet of
++	  PMC-Sierra's Big Sur SoC.
++
++config TITAN_GE
++	bool "PMC-Sierra TITAN Gigabit Ethernet Support"
++	depends on PMC_YOSEMITE
++	help
++	  This enables support for the the integrated ethernet of
++	  PMC-Sierra's Titan SoC.
++
+ endmenu
+ 
+ #
+diff -Naur linux-2.6.15.orig/drivers/net/Makefile linux-2.6.15/drivers/net/Makefile
+--- linux-2.6.15.orig/drivers/net/Makefile	2006-01-03 03:21:10.000000000 +0000
++++ linux-2.6.15/drivers/net/Makefile	2006-01-09 19:54:13.000000000 +0000
+@@ -107,6 +107,11 @@
+ 
+ obj-$(CONFIG_MV643XX_ETH) += mv643xx_eth.o
+ 
++obj-$(CONFIG_GALILEO_64240_ETH) += gt64240eth.o
++obj-$(CONFIG_MV64340_ETH) += mv64340_eth.o
++obj-$(CONFIG_BIG_SUR_FE) += big_sur_ge.o
++obj-$(CONFIG_TITAN_GE) += titan_mdio.o titan_ge.o
++
+ obj-$(CONFIG_PPP) += ppp_generic.o slhc.o
+ obj-$(CONFIG_PPP_ASYNC) += ppp_async.o
+ obj-$(CONFIG_PPP_SYNC_TTY) += ppp_synctty.o
+diff -Naur linux-2.6.15.orig/drivers/net/big_sur_ge.c linux-2.6.15/drivers/net/big_sur_ge.c
+--- linux-2.6.15.orig/drivers/net/big_sur_ge.c	1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.15/drivers/net/big_sur_ge.c	2006-01-09 19:54:12.000000000 +0000
+@@ -0,0 +1,2005 @@
++/*
++ * drivers/net/big_sur_ge.c - Driver for PMC-Sierra Big Sur ethernet ports
++ *
++ * Copyright (C) 2003 PMC-Sierra Inc.
++ * Author : Manish Lachwani (lachwani at pmc-sierra.com)
++ * Copyright (C) 2003 Ralf Baechle (ralf at linux-mips.org)
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * as published by the Free Software Foundation; either version 2
++ * of the License, or (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
++ *
++ */
++
++/*************************************************************************
++ * Description :
++ *
++ * The driver has three modes of operation: FIFO non-DMA, Simple DMA
++ * and SG DMA. There is also a Polled mode and an Interrupt mode of
++ * operation. SG DMA should do zerocopy and check offload. Probably,
++ * zerocopy on the Rx might also work. Simple DMA is the non-zerocpy
++ * case on the Tx and the Rx.
++ *
++ * We turn on Simple DMA and interrupt mode. Although, support has been
++ * added for the SG mode also but not for the polled mode. This is a
++ * Fast Ethernet driver although there will be support for Gigabit soon.
++ *
++ * The driver is divided into two parts: Hardware dependent and a
++ * Hardware independent. There is currently no support for checksum offload
++ * zerocopy and Rx NAPI. There is support for Interrupt Mitigation.
++ ****************************************************************************/
++
++/*************************************************************
++ * Hardware Indepenent Part of the driver
++ *************************************************************/
++
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/netdevice.h>
++#include <linux/etherdevice.h>
++#include <linux/skbuff.h>
++#include <linux/mii.h>
++#include <asm/io.h>
++#include <asm/irq.h>
++
++#include "big_sur_ge.h"
++
++#define TX_TIMEOUT (60*HZ)	/* Transmission timeout is 60 seconds. */
++
++static struct net_device *dev_list = NULL;
++static DEFINE_SPINLOCK(dev_lock);
++
++typedef enum DUPLEX { UNKNOWN, HALF_DUPLEX, FULL_DUPLEX } DUPLEX;
++
++/* Big Sur Ethernet MAC structure */
++struct big_sur_ge_enet {
++	struct net_device_stats stats;	/* Statistics for this device */
++	struct net_device *next_dev;	/* The next device in dev_list */
++	struct timer_list phy_timer;	/* PHY monitoring timer */
++	u32 index;		/* Which interface is this */
++	u32 save_base_address;	/* Saved physical base address */
++	struct sk_buff *saved_skb;	/* skb being transmitted */
++	spinlock_t lock;	/* For atomic access to saved_skb */
++	u8 mii_addr;		/* The MII address of the PHY */
++	big_sur_ge emac;	/* GE driver structure */
++};
++
++/* Manish : For testing purposes only */
++static unsigned char big_sur_mac_addr_base[6] = "00:11:22:33:44:55";
++
++/*********************************************************************
++ * Function Prototypes (whole bunch of them)
++ *********************************************************************/
++unsigned long big_sur_ge_dma_control(xdma_channel *);
++void big_sur_ge_dma_reset(xdma_channel *);
++static void handle_fifo_intr(big_sur_ge *);
++void big_sur_ge_check_fifo_recv_error(big_sur_ge *);
++void big_sur_ge_check_fifo_send_error(big_sur_ge *);
++static int big_sur_ge_config_fifo(big_sur_ge *);
++big_sur_ge_config *big_sur_ge_lookup_config(unsigned int);
++static int big_sur_ge_config_dma(big_sur_ge *);
++void big_sur_ge_enet_reset(big_sur_ge *);
++void big_sur_ge_check_mac_error(big_sur_ge *, unsigned long);
++
++/*********************************************************************
++ * DMA Channel Initialization
++ **********************************************************************/
++static int big_sur_ge_dma_init(xdma_channel * dma, unsigned long base_address)
++{
++	dma->reg_base_address = base_address;
++	dma->get_ptr = NULL;
++	dma->put_ptr = NULL;
++	dma->commit_ptr = NULL;
++	dma->last_ptr = NULL;
++	dma->total_desc_count = (unsigned long) NULL;
++	dma->active_desc_count = (unsigned long) NULL;
++	dma->ready = 1;		/* DMA channel is ready */
++
++	big_sur_ge_dma_reset(dma);
++
++	return 0;
++}
++
++/*********************************************************************
++ * Is the DMA channel ready yet ?
++ **********************************************************************/
++static int big_sur_ge_dma_ready(xdma_channel * dma)
++{
++	return dma->ready == 1;
++}
++
++/*********************************************************************
++ * Perform the self test on the DMA channel
++ **********************************************************************/
++#define BIG_SUR_GE_CONTROL_REG_RESET_MASK	0x98000000
++
++static int big_sur_ge_dma_self_test(xdma_channel * dma)
++{
++	unsigned long reg_data;
++
++	big_sur_ge_dma_reset(dma);
++
++	reg_data = big_sur_ge_dma_control(dma);
++	if (reg_data != BIG_SUR_GE_CONTROL_REG_RESET_MASK) {
++		printk(KERN_ERR "DMA Channel Self Test Failed \n");
++		return -1;
++	}
++
++	return 0;
++}
++
++/*********************************************************************
++ * Reset the DMA channel
++ **********************************************************************/
++static void big_sur_ge_dma_reset(xdma_channel * dma)
++{
++	BIG_SUR_GE_WRITE(dma->reg_base_address + BIG_SUR_GE_RST_REG_OFFSET,
++			 BIG_SUR_GE_RESET_MASK);
++}
++
++/*********************************************************************
++ * Get control of the DMA channel
++ **********************************************************************/
++static unsigned long big_sur_ge_dma_control(xdma_channel * dma)
++{
++	return BIG_SUR_GE_READ(dma->reg_base_address +
++			       BIG_SUR_GE_DMAC_REG_OFFSET);
++}
++
++/*********************************************************************
++ * Set control of the DMA channel
++ **********************************************************************/
++static void big_sur_ge_set_dma_control(xdma_channel * dma, unsigned long control)
++{
++	BIG_SUR_GE_WRITE(dma->reg_base_address +
++			 BIG_SUR_GE_DMAC_REG_OFFSET, control);
++}
++
++/*********************************************************************
++ * Get the status of the DMA channel
++ *********************************************************************/
++static unsigned long big_sur_ge_dma_status(xdma_channel * dma)
++{
++	return BIG_SUR_GE_READ(dma->reg_base_address +
++			       BIG_SUR_GE_DMAS_REG_OFFSET);
++}
++
++/*********************************************************************
++ * Set the interrupt status of the DMA channel
++ *********************************************************************/
++static void big_sur_ge_set_intr_status(xdma_channel * dma, unsigned long status)
++{
++	BIG_SUR_GE_WRITE(dma->reg_base_address + BIG_SUR_GE_IS_REG_OFFSET,
++			 status);
++}
++
++/*********************************************************************
++ * Get the interrupt status of the DMA channel
++ *********************************************************************/
++static unsigned long big_sur_ge_get_intr_status(xdma_channel * dma)
++{
++	return BIG_SUR_GE_READ(dma->reg_base_address +
++			       BIG_SUR_GE_IS_REG_OFFSET);
++}
++
++/*********************************************************************
++ * Set the Interrupt Enable
++ *********************************************************************/
++static void big_sur_ge_set_intr_enable(xdma_channel * dma, unsigned long enable)
++{
++	BIG_SUR_GE_WRITE(dma->reg_base_address + BIG_SUR_GE_IE_REG_OFFSET,
++			 enable);
++}
++
++/*********************************************************************
++ * Get the Interrupt Enable field to make a check
++ *********************************************************************/
++static unsigned long big_sur_ge_get_intr_enable(xdma_channel * dma)
++{
++	return BIG_SUR_GE_READ(dma->reg_base_address +
++			       BIG_SUR_GE_IE_REG_OFFSET);
++}
++
++/*********************************************************************
++ * Transfer the data over the DMA channel
++ *********************************************************************/
++static void big_sur_ge_dma_transfer(xdma_channel * dma, unsigned long *source,
++			     unsigned long *dest, unsigned long length)
++{
++	BIG_SUR_GE_WRITE(dma->reg_base_address + BIG_SUR_GE_SA_REG_OFFSET,
++			 (unsigned long) source);
++
++	BIG_SUR_GE_WRITE(dma->reg_base_address + BIG_SUR_GE_DA_REG_OFFSET,
++			 (unsigned long) dest);
++
++	BIG_SUR_GE_WRITE(dma->reg_base_address + BIG_SUR_GE_LEN_REG_OFFSET,
++			 length);
++}
++
++/*********************************************************************
++ * Get the DMA descriptor
++ *********************************************************************/
++static int big_sur_ge_get_descriptor(xdma_channel * dma,
++			      xbuf_descriptor ** buffer_desc)
++{
++	unsigned long reg_data;
++
++	reg_data = xbuf_descriptor_GetControl(dma->get_ptr);
++	xbuf_descriptor_SetControl(dma->get_ptr, reg_data |
++				   BIG_SUR_GE_DMACR_SG_DISABLE_MASK);
++
++	*buffer_desc = dma->get_ptr;
++
++	dma->get_ptr = xbuf_descriptor_GetNextPtr(dma->get_ptr);
++	dma->active_desc_count--;
++
++	return 0;
++}
++
++/*********************************************************************
++ * Get the packet count
++ *********************************************************************/
++static int big_sur_ge_get_packet_count(xdma_channel * dma)
++{
++	return (BIG_SUR_GE_READ
++		(dma->reg_base_address + BIG_SUR_GE_UPC_REG_OFFSET));
++}
++
++/*********************************************************************
++ * Descrement the packet count
++ *********************************************************************/
++static void big_sur_ge_decr_packet_count(xdma_channel * dma)
++{
++	unsigned long reg_data;
++
++	reg_data =
++	    BIG_SUR_GE_READ(dma->base_address + BIG_SUR_GE_UPC_REG_OFFSET);
++	if (reg_data > 0)
++		BIG_SUR_GE_WRITE(dma->base_address +
++				 BIG_SUR_GE_UPC_REG_OFFSET, 1);
++}
++
++/****************************************************************************
++ * Start of the code that deals with the Packet Fifo
++ *****************************************************************************/
++
++/****************************************************************************
++ * Init the packet fifo
++ ****************************************************************************/
++static int packet_fifo_init(packet_fifo * fifo, u32 reg, u32 data)
++{
++	fifo->reg_base_addr = reg;
++	fifo->data_base_address = data;
++	fifo->ready_status = 1;
++
++	BIG_SUR_GE_FIFO_RESET(fifo);
++
++	return 0;
++}
++
++/****************************************************************************
++ * Packet fifo self test
++ ****************************************************************************/
++static int packet_fifo_self_test(packet_fifo * fifo, unsigned long type)
++{
++	unsigned long reg_data;
++
++	BIG_SUR_GE_FIFO_RESET(fifo);
++	reg_data =
++	    BIG_SUR_GE_READ(fifo->reg_base_addr +
++			    BIG_SUR_GE_COUNT_STATUS_REG_OFFSET);
++
++	if (type == BIG_SUR_GE_READ_FIFO_TYPE) {
++		if (reg_data != BIG_SUR_GE_EMPTY_FULL_MASK) {
++			printk(KERN_ERR "Read FIFO not empty \n");
++			return -1;
++		}
++	} else if (!(reg_data & BIG_SUR_GE_EMPTY_FULL_MASK)) {
++		printk(KERN_ERR "Write FIFO is full \n");
++		return -1;
++	}
++
++	return 0;
++}
++
++/****************************************************************************
++ * Packet FIFO read
++ ****************************************************************************/
++static int packet_fifo_read(packet_fifo * fifo, u8 * buffer, unsigned int len)
++{
++	unsigned long fifo_count, word_count, extra_byte;
++	unsigned long *buffer_data = (unsigned long *) buffer;
++
++	fifo_count =
++	    BIG_SUR_GE_READ(fifo->reg_base_addr +
++			    BIG_SUR_GE_FIFO_WIDTH_BYTE_COUNT);
++	fifo_count &= BIG_SUR_GE_COUNT_MASK;
++
++	if ((fifo_count * BIG_SUR_GE_FIFO_WIDTH_BYTE_COUNT) < len)
++		return -1;
++
++	word_count = len / BIG_SUR_GE_FIFO_WIDTH_BYTE_COUNT;
++	extra_byte = len % BIG_SUR_GE_FIFO_WIDTH_BYTE_COUNT;
++
++	for (fifo_count = 0; fifo_count < word_count; fifo_count++)
++		buffer_data[fifo_count] =
++		    BIG_SUR_GE_READ(fifo->reg_base_addr);
++
++	if (extra_byte > 0) {
++		unsigned long last_word;
++		int *extra_buffer_data =
++		    (int *) (buffer_data + word_count);
++
++		last_word = BIG_SUR_GE_READ(fifo->data_base_address);
++		if (extra_byte == 1)
++			extra_buffer_data[0] = (int) (last_word << 24);
++		else if (extra_byte == 2) {
++			extra_buffer_data[0] = (int) (last_word << 24);
++			extra_buffer_data[1] = (int) (last_word << 16);
++		} else if (extra_byte == 3) {
++			extra_buffer_data[0] = (int) (last_word << 24);
++			extra_buffer_data[1] = (int) (last_word << 16);
++			extra_buffer_data[2] = (int) (last_word << 8);
++		}
++	}
++
++	return 0;
++}
++
++/*****************************************************************************
++ * Write the data into the packet fifo
++ *****************************************************************************/
++static int packet_fifo_write(packet_fifo * fifo, int *buffer, int len)
++{
++	unsigned long fifo_count, word_count, extra_byte;
++	unsigned long *buffer_data = (unsigned long *) buffer;
++
++	fifo_count =
++	    BIG_SUR_GE_READ(fifo->reg_base_addr +
++			    BIG_SUR_GE_FIFO_WIDTH_BYTE_COUNT);
++	fifo_count &= BIG_SUR_GE_COUNT_MASK;
++
++	word_count = len / BIG_SUR_GE_FIFO_WIDTH_BYTE_COUNT;
++	extra_byte = len % BIG_SUR_GE_FIFO_WIDTH_BYTE_COUNT;
++
++	/* You should see what the ppc driver does here. It just slobbers */
++	if (extra_byte > 0)
++		if (fifo_count > (word_count + 1)) {
++			printk(KERN_ERR
++			       "No room in the packet send fifo \n");
++			return -1;
++		}
++
++	for (fifo_count = 0; fifo_count < word_count; fifo_count++)
++		BIG_SUR_GE_WRITE(fifo->data_base_address,
++				 buffer_data[fifo_count]);
++
++
++	if (extra_byte > 0) {
++		unsigned long last_word = 0;
++		int *extra_buffer_data =
++		    (int *) (buffer_data + word_count);
++
++		if (extra_byte == 1)
++			last_word = extra_buffer_data[0] << 24;
++		else if (extra_byte == 2)
++			last_word = (extra_buffer_data[0] << 24 |
++				     extra_buffer_data[1] << 16);
++
++		else if (extra_byte == 3)
++			last_word = (extra_buffer_data[0] << 24 |
++				     extra_buffer_data[1] << 16 |
++				     extra_buffer_data[2] << 8);
++
++
++		BIG_SUR_GE_WRITE(fifo->data_base_address, last_word);
++	}
++
++	return 0;
++}
++
++
++/*****************************************************************************
++ * Interrupt handlers: We handle any errors associated with the FIFO.
++ * FIFO is for simple dma case and we do want to handle the simple DMA
++ * case. We dont handle the Scatter Gather DMA for now since it is not working.
++ ******************************************************************************/
++
++/*********************************************************************************
++ * FIFO send for Simple DMA with Interrupts
++ **********************************************************************************/
++static int big_sur_ge_enet_fifo_send(big_sur_ge * emac, u8 * buffer,
++			      unsigned long byte_cnt)
++{
++	unsigned long int_status, reg_data;
++
++	/* Silly checks here that we really dont need */
++	if (!emac->started)
++		return -1;
++
++	if (emac->polled)
++		return -1;
++
++	if (emac->dma_sg)
++		return -1;
++
++	int_status =
++	    BIG_SUR_GE_READ(emac->base_address + XIIF_V123B_IISR_OFFSET);
++	if (int_status & BIG_SUR_GE_EIR_XMIT_LFIFO_FULL_MASK) {
++		printk(KERN_ERR "Tx FIFO error: Queue is Full \n");
++		return -1;
++	}
++
++	/*
++	 * Write the data to the FIFO in the hardware
++	 */
++	if ((BIG_SUR_GE_GET_COUNT(&emac->send_fifo) *
++	     sizeof(unsigned long)) < byte_cnt) {
++		printk(KERN_ERR "Send FIFO on chip is full \n");
++		return -1;
++	}
++
++	if (big_sur_ge_dma_status(&emac->send_channel) &
++	    BIG_SUR_GE_DMASR_BUSY_MASK) {
++		printk(KERN_ERR "Send channel FIFO engine busy \n");
++		return -1;
++	}
++
++	big_sur_ge_set_dma_control(&emac->send_channel,
++				   BIG_SUR_GE_DMACR_SOURCE_INCR_MASK |
++				   BIG_SUR_GE_DMACR_DEST_LOCAL_MASK |
++				   BIG_SUR_GE_DMACR_SG_DISABLE_MASK);
++
++	big_sur_ge_dma_transfer(&emac->send_channel,
++				(unsigned long *) buffer,
++				(unsigned long *) (emac->base_address +
++						   BIG_SUR_GE_PFIFO_TXDATA_OFFSET),
++				byte_cnt);
++
++	reg_data = big_sur_ge_dma_status(&emac->send_channel);
++	while (reg_data & BIG_SUR_GE_DMASR_BUSY_MASK) {
++		reg_data = big_sur_ge_dma_status(&emac->recv_channel);
++		if (!(reg_data & BIG_SUR_GE_DMASR_BUSY_MASK))
++			break;
++	}
++
++	if ((reg_data & BIG_SUR_GE_DMASR_BUS_ERROR_MASK) ||
++	    (reg_data & BIG_SUR_GE_DMASR_BUS_TIMEOUT_MASK)) {
++		printk(KERN_ERR "Send side DMA error \n");
++		return -1;
++	}
++
++	BIG_SUR_GE_WRITE(emac->base_address + BIG_SUR_GE_TPLR_OFFSET,
++			 byte_cnt);
++
++	return 0;
++}
++
++/*************************************************************************
++ * FIFO receive for Simple DMA case
++ *************************************************************************/
++static int big_sur_ge_enet_fifo_recv(big_sur_ge * emac, u8 * buffer,
++			      unsigned long *byte_cnt)
++{
++	unsigned long int_status, reg_data;
++
++	/* Silly checks here that we really dont need */
++	if (!emac->started)
++		return -1;
++
++	if (emac->polled)
++		return -1;
++
++	if (emac->dma_sg)
++		return -1;
++
++	if (*byte_cnt < BIG_SUR_GE_MAX_FRAME_SIZE)
++		return -1;
++
++	int_status =
++	    BIG_SUR_GE_READ(emac->base_address + XIIF_V123B_IISR_OFFSET);
++	if (int_status & BIG_SUR_GE_EIR_RECV_LFIFO_EMPTY_MASK) {
++		BIG_SUR_GE_WRITE(emac->base_address +
++				 XIIF_V123B_IISR_OFFSET,
++				 BIG_SUR_GE_EIR_RECV_LFIFO_EMPTY_MASK);
++		return -1;
++	}
++
++	if (big_sur_ge_dma_status(&emac->recv_channel) &
++	    BIG_SUR_GE_DMASR_BUSY_MASK) {
++		printk(KERN_ERR "Rx side DMA Engine busy \n");
++		return -1;
++	}
++
++	if (BIG_SUR_GE_READ(emac->base_address + BIG_SUR_GE_RPLR_OFFSET) ==
++	    0) {
++		printk(KERN_ERR "MAC has the FIFO packet length 0 \n");
++		return -1;
++	}
++
++	/* For the simple DMA case only */
++	big_sur_ge_set_dma_control(&emac->recv_channel,
++				   BIG_SUR_GE_DMACR_DEST_INCR_MASK |
++				   BIG_SUR_GE_DMACR_SOURCE_LOCAL_MASK |
++				   BIG_SUR_GE_DMACR_SG_DISABLE_MASK);
++
++	if (packet_fifo_read(&emac->recv_fifo, buffer,
++			     BIG_SUR_GE_READ(emac->base_address +
++					     BIG_SUR_GE_RPLR_OFFSET)) ==
++	    -1) {
++		printk(KERN_ERR "Not enough space in the FIFO \n");
++		return -1;
++	}
++
++	big_sur_ge_dma_transfer(&emac->recv_channel,
++				(unsigned long *) (emac->base_address +
++						   BIG_SUR_GE_PFIFO_RXDATA_OFFSET),
++				(unsigned long *)
++				buffer,
++				BIG_SUR_GE_READ(emac->base_address +
++						BIG_SUR_GE_RPLR_OFFSET));
++
++	reg_data = big_sur_ge_dma_status(&emac->recv_channel);
++	while (reg_data & BIG_SUR_GE_DMASR_BUSY_MASK) {
++		reg_data = big_sur_ge_dma_status(&emac->recv_channel);
++		if (!(reg_data & BIG_SUR_GE_DMASR_BUSY_MASK))
++			break;
++	}
++
++	if ((reg_data & BIG_SUR_GE_DMASR_BUS_ERROR_MASK) ||
++	    (reg_data & BIG_SUR_GE_DMASR_BUS_TIMEOUT_MASK)) {
++		printk(KERN_ERR "DMA Bus Error \n");
++		return -1;
++	}
++
++	*byte_cnt =
++	    BIG_SUR_GE_READ(emac->base_address + BIG_SUR_GE_RPLR_OFFSET);
++
++	return 0;
++}
++
++static irqreturn_t big_sur_ge_int_handler(int irq, void *dev_id,
++				   struct pt_regs *regs)
++{
++	struct net_device *netdev = dev_id;
++	struct big_sur_ge_enet *lp = netdev->priv;
++	big_sur_ge *emac = (big_sur_ge *)emac_ptr;
++	void *emac_ptr = &lp->emac;
++	unsigned long int_status;
++
++	int_status =
++	    BIG_SUR_GE_READ(emac->base_address + XIIF_V123B_DIPR_OFFSET);
++	if (int_status & BIG_SUR_GE_IPIF_EMAC_MASK)
++		handle_fifo_intr(emac);
++
++	if (int_status & BIG_SUR_GE_IPIF_RECV_FIFO_MASK)
++		big_sur_ge_check_fifo_recv_error(emac);
++
++	if (int_status & BIG_SUR_GE_IPIF_SEND_FIFO_MASK)
++		big_sur_ge_check_fifo_send_error(emac);
++
++	if (int_status & XIIF_V123B_ERROR_MASK)
++		BIG_SUR_GE_WRITE(emac->base_address +
++				 XIIF_V123B_DISR_OFFSET,
++				 XIIF_V123B_ERROR_MASK);
++
++	return IRQ_HANDLED;
++}
++
++/****************************************************************************
++ * Set the FIFO send handler
++ ***************************************************************************/
++static void big_sur_ge_set_fifo_send_handler(big_sur_ge * emac, void *call_back,
++				      big_sur_fifo_handler function)
++{
++	emac->big_sur_ge_fifo_send_handler = function;
++	emac->fifo_send_ref = call_back;
++}
++
++/****************************************************************************
++ * Set the FIFO recv handler
++ ***************************************************************************/
++static void big_sur_ge_set_fifo_recv_handler(big_sur_ge * emac, void *call_back,
++				      big_sur_fifo_handler function)
++{
++	emac->big_sur_ge_fifo_recv_handler = function;
++	emac->fifo_recv_ref = call_back;
++}
++
++/****************************************************************************
++ * Main Fifo intr handler
++ ***************************************************************************/
++static void handle_fifo_intr(big_sur_ge * emac)
++{
++	unsigned long int_status;
++
++	/* Ack the interrupts asap */
++	int_status =
++	    BIG_SUR_GE_READ(emac->base_address + XIIF_V123B_IISR_OFFSET);
++	BIG_SUR_GE_WRITE(emac->base_address + XIIF_V123B_IISR_OFFSET,
++			 int_status);
++
++	/* Process the Rx side */
++	if (int_status & BIG_SUR_GE_EIR_RECV_DONE_MASK) {
++		emac->big_sur_ge_fifo_recv_handler(&emac->fifo_recv_ref);
++		BIG_SUR_GE_WRITE(emac->base_address +
++				 XIIF_V123B_IISR_OFFSET,
++				 BIG_SUR_GE_EIR_RECV_DONE_MASK);
++	}
++
++	if (int_status & BIG_SUR_GE_EIR_XMIT_DONE_MASK) {
++		/* We dont collect stats and hence we dont need to get status */
++
++		emac->big_sur_ge_fifo_send_handler(emac->fifo_recv_ref);
++		BIG_SUR_GE_WRITE(emac->base_address +
++				 XIIF_V123B_IISR_OFFSET,
++				 BIG_SUR_GE_EIR_XMIT_DONE_MASK);
++	}
++
++	big_sur_ge_check_mac_error(emac, int_status);
++}
++
++/******************************************************************
++ * Handle the Receive side DMA interrupts. The PPC driver has
++ * callbacks all over the place. This has been eliminated here by
++ * using the following approach:
++ *
++ * The ISR is set to the main interrrupt handler. This will handle
++ * all the interrupts including the ones for DMA. In this main isr,
++ * we determine if we need to call recv or send side intr functions.
++ * Pretty complex but thats the way it is now.
++ *******************************************************************/
++static void big_sur_ge_handle_recv_intr(big_sur_ge * emac)
++{
++	unsigned long int_status;
++
++	int_status = big_sur_ge_get_intr_status(&emac->recv_channel);
++	if (int_status & (BIG_SUR_GE_IXR_PKT_THRESHOLD_MASK |
++			  BIG_SUR_GE_IXR_PKT_WAIT_BOUND_MASK)) {
++		u32 num_packets;
++		u32 num_processed;
++		u32 num_buffers;
++		u32 num_bytes;
++		xbuf_descriptor *first_desc_ptr = NULL;
++		xbuf_descriptor *buffer_desc;
++		int is_last = 0;
++
++		/* The number of packets we need to process on the Rx */
++		num_packets =
++		    big_sur_ge_get_packet_count(&emac->recv_channel);
++
++		for (num_processed = 0; num_processed < num_packets;
++		     num_processed++) {
++			while (!is_last) {
++				if (big_sur_ge_get_descriptor
++				    (&emac->recv_channel,
++				     &buffer_desc) == -1)
++					break;
++
++				if (first_desc_ptr == NULL)
++					first_desc_ptr = buffer_desc;
++
++				num_bytes +=
++				    xbuf_descriptor_GetLength(buffer_desc);
++
++				if (xbuf_descriptor_IsLastStatus
++				    (buffer_desc)) {
++					is_last = 1;
++				}
++
++				num_buffers++;
++			}
++
++			/* Number of buffers is always 1 since we dont do SG */
++
++			/*
++			 * Only for SG DMA which is currently not supported. In the
++			 * future, as we have SG channel working, we will code this
++			 * receive side routine. For now, do nothing. This is never
++			 * called from FIFO mode - Manish
++			 */
++			big_sur_ge_decr_packet_count(&emac->recv_channel);
++		}
++	}
++
++	/* Ack the interrupts */
++	big_sur_ge_set_intr_status(&emac->recv_channel, int_status);
++
++	if (int_status & BIG_SUR_GE_IXR_DMA_ERROR_MASK) {
++		/* We need a reset here */
++	}
++
++	big_sur_ge_set_intr_status(&emac->recv_channel, int_status);
++}
++
++/****************************************************************
++ * Handle the send side DMA interrupt
++ ****************************************************************/
++static void big_sur_ge_handle_send_intr(big_sur_ge * emac)
++{
++	unsigned long int_status;
++
++	int_status = big_sur_ge_get_intr_status(&emac->send_channel);
++
++	if (int_status & (BIG_SUR_GE_IXR_PKT_THRESHOLD_MASK |
++			  BIG_SUR_GE_IXR_PKT_WAIT_BOUND_MASK)) {
++		unsigned long num_frames = 0;
++		unsigned long num_processed = 0;
++		unsigned long num_buffers = 0;
++		unsigned long num_bytes = 0;
++		unsigned long is_last = 0;
++		xbuf_descriptor *first_desc_ptr = NULL;
++		xbuf_descriptor *buffer_desc;
++
++		num_frames =
++		    big_sur_ge_get_packet_count(&emac->send_channel);
++
++		for (num_processed = 0; num_processed < num_frames;
++		     num_processed++) {
++			while (!is_last) {
++				if (big_sur_ge_get_descriptor
++				    (&emac->send_channel, &buffer_desc)
++				    == -1) {
++					break;
++				}
++
++				if (first_desc_ptr == NULL)
++					first_desc_ptr = buffer_desc;
++
++				num_bytes +=
++				    xbuf_descriptor_GetLength(buffer_desc);
++				if (xbuf_descriptor_IsLastControl
++				    (buffer_desc))
++					is_last = 1;
++
++				num_buffers++;
++			}
++
++			/*
++			 * Only for SG DMA which is currently not supported. In the
++			 * future, as we have SG channel working, we will code this
++			 * receive side routine. For now, do nothing. This is never
++			 * called from FIFO mode - Manish
++			 */
++			big_sur_ge_decr_packet_count(&emac->send_channel);
++		}
++	}
++
++	/* Ack the interrupts and reset DMA channel if necessary */
++	big_sur_ge_set_intr_status(&emac->send_channel, int_status);
++	if (int_status & BIG_SUR_GE_IXR_DMA_ERROR_MASK) {
++		/* Manish : need reset */
++	}
++
++	big_sur_ge_set_intr_status(&emac->send_channel, int_status);
++}
++
++/*****************************************************************
++ * For now, the MAC address errors dont trigger a update of the
++ * stats. There is no stats framework in place. Hence, we just
++ * check for the errors below and do a reset if needed.
++ *****************************************************************/
++static void big_sur_ge_check_mac_error(big_sur_ge * emac,
++				unsigned long int_status)
++{
++	if (int_status & (BIG_SUR_GE_EIR_RECV_DFIFO_OVER_MASK |
++			  BIG_SUR_GE_EIR_RECV_LFIFO_OVER_MASK |
++			  BIG_SUR_GE_EIR_RECV_LFIFO_UNDER_MASK |
++			  BIG_SUR_GE_EIR_RECV_ERROR_MASK |
++			  BIG_SUR_GE_EIR_RECV_MISSED_FRAME_MASK |
++			  BIG_SUR_GE_EIR_RECV_COLLISION_MASK |
++			  BIG_SUR_GE_EIR_RECV_FCS_ERROR_MASK |
++			  BIG_SUR_GE_EIR_RECV_LEN_ERROR_MASK |
++			  BIG_SUR_GE_EIR_RECV_SHORT_ERROR_MASK |
++			  BIG_SUR_GE_EIR_RECV_LONG_ERROR_MASK |
++			  BIG_SUR_GE_EIR_RECV_ALIGN_ERROR_MASK |
++			  BIG_SUR_GE_EIR_XMIT_SFIFO_OVER_MASK |
++			  BIG_SUR_GE_EIR_XMIT_LFIFO_OVER_MASK |
++			  BIG_SUR_GE_EIR_XMIT_SFIFO_UNDER_MASK |
++			  BIG_SUR_GE_EIR_XMIT_LFIFO_UNDER_MASK)) {
++
++		BIG_SUR_GE_WRITE(emac->base_address +
++				 XIIF_V123B_IIER_OFFSET, 0);
++		/*
++		 * Manish Reset the MAC here
++		 */
++	}
++}
++
++/*****************************************************************
++ * Check for FIFO Recv errors
++ *****************************************************************/
++static void big_sur_ge_check_fifo_recv_error(big_sur_ge * emac)
++{
++	if (BIG_SUR_GE_IS_DEADLOCKED(&emac->recv_fifo)) {
++		unsigned long intr_enable;
++
++		intr_enable =
++		    BIG_SUR_GE_READ(emac->base_address +
++				    XIIF_V123B_DIER_OFFSET);
++		BIG_SUR_GE_WRITE(emac->base_address +
++				 XIIF_V123B_DIER_OFFSET,
++				 intr_enable &
++				 ~(BIG_SUR_GE_IPIF_RECV_FIFO_MASK));
++
++	}
++}
++
++/*****************************************************************
++ * Check for FIFO Send errors
++ *****************************************************************/
++static void big_sur_ge_check_fifo_send_error(big_sur_ge * emac)
++{
++	if (BIG_SUR_GE_IS_DEADLOCKED(&emac->send_fifo)) {
++		unsigned long intr_enable;
++
++		intr_enable =
++		    BIG_SUR_GE_READ(emac->base_address +
++				    XIIF_V123B_DIER_OFFSET);
++		BIG_SUR_GE_WRITE(emac->base_address +
++				 XIIF_V123B_DIER_OFFSET,
++				 intr_enable &
++				 ~(BIG_SUR_GE_IPIF_SEND_FIFO_MASK));
++	}
++}
++
++/*****************************************************************
++ * GE unit init
++ ****************************************************************/
++static int big_sur_ge_enet_init(big_sur_ge * emac, unsigned int device_id)
++{
++	unsigned long reg_data;
++	big_sur_ge_config *config;
++	int err;
++
++	/* Assume that the device has been stopped */
++
++	config = big_sur_ge_lookup_config(device_id);
++	if (config == NULL)
++		return -1;
++
++	emac->ready = 0;
++	emac->started = 0;
++	emac->dma_sg = 0;	/* This MAC has no support for Scatter Gather DMA */
++	emac->has_mii = config->has_mii;
++	emac->has_mcast_hash_table = 0;
++	emac->dma_config = config->dma_config;
++
++	/*
++	 * Initialize the FIFO send and recv handlers to the stub handlers.
++	 * We only deal with the FIFO mode of operation since SG is not supported.
++	 * Also, there is no error handler. We try to handle as much of error as
++	 * possible and then return. No error codes also.
++	 */
++
++	emac->base_address = config->base_address;
++
++	if (big_sur_ge_config_dma(emac) == -1)
++		return -1;
++
++	err = big_sur_ge_config_fifo(emac);
++	if (err == -1)
++		return err;
++
++	/* Now, we know that the FIFO initialized successfully. So, set the ready flag */
++	emac->ready = 1;
++
++	/* Do we need a PHY reset here also. It did cause problems on some boards */
++	big_sur_ge_enet_reset(emac);
++
++	/* PHY reset code. Remove if causes a problem on the board */
++	reg_data =
++	    BIG_SUR_GE_READ(emac->base_address + BIG_SUR_GE_ECR_OFFSET);
++	reg_data &= ~(BIG_SUR_GE_ECR_PHY_ENABLE_MASK);
++	BIG_SUR_GE_WRITE(emac->base_address + BIG_SUR_GE_ECR_OFFSET,
++			 reg_data);
++	reg_data |= BIG_SUR_GE_ECR_PHY_ENABLE_MASK;
++	BIG_SUR_GE_WRITE(emac->base_address + BIG_SUR_GE_ECR_OFFSET,
++			 reg_data);
++
++	return 0;
++}
++
++/*******************************************************************
++ * Start the GE unit for Tx, Rx and Interrupts
++ *******************************************************************/
++static int big_sur_ge_start(big_sur_ge * emac)
++{
++	unsigned long reg_data;
++
++	/*
++	 * Basic mode of operation is polled and interrupt mode. We disable the polled
++	 * mode for good. We may use the polled mode for Rx NAPI but that does not
++	 * require all the interrupts to be disabled
++	 */
++
++	emac->polled = 0;
++
++	/*
++	 * DMA: Three modes of operation - simple, FIFO, SG. SG is surely not working
++	 * and so is kept off using the dma_sg flag. Simple and FIFO work. But, we may
++	 * not use FIFO at all. So, we enable the interrupts below
++	 */
++
++	BIG_SUR_GE_WRITE(emac->base_address + XIIF_V123B_DIER_OFFSET,
++			 BIG_SUR_GE_IPIF_FIFO_DFT_MASK |
++			 XIIF_V123B_ERROR_MASK);
++
++	BIG_SUR_GE_WRITE(emac->base_address + XIIF_V123B_IIER_OFFSET,
++			 BIG_SUR_GE_EIR_DFT_FIFO_MASK);
++
++	/* Toggle the started flag */
++	emac->started = 1;
++
++	/* Start the Tx and Rx units respectively */
++	reg_data =
++	    BIG_SUR_GE_READ(emac->base_address + BIG_SUR_GE_ECR_OFFSET);
++	reg_data &=
++	    ~(BIG_SUR_GE_ECR_XMIT_RESET_MASK |
++	      BIG_SUR_GE_ECR_RECV_RESET_MASK);
++	reg_data |=
++	    (BIG_SUR_GE_ECR_XMIT_ENABLE_MASK |
++	     BIG_SUR_GE_ECR_RECV_ENABLE_MASK);
++
++	BIG_SUR_GE_WRITE(emac->base_address + BIG_SUR_GE_ECR_OFFSET,
++			 reg_data);
++
++	return 0;
++}
++
++/**************************************************************************
++ * Stop the GE unit
++ **************************************************************************/
++static int big_sur_ge_stop(big_sur_ge * emac)
++{
++	unsigned long reg_data;
++
++	/* We assume that the device is not already stopped */
++	if (!emac->started)
++		return 0;
++
++	/* Disable the Tx and Rx unit respectively */
++	reg_data =
++	    BIG_SUR_GE_READ(emac->base_address + BIG_SUR_GE_ECR_OFFSET);
++	reg_data &=
++	    ~(BIG_SUR_GE_ECR_XMIT_ENABLE_MASK |
++	      BIG_SUR_GE_ECR_RECV_ENABLE_MASK);
++	BIG_SUR_GE_WRITE(emac->base_address + BIG_SUR_GE_ECR_OFFSET,
++			 reg_data);
++
++	/* Disable the interrupts */
++	BIG_SUR_GE_WRITE(emac->base_address + XIIF_V123B_DGIER_OFFSET, 0);
++
++	/* Toggle the started flag */
++	emac->started = 0;
++
++	return 0;
++}
++
++/************************************************************************
++ * Reset the GE MAC unit
++ *************************************************************************/
++static void big_sur_ge_enet_reset(big_sur_ge * emac)
++{
++	unsigned long reg_data;
++
++	(void) big_sur_ge_stop(emac);
++
++	BIG_SUR_GE_WRITE(emac->base_address + XIIF_V123B_RESETR_OFFSET,
++			 XIIF_V123B_RESET_MASK);
++
++	/*
++	 * For now, configure the receiver to not strip off FCS and padding since
++	 * this is not currently supported. In the future, just take the default
++	 * and provide the option for the user to change this behavior.
++	 */
++	reg_data =
++	    BIG_SUR_GE_READ(emac->base_address + BIG_SUR_GE_ECR_OFFSET);
++	reg_data &=
++	    ~(BIG_SUR_GE_ECR_RECV_PAD_ENABLE_MASK |
++	      BIG_SUR_GE_ECR_RECV_FCS_ENABLE_MASK);
++	reg_data &= ~(BIG_SUR_GE_ECR_RECV_STRIP_ENABLE_MASK);
++	BIG_SUR_GE_WRITE(emac->base_address + BIG_SUR_GE_ECR_OFFSET,
++			 reg_data);
++}
++
++/*************************************************************************
++ * Set the MAC address of the GE mac unit
++ *************************************************************************/
++static int big_sur_ge_set_mac_address(big_sur_ge * emac, unsigned char *addr)
++{
++	unsigned long mac_addr = 0;
++
++	/* Device is started and so mac address must be set */
++	if (emac->started == 1)
++		return 0;
++
++	mac_addr = ((addr[0] << 8) | addr[1]);
++	BIG_SUR_GE_WRITE(emac->base_address + BIG_SUR_GE_SAH_OFFSET,
++			 mac_addr);
++
++	mac_addr |= ((addr[2] << 24) | (addr[3] << 16) |
++		     (addr[4] << 8) | addr[5]);
++
++	BIG_SUR_GE_WRITE(emac->base_address + BIG_SUR_GE_SAL_OFFSET,
++			 mac_addr);
++
++	return 0;
++}
++
++/****************************************************************************
++ * Get the MAC address of the GE MAC unit
++ ***************************************************************************/
++static void big_sur_ge_get_mac_unit(big_sur_ge * emac, unsigned int *addr)
++{
++	unsigned long mac_addr_hi, mac_addr_lo;
++
++	mac_addr_hi =
++	    BIG_SUR_GE_READ(emac->base_address + BIG_SUR_GE_SAH_OFFSET);
++	mac_addr_lo =
++	    BIG_SUR_GE_READ(emac->base_address + BIG_SUR_GE_SAL_OFFSET);
++
++	addr[0] = (mac_addr_hi >> 8);
++	addr[1] = mac_addr_hi;
++
++	addr[2] = (mac_addr_lo >> 24);
++	addr[3] = (mac_addr_lo >> 16);
++	addr[4] = (mac_addr_lo >> 8);
++	addr[5] = mac_addr_lo;
++}
++
++/*********************************************************************************
++ * Configure the GE MAC for DMA capabilities. Not for Scatter Gather, only Simple
++ *********************************************************************************/
++static int big_sur_ge_config_dma(big_sur_ge * emac)
++{
++	if (big_sur_ge_dma_init(&emac->recv_channel, emac->base_address +
++				BIG_SUR_GE_DMA_RECV_OFFSET) == -1) {
++		printk(KERN_ERR "Could not initialize the DMA unit  \n");
++		return -1;
++	}
++
++	if (big_sur_ge_dma_init(&emac->send_channel, emac->base_address +
++				BIG_SUR_GE_DMA_SEND_OFFSET) == -1) {
++		printk(KERN_ERR "Could not initialize the DMA unit  \n");
++		return -1;
++	}
++
++	return 0;
++}
++
++/******************************************************************************
++ * Configure the FIFO for simple DMA
++ ******************************************************************************/
++static int big_sur_ge_config_fifo(big_sur_ge * emac)
++{
++	int err = 0;
++
++	err = packet_fifo_init(&emac->recv_fifo, emac->base_address +
++			       BIG_SUR_GE_PFIFO_RXREG_OFFSET,
++			       emac->base_address +
++			       BIG_SUR_GE_PFIFO_RXDATA_OFFSET);
++
++	if (err == -1) {
++		printk(KERN_ERR
++		       "Could not initialize Rx packet FIFO for Simple DMA \n");
++		return err;
++	}
++
++	err = packet_fifo_init(&emac->send_fifo, emac->base_address +
++			       BIG_SUR_GE_PFIFO_TXREG_OFFSET,
++			       emac->base_address +
++			       BIG_SUR_GE_PFIFO_TXDATA_OFFSET);
++
++	if (err == -1) {
++		printk(KERN_ERR
++		       "Could not initialize Tx packet FIFO for Simple DMA \n");
++	}
++
++	return err;
++}
++
++#define BIG_SUR_GE_NUM_INSTANCES	2
++
++
++/**********************************************************************************
++ * Look up the config of the MAC
++ **********************************************************************************/
++static big_sur_ge_config *big_sur_ge_lookup_config(unsigned int device_id)
++{
++	big_sur_ge_config *config = NULL;
++	int i = 0;
++
++	for (i = 0; i < BIG_SUR_GE_NUM_INSTANCES; i++) {
++		/* Manish : Init the config here */
++		break;
++	}
++
++	return config;
++}
++
++typedef struct {
++	unsigned long option;
++	unsigned long mask;
++} option_map;
++
++static option_map option_table[] = {
++	{BIG_SUR_GE_UNICAST_OPTION, BIG_SUR_GE_ECR_UNICAST_ENABLE_MASK},
++	{BIG_SUR_GE_BROADCAST_OPTION, BIG_SUR_GE_ECR_BROAD_ENABLE_MASK},
++	{BIG_SUR_GE_PROMISC_OPTION, BIG_SUR_GE_ECR_PROMISC_ENABLE_MASK},
++	{BIG_SUR_GE_FDUPLEX_OPTION, BIG_SUR_GE_ECR_FULL_DUPLEX_MASK},
++	{BIG_SUR_GE_LOOPBACK_OPTION, BIG_SUR_GE_ECR_LOOPBACK_MASK},
++	{BIG_SUR_GE_MULTICAST_OPTION, BIG_SUR_GE_ECR_MULTI_ENABLE_MASK},
++	{BIG_SUR_GE_FLOW_CONTROL_OPTION, BIG_SUR_GE_ECR_PAUSE_FRAME_MASK},
++	{BIG_SUR_GE_INSERT_PAD_OPTION,
++	 BIG_SUR_GE_ECR_XMIT_PAD_ENABLE_MASK},
++	{BIG_SUR_GE_INSERT_FCS_OPTION,
++	 BIG_SUR_GE_ECR_XMIT_FCS_ENABLE_MASK},
++	{BIG_SUR_GE_INSERT_ADDR_OPTION,
++	 BIG_SUR_GE_ECR_XMIT_ADDR_INSERT_MASK},
++	{BIG_SUR_GE_OVWRT_ADDR_OPTION,
++	 BIG_SUR_GE_ECR_XMIT_ADDR_OVWRT_MASK},
++	{BIG_SUR_GE_STRIP_PAD_OPTION, BIG_SUR_GE_ECR_RECV_PAD_ENABLE_MASK},
++	{BIG_SUR_GE_STRIP_FCS_OPTION, BIG_SUR_GE_ECR_RECV_FCS_ENABLE_MASK},
++	{BIG_SUR_GE_STRIP_PAD_FCS_OPTION,
++	 BIG_SUR_GE_ECR_RECV_STRIP_ENABLE_MASK}
++};
++
++#define BIG_SUR_GE_NUM_OPTIONS		(sizeof(option_table) / sizeof(option_map))
++
++/**********************************************************************
++ * Set the options for the GE
++ **********************************************************************/
++static int big_sur_ge_set_options(big_sur_ge * emac, unsigned long option_flag)
++{
++	unsigned long reg_data;
++	unsigned int index;
++
++	/* Assume that the device is stopped before calling this function */
++
++	reg_data =
++	    BIG_SUR_GE_READ(emac->base_address + BIG_SUR_GE_ECR_OFFSET);
++	for (index = 0; index < BIG_SUR_GE_NUM_OPTIONS; index++) {
++		if (option_flag & option_table[index].option)
++			reg_data |= option_table[index].mask;
++		else
++			reg_data &= ~(option_table[index].mask);
++
++	}
++
++	BIG_SUR_GE_WRITE(emac->base_address + BIG_SUR_GE_ECR_OFFSET,
++			 reg_data);
++
++	/* No polled option */
++	emac->polled = 0;
++
++	return 0;
++}
++
++/*******************************************************
++ * Get the options from the GE
++ *******************************************************/
++static unsigned long big_sur_ge_get_options(big_sur_ge * emac)
++{
++	unsigned long option_flag = 0, reg_data;
++	unsigned int index;
++
++	reg_data =
++	    BIG_SUR_GE_READ(emac->base_address + BIG_SUR_GE_ECR_OFFSET);
++
++	for (index = 0; index < BIG_SUR_GE_NUM_OPTIONS; index++) {
++		if (option_flag & option_table[index].option)
++			reg_data |= option_table[index].mask;
++	}
++
++	/* No polled mode */
++
++	return option_flag;
++}
++
++/********************************************************
++ * Set the Inter frame gap
++ ********************************************************/
++static int big_sur_ge_set_frame_gap(big_sur_ge * emac, int part1, int part2)
++{
++	unsigned long config;
++
++	/* Assume that the device is stopped before calling this */
++
++	config = ((part1 << BIG_SUR_GE_IFGP_PART1_SHIFT) |
++		  (part2 << BIG_SUR_GE_IFGP_PART2_SHIFT));
++
++	BIG_SUR_GE_WRITE(emac->base_address + BIG_SUR_GE_IFGP_OFFSET,
++			 config);
++
++	return 0;
++}
++
++/********************************************************
++ * Get the Inter frame gap
++ ********************************************************/
++static void big_sur_ge_get_frame_gap(big_sur_ge * emac, int *part1, int *part2)
++{
++	unsigned long config;
++
++	config =
++	    BIG_SUR_GE_READ(emac->base_address + BIG_SUR_GE_IFGP_OFFSET);
++	*part1 =
++	    ((config & BIG_SUR_GE_IFGP_PART1_SHIFT) >>
++	     BIG_SUR_GE_IFGP_PART1_SHIFT);
++	*part2 =
++	    ((config & BIG_SUR_GE_IFGP_PART2_SHIFT) >>
++	     BIG_SUR_GE_IFGP_PART2_SHIFT);
++}
++
++/*******************************************************************
++ * PHY specific functions for the MAC
++ *******************************************************************/
++#define BIG_SUR_GE_MAX_PHY_ADDR		32
++#define BIG_SUR_GE_MAX_PHY_REG		32
++
++/*******************************************************************
++ * Read the PHY reg
++ *******************************************************************/
++static int big_sur_ge_phy_read(big_sur_ge * emac, unsigned long addr,
++			unsigned long reg_num, unsigned int *data)
++{
++	unsigned long mii_control, mii_data;
++
++	if (!emac->has_mii)
++		return -1;
++
++	mii_control =
++	    BIG_SUR_GE_READ(emac->base_address + BIG_SUR_GE_MGTCR_OFFSET);
++	if (mii_control & BIG_SUR_GE_MGTCR_START_MASK) {
++		printk(KERN_ERR "PHY busy \n");
++		return -1;
++	}
++
++	mii_control = (addr << BIG_SUR_GE_MGTCR_PHY_ADDR_SHIFT);
++	mii_control |= (reg_num << BIG_SUR_GE_MGTCR_REG_ADDR_SHIFT);
++	mii_control |=
++	    (BIG_SUR_GE_MGTCR_RW_NOT_MASK | BIG_SUR_GE_MGTCR_START_MASK |
++	     BIG_SUR_GE_MGTCR_MII_ENABLE_MASK);
++
++	BIG_SUR_GE_WRITE(emac->base_address + BIG_SUR_GE_MGTCR_OFFSET,
++			 mii_control);
++
++	while (mii_control & BIG_SUR_GE_MGTCR_START_MASK)
++		if (!(mii_control & BIG_SUR_GE_MGTCR_START_MASK))
++			break;
++
++	mii_data =
++	    BIG_SUR_GE_READ(emac->base_address + BIG_SUR_GE_MGTDR_OFFSET);
++	*data = (unsigned int) mii_data;
++
++	return 0;
++}
++
++/**********************************************************************
++ * Write to the PHY register
++ **********************************************************************/
++static int big_sur_ge_phy_write(big_sur_ge * emac, unsigned long addr,
++			 unsigned long reg_num, unsigned int data)
++{
++	unsigned long mii_control;
++
++	if (!emac->has_mii)
++		return -1;
++
++	mii_control =
++	    BIG_SUR_GE_READ(emac->base_address + BIG_SUR_GE_MGTCR_OFFSET);
++	if (mii_control & BIG_SUR_GE_MGTCR_START_MASK) {
++		printk(KERN_ERR "PHY busy \n");
++		return -1;
++	}
++
++	BIG_SUR_GE_WRITE(emac->base_address + BIG_SUR_GE_MGTDR_OFFSET,
++			 (unsigned long) data);
++
++	mii_control = (addr << BIG_SUR_GE_MGTCR_PHY_ADDR_SHIFT);
++	mii_control |= (reg_num << BIG_SUR_GE_MGTCR_REG_ADDR_SHIFT);
++	mii_control |=
++	    (BIG_SUR_GE_MGTCR_START_MASK |
++	     BIG_SUR_GE_MGTCR_MII_ENABLE_MASK);
++
++	BIG_SUR_GE_WRITE(emac->base_address + BIG_SUR_GE_MGTCR_OFFSET,
++			 mii_control);
++
++	while (mii_control & BIG_SUR_GE_MGTCR_START_MASK)
++		if (!(mii_control & BIG_SUR_GE_MGTCR_START_MASK))
++			break;
++
++	return 0;
++}
++
++
++
++
++
++
++/********************************************************************
++ * The hardware dependent part of the driver begins here
++ ********************************************************************/
++
++
++/*******************************************************************
++ * Reset the GE system
++ *******************************************************************/
++static void big_sur_ge_reset(struct net_device *netdev, DUPLEX duplex)
++{
++	struct big_sur_ge_enet *lp = netdev->priv;
++	struct sk_buff *skb;
++	unsigned long options;
++	int ifcfg1, ifcfg2;
++
++	/* Stop the queue */
++	netif_stop_queue(netdev);
++
++	big_sur_ge_get_frame_gap(&lp->emac, &ifcfg1, &ifcfg2);
++	options = big_sur_ge_get_options(&lp->emac);
++	switch (duplex) {
++	case HALF_DUPLEX:
++		options &= ~(BIG_SUR_GE_FDUPLEX_OPTION);
++		break;
++
++	case FULL_DUPLEX:
++		options |= BIG_SUR_GE_FDUPLEX_OPTION;
++		break;
++
++	case UNKNOWN:
++		break;
++	}
++
++	/* There is no support for SG DMA in a 100 Mpbs NIC */
++
++	big_sur_ge_enet_reset(&lp->emac);
++
++	/* Set the necessary options for the MAC unit */
++	big_sur_ge_set_mac_address(&lp->emac, netdev->dev_addr);
++	big_sur_ge_set_frame_gap(&lp->emac, ifcfg1, ifcfg2);
++	big_sur_ge_set_options(&lp->emac, options);
++
++	(void) big_sur_ge_start(&lp->emac);
++
++	spin_lock_irq(&lp->lock);
++	skb = lp->saved_skb;
++	lp->saved_skb = NULL;
++	spin_unlock_irq(&lp->lock);
++
++	if (skb)
++		dev_kfree_skb(skb);
++
++	/* Wake the queue */
++	netif_wake_queue(netdev);
++}
++
++/********************************************************************
++ * Get the PHY status
++ *******************************************************************/
++static int big_sur_ge_get_phy_status(struct net_device *netdev,
++				     DUPLEX * duplex, int *linkup)
++{
++	struct big_sur_ge_enet *lp = netdev->priv;
++	unsigned int reg_data;
++	int err = 0;
++
++	err =
++	    big_sur_ge_phy_read(&lp->emac, lp->mii_addr, MII_BMCR,
++				&reg_data);
++	if (err == -1) {
++		printk(KERN_ERR "%s: Could not read PHY control register",
++		       netdev->name);
++		return err;
++	}
++
++	if (!(reg_data & BMCR_ANENABLE)) {
++		if (reg_data & BMCR_FULLDPLX)
++			*duplex = FULL_DUPLEX;
++		else
++			*duplex = HALF_DUPLEX;
++	} else {
++		unsigned int advertise, partner, neg;
++
++		err =
++		    big_sur_ge_phy_read(&lp->emac, lp->mii_addr,
++					MII_ADVERTISE, &advertise);
++		if (err == -1) {
++			printk(KERN_ERR
++			       "%s: Could not read PHY control register",
++			       netdev->name);
++			return err;
++		}
++
++		err =
++		    big_sur_ge_phy_read(&lp->emac, lp->mii_addr, MII_LPA,
++					&partner);
++		if (err == -1) {
++			printk(KERN_ERR
++			       "%s: Could not read PHY control register",
++			       netdev->name);
++			return err;
++		}
++
++		neg = advertise & partner & ADVERTISE_ALL;
++		if (neg & ADVERTISE_100FULL)
++			*duplex = FULL_DUPLEX;
++		else if (neg & ADVERTISE_100HALF)
++			*duplex = HALF_DUPLEX;
++		else if (neg & ADVERTISE_10FULL)
++			*duplex = FULL_DUPLEX;
++		else
++			*duplex = HALF_DUPLEX;
++
++		err =
++		    big_sur_ge_phy_read(&lp->emac, lp->mii_addr, MII_BMSR,
++					&reg_data);
++		if (err == -1) {
++			printk(KERN_ERR
++			       "%s: Could not read PHY control register",
++			       netdev->name);
++			return err;
++		}
++
++		*linkup = (reg_data & BMSR_LSTATUS) != 0;
++
++	}
++	return 0;
++}
++
++/************************************************************
++ * Poll the MII for duplex and link status
++ ***********************************************************/
++static void big_sur_ge_poll_mii(unsigned long data)
++{
++	struct net_device *netdev = (struct net_device *) data;
++	struct big_sur_ge_enet *lp = netdev->priv;
++	unsigned long options;
++	DUPLEX mac_duplex, phy_duplex;
++	int phy_carrier, netif_carrier;
++
++	if (big_sur_ge_get_phy_status(netdev, &phy_duplex, &phy_carrier) ==
++	    -1) {
++		printk(KERN_ERR "%s: Terminating link monitoring.\n",
++		       netdev->name);
++		return;
++	}
++
++	options = big_sur_ge_get_options(&lp->emac);
++	if (options & BIG_SUR_GE_FDUPLEX_OPTION)
++		mac_duplex = FULL_DUPLEX;
++	else
++		mac_duplex = HALF_DUPLEX;
++
++	if (mac_duplex != phy_duplex) {
++		disable_irq(netdev->irq);
++		big_sur_ge_reset(netdev, phy_duplex);
++		enable_irq(netdev->irq);
++	}
++
++	netif_carrier = netif_carrier_ok(netdev) != 0;
++
++	if (phy_carrier != netif_carrier) {
++		if (phy_carrier) {
++			printk(KERN_INFO "%s: Link carrier restored.\n",
++			       netdev->name);
++			netif_carrier_on(netdev);
++		} else {
++			printk(KERN_INFO "%s: Link carrier lost.\n",
++			       netdev->name);
++			netif_carrier_off(netdev);
++		}
++	}
++
++	/* Set up the timer so we'll get called again in 2 seconds. */
++	lp->phy_timer.expires = jiffies + 2 * HZ;
++	add_timer(&lp->phy_timer);
++}
++
++/**************************************************************
++ * Open the network interface
++ *************************************************************/
++static int big_sur_ge_open(struct net_device *netdev)
++{
++	struct big_sur_ge_enet *lp = netdev->priv;
++	unsigned long options;
++	DUPLEX phy_duplex, mac_duplex;
++	int phy_carrier, retval;
++
++	(void) big_sur_ge_stop(&lp->emac);
++
++	if (big_sur_ge_set_mac_address(&lp->emac, netdev->dev_addr) == -1) {
++		printk(KERN_ERR "%s: Could not set MAC address.\n",
++		       netdev->name);
++		return -EIO;
++	}
++
++	options = big_sur_ge_get_options(&lp->emac);
++
++	retval =
++	    request_irq(netdev->irq, &big_sur_ge_int_handler, 0,
++			netdev->name, netdev);
++	if (retval) {
++		printk(KERN_ERR
++		       "%s: Could not allocate interrupt %d.\n",
++		       netdev->name, netdev->irq);
++
++		return retval;
++	}
++
++	if (!
++	    (big_sur_ge_get_phy_status(netdev, &phy_duplex, &phy_carrier)))
++	{
++		if (options & BIG_SUR_GE_FDUPLEX_OPTION)
++			mac_duplex = FULL_DUPLEX;
++		else
++			mac_duplex = HALF_DUPLEX;
++
++		if (mac_duplex != phy_duplex) {
++			switch (phy_duplex) {
++			case HALF_DUPLEX:
++				options &= ~(BIG_SUR_GE_FDUPLEX_OPTION);
++				break;
++			case FULL_DUPLEX:
++				options |= BIG_SUR_GE_FDUPLEX_OPTION;
++				break;
++			case UNKNOWN:
++				break;
++			}
++
++			big_sur_ge_set_options(&lp->emac, options);
++		}
++	}
++
++	if (big_sur_ge_start(&lp->emac) == -1) {
++		printk(KERN_ERR "%s: Could not start device.\n",
++		       netdev->name);
++		free_irq(netdev->irq, netdev);
++		return -EBUSY;
++	}
++
++	netif_start_queue(netdev);
++
++	lp->phy_timer.expires = jiffies + 2 * HZ;
++	lp->phy_timer.data = (unsigned long) netdev;
++	lp->phy_timer.function = &big_sur_ge_poll_mii;
++	add_timer(&lp->phy_timer);
++
++	return 0;
++}
++
++/*********************************************************************
++ * Close the network device interface
++ *********************************************************************/
++static int big_sur_ge_close(struct net_device *netdev)
++{
++	struct big_sur_ge_enet *lp = netdev->priv;
++
++	del_timer_sync(&lp->phy_timer);
++	netif_stop_queue(netdev);
++
++	free_irq(netdev->irq, netdev);
++
++	if (big_sur_ge_stop(&lp->emac) == -1) {
++		printk(KERN_ERR "%s: Could not stop device.\n",
++		       netdev->name);
++		return -EBUSY;
++	}
++
++	return 0;
++}
++
++/*********************************************************************
++ * Get the network device stats. For now, do nothing
++ *********************************************************************/
++static struct net_device_stats *big_sur_ge_get_stats(struct net_device
++						     *netdev)
++{
++	/* Do nothing */
++	return (struct net_device_stats *) 0;
++}
++
++/********************************************************************
++ * FIFO send for a packet that needs to be transmitted
++ ********************************************************************/
++static int big_sur_ge_fifo_send(struct sk_buff *orig_skb,
++				struct net_device *netdev)
++{
++	struct big_sur_ge_enet *lp = netdev->priv;
++	struct sk_buff *new_skb;
++	unsigned int len, align;
++
++	netif_stop_queue(netdev);
++	len = orig_skb->len;
++
++	if (!(new_skb = dev_alloc_skb(len + 4))) {
++		dev_kfree_skb(orig_skb);
++		printk(KERN_ERR
++		       "%s: Could not allocate transmit buffer.\n",
++		       netdev->name);
++		netif_wake_queue(netdev);
++		return -EBUSY;
++	}
++
++	align = 4 - ((unsigned long) new_skb->data & 3);
++	if (align != 4)
++		skb_reserve(new_skb, align);
++
++	skb_put(new_skb, len);
++	memcpy(new_skb->data, orig_skb->data, len);
++
++	dev_kfree_skb(orig_skb);
++
++	lp->saved_skb = new_skb;
++	if (big_sur_ge_enet_fifo_send(&lp->emac, (u8 *) new_skb->data, len)
++	    == -1) {
++		spin_lock_irq(&lp->lock);
++		new_skb = lp->saved_skb;
++		lp->saved_skb = NULL;
++		spin_unlock_irq(&lp->lock);
++
++		dev_kfree_skb(new_skb);
++		printk(KERN_ERR "%s: Could not transmit buffer.\n",
++		       netdev->name);
++		netif_wake_queue(netdev);
++		return -EIO;
++	}
++	return 0;
++}
++
++/**********************************************************************
++ * Call the fifo send handler
++ **********************************************************************/
++static void big_sur_ge_fifo_send_handler(void *callback)
++{
++	struct net_device *netdev = (struct net_device *) callback;
++	struct big_sur_ge_enet *lp = netdev->priv;
++	struct sk_buff *skb;
++
++	spin_lock_irq(&lp->lock);
++	skb = lp->saved_skb;
++	lp->saved_skb = NULL;
++	spin_unlock_irq(&lp->lock);
++
++	if (skb)
++		dev_kfree_skb(skb);
++
++	netif_wake_queue(netdev);
++}
++
++/**********************************************************************
++ * Handle the timeout of the ethernet device
++ **********************************************************************/
++static void big_sur_ge_tx_timeout(struct net_device *netdev)
++{
++	printk
++	    ("%s: Exceeded transmit timeout of %lu ms.	Resetting mac.\n",
++	     netdev->name, TX_TIMEOUT * 1000UL / HZ);
++
++	disable_irq(netdev->irq);
++	big_sur_ge_reset(netdev, UNKNOWN);
++	enable_irq(netdev->irq);
++}
++
++/*********************************************************************
++ * When in FIFO mode, the callback function for packets received
++ *********************************************************************/
++static void big_sur_ge_fifo_recv_handler(void *callback)
++{
++	struct net_device *netdev = (struct net_device *) callback;
++	struct big_sur_ge_enet *lp = netdev->priv;
++	struct sk_buff *skb;
++	unsigned long len = BIG_SUR_GE_MAX_FRAME_SIZE;
++	unsigned int align;
++
++	if (!(skb = dev_alloc_skb(len + 4))) {
++		printk(KERN_ERR "%s: Could not allocate receive buffer.\n",
++		       netdev->name);
++		return;
++	}
++
++	align = 4 - ((unsigned long) skb->data & 3);
++	if (align != 4)
++		skb_reserve(skb, align);
++
++	if (big_sur_ge_enet_fifo_recv(&lp->emac, (u8 *) skb->data, &len) ==
++	    -1) {
++		dev_kfree_skb(skb);
++
++		printk(KERN_ERR "%s: Could not receive buffer \n",
++		       netdev->name);
++		netdev->tx_timeout = NULL;
++		big_sur_ge_reset(netdev, UNKNOWN);
++		netdev->tx_timeout = big_sur_ge_tx_timeout;
++	}
++
++	skb_put(skb, len);	/* Tell the skb how much data we got. */
++	skb->dev = netdev;	/* Fill out required meta-data. */
++	skb->protocol = eth_type_trans(skb, netdev);
++
++	netif_rx(skb);		/* Send the packet upstream. */
++}
++
++/*********************************************************************
++ * Set the Multicast Hash list
++ *********************************************************************/
++static void big_sur_ge_set_multicast_hash_list(struct net_device *netdev)
++{
++	struct big_sur_ge_enet *lp = netdev->priv;
++	unsigned long options;
++
++	disable_irq(netdev->irq);
++	local_bh_disable();
++
++	(void) big_sur_ge_stop(&lp->emac);
++	options = big_sur_ge_get_options(&lp->emac);
++	options &=
++	    ~(BIG_SUR_GE_PROMISC_OPTION | BIG_SUR_GE_MULTICAST_OPTION);
++
++	/* Do nothing for now */
++
++	(void) big_sur_ge_start(&lp->emac);
++	local_bh_enable();
++	enable_irq(netdev->irq);
++}
++
++/***********************************************************************
++ * IOCTL support
++ ***********************************************************************/
++static int big_sur_ge_ioctl(struct net_device *netdev, struct ifreq *rq,
++			    int cmd)
++{
++	struct big_sur_ge_enet *lp = netdev->priv;
++	struct mii_ioctl_data *data =
++	    (struct mii_ioctl_data *) &rq->ifr_data;
++
++	switch (cmd) {
++	case SIOCGMIIPHY:	/* Get address of MII PHY in use. */
++	case SIOCDEVPRIVATE:	/* for binary compat, remove in 2.5 */
++		data->phy_id = lp->mii_addr;
++
++	case SIOCGMIIREG:	/* Read MII PHY register. */
++	case SIOCDEVPRIVATE + 1:	/* for binary compat, remove in 2.5 */
++		if (data->phy_id > 31 || data->reg_num > 31)
++			return -ENXIO;
++
++		del_timer_sync(&lp->phy_timer);
++
++		if (big_sur_ge_phy_read(&lp->emac, data->phy_id,
++					data->reg_num,
++					&data->val_out) == -1) {
++			printk(KERN_ERR "%s: Could not read from PHY",
++			       netdev->name);
++			return -EBUSY;
++		}
++
++		lp->phy_timer.expires = jiffies + 2 * HZ;
++		add_timer(&lp->phy_timer);
++
++		return 0;
++
++	case SIOCSMIIREG:	/* Write MII PHY register. */
++	case SIOCDEVPRIVATE + 2:	/* for binary compat, remove in 2.5 */
++		if (data->phy_id > 31 || data->reg_num > 31)
++			return -ENXIO;
++
++		del_timer_sync(&lp->phy_timer);
++
++		if (big_sur_ge_phy_write
++		    (&lp->emac, data->phy_id, data->reg_num,
++		     data->val_in) == -1) {
++			printk(KERN_ERR "%s: Could not write to PHY",
++			       netdev->name);
++			return -EBUSY;
++		}
++
++		lp->phy_timer.expires = jiffies + 2 * HZ;
++		add_timer(&lp->phy_timer);
++
++		return 0;
++
++	default:
++		return -EOPNOTSUPP;
++	}
++}
++
++/*****************************************************************
++ * Get the config from the config table
++ *****************************************************************/
++static big_sur_ge_config *big_sur_ge_get_config(int index)
++{
++	/* Manish */
++	return (big_sur_ge_config *) 0;
++}
++
++/*****************************************************************
++ * Release the network device structure
++ *****************************************************************/
++static void big_sur_ge_remove_head(void)
++{
++	struct net_device *netdev;
++	struct big_sur_ge_enet *lp;
++	big_sur_ge_config *config;
++
++	spin_lock(&dev_lock);
++	netdev = dev_list;
++	lp = netdev->priv;
++
++	spin_unlock(&dev_lock);
++
++	config = big_sur_ge_get_config(lp->index);
++	iounmap((void *) config->base_address);
++	config->base_address = lp->save_base_address;
++
++	if (lp->saved_skb)
++		dev_kfree_skb(lp->saved_skb);
++	kfree(lp);
++
++	unregister_netdev(netdev);
++	kfree(netdev);
++}
++
++/*****************************************************************
++ * Initial Function to probe the network interface
++ *****************************************************************/
++static int __init big_sur_ge_probe(int index)
++{
++	static const unsigned long remap_size =
++	    BIG_SUR_GE_EMAC_0_HIGHADDR - BIG_SUR_GE_EMAC_0_BASEADDR + 1;
++	struct net_device *netdev;
++	struct big_sur_ge_enet *lp;
++	big_sur_ge_config *config;
++	unsigned int irq;
++	unsigned long maddr;
++	goto err;
++
++	switch (index) {
++	case 0:
++		irq = (31 - BIG_SUR_GE_INTC_0_EMAC_0_VEC_ID);
++		break;
++	case 1:
++		irq = (31 - BIG_SUR_GE_INTC_1_EMAC_1_VEC_ID);
++		break;
++	case 2:
++		irq = (31 - BIG_SUR_GE_INTC_2_EMAC_2_VEC_ID);
++		break;
++	default:
++		err = -ENODEV;
++		goto out;
++	}
++
++	config = big_sur_ge_get_config(index);
++	if (!config) {
++		err = -ENODEV;
++		goto out;
++	}
++
++	netdev = alloc_etherdev(sizeof(big_sur_ge_config));
++
++	if (!netdev) {
++		err = -ENOMEM;
++		goto out;
++	}
++
++	SET_MODULE_OWNER(netdev);
++
++	netdev->irq = irq;
++
++	lp = (struct big_sur_ge_enet *) netdev->priv;
++	memset(lp, 0, sizeof(struct big_sur_ge_enet));
++	spin_lock_init(&lp->lock);
++	spin_lock(&dev_lock);
++	lp->next_dev = dev_list;
++	dev_list = netdev;
++	spin_unlock(&dev_lock);
++
++	lp->save_base_address = config->base_address;
++	config->base_address =
++	    (unsigned long) ioremap(lp->save_base_address, remap_size);
++	if (!config->base_address) {
++		err = -ENOMEM;
++		goto out_unlock;
++	}
++
++	if (big_sur_ge_enet_init(&lp->emac, config->device_id) == -1) {
++		printk(KERN_ERR "%s: Could not initialize device.\n",
++		       netdev->name);
++		err = -ENODEV;
++		goto out_unmap;
++	}
++
++	/* Manish: dev_addr value */
++	memcpy(netdev->dev_addr, big_sur_mac_addr_base, 6);
++	if (big_sur_ge_set_mac_address(&lp->emac, netdev->dev_addr) == -1) {
++		printk(KERN_ERR "%s: Could not set MAC address.\n",
++		       netdev->name);
++		err = -EIO;
++		goto out_unmap;
++	}
++
++	/*
++	 * There is no Scatter Gather support but there is a Simple DMA support
++	 */
++	big_sur_ge_set_fifo_recv_handler(&lp->emac, netdev,
++					 big_sur_ge_fifo_recv_handler);
++	big_sur_ge_set_fifo_send_handler(&lp->emac, netdev,
++					 big_sur_ge_fifo_send_handler);
++	netdev->hard_start_xmit = big_sur_ge_fifo_send;
++
++	lp->mii_addr = 0xFF;
++
++	for (maddr = 0; maddr < 31; maddr++) {
++		unsigned int reg_data;
++
++		if (big_sur_ge_phy_read
++		    (&lp->emac, maddr, MII_BMCR, &reg_data) == 0) {
++			lp->mii_addr = maddr;
++			break;
++		}
++	}
++
++	if (lp->mii_addr == 0xFF) {
++		lp->mii_addr = 0;
++		printk(KERN_WARNING
++		       "%s: No PHY detected.  Assuming a PHY at address %d.\n",
++		       netdev->name, lp->mii_addr);
++	}
++
++	netdev->open = big_sur_ge_open;
++	netdev->stop = big_sur_ge_close;
++	netdev->get_stats = big_sur_ge_get_stats;	/* Does nothing */
++	netdev->do_ioctl = big_sur_ge_ioctl;
++	netdev->tx_timeout = big_sur_ge_tx_timeout;
++	netdev->watchdog_timeo = TX_TIMEOUT;
++
++	err = register_netdev(netdev))
++	if (!err)
++		goto out_unmap;
++
++	printk(KERN_INFO "%s: PMC-Sierra Big Sur Ethernet Device %d  at 0x%08X "
++	       "mapped to 0x%08X, irq=%d\n", netdev->name, index,
++	       lp->save_base_address, config->base_address, netdev->irq);
++
++	return ret;
++
++out_unmap:
++	iounmap(config->base_address);
++
++out_unlock:
++	big_sur_ge_remove_head();
++
++out:
++	return ret;
++}
++
++static int __init big_sur_ge_init(void)
++{
++	int index = 0;
++
++	while (big_sur_ge_probe(index++) == 0);
++
++	return (index > 1) ? 0 : -ENODEV;
++}
++
++static void __exit big_sur_ge_cleanup(void)
++{
++	while (dev_list)
++		big_sur_ge_remove_head();
++}
++
++module_init(big_sur_ge_init);
++module_exit(big_sur_ge_cleanup);
++
++MODULE_AUTHOR("Manish Lachwani <lachwani at pmc-sierra.com>");
++MODULE_DESCRIPTION("PMC-Sierra Big Sur Ethernet MAC Driver");
++MODULE_LICENSE("GPL");
+diff -Naur linux-2.6.15.orig/drivers/net/big_sur_ge.h linux-2.6.15/drivers/net/big_sur_ge.h
+--- linux-2.6.15.orig/drivers/net/big_sur_ge.h	1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.15/drivers/net/big_sur_ge.h	2006-01-09 19:54:12.000000000 +0000
+@@ -0,0 +1,713 @@
++/*
++ * drivers/net/big_sur_ge.h - Driver for PMC-Sierra Big Sur
++ * ethernet ports
++ *
++ * Copyright (C) 2003 PMC-Sierra Inc.
++ * Author : Manish Lachwani (lachwani at pmc-sierra.com)
++ * Copyright (C) 2005 Ralf Baechle (ralf at linux-mips.org)
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * as published by the Free Software Foundation; either version 2
++ * of the License, or (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
++ *
++ */
++
++#ifndef	__BIG_SUR_GE_H__
++#define	__BIG_SUR_GE_H__
++
++#include <linux/version.h>
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/spinlock.h>
++#include <linux/types.h>
++
++#define	BIG_SUR_DEVICE_NAME	"big sur"
++#define	BIG_SUR_DEVICE_DESC	"Big Sur Ethernet 10/100 MAC"
++
++#define BIG_SUR_GE_BASE			0xbb000000
++
++#define	BIG_SUR_GE_WRITE(ofs,data)	*(volatile u32 *)(BIG_SUR_GE_BASE+(ofs)) = data
++
++#define	BIG_SUR_GE_READ(ofs)		*(volatile u32 *)(BIG_SUR_GE_BASE+(ofs))
++
++/* Manish : Need to fix these defines later */
++#define	BIG_SUR_GE_EMAC_0_HIGHADDR
++#define	BIG_SUR_GE_EMAC_0_BASEADDR
++#define	BIG_SUR_GE_INTC_0_EMAC_0_VEC_ID		1
++#define	BIG_SUR_GE_INTC_1_EMAC_1_VEC_ID		2
++#define	BIG_SUR_GE_INTC_2_EMAC_2_VEC_ID		3
++#define	BIG_SUR_GE_EMAC_0_ERR_COUNT_EXIST
++#define	BIG_SUR_GE_EMAC_0_DMA_PRESENT
++#define	BIG_SUR_GE_EMAC_0_MII_EXIST
++#define	BIG_SUR_GE_OPB_ETHERNET_0_BASEADDR
++#define	BIG_SUR_GE_EMAC_0_DEVICE_ID
++#define	BIG_SUR_GE_OPB_ETHERNET_0_ERR_COUNT_EXIST
++#define	BIG_SUR_GE_OPB_ETHERNET_0_DMA_PRESENT
++#define	BIG_SUR_GE_OPB_ETHERNET_0_MII_EXIST
++#define	BIG_SUR_GE_OPB_ETHERNET_0_DEVICE_ID
++
++#define	BIG_SUR_GE_FIFO_WIDTH_BYTE_COUNT	4UL
++/* IPIF specific defines */
++#define XIIF_V123B_DISR_OFFSET     0UL  /* device interrupt status register */
++#define XIIF_V123B_DIPR_OFFSET     4UL  /* device interrupt pending register */
++#define XIIF_V123B_DIER_OFFSET     8UL  /* device interrupt enable register */
++#define XIIF_V123B_DIIR_OFFSET     24UL /* device interrupt ID register */
++#define XIIF_V123B_DGIER_OFFSET    28UL /* device global interrupt enable reg */
++#define XIIF_V123B_IISR_OFFSET     32UL /* IP interrupt status register */
++#define XIIF_V123B_IIER_OFFSET     40UL /* IP interrupt enable register */
++#define XIIF_V123B_RESETR_OFFSET   64UL /* reset register */
++#define XIIF_V123B_RESET_MASK             0xAUL
++#define	XIIF_V123B_ERROR_MASK		0x1UL
++
++/* defines */
++#define BIG_SUR_GE_UNICAST_OPTION        	0x00000001
++#define BIG_SUR_GE_BROADCAST_OPTION      	0x00000002
++#define BIG_SUR_GE_PROMISC_OPTION        	0x00000004
++#define BIG_SUR_GE_FDUPLEX_OPTION        	0x00000008
++#define BIG_SUR_GE_POLLED_OPTION         	0x00000010
++#define BIG_SUR_GE_LOOPBACK_OPTION       	0x00000020
++#define BIG_SUR_GE_FLOW_CONTROL_OPTION   	0x00000080
++#define BIG_SUR_GE_INSERT_PAD_OPTION     	0x00000100
++#define BIG_SUR_GE_INSERT_FCS_OPTION     	0x00000200
++#define BIG_SUR_GE_INSERT_ADDR_OPTION    	0x00000400
++#define BIG_SUR_GE_OVWRT_ADDR_OPTION     	0x00000800
++#define BIG_SUR_GE_STRIP_PAD_FCS_OPTION  	0x00002000
++
++/* Not Supported */
++#define BIG_SUR_GE_MULTICAST_OPTION      	0x00000040
++#define BIG_SUR_GE_FLOW_CONTROL_OPTION   	0x00000080
++#define BIG_SUR_GE_INSERT_PAD_OPTION     	0x00000100
++#define BIG_SUR_GE_INSERT_FCS_OPTION     	0x00000200
++#define BIG_SUR_GE_INSERT_ADDR_OPTION    	0x00000400
++#define BIG_SUR_GE_OVWRT_ADDR_OPTION     	0x00000800
++#define BIG_SUR_GE_STRIP_PAD_OPTION      	0x00001000
++#define BIG_SUR_GE_STRIP_FCS_OPTION     	0x00002000
++
++
++/* Defaults for Interrupt Coalescing in the SG DMA Engine */
++#define BIG_SUR_GE_SGDMA_DFT_THRESHOLD     1   /* Default pkt threshold */
++#define BIG_SUR_GE_SGDMA_MAX_THRESHOLD     255 /* Maximum pkt theshold */
++#define BIG_SUR_GE_SGDMA_DFT_WAITBOUND     5   /* Default pkt wait bound (msec) */
++#define BIG_SUR_GE_SGDMA_MAX_WAITBOUND     1023        /* Maximum pkt wait bound (msec) */
++
++/* Direction */
++#define BIG_SUR_GE_SEND    1
++#define BIG_SUR_GE_RECV    2
++
++/* SG DMA */
++#define BIG_SUR_GE_SGDMA_NODELAY     0 /* start SG DMA immediately */
++#define BIG_SUR_GE_SGDMA_DELAY       1 /* do not start SG DMA */
++
++#define BIG_SUR_GE_CFG_NO_IPIF             0   /* Not supported by the driver */
++#define BIG_SUR_GE_CFG_NO_DMA              1   /* No DMA */
++#define BIG_SUR_GE_CFG_SIMPLE_DMA          2   /* Simple DMA */
++#define BIG_SUR_GE_CFG_DMA_SG              3   /* DMA scatter gather */
++
++#define BIG_SUR_GE_MAC_ADDR_SIZE   6   /* six-byte MAC address */
++#define BIG_SUR_GE_MTU             1500        /* max size of Ethernet frame */
++#define BIG_SUR_GE_HDR_SIZE        14  /* size of Ethernet header */
++#define BIG_SUR_GE_HDR_VLAN_SIZE   18  /* size of Ethernet header with VLAN */
++#define BIG_SUR_GE_TRL_SIZE        4   /* size of Ethernet trailer (FCS) */
++#define BIG_SUR_GE_MAX_FRAME_SIZE  \
++		(BIG_SUR_GE_MTU + BIG_SUR_GE_HDR_SIZE + BIG_SUR_GE_TRL_SIZE)
++
++#define BIG_SUR_GE_MAX_VLAN_FRAME_SIZE  \
++		(BIG_SUR_GE_MTU + BIG_SUR_GE_HDR_VLAN_SIZE + BIG_SUR_GE_TRL_SIZE)
++
++/* Send and Receive buffers */
++#define BIG_SUR_GE_MIN_RECV_BUFS   32  /* minimum # of recv buffers */
++#define BIG_SUR_GE_DFT_RECV_BUFS   64  /* default # of recv buffers */
++
++#define BIG_SUR_GE_MIN_SEND_BUFS   16  /* minimum # of send buffers */
++#define BIG_SUR_GE_DFT_SEND_BUFS   32  /* default # of send buffers */
++
++#define BIG_SUR_GE_MIN_BUFFERS     (BIG_SUR_GE_MIN_RECV_BUFS + BIG_SUR_GE_MIN_SEND_BUFS)
++#define BIG_SUR_GE_DFT_BUFFERS     (BIG_SUR_GE_DFT_RECV_BUFS + BIG_SUR_GE_DFT_SEND_BUFS)
++
++/* Send and Receive Descriptors */
++#define BIG_SUR_GE_MIN_RECV_DESC   16  /* minimum # of recv descriptors */
++#define BIG_SUR_GE_DFT_RECV_DESC   32  /* default # of recv descriptors */
++
++#define BIG_SUR_GE_MIN_SEND_DESC   8   /* minimum # of send descriptors */
++#define BIG_SUR_GE_DFT_SEND_DESC   16  /* default # of send descriptors */
++
++/* FIFO Specific Defines */
++#define BIG_SUR_GE_READ_FIFO_TYPE      0       /* a read FIFO */
++#define BIG_SUR_GE_WRITE_FIFO_TYPE     1       /* a write FIFO */
++#define BIG_SUR_GE_RESET_REG_OFFSET            0UL
++#define BIG_SUR_GE_MODULE_INFO_REG_OFFSET      0UL
++#define BIG_SUR_GE_COUNT_STATUS_REG_OFFSET     4UL
++#define BIG_SUR_GE_RESET_FIFO_MASK             0x0000000A
++#define BIG_SUR_GE_COUNT_MASK                  0x0000FFFF
++#define BIG_SUR_GE_DEADLOCK_MASK               0x20000000
++#define BIG_SUR_GE_ALMOST_EMPTY_FULL_MASK      0x40000000
++#define BIG_SUR_GE_EMPTY_FULL_MASK             0x80000000
++
++#define BIG_SUR_GE_FIFO_RESET(fifo)	\
++	BIG_SUR_GE_WRITE((fifo)->reg_base_addr + BIG_SUR_GE_RESET_REG_OFFSET, BIG_SUR_GE_RESET_FIFO_MASK)
++
++#define	BIG_SUR_GE_GET_COUNT(fifo)	\
++	(BIG_SUR_GE_READ((fifo)->reg_base_addr + BIG_SUR_GE_COUNT_STATUS_REG_OFFSET) & 	\
++							BIG_SUR_GE_COUNT_MASK)
++
++#define	BIG_SUR_GE_IS_ALMOST_EMPTY(fifo)	\
++		(BIG_SUR_GE_READ(fifo->reg_base_addr + BIG_SUR_GE_COUNT_STATUS_REG_OFFSET) &	\
++							BIG_SUR_GE_ALMOST_EMPTY_FULL_MASK)
++
++#define	BIG_SUR_GE_IS_ALMOST_FULL(fifo)  \
++		(BIG_SUR_GE_READ(fifo->reg_base_addr + BIG_SUR_GE_COUNT_STATUS_REG_OFFSET) &   \
++							BIG_SUR_GE_ALMOST_EMPTY_FULL_MASK)
++
++#define BIG_SUR_GE_IS_EMPTY(fifo)  \
++		(BIG_SUR_GE_READ(fifo->reg_base_addr + BIG_SUR_GE_COUNT_STATUS_REG_OFFSET) &   \
++							BIG_SUR_GE_EMPTY_FULL_MASK)
++
++#define BIG_SUR_GE_IS_FULL(fifo)  \
++	(BIG_SUR_GE_READ(fifo->reg_base_addr + BIG_SUR_GE_COUNT_STATUS_REG_OFFSET) &   \
++							BIG_SUR_GE_EMPTY_FULL_MASK)
++
++#define	BIG_SUR_GE_IS_DEADLOCKED(fifo)	\
++	(BIG_SUR_GE_READ((fifo)->reg_base_addr + BIG_SUR_GE_COUNT_STATUS_REG_OFFSET) &   \
++							BIG_SUR_GE_DEADLOCK_MASK)
++
++/* Device Config */
++typedef struct _big_sur_ge_config {
++	u16		device_id;
++	u32		base_address;
++	u32		has_counters;
++	u32		has_sg_dma;
++	u8		dma_config;
++	u32		has_mii;
++} big_sur_ge_config;
++
++#define BIG_SUR_GE_SIZE_IN_WORDS           10
++typedef unsigned long xbuf_descriptor[BIG_SUR_GE_SIZE_IN_WORDS];
++
++/* Callback Functions */
++typedef void (*big_sur_sg_handler) (void *callback, xbuf_descriptor *desc, u32 num_desc);
++typedef	void (*big_sur_fifo_handler) (void *callback);
++typedef void (*big_sur_irq_handler) (void *instance);
++
++typedef struct _xdma_channel_tag {
++	u32			reg_base_address;
++        u32                     base_address;
++        u32                     ready;
++        xbuf_descriptor         *put_ptr;
++        xbuf_descriptor         *get_ptr;
++        xbuf_descriptor         *commit_ptr;
++        xbuf_descriptor         *last_ptr;
++
++        u32                     total_desc_count;
++        u32                     active_desc_count;
++} xdma_channel;
++
++typedef struct _packet_fifo {
++        u32             reg_base_addr;
++        u32             ready_status;
++        u32             data_base_address;
++} packet_fifo;
++
++
++/* Big Sur GE driver structure */
++typedef struct _big_sur_ge {
++	u32		base_address;
++	u32		started;
++	u32		ready;
++	u32		polled;
++	u32		dma_sg;
++
++	u8		dma_config;
++	u32		has_mii;
++	u32		has_mcast_hash_table;
++
++	/* For the FIFO and simple DMA case only */
++	packet_fifo	recv_fifo;
++	packet_fifo	send_fifo;
++
++	big_sur_fifo_handler	big_sur_ge_fifo_recv_handler;
++	big_sur_fifo_handler	big_sur_ge_fifo_send_handler;
++
++	void	*fifo_send_ref;
++	void	*fifo_recv_ref;	
++
++	/* For SG DMA only */
++	xdma_channel	recv_channel;
++	xdma_channel	send_channel;
++} big_sur_ge;
++
++/* Offset of the MAC registers from the IPIF base address */
++#define BIG_SUR_GE_REG_OFFSET     0x1100UL
++
++/*
++ * Register offsets for the Ethernet MAC. Each register is 32 bits.
++ */
++#define BIG_SUR_GE_EMIR_OFFSET   (BIG_SUR_GE_REG_OFFSET + 0x0)        /* EMAC Module ID */
++#define BIG_SUR_GE_ECR_OFFSET    (BIG_SUR_GE_REG_OFFSET + 0x4)        /* MAC Control */
++#define BIG_SUR_GE_IFGP_OFFSET   (BIG_SUR_GE_REG_OFFSET + 0x8)        /* Interframe Gap */
++#define BIG_SUR_GE_SAH_OFFSET    (BIG_SUR_GE_REG_OFFSET + 0xC)        /* Station addr, high */
++#define BIG_SUR_GE_SAL_OFFSET    (BIG_SUR_GE_REG_OFFSET + 0x10)       /* Station addr, low */
++#define BIG_SUR_GE_MGTCR_OFFSET  (BIG_SUR_GE_REG_OFFSET + 0x14)       /* MII mgmt control */
++#define BIG_SUR_GE_MGTDR_OFFSET  (BIG_SUR_GE_REG_OFFSET + 0x18)       /* MII mgmt data */
++#define BIG_SUR_GE_RPLR_OFFSET   (BIG_SUR_GE_REG_OFFSET + 0x1C)       /* Rx packet length */
++#define BIG_SUR_GE_TPLR_OFFSET   (BIG_SUR_GE_REG_OFFSET + 0x20)       /* Tx packet length */
++#define BIG_SUR_GE_TSR_OFFSET    (BIG_SUR_GE_REG_OFFSET + 0x24)       /* Tx status */
++#define BIG_SUR_GE_RMFC_OFFSET   (BIG_SUR_GE_REG_OFFSET + 0x28)       /* Rx missed frames */
++#define BIG_SUR_GE_RCC_OFFSET    (BIG_SUR_GE_REG_OFFSET + 0x2C)       /* Rx collisions */
++#define BIG_SUR_GE_RFCSEC_OFFSET (BIG_SUR_GE_REG_OFFSET + 0x30)       /* Rx FCS errors */
++#define BIG_SUR_GE_RAEC_OFFSET   (BIG_SUR_GE_REG_OFFSET + 0x34)       /* Rx alignment errors */
++#define BIG_SUR_GE_TEDC_OFFSET   (BIG_SUR_GE_REG_OFFSET + 0x38)       /* Transmit excess
++                                                         * deferral cnt */
++/*
++ * Register offsets for the IPIF components
++ */
++#define BIG_SUR_GE_ISR_OFFSET           0x20UL /* Interrupt status */
++
++#define BIG_SUR_GE_DMA_OFFSET           0x2300UL
++#define BIG_SUR_GE_DMA_SEND_OFFSET      (BIG_SUR_GE_DMA_OFFSET + 0x0) /* DMA send channel */
++#define BIG_SUR_GE_DMA_RECV_OFFSET      (BIG_SUR_GE_DMA_OFFSET + 0x40)        /* DMA recv channel */
++
++#define BIG_SUR_GE_PFIFO_OFFSET         0x2000UL
++#define BIG_SUR_GE_PFIFO_TXREG_OFFSET   (BIG_SUR_GE_PFIFO_OFFSET + 0x0)       /* Tx registers */
++#define BIG_SUR_GE_PFIFO_RXREG_OFFSET   (BIG_SUR_GE_PFIFO_OFFSET + 0x10)      /* Rx registers */
++#define BIG_SUR_GE_PFIFO_TXDATA_OFFSET  (BIG_SUR_GE_PFIFO_OFFSET + 0x100)     /* Tx keyhole */
++#define BIG_SUR_GE_PFIFO_RXDATA_OFFSET  (BIG_SUR_GE_PFIFO_OFFSET + 0x200)     /* Rx keyhole */
++
++/*
++ * EMAC Module Identification Register (EMIR)
++ */
++#define BIG_SUR_GE_EMIR_VERSION_MASK    0xFFFF0000UL   /* Device version */
++#define BIG_SUR_GE_EMIR_TYPE_MASK       0x0000FF00UL   /* Device type */
++
++/*
++ * EMAC Control Register (ECR)
++ */
++#define BIG_SUR_GE_ECR_FULL_DUPLEX_MASK         0x80000000   /* Full duplex mode */
++#define BIG_SUR_GE_ECR_XMIT_RESET_MASK          0x40000000   /* Reset transmitter */
++#define BIG_SUR_GE_ECR_XMIT_ENABLE_MASK         0x20000000   /* Enable transmitter */
++#define BIG_SUR_GE_ECR_RECV_RESET_MASK          0x10000000   /* Reset receiver */
++#define BIG_SUR_GE_ECR_RECV_ENABLE_MASK         0x08000000   /* Enable receiver */
++#define BIG_SUR_GE_ECR_PHY_ENABLE_MASK          0x04000000   /* Enable PHY */
++#define BIG_SUR_GE_ECR_XMIT_PAD_ENABLE_MASK     0x02000000   /* Enable xmit pad insert */
++#define BIG_SUR_GE_ECR_XMIT_FCS_ENABLE_MASK     0x01000000   /* Enable xmit FCS insert */
++#define BIG_SUR_GE_ECR_XMIT_ADDR_INSERT_MASK    0x00800000   /* Enable xmit source addr insertion */
++#define BIG_SUR_GE_ECR_XMIT_ERROR_INSERT_MASK   0x00400000   /* Insert xmit error */
++#define BIG_SUR_GE_ECR_XMIT_ADDR_OVWRT_MASK     0x00200000   /* Enable xmit source addr overwrite */
++#define BIG_SUR_GE_ECR_LOOPBACK_MASK            0x00100000   /* Enable internal loopback */
++#define BIG_SUR_GE_ECR_RECV_PAD_ENABLE_MASK     0x00080000   /* Enable recv pad strip */
++#define BIG_SUR_GE_ECR_RECV_FCS_ENABLE_MASK     0x00040000   /* Enable recv FCS strip */
++#define BIG_SUR_GE_ECR_RECV_STRIP_ENABLE_MASK   0x00080000   /* Enable recv pad/fcs strip */
++#define BIG_SUR_GE_ECR_UNICAST_ENABLE_MASK      0x00020000   /* Enable unicast addr */
++#define BIG_SUR_GE_ECR_MULTI_ENABLE_MASK        0x00010000   /* Enable multicast addr */
++#define BIG_SUR_GE_ECR_BROAD_ENABLE_MASK        0x00008000   /* Enable broadcast addr */
++#define BIG_SUR_GE_ECR_PROMISC_ENABLE_MASK      0x00004000   /* Enable promiscuous mode */
++#define BIG_SUR_GE_ECR_RECV_ALL_MASK            0x00002000   /* Receive all frames */
++#define BIG_SUR_GE_ECR_RESERVED2_MASK           0x00001000   /* Reserved */
++#define BIG_SUR_GE_ECR_MULTI_HASH_ENABLE_MASK   0x00000800   /* Enable multicast hash */
++#define BIG_SUR_GE_ECR_PAUSE_FRAME_MASK         0x00000400   /* Interpret pause frames */
++#define BIG_SUR_GE_ECR_CLEAR_HASH_MASK          0x00000200   /* Clear hash table */
++#define BIG_SUR_GE_ECR_ADD_HASH_ADDR_MASK       0x00000100  /* Add hash table address */
++
++/*
++ * Interframe Gap Register (IFGR)
++ */
++#define BIG_SUR_GE_IFGP_PART1_MASK         0xF8000000        /* Interframe Gap Part1 */
++#define BIG_SUR_GE_IFGP_PART1_SHIFT        27
++#define BIG_SUR_GE_IFGP_PART2_MASK         0x07C00000        /* Interframe Gap Part2 */
++#define BIG_SUR_GE_IFGP_PART2_SHIFT        22
++
++/*
++ * Station Address High Register (SAH)
++ */
++#define BIG_SUR_GE_SAH_ADDR_MASK           0x0000FFFF        /* Station address high bytes */
++
++/*
++ * Station Address Low Register (SAL)
++ */
++#define BIG_SUR_GE_SAL_ADDR_MASK           0xFFFFFFFF        /* Station address low bytes */
++
++/*
++ * MII Management Control Register (MGTCR)
++ */
++#define BIG_SUR_GE_MGTCR_START_MASK        0x80000000        /* Start/Busy */
++#define BIG_SUR_GE_MGTCR_RW_NOT_MASK       0x40000000        /* Read/Write Not (direction) */
++#define BIG_SUR_GE_MGTCR_PHY_ADDR_MASK     0x3E000000        /* PHY address */
++#define BIG_SUR_GE_MGTCR_PHY_ADDR_SHIFT    25  /* PHY address shift */
++#define BIG_SUR_GE_MGTCR_REG_ADDR_MASK     0x01F00000        /* Register address */
++#define BIG_SUR_GE_MGTCR_REG_ADDR_SHIFT    20  /* Register addr shift */
++#define BIG_SUR_GE_MGTCR_MII_ENABLE_MASK   0x00080000        /* Enable MII from EMAC */
++#define BIG_SUR_GE_MGTCR_RD_ERROR_MASK     0x00040000        /* MII mgmt read error */
++
++/*
++ * MII Management Data Register (MGTDR)
++ */
++#define BIG_SUR_GE_MGTDR_DATA_MASK         0x0000FFFF        /* MII data */
++
++/*
++ * Receive Packet Length Register (RPLR)
++ */
++#define BIG_SUR_GE_RPLR_LENGTH_MASK        0x0000FFFF        /* Receive packet length */
++
++/*
++ * Transmit Packet Length Register (TPLR)
++ */
++#define BIG_SUR_GE_TPLR_LENGTH_MASK        0x0000FFFF       /* Transmit packet length */
++
++/*
++ * Transmit Status Register (TSR)
++ */
++#define BIG_SUR_GE_TSR_EXCESS_DEFERRAL_MASK 0x80000000       /* Transmit excess deferral */
++#define BIG_SUR_GE_TSR_FIFO_UNDERRUN_MASK   0x40000000       /* Packet FIFO underrun */
++#define BIG_SUR_GE_TSR_ATTEMPTS_MASK        0x3E000000      /* Transmission attempts */
++#define BIG_SUR_GE_TSR_LATE_COLLISION_MASK  0x01000000      /* Transmit late collision */
++
++/*
++ * Receive Missed Frame Count (RMFC)
++ */
++#define BIG_SUR_GE_RMFC_DATA_MASK          0x0000FFFF
++
++/*
++ * Receive Collision Count (RCC)
++ */
++#define BIG_SUR_GE_RCC_DATA_MASK           0x0000FFFF
++/*
++ * Receive FCS Error Count (RFCSEC)
++ */
++#define BIG_SUR_GE_RFCSEC_DATA_MASK        0x0000FFFF
++
++/*
++ * Receive Alignment Error Count (RALN)
++ */
++#define BIG_SUR_GE_RAEC_DATA_MASK          0x0000FFFF
++
++/*
++ * Transmit Excess Deferral Count (TEDC)
++ */
++#define BIG_SUR_GE_TEDC_DATA_MASK          0x0000FFFF
++
++/*
++ * EMAC Interrupt Registers (Status and Enable) masks. These registers are
++ * part of the IPIF IP Interrupt registers
++ */
++#define BIG_SUR_GE_EIR_XMIT_DONE_MASK         0x00000001     /* Xmit complete */
++#define BIG_SUR_GE_EIR_RECV_DONE_MASK         0x00000002     /* Recv complete */
++#define BIG_SUR_GE_EIR_XMIT_ERROR_MASK        0x00000004     /* Xmit error */
++#define BIG_SUR_GE_EIR_RECV_ERROR_MASK        0x00000008     /* Recv error */
++#define BIG_SUR_GE_EIR_XMIT_SFIFO_EMPTY_MASK  0x00000010     /* Xmit status fifo empty */
++#define BIG_SUR_GE_EIR_RECV_LFIFO_EMPTY_MASK  0x00000020     /* Recv length fifo empty */
++#define BIG_SUR_GE_EIR_XMIT_LFIFO_FULL_MASK   0x00000040     /* Xmit length fifo full */
++#define BIG_SUR_GE_EIR_RECV_LFIFO_OVER_MASK   0x00000080     /* Recv length fifo overrun */
++#define BIG_SUR_GE_EIR_RECV_LFIFO_UNDER_MASK  0x00000100     /* Recv length fifo underrun */
++#define BIG_SUR_GE_EIR_XMIT_SFIFO_OVER_MASK   0x00000200     /* Xmit status fifo overrun */
++#define BIG_SUR_GE_EIR_XMIT_SFIFO_UNDER_MASK  0x00000400     /* Transmit status fifo underrun */
++#define BIG_SUR_GE_EIR_XMIT_LFIFO_OVER_MASK   0x00000800     /* Transmit length fifo overrun */
++#define BIG_SUR_GE_EIR_XMIT_LFIFO_UNDER_MASK  0x00001000     /* Transmit length fifo underrun */
++#define BIG_SUR_GE_EIR_XMIT_PAUSE_MASK        0x00002000     /* Transmit pause pkt received */
++#define BIG_SUR_GE_EIR_RECV_DFIFO_OVER_MASK   0x00004000     /* Receive data fifo overrun */
++#define BIG_SUR_GE_EIR_RECV_MISSED_FRAME_MASK 0x00008000     /* Receive missed frame error */
++#define BIG_SUR_GE_EIR_RECV_COLLISION_MASK    0x00010000     /* Receive collision error */
++#define BIG_SUR_GE_EIR_RECV_FCS_ERROR_MASK    0x00020000     /* Receive FCS error */
++#define BIG_SUR_GE_EIR_RECV_LEN_ERROR_MASK    0x00040000     /* Receive length field error */
++#define BIG_SUR_GE_EIR_RECV_SHORT_ERROR_MASK  0x00080000     /* Receive short frame error */
++#define BIG_SUR_GE_EIR_RECV_LONG_ERROR_MASK   0x00100000     /* Receive long frame error */
++#define BIG_SUR_GE_EIR_RECV_ALIGN_ERROR_MASK  0x00200000     /* Receive alignment error */
++
++#define	BIG_SUR_GE_READ_REG(base_addr, reg_offset)	\
++		BIG_SUR_GE_READ(base_addr + reg_offset)
++
++#define	BIG_SUR_GE_WRITE_REG(base_addr, reg_offset, data)	\
++		 BIG_SUR_GE_WRITE(base_addr + reg_offset, data)
++
++#define BIG_SUR_GE_CONTROL_REG(base_addr, mask)		\
++		BIG_SUR_GE_WRITE(base_addr + BIG_SUR_GE_ECR_OFFSET, mask)
++
++/* Set the MAC Address */
++#define	big_sur_ge_set_mac(base_addr, address)					\
++{										\
++	u32	mac_addr;							\
++										\
++	mac_addr = ((address[0] << 8) | (address[1]);				\
++	BIG_SUR_GE_WRITE(base_address + BIG_SUR_GE_SAH_OFFSET, mac_address);		\
++										\
++	mac_addr = ((address[2] << 24) | (address[3] << 16) |			\
++			(address[4] << 8) | address[5]);			\
++										\
++	BIG_SUR_GE_WRITE(base_address + BIG_SUR_GE_SAL_OFFSET, mac_address);		\
++										\
++}										
++
++/* Enable the MAC unit */
++#define	big_sur_ge_mac_enable(base_address)					\
++{										\
++	u32	control;							\
++	control = BIG_SUR_GE_READ(base_address + BIG_SUR_GE_ECR_OFFSET);		\
++	control &= ~(BIG_SUR_GE_ECR_XMIT_RESET_MASK | BIG_SUR_GE_ECR_RECV_RESET_MASK);	\
++	control |= (BIG_SUR_GE_ECR_XMIT_ENABLE_MASK | BIG_SUR_GE_ECR_RECV_ENABLE_MASK);	\
++	BIG_SUR_GE_WRITE(base_address + BIG_SUR_GE_ECR_OFFSET, control);		\
++}
++
++/* Disable the MAC unit */
++#define	big_sur_ge_mac_disable(base_address)					\
++{										\
++	u32	control;							\
++	control = BIG_SUR_GE_READ(base_address + BIG_SUR_GE_ECR_OFFSET);		\
++	control &= ~(BIG_SUR_GE_ECR_XMIT_ENABLE_MASK | BIG_SUR_GE_ECR_RECV_ENABLE_MASK);	\
++	BIG_SUR_GE_WRITE(base_address + BIG_SUR_GE_ECR_OFFSET, control);		\
++}
++
++/* Check if the Tx is done */
++#define	big_sur_ge_tx_done(base_address)						\
++	(BIG_SUR_GE_READ(base_address + BIG_SUR_GE_ISR_OFFSET) & BIG_SUR_GE_EIR_XMIT_DONE_MASK)
++
++
++/* Check if Rx FIFO is empty */
++#define	big_sur_ge_rx_empty(base_address)						\
++	(!(BIG_SUR_GE_READ(base_address + BIG_SUR_GE_ISR_OFFSET) & BIG_SUR_GE_EIR_RECV_DONE_MASK))
++
++/* Reset the MAC PHY */
++#define	big_sur_ge_reset_phy(base_address)						\
++{											\
++	u32	control;								\
++	control = BIG_SUR_GE_READ(base_address + BIG_SUR_GE_ECR_OFFSET);			\
++	control &= ~(BIG_SUR_GE_ECR_PHY_ENABLE_MASK);						\
++	BIG_SUR_GE_WRITE(base_address + BIG_SUR_GE_ECR_OFFSET, control);			\
++	control |= BIG_SUR_GE_ECR_PHY_ENABLE_MASK;						\
++	BIG_SUR_GE_WRITE(base_address + BIG_SUR_GE_ECR_OFFSET, control);			\
++}
++
++/* DMA SG defines */
++#define BIG_SUR_GE_CONTROL_LAST_BD_MASK        0x02000000
++#define BIG_SUR_GE_STATUS_LAST_BD_MASK         0x10000000
++#define BIG_SUR_GE_RST_REG_OFFSET      0       /* reset register */
++#define BIG_SUR_GE_MI_REG_OFFSET       0       /* module information register */
++#define BIG_SUR_GE_DMAC_REG_OFFSET     4       /* DMA control register */
++#define BIG_SUR_GE_SA_REG_OFFSET       8       /* source address register */
++#define BIG_SUR_GE_DA_REG_OFFSET       12      /* destination address register */
++#define BIG_SUR_GE_LEN_REG_OFFSET      16      /* length register */
++#define BIG_SUR_GE_DMAS_REG_OFFSET     20      /* DMA status register */
++#define BIG_SUR_GE_BDA_REG_OFFSET      24      /* buffer descriptor address register */
++#define BIG_SUR_GE_SWCR_REG_OFFSET 28  /* software control register */
++#define BIG_SUR_GE_UPC_REG_OFFSET      32      /* unserviced packet count register */
++#define BIG_SUR_GE_PCT_REG_OFFSET      36      /* packet count threshold register */
++#define BIG_SUR_GE_PWB_REG_OFFSET      40      /* packet wait bound register */
++#define BIG_SUR_GE_IS_REG_OFFSET       44      /* interrupt status register */
++#define BIG_SUR_GE_IE_REG_OFFSET       48      /* interrupt enable register */
++
++#define BIG_SUR_GE_RESET_MASK                          0x0000000A
++
++/* Buffer Descriptor Control */
++
++#define BIG_SUR_GE_DEVICE_STATUS_OFFSET    0
++#define BIG_SUR_GE_CONTROL_OFFSET          1
++#define BIG_SUR_GE_SOURCE_OFFSET           2
++#define BIG_SUR_GE_DESTINATION_OFFSET      3
++#define BIG_SUR_GE_LENGTH_OFFSET           4
++#define BIG_SUR_GE_STATUS_OFFSET           5
++#define BIG_SUR_GE_NEXT_PTR_OFFSET         6
++#define BIG_SUR_GE_ID_OFFSET               7
++#define BIG_SUR_GE_FLAGS_OFFSET            8
++#define BIG_SUR_GE_RQSTED_LENGTH_OFFSET    9
++
++#define BIG_SUR_GE_FLAGS_LOCKED_MASK       1
++
++#define	xbuf_descriptor_init(base)				\
++{								\
++	(*((u32 *)base + BIG_SUR_GE_CONTROL_OFFSET) = 0);		\
++	(*((u32 *)base + BIG_SUR_GE_SOURCE_OFFSET) = 0);        \
++    	(*((u32 *)base + BIG_SUR_GE_DESTINATION_OFFSET) = 0);   \
++    	(*((u32 *)base + BIG_SUR_GE_LENGTH_OFFSET) = 0);        \
++    	(*((u32 *)base + BIG_SUR_GE_STATUS_OFFSET) = 0);        \
++    	(*((u32 *)base + BIG_SUR_GE_DEVICE_STATUS_OFFSET) = 0); \
++    	(*((u32 *)base + BIG_SUR_GE_NEXT_PTR_OFFSET) = 0);      \
++    	(*((u32 *)base + BIG_SUR_GE_ID_OFFSET) = 0);            \
++    	(*((u32 *)base + BIG_SUR_GE_FLAGS_OFFSET) = 0);         \
++    	(*((u32 *)base + BIG_SUR_GE_RQSTED_LENGTH_OFFSET) = 0); \
++}
++
++#define xbuf_descriptor_GetControl(base)   \
++    (u32)(*((u32 *)base + BIG_SUR_GE_CONTROL_OFFSET))
++
++#define xbuf_descriptor_SetControl(base, Control)  \
++    (*((u32 *)base + BIG_SUR_GE_CONTROL_OFFSET) = (u32)Control)
++
++#define xbuf_descriptor_IsLastControl(base) \
++    (u32)(*((u32 *)base + BIG_SUR_GE_CONTROL_OFFSET) & \
++               BIG_SUR_GE_CONTROL_LAST_BD_MASK)
++
++#define xbuf_descriptor_SetLast(base) \
++    (*((u32 *)base + BIG_SUR_GE_CONTROL_OFFSET) |= BIG_SUR_GECONTROL_LAST_BD_MASK)
++
++#define xbuf_descriptor_GetSrcAddress(base) \
++    ((u32 *)(*((u32 *)base + BIG_SUR_GE_SOURCE_OFFSET)))
++
++#define xbuf_descriptor_SetSrcAddress(base, Source) \
++    (*((u32 *)base + BIG_SUR_GE_SOURCE_OFFSET) = (u32)Source)
++
++#define xbuf_descriptor_GetDestAddress(base) \
++    ((u32 *)(*((u32 *)base + BIG_SUR_GE_DESTINATION_OFFSET)))
++
++#define xbuf_descriptor_SetDestAddress(base, Destination) \
++    (*((u32 *)base + BIG_SUR_GE_DESTINATION_OFFSET) = (u32)Destination)
++
++#define xbuf_descriptor_GetLength(base)                           \
++    (u32)(*((u32 *)base + BIG_SUR_GE_RQSTED_LENGTH_OFFSET) -    \
++              *((u32 *)base + BIG_SUR_GE_LENGTH_OFFSET))
++
++#define xbuf_descriptor_SetLength(base, Length)                       \
++{                                                                           \
++    (*((u32 *)base + BIG_SUR_GE_LENGTH_OFFSET) = (u32)(Length));    \
++    (*((u32 *)base + BIG_SUR_GE_RQSTED_LENGTH_OFFSET) = (u32)(Length));\
++}
++
++#define xbuf_descriptor_GetStatus(base)    \
++    (u32)(*((u32 *)base + BIG_SUR_GE_STATUS_OFFSET))
++
++#define xbuf_descriptor_SetStatus(base, Status)    \
++    (*((u32 *)base + BIG_SUR_GE_STATUS_OFFSET) = (u32)Status)
++
++#define xbuf_descriptor_IsLastStatus(base) \
++    (u32)(*((u32 *)base + BIG_SUR_GE_STATUS_OFFSET) & \
++               BIG_SUR_GE_STATUS_LAST_BD_MASK)
++
++#define xbuf_descriptor_GetDeviceStatus(base) \
++    ((u32)(*((u32 *)base + BIG_SUR_GE_DEVICE_STATUS_OFFSET)))
++
++#define xbuf_descriptor_SetDeviceStatus(base, Status) \
++    (*((u32 *)base + BIG_SUR_GE_DEVICE_STATUS_OFFSET) = (u32)Status)
++
++#define xbuf_descriptor_GetNextPtr(base) \
++    (xbuf_descriptor *)(*((u32 *)base + BIG_SUR_GE_NEXT_PTR_OFFSET))
++
++#define xbuf_descriptor_SetNextPtr(base, NextPtr) \
++    (*((u32 *)base + BIG_SUR_GE_NEXT_PTR_OFFSET) = (u32)NextPtr)
++
++#define xbuf_descriptor_GetId(base) \
++    (u32)(*((u32 *)base + BIG_SUR_GE_ID_OFFSET))
++
++#define xbuf_descriptor_SetId(base, Id) \
++    (*((u32 *)base + BIG_SUR_GE_ID_OFFSET) = (u32)Id)
++
++#define xbuf_descriptor_GetFlags(base) \
++    (u32)(*((u32 *)base + BIG_SUR_GE_FLAGS_OFFSET))
++
++#define xbuf_descriptor_SetFlags(base, Flags) \
++    (*((u32 *)base + BIG_SUR_GE_FLAGS_OFFSET) = (u32)Flags)
++
++#define xbuf_descriptor_Lock(base) \
++    (*((u32 *)base + BIG_SUR_GE_FLAGS_OFFSET) |= BIG_SUR_GE_FLAGS_LOCKED_MASK)
++
++#define xbuf_descriptor_Unlock(base) \
++    (*((u32 *)base + BIG_SUR_GE_FLAGS_OFFSET) &= ~BIG_SUR_GE_FLAGS_LOCKED_MASK)
++
++#define xbuf_descriptor_IsLocked(base) \
++	(*((u32 *)base + BIG_SUR_GE_FLAGS_OFFSET) & BIG_SUR_GE_FLAGS_LOCKED_MASK)
++
++#define BIG_SUR_GE_DMACR_SOURCE_INCR_MASK      0x80000000UL    /* increment source address */
++#define BIG_SUR_GE_DMACR_DEST_INCR_MASK        0x40000000UL    /* increment dest address */
++#define BIG_SUR_GE_DMACR_SOURCE_LOCAL_MASK 0x20000000UL        /* local source address */
++#define BIG_SUR_GE_DMACR_DEST_LOCAL_MASK       0x10000000UL    /* local dest address */
++#define BIG_SUR_GE_DMACR_SG_DISABLE_MASK       0x08000000UL    /* scatter gather disable */
++#define BIG_SUR_GE_DMACR_GEN_BD_INTR_MASK      0x04000000UL    /* descriptor interrupt */
++#define BIG_SUR_GE_DMACR_LAST_BD_MASK          BIG_SUR_GE_CONTROL_LAST_BD_MASK        /* last buffer */
++#define BIG_SUR_GE_DMASR_BUSY_MASK                     0x80000000UL    /* channel is busy */
++#define BIG_SUR_GE_DMASR_BUS_ERROR_MASK        0x40000000UL    /* bus error occurred */
++#define BIG_SUR_GE_DMASR_BUS_TIMEOUT_MASK      0x20000000UL    /* bus timeout occurred */
++#define BIG_SUR_GE_DMASR_LAST_BD_MASK          BIG_SUR_GE_STATUS_LAST_BD_MASK /* last buffer */
++#define BIG_SUR_GE_DMASR_SG_BUSY_MASK          0x08000000UL    /* scatter gather is busy */
++#define BIG_SUR_GE_IXR_DMA_DONE_MASK           0x1UL   /* dma operation done */
++#define BIG_SUR_GE_IXR_DMA_ERROR_MASK      0x2UL       /* dma operation error */
++#define BIG_SUR_GE_IXR_PKT_DONE_MASK       0x4UL       /* packet done */
++#define BIG_SUR_GE_IXR_PKT_THRESHOLD_MASK      0x8UL   /* packet count threshold */
++#define BIG_SUR_GE_IXR_PKT_WAIT_BOUND_MASK 0x10UL      /* packet wait bound reached */
++#define BIG_SUR_GE_IXR_SG_DISABLE_ACK_MASK 0x20UL      /* scatter gather disable
++                                                   acknowledge occurred */
++#define BIG_SUR_GEIXR_SG_END_MASK                     0x40UL  /* last buffer descriptor
++                                                           disabled scatter gather */
++#define BIG_SUR_GEIXR_BD_MASK                         0x80UL  /* buffer descriptor done */
++
++/* BD control */
++#define BIG_SUR_GE_DFT_SEND_BD_MASK    (BIG_SUR_GEDMACR_SOURCE_INCR_MASK | \
++                                 BIG_SUR_GEDMACR_DEST_LOCAL_MASK)
++#define BIG_SUR_GE_DFT_RECV_BD_MASK    (BIG_SUR_GEDMACR_DEST_INCR_MASK |  \
++                                 BIG_SUR_GEDMACR_SOURCE_LOCAL_MASK)
++
++/* Interrupts */
++#define BIG_SUR_GE_IPIF_EMAC_MASK      0x00000004UL    /* MAC interrupt */
++#define BIG_SUR_GE_IPIF_SEND_DMA_MASK  0x00000008UL    /* Send DMA interrupt */
++#define BIG_SUR_GE_IPIF_RECV_DMA_MASK  0x00000010UL    /* Receive DMA interrupt */
++#define BIG_SUR_GE_IPIF_RECV_FIFO_MASK 0x00000020UL    /* Receive FIFO interrupt */
++#define BIG_SUR_GE_IPIF_SEND_FIFO_MASK 0x00000040UL    /* Send FIFO interrupt */
++
++#define BIG_SUR_GE_IPIF_DMA_DFT_MASK   (BIG_SUR_GE_IPIF_SEND_DMA_MASK |   \
++                                 BIG_SUR_GE_IPIF_RECV_DMA_MASK |   \
++                                 BIG_SUR_GE_IPIF_EMAC_MASK |       \
++                                 BIG_SUR_GE_IPIF_SEND_FIFO_MASK |  \
++                                 BIG_SUR_GE_IPIF_RECV_FIFO_MASK)
++
++#define BIG_SUR_GE_IPIF_FIFO_DFT_MASK  (BIG_SUR_GE_IPIF_EMAC_MASK |       \
++                                 BIG_SUR_GE_IPIF_SEND_FIFO_MASK |  \
++                                 BIG_SUR_GE_IPIF_RECV_FIFO_MASK)
++
++#define BIG_SUR_GE_IPIF_DMA_DEV_INTR_COUNT   7 /* Number of interrupt sources */
++#define BIG_SUR_GE_IPIF_FIFO_DEV_INTR_COUNT  5 /* Number of interrupt sources */
++#define BIG_SUR_GE_IPIF_DEVICE_INTR_COUNT  7   /* Number of interrupt sources */
++#define BIG_SUR_GE_IPIF_IP_INTR_COUNT      22  /* Number of MAC interrupts */
++
++/* a mask for all transmit interrupts, used in polled mode */
++#define BIG_SUR_GE_EIR_XMIT_ALL_MASK   (BIG_SUR_GE_EIR_XMIT_DONE_MASK |           \
++                                 BIG_SUR_GE_EIR_XMIT_ERROR_MASK |          \
++                                 BIG_SUR_GE_EIR_XMIT_SFIFO_EMPTY_MASK |    \
++                                 BIG_SUR_GE_EIR_XMIT_LFIFO_FULL_MASK)
++
++/* a mask for all receive interrupts, used in polled mode */
++#define BIG_SUR_GE_EIR_RECV_ALL_MASK   (BIG_SUR_GE_EIR_RECV_DONE_MASK |           \
++                                 BIG_SUR_GE_EIR_RECV_ERROR_MASK |          \
++                                 BIG_SUR_GE_EIR_RECV_LFIFO_EMPTY_MASK |    \
++                                 BIG_SUR_GE_EIR_RECV_LFIFO_OVER_MASK |     \
++                                 BIG_SUR_GE_EIR_RECV_LFIFO_UNDER_MASK |    \
++                                 BIG_SUR_GE_EIR_RECV_DFIFO_OVER_MASK |     \
++                                 BIG_SUR_GE_EIR_RECV_MISSED_FRAME_MASK |   \
++                                 BIG_SUR_GE_EIR_RECV_COLLISION_MASK |      \
++                                 BIG_SUR_GE_EIR_RECV_FCS_ERROR_MASK |      \
++                                 BIG_SUR_GE_EIR_RECV_LEN_ERROR_MASK |      \
++                                 BIG_SUR_GE_EIR_RECV_SHORT_ERROR_MASK |    \
++                                 BIG_SUR_GE_EIR_RECV_LONG_ERROR_MASK |     \
++                                 BIG_SUR_GE_EIR_RECV_ALIGN_ERROR_MASK)
++
++/* a default interrupt mask for scatter-gather DMA operation */
++#define BIG_SUR_GE_EIR_DFT_SG_MASK    (BIG_SUR_GE_EIR_RECV_ERROR_MASK |           \
++                                BIG_SUR_GE_EIR_RECV_LFIFO_OVER_MASK |      \
++                                BIG_SUR_GE_EIR_RECV_LFIFO_UNDER_MASK |     \
++                                BIG_SUR_GE_EIR_XMIT_SFIFO_OVER_MASK |      \
++                                BIG_SUR_GE_EIR_XMIT_SFIFO_UNDER_MASK |     \
++                                BIG_SUR_GE_EIR_XMIT_LFIFO_OVER_MASK |      \
++                                BIG_SUR_GE_EIR_XMIT_LFIFO_UNDER_MASK |     \
++                                BIG_SUR_GE_EIR_RECV_DFIFO_OVER_MASK |      \
++                                BIG_SUR_GE_EIR_RECV_MISSED_FRAME_MASK |    \
++                                BIG_SUR_GE_EIR_RECV_COLLISION_MASK |       \
++                                BIG_SUR_GE_EIR_RECV_FCS_ERROR_MASK |       \
++                                BIG_SUR_GE_EIR_RECV_LEN_ERROR_MASK |       \
++                                BIG_SUR_GE_EIR_RECV_SHORT_ERROR_MASK |     \
++                                BIG_SUR_GE_EIR_RECV_LONG_ERROR_MASK |      \
++                                BIG_SUR_GE_EIR_RECV_ALIGN_ERROR_MASK)
++
++/* a default interrupt mask for non-DMA operation (direct FIFOs) */
++#define BIG_SUR_GE_EIR_DFT_FIFO_MASK  (BIG_SUR_GE_EIR_XMIT_DONE_MASK |            \
++                                BIG_SUR_GE_EIR_RECV_DONE_MASK |            \
++                                BIG_SUR_GE_EIR_DFT_SG_MASK)
++
++#define BIG_SUR_GE_DMA_SG_INTR_MASK    (BIG_SUR_GEIXR_DMA_ERROR_MASK  |      \
++                                 BIG_SUR_GEIXR_PKT_THRESHOLD_MASK |   \
++                                 BIG_SUR_GEIXR_PKT_WAIT_BOUND_MASK |  \
++                                 BIG_SUR_GEIXR_SG_END_MASK)
++
++#endif
+diff -Naur linux-2.6.15.orig/drivers/net/declance.c linux-2.6.15/drivers/net/declance.c
+--- linux-2.6.15.orig/drivers/net/declance.c	2006-01-03 03:21:10.000000000 +0000
++++ linux-2.6.15/drivers/net/declance.c	2006-01-09 19:54:12.000000000 +0000
+@@ -704,8 +704,8 @@
+ 	return IRQ_HANDLED;
+ }
+ 
+-static irqreturn_t
+-lance_interrupt(const int irq, void *dev_id, struct pt_regs *regs)
++static irqreturn_t lance_interrupt(const int irq, void *dev_id,
++				   struct pt_regs *regs)
+ {
+ 	struct net_device *dev = (struct net_device *) dev_id;
+ 	struct lance_private *lp = netdev_priv(dev);
+@@ -1255,7 +1255,7 @@
+ 	return 0;
+ 
+ err_out_free_dev:
+-	kfree(dev);
++	free_netdev(dev);
+ 
+ err_out:
+ 	return ret;
+@@ -1301,6 +1301,7 @@
+ 	while (root_lance_dev) {
+ 		struct net_device *dev = root_lance_dev;
+ 		struct lance_private *lp = netdev_priv(dev);
++
+ 		unregister_netdev(dev);
+ #ifdef CONFIG_TC
+ 		if (lp->slot >= 0)
+diff -Naur linux-2.6.15.orig/drivers/net/gt64240eth.c linux-2.6.15/drivers/net/gt64240eth.c
+--- linux-2.6.15.orig/drivers/net/gt64240eth.c	1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.15/drivers/net/gt64240eth.c	2006-01-09 19:54:12.000000000 +0000
+@@ -0,0 +1,1672 @@
++/*
++ * This file is subject to the terms and conditions of the GNU General Public
++ * License.  See the file "COPYING" in the main directory of this archive
++ * for more details.
++ *
++ * Copyright (C) 2001 Patton Electronics Company
++ * Copyright (C) 2002 Momentum Computer
++ *
++ * Copyright 2000 MontaVista Software Inc.
++ * Author: MontaVista Software, Inc.
++ *         	stevel at mvista.com or support at mvista.com
++ *
++ *  This program is free software; you can distribute it and/or modify it
++ *  under the terms of the GNU General Public License (Version 2) as
++ *  published by the Free Software Foundation.
++ *
++ *  This program is distributed in the hope it will be useful, but WITHOUT
++ *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ *  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
++ *  for more details.
++ *
++ *  You should have received a copy of the GNU General Public License along
++ *  with this program; if not, write to the Free Software Foundation, Inc.,
++ *  59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
++ *
++ * Ethernet driver for the MIPS GT96100 Advanced Communication Controller.
++ * 
++ * Modified for the Gallileo/Marvell GT-64240 Communication Controller.
++ *
++ * Support for Rx NAPI, Rx checksum offload, IOCTL and ETHTOOL added
++ * Manish Lachwani (lachwani at pmc-sierra.com) - 09/16/2003
++ *
++ * Modified for later version of Linux 2.4 kernel
++ * Manish Lachwani (lachwani at pmc-sierra.com) - 04/29/2004
++ */
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/sched.h>
++#include <linux/string.h>
++#include <linux/timer.h>
++#include <linux/errno.h>
++#include <linux/in.h>
++#include <linux/ioport.h>
++#include <linux/slab.h>
++#include <linux/interrupt.h>
++#include <linux/pci.h>
++#include <linux/init.h>
++#include <linux/netdevice.h>
++#include <linux/etherdevice.h>
++#include <linux/ethtool.h>
++#include <linux/skbuff.h>
++#include <linux/delay.h>
++#include <linux/ctype.h>
++#include <linux/mii.h>
++
++#include <asm/irq.h>
++#include <asm/bitops.h>
++#include <asm/io.h>
++#include <asm/uaccess.h>
++
++#define DESC_DATA_BE 1
++
++#include "gt64240eth.h"
++
++// enable this port (set hash size to 1/2K)
++//- #define PORT_CONFIG pcrHS
++#define PORT_CONFIG (pcrHS | pcrHD)
++//- #define PORT_CONFIG pcrHS |pcrPM |pcrPBF|pcrHDM
++//- GT64240ETH_WRITE(gp, GT64240_ETH_PORT_CONFIG, pcrEN | pcrHS);
++//- GT64240ETH_WRITE(gp, GT64240_ETH_PORT_CONFIG, pcrEN | pcrHS | pcrPM);
++//- GT64240ETH_WRITE(gp, GT64240_ETH_PORT_CONFIG, pcrEN | pcrHS | pcrPM | 1<<pcrLPBKBit);
++
++// clear all the MIB ctr regs
++#define EXT_CONFIG_CLEAR (pcxrFCTL | pcxrFCTLen | pcxrFLP | pcxrDPLXen | pcxrPRIOrxOverride | pcxrRMIIen)
++
++/*
++ * _debug level:
++ * <= 2	none.
++ *  > 2	some warnings such as queue full, .....
++ *  > 3	lots of change-of-state messages.
++ *  > 4	EXTENSIVE data/descriptor dumps.
++ */
++
++#ifdef GT64240_DEBUG
++static int gt64240_debug = GT64240_DEBUG;
++#else
++static int gt64240_debug = 0;
++#endif
++
++static int debug = -1;
++
++#define GT64240_MSG_ENABLE	(NETIF_MSG_DRV          | \
++				NETIF_MSG_PROBE        | \
++				NETIF_MSG_LINK)
++
++
++/********************************************************/
++
++// prototypes
++static void gt64240_delay(int msec);
++static int gt64240_add_hash_entry(struct net_device *dev,
++				  unsigned char *addr);
++static void read_mib_counters(struct gt64240_private *gp);
++static void dump_MII(struct net_device *dev);
++static void dump_tx_desc(struct net_device *dev, int i);
++static void dump_rx_desc(struct net_device *dev, int i);
++static void dump_hw_addr(unsigned char *addr_str);
++static void update_stats(struct gt64240_private *gp);
++static void abort(struct net_device *dev, u32 abort_bits);
++static void hard_stop(struct net_device *dev);
++static void enable_ether_irq(struct net_device *dev);
++static void disable_ether_irq(struct net_device *dev);
++static int __init gt64240_probe1(unsigned long ioaddr, int irq, int port_num);
++static void reset_tx(struct net_device *dev);
++static void reset_rx(struct net_device *dev);
++static int gt64240_init(struct net_device *dev);
++static int gt64240_open(struct net_device *dev);
++static int gt64240_close(struct net_device *dev);
++static int gt64240_tx(struct sk_buff *skb, struct net_device *dev);
++#ifdef GT64240_NAPI
++static int gt64240_poll(struct net_device *dev, int *budget);
++static int gt64240_rx(struct net_device *dev, u32 status, int budget);
++#else
++static int gt64240_rx(struct net_device *dev, u32 status);
++#endif
++static void gt64240_tx_timeout(struct net_device *dev);
++static void gt64240_set_rx_mode(struct net_device *dev);
++static struct net_device_stats *gt64240_get_stats(struct net_device *dev);
++
++extern char *__init prom_getcmdline(void);
++extern int prom_get_mac_addrs(unsigned char
++			      station_addr[NUM_INTERFACES][6]);
++
++static char version[] __devinitdata =
++	"gt64240eth.o: version 0.1, <www.patton.com>\n";
++
++// PHY device addresses
++static u32 gt64240_phy_addr[NUM_INTERFACES] __devinitdata = { 0x8, 0x1, 0xa };
++
++// Need real Ethernet addresses -- in parse_mac_addr_options(),
++// these will be replaced by prom_get_mac_addrs() and/or prom_getcmdline().
++static unsigned char gt64240_station_addr[NUM_INTERFACES][6] = {
++	{0x00, 0x01, 0x02, 0x03, 0x04, 0x05},
++	{0x01, 0x02, 0x03, 0x04, 0x05, 0x06},
++	{0x02, 0x03, 0x04, 0x05, 0x06, 0x07}
++};
++
++static int max_interrupt_work = 32;
++
++/*
++ * Base address and interupt of the GT64240 ethernet controllers
++ */
++static struct {
++	unsigned int port;
++	int irq;
++} gt64240_iflist[NUM_INTERFACES] = {
++	{
++	GT64240_ETH0_BASE, 8}, {
++	GT64240_ETH1_BASE, 8}, {
++	GT64240_ETH2_BASE, 8}
++};
++
++static void gt64240_delay(int ms)
++{
++	if (in_interrupt())
++		return;
++	else {
++		current->state = TASK_INTERRUPTIBLE;
++		schedule_timeout(ms * HZ / 1000);
++	}
++}
++
++unsigned char prom_mac_addr_base[6];
++
++int prom_get_mac_addrs(unsigned char station_addr[NUM_INTERFACES][6])
++{
++	memcpy(station_addr[0], prom_mac_addr_base, 6);
++	memcpy(station_addr[1], prom_mac_addr_base, 6);
++	memcpy(station_addr[2], prom_mac_addr_base, 6);
++
++	station_addr[1][5] += 1;
++	station_addr[2][5] += 2;
++
++	return 0;
++}
++
++void parse_mac_addr_options(void)
++{
++	prom_get_mac_addrs(gt64240_station_addr);
++}
++
++static int read_MII(struct net_device *dev, int phy, int reg)
++{
++	int timedout = 20;
++	u32 smir = smirOpCode | (phy << smirPhyAdBit) |
++	    (reg << smirRegAdBit);
++
++	// wait for last operation to complete
++	while ((GT64240_READ(GT64240_ETH_SMI_REG)) & smirBusy) {
++		// snooze for 1 msec and check again
++		gt64240_delay(1);
++
++		if (--timedout == 0) {
++			printk("%s: read_MII busy timeout!!\n", dev->name);
++			return -1;
++		}
++	}
++
++	GT64240_WRITE(GT64240_ETH_SMI_REG, smir);
++
++	timedout = 20;
++	// wait for read to complete
++	while (!
++	       ((smir =
++		 GT64240_READ(GT64240_ETH_SMI_REG)) & smirReadValid)) {
++		// snooze for 1 msec and check again
++		gt64240_delay(1);
++
++		if (--timedout == 0) {
++			printk("%s: read_MII timeout!!\n", dev->name);
++			return -1;
++		}
++	}
++
++	return (int) (smir & smirDataMask);
++}
++
++static void gp_get_drvinfo (struct net_device *dev, 
++				struct ethtool_drvinfo *info)
++{
++	strcpy(info->driver, "gt64260");
++	strcpy(info->version, version);
++}
++
++static int gp_get_settings(struct net_device *dev, 
++				struct ethtool_cmd *cmd)
++{
++	struct gt64240_private *gp = netdev_priv(dev);
++	int rc;
++
++	spin_lock_irq(&gp->lock);
++	rc = mii_ethtool_gset(&gp->mii_if, cmd);
++	spin_unlock_irq(&gp->lock);
++	return rc;
++}
++
++static int gp_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
++{
++	struct gt64240_private *gp = netdev_priv(dev);
++	int rc;
++
++	spin_lock_irq(&gp->lock);
++	rc = mii_ethtool_sset(&gp->mii_if, cmd);
++	spin_unlock_irq(&gp->lock);
++	return rc;
++}
++
++static int gp_nway_reset(struct net_device *dev)
++{
++	struct gt64240_private *gp = netdev_priv(dev);
++	return mii_nway_restart(&gp->mii_if);
++}
++
++static u32 gp_get_link(struct net_device *dev)
++{
++	struct gt64240_private *gp = netdev_priv(dev);
++	return mii_link_ok(&gp->mii_if);
++}
++
++static u32 gp_get_msglevel(struct net_device *dev)
++{
++	struct gt64240_private *gp = netdev_priv(dev);
++	return gp->msg_enable;
++}
++
++static void gp_set_msglevel(struct net_device *dev, u32 value)
++{
++	struct gt64240_private *gp = netdev_priv(dev);
++	gp->msg_enable = value;
++}
++
++static struct ethtool_ops gp_ethtool_ops = {
++	.get_drvinfo		= gp_get_drvinfo,
++	.get_settings		= gp_get_settings,
++	.set_settings		= gp_set_settings,
++	.nway_reset		= gp_nway_reset,
++	.get_link		= gp_get_link,
++	.get_msglevel		= gp_get_msglevel,
++	.set_msglevel		= gp_set_msglevel,
++};
++
++static int gt64240_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
++{
++	struct gt64240_private *gp = netdev_priv(dev);
++	struct mii_ioctl_data *data =
++	    (struct mii_ioctl_data *) &rq->ifr_data;
++	int retval;
++
++	if (!netif_running(dev))
++		return -EINVAL;
++
++	spin_lock_irq(&gp->lock);
++	retval = generic_mii_ioctl(&gp->mii_if, data, cmd, NULL);
++	spin_unlock_irq(&gp->lock);
++
++	return retval;
++}
++
++static void dump_tx_desc(struct net_device *dev, int i)
++{
++	struct gt64240_private *gp = netdev_priv(dev);
++	gt64240_td_t *td = &gp->tx_ring[i];
++
++	printk("%s:tx[%d]: self=%p cmd=%08x, cnt=%4d. bufp=%08x, next=%08x\n",
++	       dev->name, i, td, td->cmdstat, td->byte_cnt, td->buff_ptr,
++	       td->next);
++}
++
++static void dump_rx_desc(struct net_device *dev, int i)
++{
++	struct gt64240_private *gp = netdev_priv(dev);
++	gt64240_rd_t *rd = &gp->rx_ring[i];
++
++	printk("%s:rx_dsc[%d]: self=%p cst=%08x,size=%4d. cnt=%4d. "
++	       "bufp=%08x, next=%08x\n",
++	       dev->name, i, rd, rd->cmdstat, rd->buff_sz, rd->byte_cnt,
++	       rd->buff_ptr, rd->next);
++}
++
++// These routines work, just disabled to avoid compile warnings
++static void write_MII(struct net_device *dev, int phy, int reg, int data)
++{
++	u32 smir = (phy << smirPhyAdBit) | (reg << smirRegAdBit) | data;
++	int timedout = 20;
++
++	// wait for last operation to complete
++	while (GT64240_READ(GT64240_ETH_SMI_REG) & smirBusy) {
++		// snooze for 1 msec and check again
++		gt64240_delay(1);
++
++		if (--timedout == 0) {
++			printk("%s: write_MII busy timeout!!\n",
++			       dev->name);
++			return;
++		}
++	}
++
++	GT64240_WRITE(GT64240_ETH_SMI_REG, smir);
++}
++
++static void dump_MII(struct net_device *dev)
++{
++	struct gt64240_private *gp = netdev_priv(dev);
++	int i, val;
++
++	for (i = 0; i < 7; i++) {
++		if ((val = read_MII(dev, gp->phy_addr, i)) >= 0)
++			printk("%s: MII Reg %d=%x\n", dev->name, i, val);
++	}
++	for (i = 16; i < 21; i++) {
++		if ((val = read_MII(dev, gp->phy_addr, i)) >= 0)
++			printk("%s: MII Reg %d=%x\n", dev->name, i, val);
++	}
++}
++
++
++static void dump_hw_addr(unsigned char *addr_str)
++{
++	int i;
++	for (i = 0; i < 6; i++) {
++		printk("%2.2x", addr_str[i]);
++		printk(i < 5 ? ":" : "\n");
++	}
++}
++
++static int gt64240_add_hash_entry(struct net_device *dev,
++				  unsigned char *addr)
++{
++	static unsigned char swapped[256];
++	struct gt64240_private *gp;
++	u32 value1, value0, *entry;
++	unsigned char hash_ea[6];
++	static int flag = 0;
++	u16 hashResult;
++	int i;
++
++	if (flag == 0) {	/* Create table to swap bits in a byte  */
++		flag = 1;
++		for (i = 0; i < 256; i++) {
++			swapped[i] = (i & 0x01) << 7;
++			swapped[i] |= (i & 0x02) << 5;
++			swapped[i] |= (i & 0x04) << 3;
++			swapped[i] |= (i & 0x08) << 1;
++			swapped[i] |= (i & 0x10) >> 1;
++			swapped[i] |= (i & 0x20) >> 3;
++			swapped[i] |= (i & 0x40) >> 5;
++			swapped[i] |= (i & 0x80) >> 7;
++		}
++	}
++
++	for (i = 0; i < 6; i++) {	/* swap bits from mac to create hash mac */
++		hash_ea[i] = swapped[addr[i]];
++	}
++
++	gp = netdev_priv(dev);
++
++	/* create hash entry address    */
++	hashResult = (((hash_ea[5] >> 2) & 0x3F) << 9) & 0x7E00;
++	hashResult |= ((hash_ea[4] & 0x7F) << 2) | (hash_ea[5] & 0x03);
++	hashResult ^=
++	    ((hash_ea[3] & 0xFF) << 1) | ((hash_ea[4] >> 7) & 0x01);
++	hashResult ^= ((hash_ea[1] & 0x01) << 8) | (hash_ea[2] & 0xFF);
++
++	value0 = hteValid | hteRD;	/* Create hash table entry value */
++	value0 |= (u32) addr[0] << 3;
++	value0 |= (u32) addr[1] << 11;
++	value0 |= (u32) addr[2] << 19;
++	value0 |= ((u32) addr[3] & 0x1f) << 27;
++
++	value1 = ((u32) addr[3] >> 5) & 0x07;
++	value1 |= (u32) addr[4] << 3;
++	value1 |= (u32) addr[5] << 11;
++
++	/* Inset entry value into hash table */
++	for (i = 0; i < HASH_HOP_NUMBER; i++) {
++		entry = (u32 *) ((u32) gp->hash_table +
++				 (((u32) hashResult & 0x07ff) << 3));
++		if ((*entry & hteValid) && !(*entry & hteSkip)) {
++			hashResult += 2;	/* oops, occupied, go to next entry */
++		} else {
++#ifdef __LITTLE_ENDIAN
++			entry[1] = value1;
++			entry[0] = value0;
++#else
++			entry[0] = value1;
++			entry[1] = value0;
++#endif
++			break;
++		}
++	}
++	if (i >= HASH_HOP_NUMBER) {
++		printk("%s: gt64240_add_hash_entry expired!\n", dev->name);
++		return (-1);
++	}
++	return (0);
++}
++
++
++static void read_mib_counters(struct gt64240_private *gp)
++{
++	u32 *mib_regs = (u32 *) & gp->mib;
++	int i;
++
++	for (i = 0; i < sizeof(mib_counters_t) / sizeof(u32); i++)
++		mib_regs[i] =
++		    GT64240ETH_READ(gp,
++				    GT64240_ETH_MIB_COUNT_BASE +
++				    i * sizeof(u32));
++}
++
++
++static void update_stats(struct gt64240_private *gp)
++{
++	mib_counters_t *mib = &gp->mib;
++	struct net_device_stats *stats = &gp->stats;
++
++	read_mib_counters(gp);
++
++	stats->rx_packets = mib->totalFramesReceived;
++	stats->tx_packets = mib->framesSent;
++	stats->rx_bytes = mib->totalByteReceived;
++	stats->tx_bytes = mib->byteSent;
++	stats->rx_errors = mib->totalFramesReceived - mib->framesReceived;
++	//the tx error counters are incremented by the ISR
++	//rx_dropped incremented by gt64240_rx
++	//tx_dropped incremented by gt64240_tx
++	stats->multicast = mib->multicastFramesReceived;
++	// collisions incremented by gt64240_tx_complete
++	stats->rx_length_errors = mib->oversizeFrames + mib->fragments;
++	// The RxError condition means the Rx DMA encountered a
++	// CPU owned descriptor, which, if things are working as
++	// they should, means the Rx ring has overflowed.
++	stats->rx_over_errors = mib->macRxError;
++	stats->rx_crc_errors = mib->cRCError;
++}
++
++static void abort(struct net_device *dev, u32 abort_bits)
++{
++	struct gt64240_private *gp = netdev_priv(dev);
++	int timedout = 100;	// wait up to 100 msec for hard stop to complete
++
++	if (gt64240_debug > 3)
++		printk("%s: abort\n", dev->name);
++
++	// Return if neither Rx or Tx abort bits are set
++	if (!(abort_bits & (sdcmrAR | sdcmrAT)))
++		return;
++
++	// make sure only the Rx/Tx abort bits are set
++	abort_bits &= (sdcmrAR | sdcmrAT);
++
++	spin_lock(&gp->lock);
++
++	// abort any Rx/Tx DMA immediately
++	GT64240ETH_WRITE(gp, GT64240_ETH_SDMA_COMM, abort_bits);
++
++	if (gt64240_debug > 3)
++		printk("%s: abort: SDMA cmd  = %x/%x\n",
++		       dev->name, abort_bits, GT64240ETH_READ(gp,
++							      GT64240_ETH_SDMA_COMM));
++
++	// wait for abort to complete
++	while ((GT64240ETH_READ(gp, GT64240_ETH_SDMA_COMM)) & abort_bits) {
++		// snooze for 20 msec and check again
++		gt64240_delay(1);
++
++		if (--timedout == 0) {
++			printk("%s: abort timeout!!\n", dev->name);
++			break;
++		}
++	}
++
++	spin_unlock(&gp->lock);
++}
++
++
++static void hard_stop(struct net_device *dev)
++{
++	struct gt64240_private *gp = netdev_priv(dev);
++
++	if (gt64240_debug > 3)
++		printk("%s: hard stop\n", dev->name);
++
++	disable_ether_irq(dev);
++
++	abort(dev, sdcmrAR | sdcmrAT);
++
++	// disable port
++	GT64240ETH_WRITE(gp, GT64240_ETH_PORT_CONFIG, 0);
++	if (gt64240_debug > 3)
++		printk("%s: gt64240_hard_stop: Port Config=%x\n",
++		       dev->name, GT64240ETH_READ(gp,
++						  GT64240_ETH_PORT_CONFIG));
++
++}
++
++static void gt64240_tx_complete(struct net_device *dev, u32 status)
++{
++	struct gt64240_private *gp = netdev_priv(dev);
++	int nextOut, cdp;
++	gt64240_td_t *td;
++	u32 cmdstat;
++
++	cdp = (GT64240ETH_READ(gp, GT64240_ETH_CURR_TX_DESC_PTR0)
++	       - gp->tx_ring_dma) / sizeof(gt64240_td_t);
++
++	if (gt64240_debug > 3) {	/*+prk17aug01 */
++		nextOut = gp->tx_next_out;
++		printk
++		    ("%s: tx_complete: TX_PTR0=0x%08x, cdp=%d. nextOut=%d.\n",
++		     dev->name, GT64240ETH_READ(gp,
++						GT64240_ETH_CURR_TX_DESC_PTR0),
++		     cdp, nextOut);
++		td = &gp->tx_ring[nextOut];
++	}
++
++/*** NEED to check and CLEAR these errors every time thru here: ***/
++	if (gt64240_debug > 2) {
++		if (GT64240_READ(COMM_UNIT_INTERRUPT_CAUSE))
++			printk
++			    ("%s: gt64240_tx_complete: CIU Cause=%08x, Mask=%08x, EAddr=%08x\n",
++			     dev->name,
++			     GT64240_READ(COMM_UNIT_INTERRUPT_CAUSE),
++			     GT64240_READ(COMM_UNIT_INTERRUPT_MASK),
++			     GT64240_READ(COMM_UNIT_ERROR_ADDRESS));
++		GT64240_WRITE(COMM_UNIT_INTERRUPT_CAUSE, 0);
++	}
++	// Continue until we reach the current descriptor pointer
++	for (nextOut = gp->tx_next_out; nextOut != cdp;
++	     nextOut = (nextOut + 1) % TX_RING_SIZE) {
++
++		if (--gp->intr_work_done == 0)
++			break;
++
++		td = &gp->tx_ring[nextOut];
++		cmdstat = td->cmdstat;
++
++		if (cmdstat & (u32) txOwn) {
++			// DMA is not finished writing descriptor???
++			// Leave and come back later to pick-up where we left off.
++			break;
++		}
++		// increment Tx error stats
++		if (cmdstat & (u32) txErrorSummary) {
++			if (gt64240_debug > 2)
++				printk
++				    ("%s: tx_complete: Tx error, cmdstat = %x\n",
++				     dev->name, cmdstat);
++			gp->stats.tx_errors++;
++			if (cmdstat & (u32) txReTxLimit)
++				gp->stats.tx_aborted_errors++;
++			if (cmdstat & (u32) txUnderrun)
++				gp->stats.tx_fifo_errors++;
++			if (cmdstat & (u32) txLateCollision)
++				gp->stats.tx_window_errors++;
++		}
++
++		if (cmdstat & (u32) txCollision)
++			gp->stats.collisions +=
++			    (unsigned long) ((cmdstat & txReTxCntMask) >>
++					     txReTxCntBit);
++
++		// Wake the queue if the ring was full
++		if (gp->tx_full) {
++			gp->tx_full = 0;
++			if (gp->last_psr & psrLink) {
++				netif_wake_queue(dev);
++			}
++		}
++		// decrement tx ring buffer count
++		if (gp->tx_count)
++			gp->tx_count--;
++
++		// free the skb
++		if (gp->tx_skbuff[nextOut]) {
++			if (gt64240_debug > 3)
++				printk
++				    ("%s: tx_complete: good Tx, skb=%p\n",
++				     dev->name, gp->tx_skbuff[nextOut]);
++			dev_kfree_skb_irq(gp->tx_skbuff[nextOut]);
++			gp->tx_skbuff[nextOut] = NULL;
++		} else {
++			printk("%s: tx_complete: no skb!\n", dev->name);
++		}
++	}
++
++	gp->tx_next_out = nextOut;
++
++	if ((status & icrTxEndLow) && gp->tx_count != 0) {
++		// we must restart the DMA
++		GT64240ETH_WRITE(gp, GT64240_ETH_SDMA_COMM,
++				 sdcmrERD | sdcmrTXDL);
++	}
++}
++
++static irqreturn_t gt64240_interrupt(int irq, void *dev_id,
++	struct pt_regs *regs)
++{
++	struct net_device *dev = (struct net_device *) dev_id;
++	struct gt64240_private *gp = netdev_priv(dev);
++	u32 status;
++
++	if (dev == NULL) {
++		printk("%s: isr: null dev ptr\n", dev->name);
++		return IRQ_NONE;
++	}
++
++	spin_lock(&gp->lock);
++
++	if (gt64240_debug > 3)
++		printk("%s: isr: entry\n", dev->name);
++
++	gp->intr_work_done = max_interrupt_work;
++
++	while (gp->intr_work_done > 0) {
++
++		status = GT64240ETH_READ(gp, GT64240_ETH_INT_CAUSE);
++#ifdef GT64240_NAPI
++		/* dont ack Rx interrupts */
++		if (!(status & icrRxBuffer))
++			GT64240ETH_WRITE(gp, GT64240_ETH_INT_CAUSE, 0);
++#else
++		// ACK interrupts
++		GT64240ETH_WRITE(gp, GT64240_ETH_INT_CAUSE, 0);
++#endif
++
++		if (gt64240_debug > 3)
++			printk("%s: isr: work=%d., icr=%x\n", dev->name,
++			       gp->intr_work_done, status);
++
++		if ((status & icrEtherIntSum) == 0) {
++			if (!(status &
++			      (icrTxBufferLow | icrTxBufferHigh |
++			       icrRxBuffer))) {
++				/* exit from the while() loop */
++				break;
++			}
++		}
++
++		if (status & icrMIIPhySTC) {
++			u32 psr =
++			    GT64240ETH_READ(gp, GT64240_ETH_PORT_STATUS);
++			if (gp->last_psr != psr) {
++				printk("%s: port status: 0x%08x\n",
++				       dev->name, psr);
++				printk
++				    ("%s:    %s MBit/s, %s-duplex, flow-control %s, link is %s,\n",
++				     dev->name,
++				     psr & psrSpeed ? "100" : "10",
++				     psr & psrDuplex ? "full" : "half",
++				     psr & psrFctl ? "disabled" :
++				     "enabled",
++				     psr & psrLink ? "up" : "down");
++				printk
++				    ("%s:    TxLowQ is %s, TxHighQ is %s, Transmitter is %s\n",
++				     dev->name,
++				     psr & psrTxLow ? "running" :
++				     "stopped",
++				     psr & psrTxHigh ? "running" :
++				     "stopped",
++				     psr & psrTxInProg ? "on" : "off");
++
++				if ((psr & psrLink) && !gp->tx_full &&
++				    netif_queue_stopped(dev)) {
++					printk
++					    ("%s: isr: Link up, waking queue.\n",
++					     dev->name);
++					netif_wake_queue(dev);
++				} else if (!(psr & psrLink)
++					   && !netif_queue_stopped(dev)) {
++					printk
++					    ("%s: isr: Link down, stopping queue.\n",
++					     dev->name);
++					netif_stop_queue(dev);
++				}
++
++				gp->last_psr = psr;
++			}
++		}
++
++		if (status & (icrTxBufferLow | icrTxEndLow))
++			gt64240_tx_complete(dev, status);
++
++		if (status & icrRxBuffer) {
++#ifdef GT64240_NAPI
++			if (netif_rx_schedule_prep(dev)) {
++				disable_ether_irq(dev);
++				__netif_rx_schedule(dev);
++			}
++#else
++			gt64240_rx(dev, status);
++#endif
++		}
++		// Now check TX errors (RX errors were handled in gt64240_rx)
++		if (status & icrTxErrorLow) {
++			printk("%s: isr: Tx resource error\n", dev->name);
++		}
++
++		if (status & icrTxUdr) {
++			printk("%s: isr: Tx underrun error\n", dev->name);
++		}
++	}
++
++	if (gp->intr_work_done == 0) {
++		// ACK any remaining pending interrupts
++		GT64240ETH_WRITE(gp, GT64240_ETH_INT_CAUSE, 0);
++		if (gt64240_debug > 3)
++			printk("%s: isr: hit max work\n", dev->name);
++	}
++
++	if (gt64240_debug > 3)
++		printk("%s: isr: exit, icr=%x\n",
++		       dev->name, GT64240ETH_READ(gp,
++						  GT64240_ETH_INT_CAUSE));
++
++	spin_unlock(&gp->lock);
++
++	return IRQ_HANDLED;
++}
++
++static void enable_ether_irq(struct net_device *dev)
++{
++	struct gt64240_private *gp = netdev_priv(dev);
++	u32 intMask;
++
++	intMask =
++	    icrTxBufferLow | icrTxEndLow | icrTxErrorLow |
++	    icrTxBufferHigh | icrTxEndHigh | icrTxErrorHigh | icrTxUdr |
++	    icrRxBuffer | icrRxOVR | icrRxError | icrMIIPhySTC |
++	    icrEtherIntSum;
++
++
++//- GT64240ETH_WRITE(gp, GT64240_ETH_INT_CAUSE, 0); /* CLEAR existing ints */
++	// unmask device interrupts:
++	GT64240ETH_WRITE(gp, GT64240_ETH_INT_MASK, intMask);
++
++	// now route ethernet interrupts to GT PCI1 (eth0 and eth1 will be
++	// sharing it).
++	intMask = MV_READ(PCI_1INTERRUPT_CAUSE_MASK_REGISTER_HIGH);
++	intMask |= 1 << gp->port_num;
++	MV_WRITE(PCI_1INTERRUPT_CAUSE_MASK_REGISTER_HIGH, intMask);
++}
++
++static void disable_ether_irq(struct net_device *dev)
++{
++	struct gt64240_private *gp = netdev_priv(dev);
++	u32 intMask;
++
++	intMask = MV_READ(PCI_1INTERRUPT_CAUSE_MASK_REGISTER_HIGH);
++	intMask &= ~(1 << gp->port_num);
++	MV_WRITE(PCI_1INTERRUPT_CAUSE_MASK_REGISTER_HIGH, intMask);
++
++	// mask all device interrupts: 
++	GT64240ETH_WRITE(gp, GT64240_ETH_INT_MASK, 0);
++}
++
++/*
++ * Probe for a GT64240 ethernet controller.
++ */
++static int __init gt64240_probe(void)
++{
++	int found = 0;
++	int i;
++
++	parse_mac_addr_options();
++
++	for (i = 0; i < NUM_INTERFACES; i++) {
++		unsigned long base_addr = gt64240_iflist[i].port;
++
++		if (check_region(base_addr, GT64240_ETH_IO_SIZE)) {
++			printk("gt64240_probe: ioaddr 0x%lx taken?\n",
++			       base_addr);
++			continue;
++		}
++
++		if (gt64240_probe1(base_addr, gt64240_iflist[i].irq, i) == 0) {
++			/*
++			 * Does not seem to be the "traditional" way folks do
++			 * this, but I want to init both eth ports if at all
++			 * possible!
++			 *
++			 * So, until I find out the "correct" way to do this:
++			 */
++			if (++found == NUM_INTERFACES)	/* That's all of them */
++				return 0;
++		}
++	}
++
++	if (found)
++		return 0;	/* as long as we found at least one! */
++
++	return -ENODEV;
++}
++
++module_init(gt64240_probe);
++
++static int __init gt64240_probe1(unsigned long ioaddr, int irq, int port_num)
++{
++	struct net_device *dev = NULL;
++	static unsigned version_printed = 0;
++	struct gt64240_private *gp = NULL;
++	int retval;
++	u32 cpuConfig;
++
++	dev = alloc_etherdev(sizeof(struct gt64240_private));
++	if (!dev)
++		return -ENOMEM;
++
++	if (irq < 0) {
++		printk
++		    ("gt64240_probe1: irq unknown - probing not supported\n");
++		return -ENODEV;
++	}
++#if 1				/* KLUDGE Alert: no check on return value: */
++	if (!request_region(ioaddr, GT64240_ETH_IO_SIZE, "gt64240eth"))
++		printk("*** request_region() failed!\n");
++#endif
++
++	cpuConfig = GT64240_READ(CPU_CONFIGURATION);
++	printk("gt64240_probe1: cpu in %s-endian mode\n",
++	       (cpuConfig & (1 << 12)) ? "little" : "big");
++
++	printk("%s: GT64240 found at ioaddr 0x%lx, irq %d.\n",
++	       dev->name, ioaddr, irq);
++
++	if (gt64240_debug && version_printed++ == 0)
++		printk("%s: %s", dev->name, version);
++
++	/* private struct aligned and zeroed by init_etherdev */
++	/* Fill in the 'dev' fields. */
++	dev->base_addr = ioaddr;
++	dev->irq = irq;
++	memcpy(dev->dev_addr, gt64240_station_addr[port_num],
++	       sizeof(dev->dev_addr));
++
++	printk("%s: HW Address ", dev->name);
++	dump_hw_addr(dev->dev_addr);
++
++	gp = dev->priv;
++
++	gp->msg_enable = (debug < 0 ? GT64240_MSG_ENABLE : debug);
++	gp->port_num = port_num;
++	gp->io_size = GT64240_ETH_IO_SIZE;
++	gp->port_offset = port_num * GT64240_ETH_IO_SIZE;
++	gp->phy_addr = gt64240_phy_addr[port_num];
++
++	printk("%s: GT64240 ethernet port %d\n", dev->name, gp->port_num);
++
++#ifdef GT64240_NAPI
++	printk("Rx NAPI supported \n");
++#endif
++
++/* MII Initialization */
++	gp->mii_if.dev = dev;
++	gp->mii_if.phy_id = dev->base_addr;
++	gp->mii_if.mdio_read = read_MII;
++	gp->mii_if.mdio_write = write_MII;
++	gp->mii_if.advertising = read_MII(dev, gp->phy_addr, MII_ADVERTISE);
++
++	// Allocate Rx and Tx descriptor rings
++	if (gp->rx_ring == NULL) {
++		// All descriptors in ring must be 16-byte aligned
++		gp->rx_ring = dma_alloc_noncoherent(NULL,
++					sizeof(gt64240_rd_t) * RX_RING_SIZE +
++					sizeof(gt64240_td_t) * TX_RING_SIZE,
++					&gp->rx_ring_dma, GFP_KERNEL);
++		if (gp->rx_ring == NULL) {
++			retval = -ENOMEM;
++			goto free_region;
++		}
++
++		gp->tx_ring = (gt64240_td_t *) (gp->rx_ring + RX_RING_SIZE);
++		gp->tx_ring_dma =
++			gp->rx_ring_dma + sizeof(gt64240_rd_t) * RX_RING_SIZE;
++	}
++	// Allocate the Rx Data Buffers
++	if (gp->rx_buff == NULL) {
++		gp->rx_buff = dma_alloc_coherent(NULL,
++				PKT_BUF_SZ * RX_RING_SIZE, &gp->rx_buff_dma,
++				GFP_KERNEL);
++		if (gp->rx_buff == NULL) {
++			dma_free_noncoherent(NULL,
++				sizeof(gt64240_rd_t) * RX_RING_SIZE +
++				sizeof(gt64240_td_t) * TX_RING_SIZE,
++				gp->rx_ring, gp->rx_ring_dma);
++			retval = -ENOMEM;
++			goto free_region;
++		}
++	}
++
++	if (gt64240_debug > 3)
++		printk("%s: gt64240_probe1, rx_ring=%p, tx_ring=%p\n",
++		       dev->name, gp->rx_ring, gp->tx_ring);
++
++	// Allocate Rx Hash Table
++	if (gp->hash_table == NULL) {
++		gp->hash_table = dma_alloc_coherent(NULL,
++				RX_HASH_TABLE_SIZE, &gp->hash_table_dma,
++				GFP_KERNEL);
++		if (gp->hash_table == NULL) {
++			dma_free_noncoherent(NULL,
++				sizeof(gt64240_rd_t) * RX_RING_SIZE +
++				sizeof(gt64240_td_t) * TX_RING_SIZE,
++				gp->rx_ring, gp->rx_ring_dma);
++			dma_free_noncoherent(NULL, PKT_BUF_SZ * RX_RING_SIZE,
++				gp->rx_buff, gp->rx_buff_dma);
++			retval = -ENOMEM;
++			goto free_region;
++		}
++	}
++
++	if (gt64240_debug > 3)
++		printk("%s: gt64240_probe1, hash=%p\n",
++		       dev->name, gp->hash_table);
++
++	spin_lock_init(&gp->lock);
++
++	dev->open = gt64240_open;
++	dev->hard_start_xmit = gt64240_tx;
++	dev->stop = gt64240_close;
++	dev->get_stats = gt64240_get_stats;
++	dev->do_ioctl = gt64240_ioctl;
++	dev->set_multicast_list = gt64240_set_rx_mode;
++	dev->tx_timeout = gt64240_tx_timeout;
++	dev->watchdog_timeo = GT64240ETH_TX_TIMEOUT;
++
++#ifdef GT64240_NAPI
++	dev->poll = gt64240_poll;
++	dev->weight = 64;
++#endif
++	dev->ethtool_ops = &gp_ethtool_ops;
++
++	/* Fill in the fields of the device structure with ethernet values. */
++	return 0;
++
++free_region:
++	release_region(ioaddr, gp->io_size);
++	unregister_netdev(dev);
++	free_netdev(dev);
++	printk("%s: gt64240_probe1 failed.  Returns %d\n",
++	       dev->name, retval);
++	return retval;
++}
++
++
++static void reset_tx(struct net_device *dev)
++{
++	struct gt64240_private *gp = netdev_priv(dev);
++	int i;
++
++	abort(dev, sdcmrAT);
++
++	for (i = 0; i < TX_RING_SIZE; i++) {
++		if (gp->tx_skbuff[i]) {
++			if (in_interrupt())
++				dev_kfree_skb_irq(gp->tx_skbuff[i]);
++			else
++				dev_kfree_skb(gp->tx_skbuff[i]);
++			gp->tx_skbuff[i] = NULL;
++		}
++//-     gp->tx_ring[i].cmdstat = 0; // CPU owns
++		gp->tx_ring[i].cmdstat =
++		    (u32) (txGenCRC | txEI | txPad | txFirst | txLast);
++		gp->tx_ring[i].byte_cnt = 0;
++		gp->tx_ring[i].buff_ptr = 0;
++		gp->tx_ring[i].next =
++		    gp->tx_ring_dma + sizeof(gt64240_td_t) * (i + 1);
++		if (gt64240_debug > 4)
++			dump_tx_desc(dev, i);
++	}
++	/* Wrap the ring. */
++	gp->tx_ring[i - 1].next = gp->tx_ring_dma;
++	if (gt64240_debug > 4)
++		dump_tx_desc(dev, i - 1);
++
++	// setup only the lowest priority TxCDP reg
++	GT64240ETH_WRITE(gp, GT64240_ETH_CURR_TX_DESC_PTR0,
++			 gp->tx_ring_dma);
++//- GT64240ETH_WRITE(gp, GT64240_ETH_CURR_TX_DESC_PTR0, 0);     /* ROLLINS */
++//- GT64240ETH_WRITE(gp, GT64240_ETH_CURR_TX_DESC_PTR0,virt_to_phys(&gp->tx_ring[0]));  /* ROLLINS */
++
++	GT64240ETH_WRITE(gp, GT64240_ETH_CURR_TX_DESC_PTR1, 0);
++
++	// init Tx indeces and pkt counter
++	gp->tx_next_in = gp->tx_next_out = 0;
++	gp->tx_count = 0;
++}
++
++static void reset_rx(struct net_device *dev)
++{
++	struct gt64240_private *gp = netdev_priv(dev);
++	int i;
++
++	abort(dev, sdcmrAR);
++
++	for (i = 0; i < RX_RING_SIZE; i++) {
++		gp->rx_ring[i].next =
++		    gp->rx_ring_dma + sizeof(gt64240_rd_t) * (i + 1);
++		gp->rx_ring[i].buff_ptr = gp->rx_buff_dma + i * PKT_BUF_SZ;
++		gp->rx_ring[i].buff_sz = PKT_BUF_SZ;
++		gp->rx_ring[i].byte_cnt = 0;	/* just for debug printk's */
++		// Give ownership to device, set first and last, enable interrupt
++		gp->rx_ring[i].cmdstat =
++		    (uint32_t) (rxFirst | rxLast | rxOwn | rxEI);
++		if (gt64240_debug > 4)
++			dump_rx_desc(dev, i);
++	}
++	/* Wrap the ring. */
++	gp->rx_ring[i - 1].next = gp->rx_ring_dma;
++	if (gt64240_debug > 4)
++		dump_rx_desc(dev, i - 1);
++
++	// Setup only the lowest priority RxFDP and RxCDP regs
++	for (i = 0; i < 4; i++) {
++		if (i == 0) {
++			GT64240ETH_WRITE(gp, GT64240_ETH_1ST_RX_DESC_PTR0,
++					 gp->rx_ring_dma);
++			GT64240ETH_WRITE(gp, GT64240_ETH_CURR_RX_DESC_PTR0,
++					 gp->rx_ring_dma);
++		} else {
++			GT64240ETH_WRITE(gp,
++					 GT64240_ETH_1ST_RX_DESC_PTR0 +
++					 i * 4, 0);
++			GT64240ETH_WRITE(gp,
++					 GT64240_ETH_CURR_RX_DESC_PTR0 +
++					 i * 4, 0);
++		}
++	}
++
++	// init Rx NextOut index
++	gp->rx_next_out = 0;
++}
++
++
++static int gt64240_init(struct net_device *dev)
++{
++	struct gt64240_private *gp = netdev_priv(dev);
++
++	if (gt64240_debug > 3) {
++		printk("%s: gt64240_init: dev=%p\n", dev->name, dev);
++		printk("%s: gt64240_init: scs0_lo=%04x, scs0_hi=%04x\n",
++		       dev->name, GT64240_READ(0x008),
++		       GT64240_READ(0x010));
++		printk("%s: gt64240_init: scs1_lo=%04x, scs1_hi=%04x\n",
++		       dev->name, GT64240_READ(0x208),
++		       GT64240_READ(0x210));
++		printk("%s: gt64240_init: scs2_lo=%04x, scs2_hi=%04x\n",
++		       dev->name, GT64240_READ(0x018),
++		       GT64240_READ(0x020));
++		printk("%s: gt64240_init: scs3_lo=%04x, scs3_hi=%04x\n",
++		       dev->name, GT64240_READ(0x218),
++		       GT64240_READ(0x220));
++	}
++	// Stop and disable Port
++	hard_stop(dev);
++
++	GT64240_WRITE(COMM_UNIT_INTERRUPT_MASK, 0x07070777);	/*+prk21aug01 */
++	if (gt64240_debug > 2)
++		printk
++		    ("%s: gt64240_init: CIU Cause=%08x, Mask=%08x, EAddr=%08x\n",
++		     dev->name, GT64240_READ(COMM_UNIT_INTERRUPT_CAUSE),
++		     GT64240_READ(COMM_UNIT_INTERRUPT_MASK),
++		     GT64240_READ(COMM_UNIT_ERROR_ADDRESS));
++
++	// Set-up hash table
++	memset(gp->hash_table, 0, RX_HASH_TABLE_SIZE);	// clear it
++	gp->hash_mode = 0;
++	// Add a single entry to hash table - our ethernet address
++	gt64240_add_hash_entry(dev, dev->dev_addr);
++	// Set-up DMA ptr to hash table
++	GT64240ETH_WRITE(gp, GT64240_ETH_HASH_TBL_PTR, gp->hash_table_dma);
++	if (gt64240_debug > 3)
++		printk("%s: gt64240_init: Hash Tbl Ptr=%x\n", dev->name,
++		       GT64240ETH_READ(gp, GT64240_ETH_HASH_TBL_PTR));
++
++	// Setup Tx
++	reset_tx(dev);
++
++	if (gt64240_debug > 3)
++		printk("%s: gt64240_init: Curr Tx Desc Ptr0=%x\n",
++		       dev->name, GT64240ETH_READ(gp,
++						  GT64240_ETH_CURR_TX_DESC_PTR0));
++
++	// Setup Rx
++	reset_rx(dev);
++
++	if (gt64240_debug > 3)
++		printk("%s: gt64240_init: 1st/Curr Rx Desc Ptr0=%x/%x\n",
++		       dev->name, GT64240ETH_READ(gp,
++						  GT64240_ETH_1ST_RX_DESC_PTR0),
++		       GT64240ETH_READ(gp, GT64240_ETH_CURR_RX_DESC_PTR0));
++
++	if (gt64240_debug > 3)
++		dump_MII(dev);
++
++	/* force a PHY reset -- self-clearing! */
++	write_MII(dev, gp->phy_addr, 0, 0x8000);
++
++	if (gt64240_debug > 3)
++		printk("%s: gt64240_init: PhyAD=%x\n", dev->name,
++		       GT64240_READ(GT64240_ETH_PHY_ADDR_REG));
++
++	// setup DMA
++	// We want the Rx/Tx DMA to write/read data to/from memory in
++	// Big Endian mode. Also set DMA Burst Size to 8 64Bit words.
++#ifdef DESC_DATA_BE
++	GT64240ETH_WRITE(gp, GT64240_ETH_SDMA_CONFIG,
++			 (0xf << sdcrRCBit) | sdcrRIFB | (3 <<
++							  sdcrBSZBit));
++#else
++	GT64240ETH_WRITE(gp, GT64240_ETH_SDMA_CONFIG, sdcrBLMR | sdcrBLMT |
++//-                  (0xf<<sdcrRCBit) | sdcrRIFB | (3<<sdcrBSZBit));
++			 (0xf << sdcrRCBit) | sdcrRIFB | (2 <<
++							  sdcrBSZBit));
++#endif
++
++	if (gt64240_debug > 3)
++		printk("%s: gt64240_init: SDMA Config=%x\n", dev->name,
++		       GT64240ETH_READ(gp, GT64240_ETH_SDMA_CONFIG));
++
++#if 0
++	// start Rx DMA
++	GT64240ETH_WRITE(gp, GT64240_ETH_SDMA_COMM, sdcmrERD);
++#endif
++
++	if (gt64240_debug > 3)
++		printk("%s: gt64240_init: SDMA Cmd =%x\n", dev->name,
++		       GT64240ETH_READ(gp, GT64240_ETH_SDMA_COMM));
++
++#if 1
++	GT64240ETH_WRITE(gp, GT64240_ETH_PORT_CONFIG, PORT_CONFIG);
++#endif
++
++	if (gt64240_debug > 3)
++		printk("%s: gt64240_init: Port Config=%x\n", dev->name,
++		       GT64240ETH_READ(gp, GT64240_ETH_PORT_CONFIG));
++
++	/*
++	 * Disable all Type-of-Service queueing. All Rx packets will be
++	 * treated normally and will be sent to the lowest priority
++	 * queue.
++	 *
++	 * Disable flow-control for now. FIX! support flow control?
++	 */
++
++#if 1
++	// clear all the MIB ctr regs
++	GT64240ETH_WRITE(gp, GT64240_ETH_PORT_CONFIG_EXT,
++			 EXT_CONFIG_CLEAR);
++	read_mib_counters(gp);
++	GT64240ETH_WRITE(gp, GT64240_ETH_PORT_CONFIG_EXT,
++			 EXT_CONFIG_CLEAR | pcxrMIBclrMode);
++
++#endif
++	if (gt64240_debug > 3)
++		printk("%s: gt64240_init: Port Config Ext=%x\n", dev->name,
++		       GT64240ETH_READ(gp, GT64240_ETH_PORT_CONFIG_EXT));
++
++	if (gt64240_debug > 3)
++		printk("%s: gt64240_init: Port Command=%x\n", dev->name,
++		       GT64240ETH_READ(gp, GT64240_ETH_PORT_COMMAND));
++	GT64240ETH_WRITE(gp, GT64240_ETH_PORT_COMMAND, 0x0);
++
++	netif_start_queue(dev);
++
++	/* enable the port */
++	GT64240ETH_WRITE(gp, GT64240_ETH_PORT_CONFIG,
++			 (PORT_CONFIG | pcrEN));
++	if (gt64240_debug > 3)
++		printk("%s: gt64240_init: Port Config=%x\n", dev->name,
++		       GT64240ETH_READ(gp, GT64240_ETH_PORT_CONFIG));
++#if 1
++	// start Rx DMA
++	GT64240ETH_WRITE(gp, GT64240_ETH_SDMA_COMM, sdcmrERD);
++#endif
++
++
++	// enable interrupts
++	enable_ether_irq(dev);
++
++//---    gp->last_psr |= psrLink;   /* KLUDGE ALERT */
++
++	// we should now be receiving frames
++	return 0;
++}
++
++
++static int gt64240_open(struct net_device *dev)
++{
++	int retval;
++
++	if (gt64240_debug > 3)
++		printk("%s: gt64240_open: dev=%p\n", dev->name, dev);
++
++	if ((retval = request_irq(dev->irq, &gt64240_interrupt,
++				  SA_SHIRQ, dev->name, dev))) {
++		printk("%s: unable to get IRQ %d\n", dev->name, dev->irq);
++
++		return retval;
++	}
++	// Initialize and startup the GT-64240 ethernet port
++	if ((retval = gt64240_init(dev))) {
++		printk("%s: error in gt64240_open\n", dev->name);
++		free_irq(dev->irq, dev);
++
++		return retval;
++	}
++
++	if (gt64240_debug > 3)
++		printk("%s: gt64240_open: Initialization done.\n",
++		       dev->name);
++
++	return 0;
++}
++
++static int gt64240_close(struct net_device *dev)
++{
++	if (gt64240_debug > 3)
++		printk("%s: gt64240_close: dev=%p\n", dev->name, dev);
++
++	// stop the device
++	if (netif_device_present(dev)) {
++		netif_stop_queue(dev);
++		hard_stop(dev);
++	}
++
++	free_irq(dev->irq, dev);
++
++	return 0;
++}
++
++#ifdef GT64240_NAPI
++/*
++ * Function will release Tx skbs which are now complete
++ */
++static void gt64240_tx_fill(struct net_device *dev, u32 status)
++{
++	struct gt64240_private *gp = netdev_priv(dev);
++	int nextOut, cdp;
++	gt64240_td_t *td;
++	u32 cmdstat;
++
++	cdp = (GT64240ETH_READ(gp, GT64240_ETH_CURR_TX_DESC_PTR0)
++	       - gp->tx_ring_dma) / sizeof(gt64240_td_t);
++
++	for (nextOut = gp->tx_next_out; nextOut != cdp;
++	     nextOut = (nextOut + 1) % TX_RING_SIZE) {
++		if (--gp->intr_work_done == 0)
++			break;
++
++		td = &gp->tx_ring[nextOut];
++		cmdstat = td->cmdstat;
++
++		if (cmdstat & (u32) txOwn)
++			break;
++
++		if (gp->tx_full) {
++			gp->tx_full = 0;
++			if (gp->last_psr & psrLink) {
++				netif_wake_queue(dev);
++			}
++		}
++		// decrement tx ring buffer count
++		if (gp->tx_count)
++			gp->tx_count--;
++
++		// free the skb
++		if (gp->tx_skbuff[nextOut]) {
++			dev_kfree_skb_irq(gp->tx_skbuff[nextOut]);
++			gp->tx_skbuff[nextOut] = NULL;
++		}
++	}
++
++	gp->tx_next_out = nextOut;
++
++	if ((status & icrTxEndLow) && gp->tx_count != 0)
++		// we must restart the DMA
++		GT64240ETH_WRITE(gp, GT64240_ETH_SDMA_COMM,
++				 sdcmrERD | sdcmrTXDL);
++}
++
++/*
++ * Main function for NAPI
++ */
++static int gt64240_poll(struct net_device *dev, int *budget)
++{
++	struct gt64240_private *gp = netdev_priv(dev);
++	unsigned long flags;
++	int done = 1, orig_budget, work_done;
++	u32 status = GT64240ETH_READ(gp, GT64240_ETH_INT_CAUSE);
++
++	spin_lock_irqsave(&gp->lock, flags);
++	gt64240_tx_fill(dev, status);
++
++	if (GT64240ETH_READ(gp, GT64240_ETH_CURR_RX_DESC_PTR0) !=
++	    gp->rx_next_out) {
++		orig_budget = *budget;
++		if (orig_budget > dev->quota)
++			orig_budget = dev->quota;
++
++		work_done = gt64240_rx(dev, status, orig_budget);
++		*budget -= work_done;
++		dev->quota -= work_done;
++		if (work_done >= orig_budget)
++			done = 0;
++		if (done) {
++			__netif_rx_complete(dev);
++			enable_ether_irq(dev);
++		}
++	}
++
++	spin_unlock_irqrestore(&gp->lock, flags);
++
++	return (done ? 0 : 1);
++}
++#endif
++
++static int gt64240_tx(struct sk_buff *skb, struct net_device *dev)
++{
++	struct gt64240_private *gp = netdev_priv(dev);
++	unsigned long flags;
++	int nextIn;
++
++	spin_lock_irqsave(&gp->lock, flags);
++
++	nextIn = gp->tx_next_in;
++
++	if (gt64240_debug > 3) {
++		printk("%s: gt64240_tx: nextIn=%d.\n", dev->name, nextIn);
++	}
++
++	if (gp->tx_count >= TX_RING_SIZE) {
++		printk("%s: Tx Ring full, pkt dropped.\n", dev->name);
++		gp->stats.tx_dropped++;
++		spin_unlock_irqrestore(&gp->lock, flags);
++		return 1;
++	}
++
++	if (!(gp->last_psr & psrLink)) {
++		printk("%s: gt64240_tx: Link down, pkt dropped.\n",
++		       dev->name);
++		gp->stats.tx_dropped++;
++		spin_unlock_irqrestore(&gp->lock, flags);
++//---   dump_MII(dev);          /* KLUDGE ALERT !!! */
++		return 1;
++	}
++
++	if (gp->tx_ring[nextIn].cmdstat & txOwn) {
++		printk
++		    ("%s: gt64240_tx: device owns descriptor, pkt dropped.\n",
++		     dev->name);
++		gp->stats.tx_dropped++;
++		// stop the queue, so Tx timeout can fix it
++		netif_stop_queue(dev);
++		spin_unlock_irqrestore(&gp->lock, flags);
++		return 1;
++	}
++	// Prepare the Descriptor at tx_next_in
++	gp->tx_skbuff[nextIn] = skb;
++	gp->tx_ring[nextIn].byte_cnt = skb->len;
++	gp->tx_ring[nextIn].buff_ptr = virt_to_phys(skb->data);
++
++	// make sure packet gets written back to memory
++	dma_cache_wback_inv((unsigned long) (skb->data), skb->len);
++	mb();
++
++	// Give ownership to device, set first and last desc, enable interrupt
++	// Setting of ownership bit must be *last*!
++	gp->tx_ring[nextIn].cmdstat =
++	    txOwn | txGenCRC | txEI | txPad | txFirst | txLast;
++
++	if (gt64240_debug > 5) {
++		dump_tx_desc(dev, nextIn);
++	}
++	// increment tx_next_in with wrap
++	gp->tx_next_in = (nextIn + 1) % TX_RING_SIZE;
++
++//+prk20aug01:
++	if (0) {		/* ROLLINS */
++		GT64240ETH_WRITE(gp, GT64240_ETH_CURR_TX_DESC_PTR0,
++				 virt_to_phys(&gp->tx_ring[nextIn]));
++	}
++
++	if (gt64240_debug > 3) {	/*+prk17aug01 */
++		printk
++		    ("%s: gt64240_tx: TX_PTR0=0x%08x, EthPortStatus=0x%08x\n",
++		     dev->name, GT64240ETH_READ(gp,
++						GT64240_ETH_CURR_TX_DESC_PTR0),
++		     GT64240ETH_READ(gp, GT64240_ETH_PORT_STATUS));
++	}
++	// If DMA is stopped, restart
++	if (!((GT64240ETH_READ(gp, GT64240_ETH_PORT_STATUS)) & psrTxLow)) {
++		GT64240ETH_WRITE(gp, GT64240_ETH_SDMA_COMM,
++				 sdcmrERD | sdcmrTXDL);
++	}
++
++	if (gt64240_debug > 3) {	/*+prk17aug01 */
++		printk
++		    ("%s: gt64240_tx: TX_PTR0=0x%08x, EthPortStatus=0x%08x\n",
++		     dev->name, GT64240ETH_READ(gp,
++						GT64240_ETH_CURR_TX_DESC_PTR0),
++		     GT64240ETH_READ(gp, GT64240_ETH_PORT_STATUS));
++	}
++	// increment count and stop queue if full
++	if (++gp->tx_count >= TX_RING_SIZE) {
++		gp->tx_full = 1;
++		netif_stop_queue(dev);
++	}
++
++	dev->trans_start = jiffies;
++	spin_unlock_irqrestore(&gp->lock, flags);
++
++	return 0;
++}
++
++
++static int
++#ifdef GT64240_NAPI
++gt64240_rx(struct net_device *dev, u32 status, int budget)
++#else
++gt64240_rx(struct net_device *dev, u32 status)
++#endif
++{
++	struct gt64240_private *gp = netdev_priv(dev);
++	struct sk_buff *skb;
++	int pkt_len, nextOut, cdp;
++	gt64240_rd_t *rd;
++	u32 cmdstat;
++
++	if (gt64240_debug > 3)
++		printk("%s: gt64240_rx: dev=%p, status=%x\n",
++		       dev->name, dev, status);
++
++	cdp = (GT64240ETH_READ(gp, GT64240_ETH_CURR_RX_DESC_PTR0)
++	       - gp->rx_ring_dma) / sizeof(gt64240_rd_t);
++
++	// Continue until we reach the current descriptor pointer
++	for (nextOut = gp->rx_next_out; nextOut != cdp;
++	     nextOut = (nextOut + 1) % RX_RING_SIZE) {
++
++#ifdef GT64240_NAPI
++		if (budget <= 0)
++			break;
++
++		budget--;
++#endif
++
++		if (--gp->intr_work_done == 0)
++			break;
++
++		if (gt64240_debug > 4)
++			dump_rx_desc(dev, nextOut);
++
++		rd = &gp->rx_ring[nextOut];
++		cmdstat = rd->cmdstat;
++
++		if (gt64240_debug > 3)
++			printk("%s: isr: Rx desc cmdstat=%x, nextOut=%d\n",
++			       dev->name, cmdstat, nextOut);
++
++		if (cmdstat & (u32) rxOwn) {
++			if (gt64240_debug > 2)
++				printk
++				    ("%s: gt64240_rx: device owns descriptor!\n",
++				     dev->name);
++			// DMA is not finished updating descriptor???
++			// Leave and come back later to pick-up where we left off.
++			break;
++		}
++		// must be first and last (ie only) buffer of packet
++		if (!(cmdstat & (u32) rxFirst)
++		    || !(cmdstat & (u32) rxLast)) {
++			printk
++			    ("%s: gt64240_rx: desc not first and last!\n",
++			     dev->name);
++			cmdstat |= (u32) rxOwn;
++			rd->cmdstat = cmdstat;
++			continue;
++		}
++		// Drop this received pkt if there were any errors
++		if ((cmdstat & (u32) rxErrorSummary)
++		    || (status & icrRxError)) {
++			// update the detailed rx error counters that are not covered
++			// by the MIB counters.
++			if (cmdstat & (u32) rxOverrun)
++				gp->stats.rx_fifo_errors++;
++			cmdstat |= (u32) rxOwn;
++			rd->cmdstat = cmdstat;
++			continue;
++		}
++
++		pkt_len = rd->byte_cnt;
++
++		/* Create new skb. */
++//      skb = dev_alloc_skb(pkt_len+2);
++		skb = dev_alloc_skb(1538);
++		if (skb == NULL) {
++			printk("%s: Memory squeeze, dropping packet.\n",
++			       dev->name);
++			gp->stats.rx_dropped++;
++			cmdstat |= (u32) rxOwn;
++			rd->cmdstat = cmdstat;
++			continue;
++		}
++		skb->dev = dev;
++		skb_reserve(skb, 2);	/* 16 byte IP header align */
++		memcpy(skb_put(skb, pkt_len),
++		       &gp->rx_buff[nextOut * PKT_BUF_SZ], pkt_len);
++		skb->protocol = eth_type_trans(skb, dev);
++
++		/* NIC performed some checksum computation */
++		skb->ip_summed = CHECKSUM_UNNECESSARY;
++#ifdef GT64240_NAPI
++		netif_receive_skb(skb);
++#else
++		netif_rx(skb);	/* pass the packet to upper layers */
++#endif
++
++		// now we can release ownership of this desc back to device
++		cmdstat |= (u32) rxOwn;
++		rd->cmdstat = cmdstat;
++
++		dev->last_rx = jiffies;
++	}
++
++	if (gt64240_debug > 3 && nextOut == gp->rx_next_out)
++		printk("%s: gt64240_rx: RxCDP did not increment?\n",
++		       dev->name);
++
++	gp->rx_next_out = nextOut;
++	return 0;
++}
++
++
++static void gt64240_tx_timeout(struct net_device *dev)
++{
++	struct gt64240_private *gp = netdev_priv(dev);
++	unsigned long flags;
++
++	spin_lock_irqsave(&gp->lock, flags);
++
++
++	if (!(gp->last_psr & psrLink)) {
++		spin_unlock_irqrestore(&gp->lock, flags);
++	} else {
++		printk("======------> gt64240_tx_timeout: %d jiffies \n",
++		       GT64240ETH_TX_TIMEOUT);
++
++		disable_ether_irq(dev);
++		spin_unlock_irqrestore(&gp->lock, flags);
++		reset_tx(dev);
++		enable_ether_irq(dev);
++
++		netif_wake_queue(dev);
++	}
++}
++
++
++static void gt64240_set_rx_mode(struct net_device *dev)
++{
++	struct gt64240_private *gp = netdev_priv(dev);
++	unsigned long flags;
++	struct dev_mc_list *mcptr;
++
++	if (gt64240_debug > 3)
++		printk("%s: gt64240_set_rx_mode: dev=%p, flags=%x\n",
++		       dev->name, dev, dev->flags);
++
++	// stop the Receiver DMA
++	abort(dev, sdcmrAR);
++
++	spin_lock_irqsave(&gp->lock, flags);
++
++	if (dev->flags & IFF_PROMISC)
++		GT64240ETH_SETBIT(gp, GT64240_ETH_PORT_CONFIG, pcrPM);
++	else
++		GT64240ETH_CLRBIT(gp, GT64240_ETH_PORT_CONFIG, pcrPM);
++/*
++	GT64240ETH_WRITE(gp, GT64240_ETH_PORT_CONFIG,
++		(PORT_CONFIG | pcrPM | pcrEN));
++*/
++
++	memset(gp->hash_table, 0, RX_HASH_TABLE_SIZE);	// clear hash table
++	// Add our ethernet address
++	gt64240_add_hash_entry(dev, dev->dev_addr);
++	if (dev->mc_count) {
++		for (mcptr = dev->mc_list; mcptr; mcptr = mcptr->next) {
++			if (gt64240_debug > 2) {
++				printk("%s: gt64240_set_rx_mode: addr=\n",
++				       dev->name);
++				dump_hw_addr(mcptr->dmi_addr);
++			}
++			gt64240_add_hash_entry(dev, mcptr->dmi_addr);
++		}
++	}
++
++	if (gt64240_debug > 3)
++		printk("%s: gt64240_set_rx: Port Config=%x\n", dev->name,
++		       GT64240ETH_READ(gp, GT64240_ETH_PORT_CONFIG));
++
++	// restart Rx DMA
++	GT64240ETH_WRITE(gp, GT64240_ETH_SDMA_COMM, sdcmrERD);
++
++	spin_unlock_irqrestore(&gp->lock, flags);
++}
++
++static struct net_device_stats *gt64240_get_stats(struct net_device *dev)
++{
++	struct gt64240_private *gp = netdev_priv(dev);
++	unsigned long flags;
++
++	if (gt64240_debug > 3)
++		printk("%s: gt64240_get_stats: dev=%p\n", dev->name, dev);
++
++	if (netif_device_present(dev)) {
++		spin_lock_irqsave(&gp->lock, flags);
++		update_stats(gp);
++		spin_unlock_irqrestore(&gp->lock, flags);
++	}
++
++	return &gp->stats;
++}
+diff -Naur linux-2.6.15.orig/drivers/net/gt64240eth.h linux-2.6.15/drivers/net/gt64240eth.h
+--- linux-2.6.15.orig/drivers/net/gt64240eth.h	2006-01-03 03:21:10.000000000 +0000
++++ linux-2.6.15/drivers/net/gt64240eth.h	2006-01-09 19:54:12.000000000 +0000
+@@ -9,6 +9,7 @@
+  * Copyright 2000 MontaVista Software Inc.
+  * Author: MontaVista Software, Inc.
+  *         	stevel at mvista.com or support at mvista.com
++ * Copyright 2004, 05 Ralf Baechle (ralf at linux-mips.org)
+  *
+  *  This program is free software; you can distribute it and/or modify it
+  *  under the terms of the GNU General Public License (Version 2) as
+@@ -31,6 +32,7 @@
+ #ifndef _GT64240ETH_H
+ #define _GT64240ETH_H
+ 
++#include <linux/config.h>
+ #include <asm/gt64240.h>
+ 
+ #define ETHERNET_PORTS_DIFFERENCE_OFFSETS	0x400
+@@ -108,10 +110,10 @@
+ #define REV_GT64240A 0x10
+ 
+ #define GT64240ETH_READ(gp, offset)					\
+-	GT_READ((gp)->port_offset + (offset))
++	MV_READ((gp)->port_offset + (offset))
+ 
+ #define GT64240ETH_WRITE(gp, offset, data)				\
+-	GT_WRITE((gp)->port_offset + (offset), (data))
++	MV_WRITE((gp)->port_offset + (offset), (data))
+ 
+ #define GT64240ETH_SETBIT(gp, offset, bits)				\
+ 	GT64240ETH_WRITE((gp), (offset),				\
+@@ -121,8 +123,8 @@
+ 	GT64240ETH_WRITE((gp), (offset),				\
+ 	                 GT64240ETH_READ((gp), (offset)) & ~(bits))
+ 
+-#define GT64240_READ(ofs)		GT_READ(ofs)
+-#define GT64240_WRITE(ofs, data)	GT_WRITE((ofs), (data))
++#define GT64240_READ(ofs)		MV_READ(ofs)
++#define GT64240_WRITE(ofs, data)	MV_WRITE((ofs), (data))
+ 
+ /* Bit definitions of the SMI Reg */
+ enum {
+diff -Naur linux-2.6.15.orig/drivers/net/sb1250-mac.c linux-2.6.15/drivers/net/sb1250-mac.c
+--- linux-2.6.15.orig/drivers/net/sb1250-mac.c	2006-01-03 03:21:10.000000000 +0000
++++ linux-2.6.15/drivers/net/sb1250-mac.c	2006-01-09 19:54:13.000000000 +0000
+@@ -1,5 +1,5 @@
+ /*
+- * Copyright (C) 2001,2002,2003 Broadcom Corporation
++ * Copyright (C) 2001,2002,2003,2004 Broadcom Corporation
+  *
+  * This program is free software; you can redistribute it and/or
+  * modify it under the terms of the GNU General Public License
+@@ -43,6 +43,7 @@
+ #define SBMAC_ETH0_HWADDR "40:00:00:00:01:00"
+ #define SBMAC_ETH1_HWADDR "40:00:00:00:01:01"
+ #define SBMAC_ETH2_HWADDR "40:00:00:00:01:02"
++#define SBMAC_ETH3_HWADDR "40:00:00:00:01:03"
+ #endif
+ 
+ 
+@@ -57,7 +58,7 @@
+ 
+ #define CONFIG_SBMAC_COALESCE
+ 
+-#define MAX_UNITS 3		/* More are supported, limit only on options */
++#define MAX_UNITS 4		/* More are supported, limit only on options */
+ 
+ /* Time in jiffies before concluding the transmitter is hung. */
+ #define TX_TIMEOUT  (2*HZ)
+@@ -85,11 +86,11 @@
+    The media type is usually passed in 'options[]'.
+ */
+ #ifdef MODULE
+-static int options[MAX_UNITS] = {-1, -1, -1};
++static int options[MAX_UNITS] = {-1, -1, -1, -1};
+ module_param_array(options, int, NULL, S_IRUGO);
+ MODULE_PARM_DESC(options, "1-" __MODULE_STRING(MAX_UNITS));
+ 
+-static int full_duplex[MAX_UNITS] = {-1, -1, -1};
++static int full_duplex[MAX_UNITS] = {-1, -1, -1, -1};
+ module_param_array(full_duplex, int, NULL, S_IRUGO);
+ MODULE_PARM_DESC(full_duplex, "1-" __MODULE_STRING(MAX_UNITS));
+ #endif
+@@ -105,13 +106,26 @@
+ #endif
+ 
+ #include <asm/sibyte/sb1250.h>
+-#include <asm/sibyte/sb1250_defs.h>
++#if defined(CONFIG_SIBYTE_BCM1x55) || defined(CONFIG_SIBYTE_BCM1x80)
++#include <asm/sibyte/bcm1480_regs.h>
++#include <asm/sibyte/bcm1480_int.h>
++#elif defined(CONFIG_SIBYTE_SB1250) || defined(CONFIG_SIBYTE_BCM112X)
+ #include <asm/sibyte/sb1250_regs.h>
+-#include <asm/sibyte/sb1250_mac.h>
+-#include <asm/sibyte/sb1250_dma.h>
+ #include <asm/sibyte/sb1250_int.h>
++#else
++#error invalid SiByte MAC configuation
++#endif
+ #include <asm/sibyte/sb1250_scd.h>
++#include <asm/sibyte/sb1250_mac.h>
++#include <asm/sibyte/sb1250_dma.h>
+ 
++#if defined(CONFIG_SIBYTE_BCM1x55) || defined(CONFIG_SIBYTE_BCM1x80)
++#define UNIT_INT(n)		(K_BCM1480_INT_MAC_0 + ((n) * 2))
++#elif defined(CONFIG_SIBYTE_SB1250) || defined(CONFIG_SIBYTE_BCM112X)
++#define UNIT_INT(n)		(K_INT_MAC_0 + (n))
++#else
++#error invalid SiByte MAC configuation
++#endif
+ 
+ /**********************************************************************
+  *  Simple types
+@@ -142,6 +156,10 @@
+ 
+ #define NUMCACHEBLKS(x) (((x)+SMP_CACHE_BYTES-1)/SMP_CACHE_BYTES)
+ 
++#define SBMAC_READCSR(t)	__raw_readq((unsigned long)t)
++#define SBMAC_WRITECSR(t,v)	__raw_writeq(v, (unsigned long)t)
++
++
+ #define SBMAC_MAX_TXDESCR	32
+ #define SBMAC_MAX_RXDESCR	32
+ 
+@@ -1476,10 +1494,10 @@
+ 	 * and make sure that RD_THRSH + WR_THRSH <=128 for pass2 and above
+ 	 * Use a larger RD_THRSH for gigabit
+ 	 */
+-	if (periph_rev >= 2)
+-		th_value = 64;
+-	else
++	if (soc_type == K_SYS_SOC_TYPE_BCM1250 && periph_rev < 2)
+ 		th_value = 28;
++	else
++		th_value = 64;
+ 
+ 	fifo = V_MAC_TX_WR_THRSH(4) |	/* Must be '4' or '8' */
+ 		((s->sbm_speed == sbmac_speed_1000)
+@@ -1589,13 +1607,17 @@
+ 	 * Turn on the rest of the bits in the enable register
+ 	 */
+ 
++#if defined(CONFIG_SIBYTE_BCM1x55) || defined(CONFIG_SIBYTE_BCM1x80)
++	__raw_writeq(M_MAC_RXDMA_EN0 |
++		       M_MAC_TXDMA_EN0, s->sbm_macenable);
++#elif defined(CONFIG_SIBYTE_SB1250) || defined(CONFIG_SIBYTE_BCM112X)
+ 	__raw_writeq(M_MAC_RXDMA_EN0 |
+ 		       M_MAC_TXDMA_EN0 |
+ 		       M_MAC_RX_ENABLE |
+ 		       M_MAC_TX_ENABLE, s->sbm_macenable);
+-
+-
+-
++#else
++#error invalid SiByte MAC configuation
++#endif
+ 
+ #ifdef CONFIG_SBMAC_COALESCE
+ 	/*
+@@ -1786,11 +1808,12 @@
+ 	reg &= ~M_MAC_IPHDR_OFFSET | V_MAC_IPHDR_OFFSET(15);
+ 	__raw_writeq(reg, sc->sbm_rxfilter);
+ 
+-	/* read system identification to determine revision */
+-	if (periph_rev >= 2) {
+-		sc->rx_hw_checksum = ENABLE;
+-	} else {
++	/* BCM1250 pass1 didn't have hardware checksum.  Everything
++	   later does.  */
++	if (soc_type == K_SYS_SOC_TYPE_BCM1250 && periph_rev < 2) {
+ 		sc->rx_hw_checksum = DISABLE;
++	} else {
++		sc->rx_hw_checksum = ENABLE;
+ 	}
+ }
+ 
+@@ -2220,7 +2243,7 @@
+ 
+ 
+ 
+-#if defined(SBMAC_ETH0_HWADDR) || defined(SBMAC_ETH1_HWADDR) || defined(SBMAC_ETH2_HWADDR)
++#if defined(SBMAC_ETH0_HWADDR) || defined(SBMAC_ETH1_HWADDR) || defined(SBMAC_ETH2_HWADDR) || defined(SBMAC_ETH3_HWADDR)
+ /**********************************************************************
+  *  SBMAC_PARSE_XDIGIT(str)
+  *
+@@ -2397,6 +2420,11 @@
+ 			sc->sbm_dev->name);
+ 	}
+ 
++	if (periph_rev >= 2) {
++		printk(KERN_INFO "%s: enabling TCP rcv checksum\n",
++			sc->sbm_dev->name);
++	}
++
+ 	/*
+ 	 * Display Ethernet address (this is called during the config
+ 	 * process so we need to finish off the config message that
+@@ -2792,7 +2820,7 @@
+ 
+ 
+ 
+-#if defined(SBMAC_ETH0_HWADDR) || defined(SBMAC_ETH1_HWADDR) || defined(SBMAC_ETH2_HWADDR)
++#if defined(SBMAC_ETH0_HWADDR) || defined(SBMAC_ETH1_HWADDR) || defined(SBMAC_ETH2_HWADDR) || defined(SBMAC_ETH3_HWADDR)
+ static void
+ sbmac_setup_hwaddr(int chan,char *addr)
+ {
+@@ -2818,25 +2846,7 @@
+ 	unsigned long port;
+ 	int chip_max_units;
+ 
+-	/*
+-	 * For bringup when not using the firmware, we can pre-fill
+-	 * the MAC addresses using the environment variables
+-	 * specified in this file (or maybe from the config file?)
+-	 */
+-#ifdef SBMAC_ETH0_HWADDR
+-	sbmac_setup_hwaddr(0,SBMAC_ETH0_HWADDR);
+-#endif
+-#ifdef SBMAC_ETH1_HWADDR
+-	sbmac_setup_hwaddr(1,SBMAC_ETH1_HWADDR);
+-#endif
+-#ifdef SBMAC_ETH2_HWADDR
+-	sbmac_setup_hwaddr(2,SBMAC_ETH2_HWADDR);
+-#endif
+-
+-	/*
+-	 * Walk through the Ethernet controllers and find
+-	 * those who have their MAC addresses set.
+-	 */
++	/* Set the number of available units based on the SOC type.  */
+ 	switch (soc_type) {
+ 	case K_SYS_SOC_TYPE_BCM1250:
+ 	case K_SYS_SOC_TYPE_BCM1250_ALT:
+@@ -2848,6 +2858,10 @@
+ 	case K_SYS_SOC_TYPE_BCM1250_ALT2: /* Hybrid */
+ 		chip_max_units = 2;
+ 		break;
++	case K_SYS_SOC_TYPE_BCM1x55:
++	case K_SYS_SOC_TYPE_BCM1x80:
++		chip_max_units = 4;
++		break;
+ 	default:
+ 		chip_max_units = 0;
+ 		break;
+@@ -2855,6 +2869,32 @@
+ 	if (chip_max_units > MAX_UNITS)
+ 		chip_max_units = MAX_UNITS;
+ 
++	/*
++	 * For bringup when not using the firmware, we can pre-fill
++	 * the MAC addresses using the environment variables
++	 * specified in this file (or maybe from the config file?)
++	 */
++#ifdef SBMAC_ETH0_HWADDR
++	if (chip_max_units > 0)
++	  sbmac_setup_hwaddr(0,SBMAC_ETH0_HWADDR);
++#endif
++#ifdef SBMAC_ETH1_HWADDR
++	if (chip_max_units > 1)
++	  sbmac_setup_hwaddr(1,SBMAC_ETH1_HWADDR);
++#endif
++#ifdef SBMAC_ETH2_HWADDR
++	if (chip_max_units > 2)
++	  sbmac_setup_hwaddr(2,SBMAC_ETH2_HWADDR);
++#endif
++#ifdef SBMAC_ETH3_HWADDR
++	if (chip_max_units > 3)
++	  sbmac_setup_hwaddr(3,SBMAC_ETH3_HWADDR);
++#endif
++
++	/*
++	 * Walk through the Ethernet controllers and find
++	 * those who have their MAC addresses set.
++	 */
+ 	for (idx = 0; idx < chip_max_units; idx++) {
+ 
+ 	        /*
+@@ -2886,7 +2926,7 @@
+ 
+ 		printk(KERN_DEBUG "sbmac: configuring MAC at %lx\n", port);
+ 
+-		dev->irq = K_INT_MAC_0 + idx;
++		dev->irq = UNIT_INT(idx);
+ 		dev->base_addr = port;
+ 		dev->mem_end = 0;
+ 		if (sbmac_init(dev, idx)) {
+diff -Naur linux-2.6.15.orig/drivers/net/titan_ge.c linux-2.6.15/drivers/net/titan_ge.c
+--- linux-2.6.15.orig/drivers/net/titan_ge.c	1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.15/drivers/net/titan_ge.c	2006-01-09 19:54:13.000000000 +0000
+@@ -0,0 +1,2071 @@
++/*
++ * drivers/net/titan_ge.c - Driver for Titan ethernet ports
++ *
++ * Copyright (C) 2003 PMC-Sierra Inc.
++ * Author : Manish Lachwani (lachwani at pmc-sierra.com)
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * as published by the Free Software Foundation; either version 2
++ * of the License, or (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
++ */
++
++/*
++ * The MAC unit of the Titan consists of the following:
++ *
++ * -> XDMA Engine to move data to from the memory to the MAC packet FIFO
++ * -> FIFO is where the incoming and outgoing data is placed
++ * -> TRTG is the unit that pulls the data from the FIFO for Tx and pushes
++ *    the data into the FIFO for Rx
++ * -> TMAC is the outgoing MAC interface and RMAC is the incoming.
++ * -> AFX is the address filtering block
++ * -> GMII block to communicate with the PHY
++ *
++ * Rx will look like the following:
++ * GMII --> RMAC --> AFX --> TRTG --> Rx FIFO --> XDMA --> CPU memory
++ *
++ * Tx will look like the following:
++ * CPU memory --> XDMA --> Tx FIFO --> TRTG --> TMAC --> GMII
++ *
++ * The Titan driver has support for the following performance features:
++ * -> Rx side checksumming
++ * -> Jumbo Frames
++ * -> Interrupt Coalscing
++ * -> Rx NAPI
++ * -> SKB Recycling
++ * -> Transmit/Receive descriptors in SRAM
++ * -> Fast routing for IP forwarding
++ */
++
++#include <linux/config.h>
++#include <linux/dma-mapping.h>
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/sched.h>
++#include <linux/ioport.h>
++#include <linux/interrupt.h>
++#include <linux/slab.h>
++#include <linux/string.h>
++#include <linux/errno.h>
++#include <linux/ip.h>
++#include <linux/init.h>
++#include <linux/in.h>
++#include <linux/platform_device.h>
++#include <linux/netdevice.h>
++#include <linux/etherdevice.h>
++#include <linux/skbuff.h>
++#include <linux/mii.h>
++#include <linux/delay.h>
++#include <linux/skbuff.h>
++#include <linux/prefetch.h>
++
++/* For MII specifc registers, titan_mdio.h should be included */
++#include <net/ip.h>
++
++#include <asm/bitops.h>
++#include <asm/io.h>
++#include <asm/types.h>
++#include <asm/pgtable.h>
++#include <asm/system.h>
++#include <asm/titan_dep.h>
++
++#include "titan_ge.h"
++#include "titan_mdio.h"
++
++/* Static Function Declarations	 */
++static int titan_ge_eth_open(struct net_device *);
++static void titan_ge_eth_stop(struct net_device *);
++static struct net_device_stats *titan_ge_get_stats(struct net_device *);
++static int titan_ge_init_rx_desc_ring(titan_ge_port_info *, int, int,
++				      unsigned long, unsigned long,
++				      unsigned long);
++static int titan_ge_init_tx_desc_ring(titan_ge_port_info *, int,
++				      unsigned long, unsigned long);
++
++static int titan_ge_open(struct net_device *);
++static int titan_ge_start_xmit(struct sk_buff *, struct net_device *);
++static int titan_ge_stop(struct net_device *);
++
++static unsigned long titan_ge_tx_coal(unsigned long, int);
++
++static void titan_ge_port_reset(unsigned int);
++static int titan_ge_free_tx_queue(titan_ge_port_info *);
++static int titan_ge_rx_task(struct net_device *, titan_ge_port_info *);
++static int titan_ge_port_start(struct net_device *, titan_ge_port_info *);
++
++static int titan_ge_return_tx_desc(titan_ge_port_info *, int);
++
++/*
++ * Some configuration for the FIFO and the XDMA channel needs
++ * to be done only once for all the ports. This flag controls
++ * that
++ */
++static unsigned long config_done;
++
++/*
++ * One time out of memory flag
++ */
++static unsigned int oom_flag;
++
++static int titan_ge_poll(struct net_device *netdev, int *budget);
++
++static int titan_ge_receive_queue(struct net_device *, unsigned int);
++
++static struct platform_device *titan_ge_device[3];
++
++/* MAC Address */
++extern unsigned char titan_ge_mac_addr_base[6];
++
++unsigned long titan_ge_base;
++static unsigned long titan_ge_sram;
++
++static char titan_string[] = "titan";
++
++/*
++ * The Titan GE has two alignment requirements:
++ * -> skb->data to be cacheline aligned (32 byte)
++ * -> IP header alignment to 16 bytes
++ *
++ * The latter is not implemented. So, that results in an extra copy on
++ * the Rx. This is a big performance hog. For the former case, the
++ * dev_alloc_skb() has been replaced with titan_ge_alloc_skb(). The size
++ * requested is calculated:
++ *
++ * Ethernet Frame Size : 1518
++ * Ethernet Header     : 14
++ * Future Titan change for IP header alignment : 2
++ *
++ * Hence, we allocate (1518 + 14 + 2+ 64) = 1580 bytes.  For IP header
++ * alignment, we use skb_reserve().
++ */
++
++#define ALIGNED_RX_SKB_ADDR(addr) \
++	((((unsigned long)(addr) + (64UL - 1UL)) \
++	& ~(64UL - 1UL)) - (unsigned long)(addr))
++
++#define titan_ge_alloc_skb(__length, __gfp_flags) \
++({      struct sk_buff *__skb; \
++	__skb = alloc_skb((__length) + 64, (__gfp_flags)); \
++	if(__skb) { \
++		int __offset = (int) ALIGNED_RX_SKB_ADDR(__skb->data); \
++		if(__offset) \
++			skb_reserve(__skb, __offset); \
++	} \
++	__skb; \
++})
++
++/*
++ * Configure the GMII block of the Titan based on what the PHY tells us
++ */
++static void titan_ge_gmii_config(int port_num)
++{
++	unsigned int reg_data = 0, phy_reg;
++	int err;
++
++	err = titan_ge_mdio_read(port_num, TITAN_GE_MDIO_PHY_STATUS, &phy_reg);
++
++	if (err == TITAN_GE_MDIO_ERROR) {
++		printk(KERN_ERR
++		       "Could not read PHY control register 0x11 \n");
++		printk(KERN_ERR
++			"Setting speed to 1000 Mbps and Duplex to Full \n");
++
++		return;
++	}
++
++	err = titan_ge_mdio_write(port_num, TITAN_GE_MDIO_PHY_IE, 0);
++
++	if (phy_reg & 0x8000) {
++		if (phy_reg & 0x2000) {
++			/* Full Duplex and 1000 Mbps */
++			TITAN_GE_WRITE((TITAN_GE_GMII_CONFIG_MODE +
++					(port_num << 12)), 0x201);
++		}  else {
++			/* Half Duplex and 1000 Mbps */
++			TITAN_GE_WRITE((TITAN_GE_GMII_CONFIG_MODE +
++					(port_num << 12)), 0x2201);
++			}
++	}
++	if (phy_reg & 0x4000) {
++		if (phy_reg & 0x2000) {
++			/* Full Duplex and 100 Mbps */
++			TITAN_GE_WRITE((TITAN_GE_GMII_CONFIG_MODE +
++					(port_num << 12)), 0x100);
++		} else {
++			/* Half Duplex and 100 Mbps */
++			TITAN_GE_WRITE((TITAN_GE_GMII_CONFIG_MODE +
++					(port_num << 12)), 0x2100);
++		}
++	}
++	reg_data = TITAN_GE_READ(TITAN_GE_GMII_CONFIG_GENERAL +
++				(port_num << 12));
++	reg_data |= 0x3;
++	TITAN_GE_WRITE((TITAN_GE_GMII_CONFIG_GENERAL +
++			(port_num << 12)), reg_data);
++}
++
++/*
++ * Enable the TMAC if it is not
++ */
++static void titan_ge_enable_tx(unsigned int port_num)
++{
++	unsigned long reg_data;
++
++	reg_data = TITAN_GE_READ(TITAN_GE_TMAC_CONFIG_1 + (port_num << 12));
++	if (!(reg_data & 0x8000)) {
++		printk("TMAC disabled for port %d!! \n", port_num);
++
++		reg_data |= 0x0001;	/* Enable TMAC */
++		reg_data |= 0x4000;	/* CRC Check Enable */
++		reg_data |= 0x2000;	/* Padding enable */
++		reg_data |= 0x0800;	/* CRC Add enable */
++		reg_data |= 0x0080;	/* PAUSE frame */
++
++		TITAN_GE_WRITE((TITAN_GE_TMAC_CONFIG_1 +
++				(port_num << 12)), reg_data);
++	}
++}
++
++/*
++ * Tx Timeout function
++ */
++static void titan_ge_tx_timeout(struct net_device *netdev)
++{
++	titan_ge_port_info *titan_ge_eth = netdev_priv(netdev);
++
++	printk(KERN_INFO "%s: TX timeout  ", netdev->name);
++	printk(KERN_INFO "Resetting card \n");
++
++	/* Do the reset outside of interrupt context */
++	schedule_work(&titan_ge_eth->tx_timeout_task);
++}
++
++/*
++ * Update the AFX tables for UC and MC for slice 0 only
++ */
++static void titan_ge_update_afx(titan_ge_port_info * titan_ge_eth)
++{
++	int port = titan_ge_eth->port_num;
++	unsigned int i;
++	volatile unsigned long reg_data = 0;
++	u8 p_addr[6];
++
++	memcpy(p_addr, titan_ge_eth->port_mac_addr, 6);
++
++	/* Set the MAC address here for TMAC and RMAC */
++	TITAN_GE_WRITE((TITAN_GE_TMAC_STATION_HI + (port << 12)),
++		       ((p_addr[5] << 8) | p_addr[4]));
++	TITAN_GE_WRITE((TITAN_GE_TMAC_STATION_MID + (port << 12)),
++		       ((p_addr[3] << 8) | p_addr[2]));
++	TITAN_GE_WRITE((TITAN_GE_TMAC_STATION_LOW + (port << 12)),
++		       ((p_addr[1] << 8) | p_addr[0]));
++
++	TITAN_GE_WRITE((TITAN_GE_RMAC_STATION_HI + (port << 12)),
++		       ((p_addr[5] << 8) | p_addr[4]));
++	TITAN_GE_WRITE((TITAN_GE_RMAC_STATION_MID + (port << 12)),
++		       ((p_addr[3] << 8) | p_addr[2]));
++	TITAN_GE_WRITE((TITAN_GE_RMAC_STATION_LOW + (port << 12)),
++		       ((p_addr[1] << 8) | p_addr[0]));
++
++	TITAN_GE_WRITE((0x112c | (port << 12)), 0x1);
++	/* Configure the eight address filters */
++	for (i = 0; i < 8; i++) {
++		/* Select each of the eight filters */
++		TITAN_GE_WRITE((TITAN_GE_AFX_ADDRS_FILTER_CTRL_2 +
++				(port << 12)), i);
++
++		/* Configure the match */
++		reg_data = 0x9;	/* Forward Enable Bit */
++		TITAN_GE_WRITE((TITAN_GE_AFX_ADDRS_FILTER_CTRL_0 +
++				(port << 12)), reg_data);
++
++		/* Finally, AFX Exact Match Address Registers */
++		TITAN_GE_WRITE((TITAN_GE_AFX_EXACT_MATCH_LOW + (port << 12)),
++			       ((p_addr[1] << 8) | p_addr[0]));
++		TITAN_GE_WRITE((TITAN_GE_AFX_EXACT_MATCH_MID + (port << 12)),
++			       ((p_addr[3] << 8) | p_addr[2]));
++		TITAN_GE_WRITE((TITAN_GE_AFX_EXACT_MATCH_HIGH + (port << 12)),
++			       ((p_addr[5] << 8) | p_addr[4]));
++
++		/* VLAN id set to 0 */
++		TITAN_GE_WRITE((TITAN_GE_AFX_EXACT_MATCH_VID +
++				(port << 12)), 0);
++	}
++}
++
++/*
++ * Actual Routine to reset the adapter when the timeout occurred
++ */
++static void titan_ge_tx_timeout_task(struct net_device *netdev)
++{
++	titan_ge_port_info *titan_ge_eth = netdev_priv(netdev);
++	int port = titan_ge_eth->port_num;
++
++	printk("Titan GE: Transmit timed out. Resetting ... \n");
++
++	/* Dump debug info */
++	printk(KERN_ERR "TRTG cause : %x \n",
++			TITAN_GE_READ(0x100c + (port << 12)));
++
++	/* Fix this for the other ports */
++	printk(KERN_ERR "FIFO cause : %x \n", TITAN_GE_READ(0x482c));
++	printk(KERN_ERR "IE cause : %x \n", TITAN_GE_READ(0x0040));
++	printk(KERN_ERR "XDMA GDI ERROR : %x \n",
++			TITAN_GE_READ(0x5008 + (port << 8)));
++	printk(KERN_ERR "CHANNEL ERROR: %x \n",
++			TITAN_GE_READ(TITAN_GE_CHANNEL0_INTERRUPT
++						+ (port << 8)));
++
++	netif_device_detach(netdev);
++	titan_ge_port_reset(titan_ge_eth->port_num);
++	titan_ge_port_start(netdev, titan_ge_eth);
++	netif_device_attach(netdev);
++}
++
++/*
++ * Change the MTU of the Ethernet Device
++ */
++static int titan_ge_change_mtu(struct net_device *netdev, int new_mtu)
++{
++	titan_ge_port_info *titan_ge_eth = netdev_priv(netdev);
++	unsigned long flags;
++
++	if ((new_mtu > 9500) || (new_mtu < 64))
++		return -EINVAL;
++
++	spin_lock_irqsave(&titan_ge_eth->lock, flags);
++
++	netdev->mtu = new_mtu;
++
++	/* Now we have to reopen the interface so that SKBs with the new
++	 * size will be allocated */
++
++	if (netif_running(netdev)) {
++		titan_ge_eth_stop(netdev);
++
++		if (titan_ge_eth_open(netdev) != TITAN_OK) {
++			printk(KERN_ERR
++			       "%s: Fatal error on opening device\n",
++			       netdev->name);
++			spin_unlock_irqrestore(&titan_ge_eth->lock, flags);
++			return -1;
++		}
++	}
++
++	spin_unlock_irqrestore(&titan_ge_eth->lock, flags);
++	return 0;
++}
++
++/*
++ * Titan Gbe Interrupt Handler. All the three ports send interrupt to one line
++ * only. Once an interrupt is triggered, figure out the port and then check
++ * the channel.
++ */
++static irqreturn_t titan_ge_int_handler(int irq, void *dev_id,
++	struct pt_regs *regs)
++{
++	struct net_device *netdev = (struct net_device *) dev_id;
++	titan_ge_port_info *titan_ge_eth = netdev_priv(netdev);
++	unsigned int port_num = titan_ge_eth->port_num;
++	unsigned int reg_data;
++	unsigned int eth_int_cause_error = 0, is;
++	unsigned long eth_int_cause1;
++	int err = 0;
++#ifdef CONFIG_SMP
++	unsigned long eth_int_cause2;
++#endif
++
++	/* Ack the CPU interrupt */
++	switch (port_num) {
++	case 0:
++		is = OCD_READ(RM9000x2_OCD_INTP0STATUS1);
++		OCD_WRITE(RM9000x2_OCD_INTP0CLEAR1, is);
++
++#ifdef CONFIG_SMP
++		is = OCD_READ(RM9000x2_OCD_INTP1STATUS1);
++		OCD_WRITE(RM9000x2_OCD_INTP1CLEAR1, is);
++#endif
++		break;
++
++	case 1:
++		is = OCD_READ(RM9000x2_OCD_INTP0STATUS0);
++		OCD_WRITE(RM9000x2_OCD_INTP0CLEAR0, is);
++
++#ifdef CONFIG_SMP
++		is = OCD_READ(RM9000x2_OCD_INTP1STATUS0);
++		OCD_WRITE(RM9000x2_OCD_INTP1CLEAR0, is);
++#endif
++		break;
++
++	case 2:
++		is = OCD_READ(RM9000x2_OCD_INTP0STATUS4);
++		OCD_WRITE(RM9000x2_OCD_INTP0CLEAR4, is);
++
++#ifdef CONFIG_SMP
++		is = OCD_READ(RM9000x2_OCD_INTP1STATUS4);
++		OCD_WRITE(RM9000x2_OCD_INTP1CLEAR4, is);
++#endif
++	}
++
++	eth_int_cause1 = TITAN_GE_READ(TITAN_GE_INTR_XDMA_CORE_A);
++#ifdef CONFIG_SMP
++	eth_int_cause2 = TITAN_GE_READ(TITAN_GE_INTR_XDMA_CORE_B);
++#endif
++
++	/* Spurious interrupt */
++#ifdef CONFIG_SMP
++	if ( (eth_int_cause1 == 0) && (eth_int_cause2 == 0)) {
++#else
++	if (eth_int_cause1 == 0) {
++#endif
++		eth_int_cause_error = TITAN_GE_READ(TITAN_GE_CHANNEL0_INTERRUPT +
++					(port_num << 8));
++
++		if (eth_int_cause_error == 0)
++			return IRQ_NONE;
++	}
++
++	/* Handle Tx first. No need to ack interrupts */
++#ifdef CONFIG_SMP
++	if ( (eth_int_cause1 & 0x20202) ||
++		(eth_int_cause2 & 0x20202) )
++#else
++	if (eth_int_cause1 & 0x20202)
++#endif
++		titan_ge_free_tx_queue(titan_ge_eth);
++
++	/* Handle the Rx next */
++#ifdef CONFIG_SMP
++	if ( (eth_int_cause1 & 0x10101) ||
++		(eth_int_cause2 & 0x10101)) {
++#else
++	if (eth_int_cause1 & 0x10101) {
++#endif
++		if (netif_rx_schedule_prep(netdev)) {
++			unsigned int ack;
++
++			ack = TITAN_GE_READ(TITAN_GE_INTR_XDMA_IE);
++			/* Disable Tx and Rx both */
++			if (port_num == 0)
++				ack &= ~(0x3);
++			if (port_num == 1)
++				ack &= ~(0x300);
++
++			if (port_num == 2)
++				ack &= ~(0x30000);
++
++			/* Interrupts have been disabled */
++			TITAN_GE_WRITE(TITAN_GE_INTR_XDMA_IE, ack);
++
++			__netif_rx_schedule(netdev);
++		}
++	}
++
++	/* Handle error interrupts */
++	if (eth_int_cause_error && (eth_int_cause_error != 0x2)) {
++		printk(KERN_ERR
++			"XDMA Channel Error : %x  on port %d\n",
++			eth_int_cause_error, port_num);
++
++		printk(KERN_ERR
++			"XDMA GDI Hardware error : %x  on port %d\n",
++			TITAN_GE_READ(0x5008 + (port_num << 8)), port_num);
++
++		printk(KERN_ERR
++			"XDMA currently has %d Rx descriptors \n",
++			TITAN_GE_READ(0x5048 + (port_num << 8)));
++
++		printk(KERN_ERR
++			"XDMA currently has prefetcted %d Rx descriptors \n",
++			TITAN_GE_READ(0x505c + (port_num << 8)));
++
++		TITAN_GE_WRITE((TITAN_GE_CHANNEL0_INTERRUPT +
++			       (port_num << 8)), eth_int_cause_error);
++	}
++
++	/*
++	 * PHY interrupt to inform abt the changes. Reading the
++	 * PHY Status register will clear the interrupt
++	 */
++	if ((!(eth_int_cause1 & 0x30303)) &&
++		(eth_int_cause_error == 0)) {
++		err =
++		    titan_ge_mdio_read(port_num,
++			       TITAN_GE_MDIO_PHY_IS, &reg_data);
++
++		if (reg_data & 0x0400) {
++			/* Link status change */
++			titan_ge_mdio_read(port_num,
++				   TITAN_GE_MDIO_PHY_STATUS, &reg_data);
++			if (!(reg_data & 0x0400)) {
++				/* Link is down */
++				netif_carrier_off(netdev);
++				netif_stop_queue(netdev);
++			} else {
++				/* Link is up */
++				netif_carrier_on(netdev);
++				netif_wake_queue(netdev);
++
++				/* Enable the queue */
++				titan_ge_enable_tx(port_num);
++			}
++		}
++	}
++
++	return IRQ_HANDLED;
++}
++
++/*
++ * Multicast and Promiscuous mode set. The
++ * set_multi entry point is called whenever the
++ * multicast address list or the network interface
++ * flags are updated.
++ */
++static void titan_ge_set_multi(struct net_device *netdev)
++{
++	titan_ge_port_info *titan_ge_eth = netdev_priv(netdev);
++	unsigned int port_num = titan_ge_eth->port_num;
++	unsigned long reg_data;
++
++	reg_data = TITAN_GE_READ(TITAN_GE_AFX_ADDRS_FILTER_CTRL_1 +
++				(port_num << 12));
++
++	if (netdev->flags & IFF_PROMISC) {
++		reg_data |= 0x2;
++	}
++	else if (netdev->flags & IFF_ALLMULTI) {
++		reg_data |= 0x01;
++		reg_data |= 0x400; /* Use the 64-bit Multicast Hash bin */
++	}
++	else {
++		reg_data = 0x2;
++	}
++
++	TITAN_GE_WRITE((TITAN_GE_AFX_ADDRS_FILTER_CTRL_1 +
++			(port_num << 12)), reg_data);
++	if (reg_data & 0x01) {
++		TITAN_GE_WRITE((TITAN_GE_AFX_MULTICAST_HASH_LOW +
++				(port_num << 12)), 0xffff);
++		TITAN_GE_WRITE((TITAN_GE_AFX_MULTICAST_HASH_MIDLOW +
++				(port_num << 12)), 0xffff);
++		TITAN_GE_WRITE((TITAN_GE_AFX_MULTICAST_HASH_MIDHI +
++				(port_num << 12)), 0xffff);
++		TITAN_GE_WRITE((TITAN_GE_AFX_MULTICAST_HASH_HI +
++				(port_num << 12)), 0xffff);
++	}
++}
++
++/*
++ * Open the network device
++ */
++static int titan_ge_open(struct net_device *netdev)
++{
++	titan_ge_port_info *titan_ge_eth = netdev_priv(netdev);
++	unsigned int port_num = titan_ge_eth->port_num;
++	unsigned int irq = TITAN_ETH_PORT_IRQ - port_num;
++	int retval;
++
++	retval = request_irq(irq, titan_ge_int_handler,
++		     SA_INTERRUPT | SA_SAMPLE_RANDOM , netdev->name, netdev);
++
++	if (retval != 0) {
++		printk(KERN_ERR "Cannot assign IRQ number to TITAN GE \n");
++		return -1;
++	}
++
++	netdev->irq = irq;
++	printk(KERN_INFO "Assigned IRQ %d to port %d\n", irq, port_num);
++
++	spin_lock_irq(&(titan_ge_eth->lock));
++
++	if (titan_ge_eth_open(netdev) != TITAN_OK) {
++		spin_unlock_irq(&(titan_ge_eth->lock));
++		printk("%s: Error opening interface \n", netdev->name);
++		free_irq(netdev->irq, netdev);
++		return -EBUSY;
++	}
++
++	spin_unlock_irq(&(titan_ge_eth->lock));
++
++	return 0;
++}
++
++/*
++ * Allocate the SKBs for the Rx ring. Also used
++ * for refilling the queue
++ */
++static int titan_ge_rx_task(struct net_device *netdev,
++				titan_ge_port_info *titan_ge_port)
++{
++	struct device *device = &titan_ge_device[titan_ge_port->port_num]->dev;
++	volatile titan_ge_rx_desc *rx_desc;
++	struct sk_buff *skb;
++	int rx_used_desc;
++	int count = 0;
++
++	while (titan_ge_port->rx_ring_skbs < titan_ge_port->rx_ring_size) {
++
++	/* First try to get the skb from the recycler */
++#ifdef TITAN_GE_JUMBO_FRAMES
++		skb = titan_ge_alloc_skb(TITAN_GE_JUMBO_BUFSIZE, GFP_ATOMIC);
++#else
++		skb = titan_ge_alloc_skb(TITAN_GE_STD_BUFSIZE, GFP_ATOMIC);
++#endif
++		if (unlikely(!skb)) {
++			/* OOM, set the flag */
++			printk("OOM \n");
++			oom_flag = 1;
++			break;
++		}
++		count++;
++		skb->dev = netdev;
++
++		titan_ge_port->rx_ring_skbs++;
++
++		rx_used_desc = titan_ge_port->rx_used_desc_q;
++		rx_desc = &(titan_ge_port->rx_desc_area[rx_used_desc]);
++
++#ifdef TITAN_GE_JUMBO_FRAMES
++		rx_desc->buffer_addr = dma_map_single(device, skb->data,
++				TITAN_GE_JUMBO_BUFSIZE - 2, DMA_FROM_DEVICE);
++#else
++		rx_desc->buffer_addr = dma_map_single(device, skb->data,
++				TITAN_GE_STD_BUFSIZE - 2, DMA_FROM_DEVICE);
++#endif
++
++		titan_ge_port->rx_skb[rx_used_desc] = skb;
++		rx_desc->cmd_sts = TITAN_GE_RX_BUFFER_OWNED;
++
++		titan_ge_port->rx_used_desc_q =
++			(rx_used_desc + 1) % TITAN_GE_RX_QUEUE;
++	}
++
++	return count;
++}
++
++/*
++ * Actual init of the Tital GE port. There is one register for
++ * the channel configuration
++ */
++static void titan_port_init(struct net_device *netdev,
++			    titan_ge_port_info * titan_ge_eth)
++{
++	unsigned long reg_data;
++
++	titan_ge_port_reset(titan_ge_eth->port_num);
++
++	/* First reset the TMAC */
++	reg_data = TITAN_GE_READ(TITAN_GE_CHANNEL0_CONFIG);
++	reg_data |= 0x80000000;
++	TITAN_GE_WRITE(TITAN_GE_CHANNEL0_CONFIG, reg_data);
++
++	udelay(30);
++
++	reg_data = TITAN_GE_READ(TITAN_GE_CHANNEL0_CONFIG);
++	reg_data &= ~(0xc0000000);
++	TITAN_GE_WRITE(TITAN_GE_CHANNEL0_CONFIG, reg_data);
++
++	/* Now reset the RMAC */
++	reg_data = TITAN_GE_READ(TITAN_GE_CHANNEL0_CONFIG);
++	reg_data |= 0x00080000;
++	TITAN_GE_WRITE(TITAN_GE_CHANNEL0_CONFIG, reg_data);
++
++	udelay(30);
++
++	reg_data = TITAN_GE_READ(TITAN_GE_CHANNEL0_CONFIG);
++	reg_data &= ~(0x000c0000);
++	TITAN_GE_WRITE(TITAN_GE_CHANNEL0_CONFIG, reg_data);
++}
++
++/*
++ * Start the port. All the hardware specific configuration
++ * for the XDMA, Tx FIFO, Rx FIFO, TMAC, RMAC, TRTG and AFX
++ * go here
++ */
++static int titan_ge_port_start(struct net_device *netdev,
++				titan_ge_port_info * titan_port)
++{
++	volatile unsigned long reg_data, reg_data1;
++	int port_num = titan_port->port_num;
++	int count = 0;
++	unsigned long reg_data_1;
++
++	if (config_done == 0) {
++		reg_data = TITAN_GE_READ(0x0004);
++		reg_data |= 0x100;
++		TITAN_GE_WRITE(0x0004, reg_data);
++
++		reg_data &= ~(0x100);
++		TITAN_GE_WRITE(0x0004, reg_data);
++
++		/* Turn on GMII/MII mode and turn off TBI mode */
++		reg_data = TITAN_GE_READ(TITAN_GE_TSB_CTRL_1);
++		reg_data |= 0x00000700;
++		reg_data &= ~(0x00800000); /* Fencing */
++
++		TITAN_GE_WRITE(0x000c, 0x00001100);
++
++		TITAN_GE_WRITE(TITAN_GE_TSB_CTRL_1, reg_data);
++
++		/* Set the CPU Resource Limit register */
++		TITAN_GE_WRITE(0x00f8, 0x8);
++
++		/* Be conservative when using the BIU buffers */
++		TITAN_GE_WRITE(0x0068, 0x4);
++	}
++
++	titan_port->tx_threshold = 0;
++	titan_port->rx_threshold = 0;
++
++	/* We need to write the descriptors for Tx and Rx */
++	TITAN_GE_WRITE((TITAN_GE_CHANNEL0_TX_DESC + (port_num << 8)),
++		       (unsigned long) titan_port->tx_dma);
++	TITAN_GE_WRITE((TITAN_GE_CHANNEL0_RX_DESC + (port_num << 8)),
++		       (unsigned long) titan_port->rx_dma);
++
++	if (config_done == 0) {
++		/* Step 1:  XDMA config	*/
++		reg_data = TITAN_GE_READ(TITAN_GE_XDMA_CONFIG);
++		reg_data &= ~(0x80000000);      /* clear reset */
++		reg_data |= 0x1 << 29;	/* sparse tx descriptor spacing */
++		reg_data |= 0x1 << 28;	/* sparse rx descriptor spacing */
++		reg_data |= (0x1 << 23) | (0x1 << 24);  /* Descriptor Coherency */
++		reg_data |= (0x1 << 21) | (0x1 << 22);  /* Data Coherency */
++		TITAN_GE_WRITE(TITAN_GE_XDMA_CONFIG, reg_data);
++	}
++
++	/* IR register for the XDMA */
++	reg_data = TITAN_GE_READ(TITAN_GE_GDI_INTERRUPT_ENABLE + (port_num << 8));
++	reg_data |= 0x80068000; /* No Rx_OOD */
++	TITAN_GE_WRITE((TITAN_GE_GDI_INTERRUPT_ENABLE + (port_num << 8)), reg_data);
++
++	/* Start the Tx and Rx XDMA controller */
++	reg_data = TITAN_GE_READ(TITAN_GE_CHANNEL0_CONFIG + (port_num << 8));
++	reg_data &= 0x4fffffff;     /* Clear tx reset */
++	reg_data &= 0xfff4ffff;     /* Clear rx reset */
++
++#ifdef TITAN_GE_JUMBO_FRAMES
++	reg_data |= 0xa0 | 0x30030000;
++#else
++	reg_data |= 0x40 | 0x20030000;
++#endif
++
++#ifndef CONFIG_SMP
++	reg_data &= ~(0x10);
++	reg_data |= 0x0f; /* All of the packet */
++#endif
++
++	TITAN_GE_WRITE((TITAN_GE_CHANNEL0_CONFIG + (port_num << 8)), reg_data);
++
++	/* Rx desc count */
++	count = titan_ge_rx_task(netdev, titan_port);
++	TITAN_GE_WRITE((0x5048 + (port_num << 8)), count);
++	count = TITAN_GE_READ(0x5048 + (port_num << 8));
++
++	udelay(30);
++
++	/*
++	 * Step 2:  Configure the SDQPF, i.e. FIFO
++	 */
++	if (config_done == 0) {
++		reg_data = TITAN_GE_READ(TITAN_GE_SDQPF_RXFIFO_CTL);
++		reg_data = 0x1;
++		TITAN_GE_WRITE(TITAN_GE_SDQPF_RXFIFO_CTL, reg_data);
++		reg_data &= ~(0x1);
++		TITAN_GE_WRITE(TITAN_GE_SDQPF_RXFIFO_CTL, reg_data);
++		reg_data = TITAN_GE_READ(TITAN_GE_SDQPF_RXFIFO_CTL);
++		TITAN_GE_WRITE(TITAN_GE_SDQPF_RXFIFO_CTL, reg_data);
++
++		reg_data = TITAN_GE_READ(TITAN_GE_SDQPF_TXFIFO_CTL);
++		reg_data = 0x1;
++		TITAN_GE_WRITE(TITAN_GE_SDQPF_TXFIFO_CTL, reg_data);
++		reg_data &= ~(0x1);
++		TITAN_GE_WRITE(TITAN_GE_SDQPF_TXFIFO_CTL, reg_data);
++		reg_data = TITAN_GE_READ(TITAN_GE_SDQPF_TXFIFO_CTL);
++		TITAN_GE_WRITE(TITAN_GE_SDQPF_TXFIFO_CTL, reg_data);
++	}
++	/*
++	 * Enable RX FIFO 0, 4 and 8
++	 */
++	if (port_num == 0) {
++		reg_data = TITAN_GE_READ(TITAN_GE_SDQPF_RXFIFO_0);
++
++		reg_data |= 0x100000;
++		reg_data |= (0xff << 10);
++
++		TITAN_GE_WRITE(TITAN_GE_SDQPF_RXFIFO_0, reg_data);
++		/*
++		 * BAV2,BAV and DAV settings for the Rx FIFO
++		 */
++		reg_data1 = TITAN_GE_READ(0x4844);
++		reg_data1 |= ( (0x10 << 20) | (0x10 << 10) | 0x1);
++		TITAN_GE_WRITE(0x4844, reg_data1);
++
++		reg_data &= ~(0x00100000);
++		reg_data |= 0x200000;
++
++		TITAN_GE_WRITE(TITAN_GE_SDQPF_RXFIFO_0, reg_data);
++
++		reg_data = TITAN_GE_READ(TITAN_GE_SDQPF_TXFIFO_0);
++		reg_data |= 0x100000;
++
++		TITAN_GE_WRITE(TITAN_GE_SDQPF_TXFIFO_0, reg_data);
++
++		reg_data |= (0xff << 10);
++
++		TITAN_GE_WRITE(TITAN_GE_SDQPF_TXFIFO_0, reg_data);
++
++		/*
++		 * BAV2, BAV and DAV settings for the Tx FIFO
++		 */
++		reg_data1 = TITAN_GE_READ(0x4944);
++		reg_data1 = ( (0x1 << 20) | (0x1 << 10) | 0x10);
++
++		TITAN_GE_WRITE(0x4944, reg_data1);
++
++		reg_data &= ~(0x00100000);
++		reg_data |= 0x200000;
++
++		TITAN_GE_WRITE(TITAN_GE_SDQPF_TXFIFO_0, reg_data);
++
++	}
++
++	if (port_num == 1) {
++		reg_data = TITAN_GE_READ(0x4870);
++
++		reg_data |= 0x100000;
++		reg_data |= (0xff << 10) | (0xff + 1);
++
++		TITAN_GE_WRITE(0x4870, reg_data);
++		/*
++		 * BAV2,BAV and DAV settings for the Rx FIFO
++		 */
++		reg_data1 = TITAN_GE_READ(0x4874);
++		reg_data1 |= ( (0x10 << 20) | (0x10 << 10) | 0x1);
++		TITAN_GE_WRITE(0x4874, reg_data1);
++
++		reg_data &= ~(0x00100000);
++		reg_data |= 0x200000;
++
++		TITAN_GE_WRITE(0x4870, reg_data);
++
++		reg_data = TITAN_GE_READ(0x494c);
++		reg_data |= 0x100000;
++
++		TITAN_GE_WRITE(0x494c, reg_data);
++		reg_data |= (0xff << 10) | (0xff + 1);
++		TITAN_GE_WRITE(0x494c, reg_data);
++
++		/*
++		 * BAV2, BAV and DAV settings for the Tx FIFO
++		 */
++		reg_data1 = TITAN_GE_READ(0x4950);
++		reg_data1 = ( (0x1 << 20) | (0x1 << 10) | 0x10);
++
++		TITAN_GE_WRITE(0x4950, reg_data1);
++
++		reg_data &= ~(0x00100000);
++		reg_data |= 0x200000;
++
++		TITAN_GE_WRITE(0x494c, reg_data);
++	}
++
++	/*
++	 * Titan 1.2 revision does support port #2
++	 */
++	if (port_num == 2) {
++		/*
++		 * Put the descriptors in the SRAM
++		 */
++		reg_data = TITAN_GE_READ(0x48a0);
++
++		reg_data |= 0x100000;
++		reg_data |= (0xff << 10) | (2*(0xff + 1));
++
++		TITAN_GE_WRITE(0x48a0, reg_data);
++		/*
++		 * BAV2,BAV and DAV settings for the Rx FIFO
++		 */
++		reg_data1 = TITAN_GE_READ(0x48a4);
++		reg_data1 |= ( (0x10 << 20) | (0x10 << 10) | 0x1);
++		TITAN_GE_WRITE(0x48a4, reg_data1);
++
++		reg_data &= ~(0x00100000);
++		reg_data |= 0x200000;
++
++		TITAN_GE_WRITE(0x48a0, reg_data);
++		
++		reg_data = TITAN_GE_READ(0x4958);
++		reg_data |= 0x100000;
++
++		TITAN_GE_WRITE(0x4958, reg_data);
++		reg_data |= (0xff << 10) | (2*(0xff + 1));
++		TITAN_GE_WRITE(0x4958, reg_data);
++
++		/*
++		 * BAV2, BAV and DAV settings for the Tx FIFO
++		 */
++		reg_data1 = TITAN_GE_READ(0x495c);
++		reg_data1 = ( (0x1 << 20) | (0x1 << 10) | 0x10);
++
++		TITAN_GE_WRITE(0x495c, reg_data1);
++
++		reg_data &= ~(0x00100000);
++		reg_data |= 0x200000;
++
++		TITAN_GE_WRITE(0x4958, reg_data);
++	}
++
++	if (port_num == 2) {
++		reg_data = TITAN_GE_READ(0x48a0);
++
++		reg_data |= 0x100000;
++		reg_data |= (0xff << 10) | (2*(0xff + 1));
++
++		TITAN_GE_WRITE(0x48a0, reg_data);
++		/*
++		 * BAV2,BAV and DAV settings for the Rx FIFO
++		 */
++		reg_data1 = TITAN_GE_READ(0x48a4);
++		reg_data1 |= ( (0x10 << 20) | (0x10 << 10) | 0x1);
++		TITAN_GE_WRITE(0x48a4, reg_data1);
++
++		reg_data &= ~(0x00100000);
++		reg_data |= 0x200000;
++
++		TITAN_GE_WRITE(0x48a0, reg_data);
++
++		reg_data = TITAN_GE_READ(0x4958);
++		reg_data |= 0x100000;
++
++		TITAN_GE_WRITE(0x4958, reg_data);
++		reg_data |= (0xff << 10) | (2*(0xff + 1));
++		TITAN_GE_WRITE(0x4958, reg_data);
++
++		/*
++		 * BAV2, BAV and DAV settings for the Tx FIFO
++		 */
++		reg_data1 = TITAN_GE_READ(0x495c);
++		reg_data1 = ( (0x1 << 20) | (0x1 << 10) | 0x10);
++
++		TITAN_GE_WRITE(0x495c, reg_data1);
++
++		reg_data &= ~(0x00100000);
++		reg_data |= 0x200000;
++
++		TITAN_GE_WRITE(0x4958, reg_data);
++	}
++
++	/*
++	 * Step 3:  TRTG block enable
++	 */
++	reg_data = TITAN_GE_READ(TITAN_GE_TRTG_CONFIG + (port_num << 12));
++
++	/*
++	 * This is the 1.2 revision of the chip. It has fix for the
++	 * IP header alignment. Now, the IP header begins at an
++	 * aligned address and this wont need an extra copy in the
++	 * driver. This performance drawback existed in the previous
++	 * versions of the silicon
++	 */
++	reg_data_1 = TITAN_GE_READ(0x103c + (port_num << 12));
++	reg_data_1 |= 0x40000000;
++	TITAN_GE_WRITE((0x103c + (port_num << 12)), reg_data_1);
++
++	reg_data_1 |= 0x04000000;
++	TITAN_GE_WRITE((0x103c + (port_num << 12)), reg_data_1);
++
++	mdelay(5);
++
++	reg_data_1 &= ~(0x04000000);
++	TITAN_GE_WRITE((0x103c + (port_num << 12)), reg_data_1);
++
++	mdelay(5);
++
++	reg_data |= 0x0001;
++	TITAN_GE_WRITE((TITAN_GE_TRTG_CONFIG + (port_num << 12)), reg_data);
++
++	/*
++	 * Step 4:  Start the Tx activity
++	 */
++	TITAN_GE_WRITE((TITAN_GE_TMAC_CONFIG_2 + (port_num << 12)), 0xe197);
++#ifdef TITAN_GE_JUMBO_FRAMES
++	TITAN_GE_WRITE((0x1258 + (port_num << 12)), 0x4000);
++#endif
++	reg_data = TITAN_GE_READ(TITAN_GE_TMAC_CONFIG_1 + (port_num << 12));
++	reg_data |= 0x0001;	/* Enable TMAC */
++	reg_data |= 0x6c70;	/* PAUSE also set */
++
++	TITAN_GE_WRITE((TITAN_GE_TMAC_CONFIG_1 + (port_num << 12)), reg_data);
++
++	udelay(30);
++
++	/* Destination Address drop bit */
++	reg_data = TITAN_GE_READ(TITAN_GE_RMAC_CONFIG_2 + (port_num << 12));
++	reg_data |= 0x218;        /* DA_DROP bit and pause */
++	TITAN_GE_WRITE((TITAN_GE_RMAC_CONFIG_2 + (port_num << 12)), reg_data);
++
++	TITAN_GE_WRITE((0x1218 + (port_num << 12)), 0x3);
++
++#ifdef TITAN_GE_JUMBO_FRAMES
++	TITAN_GE_WRITE((0x1208 + (port_num << 12)), 0x4000);
++#endif
++	/* Start the Rx activity */
++	reg_data = TITAN_GE_READ(TITAN_GE_RMAC_CONFIG_1 + (port_num << 12));
++	reg_data |= 0x0001;	/* RMAC Enable */
++	reg_data |= 0x0010;	/* CRC Check enable */
++	reg_data |= 0x0040;	/* Min Frame check enable */
++	reg_data |= 0x4400;	/* Max Frame check enable */
++
++	TITAN_GE_WRITE((TITAN_GE_RMAC_CONFIG_1 + (port_num << 12)), reg_data);
++
++	udelay(30);
++
++	/*
++	 * Enable the Interrupts for Tx and Rx
++	 */
++	reg_data1 = TITAN_GE_READ(TITAN_GE_INTR_XDMA_IE);
++
++	if (port_num == 0) {
++		reg_data1 |= 0x3;
++#ifdef CONFIG_SMP
++		TITAN_GE_WRITE(0x0038, 0x003);
++#else
++		TITAN_GE_WRITE(0x0038, 0x303);
++#endif
++	}
++
++	if (port_num == 1) {
++		reg_data1 |= 0x300;
++	}
++
++	if (port_num == 2)
++		reg_data1 |= 0x30000;
++
++	TITAN_GE_WRITE(TITAN_GE_INTR_XDMA_IE, reg_data1);
++	TITAN_GE_WRITE(0x003c, 0x300);
++
++	if (config_done == 0) {
++		TITAN_GE_WRITE(0x0024, 0x04000024);	/* IRQ vector */
++		TITAN_GE_WRITE(0x0020, 0x000fb000);	/* INTMSG base */
++	}
++
++	/* Priority */
++	reg_data = TITAN_GE_READ(0x1038 + (port_num << 12));
++	reg_data &= ~(0x00f00000);
++	TITAN_GE_WRITE((0x1038 + (port_num << 12)), reg_data);
++
++	/* Step 5:  GMII config */
++	titan_ge_gmii_config(port_num);
++
++	if (config_done == 0) {
++		TITAN_GE_WRITE(0x1a80, 0);
++		config_done = 1;
++	}
++
++	return TITAN_OK;
++}
++
++/*
++ * Function to queue the packet for the Ethernet device
++ */
++static void titan_ge_tx_queue(titan_ge_port_info * titan_ge_eth,
++				struct sk_buff * skb)
++{
++	struct device *device = &titan_ge_device[titan_ge_eth->port_num]->dev;
++	unsigned int curr_desc = titan_ge_eth->tx_curr_desc_q;
++	volatile titan_ge_tx_desc *tx_curr;
++	int port_num = titan_ge_eth->port_num;
++
++	tx_curr = &(titan_ge_eth->tx_desc_area[curr_desc]);
++	tx_curr->buffer_addr =
++		dma_map_single(device, skb->data, skb_headlen(skb),
++			       DMA_TO_DEVICE);
++
++	titan_ge_eth->tx_skb[curr_desc] = (struct sk_buff *) skb;
++	tx_curr->buffer_len = skb_headlen(skb);
++
++	/* Last descriptor enables interrupt and changes ownership */
++	tx_curr->cmd_sts = 0x1 | (1 << 15) | (1 << 5);
++
++	/* Kick the XDMA to start the transfer from memory to the FIFO */
++	TITAN_GE_WRITE((0x5044 + (port_num << 8)), 0x1);
++
++	/* Current descriptor updated */
++	titan_ge_eth->tx_curr_desc_q = (curr_desc + 1) % TITAN_GE_TX_QUEUE;
++
++	/* Prefetch the next descriptor */
++	prefetch((const void *)
++		 &titan_ge_eth->tx_desc_area[titan_ge_eth->tx_curr_desc_q]);
++}
++
++/*
++ * Actually does the open of the Ethernet device
++ */
++static int titan_ge_eth_open(struct net_device *netdev)
++{
++	titan_ge_port_info *titan_ge_eth = netdev_priv(netdev);
++	unsigned int port_num = titan_ge_eth->port_num;
++	struct device *device = &titan_ge_device[port_num]->dev;
++	unsigned long reg_data;
++	unsigned int phy_reg;
++	int err = 0;
++
++	/* Stop the Rx activity */
++	reg_data = TITAN_GE_READ(TITAN_GE_RMAC_CONFIG_1 + (port_num << 12));
++	reg_data &= ~(0x00000001);
++	TITAN_GE_WRITE((TITAN_GE_RMAC_CONFIG_1 + (port_num << 12)), reg_data);
++
++	/* Clear the port interrupts */
++	TITAN_GE_WRITE((TITAN_GE_CHANNEL0_INTERRUPT + (port_num << 8)), 0x0);
++
++	if (config_done == 0) {
++		TITAN_GE_WRITE(TITAN_GE_INTR_XDMA_CORE_A, 0);
++		TITAN_GE_WRITE(TITAN_GE_INTR_XDMA_CORE_B, 0);
++	}
++
++	/* Set the MAC Address */
++	memcpy(titan_ge_eth->port_mac_addr, netdev->dev_addr, 6);
++
++	if (config_done == 0)
++		titan_port_init(netdev, titan_ge_eth);
++
++	titan_ge_update_afx(titan_ge_eth);
++
++	/* Allocate the Tx ring now */
++	titan_ge_eth->tx_ring_skbs = 0;
++	titan_ge_eth->tx_ring_size = TITAN_GE_TX_QUEUE;
++
++	/* Allocate space in the SRAM for the descriptors */
++	titan_ge_eth->tx_desc_area = (titan_ge_tx_desc *)
++		(titan_ge_sram + TITAN_TX_RING_BYTES * port_num);
++	titan_ge_eth->tx_dma = TITAN_SRAM_BASE + TITAN_TX_RING_BYTES * port_num;
++
++	if (!titan_ge_eth->tx_desc_area) {
++		printk(KERN_ERR
++		       "%s: Cannot allocate Tx Ring (size %d bytes) for port %d\n",
++		       netdev->name, TITAN_TX_RING_BYTES, port_num);
++		return -ENOMEM;
++	}
++
++	memset(titan_ge_eth->tx_desc_area, 0, titan_ge_eth->tx_desc_area_size);
++
++	/* Now initialize the Tx descriptor ring */
++	titan_ge_init_tx_desc_ring(titan_ge_eth,
++				   titan_ge_eth->tx_ring_size,
++				   (unsigned long) titan_ge_eth->tx_desc_area,
++				   (unsigned long) titan_ge_eth->tx_dma);
++
++	/* Allocate the Rx ring now */
++	titan_ge_eth->rx_ring_size = TITAN_GE_RX_QUEUE;
++	titan_ge_eth->rx_ring_skbs = 0;
++
++	titan_ge_eth->rx_desc_area =
++		(titan_ge_rx_desc *)(titan_ge_sram + 0x1000 + TITAN_RX_RING_BYTES * port_num);
++
++	titan_ge_eth->rx_dma = TITAN_SRAM_BASE + 0x1000 + TITAN_RX_RING_BYTES * port_num;
++
++	if (!titan_ge_eth->rx_desc_area) {
++		printk(KERN_ERR "%s: Cannot allocate Rx Ring (size %d bytes)\n",
++		       netdev->name, TITAN_RX_RING_BYTES);
++
++		printk(KERN_ERR "%s: Freeing previously allocated TX queues...",
++		       netdev->name);
++
++		dma_free_coherent(device, titan_ge_eth->tx_desc_area_size,
++				    (void *) titan_ge_eth->tx_desc_area,
++				    titan_ge_eth->tx_dma);
++
++		return -ENOMEM;
++	}
++
++	memset(titan_ge_eth->rx_desc_area, 0, titan_ge_eth->rx_desc_area_size);
++
++	/* Now initialize the Rx ring */
++#ifdef TITAN_GE_JUMBO_FRAMES
++	if ((titan_ge_init_rx_desc_ring
++	    (titan_ge_eth, titan_ge_eth->rx_ring_size, TITAN_GE_JUMBO_BUFSIZE,
++	     (unsigned long) titan_ge_eth->rx_desc_area, 0,
++	      (unsigned long) titan_ge_eth->rx_dma)) == 0)
++#else
++	if ((titan_ge_init_rx_desc_ring
++	     (titan_ge_eth, titan_ge_eth->rx_ring_size, TITAN_GE_STD_BUFSIZE,
++	      (unsigned long) titan_ge_eth->rx_desc_area, 0,
++	      (unsigned long) titan_ge_eth->rx_dma)) == 0)
++#endif
++		panic("%s: Error initializing RX Ring\n", netdev->name);
++
++	/* Fill the Rx ring with the SKBs */
++	titan_ge_port_start(netdev, titan_ge_eth);
++
++	/*
++	 * Check if Interrupt Coalscing needs to be turned on. The
++	 * values specified in the register is multiplied by
++	 * (8 x 64 nanoseconds) to determine when an interrupt should
++	 * be sent to the CPU.
++	 */
++
++	if (TITAN_GE_TX_COAL) {
++		titan_ge_eth->tx_int_coal =
++		    titan_ge_tx_coal(TITAN_GE_TX_COAL, port_num);
++	}
++
++	err = titan_ge_mdio_read(port_num, TITAN_GE_MDIO_PHY_STATUS, &phy_reg);
++	if (err == TITAN_GE_MDIO_ERROR) {
++		printk(KERN_ERR
++		       "Could not read PHY control register 0x11 \n");
++		return TITAN_ERROR;
++	}
++	if (!(phy_reg & 0x0400)) {
++		netif_carrier_off(netdev);
++		netif_stop_queue(netdev);
++		return TITAN_ERROR;
++	} else {
++		netif_carrier_on(netdev);
++		netif_start_queue(netdev);
++	}
++
++	return TITAN_OK;
++}
++
++/*
++ * Queue the packet for Tx. Currently no support for zero copy,
++ * checksum offload and Scatter Gather. The chip does support
++ * Scatter Gather only. But, that wont help here since zero copy
++ * requires support for Tx checksumming also.
++ */
++int titan_ge_start_xmit(struct sk_buff *skb, struct net_device *netdev)
++{
++	titan_ge_port_info *titan_ge_eth = netdev_priv(netdev);
++	unsigned long flags;
++	struct net_device_stats *stats;
++//printk("titan_ge_start_xmit\n");
++
++	stats = &titan_ge_eth->stats;
++	spin_lock_irqsave(&titan_ge_eth->lock, flags);
++
++	if ((TITAN_GE_TX_QUEUE - titan_ge_eth->tx_ring_skbs) <=
++	    (skb_shinfo(skb)->nr_frags + 1)) {
++		netif_stop_queue(netdev);
++		spin_unlock_irqrestore(&titan_ge_eth->lock, flags);
++		printk(KERN_ERR "Tx OOD \n");
++		return 1;
++	}
++
++	titan_ge_tx_queue(titan_ge_eth, skb);
++	titan_ge_eth->tx_ring_skbs++;
++
++	if (TITAN_GE_TX_QUEUE <= (titan_ge_eth->tx_ring_skbs + 4)) {
++		spin_unlock_irqrestore(&titan_ge_eth->lock, flags);
++		titan_ge_free_tx_queue(titan_ge_eth);
++		spin_lock_irqsave(&titan_ge_eth->lock, flags);
++	}
++
++	stats->tx_bytes += skb->len;
++	stats->tx_packets++;
++
++	spin_unlock_irqrestore(&titan_ge_eth->lock, flags);
++
++	netdev->trans_start = jiffies;
++
++	return 0;
++}
++
++/*
++ * Actually does the Rx. Rx side checksumming supported.
++ */
++static int titan_ge_rx(struct net_device *netdev, int port_num,
++			titan_ge_port_info * titan_ge_port,
++		       titan_ge_packet * packet)
++{
++	int rx_curr_desc, rx_used_desc;
++	volatile titan_ge_rx_desc *rx_desc;
++
++	rx_curr_desc = titan_ge_port->rx_curr_desc_q;
++	rx_used_desc = titan_ge_port->rx_used_desc_q;
++
++	if (((rx_curr_desc + 1) % TITAN_GE_RX_QUEUE) == rx_used_desc)
++		return TITAN_ERROR;
++
++	rx_desc = &(titan_ge_port->rx_desc_area[rx_curr_desc]);
++
++	if (rx_desc->cmd_sts & TITAN_GE_RX_BUFFER_OWNED)
++		return TITAN_ERROR;
++
++	packet->skb = titan_ge_port->rx_skb[rx_curr_desc];
++	packet->len = (rx_desc->cmd_sts & 0x7fff);
++
++	/*
++	 * At this point, we dont know if the checksumming
++	 * actually helps relieve CPU. So, keep it for
++	 * port 0 only
++	 */
++	packet->checksum = ntohs((rx_desc->buffer & 0xffff0000) >> 16);
++	packet->cmd_sts = rx_desc->cmd_sts;
++
++	titan_ge_port->rx_curr_desc_q = (rx_curr_desc + 1) % TITAN_GE_RX_QUEUE;
++
++	/* Prefetch the next descriptor */
++	prefetch((const void *)
++	       &titan_ge_port->rx_desc_area[titan_ge_port->rx_curr_desc_q + 1]);
++
++	return TITAN_OK;
++}
++
++/*
++ * Free the Tx queue of the used SKBs
++ */
++static int titan_ge_free_tx_queue(titan_ge_port_info *titan_ge_eth)
++{
++	unsigned long flags;
++
++	/* Take the lock */
++	spin_lock_irqsave(&(titan_ge_eth->lock), flags);
++
++	while (titan_ge_return_tx_desc(titan_ge_eth, titan_ge_eth->port_num) == 0)
++		if (titan_ge_eth->tx_ring_skbs != 1)
++			titan_ge_eth->tx_ring_skbs--;
++
++	spin_unlock_irqrestore(&titan_ge_eth->lock, flags);
++
++	return TITAN_OK;
++}
++
++/*
++ * Threshold beyond which we do the cleaning of
++ * Tx queue and new allocation for the Rx
++ * queue
++ */
++#define	TX_THRESHOLD	4
++#define	RX_THRESHOLD	10
++
++/*
++ * Receive the packets and send it to the kernel.
++ */
++static int titan_ge_receive_queue(struct net_device *netdev, unsigned int max)
++{
++	titan_ge_port_info *titan_ge_eth = netdev_priv(netdev);
++	unsigned int port_num = titan_ge_eth->port_num;
++	titan_ge_packet packet;
++	struct net_device_stats *stats;
++	struct sk_buff *skb;
++	unsigned long received_packets = 0;
++	unsigned int ack;
++
++	stats = &titan_ge_eth->stats;
++
++	while ((--max)
++	       && (titan_ge_rx(netdev, port_num, titan_ge_eth, &packet) == TITAN_OK)) {
++		skb = (struct sk_buff *) packet.skb;
++
++		titan_ge_eth->rx_ring_skbs--;
++
++		if (--titan_ge_eth->rx_work_limit < 0)
++			break;
++		received_packets++;
++
++		stats->rx_packets++;
++		stats->rx_bytes += packet.len;
++
++		if ((packet.cmd_sts & TITAN_GE_RX_PERR) ||
++			(packet.cmd_sts & TITAN_GE_RX_OVERFLOW_ERROR) ||
++			(packet.cmd_sts & TITAN_GE_RX_TRUNC) ||
++			(packet.cmd_sts & TITAN_GE_RX_CRC_ERROR)) {
++				stats->rx_dropped++;
++				dev_kfree_skb_any(skb);
++
++				continue;
++		}
++		/*
++		 * Either support fast path or slow path. Decision
++		 * making can really slow down the performance. The
++		 * idea is to cut down the number of checks and improve
++		 * the fastpath.
++		 */
++
++		skb_put(skb, packet.len - 2);
++
++		/*
++		 * Increment data pointer by two since thats where
++		 * the MAC starts
++		 */
++		skb_reserve(skb, 2);
++		skb->protocol = eth_type_trans(skb, netdev);
++		netif_receive_skb(skb);
++
++		if (titan_ge_eth->rx_threshold > RX_THRESHOLD) {
++			ack = titan_ge_rx_task(netdev, titan_ge_eth);
++			TITAN_GE_WRITE((0x5048 + (port_num << 8)), ack);
++			titan_ge_eth->rx_threshold = 0;
++		} else
++			titan_ge_eth->rx_threshold++;
++
++		if (titan_ge_eth->tx_threshold > TX_THRESHOLD) {
++			titan_ge_eth->tx_threshold = 0;
++			titan_ge_free_tx_queue(titan_ge_eth);
++		}
++		else
++			titan_ge_eth->tx_threshold++;
++
++	}
++	return received_packets;
++}
++
++
++/*
++ * Enable the Rx side interrupts
++ */
++static void titan_ge_enable_int(unsigned int port_num,
++			titan_ge_port_info *titan_ge_eth,
++			struct net_device *netdev)
++{
++	unsigned long reg_data = TITAN_GE_READ(TITAN_GE_INTR_XDMA_IE);
++
++	if (port_num == 0)
++		reg_data |= 0x3;
++	if (port_num == 1)
++		reg_data |= 0x300;
++	if (port_num == 2)
++		reg_data |= 0x30000;
++
++	/* Re-enable interrupts */
++	TITAN_GE_WRITE(TITAN_GE_INTR_XDMA_IE, reg_data);
++}
++
++/*
++ * Main function to handle the polling for Rx side NAPI.
++ * Receive interrupts have been disabled at this point.
++ * The poll schedules the transmit followed by receive.
++ */
++static int titan_ge_poll(struct net_device *netdev, int *budget)
++{
++	titan_ge_port_info *titan_ge_eth = netdev_priv(netdev);
++	int port_num = titan_ge_eth->port_num;
++	int work_done = 0;
++	unsigned long flags, status;
++
++	titan_ge_eth->rx_work_limit = *budget;
++	if (titan_ge_eth->rx_work_limit > netdev->quota)
++		titan_ge_eth->rx_work_limit = netdev->quota;
++
++	do {
++		/* Do the transmit cleaning work here */
++		titan_ge_free_tx_queue(titan_ge_eth);
++
++		/* Ack the Rx interrupts */
++		if (port_num == 0)
++			TITAN_GE_WRITE(TITAN_GE_INTR_XDMA_CORE_A, 0x3);
++		if (port_num == 1)
++			TITAN_GE_WRITE(TITAN_GE_INTR_XDMA_CORE_A, 0x300);
++		if (port_num == 2)
++			TITAN_GE_WRITE(TITAN_GE_INTR_XDMA_CORE_A, 0x30000);
++
++		work_done += titan_ge_receive_queue(netdev, 0);
++
++		/* Out of quota and there is work to be done */
++		if (titan_ge_eth->rx_work_limit < 0)
++			goto not_done;
++
++		/* Receive alloc_skb could lead to OOM */
++		if (oom_flag == 1) {
++			oom_flag = 0;
++			goto oom;
++		}
++
++		status = TITAN_GE_READ(TITAN_GE_INTR_XDMA_CORE_A);
++	} while (status & 0x30300);
++
++	/* If we are here, then no more interrupts to process */
++	goto done;
++
++not_done:
++	*budget -= work_done;
++	netdev->quota -= work_done;
++	return 1;
++
++oom:
++	printk(KERN_ERR "OOM \n");
++	netif_rx_complete(netdev);
++	return 0;
++
++done:
++	/*
++	 * No more packets on the poll list. Turn the interrupts
++	 * back on and we should be able to catch the new
++	 * packets in the interrupt handler
++	 */
++	if (!work_done)
++		work_done = 1;
++
++	*budget -= work_done;
++	netdev->quota -= work_done;
++
++	spin_lock_irqsave(&titan_ge_eth->lock, flags);
++
++	/* Remove us from the poll list */
++	netif_rx_complete(netdev);
++
++	/* Re-enable interrupts */
++	titan_ge_enable_int(port_num, titan_ge_eth, netdev);
++
++	spin_unlock_irqrestore(&titan_ge_eth->lock, flags);
++
++	return 0;
++}
++
++/*
++ * Close the network device
++ */
++int titan_ge_stop(struct net_device *netdev)
++{
++	titan_ge_port_info *titan_ge_eth = netdev_priv(netdev);
++
++	spin_lock_irq(&(titan_ge_eth->lock));
++	titan_ge_eth_stop(netdev);
++	free_irq(netdev->irq, netdev);
++	spin_unlock_irq(&titan_ge_eth->lock);
++
++	return TITAN_OK;
++}
++
++/*
++ * Free the Tx ring
++ */
++static void titan_ge_free_tx_rings(struct net_device *netdev)
++{
++	titan_ge_port_info *titan_ge_eth = netdev_priv(netdev);
++	unsigned int port_num = titan_ge_eth->port_num;
++	unsigned int curr;
++	unsigned long reg_data;
++
++	/* Stop the Tx DMA */
++	reg_data = TITAN_GE_READ(TITAN_GE_CHANNEL0_CONFIG +
++				(port_num << 8));
++	reg_data |= 0xc0000000;
++	TITAN_GE_WRITE((TITAN_GE_CHANNEL0_CONFIG +
++			(port_num << 8)), reg_data);
++
++	/* Disable the TMAC */
++	reg_data = TITAN_GE_READ(TITAN_GE_TMAC_CONFIG_1 +
++				(port_num << 12));
++	reg_data &= ~(0x00000001);
++	TITAN_GE_WRITE((TITAN_GE_TMAC_CONFIG_1 +
++			(port_num << 12)), reg_data);
++
++	for (curr = 0;
++	     (titan_ge_eth->tx_ring_skbs) && (curr < TITAN_GE_TX_QUEUE);
++	     curr++) {
++		if (titan_ge_eth->tx_skb[curr]) {
++			dev_kfree_skb(titan_ge_eth->tx_skb[curr]);
++			titan_ge_eth->tx_ring_skbs--;
++		}
++	}
++
++	if (titan_ge_eth->tx_ring_skbs != 0)
++		printk
++		    ("%s: Error on Tx descriptor free - could not free %d"
++		     " descriptors\n", netdev->name,
++		     titan_ge_eth->tx_ring_skbs);
++
++#ifndef TITAN_RX_RING_IN_SRAM
++	dma_free_coherent(&titan_ge_device[port_num]->dev,
++			  titan_ge_eth->tx_desc_area_size,
++			  (void *) titan_ge_eth->tx_desc_area,
++			  titan_ge_eth->tx_dma);
++#endif
++}
++
++/*
++ * Free the Rx ring
++ */
++static void titan_ge_free_rx_rings(struct net_device *netdev)
++{
++	titan_ge_port_info *titan_ge_eth = netdev_priv(netdev);
++	unsigned int port_num = titan_ge_eth->port_num;
++	unsigned int curr;
++	unsigned long reg_data;
++
++	/* Stop the Rx DMA */
++	reg_data = TITAN_GE_READ(TITAN_GE_CHANNEL0_CONFIG +
++				(port_num << 8));
++	reg_data |= 0x000c0000;
++	TITAN_GE_WRITE((TITAN_GE_CHANNEL0_CONFIG +
++			(port_num << 8)), reg_data);
++
++	/* Disable the RMAC */
++	reg_data = TITAN_GE_READ(TITAN_GE_RMAC_CONFIG_1 +
++				(port_num << 12));
++	reg_data &= ~(0x00000001);
++	TITAN_GE_WRITE((TITAN_GE_RMAC_CONFIG_1 +
++			(port_num << 12)), reg_data);
++
++	for (curr = 0;
++	     titan_ge_eth->rx_ring_skbs && (curr < TITAN_GE_RX_QUEUE);
++	     curr++) {
++		if (titan_ge_eth->rx_skb[curr]) {
++			dev_kfree_skb(titan_ge_eth->rx_skb[curr]);
++			titan_ge_eth->rx_ring_skbs--;
++		}
++	}
++
++	if (titan_ge_eth->rx_ring_skbs != 0)
++		printk(KERN_ERR
++		       "%s: Error in freeing Rx Ring. %d skb's still"
++		       " stuck in RX Ring - ignoring them\n", netdev->name,
++		       titan_ge_eth->rx_ring_skbs);
++
++#ifndef TITAN_RX_RING_IN_SRAM
++	dma_free_coherent(&titan_ge_device[port_num]->dev,
++			  titan_ge_eth->rx_desc_area_size,
++			  (void *) titan_ge_eth->rx_desc_area,
++			  titan_ge_eth->rx_dma);
++#endif
++}
++
++/*
++ * Actually does the stop of the Ethernet device
++ */
++static void titan_ge_eth_stop(struct net_device *netdev)
++{
++	titan_ge_port_info *titan_ge_eth = netdev_priv(netdev);
++
++	netif_stop_queue(netdev);
++
++	titan_ge_port_reset(titan_ge_eth->port_num);
++
++	titan_ge_free_tx_rings(netdev);
++	titan_ge_free_rx_rings(netdev);
++
++	/* Disable the Tx and Rx Interrupts for all channels */
++	TITAN_GE_WRITE(TITAN_GE_INTR_XDMA_IE, 0x0);
++}
++
++/*
++ * Update the MAC address. Note that we have to write the
++ * address in three station registers, 16 bits each. And this
++ * has to be done for TMAC and RMAC
++ */
++static void titan_ge_update_mac_address(struct net_device *netdev)
++{
++	titan_ge_port_info *titan_ge_eth = netdev_priv(netdev);
++	unsigned int port_num = titan_ge_eth->port_num;
++	u8 p_addr[6];
++
++	memcpy(titan_ge_eth->port_mac_addr, netdev->dev_addr, 6);
++	memcpy(p_addr, netdev->dev_addr, 6);
++
++	/* Update the Address Filtering Match tables */
++	titan_ge_update_afx(titan_ge_eth);
++
++	printk("Station MAC : %d %d %d %d %d %d  \n",
++		p_addr[5], p_addr[4], p_addr[3],
++		p_addr[2], p_addr[1], p_addr[0]);
++
++	/* Set the MAC address here for TMAC and RMAC */
++	TITAN_GE_WRITE((TITAN_GE_TMAC_STATION_HI + (port_num << 12)),
++		       ((p_addr[5] << 8) | p_addr[4]));
++	TITAN_GE_WRITE((TITAN_GE_TMAC_STATION_MID + (port_num << 12)),
++		       ((p_addr[3] << 8) | p_addr[2]));
++	TITAN_GE_WRITE((TITAN_GE_TMAC_STATION_LOW + (port_num << 12)),
++		       ((p_addr[1] << 8) | p_addr[0]));
++
++	TITAN_GE_WRITE((TITAN_GE_RMAC_STATION_HI + (port_num << 12)),
++		       ((p_addr[5] << 8) | p_addr[4]));
++	TITAN_GE_WRITE((TITAN_GE_RMAC_STATION_MID + (port_num << 12)),
++		       ((p_addr[3] << 8) | p_addr[2]));
++	TITAN_GE_WRITE((TITAN_GE_RMAC_STATION_LOW + (port_num << 12)),
++		       ((p_addr[1] << 8) | p_addr[0]));
++}
++
++/*
++ * Set the MAC address of the Ethernet device
++ */
++static int titan_ge_set_mac_address(struct net_device *dev, void *addr)
++{
++	titan_ge_port_info *tp = netdev_priv(dev);
++	struct sockaddr *sa = addr;
++
++	memcpy(dev->dev_addr, sa->sa_data, dev->addr_len);
++
++	spin_lock_irq(&tp->lock);
++	titan_ge_update_mac_address(dev);
++	spin_unlock_irq(&tp->lock);
++
++	return 0;
++}
++
++/*
++ * Get the Ethernet device stats
++ */
++static struct net_device_stats *titan_ge_get_stats(struct net_device *netdev)
++{
++	titan_ge_port_info *titan_ge_eth = netdev_priv(netdev);
++
++	return &titan_ge_eth->stats;
++}
++
++/*
++ * Initialize the Rx descriptor ring for the Titan Ge
++ */
++static int titan_ge_init_rx_desc_ring(titan_ge_port_info * titan_eth_port,
++				      int rx_desc_num,
++				      int rx_buff_size,
++				      unsigned long rx_desc_base_addr,
++				      unsigned long rx_buff_base_addr,
++				      unsigned long rx_dma)
++{
++	volatile titan_ge_rx_desc *rx_desc;
++	unsigned long buffer_addr;
++	int index;
++	unsigned long titan_ge_rx_desc_bus = rx_dma;
++
++	buffer_addr = rx_buff_base_addr;
++	rx_desc = (titan_ge_rx_desc *) rx_desc_base_addr;
++
++	/* Check alignment */
++	if (rx_buff_base_addr & 0xF)
++		return 0;
++
++	/* Check Rx buffer size */
++	if ((rx_buff_size < 8) || (rx_buff_size > TITAN_GE_MAX_RX_BUFFER))
++		return 0;
++
++	/* 64-bit alignment
++	if ((rx_buff_base_addr + rx_buff_size) & 0x7)
++		return 0; */
++
++	/* Initialize the Rx desc ring */
++	for (index = 0; index < rx_desc_num; index++) {
++		titan_ge_rx_desc_bus += sizeof(titan_ge_rx_desc);
++		rx_desc[index].cmd_sts = 0;
++		rx_desc[index].buffer_addr = buffer_addr;
++		titan_eth_port->rx_skb[index] = NULL;
++		buffer_addr += rx_buff_size;
++	}
++
++	titan_eth_port->rx_curr_desc_q = 0;
++	titan_eth_port->rx_used_desc_q = 0;
++
++	titan_eth_port->rx_desc_area = (titan_ge_rx_desc *) rx_desc_base_addr;
++	titan_eth_port->rx_desc_area_size =
++	    rx_desc_num * sizeof(titan_ge_rx_desc);
++
++	titan_eth_port->rx_dma = rx_dma;
++
++	return TITAN_OK;
++}
++
++/*
++ * Initialize the Tx descriptor ring. Descriptors in the SRAM
++ */
++static int titan_ge_init_tx_desc_ring(titan_ge_port_info * titan_ge_port,
++				      int tx_desc_num,
++				      unsigned long tx_desc_base_addr,
++				      unsigned long tx_dma)
++{
++	titan_ge_tx_desc *tx_desc;
++	int index;
++	unsigned long titan_ge_tx_desc_bus = tx_dma;
++
++	if (tx_desc_base_addr & 0xF)
++		return 0;
++
++	tx_desc = (titan_ge_tx_desc *) tx_desc_base_addr;
++
++	for (index = 0; index < tx_desc_num; index++) {
++		titan_ge_port->tx_dma_array[index] =
++		    (dma_addr_t) titan_ge_tx_desc_bus;
++		titan_ge_tx_desc_bus += sizeof(titan_ge_tx_desc);
++		tx_desc[index].cmd_sts = 0x0000;
++		tx_desc[index].buffer_len = 0;
++		tx_desc[index].buffer_addr = 0x00000000;
++		titan_ge_port->tx_skb[index] = NULL;
++	}
++
++	titan_ge_port->tx_curr_desc_q = 0;
++	titan_ge_port->tx_used_desc_q = 0;
++
++	titan_ge_port->tx_desc_area = (titan_ge_tx_desc *) tx_desc_base_addr;
++	titan_ge_port->tx_desc_area_size =
++	    tx_desc_num * sizeof(titan_ge_tx_desc);
++
++	titan_ge_port->tx_dma = tx_dma;
++	return TITAN_OK;
++}
++
++/*
++ * Initialize the device as an Ethernet device
++ */
++static int __init titan_ge_probe(struct device *device)
++{
++	titan_ge_port_info *titan_ge_eth;
++	struct net_device *netdev;
++	int port = to_platform_device(device)->id;
++	int err;
++
++	netdev = alloc_etherdev(sizeof(titan_ge_port_info));
++	if (!netdev) {
++		err = -ENODEV;
++		goto out;
++	}
++
++	netdev->open = titan_ge_open;
++	netdev->stop = titan_ge_stop;
++	netdev->hard_start_xmit = titan_ge_start_xmit;
++	netdev->get_stats = titan_ge_get_stats;
++	netdev->set_multicast_list = titan_ge_set_multi;
++	netdev->set_mac_address = titan_ge_set_mac_address;
++
++	/* Tx timeout */
++	netdev->tx_timeout = titan_ge_tx_timeout;
++	netdev->watchdog_timeo = 2 * HZ;
++
++	/* Set these to very high values */
++	netdev->poll = titan_ge_poll;
++	netdev->weight = 64;
++
++	netdev->tx_queue_len = TITAN_GE_TX_QUEUE;
++	netif_carrier_off(netdev);
++	netdev->base_addr = 0;
++
++	netdev->change_mtu = titan_ge_change_mtu;
++
++	titan_ge_eth = netdev_priv(netdev);
++	/* Allocation of memory for the driver structures */
++
++	titan_ge_eth->port_num = port;
++
++	/* Configure the Tx timeout handler */
++	INIT_WORK(&titan_ge_eth->tx_timeout_task,
++		  (void (*)(void *)) titan_ge_tx_timeout_task, netdev);
++
++	spin_lock_init(&titan_ge_eth->lock);
++
++	/* set MAC addresses */
++	memcpy(netdev->dev_addr, titan_ge_mac_addr_base, 6);
++	netdev->dev_addr[5] += port;
++
++	err = register_netdev(netdev);
++
++	if (err)
++		goto out_free_netdev;
++
++	printk(KERN_NOTICE
++	       "%s: port %d with MAC address %02x:%02x:%02x:%02x:%02x:%02x\n",
++	       netdev->name, port, netdev->dev_addr[0],
++	       netdev->dev_addr[1], netdev->dev_addr[2],
++	       netdev->dev_addr[3], netdev->dev_addr[4],
++	       netdev->dev_addr[5]);
++
++	printk(KERN_NOTICE "Rx NAPI supported, Tx Coalescing ON \n");
++
++	return 0;
++
++out_free_netdev:
++	kfree(netdev);
++
++out:
++	return err;
++}
++
++static void __devexit titan_device_remove(struct device *device)
++{
++}
++
++/*
++ * Reset the Ethernet port
++ */
++static void titan_ge_port_reset(unsigned int port_num)
++{
++	unsigned int reg_data;
++
++	/* Stop the Tx port activity */
++	reg_data = TITAN_GE_READ(TITAN_GE_TMAC_CONFIG_1 +
++				(port_num << 12));
++	reg_data &= ~(0x0001);
++	TITAN_GE_WRITE((TITAN_GE_TMAC_CONFIG_1 +
++			(port_num << 12)), reg_data);
++
++	/* Stop the Rx port activity */
++	reg_data = TITAN_GE_READ(TITAN_GE_RMAC_CONFIG_1 +
++				(port_num << 12));
++	reg_data &= ~(0x0001);
++	TITAN_GE_WRITE((TITAN_GE_RMAC_CONFIG_1 +
++			(port_num << 12)), reg_data);
++
++	return;
++}
++
++/*
++ * Return the Tx desc after use by the XDMA
++ */
++static int titan_ge_return_tx_desc(titan_ge_port_info * titan_ge_eth, int port)
++{
++	int tx_desc_used;
++	struct sk_buff *skb;
++
++	tx_desc_used = titan_ge_eth->tx_used_desc_q;
++
++	/* return right away */
++	if (tx_desc_used == titan_ge_eth->tx_curr_desc_q)
++		return TITAN_ERROR;
++
++	/* Now the critical stuff */
++	skb = titan_ge_eth->tx_skb[tx_desc_used];
++
++	dev_kfree_skb_any(skb);
++
++	titan_ge_eth->tx_skb[tx_desc_used] = NULL;
++	titan_ge_eth->tx_used_desc_q =
++	    (tx_desc_used + 1) % TITAN_GE_TX_QUEUE;
++
++	return 0;
++}
++
++/*
++ * Coalescing for the Tx path
++ */
++static unsigned long titan_ge_tx_coal(unsigned long delay, int port)
++{
++	unsigned long rx_delay;
++
++	rx_delay = TITAN_GE_READ(TITAN_GE_INT_COALESCING);
++	delay = (delay << 16) | rx_delay;
++
++	TITAN_GE_WRITE(TITAN_GE_INT_COALESCING, delay);
++	TITAN_GE_WRITE(0x5038, delay);
++
++	return delay;
++}
++
++static struct device_driver titan_soc_driver = {
++	.name   = titan_string,
++	.bus    = &platform_bus_type,
++	.probe  = titan_ge_probe,
++	.remove = __devexit_p(titan_device_remove),
++};
++
++static void titan_platform_release (struct device *device)
++{
++	struct platform_device *pldev;
++
++	/* free device */
++	pldev = to_platform_device (device);
++	kfree (pldev);
++}
++
++/*
++ * Register the Titan GE with the kernel
++ */
++static int __init titan_ge_init_module(void)
++{
++	struct platform_device *pldev;
++	unsigned int version, device;
++	int i;
++
++	printk(KERN_NOTICE
++	       "PMC-Sierra TITAN 10/100/1000 Ethernet Driver \n");
++
++	titan_ge_base = (unsigned long) ioremap(TITAN_GE_BASE, TITAN_GE_SIZE);
++	if (!titan_ge_base) {
++		printk("Mapping Titan GE failed\n");
++		goto out;
++	}
++
++	device = TITAN_GE_READ(TITAN_GE_DEVICE_ID);
++	version = (device & 0x000f0000) >> 16;
++	device &= 0x0000ffff;
++
++	printk(KERN_NOTICE "Device Id : %x,  Version : %x \n", device, version);
++
++#ifdef TITAN_RX_RING_IN_SRAM
++	titan_ge_sram = (unsigned long) ioremap(TITAN_SRAM_BASE,
++						TITAN_SRAM_SIZE);
++	if (!titan_ge_sram) {
++		printk("Mapping Titan SRAM failed\n");
++		goto out_unmap_ge;
++	}
++#endif
++
++	if (driver_register(&titan_soc_driver)) {
++		printk(KERN_ERR "Driver registration failed\n");
++		goto out_unmap_sram;
++	}
++
++	for (i = 0; i < 3; i++) {
++		titan_ge_device[i] = NULL;
++
++	        if (!(pldev = kmalloc (sizeof (*pldev), GFP_KERNEL)))
++	                continue;
++
++                memset (pldev, 0, sizeof (*pldev));
++                pldev->name		= titan_string;
++                pldev->id		= i;
++                pldev->dev.release	= titan_platform_release;
++                titan_ge_device[i]	= pldev;
++
++                if (platform_device_register (pldev)) {
++                        kfree (pldev);
++                        titan_ge_device[i] = NULL;
++                        continue;
++                }
++                                                                                
++                if (!pldev->dev.driver) {
++	                /*
++			 * The driver was not bound to this device, there was
++	                 * no hardware at this address. Unregister it, as the
++	                 * release fuction will take care of freeing the
++	                 * allocated structure
++			 */
++                        titan_ge_device[i] = NULL;
++                        platform_device_unregister (pldev);
++                }
++        }
++
++	return 0;
++
++out_unmap_sram:
++	iounmap((void *)titan_ge_sram);
++
++out_unmap_ge:
++	iounmap((void *)titan_ge_base);
++
++out:
++	return -ENOMEM;
++}
++
++/*
++ * Unregister the Titan GE from the kernel
++ */
++static void __exit titan_ge_cleanup_module(void)
++{
++	int i;
++
++	driver_unregister(&titan_soc_driver);
++
++	for (i = 0; i < 3; i++) {
++		if (titan_ge_device[i]) {
++			platform_device_unregister (titan_ge_device[i]);
++			titan_ge_device[i] = NULL;
++		}
++	}
++
++	iounmap((void *)titan_ge_sram);
++	iounmap((void *)titan_ge_base);
++}
++
++MODULE_AUTHOR("Manish Lachwani <lachwani at pmc-sierra.com>");
++MODULE_DESCRIPTION("Titan GE Ethernet driver");
++MODULE_LICENSE("GPL");
++
++module_init(titan_ge_init_module);
++module_exit(titan_ge_cleanup_module);
+diff -Naur linux-2.6.15.orig/drivers/net/titan_ge.h linux-2.6.15/drivers/net/titan_ge.h
+--- linux-2.6.15.orig/drivers/net/titan_ge.h	1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.15/drivers/net/titan_ge.h	2006-01-09 19:54:13.000000000 +0000
+@@ -0,0 +1,419 @@
++#ifndef _TITAN_GE_H_
++#define _TITAN_GE_H_
++
++#include <linux/config.h>
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/config.h>
++#include <linux/spinlock.h>
++#include <asm/byteorder.h>
++
++/*
++ * These functions should be later moved to a more generic location since there
++ * will be others accessing it also
++ */
++
++/*
++ * This is the way it works: LKB5 Base is at 0x0128. TITAN_BASE is defined in
++ * include/asm/titan_dep.h. TITAN_GE_BASE is the value in the TITAN_GE_LKB5
++ * register.
++ */
++
++#define	TITAN_GE_BASE	0xfe000000UL
++#define	TITAN_GE_SIZE	0x10000UL
++
++extern unsigned long titan_ge_base;
++
++#define	TITAN_GE_WRITE(offset, data) \
++		*(volatile u32 *)(titan_ge_base + (offset)) = (data)
++
++#define TITAN_GE_READ(offset) *(volatile u32 *)(titan_ge_base + (offset))
++
++#ifndef msec_delay
++#define msec_delay(x)   do { if(in_interrupt()) { \
++				/* Don't mdelay in interrupt context! */ \
++				BUG(); \
++			} else { \
++				set_current_state(TASK_UNINTERRUPTIBLE); \
++				schedule_timeout((x * HZ)/1000); \
++			} } while(0)
++#endif
++
++#define TITAN_GE_PORT_0
++
++#define	TITAN_SRAM_BASE		((OCD_READ(RM9000x2_OCD_LKB13) & ~1) << 4)
++#define	TITAN_SRAM_SIZE		0x2000UL
++
++extern unsigned long titan_ge_sram;
++
++/*
++ * We may need these constants
++ */
++#define TITAN_BIT0    0x00000001
++#define TITAN_BIT1    0x00000002
++#define TITAN_BIT2    0x00000004
++#define TITAN_BIT3    0x00000008
++#define TITAN_BIT4    0x00000010
++#define TITAN_BIT5    0x00000020
++#define TITAN_BIT6    0x00000040
++#define TITAN_BIT7    0x00000080
++#define TITAN_BIT8    0x00000100
++#define TITAN_BIT9    0x00000200
++#define TITAN_BIT10   0x00000400
++#define TITAN_BIT11   0x00000800
++#define TITAN_BIT12   0x00001000
++#define TITAN_BIT13   0x00002000
++#define TITAN_BIT14   0x00004000
++#define TITAN_BIT15   0x00008000
++#define TITAN_BIT16   0x00010000
++#define TITAN_BIT17   0x00020000
++#define TITAN_BIT18   0x00040000
++#define TITAN_BIT19   0x00080000
++#define TITAN_BIT20   0x00100000
++#define TITAN_BIT21   0x00200000
++#define TITAN_BIT22   0x00400000
++#define TITAN_BIT23   0x00800000
++#define TITAN_BIT24   0x01000000
++#define TITAN_BIT25   0x02000000
++#define TITAN_BIT26   0x04000000
++#define TITAN_BIT27   0x08000000
++#define TITAN_BIT28   0x10000000
++#define TITAN_BIT29   0x20000000
++#define TITAN_BIT30   0x40000000
++#define TITAN_BIT31   0x80000000
++
++/* Flow Control */
++#define	TITAN_GE_FC_NONE	0x0
++#define	TITAN_GE_FC_FULL	0x1
++#define	TITAN_GE_FC_TX_PAUSE	0x2
++#define	TITAN_GE_FC_RX_PAUSE	0x3
++
++/* Duplex Settings */
++#define	TITAN_GE_FULL_DUPLEX	0x1
++#define	TITAN_GE_HALF_DUPLEX	0x2
++
++/* Speed settings */
++#define	TITAN_GE_SPEED_1000	0x1
++#define	TITAN_GE_SPEED_100	0x2
++#define	TITAN_GE_SPEED_10	0x3
++
++/* Debugging info only */
++#undef TITAN_DEBUG
++
++/* Keep the rings in the Titan's SSRAM */
++#define TITAN_RX_RING_IN_SRAM
++
++#ifdef CONFIG_64BIT
++#define	TITAN_GE_IE_MASK	0xfffffffffb001b64
++#define	TITAN_GE_IE_STATUS	0xfffffffffb001b60
++#else
++#define	TITAN_GE_IE_MASK	0xfb001b64
++#define	TITAN_GE_IE_STATUS	0xfb001b60
++#endif
++
++/* Support for Jumbo Frames */
++#undef TITAN_GE_JUMBO_FRAMES
++
++/* Rx buffer size */
++#ifdef TITAN_GE_JUMBO_FRAMES
++#define	TITAN_GE_JUMBO_BUFSIZE	9080
++#else
++#define	TITAN_GE_STD_BUFSIZE	1580
++#endif
++
++/*
++ * Tx and Rx Interrupt Coalescing parameter. These values are
++ * for 1 Ghz processor. Rx coalescing can be taken care of
++ * by NAPI. NAPI is adaptive and hence useful. Tx coalescing
++ * is not adaptive. Hence, these values need to be adjusted
++ * based on load, CPU speed etc.
++ */
++#define	TITAN_GE_RX_COAL	150
++#define	TITAN_GE_TX_COAL	300
++
++#if defined(__BIG_ENDIAN)
++
++/* Define the Rx descriptor */
++typedef struct eth_rx_desc {
++	u32     reserved;	/* Unused 		*/
++	u32     buffer_addr;	/* CPU buffer address 	*/
++	u32	cmd_sts;	/* Command and Status	*/
++	u32	buffer;		/* XDMA buffer address	*/
++} titan_ge_rx_desc;
++
++/* Define the Tx descriptor */
++typedef struct eth_tx_desc {
++	u16     cmd_sts;	/* Command, Status and Buffer count */
++	u16	buffer_len;	/* Length of the buffer	*/
++	u32     buffer_addr;	/* Physical address of the buffer */
++} titan_ge_tx_desc;
++
++#elif defined(__LITTLE_ENDIAN)
++
++/* Define the Rx descriptor */
++typedef struct eth_rx_desc {
++	u32	buffer_addr;	/* CPU buffer address   */
++	u32	reserved;	/* Unused               */
++	u32	buffer;		/* XDMA buffer address  */
++	u32	cmd_sts;	/* Command and Status   */
++} titan_ge_rx_desc;
++
++/* Define the Tx descriptor */
++typedef struct eth_tx_desc {
++	u32     buffer_addr;	/* Physical address of the buffer */
++	u16     buffer_len;     /* Length of the buffer */
++	u16     cmd_sts;        /* Command, Status and Buffer count */
++} titan_ge_tx_desc;
++#endif
++
++/* Default Tx Queue Size */
++#define	TITAN_GE_TX_QUEUE	128
++#define TITAN_TX_RING_BYTES	(TITAN_GE_TX_QUEUE * sizeof(struct eth_tx_desc))
++
++/* Default Rx Queue Size */
++#define	TITAN_GE_RX_QUEUE	64
++#define TITAN_RX_RING_BYTES	(TITAN_GE_RX_QUEUE * sizeof(struct eth_rx_desc))
++
++/* Packet Structure */
++typedef struct _pkt_info {
++	unsigned int           len;
++	unsigned int            cmd_sts;
++	unsigned int            buffer;
++	struct sk_buff          *skb;
++	unsigned int		checksum;
++} titan_ge_packet;
++
++
++#define	PHYS_CNT	3
++
++/* Titan Port specific data structure */
++typedef struct _eth_port_ctrl {
++	unsigned int		port_num;
++	u8			port_mac_addr[6];
++
++	/* Rx descriptor pointers */
++	int 			rx_curr_desc_q, rx_used_desc_q;
++
++	/* Tx descriptor pointers */
++	int 			tx_curr_desc_q, tx_used_desc_q;
++
++	/* Rx descriptor area */
++	volatile titan_ge_rx_desc	*rx_desc_area;
++	unsigned int			rx_desc_area_size;
++	struct sk_buff*			rx_skb[TITAN_GE_RX_QUEUE];
++
++	/* Tx Descriptor area */
++	volatile titan_ge_tx_desc	*tx_desc_area;
++	unsigned int                    tx_desc_area_size;
++	struct sk_buff*                 tx_skb[TITAN_GE_TX_QUEUE];
++
++	/* Timeout task */
++	struct work_struct		tx_timeout_task;
++
++	/* DMA structures and handles */
++	dma_addr_t			tx_dma;
++	dma_addr_t			rx_dma;
++	dma_addr_t			tx_dma_array[TITAN_GE_TX_QUEUE];
++
++	/* Device lock */
++	spinlock_t			lock;
++
++	unsigned int			tx_ring_skbs;
++	unsigned int			rx_ring_size;
++	unsigned int			tx_ring_size;
++	unsigned int			rx_ring_skbs;
++
++	struct net_device_stats		stats;
++
++	/* Tx and Rx coalescing */
++	unsigned long			rx_int_coal;
++	unsigned long			tx_int_coal;
++
++	/* Threshold for replenishing the Rx and Tx rings */
++	unsigned int			tx_threshold;
++	unsigned int			rx_threshold;
++
++	/* NAPI work limit */
++	unsigned int			rx_work_limit;
++} titan_ge_port_info;
++
++/* Titan specific constants */
++#define	TITAN_ETH_PORT_IRQ		3
++
++/* Max Rx buffer */
++#define	TITAN_GE_MAX_RX_BUFFER		65536
++
++/* Tx and Rx Error */
++#define	TITAN_GE_ERROR
++
++/* Rx Descriptor Command and Status */
++
++#define	TITAN_GE_RX_CRC_ERROR		TITAN_BIT27	/* crc error */
++#define	TITAN_GE_RX_OVERFLOW_ERROR	TITAN_BIT15	/* overflow */
++#define TITAN_GE_RX_BUFFER_OWNED	TITAN_BIT21	/* buffer ownership */
++#define	TITAN_GE_RX_STP			TITAN_BIT31	/* start of packet */
++#define	TITAN_GE_RX_BAM			TITAN_BIT30	/* broadcast address match */
++#define TITAN_GE_RX_PAM			TITAN_BIT28	/* physical address match */
++#define TITAN_GE_RX_LAFM		TITAN_BIT29	/* logical address filter match */
++#define TITAN_GE_RX_VLAN		TITAN_BIT26	/* virtual lans */
++#define TITAN_GE_RX_PERR		TITAN_BIT19	/* packet error */
++#define TITAN_GE_RX_TRUNC		TITAN_BIT20	/* packet size greater than 32 buffers */
++
++/* Tx Descriptor Command */
++#define	TITAN_GE_TX_BUFFER_OWNED	TITAN_BIT5	/* buffer ownership */
++#define	TITAN_GE_TX_ENABLE_INTERRUPT	TITAN_BIT15	/* Interrupt Enable */
++
++/* Return Status */
++#define	TITAN_OK	0x1	/* Good Status */
++#define	TITAN_ERROR	0x2	/* Error Status */
++
++/* MIB specific register offset */
++#define TITAN_GE_MSTATX_STATS_BASE_LOW       0x0800  /* MSTATX COUNTL[15:0] */
++#define TITAN_GE_MSTATX_STATS_BASE_MID       0x0804  /* MSTATX COUNTM[15:0] */
++#define TITAN_GE_MSTATX_STATS_BASE_HI        0x0808  /* MSTATX COUNTH[7:0] */
++#define TITAN_GE_MSTATX_CONTROL              0x0828  /* MSTATX Control */
++#define TITAN_GE_MSTATX_VARIABLE_SELECT      0x082C  /* MSTATX Variable Select */
++
++/* MIB counter offsets, add to the TITAN_GE_MSTATX_STATS_BASE_XXX */
++#define TITAN_GE_MSTATX_RXFRAMESOK                   0x0040
++#define TITAN_GE_MSTATX_RXOCTETSOK                   0x0050
++#define TITAN_GE_MSTATX_RXFRAMES                     0x0060
++#define TITAN_GE_MSTATX_RXOCTETS                     0x0070
++#define TITAN_GE_MSTATX_RXUNICASTFRAMESOK            0x0080
++#define TITAN_GE_MSTATX_RXBROADCASTFRAMESOK          0x0090
++#define TITAN_GE_MSTATX_RXMULTICASTFRAMESOK          0x00A0
++#define TITAN_GE_MSTATX_RXTAGGEDFRAMESOK             0x00B0
++#define TITAN_GE_MSTATX_RXMACPAUSECONTROLFRAMESOK    0x00C0
++#define TITAN_GE_MSTATX_RXMACCONTROLFRAMESOK         0x00D0
++#define TITAN_GE_MSTATX_RXFCSERROR                   0x00E0
++#define TITAN_GE_MSTATX_RXALIGNMENTERROR             0x00F0
++#define TITAN_GE_MSTATX_RXSYMBOLERROR                0x0100
++#define TITAN_GE_MSTATX_RXLAYER1ERROR                0x0110
++#define TITAN_GE_MSTATX_RXINRANGELENGTHERROR         0x0120
++#define TITAN_GE_MSTATX_RXLONGLENGTHERROR            0x0130
++#define TITAN_GE_MSTATX_RXLONGLENGTHCRCERROR         0x0140
++#define TITAN_GE_MSTATX_RXSHORTLENGTHERROR           0x0150
++#define TITAN_GE_MSTATX_RXSHORTLLENGTHCRCERROR       0x0160
++#define TITAN_GE_MSTATX_RXFRAMES64OCTETS             0x0170
++#define TITAN_GE_MSTATX_RXFRAMES65TO127OCTETS        0x0180
++#define TITAN_GE_MSTATX_RXFRAMES128TO255OCTETS       0x0190
++#define TITAN_GE_MSTATX_RXFRAMES256TO511OCTETS       0x01A0
++#define TITAN_GE_MSTATX_RXFRAMES512TO1023OCTETS      0x01B0
++#define TITAN_GE_MSTATX_RXFRAMES1024TO1518OCTETS     0x01C0
++#define TITAN_GE_MSTATX_RXFRAMES1519TOMAXSIZE        0x01D0
++#define TITAN_GE_MSTATX_RXSTATIONADDRESSFILTERED     0x01E0
++#define TITAN_GE_MSTATX_RXVARIABLE                   0x01F0
++#define TITAN_GE_MSTATX_GENERICADDRESSFILTERED       0x0200
++#define TITAN_GE_MSTATX_UNICASTFILTERED              0x0210
++#define TITAN_GE_MSTATX_MULTICASTFILTERED            0x0220
++#define TITAN_GE_MSTATX_BROADCASTFILTERED            0x0230
++#define TITAN_GE_MSTATX_HASHFILTERED                 0x0240
++#define TITAN_GE_MSTATX_TXFRAMESOK                   0x0250
++#define TITAN_GE_MSTATX_TXOCTETSOK                   0x0260
++#define TITAN_GE_MSTATX_TXOCTETS                     0x0270
++#define TITAN_GE_MSTATX_TXTAGGEDFRAMESOK             0x0280
++#define TITAN_GE_MSTATX_TXMACPAUSECONTROLFRAMESOK    0x0290
++#define TITAN_GE_MSTATX_TXFCSERROR                   0x02A0
++#define TITAN_GE_MSTATX_TXSHORTLENGTHERROR           0x02B0
++#define TITAN_GE_MSTATX_TXLONGLENGTHERROR            0x02C0
++#define TITAN_GE_MSTATX_TXSYSTEMERROR                0x02D0
++#define TITAN_GE_MSTATX_TXMACERROR                   0x02E0
++#define TITAN_GE_MSTATX_TXCARRIERSENSEERROR          0x02F0
++#define TITAN_GE_MSTATX_TXSQETESTERROR               0x0300
++#define TITAN_GE_MSTATX_TXUNICASTFRAMESOK            0x0310
++#define TITAN_GE_MSTATX_TXBROADCASTFRAMESOK          0x0320
++#define TITAN_GE_MSTATX_TXMULTICASTFRAMESOK          0x0330
++#define TITAN_GE_MSTATX_TXUNICASTFRAMESATTEMPTED     0x0340
++#define TITAN_GE_MSTATX_TXBROADCASTFRAMESATTEMPTED   0x0350
++#define TITAN_GE_MSTATX_TXMULTICASTFRAMESATTEMPTED   0x0360
++#define TITAN_GE_MSTATX_TXFRAMES64OCTETS             0x0370
++#define TITAN_GE_MSTATX_TXFRAMES65TO127OCTETS        0x0380
++#define TITAN_GE_MSTATX_TXFRAMES128TO255OCTETS       0x0390
++#define TITAN_GE_MSTATX_TXFRAMES256TO511OCTETS       0x03A0
++#define TITAN_GE_MSTATX_TXFRAMES512TO1023OCTETS      0x03B0
++#define TITAN_GE_MSTATX_TXFRAMES1024TO1518OCTETS     0x03C0
++#define TITAN_GE_MSTATX_TXFRAMES1519TOMAXSIZE        0x03D0
++#define TITAN_GE_MSTATX_TXVARIABLE                   0x03E0
++#define TITAN_GE_MSTATX_RXSYSTEMERROR                0x03F0
++#define TITAN_GE_MSTATX_SINGLECOLLISION              0x0400
++#define TITAN_GE_MSTATX_MULTIPLECOLLISION            0x0410
++#define TITAN_GE_MSTATX_DEFERREDXMISSIONS            0x0420
++#define TITAN_GE_MSTATX_LATECOLLISIONS               0x0430
++#define TITAN_GE_MSTATX_ABORTEDDUETOXSCOLLS          0x0440
++
++/* Interrupt specific defines */
++#define TITAN_GE_DEVICE_ID         0x0000  /* Device ID */
++#define TITAN_GE_RESET             0x0004  /* Reset reg */
++#define TITAN_GE_TSB_CTRL_0        0x000C  /* TSB Control reg 0 */
++#define TITAN_GE_TSB_CTRL_1        0x0010  /* TSB Control reg 1 */
++#define TITAN_GE_INTR_GRP0_STATUS  0x0040  /* General Interrupt Group 0 Status */
++#define TITAN_GE_INTR_XDMA_CORE_A  0x0048  /* XDMA Channel Interrupt Status, Core A*/
++#define TITAN_GE_INTR_XDMA_CORE_B  0x004C  /* XDMA Channel Interrupt Status, Core B*/
++#define	TITAN_GE_INTR_XDMA_IE	   0x0058  /* XDMA Channel Interrupt Enable */
++#define TITAN_GE_SDQPF_ECC_INTR    0x480C  /* SDQPF ECC Interrupt Status */
++#define TITAN_GE_SDQPF_RXFIFO_CTL  0x4828  /* SDQPF RxFifo Control and Interrupt Enb*/
++#define TITAN_GE_SDQPF_RXFIFO_INTR 0x482C  /* SDQPF RxFifo Interrupt Status */
++#define TITAN_GE_SDQPF_TXFIFO_CTL  0x4928  /* SDQPF TxFifo Control and Interrupt Enb*/
++#define TITAN_GE_SDQPF_TXFIFO_INTR 0x492C  /* SDQPF TxFifo Interrupt Status */
++#define	TITAN_GE_SDQPF_RXFIFO_0	   0x4840  /* SDQPF RxFIFO Enable */
++#define	TITAN_GE_SDQPF_TXFIFO_0	   0x4940  /* SDQPF TxFIFO Enable */
++#define TITAN_GE_XDMA_CONFIG       0x5000  /* XDMA Global Configuration */
++#define TITAN_GE_XDMA_INTR_SUMMARY 0x5010  /* XDMA Interrupt Summary */
++#define TITAN_GE_XDMA_BUFADDRPRE   0x5018  /* XDMA Buffer Address Prefix */
++#define TITAN_GE_XDMA_DESCADDRPRE  0x501C  /* XDMA Descriptor Address Prefix */
++#define TITAN_GE_XDMA_PORTWEIGHT   0x502C  /* XDMA Port Weight Configuration */
++
++/* Rx MAC defines */
++#define TITAN_GE_RMAC_CONFIG_1               0x1200  /* RMAC Configuration 1 */
++#define TITAN_GE_RMAC_CONFIG_2               0x1204  /* RMAC Configuration 2 */
++#define TITAN_GE_RMAC_MAX_FRAME_LEN          0x1208  /* RMAC Max Frame Length */
++#define TITAN_GE_RMAC_STATION_HI             0x120C  /* Rx Station Address High */
++#define TITAN_GE_RMAC_STATION_MID            0x1210  /* Rx Station Address Middle */
++#define TITAN_GE_RMAC_STATION_LOW            0x1214  /* Rx Station Address Low */
++#define TITAN_GE_RMAC_LINK_CONFIG            0x1218  /* RMAC Link Configuration */
++
++/* Tx MAC defines */
++#define TITAN_GE_TMAC_CONFIG_1               0x1240  /* TMAC Configuration 1 */
++#define TITAN_GE_TMAC_CONFIG_2               0x1244  /* TMAC Configuration 2 */
++#define TITAN_GE_TMAC_IPG                    0x1248  /* TMAC Inter-Packet Gap */
++#define TITAN_GE_TMAC_STATION_HI             0x124C  /* Tx Station Address High */
++#define TITAN_GE_TMAC_STATION_MID            0x1250  /* Tx Station Address Middle */
++#define TITAN_GE_TMAC_STATION_LOW            0x1254  /* Tx Station Address Low */
++#define TITAN_GE_TMAC_MAX_FRAME_LEN          0x1258  /* TMAC Max Frame Length */
++#define TITAN_GE_TMAC_MIN_FRAME_LEN          0x125C  /* TMAC Min Frame Length */
++#define TITAN_GE_TMAC_PAUSE_FRAME_TIME       0x1260  /* TMAC Pause Frame Time */
++#define TITAN_GE_TMAC_PAUSE_FRAME_INTERVAL   0x1264  /* TMAC Pause Frame Interval */
++
++/* GMII register */
++#define TITAN_GE_GMII_INTERRUPT_STATUS       0x1348  /* GMII Interrupt Status */
++#define TITAN_GE_GMII_CONFIG_GENERAL         0x134C  /* GMII Configuration General */
++#define TITAN_GE_GMII_CONFIG_MODE            0x1350  /* GMII Configuration Mode */
++
++/* Tx and Rx XDMA defines */
++#define	TITAN_GE_INT_COALESCING		     0x5030 /* Interrupt Coalescing */
++#define	TITAN_GE_CHANNEL0_CONFIG	     0x5040 /* Channel 0 XDMA config */
++#define	TITAN_GE_CHANNEL0_INTERRUPT	     0x504c /* Channel 0 Interrupt Status */
++#define	TITAN_GE_GDI_INTERRUPT_ENABLE        0x5050 /* IE for the GDI Errors */
++#define	TITAN_GE_CHANNEL0_PACKET	     0x5060 /* Channel 0 Packet count */
++#define	TITAN_GE_CHANNEL0_BYTE		     0x5064 /* Channel 0 Byte count */
++#define	TITAN_GE_CHANNEL0_TX_DESC	     0x5054 /* Channel 0 Tx first desc */
++#define	TITAN_GE_CHANNEL0_RX_DESC	     0x5058 /* Channel 0 Rx first desc */
++
++/* AFX (Address Filter Exact) register offsets for Slice 0 */
++#define TITAN_GE_AFX_EXACT_MATCH_LOW         0x1100  /* AFX Exact Match Address Low*/
++#define TITAN_GE_AFX_EXACT_MATCH_MID         0x1104  /* AFX Exact Match Address Mid*/
++#define TITAN_GE_AFX_EXACT_MATCH_HIGH        0x1108  /* AFX Exact Match Address Hi */
++#define TITAN_GE_AFX_EXACT_MATCH_VID         0x110C  /* AFX Exact Match VID */
++#define TITAN_GE_AFX_MULTICAST_HASH_LOW      0x1110  /* AFX Multicast HASH Low */
++#define TITAN_GE_AFX_MULTICAST_HASH_MIDLOW   0x1114  /* AFX Multicast HASH MidLow */
++#define TITAN_GE_AFX_MULTICAST_HASH_MIDHI    0x1118  /* AFX Multicast HASH MidHi */
++#define TITAN_GE_AFX_MULTICAST_HASH_HI       0x111C  /* AFX Multicast HASH Hi */
++#define TITAN_GE_AFX_ADDRS_FILTER_CTRL_0     0x1120  /* AFX Address Filter Ctrl 0 */
++#define TITAN_GE_AFX_ADDRS_FILTER_CTRL_1     0x1124  /* AFX Address Filter Ctrl 1 */
++#define TITAN_GE_AFX_ADDRS_FILTER_CTRL_2     0x1128  /* AFX Address Filter Ctrl 2 */
++
++/* Traffic Groomer block */
++#define        TITAN_GE_TRTG_CONFIG	     0x1000  /* TRTG Config */
++
++#endif 				/* _TITAN_GE_H_ */
++
+diff -Naur linux-2.6.15.orig/drivers/net/titan_mdio.c linux-2.6.15/drivers/net/titan_mdio.c
+--- linux-2.6.15.orig/drivers/net/titan_mdio.c	1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.15/drivers/net/titan_mdio.c	2006-01-09 19:54:13.000000000 +0000
+@@ -0,0 +1,217 @@
++/*
++ * drivers/net/titan_mdio.c - Driver for Titan ethernet ports
++ *
++ * Copyright (C) 2003 PMC-Sierra Inc.
++ * Author : Manish Lachwani (lachwani at pmc-sierra.com)
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * as published by the Free Software Foundation; either version 2
++ * of the License, or (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
++ *
++ * Management Data IO (MDIO) driver for the Titan GMII. Interacts with the Marvel PHY
++ * on the Titan. No support for the TBI as yet.
++ *
++ */
++
++#include	"titan_mdio.h"
++
++#define MDIO_DEBUG
++
++/*
++ * Local constants
++ */
++#define MAX_CLKA            1023
++#define MAX_PHY_DEV         31
++#define MAX_PHY_REG         31
++#define WRITEADDRS_OPCODE   0x0
++#define	READ_OPCODE	    0x2
++#define WRITE_OPCODE        0x1
++#define MAX_MDIO_POLL       100
++
++/*
++ * Titan MDIO and SCMB registers
++ */
++#define TITAN_GE_SCMB_CONTROL                0x01c0  /* SCMB Control */
++#define TITAN_GE_SCMB_CLKA	             0x01c4  /* SCMB Clock A */
++#define TITAN_GE_MDIO_COMMAND                0x01d0  /* MDIO Command */
++#define TITAN_GE_MDIO_DEVICE_PORT_ADDRESS    0x01d4  /* MDIO Device and Port addrs */
++#define TITAN_GE_MDIO_DATA                   0x01d8  /* MDIO Data */
++#define TITAN_GE_MDIO_INTERRUPTS             0x01dC  /* MDIO Interrupts */
++
++/*
++ * Function to poll the MDIO
++ */
++static int titan_ge_mdio_poll(void)
++{
++	int	i, val;
++
++	for (i = 0; i < MAX_MDIO_POLL; i++) {
++		val = TITAN_GE_MDIO_READ(TITAN_GE_MDIO_COMMAND);
++
++		if (!(val & 0x8000))
++			return TITAN_GE_MDIO_GOOD;
++	}
++
++	return TITAN_GE_MDIO_ERROR;
++}
++
++
++/*
++ * Initialize and configure the MDIO
++ */
++int titan_ge_mdio_setup(titan_ge_mdio_config *titan_mdio)
++{
++	unsigned long	val;
++
++	/* Reset the SCMB and program into MDIO mode*/
++	TITAN_GE_MDIO_WRITE(TITAN_GE_SCMB_CONTROL, 0x9000);
++	TITAN_GE_MDIO_WRITE(TITAN_GE_SCMB_CONTROL, 0x1000);
++
++	/* CLK A */
++	val = TITAN_GE_MDIO_READ(TITAN_GE_SCMB_CLKA);
++	val = ( (val & ~(0x03ff)) | (titan_mdio->clka & 0x03ff));
++	TITAN_GE_MDIO_WRITE(TITAN_GE_SCMB_CLKA, val);
++
++	/* Preamble Suppresion */
++	val = TITAN_GE_MDIO_READ(TITAN_GE_MDIO_COMMAND);
++	val = ( (val & ~(0x0001)) | (titan_mdio->mdio_spre & 0x0001));
++	TITAN_GE_MDIO_WRITE(TITAN_GE_MDIO_COMMAND, val);
++
++	/* MDIO mode */
++	val = TITAN_GE_MDIO_READ(TITAN_GE_MDIO_DEVICE_PORT_ADDRESS);
++	val = ( (val & ~(0x4000)) | (titan_mdio->mdio_mode & 0x4000));
++	TITAN_GE_MDIO_WRITE(TITAN_GE_MDIO_DEVICE_PORT_ADDRESS, val);
++
++	return TITAN_GE_MDIO_GOOD;
++}
++
++/*
++ * Set the PHY address in indirect mode
++ */
++int titan_ge_mdio_inaddrs(int dev_addr, int reg_addr)
++{
++	volatile unsigned long	val;
++
++	/* Setup the PHY device */
++	val = TITAN_GE_MDIO_READ(TITAN_GE_MDIO_DEVICE_PORT_ADDRESS);
++	val = ( (val & ~(0x1f00)) | ( (dev_addr << 8) & 0x1f00));
++	val = ( (val & ~(0x001f)) | ( reg_addr & 0x001f));
++	TITAN_GE_MDIO_WRITE(TITAN_GE_MDIO_DEVICE_PORT_ADDRESS, val);
++
++	/* Write the new address */
++	val = TITAN_GE_MDIO_READ(TITAN_GE_MDIO_COMMAND);
++	val = ( (val & ~(0x0300)) | ( (WRITEADDRS_OPCODE << 8) & 0x0300));
++	TITAN_GE_MDIO_WRITE(TITAN_GE_MDIO_COMMAND, val);
++
++	return TITAN_GE_MDIO_GOOD;
++}
++
++/*
++ * Read the MDIO register. This is what the individual parametes mean:
++ *
++ * dev_addr : PHY ID
++ * reg_addr : register offset
++ *
++ * See the spec for the Titan MAC. We operate in the Direct Mode.
++ */
++
++#define MAX_RETRIES	2
++
++int titan_ge_mdio_read(int dev_addr, int reg_addr, unsigned int *pdata)
++{
++	volatile unsigned long	val;
++	int retries = 0;
++
++	/* Setup the PHY device */
++
++again:
++	val = TITAN_GE_MDIO_READ(TITAN_GE_MDIO_DEVICE_PORT_ADDRESS);
++	val = ( (val & ~(0x1f00)) | ( (dev_addr << 8) & 0x1f00));
++	val = ( (val & ~(0x001f)) | ( reg_addr & 0x001f));
++	val |= 0x4000;
++	TITAN_GE_MDIO_WRITE(TITAN_GE_MDIO_DEVICE_PORT_ADDRESS, val);
++
++	udelay(30);
++
++	/* Issue the read command */
++	val = TITAN_GE_MDIO_READ(TITAN_GE_MDIO_COMMAND);
++	val = ( (val & ~(0x0300)) | ( (READ_OPCODE << 8) & 0x0300));
++	TITAN_GE_MDIO_WRITE(TITAN_GE_MDIO_COMMAND, val);
++
++	udelay(30);
++
++	if (titan_ge_mdio_poll() != TITAN_GE_MDIO_GOOD)
++		return TITAN_GE_MDIO_ERROR;
++
++	*pdata = (unsigned int)TITAN_GE_MDIO_READ(TITAN_GE_MDIO_DATA);
++	val = TITAN_GE_MDIO_READ(TITAN_GE_MDIO_INTERRUPTS);
++
++	udelay(30);
++
++	if (val & 0x2) {
++		if (retries == MAX_RETRIES)
++			return TITAN_GE_MDIO_ERROR;
++		else {
++			retries++;
++			goto again;
++		}
++	}
++
++	return TITAN_GE_MDIO_GOOD;
++}
++
++/*
++ * Write to the MDIO register
++ *
++ * dev_addr : PHY ID
++ * reg_addr : register that needs to be written to
++ *
++ */
++int titan_ge_mdio_write(int dev_addr, int reg_addr, unsigned int data)
++{
++	volatile unsigned long	val;
++
++	if (titan_ge_mdio_poll() != TITAN_GE_MDIO_GOOD)
++		return TITAN_GE_MDIO_ERROR;
++
++	/* Setup the PHY device */
++	val = TITAN_GE_MDIO_READ(TITAN_GE_MDIO_DEVICE_PORT_ADDRESS);
++	val = ( (val & ~(0x1f00)) | ( (dev_addr << 8) & 0x1f00));
++	val = ( (val & ~(0x001f)) | ( reg_addr & 0x001f));
++	val |= 0x4000;
++	TITAN_GE_MDIO_WRITE(TITAN_GE_MDIO_DEVICE_PORT_ADDRESS, val);
++
++	udelay(30);
++
++	/* Setup the data to write */
++	TITAN_GE_MDIO_WRITE(TITAN_GE_MDIO_DATA, data);
++
++	udelay(30);
++
++	/* Issue the write command */
++	val = TITAN_GE_MDIO_READ(TITAN_GE_MDIO_COMMAND);
++	val = ( (val & ~(0x0300)) | ( (WRITE_OPCODE << 8) & 0x0300));
++	TITAN_GE_MDIO_WRITE(TITAN_GE_MDIO_COMMAND, val);
++
++	udelay(30);
++
++	if (titan_ge_mdio_poll() != TITAN_GE_MDIO_GOOD)
++		return TITAN_GE_MDIO_ERROR;
++
++	val = TITAN_GE_MDIO_READ(TITAN_GE_MDIO_INTERRUPTS);
++	if (val & 0x2)
++		return TITAN_GE_MDIO_ERROR;
++
++	return TITAN_GE_MDIO_GOOD;
++}
++
+diff -Naur linux-2.6.15.orig/drivers/net/titan_mdio.h linux-2.6.15/drivers/net/titan_mdio.h
+--- linux-2.6.15.orig/drivers/net/titan_mdio.h	1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.15/drivers/net/titan_mdio.h	2006-01-09 19:54:13.000000000 +0000
+@@ -0,0 +1,56 @@
++/*
++ * MDIO used to interact with the PHY when using GMII/MII
++ */
++#ifndef _TITAN_MDIO_H
++#define _TITAN_MDIO_H
++
++#include <linux/netdevice.h>
++#include <linux/workqueue.h>
++#include <linux/delay.h>
++#include "titan_ge.h"
++
++
++#define	TITAN_GE_MDIO_ERROR	(-9000)
++#define	TITAN_GE_MDIO_GOOD	0
++
++#define	TITAN_GE_MDIO_BASE		titan_ge_base
++
++#define	TITAN_GE_MDIO_READ(offset)	\
++	*(volatile u32 *)(titan_ge_base + (offset))
++
++#define	TITAN_GE_MDIO_WRITE(offset, data)	\
++	*(volatile u32 *)(titan_ge_base + (offset)) = (data)
++
++
++/* GMII specific registers */
++#define	TITAN_GE_MARVEL_PHY_ID		0x00
++#define	TITAN_PHY_AUTONEG_ADV		0x04
++#define	TITAN_PHY_LP_ABILITY		0x05
++#define	TITAN_GE_MDIO_MII_CTRL		0x09
++#define	TITAN_GE_MDIO_MII_EXTENDED	0x0f
++#define	TITAN_GE_MDIO_PHY_CTRL		0x10
++#define	TITAN_GE_MDIO_PHY_STATUS	0x11
++#define	TITAN_GE_MDIO_PHY_IE		0x12
++#define	TITAN_GE_MDIO_PHY_IS		0x13
++#define	TITAN_GE_MDIO_PHY_LED		0x18
++#define	TITAN_GE_MDIO_PHY_LED_OVER	0x19
++#define	PHY_ANEG_TIME_WAIT		45	/* 45 seconds wait time */
++
++/*
++ * MDIO Config Structure
++ */
++typedef struct {
++	unsigned int		clka;
++	int			mdio_spre;
++	int			mdio_mode;
++} titan_ge_mdio_config;
++
++/*
++ * Function Prototypes
++ */
++int titan_ge_mdio_setup(titan_ge_mdio_config *);
++int titan_ge_mdio_inaddrs(int, int);
++int titan_ge_mdio_read(int, int, unsigned int *);
++int titan_ge_mdio_write(int, int, unsigned int);
++
++#endif /* _TITAN_MDIO_H */
+diff -Naur linux-2.6.15.orig/drivers/net/tulip/tulip_core.c linux-2.6.15/drivers/net/tulip/tulip_core.c
+--- linux-2.6.15.orig/drivers/net/tulip/tulip_core.c	2006-01-03 03:21:10.000000000 +0000
++++ linux-2.6.15/drivers/net/tulip/tulip_core.c	2006-01-09 19:54:13.000000000 +0000
+@@ -1495,8 +1495,8 @@
+                if ((pdev->bus->number == 0) && (PCI_SLOT(pdev->devfn) == 4)) {
+                        /* DDB5477 MAC address in first EEPROM locations. */
+                        sa_offset = 0;
+-                       /* No media table either */
+-                       tp->flags &= ~HAS_MEDIA_TABLE;
++		       /* Ensure our media table fixup get's applied */
++		       memcpy(ee_data + 16, ee_data, 8);
+                }
+ #endif
+ #ifdef CONFIG_MIPS_COBALT
+diff -Naur linux-2.6.15.orig/drivers/scsi/NCR53C9x.h linux-2.6.15/drivers/scsi/NCR53C9x.h
+--- linux-2.6.15.orig/drivers/scsi/NCR53C9x.h	2006-01-03 03:21:10.000000000 +0000
++++ linux-2.6.15/drivers/scsi/NCR53C9x.h	2006-01-09 19:54:13.000000000 +0000
+@@ -145,12 +145,7 @@
+ 
+ #ifndef MULTIPLE_PAD_SIZES
+ 
+-#ifdef CONFIG_CPU_HAS_WB
+-#include <asm/wbflush.h>
+-#define esp_write(__reg, __val) do{(__reg) = (__val); wbflush();} while(0)
+-#else
+-#define esp_write(__reg, __val) ((__reg) = (__val))
+-#endif
++#define esp_write(__reg, __val) do{(__reg) = (__val); iob();} while(0)
+ #define esp_read(__reg) (__reg)
+ 
+ struct ESP_regs {
+diff -Naur linux-2.6.15.orig/drivers/scsi/dec_esp.c linux-2.6.15/drivers/scsi/dec_esp.c
+--- linux-2.6.15.orig/drivers/scsi/dec_esp.c	2006-01-03 03:21:10.000000000 +0000
++++ linux-2.6.15/drivers/scsi/dec_esp.c	2006-01-09 19:54:13.000000000 +0000
+@@ -55,7 +55,7 @@
+ 
+ static int  dma_bytes_sent(struct NCR_ESP *esp, int fifo_count);
+ static void dma_drain(struct NCR_ESP *esp);
+-static int  dma_can_transfer(struct NCR_ESP *esp, struct scsi_cmnd *sp);
++static int  dma_can_transfer(struct NCR_ESP *esp, Scsi_Cmnd * sp);
+ static void dma_dump_state(struct NCR_ESP *esp);
+ static void dma_init_read(struct NCR_ESP *esp, u32 vaddress, int length);
+ static void dma_init_write(struct NCR_ESP *esp, u32 vaddress, int length);
+@@ -64,9 +64,9 @@
+ static int  dma_irq_p(struct NCR_ESP *esp);
+ static int  dma_ports_p(struct NCR_ESP *esp);
+ static void dma_setup(struct NCR_ESP *esp, u32 addr, int count, int write);
+-static void dma_mmu_get_scsi_one(struct NCR_ESP *esp, struct scsi_cmnd * sp);
+-static void dma_mmu_get_scsi_sgl(struct NCR_ESP *esp, struct scsi_cmnd * sp);
+-static void dma_advance_sg(struct scsi_cmnd * sp);
++static void dma_mmu_get_scsi_one(struct NCR_ESP *esp, Scsi_Cmnd * sp);
++static void dma_mmu_get_scsi_sgl(struct NCR_ESP *esp, Scsi_Cmnd * sp);
++static void dma_advance_sg(Scsi_Cmnd * sp);
+ 
+ static void pmaz_dma_drain(struct NCR_ESP *esp);
+ static void pmaz_dma_init_read(struct NCR_ESP *esp, u32 vaddress, int length);
+@@ -74,7 +74,7 @@
+ static void pmaz_dma_ints_off(struct NCR_ESP *esp);
+ static void pmaz_dma_ints_on(struct NCR_ESP *esp);
+ static void pmaz_dma_setup(struct NCR_ESP *esp, u32 addr, int count, int write);
+-static void pmaz_dma_mmu_get_scsi_one(struct NCR_ESP *esp, struct scsi_cmnd * sp);
++static void pmaz_dma_mmu_get_scsi_one(struct NCR_ESP *esp, Scsi_Cmnd * sp);
+ 
+ #define TC_ESP_RAM_SIZE 0x20000
+ #define ESP_TGT_DMA_SIZE ((TC_ESP_RAM_SIZE/7) & ~(sizeof(int)-1))
+@@ -98,7 +98,7 @@
+ static irqreturn_t scsi_dma_err_int(int, void *, struct pt_regs *);
+ static irqreturn_t scsi_dma_int(int, void *, struct pt_regs *);
+ 
+-static int dec_esp_detect(struct scsi_host_template * tpnt);
++int dec_esp_detect(Scsi_Host_Template * tpnt);
+ 
+ static int dec_esp_release(struct Scsi_Host *shost)
+ {
+@@ -110,9 +110,9 @@
+ 	return 0;
+ }
+ 
+-static struct scsi_host_template driver_template = {
++static Scsi_Host_Template driver_template = {
+ 	.proc_name		= "dec_esp",
+-	.proc_info		= esp_proc_info,
++	.proc_info		= &esp_proc_info,
+ 	.name			= "NCR53C94",
+ 	.detect			= dec_esp_detect,
+ 	.slave_alloc		= esp_slave_alloc,
+@@ -133,7 +133,7 @@
+ #include "scsi_module.c"
+ 
+ /***************************************************************** Detection */
+-static int dec_esp_detect(struct scsi_host_template * tpnt)
++int dec_esp_detect(struct scsi_host_template * tpnt)
+ {
+ 	struct NCR_ESP *esp;
+ 	struct ConfigDev *esp_dev;
+@@ -230,7 +230,7 @@
+ 			mem_start = get_tc_base_addr(slot);
+ 
+ 			/* Store base addr into esp struct */
+-			esp->slot = CPHYSADDR(mem_start);
++			esp->slot = mem_start;
+ 
+ 			esp->dregs = 0;
+ 			esp->eregs = (void *)CKSEG1ADDR(mem_start +
+@@ -379,7 +379,7 @@
+ 	}
+ }
+ 
+-static int dma_can_transfer(struct NCR_ESP *esp, struct scsi_cmnd * sp)
++static int dma_can_transfer(struct NCR_ESP *esp, Scsi_Cmnd * sp)
+ {
+ 	return sp->SCp.this_residual;
+ }
+@@ -491,12 +491,12 @@
+ 		dma_init_write(esp, addr, count);
+ }
+ 
+-static void dma_mmu_get_scsi_one(struct NCR_ESP *esp, struct scsi_cmnd * sp)
++static void dma_mmu_get_scsi_one(struct NCR_ESP *esp, Scsi_Cmnd * sp)
+ {
+ 	sp->SCp.ptr = (char *)virt_to_phys(sp->request_buffer);
+ }
+ 
+-static void dma_mmu_get_scsi_sgl(struct NCR_ESP *esp, struct scsi_cmnd * sp)
++static void dma_mmu_get_scsi_sgl(struct NCR_ESP *esp, Scsi_Cmnd * sp)
+ {
+ 	int sz = sp->SCp.buffers_residual;
+ 	struct scatterlist *sg = sp->SCp.buffer;
+@@ -508,7 +508,7 @@
+ 	sp->SCp.ptr = (char *)(sp->SCp.buffer->dma_address);
+ }
+ 
+-static void dma_advance_sg(struct scsi_cmnd * sp)
++static void dma_advance_sg(Scsi_Cmnd * sp)
+ {
+ 	sp->SCp.ptr = (char *)(sp->SCp.buffer->dma_address);
+ }
+@@ -572,7 +572,7 @@
+ 		pmaz_dma_init_write(esp, addr, count);
+ }
+ 
+-static void pmaz_dma_mmu_get_scsi_one(struct NCR_ESP *esp, struct scsi_cmnd * sp)
++static void pmaz_dma_mmu_get_scsi_one(struct NCR_ESP *esp, Scsi_Cmnd * sp)
+ {
+ 	sp->SCp.ptr = (char *)virt_to_phys(sp->request_buffer);
+ }
+diff -Naur linux-2.6.15.orig/drivers/scsi/eata.c linux-2.6.15/drivers/scsi/eata.c
+--- linux-2.6.15.orig/drivers/scsi/eata.c	2006-01-03 03:21:10.000000000 +0000
++++ linux-2.6.15/drivers/scsi/eata.c	2006-01-09 19:54:13.000000000 +0000
+@@ -941,6 +941,8 @@
+ {
+ 	int tqd, utqd;
+ 	char *tag_suffix, *link_suffix;
++	struct Scsi_Host *shost = dev->host;
++	struct hostdata *ha = (struct hostdata *)shost->hostdata;
+ 
+ 	utqd = MAX_CMD_PER_LUN;
+ 	tqd = max_queue_depth;
+@@ -971,8 +973,8 @@
+ 	else
+ 		link_suffix = "";
+ 
+-	sdev_printk(KERN_INFO, dev,
+-		"cmds/lun %d%s%s.\n",
++	printk("%s: scsi%d, channel %d, id %d, lun %d, cmds/lun %d%s%s.\n",
++	       ha->board_name, shost->host_no, dev->channel, dev->id, dev->lun,
+ 	       dev->queue_depth, link_suffix, tag_suffix);
+ 
+ 	return 0;
+@@ -1811,8 +1813,9 @@
+ 	SCpnt->host_scribble = (unsigned char *)&cpp->cpp_index;
+ 
+ 	if (do_trace)
+-		scmd_printk(KERN_INFO, SCpnt,
+-			"qcomm, mbox %d, pid %ld.\n", i, SCpnt->pid);
++		printk("%s: qcomm, mbox %d, target %d.%d:%d, pid %ld.\n",
++		       ha->board_name, i, SCpnt->device->channel, SCpnt->device->id,
++		       SCpnt->device->lun, SCpnt->pid);
+ 
+ 	cpp->reqsen = 1;
+ 	cpp->dispri = 1;
+@@ -1844,8 +1847,9 @@
+ 	if (do_dma(shost->io_port, cpp->cp_dma_addr, SEND_CP_DMA)) {
+ 		unmap_dma(i, ha);
+ 		SCpnt->host_scribble = NULL;
+-		scmd_printk(KERN_INFO, SCpnt,
+-			"qcomm, pid %ld, adapter busy.\n", SCpnt->pid);
++		printk("%s: qcomm, target %d.%d:%d, pid %ld, adapter busy.\n",
++		       ha->board_name, SCpnt->device->channel, SCpnt->device->id,
++		       SCpnt->device->lun, SCpnt->pid);
+ 		return 1;
+ 	}
+ 
+@@ -1860,14 +1864,16 @@
+ 	unsigned int i;
+ 
+ 	if (SCarg->host_scribble == NULL) {
+-		scmd_printk(KERN_INFO, SCarg,
+-			"abort, pid %ld inactive.\n", SCarg->pid);
++		printk("%s: abort, target %d.%d:%d, pid %ld inactive.\n",
++		       ha->board_name, SCarg->device->channel, SCarg->device->id,
++		       SCarg->device->lun, SCarg->pid);
+ 		return SUCCESS;
+ 	}
+ 
+ 	i = *(unsigned int *)SCarg->host_scribble;
+-	scmd_printk(KERN_WARNING, SCarg,
+-		"abort, mbox %d, pid %ld.\n", i, SCarg->pid);
++	printk("%s: abort, mbox %d, target %d.%d:%d, pid %ld.\n",
++	       ha->board_name, i, SCarg->device->channel, SCarg->device->id,
++	       SCarg->device->lun, SCarg->pid);
+ 
+ 	if (i >= shost->can_queue)
+ 		panic("%s: abort, invalid SCarg->host_scribble.\n", ha->board_name);
+@@ -1928,8 +1934,9 @@
+ 	struct Scsi_Host *shost = SCarg->device->host;
+ 	struct hostdata *ha = (struct hostdata *)shost->hostdata;
+ 
+-	scmd_printk(KERN_INFO, SCarg,
+-		"reset, enter, pid %ld.\n", SCarg->pid);
++	printk("%s: reset, enter, target %d.%d:%d, pid %ld.\n",
++	       ha->board_name, SCarg->device->channel, SCarg->device->id,
++	       SCarg->device->lun, SCarg->pid);
+ 
+ 	spin_lock_irq(shost->host_lock);
+ 
+@@ -2246,11 +2253,12 @@
+ 			k = il[n];
+ 			cpp = &ha->cp[k];
+ 			SCpnt = cpp->SCpnt;
+-			scmd_printk(KERN_INFO, SCpnt,
+-			    "%s pid %ld mb %d fc %d nr %d sec %ld ns %ld"
++			printk
++			    ("%s %d.%d:%d pid %ld mb %d fc %d nr %d sec %ld ns %ld"
+ 			     " cur %ld s:%c r:%c rev:%c in:%c ov:%c xd %d.\n",
+ 			     (ihdlr ? "ihdlr" : "qcomm"),
+-			     SCpnt->pid, k, flushcount,
++			     SCpnt->device->channel, SCpnt->device->id,
++			     SCpnt->device->lun, SCpnt->pid, k, flushcount,
+ 			     n_ready, SCpnt->request->sector,
+ 			     SCpnt->request->nr_sectors, cursec, YESNO(s),
+ 			     YESNO(r), YESNO(rev), YESNO(input_only),
+@@ -2293,11 +2301,12 @@
+ 		SCpnt = cpp->SCpnt;
+ 
+ 		if (do_dma(dev->host->io_port, cpp->cp_dma_addr, SEND_CP_DMA)) {
+-			scmd_printk(KERN_INFO, SCpnt,
+-			    "%s, pid %ld, mbox %d, adapter"
+-			     " busy, will abort.\n",
++			printk
++			    ("%s: %s, target %d.%d:%d, pid %ld, mbox %d, adapter"
++			     " busy, will abort.\n", ha->board_name,
+ 			     (ihdlr ? "ihdlr" : "qcomm"),
+-			     SCpnt->pid, k);
++			     SCpnt->device->channel, SCpnt->device->id,
++			     SCpnt->device->lun, SCpnt->pid, k);
+ 			ha->cp_stat[k] = ABORTING;
+ 			continue;
+ 		}
+@@ -2533,10 +2542,11 @@
+ 	     spp->adapter_status != ASST && ha->iocount <= 1000) ||
+ 	    do_trace || msg_byte(spp->target_status))
+ #endif
+-		scmd_printk(KERN_INFO, SCpnt, "ihdlr, mbox %2d, err 0x%x:%x,"
+-		       " pid %ld, reg 0x%x, count %d.\n",
+-		       i, spp->adapter_status, spp->target_status,
+-		       SCpnt->pid, reg, ha->iocount);
++		printk("%s: ihdlr, mbox %2d, err 0x%x:%x,"
++		       " target %d.%d:%d, pid %ld, reg 0x%x, count %d.\n",
++		       ha->board_name, i, spp->adapter_status, spp->target_status,
++		       SCpnt->device->channel, SCpnt->device->id,
++		       SCpnt->device->lun, SCpnt->pid, reg, ha->iocount);
+ 
+ 	unmap_dma(i, ha);
+ 
+diff -Naur linux-2.6.15.orig/drivers/scsi/jazz_esp.c linux-2.6.15/drivers/scsi/jazz_esp.c
+--- linux-2.6.15.orig/drivers/scsi/jazz_esp.c	2006-01-03 03:21:10.000000000 +0000
++++ linux-2.6.15/drivers/scsi/jazz_esp.c	2006-01-09 19:54:13.000000000 +0000
+@@ -52,7 +52,6 @@
+ 				 * via PIO.
+ 				 */
+ 
+-int jazz_esp_detect(struct scsi_host_template *tpnt);
+ static int jazz_esp_release(struct Scsi_Host *shost)
+ {
+ 	if (shost->irq)
+@@ -65,27 +64,6 @@
+ 	return 0;
+ }
+ 
+-static struct scsi_host_template driver_template = {
+-	.proc_name		= "jazz_esp",
+-	.proc_info		= &esp_proc_info,
+-	.name			= "ESP 100/100a/200",
+-	.detect			= jazz_esp_detect,
+-	.slave_alloc		= esp_slave_alloc,
+-	.slave_destroy		= esp_slave_destroy,
+-	.release		= jazz_esp_release,
+-	.info			= esp_info,
+-	.queuecommand		= esp_queue,
+-	.eh_abort_handler	= esp_abort,
+-	.eh_bus_reset_handler	= esp_reset,
+-	.can_queue		= 7,
+-	.this_id		= 7,
+-	.sg_tablesize		= SG_ALL,
+-	.cmd_per_lun		= 1,
+-	.use_clustering		= DISABLE_CLUSTERING,
+-};
+-
+-#include "scsi_module.c"
+-
+ /***************************************************************** Detection */
+ static int jazz_esp_detect(struct scsi_host_template *tpnt)
+ {
+@@ -96,7 +74,7 @@
+      * first assumption it is there:-)
+      */
+     if (1) {
+-	esp_dev = 0;
++	esp_dev = NULL;
+ 	esp = esp_allocate(tpnt, (void *) esp_dev);
+ 	
+ 	/* Do command transfer with programmed I/O */
+@@ -115,13 +93,13 @@
+ 	esp->dma_setup = &dma_setup;
+ 
+ 	/* Optional functions */
+-	esp->dma_barrier = 0;
+-	esp->dma_drain = 0;
+-	esp->dma_invalidate = 0;
+-	esp->dma_irq_entry = 0;
+-	esp->dma_irq_exit = 0;
+-	esp->dma_poll = 0;
+-	esp->dma_reset = 0;
++	esp->dma_barrier = NULL;
++	esp->dma_drain = NULL;
++	esp->dma_invalidate = NULL;
++	esp->dma_irq_entry = NULL;
++	esp->dma_irq_exit = NULL;
++	esp->dma_poll = NULL;
++	esp->dma_reset = NULL;
+ 	esp->dma_led_off = &dma_led_off;
+ 	esp->dma_led_on = &dma_led_on;
+ 	
+@@ -141,7 +119,7 @@
+ 	 * of DMA channel, so we can use the jazz DMA functions
+ 	 * 
+ 	 */
+-	esp->dregs = JAZZ_SCSI_DMA;
++	esp->dregs = (void *) JAZZ_SCSI_DMA;
+ 	
+ 	/* ESP register base */
+ 	esp->eregs = (struct ESP_regs *)(JAZZ_SCSI_BASE);
+diff -Naur linux-2.6.15.orig/drivers/scsi/sym53c8xx_defs.h linux-2.6.15/drivers/scsi/sym53c8xx_defs.h
+--- linux-2.6.15.orig/drivers/scsi/sym53c8xx_defs.h	2006-01-03 03:21:10.000000000 +0000
++++ linux-2.6.15/drivers/scsi/sym53c8xx_defs.h	2006-01-09 19:54:13.000000000 +0000
+@@ -301,9 +301,19 @@
+ #define	writew_b2l	__raw_writew
+ #define	writel_b2l	__raw_writel
+ #define	readw_raw	__raw_readw
+-#define	readl_raw	__raw_readl
++#define	readl_raw(a)	__raw_readl((unsigned long)(a))
+ #define	writew_raw	__raw_writew
+-#define	writel_raw	__raw_writel
++#define	writel_raw(v,a)	__raw_writel(v,(unsigned long)(a))
++#else /* Other big-endian */
++#elif defined(__mips__)
++#define readw_l2b	readw
++#define readl_l2b	readl
++#define writew_b2l	writew
++#define writel_b2l	writel
++#define inw_l2b 	inw
++#define inl_l2b 	inl
++#define outw_b2l	outw
++#define outl_b2l	outl
+ #else	/* Other big-endian */
+ #define	readw_l2b	readw
+ #define	readl_l2b	readl
+diff -Naur linux-2.6.15.orig/drivers/serial/8250.c linux-2.6.15/drivers/serial/8250.c
+--- linux-2.6.15.orig/drivers/serial/8250.c	2006-01-03 03:21:10.000000000 +0000
++++ linux-2.6.15/drivers/serial/8250.c	2006-01-09 19:54:13.000000000 +0000
+@@ -2214,8 +2214,10 @@
+ 
+ 	touch_nmi_watchdog();
+ 
++	spin_lock(&up->port.lock); 
++
+ 	/*
+-	 *	First save the UER then disable the interrupts
++	 *	First save the IER then disable the interrupts
+ 	 */
+ 	ier = serial_in(up, UART_IER);
+ 
+@@ -2247,6 +2249,8 @@
+ 	 */
+ 	wait_for_xmitr(up);
+ 	serial_out(up, UART_IER, ier);
++
++	spin_unlock(&up->port.lock);
+ }
+ 
+ static int serial8250_console_setup(struct console *co, char *options)
+diff -Naur linux-2.6.15.orig/drivers/serial/Kconfig linux-2.6.15/drivers/serial/Kconfig
+--- linux-2.6.15.orig/drivers/serial/Kconfig	2006-01-03 03:21:10.000000000 +0000
++++ linux-2.6.15/drivers/serial/Kconfig	2006-01-09 19:54:13.000000000 +0000
+@@ -616,6 +616,25 @@
+ 	  If you have an Alchemy AU1X00 processor (MIPS based) and you want
+ 	  to use a console on a serial port, say Y.  Otherwise, say N.
+ 
++config SERIAL_IP3106
++	bool "Enable IP3106 UART Support (Philips PNX 8xx0 SoCs)"
++	depends on MIPS && (SOC_PNX8550 || SOC_PNX8330)
++	select SERIAL_CORE
++	help
++	  If you have a Philips SoC with an IP 3106 UART in it, such as
++	  the PNX8550 or PNX8330 (MIPS based) and you want to use
++	  serial ports, say Y.  Otherwise, say N.
++
++config SERIAL_IP3106_CONSOLE
++	bool "Enable PNX8XX0 serial console"
++	depends on SERIAL_IP3106
++	select SERIAL_CORE_CONSOLE
++	help
++	  If you have a Philips SoC with an IP 3106 UART in it, such as
++	  the PNX8550 or PNX8330 (MIPS based) and you want to use
++	  a serial console, say Y.
++	  Otherwise, say N.
++
+ config SERIAL_CORE
+ 	tristate
+ 
+diff -Naur linux-2.6.15.orig/drivers/serial/Makefile linux-2.6.15/drivers/serial/Makefile
+--- linux-2.6.15.orig/drivers/serial/Makefile	2006-01-03 03:21:10.000000000 +0000
++++ linux-2.6.15/drivers/serial/Makefile	2006-01-09 19:54:13.000000000 +0000
+@@ -43,6 +43,7 @@
+ obj-$(CONFIG_SERIAL_PMACZILOG) += pmac_zilog.o
+ obj-$(CONFIG_SERIAL_LH7A40X) += serial_lh7a40x.o
+ obj-$(CONFIG_SERIAL_AU1X00) += au1x00_uart.o
++obj-$(CONFIG_SERIAL_IP3106) += ip3106_uart.o
+ obj-$(CONFIG_SERIAL_DZ) += dz.o
+ obj-$(CONFIG_SERIAL_SH_SCI) += sh-sci.o
+ obj-$(CONFIG_SERIAL_SGI_L1_CONSOLE) += sn_console.o
+diff -Naur linux-2.6.15.orig/drivers/serial/au1x00_uart.c linux-2.6.15/drivers/serial/au1x00_uart.c
+--- linux-2.6.15.orig/drivers/serial/au1x00_uart.c	2006-01-03 03:21:10.000000000 +0000
++++ linux-2.6.15/drivers/serial/au1x00_uart.c	2006-01-09 19:54:13.000000000 +0000
+@@ -67,30 +67,7 @@
+ #define is_real_interrupt(irq)	((irq) != 0)
+ 
+ static struct old_serial_port old_serial_port[] = {
+-	{	.baud_base = 0,
+-		.iomem_base = (u8 *)UART0_ADDR,
+-		.irq = AU1000_UART0_INT,
+-		.flags = STD_COM_FLAGS,
+-		.iomem_reg_shift = 2,
+-	}, {
+-		.baud_base = 0,
+-		.iomem_base = (u8 *)UART1_ADDR,
+-		.irq = AU1000_UART1_INT,
+-		.flags = STD_COM_FLAGS,
+-		.iomem_reg_shift = 2
+-	}, {
+-		.baud_base = 0,
+-		.iomem_base = (u8 *)UART2_ADDR,
+-		.irq = AU1000_UART2_INT,
+-		.flags = STD_COM_FLAGS,
+-		.iomem_reg_shift = 2
+-	}, {
+-		.baud_base = 0,
+-		.iomem_base = (u8 *)UART3_ADDR,
+-		.irq = AU1000_UART3_INT,
+-		.flags = STD_COM_FLAGS,
+-		.iomem_reg_shift = 2
+-	}
++	SERIAL_PORT_DFNS
+ };
+ 
+ #define UART_NR	ARRAY_SIZE(old_serial_port)
+@@ -194,7 +171,7 @@
+ 	(void)serial_in(up, UART_RX);
+ 	serial_outp(up, UART_IER, 0);
+ 
+- out:	
++ out:
+ 	spin_unlock_irqrestore(&up->port.lock, flags);
+ //	restore_flags(flags);
+ 	DEBUG_AUTOCONF("type=%s\n", uart_config[up->port.type].name);
+@@ -798,9 +775,8 @@
+ 	/*
+ 	 * Ask the core to calculate the divisor for us.
+ 	 */
+-	baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16); 
++	baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16);
+ 	quot = serial8250_get_divisor(port, baud);
+-	quot = 0x35; /* FIXME */
+ 
+ 	/*
+ 	 * Work around a bug in the Oxford Semiconductor 952 rev B
+@@ -866,6 +842,7 @@
+ 
+ 	serial_out(up, UART_IER, up->ier);
+ 	serial_outp(up, 0x28, quot & 0xffff);
++	serial_out(up, UART_LCR, cval);			/* reset DLAB */
+ 	up->lcr = cval;					/* Save LCR */
+ 	if (up->port.type != PORT_16750) {
+ 		if (fcr & UART_FCR_ENABLE_FIFO) {
+@@ -1068,7 +1045,7 @@
+ 	     i++, up++) {
+ 		up->port.iobase   = old_serial_port[i].port;
+ 		up->port.irq      = old_serial_port[i].irq;
+-		up->port.uartclk  = get_au1x00_uart_baud_base();
++		up->port.uartclk  = get_au1x00_uart_baud_base() * 16;
+ 		up->port.flags    = old_serial_port[i].flags;
+ 		up->port.hub6     = old_serial_port[i].hub6;
+ 		up->port.membase  = old_serial_port[i].iomem_base;
+@@ -1206,7 +1183,7 @@
+ 	return uart_set_options(port, co, baud, parity, bits, flow);
+ }
+ 
+-extern struct uart_driver serial8250_reg;
++static struct uart_driver serial8250_reg;
+ static struct console serial8250_console = {
+ 	.name		= "ttyS",
+ 	.write		= serial8250_console_write,
+diff -Naur linux-2.6.15.orig/drivers/serial/dz.c linux-2.6.15/drivers/serial/dz.c
+--- linux-2.6.15.orig/drivers/serial/dz.c	2006-01-03 03:21:10.000000000 +0000
++++ linux-2.6.15/drivers/serial/dz.c	2006-01-09 19:54:13.000000000 +0000
+@@ -264,6 +264,7 @@
+ 		}
+ 		tty_insert_flip_char(tty, ch, flag);
+ 	      ignore_char:
++			;
+ 	} while (status & DZ_DVAL);
+ 
+ 	if (tty)
+diff -Naur linux-2.6.15.orig/drivers/serial/ip22zilog.c linux-2.6.15/drivers/serial/ip22zilog.c
+--- linux-2.6.15.orig/drivers/serial/ip22zilog.c	2006-01-03 03:21:10.000000000 +0000
++++ linux-2.6.15/drivers/serial/ip22zilog.c	2006-01-09 19:54:13.000000000 +0000
+@@ -215,7 +215,7 @@
+ 	/* Lower and upper byte of baud rate generator divisor.  */
+ 	write_zsreg(channel, R12, regs[R12]);
+ 	write_zsreg(channel, R13, regs[R13]);
+-	
++
+ 	/* Now rewrite R14, with BRENAB (if set).  */
+ 	write_zsreg(channel, R14, regs[R14]);
+ 
+@@ -585,7 +585,7 @@
+ 	else
+ 		clear_bits |= DTR;
+ 
+-	/* NOTE: Not subject to 'transmitter active' rule.  */ 
++	/* NOTE: Not subject to 'transmitter active' rule.  */
+ 	up->curregs[R5] |= set_bits;
+ 	up->curregs[R5] &= ~clear_bits;
+ 	write_zsreg(channel, R5, up->curregs[R5]);
+@@ -668,7 +668,7 @@
+ 	if (new_reg != up->curregs[R15]) {
+ 		up->curregs[R15] = new_reg;
+ 
+-		/* NOTE: Not subject to 'transmitter active' rule.  */ 
++		/* NOTE: Not subject to 'transmitter active' rule.  */
+ 		write_zsreg(channel, R15, up->curregs[R15]);
+ 	}
+ }
+@@ -694,7 +694,7 @@
+ 	if (new_reg != up->curregs[R5]) {
+ 		up->curregs[R5] = new_reg;
+ 
+-		/* NOTE: Not subject to 'transmitter active' rule.  */ 
++		/* NOTE: Not subject to 'transmitter active' rule.  */
+ 		write_zsreg(channel, R5, up->curregs[R5]);
+ 	}
+ 
+@@ -882,6 +882,7 @@
+ 	up->cflag = termios->c_cflag;
+ 
+ 	ip22zilog_maybe_update_regs(up, ZILOG_CHANNEL_FROM_PORT(port));
++	uart_update_timeout(port, termios->c_cflag, baud);
+ 
+ 	spin_unlock_irqrestore(&up->port.lock, flags);
+ }
+@@ -1048,6 +1049,8 @@
+ 	}
+ 
+ 	con->cflag = cflag | CS8;			/* 8N1 */
++
++	uart_update_timeout(&ip22zilog_port_table[con->index].port, cflag, baud);
+ }
+ 
+ static int __init ip22zilog_console_setup(struct console *con, char *options)
+diff -Naur linux-2.6.15.orig/drivers/serial/ip3106_uart.c linux-2.6.15/drivers/serial/ip3106_uart.c
+--- linux-2.6.15.orig/drivers/serial/ip3106_uart.c	1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.15/drivers/serial/ip3106_uart.c	2006-01-09 19:54:13.000000000 +0000
+@@ -0,0 +1,912 @@
++/*
++ * Initially based on linux-2.4.20_mvl31-pnx8xx0/drivers/char/serial_pnx8550.c
++ *
++ * Complete rewrite to drivers/serial/pnx8550_uart.c by
++ * Embedded Alley Solutions, source at embeddedalley.com as part of the
++ * PNX8550 2.6 port, and then drivers/serial/ip3106_uart.c to work
++ * with other Philips SoCs.
++ *
++ * Existing copyrights from files used to write this driver:
++ * Author: Per Hallsmark per.hallsmark at mvista.com
++ *
++ * and
++ *
++ * Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o.
++ * Copyright (C) 2000 Deep Blue Solutions Ltd.
++ *
++ */
++
++#include <linux/config.h>
++
++#if defined(CONFIG_SERIAL_IP3106_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
++#define SUPPORT_SYSRQ
++#endif
++
++#include <linux/module.h>
++#include <linux/ioport.h>
++#include <linux/init.h>
++#include <linux/console.h>
++#include <linux/sysrq.h>
++#include <linux/device.h>
++#include <linux/tty.h>
++#include <linux/tty_flip.h>
++#include <linux/serial_core.h>
++#include <linux/serial.h>
++#include <linux/serial_ip3106.h>
++
++#include <asm/io.h>
++#include <asm/irq.h>
++
++#include <uart.h>
++
++/* We've been assigned a range on the "Low-density serial ports" major */
++#define SERIAL_IP3106_MAJOR	204
++#define MINOR_START		5
++
++#define NR_PORTS		2
++
++#define IP3106_ISR_PASS_LIMIT	256
++
++/*
++ * Convert from ignore_status_mask or read_status_mask to FIFO
++ * and interrupt status bits
++ */
++#define SM_TO_FIFO(x)	((x) >> 10)
++#define SM_TO_ISTAT(x)	((x) & 0x000001ff)
++#define FIFO_TO_SM(x)	((x) << 10)
++#define ISTAT_TO_SM(x)	((x) & 0x000001ff)
++
++/*
++ * This is the size of our serial port register set.
++ */
++#define UART_PORT_SIZE	0x1000
++
++/*
++ * This determines how often we check the modem status signals
++ * for any change.  They generally aren't connected to an IRQ
++ * so we have to poll them.  We also check immediately before
++ * filling the TX fifo incase CTS has been dropped.
++ */
++#define MCTRL_TIMEOUT	(250*HZ/1000)
++
++
++extern struct ip3106_port ip3106_ports[];
++
++static inline int serial_in(struct ip3106_port *sport, int offset)
++{
++	return (__raw_readl(sport->port.membase + offset));
++}
++
++static inline void serial_out(struct ip3106_port *sport, int offset, int value)
++{
++	__raw_writel(value, sport->port.membase + offset);
++}
++
++/*
++ * Handle any change of modem status signal since we were last called.
++ */
++static void ip3106_mctrl_check(struct ip3106_port *sport)
++{
++	unsigned int status, changed;
++
++	status = sport->port.ops->get_mctrl(&sport->port);
++	changed = status ^ sport->old_status;
++
++	if (changed == 0)
++		return;
++
++	sport->old_status = status;
++
++	if (changed & TIOCM_RI)
++		sport->port.icount.rng++;
++	if (changed & TIOCM_DSR)
++		sport->port.icount.dsr++;
++	if (changed & TIOCM_CAR)
++		uart_handle_dcd_change(&sport->port, status & TIOCM_CAR);
++	if (changed & TIOCM_CTS)
++		uart_handle_cts_change(&sport->port, status & TIOCM_CTS);
++
++	wake_up_interruptible(&sport->port.info->delta_msr_wait);
++}
++
++/*
++ * This is our per-port timeout handler, for checking the
++ * modem status signals.
++ */
++static void ip3106_timeout(unsigned long data)
++{
++	struct ip3106_port *sport = (struct ip3106_port *)data;
++	unsigned long flags;
++
++	if (sport->port.info) {
++		spin_lock_irqsave(&sport->port.lock, flags);
++		ip3106_mctrl_check(sport);
++		spin_unlock_irqrestore(&sport->port.lock, flags);
++
++		mod_timer(&sport->timer, jiffies + MCTRL_TIMEOUT);
++	}
++}
++
++/*
++ * interrupts disabled on entry
++ */
++static void ip3106_stop_tx(struct uart_port *port, unsigned int tty_stop)
++{
++	struct ip3106_port *sport = (struct ip3106_port *)port;
++	u32 ien;
++
++	/* Disable TX intr */
++	ien = serial_in(sport, IP3106_IEN);
++	serial_out(sport, IP3106_IEN, ien & ~IP3106_UART_INT_ALLTX);
++
++	/* Clear all pending TX intr */
++	serial_out(sport, IP3106_ICLR, IP3106_UART_INT_ALLTX);
++}
++
++/*
++ * interrupts may not be disabled on entry
++ */
++static void ip3106_start_tx(struct uart_port *port, unsigned int tty_start)
++{
++	struct ip3106_port *sport = (struct ip3106_port *)port;
++	unsigned long flags;
++	u32 ien;
++
++	spin_lock_irqsave(&sport->port.lock, flags);
++
++	/* Clear all pending TX intr */
++	serial_out(sport, IP3106_ICLR, IP3106_UART_INT_ALLTX);
++
++	/* Enable TX intr */
++	ien = serial_in(sport, IP3106_IEN);
++	serial_out(sport, IP3106_IEN, ien | IP3106_UART_INT_ALLTX);
++
++	spin_unlock_irqrestore(&sport->port.lock, flags);
++}
++
++/*
++ * Interrupts enabled
++ */
++static void ip3106_stop_rx(struct uart_port *port)
++{
++	struct ip3106_port *sport = (struct ip3106_port *)port;
++	u32 ien;
++
++	/* Disable RX intr */
++	ien = serial_in(sport, IP3106_IEN);
++	serial_out(sport, IP3106_IEN, ien & ~IP3106_UART_INT_ALLRX);
++
++	/* Clear all pending RX intr */
++	serial_out(sport, IP3106_ICLR, IP3106_UART_INT_ALLRX);
++}
++
++/*
++ * Set the modem control timer to fire immediately.
++ */
++static void ip3106_enable_ms(struct uart_port *port)
++{
++	struct ip3106_port *sport = (struct ip3106_port *)port;
++
++	mod_timer(&sport->timer, jiffies);
++}
++
++static void
++ip3106_rx_chars(struct ip3106_port *sport, struct pt_regs *regs)
++{
++	struct tty_struct *tty = sport->port.info->tty;
++	unsigned int status, ch, flg, ignored = 0;
++
++	status = FIFO_TO_SM(serial_in(sport, IP3106_FIFO)) |
++		 ISTAT_TO_SM(serial_in(sport, IP3106_ISTAT));
++	while (status & FIFO_TO_SM(IP3106_UART_FIFO_RXFIFO)) {
++		ch = serial_in(sport, IP3106_FIFO);
++
++		if (tty->flip.count >= TTY_FLIPBUF_SIZE)
++			goto ignore_char;
++		sport->port.icount.rx++;
++
++		flg = TTY_NORMAL;
++
++		/*
++		 * note that the error handling code is
++		 * out of the main execution path
++		 */
++		if (status & FIFO_TO_SM(IP3106_UART_FIFO_RXFE |
++					IP3106_UART_FIFO_RXPAR))
++			goto handle_error;
++
++		if (uart_handle_sysrq_char(&sport->port, ch, regs))
++			goto ignore_char;
++
++	error_return:
++		tty_insert_flip_char(tty, ch, flg);
++	ignore_char:
++		serial_out(sport, IP3106_LCR, serial_in(sport, IP3106_LCR) |
++				IP3106_UART_LCR_RX_NEXT);
++		status = FIFO_TO_SM(serial_in(sport, IP3106_FIFO)) |
++			 ISTAT_TO_SM(serial_in(sport, IP3106_ISTAT));
++	}
++ out:
++	tty_flip_buffer_push(tty);
++	return;
++
++ handle_error:
++	if (status & FIFO_TO_SM(IP3106_UART_FIFO_RXPAR))
++		sport->port.icount.parity++;
++	else if (status & FIFO_TO_SM(IP3106_UART_FIFO_RXFE))
++		sport->port.icount.frame++;
++	if (status & ISTAT_TO_SM(IP3106_UART_INT_RXOVRN))
++		sport->port.icount.overrun++;
++
++	if (status & sport->port.ignore_status_mask) {
++		if (++ignored > 100)
++			goto out;
++		goto ignore_char;
++	}
++
++//	status &= sport->port.read_status_mask;
++
++	if (status & FIFO_TO_SM(IP3106_UART_FIFO_RXPAR))
++		flg = TTY_PARITY;
++	else if (status & FIFO_TO_SM(IP3106_UART_FIFO_RXFE))
++		flg = TTY_FRAME;
++
++	if (status & ISTAT_TO_SM(IP3106_UART_INT_RXOVRN)) {
++		/*
++		 * overrun does *not* affect the character
++		 * we read from the FIFO
++		 */
++		tty_insert_flip_char(tty, ch, flg);
++		ch = 0;
++		flg = TTY_OVERRUN;
++	}
++#ifdef SUPPORT_SYSRQ
++	sport->port.sysrq = 0;
++#endif
++	goto error_return;
++}
++
++static void ip3106_tx_chars(struct ip3106_port *sport)
++{
++	struct circ_buf *xmit = &sport->port.info->xmit;
++
++	if (sport->port.x_char) {
++		serial_out(sport, IP3106_FIFO, sport->port.x_char);
++		sport->port.icount.tx++;
++		sport->port.x_char = 0;
++		return;
++	}
++
++	/*
++	 * Check the modem control lines before
++	 * transmitting anything.
++	 */
++	ip3106_mctrl_check(sport);
++
++	if (uart_circ_empty(xmit) || uart_tx_stopped(&sport->port)) {
++		ip3106_stop_tx(&sport->port, 0);
++		return;
++	}
++
++	/*
++	 * TX while bytes available
++	 */
++	while (((serial_in(sport, IP3106_FIFO) &
++					IP3106_UART_FIFO_TXFIFO) >> 16) < 16) {
++		serial_out(sport, IP3106_FIFO, xmit->buf[xmit->tail]);
++		xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
++		sport->port.icount.tx++;
++		if (uart_circ_empty(xmit))
++			break;
++	}
++
++	if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
++		uart_write_wakeup(&sport->port);
++
++	if (uart_circ_empty(xmit))
++		ip3106_stop_tx(&sport->port, 0);
++}
++
++static irqreturn_t ip3106_int(int irq, void *dev_id, struct pt_regs *regs)
++{
++	struct ip3106_port *sport = dev_id;
++	unsigned int status;
++
++	spin_lock(&sport->port.lock);
++	/* Get the interrupts */
++	status  = serial_in(sport, IP3106_ISTAT) & serial_in(sport, IP3106_IEN);
++
++	/* RX Receiver Holding Register Overrun */
++	if (status & IP3106_UART_INT_RXOVRN) {
++		sport->port.icount.overrun++;
++		serial_out(sport, IP3106_ICLR, IP3106_UART_INT_RXOVRN);
++	}
++
++	/* RX Frame Error */
++	if (status & IP3106_UART_INT_FRERR) {
++		sport->port.icount.frame++;
++		serial_out(sport, IP3106_ICLR, IP3106_UART_INT_FRERR);
++	}
++
++	/* Break signal received */
++	if (status & IP3106_UART_INT_BREAK) {
++		sport->port.icount.brk++;
++		serial_out(sport, IP3106_ICLR, IP3106_UART_INT_BREAK);
++	}
++
++	/* RX Parity Error */
++	if (status & IP3106_UART_INT_PARITY) {
++		sport->port.icount.parity++;
++		serial_out(sport, IP3106_ICLR, IP3106_UART_INT_PARITY);
++	}
++
++	/* Byte received */
++	if (status & IP3106_UART_INT_RX) {
++		ip3106_rx_chars(sport, regs);
++		serial_out(sport, IP3106_ICLR, IP3106_UART_INT_RX);
++	}
++
++	/* TX holding register empty - transmit a byte */
++	if (status & IP3106_UART_INT_TX) {
++		ip3106_tx_chars(sport);
++		serial_out(sport, IP3106_ICLR, IP3106_UART_INT_TX);
++	}
++
++	/* TX shift register and holding register empty  */
++	if (status & IP3106_UART_INT_EMPTY) {
++		serial_out(sport, IP3106_ICLR, IP3106_UART_INT_EMPTY);
++	}
++
++	/* Receiver time out */
++	if (status & IP3106_UART_INT_RCVTO) {
++		serial_out(sport, IP3106_ICLR, IP3106_UART_INT_RCVTO);
++	}
++	spin_unlock(&sport->port.lock);
++	return IRQ_HANDLED;
++}
++
++/*
++ * Return TIOCSER_TEMT when transmitter is not busy.
++ */
++static unsigned int ip3106_tx_empty(struct uart_port *port)
++{
++	struct ip3106_port *sport = (struct ip3106_port *)port;
++
++	return serial_in(sport, IP3106_FIFO) & IP3106_UART_FIFO_TXFIFO_STA ? 0 : TIOCSER_TEMT;
++}
++
++static unsigned int ip3106_get_mctrl(struct uart_port *port)
++{
++	struct ip3106_port *sport = (struct ip3106_port *)port;
++	unsigned int mctrl = TIOCM_DSR;
++	unsigned int msr;
++
++	/* REVISIT */
++
++	msr = serial_in(sport, IP3106_MCR);
++
++	mctrl |= msr & IP3106_UART_MCR_CTS ? TIOCM_CTS : 0;
++	mctrl |= msr & IP3106_UART_MCR_DCD ? TIOCM_CAR : 0;
++
++	return mctrl;
++}
++
++static void ip3106_set_mctrl(struct uart_port *port, unsigned int mctrl)
++{
++#if	0	/* FIXME */
++	struct ip3106_port *sport = (struct ip3106_port *)port;
++	unsigned int msr;
++#endif
++}
++
++/*
++ * Interrupts always disabled.
++ */
++static void ip3106_break_ctl(struct uart_port *port, int break_state)
++{
++	struct ip3106_port *sport = (struct ip3106_port *)port;
++	unsigned long flags;
++	unsigned int lcr;
++
++	spin_lock_irqsave(&sport->port.lock, flags);
++	lcr = serial_in(sport, IP3106_LCR);
++	if (break_state == -1)
++		lcr |= IP3106_UART_LCR_TXBREAK;
++	else
++		lcr &= ~IP3106_UART_LCR_TXBREAK;
++	serial_out(sport, IP3106_LCR, lcr);
++	spin_unlock_irqrestore(&sport->port.lock, flags);
++}
++
++static int ip3106_startup(struct uart_port *port)
++{
++	struct ip3106_port *sport = (struct ip3106_port *)port;
++	int retval;
++
++	/*
++	 * Allocate the IRQ
++	 */
++	retval = request_irq(sport->port.irq, ip3106_int, 0,
++			     "ip3106-uart", sport);
++	if (retval)
++		return retval;
++
++	/*
++	 * Finally, clear and enable interrupts
++	 */
++
++	serial_out(sport, IP3106_ICLR, IP3106_UART_INT_ALLRX |
++			     IP3106_UART_INT_ALLTX);
++
++	serial_out(sport, IP3106_IEN, serial_in(sport, IP3106_IEN) |
++			    IP3106_UART_INT_ALLRX |
++			    IP3106_UART_INT_ALLTX);
++
++	/*
++	 * Enable modem status interrupts
++	 */
++	spin_lock_irq(&sport->port.lock);
++	ip3106_enable_ms(&sport->port);
++	spin_unlock_irq(&sport->port.lock);
++
++	return 0;
++}
++
++static void ip3106_shutdown(struct uart_port *port)
++{
++	struct ip3106_port *sport = (struct ip3106_port *)port;
++
++	/*
++	 * Stop our timer.
++	 */
++	del_timer_sync(&sport->timer);
++
++	/*
++	 * Disable all interrupts, port and break condition.
++	 */
++	serial_out(sport, IP3106_IEN, 0);
++
++	/*
++	 * Reset the Tx and Rx FIFOS
++	 */
++	serial_out(sport, IP3106_LCR, serial_in(sport, IP3106_LCR) |
++			    IP3106_UART_LCR_TX_RST |
++			    IP3106_UART_LCR_RX_RST);
++
++	/*
++	 * Clear all interrupts
++	 */
++	serial_out(sport, IP3106_ICLR, IP3106_UART_INT_ALLRX |
++			     IP3106_UART_INT_ALLTX);
++
++	/*
++	 * Free the interrupt
++	 */
++	free_irq(sport->port.irq, sport);
++}
++
++static void
++ip3106_set_termios(struct uart_port *port, struct termios *termios,
++		   struct termios *old)
++{
++	struct ip3106_port *sport = (struct ip3106_port *)port;
++	unsigned long flags;
++	unsigned int lcr_fcr, old_ien, baud, quot;
++	unsigned int old_csize = old ? old->c_cflag & CSIZE : CS8;
++
++	/*
++	 * We only support CS7 and CS8.
++	 */
++	while ((termios->c_cflag & CSIZE) != CS7 &&
++	       (termios->c_cflag & CSIZE) != CS8) {
++		termios->c_cflag &= ~CSIZE;
++		termios->c_cflag |= old_csize;
++		old_csize = CS8;
++	}
++
++	if ((termios->c_cflag & CSIZE) == CS8)
++		lcr_fcr = IP3106_UART_LCR_8BIT;
++	else
++		lcr_fcr = 0;
++
++	if (termios->c_cflag & CSTOPB)
++		lcr_fcr |= IP3106_UART_LCR_2STOPB;
++	if (termios->c_cflag & PARENB) {
++		lcr_fcr |= IP3106_UART_LCR_PAREN;
++		if (!(termios->c_cflag & PARODD))
++			lcr_fcr |= IP3106_UART_LCR_PAREVN;
++	}
++
++	/*
++	 * Ask the core to calculate the divisor for us.
++	 */
++	baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16);
++	quot = uart_get_divisor(port, baud);
++
++	spin_lock_irqsave(&sport->port.lock, flags);
++
++#if	0	/* REVISIT */
++	sport->port.read_status_mask &= UTSR0_TO_SM(UTSR0_TFS);
++	sport->port.read_status_mask |= UTSR1_TO_SM(UTSR1_ROR);
++	if (termios->c_iflag & INPCK)
++		sport->port.read_status_mask |=
++				UTSR1_TO_SM(UTSR1_FRE | UTSR1_PRE);
++	if (termios->c_iflag & (BRKINT | PARMRK))
++		sport->port.read_status_mask |=
++				UTSR0_TO_SM(UTSR0_RBB | UTSR0_REB);
++
++	/*
++	 * Characters to ignore
++	 */
++	sport->port.ignore_status_mask = 0;
++	if (termios->c_iflag & IGNPAR)
++		sport->port.ignore_status_mask |=
++				UTSR1_TO_SM(UTSR1_FRE | UTSR1_PRE);
++	if (termios->c_iflag & IGNBRK) {
++		sport->port.ignore_status_mask |=
++				UTSR0_TO_SM(UTSR0_RBB | UTSR0_REB);
++		/*
++		 * If we're ignoring parity and break indicators,
++		 * ignore overruns too (for real raw support).
++		 */
++		if (termios->c_iflag & IGNPAR)
++			sport->port.ignore_status_mask |=
++				UTSR1_TO_SM(UTSR1_ROR);
++	}
++#endif
++
++	del_timer_sync(&sport->timer);
++
++	/*
++	 * Update the per-port timeout.
++	 */
++	uart_update_timeout(port, termios->c_cflag, baud);
++
++	/*
++	 * disable interrupts and drain transmitter
++	 */
++	old_ien = serial_in(sport, IP3106_IEN);
++	serial_out(sport, IP3106_IEN, old_ien & ~(IP3106_UART_INT_ALLTX |
++					IP3106_UART_INT_ALLRX));
++
++	while (serial_in(sport, IP3106_FIFO) & IP3106_UART_FIFO_TXFIFO_STA)
++		barrier();
++
++	/* then, disable everything */
++	serial_out(sport, IP3106_IEN, 0);
++
++	/* Reset the Rx and Tx FIFOs too */
++	lcr_fcr |= IP3106_UART_LCR_TX_RST;
++	lcr_fcr |= IP3106_UART_LCR_RX_RST;
++
++	/* set the parity, stop bits and data size */
++	serial_out(sport, IP3106_LCR, lcr_fcr);
++
++	/* set the baud rate */
++	quot -= 1;
++	serial_out(sport, IP3106_BAUD, quot);
++
++	serial_out(sport, IP3106_ICLR, -1);
++
++	serial_out(sport, IP3106_IEN, old_ien);
++
++	if (UART_ENABLE_MS(&sport->port, termios->c_cflag))
++		ip3106_enable_ms(&sport->port);
++
++	spin_unlock_irqrestore(&sport->port.lock, flags);
++}
++
++static const char *ip3106_type(struct uart_port *port)
++{
++	struct ip3106_port *sport = (struct ip3106_port *)port;
++
++	return sport->port.type == PORT_IP3106 ? "IP3106" : NULL;
++}
++
++/*
++ * Release the memory region(s) being used by 'port'.
++ */
++static void ip3106_release_port(struct uart_port *port)
++{
++	struct ip3106_port *sport = (struct ip3106_port *)port;
++
++	release_mem_region(sport->port.mapbase, UART_PORT_SIZE);
++}
++
++/*
++ * Request the memory region(s) being used by 'port'.
++ */
++static int ip3106_request_port(struct uart_port *port)
++{
++	struct ip3106_port *sport = (struct ip3106_port *)port;
++
++	return request_mem_region(sport->port.mapbase, UART_PORT_SIZE,
++			"ip3106-uart") != NULL ? 0 : -EBUSY;
++}
++
++/*
++ * Configure/autoconfigure the port.
++ */
++static void ip3106_config_port(struct uart_port *port, int flags)
++{
++	struct ip3106_port *sport = (struct ip3106_port *)port;
++
++	if (flags & UART_CONFIG_TYPE &&
++	    ip3106_request_port(&sport->port) == 0)
++		sport->port.type = PORT_IP3106;
++}
++
++/*
++ * Verify the new serial_struct (for TIOCSSERIAL).
++ * The only change we allow are to the flags and type, and
++ * even then only between PORT_IP3106 and PORT_UNKNOWN
++ */
++static int
++ip3106_verify_port(struct uart_port *port, struct serial_struct *ser)
++{
++	struct ip3106_port *sport = (struct ip3106_port *)port;
++	int ret = 0;
++
++	if (ser->type != PORT_UNKNOWN && ser->type != PORT_IP3106)
++		ret = -EINVAL;
++	if (sport->port.irq != ser->irq)
++		ret = -EINVAL;
++	if (ser->io_type != SERIAL_IO_MEM)
++		ret = -EINVAL;
++	if (sport->port.uartclk / 16 != ser->baud_base)
++		ret = -EINVAL;
++	if ((void *)sport->port.mapbase != ser->iomem_base)
++		ret = -EINVAL;
++	if (sport->port.iobase != ser->port)
++		ret = -EINVAL;
++	if (ser->hub6 != 0)
++		ret = -EINVAL;
++	return ret;
++}
++
++struct uart_ops ip3106_pops = {
++	.tx_empty	= ip3106_tx_empty,
++	.set_mctrl	= ip3106_set_mctrl,
++	.get_mctrl	= ip3106_get_mctrl,
++	.stop_tx	= ip3106_stop_tx,
++	.start_tx	= ip3106_start_tx,
++	.stop_rx	= ip3106_stop_rx,
++	.enable_ms	= ip3106_enable_ms,
++	.break_ctl	= ip3106_break_ctl,
++	.startup	= ip3106_startup,
++	.shutdown	= ip3106_shutdown,
++	.set_termios	= ip3106_set_termios,
++	.type		= ip3106_type,
++	.release_port	= ip3106_release_port,
++	.request_port	= ip3106_request_port,
++	.config_port	= ip3106_config_port,
++	.verify_port	= ip3106_verify_port,
++};
++
++
++/*
++ * Setup the IP3106 serial ports.
++ *
++ * Note also that we support "console=ttySx" where "x" is either 0 or 1.
++ */
++static void __init ip3106_init_ports(void)
++{
++	static int first = 1;
++	int i;
++
++	if (!first)
++		return;
++	first = 0;
++
++	for (i = 0; i < NR_PORTS; i++) {
++		init_timer(&ip3106_ports[i].timer);
++		ip3106_ports[i].timer.function = ip3106_timeout;
++		ip3106_ports[i].timer.data     = (unsigned long)&ip3106_ports[i];
++	}
++}
++
++#ifdef CONFIG_SERIAL_IP3106_CONSOLE
++
++/*
++ * Interrupts are disabled on entering
++ */
++static void
++ip3106_console_write(struct console *co, const char *s, unsigned int count)
++{
++	struct ip3106_port *sport = &ip3106_ports[co->index];
++	unsigned int old_ien, status, i;
++
++	/*
++	 *	First, save IEN and then disable interrupts
++	 */
++	old_ien = serial_in(sport, IP3106_IEN);
++	serial_out(sport, IP3106_IEN, old_ien & ~(IP3106_UART_INT_ALLTX |
++					IP3106_UART_INT_ALLRX));
++
++	/*
++	 *	Now, do each character
++	 */
++	for (i = 0; i < count; i++) {
++		do {
++			/* Wait for UART_TX register to empty */
++			status = serial_in(sport, IP3106_FIFO);
++		} while (status & IP3106_UART_FIFO_TXFIFO);
++		serial_out(sport, IP3106_FIFO, s[i]);
++		if (s[i] == '\n') {
++			do {
++				status = serial_in(sport, IP3106_FIFO);
++			} while (status & IP3106_UART_FIFO_TXFIFO);
++			serial_out(sport, IP3106_FIFO, '\r');
++		}
++	}
++
++	/*
++	 *	Finally, wait for transmitter to become empty
++	 *	and restore IEN
++	 */
++	do {
++		/* Wait for UART_TX register to empty */
++		status = serial_in(sport, IP3106_FIFO);
++	} while (status & IP3106_UART_FIFO_TXFIFO);
++
++	/* Clear TX and EMPTY interrupt */
++	serial_out(sport, IP3106_ICLR, IP3106_UART_INT_TX |
++			     IP3106_UART_INT_EMPTY);
++
++	serial_out(sport, IP3106_IEN, old_ien);
++}
++
++static int __init
++ip3106_console_setup(struct console *co, char *options)
++{
++	struct ip3106_port *sport;
++	int baud = 38400;
++	int bits = 8;
++	int parity = 'n';
++	int flow = 'n';
++
++	/*
++	 * Check whether an invalid uart number has been specified, and
++	 * if so, search for the first available port that does have
++	 * console support.
++	 */
++	if (co->index == -1 || co->index >= NR_PORTS)
++		co->index = 0;
++	sport = &ip3106_ports[co->index];
++
++	if (options)
++		uart_parse_options(options, &baud, &parity, &bits, &flow);
++
++	return uart_set_options(&sport->port, co, baud, parity, bits, flow);
++}
++
++extern struct uart_driver ip3106_reg;
++static struct console ip3106_console = {
++	.name		= "ttyS",
++	.write		= ip3106_console_write,
++	.device		= uart_console_device,
++	.setup		= ip3106_console_setup,
++	.flags		= CON_PRINTBUFFER,
++	.index		= -1,
++	.data		= &ip3106_reg,
++};
++
++static int __init ip3106_rs_console_init(void)
++{
++	ip3106_init_ports();
++	register_console(&ip3106_console);
++	return 0;
++}
++console_initcall(ip3106_rs_console_init);
++
++#define IP3106_CONSOLE	&ip3106_console
++#else
++#define IP3106_CONSOLE	NULL
++#endif
++
++static struct uart_driver ip3106_reg = {
++	.owner			= THIS_MODULE,
++	.driver_name		= "ttyS",
++	.dev_name		= "ttyS",
++	.devfs_name		= "tts/",
++	.major			= SERIAL_IP3106_MAJOR,
++	.minor			= MINOR_START,
++	.nr			= NR_PORTS,
++	.cons			= IP3106_CONSOLE,
++};
++
++static int ip3106_serial_suspend(struct device *_dev, u32 state, u32 level)
++{
++	struct ip3106_port *sport = dev_get_drvdata(_dev);
++
++	if (sport && level == SUSPEND_DISABLE)
++		uart_suspend_port(&ip3106_reg, &sport->port);
++
++	return 0;
++}
++
++static int ip3106_serial_resume(struct device *_dev, u32 level)
++{
++	struct ip3106_port *sport = dev_get_drvdata(_dev);
++
++	if (sport && level == RESUME_ENABLE)
++		uart_resume_port(&ip3106_reg, &sport->port);
++
++	return 0;
++}
++
++static int ip3106_serial_probe(struct device *_dev)
++{
++	struct platform_device *dev = to_platform_device(_dev);
++	struct resource *res = dev->resource;
++	int i;
++
++	for (i = 0; i < dev->num_resources; i++, res++) {
++		if (!(res->flags & IORESOURCE_MEM))
++			continue;
++
++		for (i = 0; i < NR_PORTS; i++) {
++			if (ip3106_ports[i].port.mapbase != res->start)
++				continue;
++
++			ip3106_ports[i].port.dev = _dev;
++			uart_add_one_port(&ip3106_reg, &ip3106_ports[i].port);
++			dev_set_drvdata(_dev, &ip3106_ports[i]);
++			break;
++		}
++	}
++
++	return 0;
++}
++
++static int ip3106_serial_remove(struct device *_dev)
++{
++	struct ip3106_port *sport = dev_get_drvdata(_dev);
++
++	dev_set_drvdata(_dev, NULL);
++
++	if (sport)
++		uart_remove_one_port(&ip3106_reg, &sport->port);
++
++	return 0;
++}
++
++static struct device_driver ip3106_serial_driver = {
++	.name		= "ip3106-uart",
++	.bus		= &platform_bus_type,
++	.probe		= ip3106_serial_probe,
++	.remove		= ip3106_serial_remove,
++	.suspend	= ip3106_serial_suspend,
++	.resume		= ip3106_serial_resume,
++};
++
++static int __init ip3106_serial_init(void)
++{
++	int ret;
++
++	printk(KERN_INFO "Serial: IP3106 driver $Revision: 1.2 $\n");
++
++	ip3106_init_ports();
++
++	ret = uart_register_driver(&ip3106_reg);
++	if (ret == 0) {
++		ret = driver_register(&ip3106_serial_driver);
++		if (ret)
++			uart_unregister_driver(&ip3106_reg);
++	}
++	return ret;
++}
++
++static void __exit ip3106_serial_exit(void)
++{
++	driver_unregister(&ip3106_serial_driver);
++	uart_unregister_driver(&ip3106_reg);
++}
++
++module_init(ip3106_serial_init);
++module_exit(ip3106_serial_exit);
++
++MODULE_AUTHOR("Embedded Alley Solutions, Inc.");
++MODULE_DESCRIPTION("IP3106 generic serial port driver");
++MODULE_LICENSE("GPL");
++MODULE_ALIAS_CHARDEV_MAJOR(SERIAL_IP3106_MAJOR);
+diff -Naur linux-2.6.15.orig/drivers/usb/gadget/net2280.c linux-2.6.15/drivers/usb/gadget/net2280.c
+--- linux-2.6.15.orig/drivers/usb/gadget/net2280.c	2006-01-03 03:21:10.000000000 +0000
++++ linux-2.6.15/drivers/usb/gadget/net2280.c	2006-01-09 19:54:13.000000000 +0000
+@@ -448,7 +448,8 @@
+ #elif	defined(CONFIG_PPC) && !defined(CONFIG_NOT_COHERENT_CACHE)
+ #define USE_KMALLOC
+ 
+-#elif	defined(CONFIG_MIPS) && !defined(CONFIG_DMA_NONCOHERENT)
++#elif	defined(CONFIG_MIPS) && \
++	(defined(CONFIG_DMA_COHERENT) || defined(CONFIG_DMA_IP27))
+ #define USE_KMALLOC
+ 
+ /* FIXME there are other cases, including an x86-64 one ...  */
+diff -Naur linux-2.6.15.orig/drivers/usb/host/ohci-au1xxx.c linux-2.6.15/drivers/usb/host/ohci-au1xxx.c
+--- linux-2.6.15.orig/drivers/usb/host/ohci-au1xxx.c	2006-01-03 03:21:10.000000000 +0000
++++ linux-2.6.15/drivers/usb/host/ohci-au1xxx.c	2006-01-09 19:54:13.000000000 +0000
+@@ -91,12 +91,12 @@
+ 	int retval;
+ 	struct usb_hcd *hcd;
+ 
+-	if(dev->resource[1].flags != IORESOURCE_IRQ) {
++	if (dev->resource[1].flags != IORESOURCE_IRQ) {
+ 		pr_debug ("resource[1] is not IORESOURCE_IRQ");
+-		return -ENOMEM;
++		retval = -ENOMEM;
+ 	}
+ 
+-	hcd = usb_create_hcd(driver, &dev->dev, "au1xxx");
++	hcd = usb_create_hcd(driver, &dev->dev, "Au1xxx");
+ 	if (!hcd)
+ 		return -ENOMEM;
+ 	hcd->rsrc_start = dev->resource[0].start;
+diff -Naur linux-2.6.15.orig/drivers/usb/host/ohci-hcd.c linux-2.6.15/drivers/usb/host/ohci-hcd.c
+--- linux-2.6.15.orig/drivers/usb/host/ohci-hcd.c	2006-01-03 03:21:10.000000000 +0000
++++ linux-2.6.15/drivers/usb/host/ohci-hcd.c	2006-01-09 19:54:13.000000000 +0000
+@@ -913,6 +913,10 @@
+ #include "ohci-au1xxx.c"
+ #endif
+ 
++#ifdef CONFIG_PNX8550
++#include "ohci-pnx8550.c"
++#endif
++
+ #ifdef CONFIG_USB_OHCI_HCD_PPC_SOC
+ #include "ohci-ppc-soc.c"
+ #endif
+diff -Naur linux-2.6.15.orig/drivers/usb/host/ohci-pnx8550.c linux-2.6.15/drivers/usb/host/ohci-pnx8550.c
+--- linux-2.6.15.orig/drivers/usb/host/ohci-pnx8550.c	1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.15/drivers/usb/host/ohci-pnx8550.c	2006-01-09 19:54:13.000000000 +0000
+@@ -0,0 +1,277 @@
++/*
++ * OHCI HCD (Host Controller Driver) for USB.
++ *
++ * (C) Copyright 1999 Roman Weissgaerber <weissg at vienna.at>
++ * (C) Copyright 2000-2002 David Brownell <dbrownell at users.sourceforge.net>
++ * (C) Copyright 2002 Hewlett-Packard Company
++ * (C) Copyright 2005 Embedded Alley Solutions, Inc.
++ *
++ * Bus Glue for PNX8550
++ *
++ * Written by Christopher Hoover <ch at hpl.hp.com>
++ * Based on fragments of previous driver by Russell King et al.
++ *
++ * Modified for LH7A404 from ohci-sa1111.c
++ *  by Durgesh Pattamatta <pattamattad at sharpsec.com>
++ *
++ * Modified for pxa27x from ohci-lh7a404.c
++ *  by Nick Bane <nick at cecomputing.co.uk> 26-8-2004
++ *
++ * Modified for PNX8550 from ohci-pxa27x.c
++ *  by Embedded Alley Solutions, Inc. 
++ *
++ * This file is licenced under the GPL.
++ */
++
++#include <linux/device.h>
++#include <asm/mach-pnx8550/usb.h>
++#include <asm/mach-pnx8550/int.h>
++#include <asm/mach-pnx8550/pci.h>
++
++#ifndef CONFIG_PNX8550
++#error "This file is PNX8550 bus glue.  CONFIG_PNX8550 must be defined."
++#endif
++
++extern int usb_disabled(void);
++
++/*-------------------------------------------------------------------------*/
++
++static void pnx8550_start_hc(struct platform_device *dev)
++{
++	/*
++	 * Set register CLK48CTL to enable and 48MHz
++	 */
++	outl(0x00000003, PCI_BASE | 0x0004770c);
++
++	/*
++	 * Set register CLK12CTL to enable and 48MHz
++	 */
++	outl(0x00000003, PCI_BASE | 0x00047710);
++
++	udelay(100);
++}
++
++static void pnx8550_stop_hc(struct platform_device *dev)
++{
++	udelay(10);
++}
++
++
++/*-------------------------------------------------------------------------*/
++
++/* configure so an HC device and id are always provided */
++/* always called with process context; sleeping is OK */
++
++
++/**
++ * usb_hcd_pnx8550_probe - initialize pnx8550-based HCDs
++ * Context: !in_interrupt()
++ *
++ * Allocates basic resources for this USB host controller, and
++ * then invokes the start() method for the HCD associated with it
++ * through the hotplug entry's driver_data.
++ *
++ */
++int usb_hcd_pnx8550_probe (const struct hc_driver *driver,
++			  struct platform_device *dev)
++{
++	int retval;
++	struct usb_hcd *hcd;
++
++	if (dev->resource[1].flags != IORESOURCE_IRQ) {
++		pr_debug ("resource[1] is not IORESOURCE_IRQ");
++		return -ENOMEM;
++	}
++
++	hcd = usb_create_hcd (driver, &dev->dev, "pnx8550");
++	if (!hcd)
++		return -ENOMEM;
++	hcd->rsrc_start = dev->resource[0].start;
++	hcd->rsrc_len = dev->resource[0].end - dev->resource[0].start + 1;
++
++	if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
++		pr_debug("request_mem_region failed");
++		retval = -EBUSY;
++		goto err1;
++	}
++
++	hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
++	if (!hcd->regs) {
++		pr_debug("ioremap failed");
++		retval = -ENOMEM;
++		goto err2;
++	}
++
++	pnx8550_start_hc(dev);
++
++	ohci_hcd_init(hcd_to_ohci(hcd));
++
++	retval = usb_add_hcd(hcd, dev->resource[1].start, SA_INTERRUPT);
++	if (retval == 0)
++		return retval;
++
++	pnx8550_stop_hc(dev);
++	iounmap(hcd->regs);
++ err2:
++	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
++ err1:
++	usb_put_hcd(hcd);
++	return retval;
++}
++
++
++/* may be called without controller electrically present */
++/* may be called with controller, bus, and devices active */
++
++/**
++ * usb_hcd_pnx8550_remove - shutdown processing for pnx8550-based HCDs
++ * @dev: USB Host Controller being removed
++ * Context: !in_interrupt()
++ *
++ * Reverses the effect of usb_hcd_pnx8550_probe(), first invoking
++ * the HCD's stop() method.  It is always called from a thread
++ * context, normally "rmmod", "apmd", or something similar.
++ *
++ */
++void usb_hcd_pnx8550_remove (struct usb_hcd *hcd, struct platform_device *dev)
++{
++	usb_remove_hcd(hcd);
++	pnx8550_stop_hc(dev);
++	iounmap(hcd->regs);
++	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
++	usb_put_hcd(hcd);
++}
++
++/*-------------------------------------------------------------------------*/
++
++static int __devinit
++ohci_pnx8550_start (struct usb_hcd *hcd)
++{
++	struct ohci_hcd	*ohci = hcd_to_ohci (hcd);
++	int		ret;
++
++	ohci_dbg (ohci, "ohci_pnx8550_start, ohci:%p", ohci);
++
++	if ((ret = ohci_init(ohci)) < 0)
++		return ret;
++
++	if ((ret = ohci_run (ohci)) < 0) {
++		err ("can't start %s", hcd->self.bus_name);
++		ohci_stop (hcd);
++		return ret;
++	}
++
++	return 0;
++}
++
++/*-------------------------------------------------------------------------*/
++
++static const struct hc_driver ohci_pnx8550_hc_driver = {
++	.description =		hcd_name,
++	.product_desc =		"PNX8550 OHCI",
++	.hcd_priv_size =	sizeof(struct ohci_hcd),
++
++	/*
++	 * generic hardware linkage
++	 */
++	.irq =			ohci_irq,
++	.flags =		HCD_USB11 | HCD_MEMORY,
++
++	/*
++	 * basic lifecycle operations
++	 */
++	.start =		ohci_pnx8550_start,
++	.stop =			ohci_stop,
++
++	/*
++	 * managing i/o requests and associated device resources
++	 */
++	.urb_enqueue =		ohci_urb_enqueue,
++	.urb_dequeue =		ohci_urb_dequeue,
++	.endpoint_disable =	ohci_endpoint_disable,
++
++	/*
++	 * scheduling support
++	 */
++	.get_frame_number =	ohci_get_frame,
++
++	/*
++	 * root hub support
++	 */
++	.hub_status_data =	ohci_hub_status_data,
++	.hub_control =		ohci_hub_control,
++#ifdef  CONFIG_USB_SUSPEND
++	.hub_suspend =		ohci_hub_suspend,
++	.hub_resume =		ohci_hub_resume,
++#endif
++};
++
++/*-------------------------------------------------------------------------*/
++
++static int ohci_hcd_pnx8550_drv_probe(struct device *dev)
++{
++	struct platform_device *pdev = to_platform_device(dev);
++	int ret;
++
++	pr_debug ("In ohci_hcd_pnx8550_drv_probe");
++
++	if (usb_disabled())
++		return -ENODEV;
++
++	ret = usb_hcd_pnx8550_probe(&ohci_pnx8550_hc_driver, pdev);
++	return ret;
++}
++
++static int ohci_hcd_pnx8550_drv_remove(struct device *dev)
++{
++	struct platform_device *pdev = to_platform_device(dev);
++	struct usb_hcd *hcd = dev_get_drvdata(dev);
++
++	usb_hcd_pnx8550_remove(hcd, pdev);
++	return 0;
++}
++
++static int ohci_hcd_pnx8550_drv_suspend(struct device *dev, u32 state, u32 level)
++{
++//	struct platform_device *pdev = to_platform_device(dev);
++//	struct usb_hcd *hcd = dev_get_drvdata(dev);
++	printk("%s: not implemented yet\n", __FUNCTION__);
++
++	return 0;
++}
++
++static int ohci_hcd_pnx8550_drv_resume(struct device *dev, u32 state)
++{
++//	struct platform_device *pdev = to_platform_device(dev);
++//	struct usb_hcd *hcd = dev_get_drvdata(dev);
++	printk("%s: not implemented yet\n", __FUNCTION__);
++
++	return 0;
++}
++
++
++static struct device_driver ohci_hcd_pnx8550_driver = {
++	.name		= "pnx8550-ohci",
++	.bus		= &platform_bus_type,
++	.probe		= ohci_hcd_pnx8550_drv_probe,
++	.remove		= ohci_hcd_pnx8550_drv_remove,
++	.suspend	= ohci_hcd_pnx8550_drv_suspend, 
++	.resume		= ohci_hcd_pnx8550_drv_resume, 
++};
++
++static int __init ohci_hcd_pnx8550_init (void)
++{
++	pr_debug (DRIVER_INFO " (pnx8550)");
++	pr_debug ("block sizes: ed %d td %d\n",
++		sizeof (struct ed), sizeof (struct td));
++
++	return driver_register(&ohci_hcd_pnx8550_driver);
++}
++
++static void __exit ohci_hcd_pnx8550_cleanup (void)
++{
++	driver_unregister(&ohci_hcd_pnx8550_driver);
++}
++
++module_init (ohci_hcd_pnx8550_init);
++module_exit (ohci_hcd_pnx8550_cleanup);
+diff -Naur linux-2.6.15.orig/drivers/video/Kconfig linux-2.6.15/drivers/video/Kconfig
+--- linux-2.6.15.orig/drivers/video/Kconfig	2006-01-03 03:21:10.000000000 +0000
++++ linux-2.6.15/drivers/video/Kconfig	2006-01-09 19:54:13.000000000 +0000
+@@ -1149,6 +1149,17 @@
+ 	  Please read the <file:Documentation/fb/README-sstfb.txt> for supported
+ 	  options and other important info  support.
+ 
++config FB_SMIVGX
++	tristate "Silicon Motion VoyagerGX support"
++	depends on FB && PCI && (MIPS || EXPERIMENTAL)
++	select FB_CFB_FILLRECT
++	select FB_CFB_COPYAREA
++	select FB_CFB_IMAGEBLIT
++	---help---
++	  This drivers supports SMI VoyagerGX 501 based PCI boards
++	  The default settings drive both a CRT and LCD.  The CRT
++	  can be turned off by passing in the no_crt option
++
+ config FB_CYBLA
+ 	tristate "Cyberblade/i1 support"
+ 	depends on FB && PCI
+@@ -1213,7 +1224,25 @@
+ 
+ config FB_AU1100
+ 	bool "Au1100 LCD Driver"
+-	depends on (FB = y) && EXPERIMENTAL && PCI && MIPS && MIPS_PB1100=y
++	depends on FB && MIPS && SOC_AU1100
++	select FB_CFB_FILLRECT
++	select FB_CFB_COPYAREA
++	select FB_CFB_IMAGEBLIT
++	help
++	  This is the framebuffer driver for the AMD Au1100 SOC.  It can drive
++	  various panels and CRTs by passing in kernel cmd line option
++	  au1100fb:panel=<name>.
++
++config FB_AU1200
++	bool "Au1200 LCD Driver"
++	depends on FB && MIPS && SOC_AU1200
++	select FB_CFB_FILLRECT
++	select FB_CFB_COPYAREA
++	select FB_CFB_IMAGEBLIT
++	help
++	  This is the framebuffer driver for the AMD Au1200 SOC.  It can drive
++	  various panels and CRTs by passing in kernel cmd line option
++	  au1200fb:panel=<name>.
+ 
+ source "drivers/video/geode/Kconfig"
+ 
+@@ -1318,8 +1347,8 @@
+  	select FB_CFB_IMAGEBLIT
+ 	help
+ 	  Support for the PMAGB-B TURBOchannel framebuffer card used mainly
+-	  in the MIPS-based DECstation series. The card is currently only
+-	  supported in 1280x1024x8 mode.
++	  in the MIPS-based DECstation series. The card is currently only 
++	  supported in 1280x1024x8 mode.  
+ 
+ config FB_MAXINE
+ 	bool "Maxine (Personal DECstation) onboard framebuffer support"
+diff -Naur linux-2.6.15.orig/drivers/video/Makefile linux-2.6.15/drivers/video/Makefile
+--- linux-2.6.15.orig/drivers/video/Makefile	2006-01-03 03:21:10.000000000 +0000
++++ linux-2.6.15/drivers/video/Makefile	2006-01-09 19:54:13.000000000 +0000
+@@ -86,6 +86,7 @@
+ obj-$(CONFIG_FB_PXA)		  += pxafb.o
+ obj-$(CONFIG_FB_W100)		  += w100fb.o
+ obj-$(CONFIG_FB_AU1100)		  += au1100fb.o
++obj-$(CONFIG_FB_AU1200)		  += au1200fb.o
+ obj-$(CONFIG_FB_PMAG_AA)	  += pmag-aa-fb.o
+ obj-$(CONFIG_FB_PMAG_BA)	  += pmag-ba-fb.o
+ obj-$(CONFIG_FB_PMAGB_B)	  += pmagb-b-fb.o
+@@ -93,6 +94,7 @@
+ obj-$(CONFIG_FB_TX3912)		  += tx3912fb.o
+ obj-$(CONFIG_FB_S1D13XXX)	  += s1d13xxxfb.o
+ obj-$(CONFIG_FB_IMX)              += imxfb.o
++obj-$(CONFIG_FB_SMIVGX)		  += smivgxfb.o
+ obj-$(CONFIG_FB_S3C2410)	  += s3c2410fb.o
+ 
+ # Platform or fallback drivers go here
+diff -Naur linux-2.6.15.orig/drivers/video/au1100fb.c linux-2.6.15/drivers/video/au1100fb.c
+--- linux-2.6.15.orig/drivers/video/au1100fb.c	2006-01-03 03:21:10.000000000 +0000
++++ linux-2.6.15/drivers/video/au1100fb.c	2006-01-09 19:54:13.000000000 +0000
+@@ -3,7 +3,7 @@
+  *	Au1100 LCD Driver.
+  *
+  * Rewritten for 2.6 by Embedded Alley Solutions
+- * 	<source at embeddedalley.com>, based on submissions by
++ * 	<source at embeddedalley.com>, based on submissions by 
+  *  	Karl Lessard <klessard at sunrisetelecom.com>
+  *  	<c.pellegrin at exadron.com>
+  *
+@@ -38,6 +38,7 @@
+  *  with this program; if not, write  to the Free Software Foundation, Inc.,
+  *  675 Mass Ave, Cambridge, MA 02139, USA.
+  */
++
+ #include <linux/config.h>
+ #include <linux/module.h>
+ #include <linux/kernel.h>
+@@ -56,7 +57,7 @@
+ 
+ #include "au1100fb.h"
+ 
+-/*
++/* 
+  * Sanity check. If this is a new Au1100 based board, search for
+  * the PB1100 ifdefs to make sure you modify the code accordingly.
+  */
+@@ -74,11 +75,11 @@
+ #define to_au1100fb_device(_info) \
+ 	  (_info ? container_of(_info, struct au1100fb_device, info) : NULL);
+ 
+-/* Bitfields format supported by the controller. Note that the order of formats
++/* Bitfields format supported by the controller. Note that the order of formats 
+  * SHOULD be the same as in the LCD_CONTROL_SBPPF field, so we can retrieve the
+  * right pixel format by doing rgb_bitfields[LCD_CONTROL_SBPPF_XXX >> LCD_CONTROL_SBPPF]
+  */
+-struct fb_bitfield rgb_bitfields[][4] =
++struct fb_bitfield rgb_bitfields[][4] = 
+ {
+   	/*     Red, 	   Green, 	 Blue, 	     Transp   */
+ 	{ { 10, 6, 0 }, { 5, 5, 0 }, { 0, 5, 0 }, { 0, 0, 0 } },
+@@ -142,7 +143,7 @@
+ 			info->var.transp.msb_right = 0;
+ 
+ 			info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
+-			info->fix.line_length = info->var.xres_virtual /
++			info->fix.line_length = info->var.xres_virtual / 
+ 							(8/info->var.bits_per_pixel);
+ 		} else {
+ 			/* non-palettized */
+@@ -162,7 +163,7 @@
+ 	}
+ 
+ 	info->screen_size = info->fix.line_length * info->var.yres_virtual;
+-
++	
+ 	/* Determine BPP mode and format */
+ 	fbdev->regs->lcd_control = fbdev->panel->control_base |
+ 			    ((info->var.rotate/90) << LCD_CONTROL_SM_BIT);
+@@ -183,7 +184,7 @@
+ 		 * otherwise display the same as the first panel */
+ 		if (info->var.yres_virtual >= (info->var.yres << 1)) {
+ 			fbdev->regs->lcd_dmaaddr1 = LCD_DMA_SA_N(fbdev->fb_phys +
+-							  (info->fix.line_length *
++							  (info->fix.line_length * 
+ 						          (info->var.yres_virtual >> 1)));
+ 		} else {
+ 			fbdev->regs->lcd_dmaaddr1 = LCD_DMA_SA_N(fbdev->fb_phys);
+@@ -201,7 +202,7 @@
+ 
+ 	fbdev->regs->lcd_pwmdiv = 0;
+ 	fbdev->regs->lcd_pwmhi = 0;
+-
++   
+ 	/* Resume controller */
+ 	fbdev->regs->lcd_control |= LCD_CONTROL_GO;
+ 
+@@ -222,22 +223,22 @@
+ 
+ 	if (fbi->var.grayscale) {
+ 		/* Convert color to grayscale */
+-		red = green = blue =
++		red = green = blue = 
+ 			(19595 * red + 38470 * green + 7471 * blue) >> 16;
+ 	}
+-
++   
+ 	if (fbi->fix.visual == FB_VISUAL_TRUECOLOR) {
+ 		/* Place color in the pseudopalette */
+ 		if (regno > 16)
+ 			return -EINVAL;
+-
++   
+ 		palette = (u32*)fbi->pseudo_palette;
+ 
+ 		red   >>= (16 - fbi->var.red.length);
+ 		green >>= (16 - fbi->var.green.length);
+ 		blue  >>= (16 - fbi->var.blue.length);
+-
+-		value = (red   << fbi->var.red.offset) 	|
++	
++		value = (red   << fbi->var.red.offset) 	|	
+ 			(green << fbi->var.green.offset)|
+ 			(blue  << fbi->var.blue.offset);
+ 		value &= 0xFFFF;
+@@ -249,8 +250,8 @@
+ 
+ 	} else if (panel_is_color(fbdev->panel)) {
+ 		/* COLOR STN MODE */
+-		value = (((panel_swap_rgb(fbdev->panel) ? blue : red) >> 12) & 0x000F) |
+-			((green >> 8) & 0x00F0) |
++		value = (((panel_swap_rgb(fbdev->panel) ? blue : red) >> 12) & 0x000F) | 
++			((green >> 8) & 0x00F0) | 
+ 			(((panel_swap_rgb(fbdev->panel) ? red : blue) >> 4) & 0x0F00);
+ 		value &= 0xFFF;
+ 	} else {
+@@ -260,7 +261,7 @@
+ 	}
+ 
+ 	palette[regno] = value;
+-
++	
+ 	return 0;
+ }
+ 
+@@ -281,8 +282,8 @@
+ 			fbdev->regs->lcd_control |= LCD_CONTROL_GO;
+ #ifdef CONFIG_MIPS_PB1100
+ 			if (drv_info.panel_idx == 1) {
+-				au_writew(au_readw(PB1100_G_CONTROL)
+-					  | (PB1100_G_CONTROL_BL | PB1100_G_CONTROL_VDD),
++				au_writew(au_readw(PB1100_G_CONTROL) 
++					  | (PB1100_G_CONTROL_BL | PB1100_G_CONTROL_VDD), 
+ 			PB1100_G_CONTROL);
+ 			}
+ #endif
+@@ -296,14 +297,14 @@
+ 			fbdev->regs->lcd_control &= ~LCD_CONTROL_GO;
+ #ifdef CONFIG_MIPS_PB1100
+ 			if (drv_info.panel_idx == 1) {
+-				au_writew(au_readw(PB1100_G_CONTROL)
++				au_writew(au_readw(PB1100_G_CONTROL) 
+ 				  	  & ~(PB1100_G_CONTROL_BL | PB1100_G_CONTROL_VDD),
+ 			PB1100_G_CONTROL);
+ 			}
+ #endif
+ 		au_sync();
+ 		break;
+-	default:
++	default: 
+ 		break;
+ 
+ 	}
+@@ -328,7 +329,7 @@
+ 		/* No support for X panning for now! */
+ 		return -EINVAL;
+ 	}
+-
++			
+ 	print_dbg("fb_pan_display 2 %p %p", var, fbi);
+ 	dy = var->yoffset - fbi->var.yoffset;
+ 	if (dy) {
+@@ -388,7 +389,7 @@
+ 	if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT)) {
+ 		return -EINVAL;
+ 	}
+-
++    
+ 	start = fbdev->fb_phys & PAGE_MASK;
+ 	len = PAGE_ALIGN((start & ~PAGE_MASK) + fbdev->fb_len);
+ 
+@@ -405,7 +406,7 @@
+ 	pgprot_val(vma->vm_page_prot) |= (6 << 9); //CCA=6
+ 
+ 	vma->vm_flags |= VM_IO;
+-
++    
+ 	if (io_remap_page_range(vma, vma->vm_start, off,
+ 				vma->vm_end - vma->vm_start,
+ 				vma->vm_page_prot)) {
+@@ -415,7 +416,7 @@
+ 	return 0;
+ }
+ 
+-static struct fb_ops au1100fb_ops =
++static struct fb_ops au1100fb_ops = 
+ {
+ 	.owner			= THIS_MODULE,
+ 	.fb_setcolreg		= au1100fb_fb_setcolreg,
+@@ -455,7 +456,7 @@
+ 	dev_set_drvdata(dev, (void*)fbdev);
+ 
+ 	/* Allocate region for our registers and map them */
+-	if (!(regs_res = platform_get_resource(to_platform_device(dev),
++	if (!(regs_res = platform_get_resource(to_platform_device(dev), 
+ 					IORESOURCE_MEM, 0))) {
+ 		print_err("fail to retrieve registers resource");
+ 		return -EFAULT;
+@@ -464,9 +465,9 @@
+ 	au1100fb_fix.mmio_start = regs_res->start;
+ 	au1100fb_fix.mmio_len = regs_res->end - regs_res->start + 1;
+ 
+-	if (!request_mem_region(au1100fb_fix.mmio_start, au1100fb_fix.mmio_len,
++	if (!request_mem_region(au1100fb_fix.mmio_start, au1100fb_fix.mmio_len, 
+ 				DRIVER_NAME)) {
+-		print_err("fail to lock memory region at 0x%08x",
++		print_err("fail to lock memory region at 0x%08x", 
+ 				au1100fb_fix.mmio_start);
+ 		return -EBUSY;
+ 	}
+@@ -481,11 +482,11 @@
+ 	/* Allocate the framebuffer to the maximum screen size * nbr of video buffers */
+ 	fbdev->fb_len = fbdev->panel->xres * fbdev->panel->yres *
+ 		  	(fbdev->panel->bpp >> 3) * AU1100FB_NBR_VIDEO_BUFFERS;
+-
+-	fbdev->fb_mem = dma_alloc_coherent(dev, PAGE_ALIGN(fbdev->fb_len),
++	
++	fbdev->fb_mem = dma_alloc_coherent(dev, PAGE_ALIGN(fbdev->fb_len), 
+ 					&fbdev->fb_phys, GFP_KERNEL);
+ 	if (!fbdev->fb_mem) {
+-		print_err("fail to allocate frambuffer (size: %dK))",
++		print_err("fail to allocate frambuffer (size: %dK))", 
+ 			  fbdev->fb_len / 1024);
+ 		return -ENOMEM;
+ 	}
+@@ -498,7 +499,7 @@
+ 	 * since we'll be remapping normal memory.
+ 	 */
+ 	for (page = (unsigned long)fbdev->fb_mem;
+-	     page < PAGE_ALIGN((unsigned long)fbdev->fb_mem + fbdev->fb_len);
++	     page < PAGE_ALIGN((unsigned long)fbdev->fb_mem + fbdev->fb_len); 
+ 	     page += PAGE_SIZE) {
+ #if CONFIG_DMA_NONCOHERENT
+ 		SetPageReserved(virt_to_page(CAC_ADDR(page)));
+@@ -615,11 +616,11 @@
+ 	.suspend	= au1100fb_drv_suspend,
+         .resume		= au1100fb_drv_resume,
+ };
+-
++    
+ /*-------------------------------------------------------------------------*/
+ 
+ /* Kernel driver */
+-
++    
+ int au1100fb_setup(char *options)
+ {
+ 	char* this_opt;
+@@ -640,7 +641,7 @@
+ 				this_opt += 6;
+ 				for (i = 0; i < num_panels; i++) {
+ 					if (!strncmp(this_opt,
+-					      	     known_lcd_panels[i].name,
++					      	     known_lcd_panels[i].name, 
+ 							strlen(this_opt))) {
+ 						panel_idx = i;
+ 					break;
+@@ -660,7 +661,7 @@
+ 				print_warn("Unsupported option \"%s\"", this_opt);
+ 		}
+ 		}
+-	}
++	} 
+ 
+ 	drv_info.panel_idx = panel_idx;
+ 	drv_info.opt_mode = mode;
+@@ -676,9 +677,9 @@
+ {
+ 	char* options;
+ 	int ret;
+-
++	
+ 	print_info("" DRIVER_DESC "");
+-
++	
+ 	memset(&drv_info, 0, sizeof(drv_info));
+ 
+ 	if (fb_get_options(DRIVER_NAME, &options))
+diff -Naur linux-2.6.15.orig/drivers/video/au1100fb.h linux-2.6.15/drivers/video/au1100fb.h
+--- linux-2.6.15.orig/drivers/video/au1100fb.h	2006-01-03 03:21:10.000000000 +0000
++++ linux-2.6.15/drivers/video/au1100fb.h	2006-01-09 19:54:13.000000000 +0000
+@@ -78,7 +78,7 @@
+ 	u32 	bpp;		/* Maximum depth supported */
+ };
+ 
+-struct au1100fb_regs
++struct au1100fb_regs 
+ {
+ 	u32  lcd_control;
+ 	u32  lcd_intstatus;
+@@ -255,7 +255,7 @@
+ 
+ /* List of panels known to work with the AU1100 LCD controller.
+  * To add a new panel, enter the same specifications as the
+- * Generic_TFT one, and MAKE SURE that it doesn't conflicts
++ * Generic_TFT one, and MAKE SURE that it doesn't conflicts 
+  * with the controller restrictions. Restrictions are:
+  *
+  * STN color panels: max_bpp <= 12
+@@ -272,7 +272,7 @@
+ 		.xres = 800,
+ 		.yres = 600,
+ 		.bpp = 16,
+-		.control_base =	0x0004886A |
++		.control_base =	0x0004886A | 
+ 			LCD_CONTROL_DEFAULT_PO | LCD_CONTROL_DEFAULT_SBPPF |
+ 			LCD_CONTROL_BPP_16,
+ 		.clkcontrol_base = 0x00020000,
+diff -Naur linux-2.6.15.orig/drivers/video/au1200fb.c linux-2.6.15/drivers/video/au1200fb.c
+--- linux-2.6.15.orig/drivers/video/au1200fb.c	1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.15/drivers/video/au1200fb.c	2006-01-09 19:54:13.000000000 +0000
+@@ -0,0 +1,1940 @@
++/*
++ * BRIEF MODULE DESCRIPTION
++ *	Au1200 LCD Driver.
++ *
++ * Copyright 2004-2005 AMD
++ * Author: AMD
++ *
++ * Based on:
++ * linux/drivers/video/skeletonfb.c -- Skeleton for a frame buffer device
++ *  Created 28 Dec 1997 by Geert Uytterhoeven
++ *
++ *  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/module.h>
++#include <linux/platform_device.h>
++#include <linux/kernel.h>
++#include <linux/errno.h>
++#include <linux/string.h>
++#include <linux/mm.h>
++#include <linux/fb.h>
++#include <linux/init.h>
++#include <linux/interrupt.h>
++#include <linux/ctype.h>
++#include <linux/dma-mapping.h>
++
++#include <asm/mach-au1x00/au1000.h>
++#include "au1200fb.h"
++
++#ifdef CONFIG_PM
++#include <asm/mach-au1x00/au1xxx_pm.h>
++#endif
++
++#ifndef CONFIG_FB_AU1200_DEVS
++#define CONFIG_FB_AU1200_DEVS 4
++#endif
++
++#define DRIVER_NAME "au1200fb"
++#define DRIVER_DESC "LCD controller driver for AU1200 processors"
++
++#define DEBUG 1
++
++#define print_err(f, arg...) printk(KERN_ERR DRIVER_NAME ": " f "\n", ## arg)
++#define print_warn(f, arg...) printk(KERN_WARNING DRIVER_NAME ": " f "\n", ## arg)
++#define print_info(f, arg...) printk(KERN_INFO DRIVER_NAME ": " f "\n", ## arg)
++
++#if DEBUG
++#define print_dbg(f, arg...) printk(KERN_DEBUG __FILE__ ": " f "\n", ## arg)
++#else
++#define print_dbg(f, arg...) do {} while (0)
++#endif
++
++
++#define AU1200_LCD_FB_IOCTL 0x46FF
++
++#define AU1200_LCD_SET_SCREEN 1
++#define AU1200_LCD_GET_SCREEN 2
++#define AU1200_LCD_SET_WINDOW 3
++#define AU1200_LCD_GET_WINDOW 4
++#define AU1200_LCD_SET_PANEL  5
++#define AU1200_LCD_GET_PANEL  6
++
++#define SCREEN_SIZE		    (1<< 1)
++#define SCREEN_BACKCOLOR    (1<< 2)
++#define SCREEN_BRIGHTNESS   (1<< 3)
++#define SCREEN_COLORKEY     (1<< 4)
++#define SCREEN_MASK         (1<< 5)
++typedef struct au1200_lcd_global_regs_t
++{
++    unsigned int flags;
++    unsigned int xsize;
++    unsigned int ysize;
++    unsigned int backcolor;
++    unsigned int brightness;
++	unsigned int colorkey;
++	unsigned int mask;
++    unsigned int panel_choice;
++    char panel_desc[80];
++
++} au1200_lcd_global_regs_t;
++
++#define WIN_POSITION            (1<< 0)
++#define WIN_ALPHA_COLOR         (1<< 1)
++#define WIN_ALPHA_MODE          (1<< 2)
++#define WIN_PRIORITY            (1<< 3)
++#define WIN_CHANNEL             (1<< 4)
++#define WIN_BUFFER_FORMAT       (1<< 5)
++#define WIN_COLOR_ORDER         (1<< 6)
++#define WIN_PIXEL_ORDER         (1<< 7)
++#define WIN_SIZE                (1<< 8)
++#define WIN_COLORKEY_MODE       (1<< 9)
++#define WIN_DOUBLE_BUFFER_MODE  (1<< 10)
++#define WIN_RAM_ARRAY_MODE      (1<< 11)
++#define WIN_BUFFER_SCALE        (1<< 12)
++#define WIN_ENABLE	            (1<< 13)
++
++typedef struct au1200_lcd_window_regs_t
++{
++    unsigned int flags;
++    unsigned int xpos;
++    unsigned int ypos;
++    unsigned int alpha_color;
++    unsigned int alpha_mode;
++    unsigned int priority;
++    unsigned int channel;
++    unsigned int buffer_format;
++    unsigned int color_order;
++    unsigned int pixel_order;
++    unsigned int xsize;
++    unsigned int ysize;
++    unsigned int colorkey_mode;
++    unsigned int double_buffer_mode;
++    unsigned int ram_array_mode;
++    unsigned int xscale;
++    unsigned int yscale;
++    unsigned int enable;
++} au1200_lcd_window_regs_t;
++
++
++typedef struct au1200_lcd_iodata_t
++{
++
++    unsigned int subcmd;
++    au1200_lcd_global_regs_t global;
++    au1200_lcd_window_regs_t window;
++
++} au1200_lcd_iodata_t;
++
++#if defined(__BIG_ENDIAN)
++#define LCD_CONTROL_DEFAULT_PO LCD_CONTROL_PO_11
++#else
++#define LCD_CONTROL_DEFAULT_PO LCD_CONTROL_PO_00
++#endif
++#define LCD_CONTROL_DEFAULT_SBPPF LCD_CONTROL_SBPPF_565
++
++/* Private, per-framebuffer management information (independent of the panel itself) */
++struct au1200fb_device {
++	struct fb_info fb_info;			/* FB driver info record */
++
++	int					plane;
++	unsigned char* 		fb_mem;		/* FrameBuffer memory map */
++	unsigned int		fb_len;
++	dma_addr_t    		fb_phys;
++};
++
++static struct au1200fb_device _au1200fb_devices[CONFIG_FB_AU1200_DEVS];
++/********************************************************************/
++
++/* LCD controller restrictions */
++#define AU1200_LCD_MAX_XRES	1280
++#define AU1200_LCD_MAX_YRES	1024
++#define AU1200_LCD_MAX_BPP	32
++#define AU1200_LCD_MAX_CLK	96000000 /* fixme: this needs to go away ? */
++#define AU1200_LCD_NBR_PALETTE_ENTRIES 256
++
++/* Default number of visible screen buffer to allocate */
++#define AU1200FB_NBR_VIDEO_BUFFERS 1
++
++/********************************************************************/
++
++AU1200_LCD *lcd = (AU1200_LCD *)AU1200_LCD_ADDR;
++static int window_index = 2; /* default is zero */
++static int panel_index = 2; /* default is zero */
++static struct window_settings *win;
++static struct panel_settings *panel;
++static int noblanking = 1;
++static int nohwcursor = 0;
++
++struct window_settings
++{
++	unsigned char name[64];
++	uint32 mode_backcolor;
++	uint32 mode_colorkey;
++	uint32 mode_colorkeymsk;
++	struct
++	{
++		int xres;
++		int yres;
++		int xpos;
++		int ypos;
++		uint32 mode_winctrl1; /* winctrl1[FRM,CCO,PO,PIPE] */
++		uint32 mode_winenable;
++	} w[4];
++};
++
++#if defined(__BIG_ENDIAN)
++#define LCD_WINCTRL1_PO_16BPP LCD_WINCTRL1_PO_00
++#else
++#define LCD_WINCTRL1_PO_16BPP LCD_WINCTRL1_PO_01
++#endif
++
++extern int board_au1200fb_panel_init (void);
++extern int board_au1200fb_panel_shutdown (void);
++
++#ifdef CONFIG_PM 
++int au1200fb_pm_callback(au1xxx_power_dev_t *dev, 
++		au1xxx_request_t request, void *data);
++au1xxx_power_dev_t *LCD_pm_dev;
++#endif
++
++/*
++ * Default window configurations
++ */
++static struct window_settings windows[] =
++{
++	{ /* Index 0 */
++		"0-FS gfx, 1-video, 2-ovly gfx, 3-ovly gfx",
++		/* mode_backcolor	*/ 0x006600ff,
++		/* mode_colorkey,msk*/ 0, 0,
++		{
++			{
++			/* xres, yres, xpos, ypos */ 0, 0, 0, 0,
++			/* mode_winctrl1 */ LCD_WINCTRL1_FRM_16BPP565 |
++				LCD_WINCTRL1_PO_16BPP,
++			/* mode_winenable*/ LCD_WINENABLE_WEN0,
++			},
++			{
++			/* xres, yres, xpos, ypos */ 100, 100, 100, 100,
++			/* mode_winctrl1 */ LCD_WINCTRL1_FRM_16BPP565 |
++				LCD_WINCTRL1_PO_16BPP |
++				LCD_WINCTRL1_PIPE,
++			/* mode_winenable*/ LCD_WINENABLE_WEN1,
++			},
++			{
++			/* xres, yres, xpos, ypos */ 0, 0, 0, 0,
++			/* mode_winctrl1 */ LCD_WINCTRL1_FRM_16BPP565 |
++				LCD_WINCTRL1_PO_16BPP,
++			/* mode_winenable*/ 0,
++			},
++			{
++			/* xres, yres, xpos, ypos */ 0, 0, 0, 0,
++			/* mode_winctrl1 */ LCD_WINCTRL1_FRM_16BPP565 |
++				LCD_WINCTRL1_PO_16BPP |
++				LCD_WINCTRL1_PIPE,
++			/* mode_winenable*/ 0,
++			},
++		},
++	},
++
++	{ /* Index 1 */
++		"0-FS gfx, 1-video, 2-ovly gfx, 3-ovly gfx",
++		/* mode_backcolor	*/ 0x006600ff,
++		/* mode_colorkey,msk*/ 0, 0,
++		{
++			{
++			/* xres, yres, xpos, ypos */ 320, 240, 5, 5,
++			/* mode_winctrl1 */ LCD_WINCTRL1_FRM_24BPP |
++				LCD_WINCTRL1_PO_00,
++			/* mode_winenable*/ LCD_WINENABLE_WEN0,
++			},
++			{
++			/* xres, yres, xpos, ypos */ 0, 0, 0, 0,
++			/* mode_winctrl1 */ LCD_WINCTRL1_FRM_16BPP565 
++				| LCD_WINCTRL1_PO_16BPP,
++			/* mode_winenable*/ 0,
++			},
++			{
++			/* xres, yres, xpos, ypos */ 100, 100, 0, 0,
++			/* mode_winctrl1 */ LCD_WINCTRL1_FRM_16BPP565 | 
++				LCD_WINCTRL1_PO_16BPP |
++				LCD_WINCTRL1_PIPE,
++			/* mode_winenable*/ 0/*LCD_WINENABLE_WEN2*/,
++			},
++			{
++			/* xres, yres, xpos, ypos */ 200, 25, 0, 0,
++			/* mode_winctrl1 */ LCD_WINCTRL1_FRM_16BPP565 |
++				LCD_WINCTRL1_PO_16BPP |
++				LCD_WINCTRL1_PIPE,
++			/* mode_winenable*/ 0,
++			},
++		},
++	},
++	{ /* Index 2 */
++		"0-FS gfx, 1-video, 2-ovly gfx, 3-ovly gfx",
++		/* mode_backcolor	*/ 0x006600ff,
++		/* mode_colorkey,msk*/ 0, 0,
++		{
++			{
++			/* xres, yres, xpos, ypos */ 0, 0, 0, 0,
++			/* mode_winctrl1 */ LCD_WINCTRL1_FRM_16BPP565 |
++				LCD_WINCTRL1_PO_16BPP,
++			/* mode_winenable*/ LCD_WINENABLE_WEN0,
++			},
++			{
++			/* xres, yres, xpos, ypos */ 0, 0, 0, 0,
++			/* mode_winctrl1 */ LCD_WINCTRL1_FRM_16BPP565 |
++				LCD_WINCTRL1_PO_16BPP,
++			/* mode_winenable*/ 0,
++			},
++			{
++			/* xres, yres, xpos, ypos */ 0, 0, 0, 0,
++			/* mode_winctrl1 */ LCD_WINCTRL1_FRM_32BPP |
++				LCD_WINCTRL1_PO_00|LCD_WINCTRL1_PIPE,
++			/* mode_winenable*/ 0/*LCD_WINENABLE_WEN2*/,
++			},
++			{
++			/* xres, yres, xpos, ypos */ 0, 0, 0, 0,
++			/* mode_winctrl1 */ LCD_WINCTRL1_FRM_16BPP565 |
++				LCD_WINCTRL1_PO_16BPP |
++				LCD_WINCTRL1_PIPE,
++			/* mode_winenable*/ 0,
++			},
++		},
++	},
++	/* Need VGA 640 @ 24bpp, @ 32bpp */
++	/* Need VGA 800 @ 24bpp, @ 32bpp */
++	/* Need VGA 1024 @ 24bpp, @ 32bpp */
++} ;
++
++/*
++ * Controller configurations for various panels.
++ */
++
++struct panel_settings
++{
++	const char name[25];		/* Full name <vendor>_<model> */
++
++	struct 	fb_monspecs monspecs; 	/* FB monitor specs */
++
++	/* panel timings */
++	uint32 mode_screen;
++	uint32 mode_horztiming;
++	uint32 mode_verttiming;
++	uint32 mode_clkcontrol;
++	uint32 mode_pwmdiv;
++	uint32 mode_pwmhi;
++	uint32 mode_outmask;
++	uint32 mode_fifoctrl;
++	uint32 mode_toyclksrc;
++	uint32 mode_backlight;
++	uint32 mode_auxpll;
++	int (*device_init)(void);
++	int (*device_shutdown)(void);
++#define Xres min_xres
++#define Yres min_yres
++	u32	min_xres;		/* Minimum horizontal resolution */
++	u32	max_xres;		/* Maximum horizontal resolution */
++	u32 	min_yres;		/* Minimum vertical resolution */
++	u32 	max_yres;		/* Maximum vertical resolution */
++};
++
++/********************************************************************/
++/* fixme: Maybe a modedb for the CRT ? otherwise panels should be as-is */
++
++/* List of panels known to work with the AU1200 LCD controller.
++ * To add a new panel, enter the same specifications as the
++ * Generic_TFT one, and MAKE SURE that it doesn't conflicts 
++ * with the controller restrictions. Restrictions are:
++ *
++ * STN color panels: max_bpp <= 12
++ * STN mono panels: max_bpp <= 4
++ * TFT panels: max_bpp <= 16
++ * max_xres <= 800
++ * max_yres <= 600
++ */
++static struct panel_settings known_lcd_panels[] =
++{
++	[0] = { /* QVGA 320x240 H:33.3kHz V:110Hz */
++		.name = "QVGA_320x240",
++		.monspecs = {
++			.modedb = NULL,
++			.modedb_len = 0,
++			.hfmin = 30000, 
++			.hfmax = 70000,
++			.vfmin = 60, 
++			.vfmax = 60, 
++			.dclkmin = 6000000,
++			.dclkmax = 28000000,
++			.input = FB_DISP_RGB,
++		},
++		.mode_screen		= LCD_SCREEN_SX_N(320) | 
++			LCD_SCREEN_SY_N(240),
++		.mode_horztiming	= 0x00c4623b,
++		.mode_verttiming	= 0x00502814,
++		.mode_clkcontrol	= 0x00020002, /* /4=24Mhz */
++		.mode_pwmdiv		= 0x00000000,
++		.mode_pwmhi		= 0x00000000,
++		.mode_outmask	= 0x00FFFFFF,
++		.mode_fifoctrl	= 0x2f2f2f2f,
++		.mode_toyclksrc	= 0x00000004, /* AUXPLL directly */
++		.mode_backlight	= 0x00000000,
++		.mode_auxpll		= 8, /* 96MHz AUXPLL */
++		.device_init		= NULL,
++		.device_shutdown	= NULL,
++		320, 320,
++		240, 240,
++	},
++
++	[1] = { /* VGA 640x480 H:30.3kHz V:58Hz */
++		.name = "VGA_640x480",
++		.monspecs = {
++			.modedb = NULL,
++			.modedb_len = 0,
++			.hfmin = 30000,
++			.hfmax = 70000,
++			.vfmin = 60,
++			.vfmax = 60,
++			.dclkmin = 6000000,
++			.dclkmax = 28000000,
++			.input = FB_DISP_RGB,
++		},
++		.mode_screen		= 0x13f9df80,
++		.mode_horztiming	= 0x003c5859,
++		.mode_verttiming	= 0x00741201,
++		.mode_clkcontrol	= 0x00020001, /* /4=24Mhz */
++		.mode_pwmdiv		= 0x00000000,
++		.mode_pwmhi		= 0x00000000,
++		.mode_outmask	= 0x00FFFFFF,
++		.mode_fifoctrl	= 0x2f2f2f2f,
++		.mode_toyclksrc	= 0x00000004, /* AUXPLL directly */
++		.mode_backlight	= 0x00000000,
++		.mode_auxpll		= 8, /* 96MHz AUXPLL */
++		.device_init		= NULL,
++		.device_shutdown	= NULL,
++		640, 480,
++		640, 480,
++	},
++
++	[2] = { /* SVGA 800x600 H:46.1kHz V:69Hz */
++		.name = "SVGA_800x600",
++		.monspecs = {
++			.modedb = NULL,
++			.modedb_len = 0,
++			.hfmin = 30000,
++			.hfmax = 70000,
++			.vfmin = 60,
++			.vfmax = 60,
++			.dclkmin = 6000000,
++			.dclkmax = 28000000,
++			.input = FB_DISP_RGB,
++		},
++		.mode_screen		= 0x18fa5780,
++		.mode_horztiming	= 0x00dc7e77,
++		.mode_verttiming	= 0x00584805,
++		.mode_clkcontrol	= 0x00020000, /* /2=48Mhz */
++		.mode_pwmdiv		= 0x00000000,
++		.mode_pwmhi		= 0x00000000,
++		.mode_outmask	= 0x00FFFFFF,
++		.mode_fifoctrl	= 0x2f2f2f2f,
++		.mode_toyclksrc	= 0x00000004, /* AUXPLL directly */
++		.mode_backlight	= 0x00000000,
++		.mode_auxpll		= 8, /* 96MHz AUXPLL */
++		.device_init		= NULL,
++		.device_shutdown	= NULL,
++		800, 800,
++		600, 600,
++	},
++
++	[3] = { /* XVGA 1024x768 H:56.2kHz V:70Hz */
++		.name = "XVGA_1024x768",
++		.monspecs = {
++			.modedb = NULL,
++			.modedb_len = 0,
++			.hfmin = 30000,
++			.hfmax = 70000,
++			.vfmin = 60,
++			.vfmax = 60,
++			.dclkmin = 6000000,
++			.dclkmax = 28000000,
++			.input = FB_DISP_RGB,
++		},
++		.mode_screen		= 0x1ffaff80,
++		.mode_horztiming	= 0x007d0e57,
++		.mode_verttiming	= 0x00740a01,
++		.mode_clkcontrol	= 0x000A0000, /* /1 */
++		.mode_pwmdiv		= 0x00000000,
++		.mode_pwmhi		= 0x00000000,
++		.mode_outmask	= 0x00FFFFFF,
++		.mode_fifoctrl	= 0x2f2f2f2f,
++		.mode_toyclksrc	= 0x00000004, /* AUXPLL directly */
++		.mode_backlight	= 0x00000000,
++		.mode_auxpll		= 6, /* 72MHz AUXPLL */
++		.device_init		= NULL,
++		.device_shutdown	= NULL,
++		1024, 1024,
++		768, 768,
++	},
++
++	[4] = { /* XVGA XVGA 1280x1024 H:68.5kHz V:65Hz */
++		.name = "XVGA_1280x1024",
++		.monspecs = {
++			.modedb = NULL,
++			.modedb_len = 0,
++			.hfmin = 30000,
++			.hfmax = 70000,
++			.vfmin = 60,
++			.vfmax = 60,
++			.dclkmin = 6000000,
++			.dclkmax = 28000000,
++			.input = FB_DISP_RGB,
++		},
++		.mode_screen		= 0x27fbff80,
++		.mode_horztiming	= 0x00cdb2c7,
++		.mode_verttiming	= 0x00600002,
++		.mode_clkcontrol	= 0x000A0000, /* /1 */
++		.mode_pwmdiv		= 0x00000000,
++		.mode_pwmhi		= 0x00000000,
++		.mode_outmask	= 0x00FFFFFF,
++		.mode_fifoctrl	= 0x2f2f2f2f,
++		.mode_toyclksrc	= 0x00000004, /* AUXPLL directly */
++		.mode_backlight	= 0x00000000,
++		.mode_auxpll		= 10, /* 120MHz AUXPLL */
++		.device_init		= NULL,
++		.device_shutdown	= NULL,
++		1280, 1280,
++		1024, 1024,
++	},
++
++	[5] = { /* Samsung 1024x768 TFT */
++		.name = "Samsung_1024x768_TFT",
++		.monspecs = {
++			.modedb = NULL,
++			.modedb_len = 0,
++			.hfmin = 30000,
++			.hfmax = 70000,
++			.vfmin = 60,
++			.vfmax = 60,
++			.dclkmin = 6000000,
++			.dclkmax = 28000000,
++			.input = FB_DISP_RGB,
++		},
++		.mode_screen		= 0x1ffaff80,
++		.mode_horztiming	= 0x018cc677,
++		.mode_verttiming	= 0x00241217,
++		.mode_clkcontrol	= 0x00000000, /* SCB 0x1 /4=24Mhz */
++		.mode_pwmdiv		= 0x8000063f, /* SCB 0x0 */
++		.mode_pwmhi		= 0x03400000, /* SCB 0x0 */
++		.mode_outmask	= 0x00FFFFFF,
++		.mode_fifoctrl	= 0x2f2f2f2f,
++		.mode_toyclksrc	= 0x00000004, /* AUXPLL directly */
++		.mode_backlight	= 0x00000000,
++		.mode_auxpll		= 8, /* 96MHz AUXPLL */
++		.device_init		= board_au1200fb_panel_init,
++		.device_shutdown	= board_au1200fb_panel_shutdown,
++		1024, 1024,
++		768, 768,
++	},
++
++	[6] = { /* Toshiba 640x480 TFT */
++		.name = "Toshiba_640x480_TFT",
++		.monspecs = {
++			.modedb = NULL,
++			.modedb_len = 0,
++			.hfmin = 30000,
++			.hfmax = 70000,
++			.vfmin = 60,
++			.vfmax = 60,
++			.dclkmin = 6000000,
++			.dclkmax = 28000000,
++			.input = FB_DISP_RGB,
++		},
++		.mode_screen		= LCD_SCREEN_SX_N(640) | 
++			LCD_SCREEN_SY_N(480),
++		.mode_horztiming	= LCD_HORZTIMING_HPW_N(96) | 
++			LCD_HORZTIMING_HND1_N(13) | LCD_HORZTIMING_HND2_N(51),
++		.mode_verttiming	= LCD_VERTTIMING_VPW_N(2) | 
++			LCD_VERTTIMING_VND1_N(11) | LCD_VERTTIMING_VND2_N(32),
++		.mode_clkcontrol	= 0x00000000, /* /4=24Mhz */
++		.mode_pwmdiv		= 0x8000063f,
++		.mode_pwmhi		= 0x03400000,
++		.mode_outmask	= 0x00fcfcfc,
++		.mode_fifoctrl	= 0x2f2f2f2f,
++		.mode_toyclksrc	= 0x00000004, /* AUXPLL directly */
++		.mode_backlight	= 0x00000000,
++		.mode_auxpll		= 8, /* 96MHz AUXPLL */
++		.device_init		= board_au1200fb_panel_init,
++		.device_shutdown	= board_au1200fb_panel_shutdown,
++		640, 480,
++		640, 480,
++	},
++
++	[7] = { /* Sharp 320x240 TFT */
++		.name = "Sharp_320x240_TFT",
++		.monspecs = {
++			.modedb = NULL,
++			.modedb_len = 0,
++			.hfmin = 12500,
++			.hfmax = 20000,
++			.vfmin = 38,
++			.vfmax = 81,
++			.dclkmin = 4500000,
++			.dclkmax = 6800000,
++			.input = FB_DISP_RGB,
++		},
++		.mode_screen		= LCD_SCREEN_SX_N(320) | 
++			LCD_SCREEN_SY_N(240),
++		.mode_horztiming	= LCD_HORZTIMING_HPW_N(60) | 
++			LCD_HORZTIMING_HND1_N(13) | LCD_HORZTIMING_HND2_N(2),
++		.mode_verttiming	= LCD_VERTTIMING_VPW_N(2) | 
++			LCD_VERTTIMING_VND1_N(2) | LCD_VERTTIMING_VND2_N(5),
++		.mode_clkcontrol	= LCD_CLKCONTROL_PCD_N(7), /*16=6Mhz*/
++		.mode_pwmdiv		= 0x8000063f,
++		.mode_pwmhi		= 0x03400000,
++		.mode_outmask	= 0x00fcfcfc,
++		.mode_fifoctrl	= 0x2f2f2f2f,
++		.mode_toyclksrc	= 0x00000004, /* AUXPLL directly */
++		.mode_backlight	= 0x00000000,
++		.mode_auxpll		= 8, /* 96MHz AUXPLL */
++		.device_init		= board_au1200fb_panel_init,
++		.device_shutdown	= board_au1200fb_panel_shutdown,
++		320, 320,
++		240, 240,
++	},
++
++	[8] = { /* Toppoly TD070WGCB2 7" 856x480 TFT */
++		.name = "Toppoly_TD070WGCB2",
++		.monspecs = {
++			.modedb = NULL,
++			.modedb_len = 0,
++			.hfmin = 30000,	
++			.hfmax = 70000, 
++			.vfmin = 60, 
++			.vfmax = 60, 
++			.dclkmin = 6000000, 
++			.dclkmax = 28000000, 
++			.input = FB_DISP_RGB,
++		},
++		.mode_screen		= LCD_SCREEN_SX_N(856) | 
++			LCD_SCREEN_SY_N(480),
++		.mode_horztiming	= LCD_HORZTIMING_HND2_N(43) | 
++			LCD_HORZTIMING_HND1_N(43) | LCD_HORZTIMING_HPW_N(114),
++		.mode_verttiming	= LCD_VERTTIMING_VND2_N(20) | 
++			LCD_VERTTIMING_VND1_N(21) | LCD_VERTTIMING_VPW_N(4),
++		.mode_clkcontrol	= 0x00020001, /* /4=24Mhz */
++		.mode_pwmdiv		= 0x8000063f,
++		.mode_pwmhi		= 0x03400000,
++		.mode_outmask	= 0x00fcfcfc,
++		.mode_fifoctrl	= 0x2f2f2f2f,
++		.mode_toyclksrc	= 0x00000004, /* AUXPLL directly */
++		.mode_backlight	= 0x00000000,
++		.mode_auxpll		= 8, /* 96MHz AUXPLL */
++		.device_init		= board_au1200fb_panel_init,
++		.device_shutdown	= board_au1200fb_panel_shutdown,
++		856, 856,
++		480, 480,
++	},
++};
++
++#define NUM_PANELS (sizeof(known_lcd_panels) / sizeof(struct panel_settings))
++
++/********************************************************************/
++
++static int set_brightness(unsigned int brightness)
++{
++	unsigned int hi1, divider;
++
++	/* limit brightness pwm duty to >= 30/1600 */
++	if (brightness < 30) {
++		brightness = 30;
++	}
++	divider = (lcd->pwmdiv & 0x3FFFF) + 1;
++	hi1 = (lcd->pwmhi >> 16) + 1;
++	hi1 = (((brightness & 0xFF)+1) * divider >> 8);
++	lcd->pwmhi &= 0xFFFF;
++	lcd->pwmhi |= (hi1 << 16);
++
++	return brightness;
++}
++
++static int
++winbpp (unsigned int winctrl1)
++{
++	/* how many bits are needed for each pixel format */
++	switch (winctrl1 & LCD_WINCTRL1_FRM)
++	{
++		case LCD_WINCTRL1_FRM_1BPP: return 1; break;
++		case LCD_WINCTRL1_FRM_2BPP: return 2; break;
++		case LCD_WINCTRL1_FRM_4BPP: return 4; break;
++		case LCD_WINCTRL1_FRM_8BPP: return 8; break;
++		case LCD_WINCTRL1_FRM_12BPP: return 16; break;
++		case LCD_WINCTRL1_FRM_16BPP655: return 16; break;
++		case LCD_WINCTRL1_FRM_16BPP565: return 16; break;
++		case LCD_WINCTRL1_FRM_16BPP556: return 16; break;
++		case LCD_WINCTRL1_FRM_16BPPI1555: return 16; break;
++		case LCD_WINCTRL1_FRM_16BPPI5551: return 16; break;
++		case LCD_WINCTRL1_FRM_16BPPA1555: return 16; break;
++		case LCD_WINCTRL1_FRM_16BPPA5551: return 16; break;
++		case LCD_WINCTRL1_FRM_24BPP: return 32; break;
++		case LCD_WINCTRL1_FRM_32BPP: return 32; break;
++		default: return 0; break;
++	}
++}
++
++static int
++fbinfo2index (struct fb_info *fb_info)
++{
++	int i;
++	for (i = 0; i < CONFIG_FB_AU1200_DEVS; ++i)
++	{
++		if (fb_info == (struct fb_info *)(&_au1200fb_devices[i].fb_info))
++			return i;
++	}
++	printk("au1200fb: ERROR: fbinfo2index failed!\n");
++	return -1;
++}
++
++static int au1200_setlocation (struct au1200fb_device *fbdev, int plane, int xpos, int ypos)
++{
++	uint32 winctrl0, winctrl1, winenable, fb_offset = 0;
++	int xsz, ysz;
++
++	/* FIX!!! NOT CHECKING FOR COMPLETE OFFSCREEN YET */
++
++	winctrl0 = lcd->window[plane].winctrl0;
++	winctrl1 = lcd->window[plane].winctrl1;
++	winctrl0 &= (LCD_WINCTRL0_A | LCD_WINCTRL0_AEN);
++	winctrl1 &= ~(LCD_WINCTRL1_SZX | LCD_WINCTRL1_SZY);
++
++	/* Check for off-screen adjustments */
++	xsz = win->w[plane].xres;
++	ysz = win->w[plane].yres;
++	if ((xpos + win->w[plane].xres) > panel->Xres)
++	{
++		/* Off-screen to the right */
++		xsz = panel->Xres - xpos; /* off by 1 ??? */
++		/*printk("off screen right\n");*/
++	}
++
++	if ((ypos + win->w[plane].yres) > panel->Yres)
++	{
++		/* Off-screen to the bottom */
++		ysz = panel->Yres - ypos; /* off by 1 ??? */
++		/*printk("off screen bottom\n");*/
++	}
++
++	if (xpos < 0)
++	{
++		/* Off-screen to the left */
++		xsz = win->w[plane].xres + xpos;
++		fb_offset += (((0 - xpos) * winbpp(lcd->window[plane].winctrl1))/8);
++		xpos = 0;
++		/*printk("off screen left\n");*/
++	}
++
++	if (ypos < 0)
++	{
++		/* Off-screen to the top */
++		ysz = win->w[plane].yres + ypos;
++		/* fixme: fb_offset += ((0-ypos)*fb_pars[plane].line_length); */
++		ypos = 0;
++		/*printk("off screen top\n");*/
++	}
++
++	/* record settings */
++	win->w[plane].xpos = xpos;
++	win->w[plane].ypos = ypos;
++
++	xsz -= 1;
++	ysz -= 1;
++	winctrl0 |= (xpos << 21);
++	winctrl0 |= (ypos << 10);
++	winctrl1 |= (xsz << 11);
++	winctrl1 |= (ysz << 0);
++
++	/* Disable the window while making changes, then restore WINEN */
++	winenable = lcd->winenable & (1 << plane);
++	au_sync();
++	lcd->winenable &= ~(1 << plane);
++	lcd->window[plane].winctrl0 = winctrl0;
++	lcd->window[plane].winctrl1 = winctrl1;
++	lcd->window[plane].winbuf0 =
++	lcd->window[plane].winbuf1 = fbdev->fb_phys;
++	lcd->window[plane].winbufctrl = 0; /* select winbuf0 */
++	lcd->winenable |= winenable;
++	au_sync();
++
++	return 0;
++}
++
++static void au1200_setpanel (struct panel_settings *newpanel)
++{
++	/*
++	 * Perform global setup/init of LCD controller
++	 */
++	uint32 winenable;
++
++	/* Make sure all windows disabled */
++	winenable = lcd->winenable;
++	lcd->winenable = 0;
++	au_sync();
++	/*
++	 * Ensure everything is disabled before reconfiguring
++	 */
++	if (lcd->screen & LCD_SCREEN_SEN)
++	{
++		/* Wait for vertical sync period */
++		lcd->intstatus = LCD_INT_SS;
++		while ((lcd->intstatus & LCD_INT_SS) == 0) {
++			au_sync();
++		}
++		
++		lcd->screen &= ~LCD_SCREEN_SEN;	/*disable the controller*/
++		
++		do
++		{
++			lcd->intstatus = lcd->intstatus; /*clear interrupts*/
++			au_sync();
++		}
++		/*wait for controller to shut down*/
++		while ((lcd->intstatus & LCD_INT_SD) == 0);
++		
++		/* Call shutdown of current panel (if up) */
++		/* this must occur last, because if an external clock is driving
++		    the controller, the clock cannot be turned off before first
++			shutting down the controller.
++		 */
++		if (panel->device_shutdown != NULL) panel->device_shutdown();
++	}
++
++	/* Newpanel == NULL indicates a shutdown operation only */
++	if (newpanel == NULL)
++		return;
++
++	panel = newpanel;
++	
++	printk("Panel(%s), %dx%d\n", panel->name, panel->Xres, panel->Yres);
++
++	/*
++	 * Setup clocking if internal LCD clock source (assumes sys_auxpll valid)
++	 */
++	if (!(panel->mode_clkcontrol & LCD_CLKCONTROL_EXT))
++	{
++		uint32 sys_clksrc;
++		au_writel(panel->mode_auxpll, SYS_AUXPLL);
++		sys_clksrc = au_readl(SYS_CLKSRC) & ~0x0000001f; 
++		sys_clksrc |= panel->mode_toyclksrc;
++		au_writel(sys_clksrc, SYS_CLKSRC);
++	}
++
++	/*
++	 * Configure panel timings
++	 */
++	lcd->screen = panel->mode_screen;
++	lcd->horztiming = panel->mode_horztiming;
++	lcd->verttiming = panel->mode_verttiming;
++	lcd->clkcontrol = panel->mode_clkcontrol;
++	lcd->pwmdiv = panel->mode_pwmdiv;
++	lcd->pwmhi = panel->mode_pwmhi;
++	lcd->outmask = panel->mode_outmask;
++	lcd->fifoctrl = panel->mode_fifoctrl;
++	au_sync();
++
++	/* fixme: Check window settings to make sure still valid 
++	 * for new geometry */
++#if 0
++	au1200_setlocation(fbdev, 0, win->w[0].xpos, win->w[0].ypos);
++	au1200_setlocation(fbdev, 1, win->w[1].xpos, win->w[1].ypos);
++	au1200_setlocation(fbdev, 2, win->w[2].xpos, win->w[2].ypos);
++	au1200_setlocation(fbdev, 3, win->w[3].xpos, win->w[3].ypos);
++#endif
++	lcd->winenable = winenable;
++
++	/*
++	 * Re-enable screen now that it is configured
++	 */
++	lcd->screen |= LCD_SCREEN_SEN;
++	au_sync();
++
++	/* Call init of panel */
++	if (panel->device_init != NULL) panel->device_init();
++
++	/* FIX!!!! not appropriate on panel change!!! Global setup/init */
++	lcd->intenable = 0;
++	lcd->intstatus = ~0;
++	lcd->backcolor = win->mode_backcolor;
++
++	/* Setup Color Key - FIX!!! */
++	lcd->colorkey = win->mode_colorkey;
++	lcd->colorkeymsk = win->mode_colorkeymsk;
++
++	/* Setup HWCursor - FIX!!! Need to support this eventually */
++	lcd->hwc.cursorctrl = 0;
++	lcd->hwc.cursorpos = 0;
++	lcd->hwc.cursorcolor0 = 0;
++	lcd->hwc.cursorcolor1 = 0;
++	lcd->hwc.cursorcolor2 = 0;
++	lcd->hwc.cursorcolor3 = 0;
++
++
++#if 0
++#define D(X) printk("%25s: %08X\n", #X, X)
++	D(lcd->screen);
++	D(lcd->horztiming);
++	D(lcd->verttiming);
++	D(lcd->clkcontrol);
++	D(lcd->pwmdiv);
++	D(lcd->pwmhi);
++	D(lcd->outmask);
++	D(lcd->fifoctrl);
++	D(lcd->window[0].winctrl0);
++	D(lcd->window[0].winctrl1);
++	D(lcd->window[0].winctrl2);
++	D(lcd->window[0].winbuf0);
++	D(lcd->window[0].winbuf1);
++	D(lcd->window[0].winbufctrl);
++	D(lcd->window[1].winctrl0);
++	D(lcd->window[1].winctrl1);
++	D(lcd->window[1].winctrl2);
++	D(lcd->window[1].winbuf0);
++	D(lcd->window[1].winbuf1);
++	D(lcd->window[1].winbufctrl);
++	D(lcd->window[2].winctrl0);
++	D(lcd->window[2].winctrl1);
++	D(lcd->window[2].winctrl2);
++	D(lcd->window[2].winbuf0);
++	D(lcd->window[2].winbuf1);
++	D(lcd->window[2].winbufctrl);
++	D(lcd->window[3].winctrl0);
++	D(lcd->window[3].winctrl1);
++	D(lcd->window[3].winctrl2);
++	D(lcd->window[3].winbuf0);
++	D(lcd->window[3].winbuf1);
++	D(lcd->window[3].winbufctrl);
++	D(lcd->winenable);
++	D(lcd->intenable);
++	D(lcd->intstatus);
++	D(lcd->backcolor);
++	D(lcd->winenable);
++	D(lcd->colorkey);
++    D(lcd->colorkeymsk);
++	D(lcd->hwc.cursorctrl);
++	D(lcd->hwc.cursorpos);
++	D(lcd->hwc.cursorcolor0);
++	D(lcd->hwc.cursorcolor1);
++	D(lcd->hwc.cursorcolor2);
++	D(lcd->hwc.cursorcolor3);
++#endif
++}
++
++static void au1200_setmode(struct au1200fb_device *fbdev)
++{
++	int plane = fbdev->plane;
++	/* Window/plane setup */
++	lcd->window[plane].winctrl1 = ( 0
++		| LCD_WINCTRL1_PRI_N(plane)
++		| win->w[plane].mode_winctrl1 /* FRM,CCO,PO,PIPE */
++		) ;
++
++	au1200_setlocation(fbdev, plane, win->w[plane].xpos, win->w[plane].ypos);
++
++	lcd->window[plane].winctrl2 = ( 0
++		| LCD_WINCTRL2_CKMODE_00
++		| LCD_WINCTRL2_DBM
++		| LCD_WINCTRL2_BX_N( fbdev->fb_info.fix.line_length)
++		| LCD_WINCTRL2_SCX_1
++		| LCD_WINCTRL2_SCY_1
++		) ;
++	lcd->winenable |= win->w[plane].mode_winenable;
++	au_sync();
++}
++
++
++/* Inline helpers */
++
++/*#define panel_is_dual(panel)  ((panel->mode_screen & LCD_SCREEN_PT) == LCD_SCREEN_PT_010)*/
++/*#define panel_is_active(panel)((panel->mode_screen & LCD_SCREEN_PT) == LCD_SCREEN_PT_010)*/
++
++#define panel_is_color(panel) ((panel->mode_screen & LCD_SCREEN_PT) <= LCD_SCREEN_PT_CDSTN)
++
++/* Bitfields format supported by the controller. */
++struct fb_bitfield rgb_bitfields[][4] = 
++{
++  	/*     Red, 	   Green, 	 Blue, 	     Transp   */
++	[LCD_WINCTRL1_FRM_16BPP655 >> 25] =
++		{ { 10, 6, 0 }, { 5, 5, 0 }, { 0, 5, 0 }, { 0, 0, 0 } },
++
++	[LCD_WINCTRL1_FRM_16BPP565 >> 25] =
++		{ { 11, 5, 0 }, { 5, 6, 0 }, { 0, 5, 0 }, { 0, 0, 0 } },
++
++	[LCD_WINCTRL1_FRM_16BPP556 >> 25] =
++		{ { 11, 5, 0 }, { 6, 5, 0 }, { 0, 6, 0 }, { 0, 0, 0 } },
++
++	[LCD_WINCTRL1_FRM_16BPPI1555 >> 25] =
++		{ { 10, 5, 0 }, { 5, 5, 0 }, { 0, 5, 0 }, { 0, 0, 0 } },
++
++	[LCD_WINCTRL1_FRM_16BPPI5551 >> 25] =
++		{ { 11, 5, 0 }, { 6, 5, 0 }, { 1, 5, 0 }, { 0, 0, 0 } },
++
++	[LCD_WINCTRL1_FRM_16BPPA1555 >> 25] =
++		{ { 10, 5, 0 }, { 5, 5, 0 }, { 0, 5, 0 }, { 15, 1, 0 } },
++
++	[LCD_WINCTRL1_FRM_16BPPA5551 >> 25] =
++		{ { 11, 5, 0 }, { 6, 5, 0 }, { 1, 5, 0 }, { 0, 1, 0 } },
++
++	[LCD_WINCTRL1_FRM_24BPP >> 25] =
++		{ { 16, 8, 0 }, { 8, 8, 0 }, { 0, 8, 0 }, { 0, 0, 0 } },
++
++	[LCD_WINCTRL1_FRM_32BPP >> 25] =
++		{ { 16, 8, 0 }, { 8, 8, 0 }, { 0, 8, 0 }, { 24, 0, 0 } },
++};
++
++/*-------------------------------------------------------------------------*/
++
++/* Helpers */
++	
++static void 
++au1200fb_update_fbinfo(struct fb_info *fbi)
++{
++	/* FIX!!!! This also needs to take the window pixel format into account!!! */
++
++	/* Update var-dependent FB info */
++	if (panel_is_color(panel)) {
++		if (fbi->var.bits_per_pixel <= 8) {
++			/* palettized */
++			fbi->fix.visual = FB_VISUAL_PSEUDOCOLOR;
++			fbi->fix.line_length = fbi->var.xres_virtual / 
++				(8/fbi->var.bits_per_pixel);
++		} else {
++			/* non-palettized */
++			fbi->fix.visual = FB_VISUAL_TRUECOLOR;
++			fbi->fix.line_length = fbi->var.xres_virtual * (fbi->var.bits_per_pixel / 8); 
++		}
++	} else {
++		/* mono FIX!!! mono 8 and 4 bits */
++		fbi->fix.visual = FB_VISUAL_MONO10;
++		fbi->fix.line_length = fbi->var.xres_virtual / 8;
++	}
++
++	fbi->screen_size = fbi->fix.line_length * fbi->var.yres_virtual;
++	print_dbg("line length: %d\n", fbi->fix.line_length);
++	print_dbg("bits_per_pixel: %d\n", fbi->var.bits_per_pixel);
++}
++
++/*-------------------------------------------------------------------------*/
++
++/* AU1200 framebuffer driver */
++
++int au1200fb_fb_open(struct fb_info *fbi, int user)
++{
++	return 0;
++}
++
++int au1200fb_fb_release(struct fb_info *fbi, int user)
++{
++	return 0;
++}
++
++/* fb_check_var
++ * Validate var settings with hardware restrictions and modify it if necessary 
++ */
++int au1200fb_fb_check_var(struct fb_var_screeninfo *var, struct fb_info *fbi)
++{
++	struct au1200fb_device *fbdev = (struct au1200fb_device *)fbi;
++	u32 pixclock;
++	int screen_size, plane;
++
++	plane = fbdev->plane;
++
++	/* Make sure that the mode respect all LCD controller and 
++	 * panel restrictions. */
++	var->xres = win->w[plane].xres;
++	var->yres = win->w[plane].yres;
++	
++	/* No need for virtual resolution support */
++	var->xres_virtual = var->xres;
++	var->yres_virtual = var->yres;
++
++	var->bits_per_pixel = winbpp(win->w[plane].mode_winctrl1);
++
++	screen_size = var->xres_virtual * var->yres_virtual;
++	if (var->bits_per_pixel > 8) screen_size *= (var->bits_per_pixel / 8);  
++	else screen_size /= (8/var->bits_per_pixel);
++
++	if (fbdev->fb_len < screen_size)
++		return -EINVAL; /* Virtual screen is to big, abort */
++
++	/* FIX!!!! what are the implicaitons of ignoring this for windows ??? */
++	/* The max LCD clock is fixed to 48MHz (value of AUX_CLK). The pixel
++	 * clock can only be obtain by dividing this value by an even integer.
++	 * Fallback to a slower pixel clock if necessary. */
++	pixclock = max((u32)(PICOS2KHZ(var->pixclock) * 1000), fbi->monspecs.dclkmin);
++	pixclock = min(pixclock, min(fbi->monspecs.dclkmax, (u32)AU1200_LCD_MAX_CLK/2));
++
++	if (AU1200_LCD_MAX_CLK % pixclock) {
++		int diff = AU1200_LCD_MAX_CLK % pixclock;
++		pixclock -= diff;
++	}
++
++	var->pixclock = KHZ2PICOS(pixclock/1000);
++#if 0
++	if (!panel_is_active(panel)) {
++		int pcd = AU1200_LCD_MAX_CLK / (pixclock * 2) - 1;
++
++		if (!panel_is_color(panel) 
++			&& (panel->control_base & LCD_CONTROL_MPI) && (pcd < 3)) {
++			/* STN 8bit mono panel support is up to 6MHz pixclock */
++			var->pixclock = KHZ2PICOS(6000);
++		} else if (!pcd) {
++			/* Other STN panel support is up to 12MHz  */
++			var->pixclock = KHZ2PICOS(12000);
++		}
++	}
++#endif
++	/* Set bitfield accordingly */
++	switch (var->bits_per_pixel) {
++		case 16:
++		{
++			/* 16bpp True color.  
++			 * These must be set to MATCH WINCTRL[FORM] */
++			int idx;
++			idx = (win->w[0].mode_winctrl1 & LCD_WINCTRL1_FRM) >> 25;
++			var->red    = rgb_bitfields[idx][0];
++			var->green  = rgb_bitfields[idx][1];
++			var->blue   = rgb_bitfields[idx][2];
++			var->transp = rgb_bitfields[idx][3];
++			break;
++		}
++
++		case 32:
++		{
++			/* 32bpp True color.  
++			 * These must be set to MATCH WINCTRL[FORM] */
++			int idx;
++			idx = (win->w[0].mode_winctrl1 & LCD_WINCTRL1_FRM) >> 25;
++			var->red    = rgb_bitfields[idx][0];
++			var->green  = rgb_bitfields[idx][1];
++			var->blue   = rgb_bitfields[idx][2];
++			var->transp = rgb_bitfields[idx][3];
++			break;
++		}
++		default:
++			print_dbg("Unsupported depth %dbpp", var->bits_per_pixel);
++			return -EINVAL;
++	}
++
++	return 0;
++}
++
++/* fb_set_par 
++ * Set hardware with var settings. This will enable the controller with a 
++ * specific mode, normally validated with the fb_check_var method
++ */
++int au1200fb_fb_set_par(struct fb_info *fbi)
++{
++	struct au1200fb_device *fbdev = (struct au1200fb_device *)fbi;
++
++	au1200fb_update_fbinfo(fbi);
++	au1200_setmode(fbdev);
++
++	return 0;
++}
++
++/* fb_setcolreg
++ * Set color in LCD palette.
++ */
++int au1200fb_fb_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue, unsigned transp, struct fb_info *fbi)
++{
++	u32 *palette = lcd->palette;
++	u32 value;
++
++	if (regno > (AU1200_LCD_NBR_PALETTE_ENTRIES - 1))
++		return -EINVAL;
++
++	if (fbi->var.grayscale) {
++		/* Convert color to grayscale */
++		red = green = blue = 
++			(19595 * red + 38470 * green + 7471 * blue) >> 16;
++	}
++
++	if (fbi->fix.visual == FB_VISUAL_TRUECOLOR) {
++		/* Place color in the pseudopalette */
++		if (regno > 16)
++			return -EINVAL;
++   
++		palette = (u32*)fbi->pseudo_palette;
++
++		red   >>= (16 - fbi->var.red.length);
++		green >>= (16 - fbi->var.green.length);
++		blue  >>= (16 - fbi->var.blue.length);
++	
++		value = (red   << fbi->var.red.offset) 	|	
++			(green << fbi->var.green.offset)|
++			(blue  << fbi->var.blue.offset);
++		value &= 0xFFFF;
++
++	} else if (1 /*FIX!!! panel_is_active(fbdev->panel)*/) {
++		/* COLOR TFT PALLETTIZED (use RGB 565) */
++		value = (red & 0xF800)|((green >> 5) & 
++				0x07E0)|((blue >> 11) & 0x001F);
++		value &= 0xFFFF;
++
++	} else if (0 /*panel_is_color(fbdev->panel)*/) {
++		/* COLOR STN MODE */
++		value = 0x1234;
++		value &= 0xFFF;
++	} else {
++		/* MONOCHROME MODE */
++		value = (green >> 12) & 0x000F;
++		value &= 0xF;
++	}
++
++	palette[regno] = value;
++	
++	return 0;
++}
++
++/* fb_blank
++ * Blank the screen. Depending on the mode, the screen will be
++ * activated with the backlight color, or desactivated
++ */
++int au1200fb_fb_blank(int blank_mode, struct fb_info *fbi)
++{
++	/* Short-circuit screen blanking */
++	if (noblanking)
++		return 0;
++
++	switch (blank_mode) {
++
++	case VESA_NO_BLANKING:
++		/* printk("turn on panel\n"); */
++		au1200_setpanel(panel);
++		break;
++
++	case VESA_VSYNC_SUSPEND:
++	case VESA_HSYNC_SUSPEND:
++	case VESA_POWERDOWN:
++		/* printk("turn off panel\n"); */
++		au1200_setpanel(NULL);
++		break;
++	default: 
++		break;
++
++	}
++	return 0;
++}
++
++/* fb_mmap
++ * Map video memory in user space. We don't use the generic fb_mmap 
++ * method mainly to allow the use of the TLB streaming flag (CCA=6)
++ */
++int au1200fb_fb_mmap(struct fb_info *fbi, struct file *file, struct vm_area_struct *vma)
++{
++	unsigned int len;
++	unsigned long start=0, off;
++	struct au1200fb_device *fbdev = (struct au1200fb_device *)fbi;
++
++#ifdef CONFIG_PM
++	au1xxx_pm_access(LCD_pm_dev);
++#endif
++
++	if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT)) {
++		return -EINVAL;
++	}
++    
++	start = fbdev->fb_phys & PAGE_MASK;
++	len = PAGE_ALIGN((start & ~PAGE_MASK) + fbdev->fb_len);
++
++	off = vma->vm_pgoff << PAGE_SHIFT;
++
++	if ((vma->vm_end - vma->vm_start + off) > len) {
++		return -EINVAL;
++	}
++
++	off += start;
++	vma->vm_pgoff = off >> PAGE_SHIFT;
++
++	vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
++	pgprot_val(vma->vm_page_prot) |= _CACHE_MASK; /* CCA=7 */
++
++	vma->vm_flags |= VM_IO;
++   
++	return io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT,
++				  vma->vm_end - vma->vm_start,
++				  vma->vm_page_prot);
++
++	return 0;
++}
++
++void set_global(u_int cmd, au1200_lcd_global_regs_t *pdata) {
++
++	unsigned int hi1, divider;
++	
++	/* SCREEN_SIZE: user cannot reset size, must switch panel choice */
++	
++	if (pdata->flags & SCREEN_BACKCOLOR)
++		lcd->backcolor = pdata->backcolor;
++	
++	if (pdata->flags & SCREEN_BRIGHTNESS) {
++	
++		// limit brightness pwm duty to >= 30/1600
++		if (pdata->brightness < 30) {
++			pdata->brightness = 30;
++		}
++		divider = (lcd->pwmdiv & 0x3FFFF) + 1;
++		hi1 = (lcd->pwmhi >> 16) + 1;
++		hi1 = (((pdata->brightness & 0xFF)+1) * divider >> 8);
++		lcd->pwmhi &= 0xFFFF;
++		lcd->pwmhi |= (hi1 << 16);
++	}
++	
++	if (pdata->flags & SCREEN_COLORKEY)
++		lcd->colorkey = pdata->colorkey;
++	
++	if (pdata->flags & SCREEN_MASK)
++		lcd->colorkeymsk = pdata->mask;
++	au_sync();
++}
++
++void get_global(u_int cmd, au1200_lcd_global_regs_t *pdata) {
++	unsigned int hi1, divider;
++	
++	pdata->xsize = ((lcd->screen & LCD_SCREEN_SX) >> 19) + 1;
++	pdata->ysize = ((lcd->screen & LCD_SCREEN_SY) >> 8) + 1;
++	
++	pdata->backcolor = lcd->backcolor;
++	pdata->colorkey = lcd->colorkey;
++	pdata->mask = lcd->colorkeymsk;
++	
++	// brightness
++	hi1 = (lcd->pwmhi >> 16) + 1;
++	divider = (lcd->pwmdiv & 0x3FFFF) + 1;
++	pdata->brightness = ((hi1 << 8) / divider) - 1;
++	au_sync();
++}
++
++void print_global(au1200_lcd_global_regs_t *pdata) {
++
++	printk("pdata->xsize %x\n", pdata->xsize);
++	printk("pdata->ysize %x\n", pdata->ysize);
++	printk("pdata->backcolor %x\n", pdata->backcolor);
++	printk("pdata->brightness %x\n", pdata->brightness);
++	printk("pdata->colorkey %x\n", pdata->colorkey);
++	printk("pdata->mask %x\n", pdata->mask);
++}
++
++void set_window(unsigned int plane, au1200_lcd_window_regs_t *pdata) {
++	
++	unsigned int val, bpp;
++	
++	/* Window control register 0 */
++	if (pdata->flags & WIN_POSITION) {
++		val = lcd->window[plane].winctrl0 & ~(LCD_WINCTRL0_OX | 
++				LCD_WINCTRL0_OY);
++		val |= ((pdata->xpos << 21) & LCD_WINCTRL0_OX);
++		val |= ((pdata->ypos << 10) & LCD_WINCTRL0_OY);
++		lcd->window[plane].winctrl0 = val;
++	}
++	if (pdata->flags & WIN_ALPHA_COLOR) {
++		val = lcd->window[plane].winctrl0 & ~(LCD_WINCTRL0_A);
++		val |= ((pdata->alpha_color << 2) & LCD_WINCTRL0_A);
++		lcd->window[plane].winctrl0 = val;
++	}
++	if (pdata->flags & WIN_ALPHA_MODE) {
++		val = lcd->window[plane].winctrl0 & ~(LCD_WINCTRL0_AEN);
++		val |= ((pdata->alpha_mode << 1) & LCD_WINCTRL0_AEN);
++		lcd->window[plane].winctrl0 = val;
++	}
++	
++	/* Window control register 1 */
++	if (pdata->flags & WIN_PRIORITY) {
++		val = lcd->window[plane].winctrl1 & ~(LCD_WINCTRL1_PRI);
++		val |= ((pdata->priority << 30) & LCD_WINCTRL1_PRI);
++		lcd->window[plane].winctrl1 = val;
++	}
++	if (pdata->flags & WIN_CHANNEL) {
++		val = lcd->window[plane].winctrl1 & ~(LCD_WINCTRL1_PIPE);
++		val |= ((pdata->channel << 29) & LCD_WINCTRL1_PIPE);
++		lcd->window[plane].winctrl1 = val;
++	}
++	if (pdata->flags & WIN_BUFFER_FORMAT) {
++		val = lcd->window[plane].winctrl1 & ~(LCD_WINCTRL1_FRM);
++		val |= ((pdata->buffer_format << 25) & LCD_WINCTRL1_FRM);
++		lcd->window[plane].winctrl1 = val;
++	}
++	if (pdata->flags & WIN_COLOR_ORDER) {
++		val = lcd->window[plane].winctrl1 & ~(LCD_WINCTRL1_CCO);
++		val |= ((pdata->color_order << 24) & LCD_WINCTRL1_CCO);
++		lcd->window[plane].winctrl1 = val;
++	}
++	if (pdata->flags & WIN_PIXEL_ORDER) {
++		val = lcd->window[plane].winctrl1 & ~(LCD_WINCTRL1_PO);
++		val |= ((pdata->pixel_order << 22) & LCD_WINCTRL1_PO);
++		lcd->window[plane].winctrl1 = val;
++	}
++	if (pdata->flags & WIN_SIZE) {
++		val = lcd->window[plane].winctrl1 & ~(LCD_WINCTRL1_SZX | 
++				LCD_WINCTRL1_SZY);
++		val |= (((pdata->xsize << 11) - 1) & LCD_WINCTRL1_SZX);
++		val |= (((pdata->ysize) - 1) & LCD_WINCTRL1_SZY);
++		lcd->window[plane].winctrl1 = val;
++		/* program buffer line width */
++		bpp = winbpp(val) / 8;
++		val = lcd->window[plane].winctrl2 & ~(LCD_WINCTRL2_BX);
++		val |= (((pdata->xsize * bpp) << 8) & LCD_WINCTRL2_BX);
++		lcd->window[plane].winctrl2 = val;
++	}
++	
++	/* Window control register 2 */
++	if (pdata->flags & WIN_COLORKEY_MODE) {
++		val = lcd->window[plane].winctrl2 & ~(LCD_WINCTRL2_CKMODE);
++		val |= ((pdata->colorkey_mode << 24) & LCD_WINCTRL2_CKMODE);
++		lcd->window[plane].winctrl2 = val;
++	}
++	if (pdata->flags & WIN_DOUBLE_BUFFER_MODE) {
++		val = lcd->window[plane].winctrl2 & ~(LCD_WINCTRL2_DBM);
++		val |= ((pdata->double_buffer_mode << 23) & LCD_WINCTRL2_DBM);
++		lcd->window[plane].winctrl2 = val;
++	}
++	if (pdata->flags & WIN_RAM_ARRAY_MODE) {
++		val = lcd->window[plane].winctrl2 & ~(LCD_WINCTRL2_RAM);
++		val |= ((pdata->ram_array_mode << 21) & LCD_WINCTRL2_RAM);
++		lcd->window[plane].winctrl2 = val;
++	}
++	
++	/* Buffer line width programmed with WIN_SIZE */
++	
++	if (pdata->flags & WIN_BUFFER_SCALE) {
++		val = lcd->window[plane].winctrl2 & ~(LCD_WINCTRL2_SCX | 
++				LCD_WINCTRL2_SCY);
++		val |= ((pdata->xsize << 11) & LCD_WINCTRL2_SCX);
++		val |= ((pdata->ysize) & LCD_WINCTRL2_SCY);
++		lcd->window[plane].winctrl2 = val;
++	}
++	
++	if (pdata->flags & WIN_ENABLE) {
++		val = lcd->winenable;
++		val &= ~(1<<plane);
++		val |= (pdata->enable & 1) << plane;
++		lcd->winenable = val;
++	}
++	au_sync();
++}
++
++void get_window(unsigned int plane, au1200_lcd_window_regs_t *pdata) {
++
++	/* Window control register 0 */
++	pdata->xpos = (lcd->window[plane].winctrl0 & LCD_WINCTRL0_OX) >> 21;
++	pdata->ypos = (lcd->window[plane].winctrl0 & LCD_WINCTRL0_OY) >> 10;
++	pdata->alpha_color = (lcd->window[plane].winctrl0 & LCD_WINCTRL0_A) >> 2;
++	pdata->alpha_mode = (lcd->window[plane].winctrl0 & LCD_WINCTRL0_AEN) >> 1;
++	
++	/* Window control register 1 */
++	pdata->priority = (lcd->window[plane].winctrl1& LCD_WINCTRL1_PRI) >> 30;
++	pdata->channel = (lcd->window[plane].winctrl1 & LCD_WINCTRL1_PIPE) >> 29;
++	pdata->buffer_format = (lcd->window[plane].winctrl1 & LCD_WINCTRL1_FRM) >> 25;
++	pdata->color_order = (lcd->window[plane].winctrl1 & LCD_WINCTRL1_CCO) >> 24;
++	pdata->pixel_order = (lcd->window[plane].winctrl1 & LCD_WINCTRL1_PO) >> 22;
++	pdata->xsize = ((lcd->window[plane].winctrl1 & LCD_WINCTRL1_SZX) >> 11) + 1;
++	pdata->ysize = (lcd->window[plane].winctrl1 & LCD_WINCTRL1_SZY) + 1;
++	
++	/* Window control register 2 */
++	pdata->colorkey_mode = (lcd->window[plane].winctrl2 & LCD_WINCTRL2_CKMODE) >> 24;
++	pdata->double_buffer_mode = (lcd->window[plane].winctrl2 & LCD_WINCTRL2_DBM) >> 23;
++	pdata->ram_array_mode = (lcd->window[plane].winctrl2 & LCD_WINCTRL2_RAM) >> 21;
++	
++	pdata->enable = (lcd->winenable >> plane) & 1;
++	au_sync();
++}
++
++static int au1200fb_ioctl(struct inode *inode, struct file *file, u_int cmd,
++			  u_long arg, struct fb_info *info)
++{
++	int plane;
++	int val;
++
++#ifdef CONFIG_PM
++	au1xxx_pm_access(LCD_pm_dev);
++#endif
++	
++	plane = fbinfo2index(info);
++	print_dbg("au1200fb: ioctl %d on plane %d\n", cmd, plane);
++	
++	if (cmd == AU1200_LCD_FB_IOCTL) {
++		au1200_lcd_iodata_t iodata;
++	
++		if (copy_from_user(&iodata, (void *) arg, sizeof(au1200_lcd_iodata_t)))
++			return -EFAULT;
++	
++		print_dbg("FB IOCTL called\n");
++	
++		switch (iodata.subcmd)
++		{
++	
++		case AU1200_LCD_SET_SCREEN:
++			print_dbg("AU1200_LCD_SET_SCREEN\n");
++			set_global(cmd, &iodata.global);
++			break;
++	
++		case AU1200_LCD_GET_SCREEN:
++			print_dbg("AU1200_LCD_GET_SCREEN\n");
++			get_global(cmd, &iodata.global);
++			break;
++	
++		case AU1200_LCD_SET_WINDOW:
++			print_dbg("AU1200_LCD_SET_WINDOW\n");
++			set_window(plane, &iodata.window);
++			break;
++	
++		case AU1200_LCD_GET_WINDOW:
++			print_dbg("AU1200_LCD_GET_WINDOW\n");
++			get_window(plane, &iodata.window);
++			break;
++	
++		case AU1200_LCD_SET_PANEL:
++			print_dbg("AU1200_LCD_SET_PANEL\n");
++			if ((iodata.global.panel_choice >= 0) && 
++					(iodata.global.panel_choice < 
++					 NUM_PANELS))
++			{
++				struct panel_settings *newpanel;
++				panel_index = iodata.global.panel_choice;
++				newpanel = &known_lcd_panels[panel_index];
++				au1200_setpanel(newpanel);
++			}
++			break;
++	
++		case AU1200_LCD_GET_PANEL:
++			print_dbg("AU1200_LCD_GET_PANEL\n");
++			iodata.global.panel_choice = panel_index;
++			break;
++	
++		default:
++			return -EINVAL;
++		}
++	
++		val = copy_to_user((void *) arg, &iodata, sizeof(au1200_lcd_iodata_t));
++		if (val) {
++			print_dbg("error: could not copy %d bytes\n", val);
++			return -EFAULT;
++		}
++	}
++	
++return 0;
++}
++
++
++static struct fb_ops au1200fb_fb_ops = 
++{
++	.owner			= THIS_MODULE,
++	.fb_open		= au1200fb_fb_open,
++	.fb_release		= au1200fb_fb_release,
++	.fb_check_var	= au1200fb_fb_check_var,
++	.fb_set_par		= au1200fb_fb_set_par,
++	.fb_setcolreg	= au1200fb_fb_setcolreg,
++	.fb_blank		= au1200fb_fb_blank,
++	.fb_fillrect	= cfb_fillrect,
++	.fb_copyarea	= cfb_copyarea,
++	.fb_imageblit	= cfb_imageblit,
++	.fb_sync		= NULL,
++	.fb_ioctl		= au1200fb_ioctl,
++	.fb_mmap		= au1200fb_fb_mmap,
++};
++
++/*-------------------------------------------------------------------------*/
++
++static irqreturn_t au1200fb_handle_irq(int irq, void* dev_id, struct pt_regs *regs)
++{
++	/* Nothing to do for now, just clear any pending interrupt */
++	lcd->intstatus = lcd->intstatus;
++	au_sync();
++	return IRQ_HANDLED;
++}
++
++/*-------------------------------------------------------------------------*/
++
++/* AU1200 LCD device probe helpers */
++
++static int au1200fb_init_fbinfo(struct au1200fb_device *fbdev)
++{
++	struct fb_info *fbi = &fbdev->fb_info;
++	int bpp;
++	
++	memset(fbi, 0, sizeof(struct fb_info));
++	fbi->fbops = &au1200fb_fb_ops;
++	
++	bpp = winbpp(win->w[fbdev->plane].mode_winctrl1);
++
++	/* Copy monitor specs from panel data */
++	/* fixme: we're setting up LCD controller windows, so these dont give a
++	damn as to what the monitor specs are (the panel itself does, but that
++	isnt done here...so maybe need a generic catchall monitor setting??? */
++	memcpy(&fbi->monspecs, &panel->monspecs, sizeof(struct fb_monspecs));
++
++	/* We first try the user mode passed in argument. If that failed, 
++	 * or if no one has been specified, we default to the first mode of the 
++	 * panel list. Note that after this call, var data will be set */
++	if (!fb_find_mode(&fbi->var, 
++			  fbi, 
++			  NULL, /* drv_info.opt_mode, */
++			  fbi->monspecs.modedb, 
++			  fbi->monspecs.modedb_len,
++			  fbi->monspecs.modedb, 
++			  bpp)) {
++
++		print_err("Cannot find valid mode for panel %s", panel->name);
++		return -EFAULT;
++	}
++
++	fbi->pseudo_palette = kmalloc(sizeof(u32) * 16, GFP_KERNEL);
++	if (!fbi->pseudo_palette) {
++		return -ENOMEM;
++	}
++	memset(fbi->pseudo_palette, 0, sizeof(u32) * 16);
++
++	if (fb_alloc_cmap(&fbi->cmap, AU1200_LCD_NBR_PALETTE_ENTRIES, 0) < 0) {
++		print_err("Fail to allocate colormap (%d entries)",
++			   AU1200_LCD_NBR_PALETTE_ENTRIES);
++		kfree(fbi->pseudo_palette);
++		return -EFAULT;
++	}
++
++	strncpy(fbi->fix.id, "AU1200", sizeof(fbi->fix.id));
++	fbi->fix.smem_start = fbdev->fb_phys;
++	fbi->fix.smem_len = fbdev->fb_len;
++	fbi->fix.type = FB_TYPE_PACKED_PIXELS;
++	fbi->fix.xpanstep = 1;
++	fbi->fix.ypanstep = 1;
++	fbi->fix.mmio_start = 0;
++	fbi->fix.mmio_len = 0;
++	fbi->fix.accel = FB_ACCEL_NONE;
++
++	fbi->screen_base = fbdev->fb_mem;
++
++	au1200fb_update_fbinfo(fbi);
++
++	return 0;
++}
++
++/*-------------------------------------------------------------------------*/
++
++/* AU1200 LCD controller device driver */
++
++int au1200fb_drv_probe(struct device *dev)
++{
++	struct au1200fb_device *fbdev;
++	unsigned long page;
++	int bpp, plane, ret;
++
++	if (!dev)
++		return -EINVAL;
++
++	for (plane = 0; plane < CONFIG_FB_AU1200_DEVS; ++plane)
++	{
++		bpp = winbpp(win->w[plane].mode_winctrl1);
++		if (win->w[plane].xres == 0)
++			win->w[plane].xres = panel->Xres;
++		if (win->w[plane].yres == 0)
++			win->w[plane].yres = panel->Yres;
++
++		fbdev = &_au1200fb_devices[plane];
++		memset((void *)fbdev, 0, sizeof(struct au1200fb_device));
++		fbdev->plane = plane;
++
++		/* Allocate the framebuffer to the maximum screen size */
++		fbdev->fb_len = (win->w[plane].xres * win->w[plane].yres * bpp) / 8;
++
++		fbdev->fb_mem = dma_alloc_noncoherent(dev, 
++				PAGE_ALIGN(fbdev->fb_len), 
++				&fbdev->fb_phys, GFP_KERNEL);
++		if (!fbdev->fb_mem) {
++			print_err("fail to allocate frambuffer (size: %dK))", 
++				  fbdev->fb_len / 1024);
++			return -ENOMEM;
++		}
++
++		/*
++		 * Set page reserved so that mmap will work. This is necessary
++		 * since we'll be remapping normal memory.
++		 */
++		for (page = (unsigned long)fbdev->fb_phys;
++		     page < PAGE_ALIGN((unsigned long)fbdev->fb_phys + 
++			     fbdev->fb_len);
++		     page += PAGE_SIZE) {
++			SetPageReserved(pfn_to_page(page >> PAGE_SHIFT)); /* LCD DMA is NOT coherent on Au1200 */
++		}
++		print_dbg("Framebuffer memory map at %p", fbdev->fb_mem);
++		print_dbg("phys=0x%08x, size=%dK", fbdev->fb_phys, fbdev->fb_len / 1024);
++
++		/* Init FB data */
++		if ((ret = au1200fb_init_fbinfo(fbdev)) < 0)
++			goto failed;
++
++		/* Register new framebuffer */
++		if ((ret = register_framebuffer(&fbdev->fb_info)) < 0) {
++			print_err("cannot register new framebuffer");
++			goto failed;
++		}
++		
++		au1200fb_fb_set_par(&fbdev->fb_info);
++
++#if !defined(CONFIG_FRAMEBUFFER_CONSOLE) && defined(CONFIG_LOGO)
++		if (plane == 0)
++			if (fb_prepare_logo(&fbdev->fb_info, FB_ROTATE_UR)) {
++				/* Start display and show logo on boot */
++				fb_set_cmap(&fbdev->fb_info.cmap, 
++						&fbdev->fb_info);
++
++				fb_show_logo(&fbdev->fb_info, FB_ROTATE_UR);
++			}
++#endif
++	}
++
++	/* Now hook interrupt too */
++	if ((ret = request_irq(AU1200_LCD_INT, au1200fb_handle_irq,
++		 	  SA_INTERRUPT | SA_SHIRQ, "lcd", (void *)dev)) < 0) {
++		print_err("fail to request interrupt line %d (err: %d)",
++			  AU1200_LCD_INT, ret);
++		goto failed;
++	}
++
++	return 0;
++
++failed:
++	/* NOTE: This only does the current plane/window that failed; others are still active */
++	if (fbdev->fb_mem)
++		dma_free_noncoherent(dev, PAGE_ALIGN(fbdev->fb_len), 
++				fbdev->fb_mem, fbdev->fb_phys);
++	if (fbdev->fb_info.cmap.len != 0)
++		fb_dealloc_cmap(&fbdev->fb_info.cmap);
++	if (fbdev->fb_info.pseudo_palette)
++		kfree(fbdev->fb_info.pseudo_palette);
++	if (plane == 0)
++		free_irq(AU1200_LCD_INT, (void*)dev);
++	return ret;
++}
++
++int au1200fb_drv_remove(struct device *dev)
++{
++	struct au1200fb_device *fbdev;
++	int plane;
++
++	if (!dev)
++		return -ENODEV;
++
++	/* Turn off the panel */
++	au1200_setpanel(NULL);
++
++	for (plane = 0; plane < CONFIG_FB_AU1200_DEVS; ++plane)
++	{
++		fbdev = &_au1200fb_devices[plane];
++
++		/* Clean up all probe data */
++		unregister_framebuffer(&fbdev->fb_info);
++		if (fbdev->fb_mem)
++			dma_free_noncoherent(dev, PAGE_ALIGN(fbdev->fb_len), 
++					fbdev->fb_mem, fbdev->fb_phys);
++		if (fbdev->fb_info.cmap.len != 0)
++			fb_dealloc_cmap(&fbdev->fb_info.cmap);
++		if (fbdev->fb_info.pseudo_palette)
++			kfree(fbdev->fb_info.pseudo_palette);
++	}
++
++	free_irq(AU1200_LCD_INT, (void *)dev);
++
++	return 0;
++}
++
++int au1200fb_drv_suspend(struct device *dev, u32 state, u32 level)
++{
++	/* TODO */
++	return 0;
++}
++
++int au1200fb_drv_resume(struct device *dev, u32 level)
++{
++	/* TODO */
++	return 0;
++}
++
++static struct device_driver au1200fb_driver = {
++	.name		= "au1200-lcd",
++	.bus		= &platform_bus_type,
++	.probe		= au1200fb_drv_probe,
++	.remove		= au1200fb_drv_remove,
++#ifdef CONFIG_PM
++	.suspend	= au1200fb_drv_suspend,
++	.resume		= au1200fb_drv_resume,
++#endif
++};
++
++/*-------------------------------------------------------------------------*/
++
++/* Kernel driver */
++
++static void au1200fb_setup(void)
++{
++	char* options = NULL;
++	char* this_opt;
++	int num_panels = ARRAY_SIZE(known_lcd_panels);
++	int panel_idx = -1;
++
++	fb_get_options(DRIVER_NAME, &options);
++
++	if (options) {
++		while ((this_opt = strsep(&options,",")) != NULL) {
++			/* Panel option - can be panel name, 
++			 * "bs" for board-switch, or number/index */
++			if (!strncmp(this_opt, "panel:", 6)) {
++				int i;
++				long int li;
++				char *endptr;
++				this_opt += 6;
++				/* First check for index, which allows 
++				 * to short circuit this mess */
++				li = simple_strtol(this_opt, &endptr, 0);
++				if (*endptr == '\0') {
++					panel_idx = (int)li;
++				}
++				else if (strcmp(this_opt, "bs") == 0) {
++					extern int board_au1200fb_panel(void);
++					panel_idx = board_au1200fb_panel();
++				}
++
++				else
++				for (i = 0; i < num_panels; i++) {
++					if (!strcmp(this_opt, known_lcd_panels[i].name)) {
++						panel_idx = i;
++						break;
++					}
++				}
++
++				if ((panel_idx < 0) || (panel_idx >= num_panels)) {
++						print_warn("Panel %s not supported!", this_opt);
++				}
++				else
++					panel_index = panel_idx;
++			}
++
++			else if (strncmp(this_opt, "nohwcursor", 10) == 0) {
++				nohwcursor = 1;
++			}
++
++			/* Unsupported option */
++			else {
++				print_warn("Unsupported option \"%s\"", this_opt);
++			}
++		}
++	} 
++}
++
++#ifdef CONFIG_PM
++int au1200fb_pm_callback(au1xxx_power_dev_t *dev, 
++		au1xxx_request_t request, void *data) {
++	int retval = -1;
++	unsigned int d = 0;
++	unsigned int brightness = 0;
++
++	if (request == AU1XXX_PM_SLEEP) {
++		board_au1200fb_panel_shutdown();
++	}
++	else if (request == AU1XXX_PM_WAKEUP) {
++		if(dev->prev_state == SLEEP_STATE)
++		{
++			int plane;
++			au1200_setpanel(panel);
++			for (plane = 0; plane < CONFIG_FB_AU1200_DEVS; ++plane) 	{
++				struct au1200fb_device *fbdev;
++				fbdev = &_au1200fb_devices[plane];
++				au1200fb_fb_set_par(&fbdev->fb_info);
++			}
++		}
++
++		d = *((unsigned int*)data);
++		if(d <=10) brightness = 26;
++		else if(d<=20) brightness = 51;
++		else if(d<=30) brightness = 77;
++		else if(d<=40) brightness = 102;
++		else if(d<=50) brightness = 128;
++		else if(d<=60) brightness = 153;
++		else if(d<=70) brightness = 179;
++		else if(d<=80) brightness = 204;
++		else if(d<=90) brightness = 230;
++		else brightness = 255;
++		set_brightness(brightness);
++	}
++	else if (request == AU1XXX_PM_GETSTATUS) {
++		return dev->cur_state;
++	}
++	else if (request == AU1XXX_PM_ACCESS) {
++		if (dev->cur_state != SLEEP_STATE)
++			return retval;
++		else {
++			au1200_setpanel(panel);
++		}
++	}
++	else if (request == AU1XXX_PM_IDLE) {
++	}
++	else if (request == AU1XXX_PM_CLEANUP) {
++	}
++
++	return retval; 
++}
++#endif
++
++int __init au1200fb_init(void)
++{
++	print_info("" DRIVER_DESC "");
++	
++	/* Setup driver with options */
++	au1200fb_setup();
++
++	/* Point to the panel selected */
++	panel = &known_lcd_panels[panel_index];
++	win = &windows[window_index];
++
++	printk(DRIVER_NAME ": Panel %d %s\n", panel_index, panel->name);
++	printk(DRIVER_NAME ": Win %d %s\n", window_index, win->name);
++
++	/* Kickstart the panel, the framebuffers/windows come soon enough */
++	au1200_setpanel(panel);
++
++	#ifdef CONFIG_PM
++	LCD_pm_dev = new_au1xxx_power_device("LCD", &au1200fb_pm_callback, NULL);
++	if ( LCD_pm_dev == NULL)
++		printk(KERN_INFO "Unable to create a power management device entry for the au1200fb.\n");
++	else
++		printk(KERN_INFO "Power management device entry for the au1200fb loaded.\n");
++	#endif
++
++	return driver_register(&au1200fb_driver);
++}
++
++void __exit au1200fb_cleanup(void)
++{
++	driver_unregister(&au1200fb_driver);
++}
++
++module_init(au1200fb_init);
++module_exit(au1200fb_cleanup);
++
++MODULE_DESCRIPTION(DRIVER_DESC);
++MODULE_LICENSE("GPL");
+diff -Naur linux-2.6.15.orig/drivers/video/au1200fb.h linux-2.6.15/drivers/video/au1200fb.h
+--- linux-2.6.15.orig/drivers/video/au1200fb.h	1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.15/drivers/video/au1200fb.h	2006-01-09 19:54:13.000000000 +0000
+@@ -0,0 +1,288 @@
++/*
++ * BRIEF MODULE DESCRIPTION
++ *	Hardware definitions for the Au1200 LCD controller
++ *
++ * Copyright 2004 AMD
++ * Author:	AMD
++ *
++ *  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 _AU1200LCD_H
++#define _AU1200LCD_H
++
++/********************************************************************/
++#define AU1200_LCD_ADDR		0xB5000000
++
++#define uint8 unsigned char
++#define uint32 unsigned int
++
++typedef volatile struct
++{
++	uint32	reserved0;
++	uint32	screen;
++	uint32	backcolor;
++	uint32	horztiming;
++	uint32	verttiming;
++	uint32	clkcontrol;
++	uint32	pwmdiv;
++	uint32	pwmhi;
++	uint32	reserved1;
++	uint32	winenable;
++	uint32	colorkey;
++	uint32	colorkeymsk;
++	struct
++	{
++		uint32	cursorctrl;
++		uint32	cursorpos;
++		uint32	cursorcolor0;
++		uint32	cursorcolor1;
++		uint32	cursorcolor2;
++		uint32	cursorcolor3;
++	} hwc;
++	uint32	intstatus;
++	uint32	intenable;
++	uint32	outmask;
++	uint32	fifoctrl;
++	uint32	reserved2[(0x0100-0x0058)/4];
++	struct
++	{
++		uint32	winctrl0;
++		uint32	winctrl1;
++		uint32	winctrl2;
++		uint32	winbuf0;
++		uint32	winbuf1;
++		uint32	winbufctrl;
++		uint32	winreserved0;
++		uint32	winreserved1;
++	} window[4];
++
++	uint32	reserved3[(0x0400-0x0180)/4];
++
++	uint32	palette[(0x0800-0x0400)/4];
++
++	uint8	cursorpattern[256];
++
++} AU1200_LCD;
++
++/* lcd_screen */
++#define LCD_SCREEN_SEN		(1<<31)
++#define LCD_SCREEN_SX		(0x07FF<<19)
++#define LCD_SCREEN_SY		(0x07FF<< 8)
++#define LCD_SCREEN_SWP		(1<<7)
++#define LCD_SCREEN_SWD		(1<<6)
++#define LCD_SCREEN_PT		(7<<0)
++#define LCD_SCREEN_PT_TFT	(0<<0)
++#define LCD_SCREEN_SX_N(WIDTH)	((WIDTH-1)<<19)
++#define LCD_SCREEN_SY_N(HEIGHT)	((HEIGHT-1)<<8)
++#define LCD_SCREEN_PT_CSTN	(1<<0)
++#define LCD_SCREEN_PT_CDSTN	(2<<0)
++#define LCD_SCREEN_PT_M8STN	(3<<0)
++#define LCD_SCREEN_PT_M4STN	(4<<0)
++
++/* lcd_backcolor */
++#define LCD_BACKCOLOR_SBGR		(0xFF<<16)
++#define LCD_BACKCOLOR_SBGG		(0xFF<<8)
++#define LCD_BACKCOLOR_SBGB		(0xFF<<0)
++#define LCD_BACKCOLOR_SBGR_N(N)	((N)<<16)
++#define LCD_BACKCOLOR_SBGG_N(N)	((N)<<8)
++#define LCD_BACKCOLOR_SBGB_N(N)	((N)<<0)
++
++/* lcd_winenable */
++#define LCD_WINENABLE_WEN3		(1<<3)
++#define LCD_WINENABLE_WEN2		(1<<2)
++#define LCD_WINENABLE_WEN1		(1<<1)
++#define LCD_WINENABLE_WEN0		(1<<0)
++
++/* lcd_colorkey */
++#define LCD_COLORKEY_CKR		(0xFF<<16)
++#define LCD_COLORKEY_CKG		(0xFF<<8)
++#define LCD_COLORKEY_CKB		(0xFF<<0)
++#define LCD_COLORKEY_CKR_N(N)	((N)<<16)
++#define LCD_COLORKEY_CKG_N(N)	((N)<<8)
++#define LCD_COLORKEY_CKB_N(N)	((N)<<0)
++
++/* lcd_colorkeymsk */
++#define LCD_COLORKEYMSK_CKMR		(0xFF<<16)
++#define LCD_COLORKEYMSK_CKMG		(0xFF<<8)
++#define LCD_COLORKEYMSK_CKMB		(0xFF<<0)
++#define LCD_COLORKEYMSK_CKMR_N(N)	((N)<<16)
++#define LCD_COLORKEYMSK_CKMG_N(N)	((N)<<8)
++#define LCD_COLORKEYMSK_CKMB_N(N)	((N)<<0)
++
++/* lcd windows control 0 */
++#define LCD_WINCTRL0_OX		(0x07FF<<21)
++#define LCD_WINCTRL0_OY		(0x07FF<<10)
++#define LCD_WINCTRL0_A		(0x00FF<<2)
++#define LCD_WINCTRL0_AEN	(1<<1)
++#define LCD_WINCTRL0_OX_N(N) ((N)<<21)
++#define LCD_WINCTRL0_OY_N(N) ((N)<<10)
++#define LCD_WINCTRL0_A_N(N) ((N)<<2)
++
++/* lcd windows control 1 */
++#define LCD_WINCTRL1_PRI	(3<<30)
++#define LCD_WINCTRL1_PIPE	(1<<29)
++#define LCD_WINCTRL1_FRM	(0xF<<25)
++#define LCD_WINCTRL1_CCO	(1<<24)
++#define LCD_WINCTRL1_PO		(3<<22)
++#define LCD_WINCTRL1_SZX	(0x07FF<<11)
++#define LCD_WINCTRL1_SZY	(0x07FF<<0)
++#define LCD_WINCTRL1_FRM_1BPP	(0<<25)
++#define LCD_WINCTRL1_FRM_2BPP	(1<<25)
++#define LCD_WINCTRL1_FRM_4BPP	(2<<25)
++#define LCD_WINCTRL1_FRM_8BPP	(3<<25)
++#define LCD_WINCTRL1_FRM_12BPP	(4<<25)
++#define LCD_WINCTRL1_FRM_16BPP655	(5<<25)
++#define LCD_WINCTRL1_FRM_16BPP565	(6<<25)
++#define LCD_WINCTRL1_FRM_16BPP556	(7<<25)
++#define LCD_WINCTRL1_FRM_16BPPI1555	(8<<25)
++#define LCD_WINCTRL1_FRM_16BPPI5551	(9<<25)
++#define LCD_WINCTRL1_FRM_16BPPA1555	(10<<25)
++#define LCD_WINCTRL1_FRM_16BPPA5551	(11<<25)
++#define LCD_WINCTRL1_FRM_24BPP		(12<<25)
++#define LCD_WINCTRL1_FRM_32BPP		(13<<25)
++#define LCD_WINCTRL1_PRI_N(N)	((N)<<30)
++#define LCD_WINCTRL1_PO_00		(0<<22)
++#define LCD_WINCTRL1_PO_01		(1<<22)
++#define LCD_WINCTRL1_PO_10		(2<<22)
++#define LCD_WINCTRL1_PO_11		(3<<22)
++#define LCD_WINCTRL1_SZX_N(N)	((N-1)<<11)
++#define LCD_WINCTRL1_SZY_N(N)	((N-1)<<0)
++
++/* lcd windows control 2 */
++#define LCD_WINCTRL2_CKMODE		(3<<24)
++#define LCD_WINCTRL2_DBM		(1<<23)
++#define LCD_WINCTRL2_RAM		(3<<21)
++#define LCD_WINCTRL2_BX			(0x1FFF<<8)
++#define LCD_WINCTRL2_SCX		(0xF<<4)
++#define LCD_WINCTRL2_SCY		(0xF<<0)
++#define LCD_WINCTRL2_CKMODE_00		(0<<24)
++#define LCD_WINCTRL2_CKMODE_01		(1<<24)
++#define LCD_WINCTRL2_CKMODE_10		(2<<24)
++#define LCD_WINCTRL2_CKMODE_11		(3<<24)
++#define LCD_WINCTRL2_RAM_NONE		(0<<21)
++#define LCD_WINCTRL2_RAM_PALETTE	(1<<21)
++#define LCD_WINCTRL2_RAM_GAMMA		(2<<21)
++#define LCD_WINCTRL2_RAM_BUFFER		(3<<21)
++#define LCD_WINCTRL2_BX_N(N)	((N)<<8)
++#define LCD_WINCTRL2_SCX_1		(0<<4)
++#define LCD_WINCTRL2_SCX_2		(1<<4)
++#define LCD_WINCTRL2_SCX_4		(2<<4)
++#define LCD_WINCTRL2_SCY_1		(0<<0)
++#define LCD_WINCTRL2_SCY_2		(1<<0)
++#define LCD_WINCTRL2_SCY_4		(2<<0)
++
++/* lcd windows buffer control */
++#define LCD_WINBUFCTRL_DB		(1<<1)
++#define LCD_WINBUFCTRL_DBN		(1<<0)
++
++/* lcd_intstatus, lcd_intenable */
++#define LCD_INT_IFO				(0xF<<14)
++#define LCD_INT_IFU				(0xF<<10)
++#define LCD_INT_OFO				(1<<9)
++#define LCD_INT_OFU				(1<<8)
++#define LCD_INT_WAIT			(1<<3)
++#define LCD_INT_SD				(1<<2)
++#define LCD_INT_SA				(1<<1)
++#define LCD_INT_SS				(1<<0)
++
++/* lcd_horztiming */
++#define LCD_HORZTIMING_HND2		(0x1FF<<18)
++#define LCD_HORZTIMING_HND1		(0x1FF<<9)
++#define LCD_HORZTIMING_HPW		(0x1FF<<0)
++#define LCD_HORZTIMING_HND2_N(N)(((N)-1)<<18)
++#define LCD_HORZTIMING_HND1_N(N)(((N)-1)<<9)
++#define LCD_HORZTIMING_HPW_N(N)	(((N)-1)<<0)
++
++/* lcd_verttiming */
++#define LCD_VERTTIMING_VND2		(0x1FF<<18)
++#define LCD_VERTTIMING_VND1		(0x1FF<<9)
++#define LCD_VERTTIMING_VPW		(0x1FF<<0)
++#define LCD_VERTTIMING_VND2_N(N)(((N)-1)<<18)
++#define LCD_VERTTIMING_VND1_N(N)(((N)-1)<<9)
++#define LCD_VERTTIMING_VPW_N(N)	(((N)-1)<<0)
++
++/* lcd_clkcontrol */
++#define LCD_CLKCONTROL_EXT		(1<<22)
++#define LCD_CLKCONTROL_DELAY	(3<<20)
++#define LCD_CLKCONTROL_CDD		(1<<19)
++#define LCD_CLKCONTROL_IB		(1<<18)
++#define LCD_CLKCONTROL_IC		(1<<17)
++#define LCD_CLKCONTROL_IH		(1<<16)
++#define LCD_CLKCONTROL_IV		(1<<15)
++#define LCD_CLKCONTROL_BF		(0x1F<<10)
++#define LCD_CLKCONTROL_PCD		(0x3FF<<0)
++#define LCD_CLKCONTROL_BF_N(N)	(((N)-1)<<10)
++#define LCD_CLKCONTROL_PCD_N(N)	((N)<<0)
++
++/* lcd_pwmdiv */
++#define LCD_PWMDIV_EN			(1<<31)
++#define LCD_PWMDIV_PWMDIV		(0x1FFFF<<0)
++#define LCD_PWMDIV_PWMDIV_N(N)	((N)<<0)
++
++/* lcd_pwmhi */
++#define LCD_PWMHI_PWMHI1		(0xFFFF<<16)
++#define LCD_PWMHI_PWMHI0		(0xFFFF<<0)
++#define LCD_PWMHI_PWMHI1_N(N)	((N)<<16)
++#define LCD_PWMHI_PWMHI0_N(N)	((N)<<0)
++
++/* lcd_hwccon */
++#define LCD_HWCCON_EN			(1<<0)
++
++/* lcd_cursorpos */
++#define LCD_CURSORPOS_HWCXOFF		(0x1F<<27)
++#define LCD_CURSORPOS_HWCXPOS		(0x07FF<<16)
++#define LCD_CURSORPOS_HWCYOFF		(0x1F<<11)
++#define LCD_CURSORPOS_HWCYPOS		(0x07FF<<0)
++#define LCD_CURSORPOS_HWCXOFF_N(N)	((N)<<27)
++#define LCD_CURSORPOS_HWCXPOS_N(N)	((N)<<16)
++#define LCD_CURSORPOS_HWCYOFF_N(N)	((N)<<11)
++#define LCD_CURSORPOS_HWCYPOS_N(N)	((N)<<0)
++
++/* lcd_cursorcolor */
++#define LCD_CURSORCOLOR_HWCA		(0xFF<<24)
++#define LCD_CURSORCOLOR_HWCR		(0xFF<<16)
++#define LCD_CURSORCOLOR_HWCG		(0xFF<<8)
++#define LCD_CURSORCOLOR_HWCB		(0xFF<<0)
++#define LCD_CURSORCOLOR_HWCA_N(N)	((N)<<24)
++#define LCD_CURSORCOLOR_HWCR_N(N)	((N)<<16)
++#define LCD_CURSORCOLOR_HWCG_N(N)	((N)<<8)
++#define LCD_CURSORCOLOR_HWCB_N(N)	((N)<<0)
++
++/* lcd_fifoctrl */
++#define LCD_FIFOCTRL_F3IF		(1<<29)
++#define LCD_FIFOCTRL_F3REQ		(0x1F<<24)
++#define LCD_FIFOCTRL_F2IF		(1<<29)
++#define LCD_FIFOCTRL_F2REQ		(0x1F<<16)
++#define LCD_FIFOCTRL_F1IF		(1<<29)
++#define LCD_FIFOCTRL_F1REQ		(0x1F<<8)
++#define LCD_FIFOCTRL_F0IF		(1<<29)
++#define LCD_FIFOCTRL_F0REQ		(0x1F<<0)
++#define LCD_FIFOCTRL_F3REQ_N(N)	((N-1)<<24)
++#define LCD_FIFOCTRL_F2REQ_N(N)	((N-1)<<16)
++#define LCD_FIFOCTRL_F1REQ_N(N)	((N-1)<<8)
++#define LCD_FIFOCTRL_F0REQ_N(N)	((N-1)<<0)
++
++/* lcd_outmask */
++#define LCD_OUTMASK_MASK		(0x00FFFFFF)
++
++/********************************************************************/
++#endif /* _AU1200LCD_H */
+diff -Naur linux-2.6.15.orig/drivers/video/smivgxfb.c linux-2.6.15/drivers/video/smivgxfb.c
+--- linux-2.6.15.orig/drivers/video/smivgxfb.c	1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.15/drivers/video/smivgxfb.c	2006-01-09 19:54:13.000000000 +0000
+@@ -0,0 +1,387 @@
++/***************************************************************************
++ *  Silicon Motion VoyagerGX framebuffer driver
++ *
++ * 	ported to 2.6 by Embedded Alley Solutions, Inc
++ * 	Copyright (C) 2005 Embedded Alley Solutions, Inc
++ *
++ * 		based on
++    copyright            : (C) 2001 by Szu-Tao Huang
++    email                : johuang at siliconmotion.com
++    Updated to SM501 by Eric.Devolder at amd.com and dan at embeddededge.com
++    for the AMD Mirage Portable Tablet.  20 Oct 2003
++ ***************************************************************************/
++
++/***************************************************************************
++ *                                                                         *
++ *   This program is free software; you can redistribute it and/or modify  *
++ *   it under the terms of the GNU General Public License as published by  *
++ *   the Free Software Foundation; either version 2 of the License, or     *
++ *   (at your option) any later version.                                   *
++ *                                                                         *
++ ***************************************************************************/
++
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/errno.h>
++#include <linux/string.h>
++#include <linux/mm.h>
++#include <linux/tty.h>
++#include <linux/slab.h>
++#include <linux/delay.h>
++#include <linux/fb.h>
++#include <linux/pci.h>
++#include <linux/init.h>
++
++#include <asm/io.h>
++#include <asm/irq.h>
++#include <asm/pgtable.h>
++#include <asm/system.h>
++#include <asm/uaccess.h>
++
++static char __iomem *SMIRegs;	// point to virtual Memory Map IO starting address
++static char __iomem *SMILFB;	// point to virtual video memory starting address
++
++static struct fb_fix_screeninfo smifb_fix __devinitdata = {
++	.id =		"smivgx",
++	.type =		FB_TYPE_PACKED_PIXELS,
++	.visual =	FB_VISUAL_TRUECOLOR,
++	.ywrapstep = 	0,
++	.line_length	= 1024 * 2, /* (bbp * xres)/8 */
++	.accel =	FB_ACCEL_NONE,
++};
++
++static struct fb_var_screeninfo smifb_var __devinitdata = {
++	.xres           = 1024,
++	.yres           = 768,
++	.xres_virtual   = 1024,
++	.yres_virtual   = 768,
++	.bits_per_pixel = 16,
++	.red            = { 11, 5, 0 },
++	.green          = {  5, 6, 0 },
++	.blue           = {  0, 5, 0 },
++	.activate       = FB_ACTIVATE_NOW,
++	.height         = -1,
++	.width          = -1,
++	.vmode          = FB_VMODE_NONINTERLACED,
++};
++
++
++static struct fb_info info;
++
++#define smi_mmiowb(dat,reg)	writeb(dat, (SMIRegs + reg))
++#define smi_mmioww(dat,reg)	writew(dat, (SMIRegs + reg))
++#define smi_mmiowl(dat,reg)	writel(dat, (SMIRegs + reg))
++
++#define smi_mmiorb(reg)	        readb(SMIRegs + reg)
++#define smi_mmiorw(reg)	        readw(SMIRegs + reg)
++#define smi_mmiorl(reg)	        readl(SMIRegs + reg)
++
++/* Address space offsets for various control/status registers.
++*/
++#define MISC_CTRL			0x000004
++#define GPIO_LO_CTRL			0x000008
++#define GPIO_HI_CTRL			0x00000c
++#define DRAM_CTRL			0x000010
++#define CURRENT_POWER_GATE		0x000038
++#define CURRENT_POWER_CLOCK		0x00003C
++#define POWER_MODE1_GATE                0x000048
++#define POWER_MODE1_CLOCK               0x00004C
++#define POWER_MODE_CTRL			0x000054
++
++#define GPIO_DATA_LO			0x010000
++#define GPIO_DATA_HI			0x010004
++#define GPIO_DATA_DIR_LO		0x010008
++#define GPIO_DATA_DIR_HI		0x01000c
++#define I2C_BYTE_COUNT			0x010040
++#define I2C_CONTROL			0x010041
++#define I2C_STATUS_RESET		0x010042
++#define I2C_SLAVE_ADDRESS		0x010043
++#define I2C_DATA			0x010044
++
++#define DE_COLOR_COMPARE		0x100020
++#define DE_COLOR_COMPARE_MASK		0x100024
++#define DE_MASKS			0x100028
++#define DE_WRAP				0x10004C
++
++#define PANEL_DISPLAY_CTRL              0x080000
++#define PANEL_PAN_CTRL                  0x080004
++#define PANEL_COLOR_KEY                 0x080008
++#define PANEL_FB_ADDRESS                0x08000C
++#define PANEL_FB_WIDTH                  0x080010
++#define PANEL_WINDOW_WIDTH              0x080014
++#define PANEL_WINDOW_HEIGHT             0x080018
++#define PANEL_PLANE_TL                  0x08001C
++#define PANEL_PLANE_BR                  0x080020
++#define PANEL_HORIZONTAL_TOTAL          0x080024
++#define PANEL_HORIZONTAL_SYNC           0x080028
++#define PANEL_VERTICAL_TOTAL            0x08002C
++#define PANEL_VERTICAL_SYNC             0x080030
++#define PANEL_CURRENT_LINE              0x080034
++#define VIDEO_DISPLAY_CTRL		0x080040
++#define VIDEO_DISPLAY_FB0		0x080044
++#define VIDEO_DISPLAY_FBWIDTH		0x080048
++#define VIDEO_DISPLAY_FB0LAST		0x08004C
++#define VIDEO_DISPLAY_TL		0x080050
++#define VIDEO_DISPLAY_BR		0x080054
++#define VIDEO_SCALE			0x080058
++#define VIDEO_INITIAL_SCALE		0x08005C
++#define VIDEO_YUV_CONSTANTS		0x080060
++#define VIDEO_DISPLAY_FB1		0x080064
++#define VIDEO_DISPLAY_FB1LAST		0x080068
++#define VIDEO_ALPHA_CTRL		0x080080
++#define PANEL_HWC_ADDRESS		0x0800F0
++#define CRT_DISPLAY_CTRL		0x080200
++#define CRT_FB_ADDRESS			0x080204
++#define CRT_FB_WIDTH			0x080208
++#define CRT_HORIZONTAL_TOTAL		0x08020c
++#define CRT_HORIZONTAL_SYNC		0x080210
++#define CRT_VERTICAL_TOTAL		0x080214
++#define CRT_VERTICAL_SYNC		0x080218
++#define CRT_HWC_ADDRESS			0x080230
++#define CRT_HWC_LOCATION		0x080234
++
++#define ZV_CAPTURE_CTRL			0x090000
++#define ZV_CAPTURE_CLIP			0x090004
++#define ZV_CAPTURE_SIZE			0x090008
++#define ZV_CAPTURE_BUF0			0x09000c
++#define ZV_CAPTURE_BUF1			0x090010
++#define ZV_CAPTURE_OFFSET		0x090014
++#define ZV_FIFO_CTRL			0x090018
++
++#define waitforvsync() udelay(400)
++
++static int initdone = 0;
++static int crt_out = 1;
++
++
++static int
++smi_setcolreg(unsigned regno, unsigned red, unsigned green,
++	unsigned blue, unsigned transp,
++	struct fb_info *info)
++{
++	if (regno > 255)
++		return 1;
++
++	((u32 *)(info->pseudo_palette))[regno] =
++		    ((red & 0xf800) >> 0) |
++		    ((green & 0xfc00) >> 5) |
++		    ((blue & 0xf800) >> 11);
++
++	return 0;
++}
++
++/* This function still needs lots of work to generically support
++ * different output devices (CRT or LCD) and resolutions.
++ * Currently hard-coded for 1024x768 LCD panel.
++ */
++static void smi_setmode(void)
++{
++	if (initdone)
++		return;
++
++	initdone = 1;
++
++	/* Just blast in some control values based upon the chip
++	 * documentation.  We use the internal memory, I don't know
++	 * how to determine the amount available yet.
++	 */
++	smi_mmiowl(0x07F127C2, DRAM_CTRL);
++	smi_mmiowl(0x02000020, PANEL_HWC_ADDRESS);
++	smi_mmiowl(0x007FF800, PANEL_HWC_ADDRESS);
++	smi_mmiowl(0x00021827, POWER_MODE1_GATE);
++	smi_mmiowl(0x011A0A09, POWER_MODE1_CLOCK);
++	smi_mmiowl(0x00000001, POWER_MODE_CTRL);
++	smi_mmiowl(0x80000000, PANEL_FB_ADDRESS);
++	smi_mmiowl(0x08000800, PANEL_FB_WIDTH);
++	smi_mmiowl(0x04000000, PANEL_WINDOW_WIDTH);
++	smi_mmiowl(0x03000000, PANEL_WINDOW_HEIGHT);
++	smi_mmiowl(0x00000000, PANEL_PLANE_TL);
++	smi_mmiowl(0x02FF03FF, PANEL_PLANE_BR);
++	smi_mmiowl(0x05D003FF, PANEL_HORIZONTAL_TOTAL);
++	smi_mmiowl(0x00C80424, PANEL_HORIZONTAL_SYNC);
++	smi_mmiowl(0x032502FF, PANEL_VERTICAL_TOTAL);
++	smi_mmiowl(0x00060302, PANEL_VERTICAL_SYNC);
++	smi_mmiowl(0x00013905, PANEL_DISPLAY_CTRL);
++	smi_mmiowl(0x01013105, PANEL_DISPLAY_CTRL);
++	waitforvsync();
++	smi_mmiowl(0x03013905, PANEL_DISPLAY_CTRL);
++	waitforvsync();
++	smi_mmiowl(0x07013905, PANEL_DISPLAY_CTRL);
++	waitforvsync();
++	smi_mmiowl(0x0F013905, PANEL_DISPLAY_CTRL);
++	smi_mmiowl(0x0002187F, POWER_MODE1_GATE);
++	smi_mmiowl(0x01011801, POWER_MODE1_CLOCK);
++	smi_mmiowl(0x00000001, POWER_MODE_CTRL);
++
++	smi_mmiowl(0x80000000, PANEL_FB_ADDRESS);
++	smi_mmiowl(0x00000000, PANEL_PAN_CTRL);
++	smi_mmiowl(0x00000000, PANEL_COLOR_KEY);
++
++	if (crt_out) {
++		/* Just sent the panel out to the CRT for now.
++		*/
++		smi_mmiowl(0x80000000, CRT_FB_ADDRESS);
++		smi_mmiowl(0x08000800, CRT_FB_WIDTH);
++		smi_mmiowl(0x05D003FF, CRT_HORIZONTAL_TOTAL);
++		smi_mmiowl(0x00C80424, CRT_HORIZONTAL_SYNC);
++		smi_mmiowl(0x032502FF, CRT_VERTICAL_TOTAL);
++		smi_mmiowl(0x00060302, CRT_VERTICAL_SYNC);
++		smi_mmiowl(0x007FF800, CRT_HWC_ADDRESS);
++		smi_mmiowl(0x00010305, CRT_DISPLAY_CTRL);
++		smi_mmiowl(0x00000001, MISC_CTRL);
++	}
++}
++
++/*
++ * Unmap in the memory mapped IO registers
++ *
++ */
++
++static void __devinit smi_unmap_mmio(void)
++{
++	if (SMIRegs) {
++		iounmap(SMIRegs);
++		SMIRegs = NULL;
++	}
++}
++
++
++/*
++ * Unmap in the screen memory
++ *
++ */
++static void __devinit smi_unmap_smem(void)
++{
++	if (SMILFB) {
++		iounmap(SMILFB);
++		SMILFB = NULL;
++	}
++}
++
++static void vgxfb_setup(char *options)
++{
++
++	if (!options || !*options)
++		return;
++
++	/* The only thing I'm looking for right now is to disable a
++	 * CRT output that mirrors the panel display.
++	 */
++	if (strcmp(options, "no_crt") == 0)
++		crt_out = 0;
++
++	return;
++}
++
++static struct fb_ops smifb_ops = {
++	.owner =		THIS_MODULE,
++	.fb_setcolreg =		smi_setcolreg,
++	.fb_fillrect =		cfb_fillrect,
++	.fb_copyarea =		cfb_copyarea,
++	.fb_imageblit =		cfb_imageblit,
++};
++
++static int __devinit vgx_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
++{
++	int err;
++
++	/* Enable the chip.
++	*/
++	err = pci_enable_device(dev);
++	if (err)
++		return err;
++
++
++	/* Set up MMIO space.
++	*/
++	smifb_fix.mmio_start = pci_resource_start(dev,1);
++	smifb_fix.mmio_len = 0x00200000;
++	SMIRegs = ioremap(smifb_fix.mmio_start, smifb_fix.mmio_len);
++
++	/* Set up framebuffer.  It's a 64M space, various amount of
++	 * internal memory.  I don't know how to determine the real
++	 * amount of memory (yet).
++	 */
++	smifb_fix.smem_start = pci_resource_start(dev,0);
++	smifb_fix.smem_len = 0x00800000;
++	SMILFB = ioremap(smifb_fix.smem_start, smifb_fix.smem_len);
++
++	memset_io(SMILFB, 0, smifb_fix.smem_len);
++
++	info.screen_base = SMILFB;
++	info.fbops = &smifb_ops;
++	info.fix = smifb_fix;
++
++	info.flags = FBINFO_FLAG_DEFAULT;
++
++	info.pseudo_palette = kmalloc(sizeof(u32) * 16, GFP_KERNEL);
++	if (!info.pseudo_palette) {
++		return -ENOMEM;
++	}
++	memset(info.pseudo_palette, 0, sizeof(u32) *16);
++
++	fb_alloc_cmap(&info.cmap,256,0);
++
++	smi_setmode();
++
++	info.var = smifb_var;
++
++	if (register_framebuffer(&info) < 0)
++		goto failed;
++
++	return 0;
++
++failed:
++	smi_unmap_smem();
++	smi_unmap_mmio();
++
++	return err;
++}
++
++static void __devexit vgx_pci_remove(struct pci_dev *dev)
++{
++	unregister_framebuffer(&info);
++	smi_unmap_smem();
++	smi_unmap_mmio();
++}
++
++static struct pci_device_id vgx_devices[] = {
++	{PCI_VENDOR_ID_SILICON_MOTION, PCI_DEVICE_ID_SM501_VOYAGER_GX_REV_AA,
++	 PCI_ANY_ID, PCI_ANY_ID},
++	{PCI_VENDOR_ID_SILICON_MOTION, PCI_DEVICE_ID_SM501_VOYAGER_GX_REV_B,
++	 PCI_ANY_ID, PCI_ANY_ID},
++	{0}
++};
++
++MODULE_DEVICE_TABLE(pci, vgx_devices);
++
++static struct pci_driver vgxfb_pci_driver = {
++	.name	= "vgxfb",
++	.id_table= vgx_devices,
++	.probe	= vgx_pci_probe,
++	.remove	= __devexit_p(vgx_pci_remove),
++};
++
++static int __init vgxfb_init(void)
++{
++	char *option = NULL;
++
++	if (fb_get_options("vgxfb", &option))
++		return -ENODEV;
++	vgxfb_setup(option);
++
++	printk("Silicon Motion Inc. VOYAGER Init complete.\n");
++	return pci_module_init(&vgxfb_pci_driver);
++}
++
++static void __exit vgxfb_exit(void)
++{
++	pci_unregister_driver(&vgxfb_pci_driver);
++}
++
++module_init(vgxfb_init);
++module_exit(vgxfb_exit);
++
++MODULE_AUTHOR("");
++MODULE_DESCRIPTION("Framebuffer driver for SMI Voyager");
++MODULE_LICENSE("GPL");
+diff -Naur linux-2.6.15.orig/include/asm-mips/atomic.h linux-2.6.15/include/asm-mips/atomic.h
+--- linux-2.6.15.orig/include/asm-mips/atomic.h	2006-01-03 03:21:10.000000000 +0000
++++ linux-2.6.15/include/asm-mips/atomic.h	2006-01-09 19:54:13.000000000 +0000
+@@ -24,10 +24,9 @@
+ #define _ASM_ATOMIC_H
+ 
+ #include <asm/cpu-features.h>
++#include <asm/interrupt.h>
+ #include <asm/war.h>
+ 
+-extern spinlock_t atomic_lock;
+-
+ typedef struct { volatile int counter; } atomic_t;
+ 
+ #define ATOMIC_INIT(i)    { (i) }
+@@ -85,9 +84,9 @@
+ 	} else {
+ 		unsigned long flags;
+ 
+-		spin_lock_irqsave(&atomic_lock, flags);
++		local_irq_save(flags);
+ 		v->counter += i;
+-		spin_unlock_irqrestore(&atomic_lock, flags);
++		local_irq_restore(flags);
+ 	}
+ }
+ 
+@@ -127,9 +126,9 @@
+ 	} else {
+ 		unsigned long flags;
+ 
+-		spin_lock_irqsave(&atomic_lock, flags);
++		local_irq_save(flags);
+ 		v->counter -= i;
+-		spin_unlock_irqrestore(&atomic_lock, flags);
++		local_irq_restore(flags);
+ 	}
+ }
+ 
+@@ -173,11 +172,11 @@
+ 	} else {
+ 		unsigned long flags;
+ 
+-		spin_lock_irqsave(&atomic_lock, flags);
++		local_irq_save(flags);
+ 		result = v->counter;
+ 		result += i;
+ 		v->counter = result;
+-		spin_unlock_irqrestore(&atomic_lock, flags);
++		local_irq_restore(flags);
+ 	}
+ 
+ 	return result;
+@@ -220,11 +219,11 @@
+ 	} else {
+ 		unsigned long flags;
+ 
+-		spin_lock_irqsave(&atomic_lock, flags);
++		local_irq_save(flags);
+ 		result = v->counter;
+ 		result -= i;
+ 		v->counter = result;
+-		spin_unlock_irqrestore(&atomic_lock, flags);
++		local_irq_restore(flags);
+ 	}
+ 
+ 	return result;
+@@ -277,12 +276,12 @@
+ 	} else {
+ 		unsigned long flags;
+ 
+-		spin_lock_irqsave(&atomic_lock, flags);
++		local_irq_save(flags);
+ 		result = v->counter;
+ 		result -= i;
+ 		if (result >= 0)
+ 			v->counter = result;
+-		spin_unlock_irqrestore(&atomic_lock, flags);
++		local_irq_restore(flags);
+ 	}
+ 
+ 	return result;
+@@ -432,9 +431,9 @@
+ 	} else {
+ 		unsigned long flags;
+ 
+-		spin_lock_irqsave(&atomic_lock, flags);
++		local_irq_save(flags);
+ 		v->counter += i;
+-		spin_unlock_irqrestore(&atomic_lock, flags);
++		local_irq_restore(flags);
+ 	}
+ }
+ 
+@@ -474,9 +473,9 @@
+ 	} else {
+ 		unsigned long flags;
+ 
+-		spin_lock_irqsave(&atomic_lock, flags);
++		local_irq_save(flags);
+ 		v->counter -= i;
+-		spin_unlock_irqrestore(&atomic_lock, flags);
++		local_irq_restore(flags);
+ 	}
+ }
+ 
+@@ -520,11 +519,11 @@
+ 	} else {
+ 		unsigned long flags;
+ 
+-		spin_lock_irqsave(&atomic_lock, flags);
++		local_irq_save(flags);
+ 		result = v->counter;
+ 		result += i;
+ 		v->counter = result;
+-		spin_unlock_irqrestore(&atomic_lock, flags);
++		local_irq_restore(flags);
+ 	}
+ 
+ 	return result;
+@@ -567,11 +566,11 @@
+ 	} else {
+ 		unsigned long flags;
+ 
+-		spin_lock_irqsave(&atomic_lock, flags);
++		local_irq_save(flags);
+ 		result = v->counter;
+ 		result -= i;
+ 		v->counter = result;
+-		spin_unlock_irqrestore(&atomic_lock, flags);
++		local_irq_restore(flags);
+ 	}
+ 
+ 	return result;
+@@ -624,12 +623,12 @@
+ 	} else {
+ 		unsigned long flags;
+ 
+-		spin_lock_irqsave(&atomic_lock, flags);
++		local_irq_save(flags);
+ 		result = v->counter;
+ 		result -= i;
+ 		if (result >= 0)
+ 			v->counter = result;
+-		spin_unlock_irqrestore(&atomic_lock, flags);
++		local_irq_restore(flags);
+ 	}
+ 
+ 	return result;
+diff -Naur linux-2.6.15.orig/include/asm-mips/cpu-features.h linux-2.6.15/include/asm-mips/cpu-features.h
+--- linux-2.6.15.orig/include/asm-mips/cpu-features.h	2006-01-03 03:21:10.000000000 +0000
++++ linux-2.6.15/include/asm-mips/cpu-features.h	2006-01-09 19:54:13.000000000 +0000
+@@ -116,6 +116,27 @@
+ #endif
+ #endif
+ 
++# ifndef cpu_has_mips32r1
++# define cpu_has_mips32r1	(cpu_data[0].isa_level & MIPS_CPU_ISA_M32R1)
++# endif
++# ifndef cpu_has_mips32r2
++# define cpu_has_mips32r2	(cpu_data[0].isa_level & MIPS_CPU_ISA_M32R2)
++# endif
++# ifndef cpu_has_mips64r1
++# define cpu_has_mips64r1	(cpu_data[0].isa_level & MIPS_CPU_ISA_M64R1)
++# endif
++# ifndef cpu_has_mips64r2
++# define cpu_has_mips64r2	(cpu_data[0].isa_level & MIPS_CPU_ISA_M64R2)
++# endif
++
++/*
++ * Shortcuts ...
++ */
++#define cpu_has_mips32	(cpu_has_mips32r1 | cpu_has_mips32r2)
++#define cpu_has_mips64	(cpu_has_mips64r1 | cpu_has_mips64r2)
++#define cpu_has_mips_r1	(cpu_has_mips32r1 | cpu_has_mips64r1)
++#define cpu_has_mips_r2	(cpu_has_mips32r2 | cpu_has_mips64r2)
++
+ #ifndef cpu_has_dsp
+ #define cpu_has_dsp		(cpu_data[0].ases & MIPS_ASE_DSP)
+ #endif
+diff -Naur linux-2.6.15.orig/include/asm-mips/cpu.h linux-2.6.15/include/asm-mips/cpu.h
+--- linux-2.6.15.orig/include/asm-mips/cpu.h	2006-01-03 03:21:10.000000000 +0000
++++ linux-2.6.15/include/asm-mips/cpu.h	2006-01-09 19:54:13.000000000 +0000
+@@ -204,16 +204,18 @@
+  */
+ #define MIPS_CPU_ISA_I		0x00000001
+ #define MIPS_CPU_ISA_II		0x00000002
+-#define MIPS_CPU_ISA_III	0x00008003
+-#define MIPS_CPU_ISA_IV		0x00008004
+-#define MIPS_CPU_ISA_V		0x00008005
+-#define MIPS_CPU_ISA_M32	0x00000020
+-#define MIPS_CPU_ISA_M64	0x00008040
++#define MIPS_CPU_ISA_III	0x00000003
++#define MIPS_CPU_ISA_IV		0x00000004
++#define MIPS_CPU_ISA_V		0x00000005
++#define MIPS_CPU_ISA_M32R1	0x00000020
++#define MIPS_CPU_ISA_M32R2	0x00000040
++#define MIPS_CPU_ISA_M64R1	0x00000080
++#define MIPS_CPU_ISA_M64R2	0x00000100
+ 
+-/*
+- * Bit 15 encodes if an ISA level supports 64-bit operations.
+- */
+-#define MIPS_CPU_ISA_64BIT	0x00008000
++#define MIPS_CPU_ISA_32BIT (MIPS_CPU_ISA_I | MIPS_CPU_ISA_II | \
++	MIPS_CPU_ISA_M32R1 | MIPS_CPU_ISA_M32R2 )
++#define MIPS_CPU_ISA_64BIT (MIPS_CPU_ISA_III | MIPS_CPU_ISA_IV | \
++	MIPS_CPU_ISA_V | MIPS_CPU_ISA_M64R1 | MIPS_CPU_ISA_M64R2)
+ 
+ /*
+  * CPU Option encodings
+diff -Naur linux-2.6.15.orig/include/asm-mips/delay.h linux-2.6.15/include/asm-mips/delay.h
+--- linux-2.6.15.orig/include/asm-mips/delay.h	2006-01-03 03:21:10.000000000 +0000
++++ linux-2.6.15/include/asm-mips/delay.h	2006-01-09 19:54:13.000000000 +0000
+@@ -52,13 +52,11 @@
+ 	unsigned long lo;
+ 
+ 	/*
+-	 * The common rates of 1000 and 128 are rounded wrongly by the
+-	 * catchall case for 64-bit.  Excessive precission?  Probably ...
++	 * The rates of 128 is rounded wrongly by the catchall case
++	 * for 64-bit.  Excessive precission?  Probably ...
+ 	 */
+ #if defined(CONFIG_64BIT) && (HZ == 128)
+ 	usecs *= 0x0008637bd05af6c7UL;		/* 2**64 / (1000000 / HZ) */
+-#elif defined(CONFIG_64BIT) && (HZ == 1000)
+-	usecs *= 0x004189374BC6A7f0UL;		/* 2**64 / (1000000 / HZ) */
+ #elif defined(CONFIG_64BIT)
+ 	usecs *= (0x8000000000000000UL / (500000 / HZ));
+ #else /* 32-bit junk follows here */
+diff -Naur linux-2.6.15.orig/include/asm-mips/dsp.h linux-2.6.15/include/asm-mips/dsp.h
+--- linux-2.6.15.orig/include/asm-mips/dsp.h	2006-01-03 03:21:10.000000000 +0000
++++ linux-2.6.15/include/asm-mips/dsp.h	2006-01-09 19:54:13.000000000 +0000
+@@ -16,7 +16,7 @@
+ #include <asm/mipsregs.h>
+ 
+ #define DSP_DEFAULT	0x00000000
+-#define DSP_MASK	0x1f
++#define DSP_MASK	0x3ff
+ 
+ #define __enable_dsp_hazard()						\
+ do {									\
+@@ -48,6 +48,7 @@
+ 	tsk->thread.dsp.dspr[3] = mflo2();				\
+ 	tsk->thread.dsp.dspr[4] = mfhi3();				\
+ 	tsk->thread.dsp.dspr[5] = mflo3();				\
++	tsk->thread.dsp.dspcontrol = rddsp(DSP_MASK);			\
+ } while (0)
+ 
+ #define save_dsp(tsk)							\
+@@ -64,6 +65,7 @@
+ 	mtlo2(tsk->thread.dsp.dspr[3]);					\
+ 	mthi3(tsk->thread.dsp.dspr[4]);					\
+ 	mtlo3(tsk->thread.dsp.dspr[5]);					\
++	wrdsp(tsk->thread.dsp.dspcontrol, DSP_MASK);			\
+ } while (0)
+ 
+ #define restore_dsp(tsk)						\
+diff -Naur linux-2.6.15.orig/include/asm-mips/elf.h linux-2.6.15/include/asm-mips/elf.h
+--- linux-2.6.15.orig/include/asm-mips/elf.h	2006-01-03 03:21:10.000000000 +0000
++++ linux-2.6.15/include/asm-mips/elf.h	2006-01-09 19:54:13.000000000 +0000
+@@ -277,12 +277,12 @@
+ 
+ struct task_struct;
+ 
+-extern void dump_regs(elf_greg_t *, struct pt_regs *regs);
++extern void elf_dump_regs(elf_greg_t *, struct pt_regs *regs);
+ extern int dump_task_regs (struct task_struct *, elf_gregset_t *);
+ extern int dump_task_fpu(struct task_struct *, elf_fpregset_t *);
+ 
+ #define ELF_CORE_COPY_REGS(elf_regs, regs)			\
+-	dump_regs((elf_greg_t *)&(elf_regs), regs);
++	elf_dump_regs((elf_greg_t *)&(elf_regs), regs);
+ #define ELF_CORE_COPY_TASK_REGS(tsk, elf_regs) dump_task_regs(tsk, elf_regs)
+ #define ELF_CORE_COPY_FPREGS(tsk, elf_fpregs)			\
+ 	dump_task_fpu(tsk, elf_fpregs)
+diff -Naur linux-2.6.15.orig/include/asm-mips/hazards.h linux-2.6.15/include/asm-mips/hazards.h
+--- linux-2.6.15.orig/include/asm-mips/hazards.h	2006-01-03 03:21:10.000000000 +0000
++++ linux-2.6.15/include/asm-mips/hazards.h	2006-01-09 19:54:13.000000000 +0000
+@@ -233,15 +233,25 @@
+ #endif
+ 
+ #ifdef CONFIG_CPU_MIPSR2
++/*
++ * gcc has a tradition of misscompiling the previous construct using the
++ * address of a label as argument to inline assembler.  Gas otoh has the
++ * annoying difference between la and dla which are only usable for 32-bit
++ * rsp. 64-bit code, so can't be used without conditional compilation.
++ * The alterantive is switching the assembler to 64-bit code which happens
++ * to work right even for 32-bit code ...
++ */
+ #define instruction_hazard()						\
+ do {									\
+-__label__ __next;							\
++	unsigned long tmp;						\
++									\
+ 	__asm__ __volatile__(						\
++	"	.set	mips64r2				\n"	\
++	"	dla	%0, 1f					\n"	\
+ 	"	jr.hb	%0					\n"	\
+-	:								\
+-	: "r" (&&__next));						\
+-__next:									\
+-	;								\
++	"	.set	mips0					\n"	\
++	"1:							\n"	\
++	: "=r" (tmp));							\
+ } while (0)
+ 
+ #else
+diff -Naur linux-2.6.15.orig/include/asm-mips/interrupt.h linux-2.6.15/include/asm-mips/interrupt.h
+--- linux-2.6.15.orig/include/asm-mips/interrupt.h	2006-01-03 03:21:10.000000000 +0000
++++ linux-2.6.15/include/asm-mips/interrupt.h	2006-01-09 19:54:13.000000000 +0000
+@@ -93,6 +93,7 @@
+ 	"	.set	noat						\n"
+ #ifdef CONFIG_CPU_MIPSR2
+ 	"	di	\\result					\n"
++	"	andi	\\result, 1					\n"
+ #else
+ 	"	mfc0	\\result, $12					\n"
+ 	"	ori	$1, \\result, 1					\n"
+diff -Naur linux-2.6.15.orig/include/asm-mips/io.h linux-2.6.15/include/asm-mips/io.h
+--- linux-2.6.15.orig/include/asm-mips/io.h	2006-01-03 03:21:10.000000000 +0000
++++ linux-2.6.15/include/asm-mips/io.h	2006-01-09 19:54:13.000000000 +0000
+@@ -535,34 +535,6 @@
+ }
+ 
+ /*
+- * Memory Mapped I/O
+- */
+-#define ioread8(addr)		readb(addr)
+-#define ioread16(addr)		readw(addr)
+-#define ioread32(addr)		readl(addr)
+-
+-#define iowrite8(b,addr)	writeb(b,addr)
+-#define iowrite16(w,addr)	writew(w,addr)
+-#define iowrite32(l,addr)	writel(l,addr)
+-
+-#define ioread8_rep(a,b,c)	readsb(a,b,c)
+-#define ioread16_rep(a,b,c)	readsw(a,b,c)
+-#define ioread32_rep(a,b,c)	readsl(a,b,c)
+-
+-#define iowrite8_rep(a,b,c)	writesb(a,b,c)
+-#define iowrite16_rep(a,b,c)	writesw(a,b,c)
+-#define iowrite32_rep(a,b,c)	writesl(a,b,c)
+-
+-/* Create a virtual mapping cookie for an IO port range */
+-extern void __iomem *ioport_map(unsigned long port, unsigned int nr);
+-extern void ioport_unmap(void __iomem *);
+-
+-/* Create a virtual mapping cookie for a PCI BAR (memory or IO) */
+-struct pci_dev;
+-extern void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long max);
+-extern void pci_iounmap(struct pci_dev *dev, void __iomem *);
+-
+-/*
+  * ISA space is 'always mapped' on currently supported MIPS systems, no need
+  * to explicitly ioremap() it. The fact that the ISA IO space is mapped
+  * to PAGE_OFFSET is pure coincidence - it does not mean ISA values
+diff -Naur linux-2.6.15.orig/include/asm-mips/mach-au1x00/au1000.h linux-2.6.15/include/asm-mips/mach-au1x00/au1000.h
+--- linux-2.6.15.orig/include/asm-mips/mach-au1x00/au1000.h	2006-01-03 03:21:10.000000000 +0000
++++ linux-2.6.15/include/asm-mips/mach-au1x00/au1000.h	2006-01-09 19:54:13.000000000 +0000
+@@ -838,6 +838,7 @@
+ #define UART3_ADDR                0xB1400000
+ 
+ #define USB_OHCI_BASE             0x14020000 // phys addr for ioremap
++#define USB_OHCI_LEN              0x00060000
+ #define USB_HOST_CONFIG           0xB4027ffc
+ 
+ #define AU1550_ETH0_BASE      0xB0500000
+@@ -1017,10 +1018,12 @@
+   #define I2S_CONTROL_D         (1<<1)
+   #define I2S_CONTROL_CE        (1<<0)
+ 
+-#ifndef CONFIG_SOC_AU1200
+-
+ /* USB Host Controller */
++#ifndef USB_OHCI_LEN
+ #define USB_OHCI_LEN              0x00100000
++#endif
++
++#ifndef CONFIG_SOC_AU1200
+ 
+ /* USB Device Controller */
+ #define USBD_EP0RD                0xB0200000
+diff -Naur linux-2.6.15.orig/include/asm-mips/mach-au1x00/au1xxx_ide.h linux-2.6.15/include/asm-mips/mach-au1x00/au1xxx_ide.h
+--- linux-2.6.15.orig/include/asm-mips/mach-au1x00/au1xxx_ide.h	2006-01-03 03:21:10.000000000 +0000
++++ linux-2.6.15/include/asm-mips/mach-au1x00/au1xxx_ide.h	2006-01-09 19:54:13.000000000 +0000
+@@ -84,6 +84,11 @@
+ } _auide_hwif;
+ 
+ #ifdef CONFIG_BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA
++struct drive_list_entry {
++	const char *id_model;
++	const char *id_firmware;
++};
++
+ /* HD white list */
+ static const struct drive_list_entry dma_white_list [] = {
+ /*
+diff -Naur linux-2.6.15.orig/include/asm-mips/mach-generic/timex.h linux-2.6.15/include/asm-mips/mach-generic/timex.h
+--- linux-2.6.15.orig/include/asm-mips/mach-generic/timex.h	2006-01-03 03:21:10.000000000 +0000
++++ linux-2.6.15/include/asm-mips/mach-generic/timex.h	2006-01-09 19:54:13.000000000 +0000
+@@ -3,20 +3,11 @@
+  * License.  See the file "COPYING" in the main directory of this archive
+  * for more details.
+  *
+- * Copyright (C) 2003 by Ralf Baechle
++ * Copyright (C) 2003, 2005 by Ralf Baechle
+  */
+ #ifndef __ASM_MACH_GENERIC_TIMEX_H
+ #define __ASM_MACH_GENERIC_TIMEX_H
+ 
+-#include <linux/config.h>
+-
+-/*
+- * Last remaining user of the i8254 PIC, will be converted, too ...
+- */
+-#ifdef CONFIG_SNI_RM200_PCI
+-#define CLOCK_TICK_RATE		1193182
+-#else
+ #define CLOCK_TICK_RATE		500000
+-#endif
+ 
+ #endif /* __ASM_MACH_GENERIC_TIMEX_H */
+diff -Naur linux-2.6.15.orig/include/asm-mips/mach-ip22/cpu-feature-overrides.h linux-2.6.15/include/asm-mips/mach-ip22/cpu-feature-overrides.h
+--- linux-2.6.15.orig/include/asm-mips/mach-ip22/cpu-feature-overrides.h	2006-01-03 03:21:10.000000000 +0000
++++ linux-2.6.15/include/asm-mips/mach-ip22/cpu-feature-overrides.h	2006-01-09 19:54:13.000000000 +0000
+@@ -34,4 +34,9 @@
+ #define cpu_has_nofpuex		0
+ #define cpu_has_64bits		1
+ 
++#define cpu_has_mips32r1	0
++#define cpu_has_mips32r2	0
++#define cpu_has_mips64r1	0
++#define cpu_has_mips64r2	0
++
+ #endif /* __ASM_MACH_IP22_CPU_FEATURE_OVERRIDES_H */
+diff -Naur linux-2.6.15.orig/include/asm-mips/mach-ip27/cpu-feature-overrides.h linux-2.6.15/include/asm-mips/mach-ip27/cpu-feature-overrides.h
+--- linux-2.6.15.orig/include/asm-mips/mach-ip27/cpu-feature-overrides.h	2006-01-03 03:21:10.000000000 +0000
++++ linux-2.6.15/include/asm-mips/mach-ip27/cpu-feature-overrides.h	2006-01-09 19:54:13.000000000 +0000
+@@ -37,4 +37,9 @@
+ #define cpu_icache_line_size()	64
+ #define cpu_scache_line_size()	128
+ 
++#define cpu_has_mips32r1	0
++#define cpu_has_mips32r2	0
++#define cpu_has_mips64r1	0
++#define cpu_has_mips64r2	0
++
+ #endif /* __ASM_MACH_IP27_CPU_FEATURE_OVERRIDES_H */
+diff -Naur linux-2.6.15.orig/include/asm-mips/mach-ip32/cpu-feature-overrides.h linux-2.6.15/include/asm-mips/mach-ip32/cpu-feature-overrides.h
+--- linux-2.6.15.orig/include/asm-mips/mach-ip32/cpu-feature-overrides.h	2006-01-03 03:21:10.000000000 +0000
++++ linux-2.6.15/include/asm-mips/mach-ip32/cpu-feature-overrides.h	2006-01-09 19:54:13.000000000 +0000
+@@ -39,4 +39,9 @@
+ #define cpu_has_ic_fills_f_dc	0
+ #define cpu_has_dsp		0
+ 
++#define cpu_has_mips32r1	0
++#define cpu_has_mips32r2	0
++#define cpu_has_mips64r1	0
++#define cpu_has_mips64r2	0
++
+ #endif /* __ASM_MACH_IP32_CPU_FEATURE_OVERRIDES_H */
+diff -Naur linux-2.6.15.orig/include/asm-mips/mach-ja/cpu-feature-overrides.h linux-2.6.15/include/asm-mips/mach-ja/cpu-feature-overrides.h
+--- linux-2.6.15.orig/include/asm-mips/mach-ja/cpu-feature-overrides.h	2006-01-03 03:21:10.000000000 +0000
++++ linux-2.6.15/include/asm-mips/mach-ja/cpu-feature-overrides.h	2006-01-09 19:54:13.000000000 +0000
+@@ -37,4 +37,9 @@
+ #define cpu_icache_line_size()	32
+ #define cpu_scache_line_size()	32
+ 
++#define cpu_has_mips32r1	0
++#define cpu_has_mips32r2	0
++#define cpu_has_mips64r1	0
++#define cpu_has_mips64r2	0
++
+ #endif /* __ASM_MACH_JA_CPU_FEATURE_OVERRIDES_H */
+diff -Naur linux-2.6.15.orig/include/asm-mips/mach-ocelot3/cpu-feature-overrides.h linux-2.6.15/include/asm-mips/mach-ocelot3/cpu-feature-overrides.h
+--- linux-2.6.15.orig/include/asm-mips/mach-ocelot3/cpu-feature-overrides.h	2006-01-03 03:21:10.000000000 +0000
++++ linux-2.6.15/include/asm-mips/mach-ocelot3/cpu-feature-overrides.h	2006-01-09 19:54:13.000000000 +0000
+@@ -40,4 +40,9 @@
+ #define cpu_icache_line_size()	32
+ #define cpu_scache_line_size()	32
+ 
++#define cpu_has_mips32r1	0
++#define cpu_has_mips32r2	0
++#define cpu_has_mips64r1	0
++#define cpu_has_mips64r2	0
++
+ #endif /* __ASM_MACH_JA_CPU_FEATURE_OVERRIDES_H */
+diff -Naur linux-2.6.15.orig/include/asm-mips/mach-rm200/cpu-feature-overrides.h linux-2.6.15/include/asm-mips/mach-rm200/cpu-feature-overrides.h
+--- linux-2.6.15.orig/include/asm-mips/mach-rm200/cpu-feature-overrides.h	2006-01-03 03:21:10.000000000 +0000
++++ linux-2.6.15/include/asm-mips/mach-rm200/cpu-feature-overrides.h	2006-01-09 19:54:13.000000000 +0000
+@@ -40,4 +40,9 @@
+ #define cpu_icache_line_size()	32
+ #define cpu_scache_line_size()	0	/* No S-cache on R5000 I think ...  */
+ 
++#define cpu_has_mips32r1	0
++#define cpu_has_mips32r2	0
++#define cpu_has_mips64r1	0
++#define cpu_has_mips64r2	0
++
+ #endif /* __ASM_MACH_RM200_CPU_FEATURE_OVERRIDES_H */
+diff -Naur linux-2.6.15.orig/include/asm-mips/mach-rm200/timex.h linux-2.6.15/include/asm-mips/mach-rm200/timex.h
+--- linux-2.6.15.orig/include/asm-mips/mach-rm200/timex.h	1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.15/include/asm-mips/mach-rm200/timex.h	2006-01-09 19:54:13.000000000 +0000
+@@ -0,0 +1,13 @@
++/*
++ * This file is subject to the terms and conditions of the GNU General Public
++ * License.  See the file "COPYING" in the main directory of this archive
++ * for more details.
++ *
++ * Copyright (C) 2003, 2005 by Ralf Baechle
++ */
++#ifndef __ASM_MACH_RM200_TIMEX_H
++#define __ASM_MACH_RM200_TIMEX_H
++
++#define CLOCK_TICK_RATE		1193182
++
++#endif /* __ASM_MACH_RM200_TIMEX_H */
+diff -Naur linux-2.6.15.orig/include/asm-mips/mach-vr41xx/timex.h linux-2.6.15/include/asm-mips/mach-vr41xx/timex.h
+--- linux-2.6.15.orig/include/asm-mips/mach-vr41xx/timex.h	1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.15/include/asm-mips/mach-vr41xx/timex.h	2006-01-09 19:54:13.000000000 +0000
+@@ -0,0 +1,18 @@
++/*
++ * This file is subject to the terms and conditions of the GNU General Public
++ * License.  See the file "COPYING" in the main directory of this archive
++ * for more details.
++ *
++ * Copyright (C) 2003 by Ralf Baechle
++ */
++/*
++ * Changes:
++ *  Yoichi Yuasa <yuasa at hh.iij4u.or.jp>
++ *  - CLOCK_TICK_RATE is changed into 32768 from 6144000.
++ */
++#ifndef __ASM_MACH_VR41XX_TIMEX_H
++#define __ASM_MACH_VR41XX_TIMEX_H
++
++#define CLOCK_TICK_RATE		32768
++
++#endif /* __ASM_MACH_VR41XX_TIMEX_H */
+diff -Naur linux-2.6.15.orig/include/asm-mips/mach-yosemite/cpu-feature-overrides.h linux-2.6.15/include/asm-mips/mach-yosemite/cpu-feature-overrides.h
+--- linux-2.6.15.orig/include/asm-mips/mach-yosemite/cpu-feature-overrides.h	2006-01-03 03:21:10.000000000 +0000
++++ linux-2.6.15/include/asm-mips/mach-yosemite/cpu-feature-overrides.h	2006-01-09 19:54:13.000000000 +0000
+@@ -37,4 +37,9 @@
+ #define cpu_icache_line_size()	32
+ #define cpu_scache_line_size()	32
+ 
++#define cpu_has_mips32r1	0
++#define cpu_has_mips32r2	0
++#define cpu_has_mips64r1	0
++#define cpu_has_mips64r2	0
++
+ #endif /* __ASM_MACH_YOSEMITE_CPU_FEATURE_OVERRIDES_H */
+diff -Naur linux-2.6.15.orig/include/asm-mips/mipsregs.h linux-2.6.15/include/asm-mips/mipsregs.h
+--- linux-2.6.15.orig/include/asm-mips/mipsregs.h	2006-01-03 03:21:10.000000000 +0000
++++ linux-2.6.15/include/asm-mips/mipsregs.h	2006-01-09 19:54:13.000000000 +0000
+@@ -1059,7 +1059,7 @@
+ 	"	.set	noat					\n"	\
+ 	"	move	$1, %0					\n"	\
+ 	"	# wrdsp $1, %x1					\n"	\
+-	"	.word	0x7c2004f8 | (%x1 << 15)		\n"	\
++	"	.word	0x7c2004f8 | (%x1 << 11)		\n"	\
+ 	"	.set	pop					\n"	\
+         :								\
+ 	: "r" (val), "i" (mask));					\
+diff -Naur linux-2.6.15.orig/include/asm-mips/processor.h linux-2.6.15/include/asm-mips/processor.h
+--- linux-2.6.15.orig/include/asm-mips/processor.h	2006-01-03 03:21:10.000000000 +0000
++++ linux-2.6.15/include/asm-mips/processor.h	2006-01-09 19:54:13.000000000 +0000
+@@ -103,7 +103,6 @@
+ struct mips_dsp_state {
+ 	dspreg_t        dspr[NUM_DSP_REGS];
+ 	unsigned int    dspcontrol;
+-	unsigned short	used_dsp;
+ };
+ 
+ #define INIT_DSP {{0,},}
+diff -Naur linux-2.6.15.orig/include/asm-mips/vr41xx/siu.h linux-2.6.15/include/asm-mips/vr41xx/siu.h
+--- linux-2.6.15.orig/include/asm-mips/vr41xx/siu.h	2006-01-03 03:21:10.000000000 +0000
++++ linux-2.6.15/include/asm-mips/vr41xx/siu.h	1970-01-01 00:00:00.000000000 +0000
+@@ -1,50 +0,0 @@
+-/*
+- *  Include file for NEC VR4100 series Serial Interface Unit.
+- *
+- *  Copyright (C) 2005  Yoichi Yuasa <yuasa at hh.iij4u.or.jp>
+- *
+- *  This program is free software; you can redistribute it and/or modify
+- *  it under the terms of the GNU General Public License as published by
+- *  the Free Software Foundation; either version 2 of the License, or
+- *  (at your option) any later version.
+- *
+- *  This program is distributed in the hope that it will be useful,
+- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+- *  GNU General Public License for more details.
+- *
+- *  You should have received a copy of the GNU General Public License
+- *  along with this program; if not, write to the Free Software
+- *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+- */
+-#ifndef __NEC_VR41XX_SIU_H
+-#define __NEC_VR41XX_SIU_H
+-
+-typedef enum {
+-	SIU_INTERFACE_RS232C,
+-	SIU_INTERFACE_IRDA,
+-} siu_interface_t;
+-
+-extern void vr41xx_select_siu_interface(siu_interface_t interface);
+-
+-typedef enum {
+-	SIU_USE_IRDA,
+-	FIR_USE_IRDA,
+-} irda_use_t;
+-
+-extern void vr41xx_use_irda(irda_use_t use);
+-
+-typedef enum {
+-	SHARP_IRDA,
+-	TEMIC_IRDA,
+-	HP_IRDA,
+-} irda_module_t;
+-
+-typedef enum {
+-	IRDA_TX_1_5MBPS,
+-	IRDA_TX_4MBPS,
+-} irda_speed_t;
+-
+-extern void vr41xx_select_irda_module(irda_module_t module, irda_speed_t speed);
+-
+-#endif /* __NEC_VR41XX_SIU_H */
+diff -Naur linux-2.6.15.orig/include/asm-mips/vr41xx/tb0287.h linux-2.6.15/include/asm-mips/vr41xx/tb0287.h
+--- linux-2.6.15.orig/include/asm-mips/vr41xx/tb0287.h	2006-01-03 03:21:10.000000000 +0000
++++ linux-2.6.15/include/asm-mips/vr41xx/tb0287.h	1970-01-01 00:00:00.000000000 +0000
+@@ -1,43 +0,0 @@
+-/*
+- *  tb0287.h, Include file for TANBAC TB0287 mini-ITX board.
+- *
+- *  Copyright (C) 2005  Media Lab Inc. <ito at mlb.co.jp>
+- *
+- *  This code is largely based on tb0219.h.
+- *
+- *  This program is free software; you can redistribute it and/or modify
+- *  it under the terms of the GNU General Public License as published by
+- *  the Free Software Foundation; either version 2 of the License, or
+- *  (at your option) any later version.
+- *
+- *  This program is distributed in the hope that it will be useful,
+- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+- *  GNU General Public License for more details.
+- *
+- *  You should have received a copy of the GNU General Public License
+- *  along with this program; if not, write to the Free Software
+- *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+- */
+-#ifndef __TANBAC_TB0287_H
+-#define __TANBAC_TB0287_H
+-
+-#include <asm/vr41xx/vr41xx.h>
+-
+-/*
+- * General-Purpose I/O Pin Number
+- */
+-#define TB0287_PCI_SLOT_PIN		2
+-#define TB0287_SM501_PIN		3
+-#define TB0287_SIL680A_PIN		8
+-#define TB0287_RTL8110_PIN		13
+-
+-/*
+- * Interrupt Number
+- */
+-#define TB0287_PCI_SLOT_IRQ		GIU_IRQ(TB0287_PCI_SLOT_PIN)
+-#define TB0287_SM501_IRQ		GIU_IRQ(TB0287_SM501_PIN)
+-#define TB0287_SIL680A_IRQ		GIU_IRQ(TB0287_SIL680A_PIN)
+-#define TB0287_RTL8110_IRQ		GIU_IRQ(TB0287_RTL8110_PIN)
+-
+-#endif /* __TANBAC_TB0287_H */
+diff -Naur linux-2.6.15.orig/include/asm-mips/vr41xx/vr41xx.h linux-2.6.15/include/asm-mips/vr41xx/vr41xx.h
+--- linux-2.6.15.orig/include/asm-mips/vr41xx/vr41xx.h	2006-01-03 03:21:10.000000000 +0000
++++ linux-2.6.15/include/asm-mips/vr41xx/vr41xx.h	2006-01-09 19:54:13.000000000 +0000
+@@ -7,7 +7,7 @@
+  * Copyright (C) 2001, 2002 Paul Mundt
+  * Copyright (C) 2002 MontaVista Software, Inc.
+  * Copyright (C) 2002 TimeSys Corp.
+- * Copyright (C) 2003-2005 Yoichi Yuasa <yuasa at hh.iij4u.or.jp>
++ * Copyright (C) 2003-2004 Yoichi Yuasa <yuasa at hh.iij4u.or.jp>
+  *
+  * 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
+diff -Naur linux-2.6.15.orig/include/linux/elf.h linux-2.6.15/include/linux/elf.h
+--- linux-2.6.15.orig/include/linux/elf.h	2006-01-03 03:21:10.000000000 +0000
++++ linux-2.6.15/include/linux/elf.h	2006-01-09 19:54:13.000000000 +0000
+@@ -67,7 +67,7 @@
+ 
+ #define EM_MIPS		8	/* MIPS R3000 (officially, big-endian only) */
+ 
+-#define EM_MIPS_RS4_BE 10	/* MIPS R4000 big-endian */
++#define EM_MIPS_RS3_LE 10	/* MIPS R3000 little-endian */
+ 
+ #define EM_PARISC      15	/* HPPA */
+ 
+diff -Naur linux-2.6.15.orig/include/linux/mc146818rtc.h linux-2.6.15/include/linux/mc146818rtc.h
+--- linux-2.6.15.orig/include/linux/mc146818rtc.h	2006-01-03 03:21:10.000000000 +0000
++++ linux-2.6.15/include/linux/mc146818rtc.h	2006-01-09 19:54:13.000000000 +0000
+@@ -89,4 +89,12 @@
+ # define RTC_VRT 0x80		/* valid RAM and time */
+ /**********************************************************************/
+ 
++#ifndef RTC_IO_EXTENT
++#define RTC_IO_EXTENT	0x8
++#endif
++
++#ifndef RTC_IOMAPPED
++#define RTC_IOMAPPED	1	/* Default to I/O mapping. */
++#endif
++
+ #endif /* _MC146818RTC_H */
+diff -Naur linux-2.6.15.orig/include/linux/pci_ids.h linux-2.6.15/include/linux/pci_ids.h
+--- linux-2.6.15.orig/include/linux/pci_ids.h	2006-01-03 03:21:10.000000000 +0000
++++ linux-2.6.15/include/linux/pci_ids.h	2006-01-09 19:54:13.000000000 +0000
+@@ -1530,6 +1530,9 @@
+ #define PCI_VENDOR_ID_SATSAGEM		0x1267
+ #define PCI_DEVICE_ID_SATSAGEM_NICCY	0x1016
+ 
++#define PCI_VENDOR_ID_SILICON_MOTION		0x126f
++#define PCI_DEVICE_ID_SM501_VOYAGER_GX_REV_AA	0x0501
++#define PCI_DEVICE_ID_SM501_VOYAGER_GX_REV_B	0x0510
+ 
+ #define PCI_VENDOR_ID_ENSONIQ		0x1274
+ #define PCI_DEVICE_ID_ENSONIQ_CT5880	0x5880
+diff -Naur linux-2.6.15.orig/include/linux/serial.h linux-2.6.15/include/linux/serial.h
+--- linux-2.6.15.orig/include/linux/serial.h	2006-01-03 03:21:10.000000000 +0000
++++ linux-2.6.15/include/linux/serial.h	2006-01-09 19:54:13.000000000 +0000
+@@ -76,7 +76,8 @@
+ #define PORT_16654	11
+ #define PORT_16850	12
+ #define PORT_RSA	13	/* RSA-DV II/S card */
+-#define PORT_MAX	13
++#define PORT_SB1250	14
++#define PORT_MAX	14
+ 
+ #define SERIAL_IO_PORT	0
+ #define SERIAL_IO_HUB6	1
+diff -Naur linux-2.6.15.orig/include/linux/serial_ip3106.h linux-2.6.15/include/linux/serial_ip3106.h
+--- linux-2.6.15.orig/include/linux/serial_ip3106.h	2006-01-03 03:21:10.000000000 +0000
++++ linux-2.6.15/include/linux/serial_ip3106.h	2006-01-09 19:54:13.000000000 +0000
+@@ -78,4 +78,16 @@
+ #define IP3106_UART_FIFO_RXFIFO		0x00001F00
+ #define IP3106_UART_FIFO_RBRTHR		0x000000FF
+ 
++#define ip3106_lcr(base,port)    *(volatile u32 *)(base+(port*0x1000) + 0x000)
++#define ip3106_mcr(base, port)   *(volatile u32 *)(base+(port*0x1000) + 0x004)
++#define ip3106_baud(base, port)  *(volatile u32 *)(base+(port*0x1000) + 0x008)
++#define ip3106_cfg(base, port)   *(volatile u32 *)(base+(port*0x1000) + 0x00C)
++#define ip3106_fifo(base, port)	 *(volatile u32 *)(base+(port*0x1000) + 0x028)
++#define ip3106_istat(base, port) *(volatile u32 *)(base+(port*0x1000) + 0xFE0)
++#define ip3106_ien(base, port)   *(volatile u32 *)(base+(port*0x1000) + 0xFE4)
++#define ip3106_iclr(base, port)  *(volatile u32 *)(base+(port*0x1000) + 0xFE8)
++#define ip3106_iset(base, port)  *(volatile u32 *)(base+(port*0x1000) + 0xFEC)
++#define ip3106_pd(base, port)    *(volatile u32 *)(base+(port*0x1000) + 0xFF4)
++#define ip3106_mid(base, port)   *(volatile u32 *)(base+(port*0x1000) + 0xFFC)
++
+ #endif
+diff -Naur linux-2.6.15.orig/sound/oss/Kconfig linux-2.6.15/sound/oss/Kconfig
+--- linux-2.6.15.orig/sound/oss/Kconfig	2006-01-03 03:21:10.000000000 +0000
++++ linux-2.6.15/sound/oss/Kconfig	2006-01-09 19:54:13.000000000 +0000
+@@ -239,6 +239,10 @@
+ 	tristate "Au1550 AC97 Sound"
+ 	depends on SOUND_PRIME && SOC_AU1550
+ 
++config SOUND_AU1550_I2S
++	tristate "Au1550 I2S Sound"
++	depends on SOUND_PRIME && SOC_AU1550
++
+ config SOUND_TRIDENT
+ 	tristate "Trident 4DWave DX/NX, SiS 7018 or ALi 5451 PCI Audio Core"
+ 	depends on SOUND_PRIME && PCI
+diff -Naur linux-2.6.15.orig/sound/oss/Makefile linux-2.6.15/sound/oss/Makefile
+--- linux-2.6.15.orig/sound/oss/Makefile	2006-01-03 03:21:10.000000000 +0000
++++ linux-2.6.15/sound/oss/Makefile	2006-01-09 19:54:13.000000000 +0000
+@@ -66,6 +66,7 @@
+ obj-$(CONFIG_SOUND_VRC5477)	+= nec_vrc5477.o ac97_codec.o
+ obj-$(CONFIG_SOUND_AU1000)	+= au1000.o ac97_codec.o
+ obj-$(CONFIG_SOUND_AU1550_AC97)	+= au1550_ac97.o ac97_codec.o
++obj-$(CONFIG_SOUND_AU1550_I2S)	+= au1550_i2s.o
+ obj-$(CONFIG_SOUND_ESSSOLO1)	+= esssolo1.o
+ obj-$(CONFIG_SOUND_FUSION)	+= cs46xx.o ac97_codec.o
+ obj-$(CONFIG_SOUND_MAESTRO)	+= maestro.o
+diff -Naur linux-2.6.15.orig/sound/oss/au1550_ac97.c linux-2.6.15/sound/oss/au1550_ac97.c
+--- linux-2.6.15.orig/sound/oss/au1550_ac97.c	2006-01-03 03:21:10.000000000 +0000
++++ linux-2.6.15/sound/oss/au1550_ac97.c	2006-01-09 19:54:13.000000000 +0000
+@@ -58,6 +58,7 @@
+ #include <asm/mach-au1x00/au1000.h>
+ #include <asm/mach-au1x00/au1xxx_psc.h>
+ #include <asm/mach-au1x00/au1xxx_dbdma.h>
++#include <asm/mach-pb1x00/pb1550.h>
+ 
+ #undef OSS_DOCUMENTED_MIXER_SEMANTICS
+ 
+diff -Naur linux-2.6.15.orig/sound/oss/au1550_i2s.c linux-2.6.15/sound/oss/au1550_i2s.c
+--- linux-2.6.15.orig/sound/oss/au1550_i2s.c	1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.15/sound/oss/au1550_i2s.c	2006-01-09 19:54:13.000000000 +0000
+@@ -0,0 +1,2029 @@
++/*
++ *      au1550_i2s.c  --  Sound driver for Alchemy Au1550 MIPS
++ *			Internet Edge Processor.
++ *
++ * Copyright 2004 Embedded Edge, LLC
++ *	dan at embeddededge.com
++ * Copyright 2005 Matt Porter <mporter at kernel.crashing.org>
++ *
++ * Mostly copied from the au1550_psc.c driver and some from the
++ * PowerMac dbdma driver.
++ * We assume the processor can do memory coherent DMA.
++ *
++ * WM8731 mixer support, codec framework, cleanup, and 2.6 port
++ * Matt Porter <mporter at kernel.crashing.org>
++ *
++ * The SMBus (I2C) is required for the control of the
++ * appears at I2C address 0x36 (I2C binary 0011011).  The Pb1550
++ * uses the Wolfson WM8731 codec, which is controlled over the I2C.
++ * It's connected to a 12MHz clock, so we can only reliably support
++ * 96KHz, 48KHz, 32KHz, and 8KHz data rates.  Variable rate audio is
++ * unsupported, we currently force it to 48KHz.
++ *
++ *  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/module.h>
++#include <linux/string.h>
++#include <linux/ioport.h>
++#include <linux/sched.h>
++#include <linux/delay.h>
++#include <linux/fs.h>
++#include <linux/hardirq.h>
++#include <linux/sound.h>
++#include <linux/slab.h>
++#include <linux/soundcard.h>
++#include <linux/init.h>
++#include <linux/poll.h>
++#include <linux/pci.h>
++#include <linux/bitops.h>
++#include <linux/proc_fs.h>
++#include <linux/spinlock.h>
++#include <linux/smp_lock.h>
++
++#include <asm/io.h>
++#include <asm/uaccess.h>
++#include <asm/hardirq.h>
++
++#include <asm/mach-au1x00/au1000.h>
++#include <asm/mach-au1x00/au1xxx_psc.h>
++#include <asm/mach-au1x00/au1xxx_dbdma.h>
++#include <asm/mach-pb1x00/pb1550.h>
++
++#undef OSS_DOCUMENTED_MIXER_SEMANTICS
++
++#define AU1550_MODULE_NAME "Au1550 I2S Audio"
++#define PFX AU1550_MODULE_NAME
++
++/* Define this if you want to try running at the 44.1 KHz rate.
++ * It's just a little off, I think it's actually 44117 or something.
++ * I did this for debugging, since many programs, including this
++ * driver, will try to upsample from 44.1 to 48 KHz.
++ * Seems to work well, we'll just leave it this way.
++ */
++#define TRY_441KHz
++
++#ifdef TRY_441KHz
++#define SAMP_RATE	44100
++#else
++#define SAMP_RATE	48000
++#endif
++
++/* The number of DBDMA ring descriptors to allocate.  No sense making
++ * this too large....if you can't keep up with a few you aren't likely
++ * to be able to with lots of them, either.
++ */
++#define NUM_DBDMA_DESCRIPTORS 4
++
++#define pr_error(format, arg...) printk(KERN_ERR PFX ": " format "\n" , ## arg)
++
++static void
++au1550_delay(int msec)
++{
++	unsigned long   tmo;
++	signed long     tmo2;
++
++	if (in_interrupt())
++		return;
++
++	tmo = jiffies + (msec * HZ) / 1000;
++	for (;;) {
++		tmo2 = tmo - jiffies;
++		if (tmo2 <= 0)
++			break;
++		schedule_timeout(tmo2);
++	}
++}
++
++/*
++ * Codec framework. If somebody supports another codec, they
++ * should hopefully be able to define another struct i2s_codec
++ * definition, and #ifdef the support for it and the WM8731 so
++ * they can be selected via a CONFIG option. For now, we just
++ * hardcode WM8731_CODEC.
++ */
++#define i2s_supported_mixer(CODEC,FOO) ((FOO >= 0) && \
++                                    (FOO < SOUND_MIXER_NRDEVICES) && \
++                                    (CODEC)->supported_mixers & (1<<FOO) )
++
++struct i2s_codec {
++	int			modcnt;
++	int			supported_mixers;
++	int			stereo_mixers;
++	int			record_sources;
++	unsigned int		mixer_state[SOUND_MIXER_NRDEVICES];
++	void			*data;
++	int			(*set_mixer) (struct i2s_codec *codec, unsigned int oss_mixer, unsigned int val);
++	void			(*init_codec) (struct i2s_codec *codec);
++};
++
++#define WM8731_CODEC
++#ifdef WM8731_CODEC
++/*
++ * WM8731 codec support
++ */
++#define WM8731_SUPPORTED_MASK (WM8731_STEREO_MASK|WM8731_RECORD_MASK)
++#define WM8731_STEREO_MASK (SOUND_MASK_VOLUME|SOUND_MASK_LINE)
++#define WM8731_RECORD_MASK (SOUND_MASK_MIC|SOUND_MASK_LINE)
++
++static struct codec_data {
++	u16			audio_path;
++} wm8731_data;
++
++static void
++wm8731_wrcodec(u8 ctlreg, u8 val)
++{
++	int	rcnt;
++	extern int pb1550_wm_codec_write(u8 addr, u8 reg, u8 val);
++
++	/* The codec is a write only device, with a 16-bit control/data
++	 * word.  Although it is written as two bytes on the I2C, the
++	 * format is actually 7 bits of register and 9 bits of data.
++	 * The ls bit of the first byte is the ms bit of the data.
++	 */
++	rcnt = 0;
++	while ((pb1550_wm_codec_write((0x36 >> 1), ctlreg, val) != 1)
++							&& (rcnt < 50)) {
++		rcnt++;
++	}
++}
++
++static int
++wm8731_set_mixer(struct i2s_codec *codec, unsigned int oss_mixer, unsigned int val)
++{
++	unsigned int lvol, rvol;
++	struct codec_data *cdata = (struct codec_data *)codec->data;
++
++	switch (oss_mixer) {
++		case SOUND_MIXER_VOLUME:
++			/* normalize OSS range to fit codec volume control */
++			lvol = ((((val & 0x7f00) >> 8) * 0x60) / 0x64) + 0x1f;
++			rvol = (((val & 0x7f) * 0x60) / 0x64) + 0x1f;
++			lvol |= 0x80;
++			rvol |= 0x80;
++			wm8731_wrcodec(0x04, lvol);
++			au1550_delay(10);
++			wm8731_wrcodec(0x06, rvol);
++			au1550_delay(10);
++			codec->mixer_state[oss_mixer] = val;
++			break;
++		case SOUND_MIXER_LINE:
++			/* normalize OSS range to fit codec line control */
++			lvol = ((((val & 0x7f00) >> 8) * 0x1f) / 0x64);
++			rvol = (((val & 0x7f) * 0x1f) / 0x64);
++			if (!(val & 0x1f00))
++				lvol |= 0x80;
++			else
++				lvol &= ~0x80;
++			if (!(val & 0x001f))
++				rvol |= 0x80;
++			else
++				rvol &= ~0x80;
++			wm8731_wrcodec(0x00, lvol);
++			au1550_delay(10);
++			wm8731_wrcodec(0x02, rvol);
++			au1550_delay(10);
++			codec->mixer_state[oss_mixer] = val;
++			break;
++		case SOUND_MIXER_MIC:
++			if (!val)
++				cdata->audio_path |= 0x02;
++			else {
++				if (val >= 0x32)
++					cdata->audio_path |= 0x01;
++				else
++					cdata->audio_path &= ~0x01;
++				cdata->audio_path &= ~0x02;
++			}
++			wm8731_wrcodec(0x08, cdata->audio_path);
++			au1550_delay(10);
++			codec->mixer_state[oss_mixer] = val;
++			break;
++		case SOUND_MIXER_RECSRC:
++			if (val & SOUND_MASK_LINE)
++				cdata->audio_path &= ~0x04;
++			else
++				cdata->audio_path |= 0x04;
++			wm8731_wrcodec(0x08, cdata->audio_path);
++			au1550_delay(10);
++			codec->mixer_state[oss_mixer] = val;
++			break;
++		default:
++			return -EINVAL;
++	}
++
++	return 0;
++}
++
++void
++wm8731_init_codec(struct i2s_codec *codec)
++{
++	struct codec_data *cdata = (struct codec_data *)codec->data;
++
++	wm8731_wrcodec(0x1e, 0x00);	/* Reset */
++	au1550_delay(200);
++	wm8731_wrcodec(0x0c, 0x00);	/* Power up everything */
++	au1550_delay(10);
++	wm8731_wrcodec(0x12, 0x00);	/* Deactivate codec */
++	au1550_delay(10);
++	cdata->audio_path = 0x10;
++	/* Select DAC outputs to line out */
++	wm8731_wrcodec(0x08, cdata->audio_path);
++	au1550_delay(10);
++	wm8731_wrcodec(0x0a, 0x00);	/* Disable output mute */
++	au1550_delay(10);
++	wm8731_wrcodec(0x0e, 0x02);	/* Set slave, 16-bit, I2S modes */
++	au1550_delay(10);
++	wm8731_wrcodec(0x10, 0x01);	/* 12MHz (USB), 250fs */
++	au1550_delay(10);
++	wm8731_wrcodec(0x12, 0x01);	/* Activate codec */
++	au1550_delay(10);
++
++	codec->set_mixer(codec, SOUND_MIXER_VOLUME, 0x5050);
++	codec->set_mixer(codec, SOUND_MIXER_LINE, 0x0000);
++	codec->set_mixer(codec, SOUND_MIXER_MIC, 0x00);
++	codec->mixer_state[SOUND_MIXER_RECSRC] = SOUND_MIXER_LINE;
++}
++
++static struct i2s_codec au1550_i2s_codec = {
++	.supported_mixers	= WM8731_SUPPORTED_MASK,
++	.stereo_mixers		= WM8731_STEREO_MASK,
++	.record_sources		= WM8731_RECORD_MASK,
++	.init_codec		= &wm8731_init_codec,
++	.set_mixer		= &wm8731_set_mixer,
++	.data			= &wm8731_data,
++};
++#endif /* WM8731_CODEC */
++
++static struct au1550_state {
++	/* soundcore stuff */
++	int             dev_audio;
++	int		dev_mixer;
++
++	spinlock_t		lock;
++	struct semaphore	open_sem;
++	struct semaphore	sem;
++	mode_t			open_mode;
++	wait_queue_head_t	open_wait;
++	volatile psc_i2s_t	*psc_addr;
++	struct i2s_codec	*codec;
++
++	struct dmabuf {
++		u32		dmanr;
++		unsigned        sample_rate;
++		unsigned	src_factor;
++		unsigned        sample_size;
++		int             num_channels;
++		int		dma_bytes_per_sample;
++		int		user_bytes_per_sample;
++		int		cnt_factor;
++
++		void		*rawbuf;
++		unsigned        buforder;
++		unsigned	numfrag;
++		unsigned        fragshift;
++		void		*nextIn;
++		void		*nextOut;
++		int		count;
++		unsigned        total_bytes;
++		unsigned        error;
++		wait_queue_head_t wait;
++
++		/* redundant, but makes calculations easier */
++		unsigned	fragsize;
++		unsigned	dma_fragsize;
++		unsigned	dmasize;
++		unsigned	dma_qcount;
++
++		/* OSS stuff */
++		unsigned        mapped:1;
++		unsigned        ready:1;
++		unsigned        stopped:1;
++		unsigned        ossfragshift;
++		int             ossmaxfrags;
++		unsigned        subdivision;
++
++		/* Mixer stuff */
++		int		dev_mixer;
++	} dma_dac, dma_adc;
++} au1550_state;
++
++static unsigned
++ld2(unsigned int x)
++{
++	unsigned        r = 0;
++
++	if (x >= 0x10000) {
++		x >>= 16;
++		r += 16;
++	}
++	if (x >= 0x100) {
++		x >>= 8;
++		r += 8;
++	}
++	if (x >= 0x10) {
++		x >>= 4;
++		r += 4;
++	}
++	if (x >= 4) {
++		x >>= 2;
++		r += 2;
++	}
++	if (x >= 2)
++		r++;
++	return r;
++}
++
++/* stop the ADC before calling */
++static void
++set_adc_rate(struct au1550_state *s, unsigned rate)
++{
++	struct dmabuf  *adc = &s->dma_adc;
++
++	/* calc SRC factor */
++	adc->src_factor = (((SAMP_RATE*2) / rate) + 1) >> 1;
++	adc->sample_rate = SAMP_RATE / adc->src_factor;
++	return;
++
++	adc->src_factor = 1;
++}
++
++/* stop the DAC before calling */
++static void
++set_dac_rate(struct au1550_state *s, unsigned rate)
++{
++	struct dmabuf  *dac = &s->dma_dac;
++
++	/* calc SRC factor */
++	dac->src_factor = (((SAMP_RATE*2) / rate) + 1) >> 1;
++	dac->sample_rate = SAMP_RATE / dac->src_factor;
++	return;
++
++	dac->src_factor = 1;
++}
++
++static void
++stop_dac(struct au1550_state *s)
++{
++	struct dmabuf  *db = &s->dma_dac;
++	unsigned long   flags;
++	uint	stat;
++	volatile psc_i2s_t *ip;
++
++	if (db->stopped)
++		return;
++
++	ip = s->psc_addr;
++	spin_lock_irqsave(&s->lock, flags);
++
++	ip->psc_i2spcr = PSC_I2SPCR_TP;
++	au_sync();
++
++	/* Wait for Transmit Busy to show disabled.
++	*/
++	do {
++		stat = ip->psc_i2sstat;
++		au_sync();
++	} while ((stat & PSC_I2SSTAT_TB) != 0);
++
++	au1xxx_dbdma_reset(db->dmanr);
++
++	db->stopped = 1;
++
++	spin_unlock_irqrestore(&s->lock, flags);
++}
++
++static void
++stop_adc(struct au1550_state *s)
++{
++	struct dmabuf  *db = &s->dma_adc;
++	unsigned long   flags;
++	uint	stat;
++	volatile psc_i2s_t *ip;
++
++	if (db->stopped)
++		return;
++
++	ip = s->psc_addr;
++	spin_lock_irqsave(&s->lock, flags);
++
++	ip->psc_i2spcr = PSC_I2SPCR_RP;
++	au_sync();
++
++	/* Wait for Receive Busy to show disabled.
++	*/
++	do {
++		stat = ip->psc_i2sstat;
++		au_sync();
++	} while ((stat & PSC_I2SSTAT_RB) != 0);
++
++	au1xxx_dbdma_reset(db->dmanr);
++
++	db->stopped = 1;
++
++	spin_unlock_irqrestore(&s->lock, flags);
++}
++
++static void
++set_xmit_slots(int num_channels)
++{
++	/* This is here just as a place holder.  The WM8731 only
++	 * supports two fixed channels.
++	 */
++}
++
++static void
++set_recv_slots(int num_channels)
++{
++	/* This is here just as a place holder.  The WM8731 only
++	 * supports two fixed channels.
++	 */
++}
++
++static void
++start_dac(struct au1550_state *s)
++{
++	struct dmabuf  *db = &s->dma_dac;
++	unsigned long   flags;
++	volatile psc_i2s_t *ip;
++
++	if (!db->stopped)
++		return;
++
++	spin_lock_irqsave(&s->lock, flags);
++
++	ip = s->psc_addr;
++	set_xmit_slots(db->num_channels);
++	ip->psc_i2spcr = PSC_I2SPCR_TC;
++	au_sync();
++	ip->psc_i2spcr = PSC_I2SPCR_TS;
++	au_sync();
++
++	au1xxx_dbdma_start(db->dmanr);
++
++	db->stopped = 0;
++
++	spin_unlock_irqrestore(&s->lock, flags);
++}
++
++static void
++start_adc(struct au1550_state *s)
++{
++	struct dmabuf  *db = &s->dma_adc;
++	int	i;
++	volatile psc_i2s_t *ip;
++
++	if (!db->stopped)
++		return;
++
++	/* Put two buffers on the ring to get things started.
++	*/
++	for (i=0; i<2; i++) {
++		au1xxx_dbdma_put_dest(db->dmanr, db->nextIn, db->dma_fragsize);
++
++		db->nextIn += db->dma_fragsize;
++		if (db->nextIn >= db->rawbuf + db->dmasize)
++			db->nextIn -= db->dmasize;
++	}
++
++	ip = s->psc_addr;
++	set_recv_slots(db->num_channels);
++	au1xxx_dbdma_start(db->dmanr);
++	ip->psc_i2spcr = PSC_I2SPCR_RC;
++	au_sync();
++	ip->psc_i2spcr = PSC_I2SPCR_RS;
++	au_sync();
++
++	db->stopped = 0;
++}
++
++static int
++prog_dmabuf(struct au1550_state *s, struct dmabuf *db)
++{
++	unsigned user_bytes_per_sec;
++	unsigned        bufs;
++	unsigned        rate = db->sample_rate;
++
++	if (!db->rawbuf) {
++		db->ready = db->mapped = 0;
++		db->buforder = 5;	/* 32 * PAGE_SIZE */
++		db->rawbuf = kmalloc((PAGE_SIZE << db->buforder), GFP_KERNEL);
++		if (!db->rawbuf)
++			return -ENOMEM;
++	}
++
++	db->cnt_factor = 1;
++	if (db->sample_size == 8)
++		db->cnt_factor *= 2;
++	if (db->num_channels == 1)
++		db->cnt_factor *= 2;
++	db->cnt_factor *= db->src_factor;
++
++	db->count = 0;
++	db->dma_qcount = 0;
++	db->nextIn = db->nextOut = db->rawbuf;
++
++	db->user_bytes_per_sample = (db->sample_size>>3) * db->num_channels;
++	db->dma_bytes_per_sample = 2 * ((db->num_channels == 1) ?
++					2 : db->num_channels);
++
++	user_bytes_per_sec = rate * db->user_bytes_per_sample;
++	bufs = PAGE_SIZE << db->buforder;
++	if (db->ossfragshift) {
++		if ((1000 << db->ossfragshift) < user_bytes_per_sec)
++			db->fragshift = ld2(user_bytes_per_sec/1000);
++		else
++			db->fragshift = db->ossfragshift;
++	} else {
++		db->fragshift = ld2(user_bytes_per_sec / 100 /
++				    (db->subdivision ? db->subdivision : 1));
++		if (db->fragshift < 3)
++			db->fragshift = 3;
++	}
++
++	db->fragsize = 1 << db->fragshift;
++	db->dma_fragsize = db->fragsize * db->cnt_factor;
++	db->numfrag = bufs / db->dma_fragsize;
++
++	while (db->numfrag < 4 && db->fragshift > 3) {
++		db->fragshift--;
++		db->fragsize = 1 << db->fragshift;
++		db->dma_fragsize = db->fragsize * db->cnt_factor;
++		db->numfrag = bufs / db->dma_fragsize;
++	}
++
++	if (db->ossmaxfrags >= 4 && db->ossmaxfrags < db->numfrag)
++		db->numfrag = db->ossmaxfrags;
++
++	db->dmasize = db->dma_fragsize * db->numfrag;
++	memset(db->rawbuf, 0, bufs);
++
++#ifdef AU1000_VERBOSE_DEBUG
++	dbg("rate=%d, samplesize=%d, channels=%d",
++	    rate, db->sample_size, db->num_channels);
++	dbg("fragsize=%d, cnt_factor=%d, dma_fragsize=%d",
++	    db->fragsize, db->cnt_factor, db->dma_fragsize);
++	dbg("numfrag=%d, dmasize=%d", db->numfrag, db->dmasize);
++#endif
++
++	db->ready = 1;
++	return 0;
++}
++
++static int
++prog_dmabuf_adc(struct au1550_state *s)
++{
++	stop_adc(s);
++	return prog_dmabuf(s, &s->dma_adc);
++
++}
++
++static int
++prog_dmabuf_dac(struct au1550_state *s)
++{
++	stop_dac(s);
++	return prog_dmabuf(s, &s->dma_dac);
++}
++
++
++/* hold spinlock for the following */
++static void
++dac_dma_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++{
++	struct au1550_state *s = (struct au1550_state *) dev_id;
++	struct dmabuf  *db = &s->dma_dac;
++	u32	i2s_stat;
++	volatile psc_i2s_t *ip;
++
++	ip = s->psc_addr;
++	i2s_stat = ip->psc_i2sstat;
++#ifdef AU1000_VERBOSE_DEBUG
++	if (i2s_stat & (PSC_I2SSTAT_TF | PSC_I2SSTAT_TR | PSC_I2SSTAT_TF))
++		dbg("I2S status = 0x%08x", i2s_stat);
++#endif
++	db->dma_qcount--;
++
++	if (db->count >= db->fragsize) {
++		if (au1xxx_dbdma_put_source(db->dmanr, db->nextOut,
++							db->fragsize) == 0) {
++			pr_error("qcount < 2 and no ring room!");
++		}
++		db->nextOut += db->fragsize;
++		if (db->nextOut >= db->rawbuf + db->dmasize)
++			db->nextOut -= db->dmasize;
++		db->count -= db->fragsize;
++		db->total_bytes += db->dma_fragsize;
++		db->dma_qcount++;
++	}
++
++	/* wake up anybody listening */
++	if (waitqueue_active(&db->wait))
++		wake_up(&db->wait);
++}
++
++
++static void
++adc_dma_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++{
++	struct	au1550_state *s = (struct au1550_state *)dev_id;
++	struct	dmabuf  *dp = &s->dma_adc;
++	u32	obytes;
++	char	*obuf;
++
++	/* Pull the buffer from the dma queue.
++	*/
++	au1xxx_dbdma_get_dest(dp->dmanr, (void *)(&obuf), &obytes);
++
++	if ((dp->count + obytes) > dp->dmasize) {
++		/* Overrun. Stop ADC and log the error
++		*/
++		stop_adc(s);
++		dp->error++;
++		pr_error("adc overrun");
++		return;
++	}
++
++	/* Put a new empty buffer on the destination DMA.
++	*/
++	au1xxx_dbdma_put_dest(dp->dmanr, dp->nextIn, dp->dma_fragsize);
++
++	dp->nextIn += dp->dma_fragsize;
++	if (dp->nextIn >= dp->rawbuf + dp->dmasize)
++		dp->nextIn -= dp->dmasize;
++
++	dp->count += obytes;
++	dp->total_bytes += obytes;
++
++	/* wake up anybody listening
++	*/
++	if (waitqueue_active(&dp->wait))
++		wake_up(&dp->wait);
++
++}
++
++static loff_t
++au1550_llseek(struct file *file, loff_t offset, int origin)
++{
++	return -ESPIPE;
++}
++
++static int
++au1550_open_mixdev(struct inode *inode, struct file *file)
++{
++	file->private_data = &au1550_state;
++	return 0;
++}
++
++static int
++au1550_release_mixdev(struct inode *inode, struct file *file)
++{
++	return 0;
++}
++
++#define I2S_CODEC	"Wolfson WM8731"
++
++static int
++au1550_ioctl_mixdev(struct inode *inode, struct file *file,
++			       unsigned int cmd, unsigned long arg)
++{
++	struct au1550_state *s = (struct au1550_state *)file->private_data;
++	struct i2s_codec *codec = s->codec;
++	int i, val = 0;
++
++	if (cmd == SOUND_MIXER_INFO) {
++		mixer_info info;
++		memset(&info, 0, sizeof(info));
++		strlcpy(info.id, I2S_CODEC, sizeof(info.id));
++		strlcpy(info.name, I2S_CODEC, sizeof(info.name));
++		info.modify_counter = codec->modcnt;
++		if (copy_to_user((void __user *)arg, &info, sizeof(info)))
++			return -EFAULT;
++		return 0;
++	}
++	if (cmd == SOUND_OLD_MIXER_INFO) {
++		_old_mixer_info info;
++		memset(&info, 0, sizeof(info));
++		strlcpy(info.id, I2S_CODEC, sizeof(info.id));
++		strlcpy(info.name, I2S_CODEC, sizeof(info.name));
++		if (copy_to_user((void __user *)arg, &info, sizeof(info)))
++			return -EFAULT;
++		return 0;
++	}
++
++	if (_IOC_TYPE(cmd) != 'M' || _SIOC_SIZE(cmd) != sizeof(int))
++		return -EINVAL;
++
++	if (cmd == OSS_GETVERSION)
++		return put_user(SOUND_VERSION, (int __user *)arg);
++
++	if (_SIOC_DIR(cmd) == _SIOC_READ) {
++		switch (_IOC_NR(cmd)) {
++		case SOUND_MIXER_RECSRC: /* give them the current record source */
++			val = codec->mixer_state[SOUND_MIXER_RECSRC];
++			break;
++
++		case SOUND_MIXER_DEVMASK: /* give them the supported mixers */
++			val = codec->supported_mixers;
++			break;
++
++		case SOUND_MIXER_RECMASK: /* Arg contains a bit for each supported recording source */
++			val = codec->record_sources;
++			break;
++
++		case SOUND_MIXER_STEREODEVS: /* Mixer channels supporting stereo */
++			val = codec->stereo_mixers;
++			break;
++
++		case SOUND_MIXER_CAPS:
++			val = SOUND_CAP_EXCL_INPUT;
++			break;
++
++		default: /* read a specific mixer */
++			i = _IOC_NR(cmd);
++
++			if (!i2s_supported_mixer(codec, i))
++				return -EINVAL;
++
++			val = codec->mixer_state[i];
++ 			break;
++		}
++		return put_user(val, (int __user *)arg);
++	}
++
++	if (_SIOC_DIR(cmd) == (_SIOC_WRITE|_SIOC_READ)) {
++		codec->modcnt++;
++		if (get_user(val, (int __user *)arg))
++			return -EFAULT;
++
++		switch (_IOC_NR(cmd)) {
++		case SOUND_MIXER_RECSRC: /* Arg contains a bit for each recording source */
++			if (!val) return 0;
++			if (!(val &= codec->record_sources)) return -EINVAL;
++
++			codec->set_mixer(codec, SOUND_MIXER_RECSRC, val);
++
++			return 0;
++		default: /* write a specific mixer */
++			i = _IOC_NR(cmd);
++
++			if (!i2s_supported_mixer(codec, i))
++				return -EINVAL;
++
++			codec->set_mixer(codec, i, val);
++
++			return 0;
++		}
++	}
++	return -EINVAL;
++}
++
++static struct file_operations au1550_mixer_fops = {
++	owner:THIS_MODULE,
++	llseek:au1550_llseek,
++	ioctl:au1550_ioctl_mixdev,
++	open:au1550_open_mixdev,
++	release:au1550_release_mixdev,
++};
++
++static int
++drain_dac(struct au1550_state *s, int nonblock)
++{
++	unsigned long   flags;
++	int             count, tmo;
++
++	if (s->dma_dac.mapped || !s->dma_dac.ready || s->dma_dac.stopped)
++		return 0;
++
++	for (;;) {
++		spin_lock_irqsave(&s->lock, flags);
++		count = s->dma_dac.count;
++		spin_unlock_irqrestore(&s->lock, flags);
++		if (count <= 0)
++			break;
++		if (signal_pending(current))
++			break;
++		if (nonblock)
++			return -EBUSY;
++		tmo = 1000 * count / SAMP_RATE;
++		tmo /= s->dma_dac.dma_bytes_per_sample;
++		au1550_delay(tmo);
++	}
++	if (signal_pending(current))
++		return -ERESTARTSYS;
++	return 0;
++}
++
++static inline u8 S16_TO_U8(s16 ch)
++{
++	return (u8) (ch >> 8) + 0x80;
++}
++static inline s16 U8_TO_S16(u8 ch)
++{
++	return (s16) (ch - 0x80) << 8;
++}
++
++/*
++ * Translates user samples to dma buffer suitable for audio DAC data:
++ *     If mono, copy left channel to right channel in dma buffer.
++ *     If 8 bit samples, cvt to 16-bit before writing to dma buffer.
++ *     If interpolating (no VRA), duplicate every audio frame src_factor times.
++ */
++static int
++translate_from_user(struct dmabuf *db, char* dmabuf, char* userbuf,
++							       int dmacount)
++{
++	int             sample, i;
++	int             interp_bytes_per_sample;
++	int             num_samples;
++	int             mono = (db->num_channels == 1);
++	char            usersample[12];
++	s16             ch, dmasample[6];
++
++	if (db->sample_size == 16 && !mono && db->src_factor == 1) {
++		/* no translation necessary, just copy
++		*/
++		if (copy_from_user(dmabuf, userbuf, dmacount))
++			return -EFAULT;
++		return dmacount;
++	}
++
++	interp_bytes_per_sample = db->dma_bytes_per_sample * db->src_factor;
++	num_samples = dmacount / interp_bytes_per_sample;
++
++	for (sample = 0; sample < num_samples; sample++) {
++		if (copy_from_user(usersample, userbuf,
++				   db->user_bytes_per_sample)) {
++			return -EFAULT;
++		}
++
++		for (i = 0; i < db->num_channels; i++) {
++			if (db->sample_size == 8)
++				ch = U8_TO_S16(usersample[i]);
++			else
++				ch = *((s16 *) (&usersample[i * 2]));
++			dmasample[i] = ch;
++			if (mono)
++				dmasample[i + 1] = ch;	/* right channel */
++		}
++
++		/* duplicate every audio frame src_factor times
++		*/
++		for (i = 0; i < db->src_factor; i++)
++			memcpy(dmabuf, dmasample, db->dma_bytes_per_sample);
++
++		userbuf += db->user_bytes_per_sample;
++		dmabuf += interp_bytes_per_sample;
++	}
++
++	return num_samples * interp_bytes_per_sample;
++}
++
++/*
++ * Translates audio ADC samples to user buffer:
++ *     If mono, send only left channel to user buffer.
++ *     If 8 bit samples, cvt from 16 to 8 bit before writing to user buffer.
++ *     If decimating (no VRA), skip over src_factor audio frames.
++ */
++static int
++translate_to_user(struct dmabuf *db, char* userbuf, char* dmabuf,
++							     int dmacount)
++{
++	int             sample, i;
++	int             interp_bytes_per_sample;
++	int             num_samples;
++	int             mono = (db->num_channels == 1);
++	char            usersample[12];
++
++	if (db->sample_size == 16 && !mono && db->src_factor == 1) {
++		/* no translation necessary, just copy
++		*/
++		if (copy_to_user(userbuf, dmabuf, dmacount))
++			return -EFAULT;
++		return dmacount;
++	}
++
++	interp_bytes_per_sample = db->dma_bytes_per_sample * db->src_factor;
++	num_samples = dmacount / interp_bytes_per_sample;
++
++	for (sample = 0; sample < num_samples; sample++) {
++		for (i = 0; i < db->num_channels; i++) {
++			if (db->sample_size == 8)
++				usersample[i] =
++					S16_TO_U8(*((s16 *) (&dmabuf[i * 2])));
++			else
++				*((s16 *) (&usersample[i * 2])) =
++					*((s16 *) (&dmabuf[i * 2]));
++		}
++
++		if (copy_to_user(userbuf, usersample,
++				 db->user_bytes_per_sample)) {
++			return -EFAULT;
++		}
++
++		userbuf += db->user_bytes_per_sample;
++		dmabuf += interp_bytes_per_sample;
++	}
++
++	return num_samples * interp_bytes_per_sample;
++}
++
++/*
++ * Copy audio data to/from user buffer from/to dma buffer, taking care
++ * that we wrap when reading/writing the dma buffer. Returns actual byte
++ * count written to or read from the dma buffer.
++ */
++static int
++copy_dmabuf_user(struct dmabuf *db, char* userbuf, int count, int to_user)
++{
++	char           *bufptr = to_user ? db->nextOut : db->nextIn;
++	char           *bufend = db->rawbuf + db->dmasize;
++	int             cnt, ret;
++
++	if (bufptr + count > bufend) {
++		int             partial = (int) (bufend - bufptr);
++		if (to_user) {
++			if ((cnt = translate_to_user(db, userbuf,
++						     bufptr, partial)) < 0)
++				return cnt;
++			ret = cnt;
++			if ((cnt = translate_to_user(db, userbuf + partial,
++						     db->rawbuf,
++						     count - partial)) < 0)
++				return cnt;
++			ret += cnt;
++		} else {
++			if ((cnt = translate_from_user(db, bufptr, userbuf,
++						       partial)) < 0)
++				return cnt;
++			ret = cnt;
++			if ((cnt = translate_from_user(db, db->rawbuf,
++						       userbuf + partial,
++						       count - partial)) < 0)
++				return cnt;
++			ret += cnt;
++		}
++	} else {
++		if (to_user)
++			ret = translate_to_user(db, userbuf, bufptr, count);
++		else
++			ret = translate_from_user(db, bufptr, userbuf, count);
++	}
++
++	return ret;
++}
++
++static ssize_t
++au1550_read(struct file *file, char *buffer, size_t count, loff_t *ppos)
++{
++	struct au1550_state *s = (struct au1550_state *)file->private_data;
++	struct dmabuf  *db = &s->dma_adc;
++	DECLARE_WAITQUEUE(wait, current);
++	ssize_t         ret;
++	unsigned long   flags;
++	int             cnt, usercnt, avail;
++
++	if (db->mapped)
++		return -ENXIO;
++	if (!access_ok(VERIFY_WRITE, buffer, count))
++		return -EFAULT;
++	ret = 0;
++
++	count *= db->cnt_factor;
++
++	down(&s->sem);
++	add_wait_queue(&db->wait, &wait);
++
++	while (count > 0) {
++		/* wait for samples in ADC dma buffer
++		*/
++		do {
++			if (db->stopped)
++				start_adc(s);
++			spin_lock_irqsave(&s->lock, flags);
++			avail = db->count;
++			if (avail <= 0)
++				__set_current_state(TASK_INTERRUPTIBLE);
++			spin_unlock_irqrestore(&s->lock, flags);
++			if (avail <= 0) {
++				if (file->f_flags & O_NONBLOCK) {
++					if (!ret)
++						ret = -EAGAIN;
++					goto out;
++				}
++				up(&s->sem);
++				schedule();
++				if (signal_pending(current)) {
++					if (!ret)
++						ret = -ERESTARTSYS;
++					goto out2;
++				}
++				down(&s->sem);
++			}
++		} while (avail <= 0);
++
++		/* copy from nextOut to user
++		*/
++		if ((cnt = copy_dmabuf_user(db, buffer,
++					    count > avail ?
++					    avail : count, 1)) < 0) {
++			if (!ret)
++				ret = -EFAULT;
++			goto out;
++		}
++
++		spin_lock_irqsave(&s->lock, flags);
++		db->count -= cnt;
++		db->nextOut += cnt;
++		if (db->nextOut >= db->rawbuf + db->dmasize)
++			db->nextOut -= db->dmasize;
++		spin_unlock_irqrestore(&s->lock, flags);
++
++		count -= cnt;
++		usercnt = cnt / db->cnt_factor;
++		buffer += usercnt;
++		ret += usercnt;
++	}			/* while (count > 0) */
++
++out:
++	up(&s->sem);
++out2:
++	remove_wait_queue(&db->wait, &wait);
++	set_current_state(TASK_RUNNING);
++	return ret;
++}
++
++static ssize_t
++au1550_write(struct file *file, const char *buffer, size_t count, loff_t * ppos)
++{
++	struct au1550_state *s = (struct au1550_state *)file->private_data;
++	struct dmabuf  *db = &s->dma_dac;
++	DECLARE_WAITQUEUE(wait, current);
++	ssize_t         ret = 0;
++	unsigned long   flags;
++	int             cnt, usercnt, avail;
++
++#ifdef AU1000_VERBOSE_DEBUG
++	dbg("write: count=%d", count);
++#endif
++
++	if (db->mapped)
++		return -ENXIO;
++	if (!access_ok(VERIFY_READ, buffer, count))
++		return -EFAULT;
++
++	count *= db->cnt_factor;
++
++	down(&s->sem);
++	add_wait_queue(&db->wait, &wait);
++
++	while (count > 0) {
++		/* wait for space in playback buffer
++		*/
++		do {
++			spin_lock_irqsave(&s->lock, flags);
++			avail = (int) db->dmasize - db->count;
++			if (avail <= 0)
++				__set_current_state(TASK_INTERRUPTIBLE);
++			spin_unlock_irqrestore(&s->lock, flags);
++			if (avail <= 0) {
++				if (file->f_flags & O_NONBLOCK) {
++					if (!ret)
++						ret = -EAGAIN;
++					goto out;
++				}
++				up(&s->sem);
++				schedule();
++				if (signal_pending(current)) {
++					if (!ret)
++						ret = -ERESTARTSYS;
++					goto out2;
++				}
++				down(&s->sem);
++			}
++		} while (avail <= 0);
++
++		/* copy from user to nextIn
++		*/
++		if ((cnt = copy_dmabuf_user(db, (char *) buffer,
++					    count > avail ?
++					    avail : count, 0)) < 0) {
++			if (!ret)
++				ret = -EFAULT;
++			goto out;
++		}
++
++		spin_lock_irqsave(&s->lock, flags);
++		db->count += cnt;
++		db->nextIn += cnt;
++		if (db->nextIn >= db->rawbuf + db->dmasize)
++			db->nextIn -= db->dmasize;
++
++		/* If the data is available, we want to keep two buffers
++		 * on the dma queue.  If the queue count reaches zero,
++		 * we know the dma has stopped.
++		 */
++		while ((db->dma_qcount < 2) && (db->count >= db->fragsize)) {
++			if (au1xxx_dbdma_put_source(db->dmanr, db->nextOut,
++							db->fragsize) == 0) {
++				pr_error("qcount < 2 and no ring room!");
++			}
++			db->nextOut += db->fragsize;
++			if (db->nextOut >= db->rawbuf + db->dmasize)
++				db->nextOut -= db->dmasize;
++			db->count -= db->fragsize;
++			db->total_bytes += db->dma_fragsize;
++			if (db->dma_qcount == 0)
++				start_dac(s);
++			db->dma_qcount++;
++		}
++		spin_unlock_irqrestore(&s->lock, flags);
++
++		count -= cnt;
++		usercnt = cnt / db->cnt_factor;
++		buffer += usercnt;
++		ret += usercnt;
++	}			/* while (count > 0) */
++
++out:
++	up(&s->sem);
++out2:
++	remove_wait_queue(&db->wait, &wait);
++	set_current_state(TASK_RUNNING);
++	return ret;
++}
++
++
++/* No kernel lock - we have our own spinlock */
++static unsigned int
++au1550_poll(struct file *file, struct poll_table_struct *wait)
++{
++	struct au1550_state *s = (struct au1550_state *)file->private_data;
++	unsigned long   flags;
++	unsigned int    mask = 0;
++
++	if (file->f_mode & FMODE_WRITE) {
++		if (!s->dma_dac.ready)
++			return 0;
++		poll_wait(file, &s->dma_dac.wait, wait);
++	}
++	if (file->f_mode & FMODE_READ) {
++		if (!s->dma_adc.ready)
++			return 0;
++		poll_wait(file, &s->dma_adc.wait, wait);
++	}
++
++	spin_lock_irqsave(&s->lock, flags);
++
++	if (file->f_mode & FMODE_READ) {
++		if (s->dma_adc.count >= (signed)s->dma_adc.dma_fragsize)
++			mask |= POLLIN | POLLRDNORM;
++	}
++	if (file->f_mode & FMODE_WRITE) {
++		if (s->dma_dac.mapped) {
++			if (s->dma_dac.count >=
++			    (signed)s->dma_dac.dma_fragsize)
++				mask |= POLLOUT | POLLWRNORM;
++		} else {
++			if ((signed) s->dma_dac.dmasize >=
++			    s->dma_dac.count + (signed)s->dma_dac.dma_fragsize)
++				mask |= POLLOUT | POLLWRNORM;
++		}
++	}
++	spin_unlock_irqrestore(&s->lock, flags);
++	return mask;
++}
++
++static int
++au1550_mmap(struct file *file, struct vm_area_struct *vma)
++{
++	struct au1550_state *s = (struct au1550_state *)file->private_data;
++	struct dmabuf  *db;
++	unsigned long   size;
++	int ret = 0;
++
++	lock_kernel();
++	down(&s->sem);
++	if (vma->vm_flags & VM_WRITE)
++		db = &s->dma_dac;
++	else if (vma->vm_flags & VM_READ)
++		db = &s->dma_adc;
++	else {
++		ret = -EINVAL;
++		goto out;
++	}
++	if (vma->vm_pgoff != 0) {
++		ret = -EINVAL;
++		goto out;
++	}
++	size = vma->vm_end - vma->vm_start;
++	if (size > (PAGE_SIZE << db->buforder)) {
++		ret = -EINVAL;
++		goto out;
++	}
++	if (remap_pfn_range(vma, vma->vm_start,
++			     page_to_pfn(virt_to_page(db->rawbuf)),
++			     size, vma->vm_page_prot)) {
++		ret = -EAGAIN;
++		goto out;
++	}
++	vma->vm_flags &= ~VM_IO;
++	db->mapped = 1;
++out:
++	up(&s->sem);
++	unlock_kernel();
++	return ret;
++}
++
++
++#ifdef AU1000_VERBOSE_DEBUG
++static struct ioctl_str_t {
++	unsigned int    cmd;
++	const char     *str;
++} ioctl_str[] = {
++	{SNDCTL_DSP_RESET, "SNDCTL_DSP_RESET"},
++	{SNDCTL_DSP_SYNC, "SNDCTL_DSP_SYNC"},
++	{SNDCTL_DSP_SPEED, "SNDCTL_DSP_SPEED"},
++	{SNDCTL_DSP_STEREO, "SNDCTL_DSP_STEREO"},
++	{SNDCTL_DSP_GETBLKSIZE, "SNDCTL_DSP_GETBLKSIZE"},
++	{SNDCTL_DSP_SAMPLESIZE, "SNDCTL_DSP_SAMPLESIZE"},
++	{SNDCTL_DSP_CHANNELS, "SNDCTL_DSP_CHANNELS"},
++	{SOUND_PCM_WRITE_CHANNELS, "SOUND_PCM_WRITE_CHANNELS"},
++	{SOUND_PCM_WRITE_FILTER, "SOUND_PCM_WRITE_FILTER"},
++	{SNDCTL_DSP_POST, "SNDCTL_DSP_POST"},
++	{SNDCTL_DSP_SUBDIVIDE, "SNDCTL_DSP_SUBDIVIDE"},
++	{SNDCTL_DSP_SETFRAGMENT, "SNDCTL_DSP_SETFRAGMENT"},
++	{SNDCTL_DSP_GETFMTS, "SNDCTL_DSP_GETFMTS"},
++	{SNDCTL_DSP_SETFMT, "SNDCTL_DSP_SETFMT"},
++	{SNDCTL_DSP_GETOSPACE, "SNDCTL_DSP_GETOSPACE"},
++	{SNDCTL_DSP_GETISPACE, "SNDCTL_DSP_GETISPACE"},
++	{SNDCTL_DSP_NONBLOCK, "SNDCTL_DSP_NONBLOCK"},
++	{SNDCTL_DSP_GETCAPS, "SNDCTL_DSP_GETCAPS"},
++	{SNDCTL_DSP_GETTRIGGER, "SNDCTL_DSP_GETTRIGGER"},
++	{SNDCTL_DSP_SETTRIGGER, "SNDCTL_DSP_SETTRIGGER"},
++	{SNDCTL_DSP_GETIPTR, "SNDCTL_DSP_GETIPTR"},
++	{SNDCTL_DSP_GETOPTR, "SNDCTL_DSP_GETOPTR"},
++	{SNDCTL_DSP_MAPINBUF, "SNDCTL_DSP_MAPINBUF"},
++	{SNDCTL_DSP_MAPOUTBUF, "SNDCTL_DSP_MAPOUTBUF"},
++	{SNDCTL_DSP_SETSYNCRO, "SNDCTL_DSP_SETSYNCRO"},
++	{SNDCTL_DSP_SETDUPLEX, "SNDCTL_DSP_SETDUPLEX"},
++	{SNDCTL_DSP_GETODELAY, "SNDCTL_DSP_GETODELAY"},
++	{SNDCTL_DSP_GETCHANNELMASK, "SNDCTL_DSP_GETCHANNELMASK"},
++	{SNDCTL_DSP_BIND_CHANNEL, "SNDCTL_DSP_BIND_CHANNEL"},
++	{OSS_GETVERSION, "OSS_GETVERSION"},
++	{SOUND_PCM_READ_RATE, "SOUND_PCM_READ_RATE"},
++	{SOUND_PCM_READ_CHANNELS, "SOUND_PCM_READ_CHANNELS"},
++	{SOUND_PCM_READ_BITS, "SOUND_PCM_READ_BITS"},
++	{SOUND_PCM_READ_FILTER, "SOUND_PCM_READ_FILTER"}
++};
++#endif
++
++static int
++dma_count_done(struct dmabuf *db)
++{
++	if (db->stopped)
++		return 0;
++
++	return db->dma_fragsize - au1xxx_get_dma_residue(db->dmanr);
++}
++
++
++static int
++au1550_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
++							unsigned long arg)
++{
++	struct au1550_state *s = (struct au1550_state *)file->private_data;
++	unsigned long   flags;
++	audio_buf_info  abinfo;
++	count_info      cinfo;
++	int             count;
++	int             val, mapped, ret, diff;
++
++	mapped = ((file->f_mode & FMODE_WRITE) && s->dma_dac.mapped) ||
++		((file->f_mode & FMODE_READ) && s->dma_adc.mapped);
++
++#ifdef AU1000_VERBOSE_DEBUG
++	for (count=0; count<sizeof(ioctl_str)/sizeof(ioctl_str[0]); count++) {
++		if (ioctl_str[count].cmd == cmd)
++			break;
++	}
++	if (count < sizeof(ioctl_str) / sizeof(ioctl_str[0]))
++		dbg("ioctl %s, arg=0x%lx", ioctl_str[count].str, arg);
++	else
++		dbg("ioctl 0x%x unknown, arg=0x%lx", cmd, arg);
++#endif
++
++	switch (cmd) {
++	case OSS_GETVERSION:
++		return put_user(SOUND_VERSION, (int *) arg);
++
++	case SNDCTL_DSP_SYNC:
++		if (file->f_mode & FMODE_WRITE)
++			return drain_dac(s, file->f_flags & O_NONBLOCK);
++		return 0;
++
++	case SNDCTL_DSP_SETDUPLEX:
++		return 0;
++
++	case SNDCTL_DSP_GETCAPS:
++		return put_user(DSP_CAP_DUPLEX | DSP_CAP_REALTIME |
++				DSP_CAP_TRIGGER | DSP_CAP_MMAP, (int *)arg);
++
++	case SNDCTL_DSP_RESET:
++		if (file->f_mode & FMODE_WRITE) {
++			stop_dac(s);
++			synchronize_irq();
++			s->dma_dac.count = s->dma_dac.total_bytes = 0;
++			s->dma_dac.nextIn = s->dma_dac.nextOut =
++				s->dma_dac.rawbuf;
++		}
++		if (file->f_mode & FMODE_READ) {
++			stop_adc(s);
++			synchronize_irq();
++			s->dma_adc.count = s->dma_adc.total_bytes = 0;
++			s->dma_adc.nextIn = s->dma_adc.nextOut =
++				s->dma_adc.rawbuf;
++		}
++		return 0;
++
++	case SNDCTL_DSP_SPEED:
++		if (get_user(val, (int *) arg))
++			return -EFAULT;
++		if (val >= 0) {
++			if (file->f_mode & FMODE_READ) {
++				stop_adc(s);
++				set_adc_rate(s, val);
++			}
++			if (file->f_mode & FMODE_WRITE) {
++				stop_dac(s);
++				set_dac_rate(s, val);
++			}
++			if (s->open_mode & FMODE_READ)
++				if ((ret = prog_dmabuf_adc(s)))
++					return ret;
++			if (s->open_mode & FMODE_WRITE)
++				if ((ret = prog_dmabuf_dac(s)))
++					return ret;
++		}
++		return put_user((file->f_mode & FMODE_READ) ?
++				s->dma_adc.sample_rate :
++				s->dma_dac.sample_rate,
++				(int *)arg);
++
++	case SNDCTL_DSP_STEREO:
++		if (get_user(val, (int *) arg))
++			return -EFAULT;
++		if (file->f_mode & FMODE_READ) {
++			stop_adc(s);
++			s->dma_adc.num_channels = val ? 2 : 1;
++			if ((ret = prog_dmabuf_adc(s)))
++				return ret;
++		}
++		if (file->f_mode & FMODE_WRITE) {
++			stop_dac(s);
++			s->dma_dac.num_channels = val ? 2 : 1;
++			if ((ret = prog_dmabuf_dac(s)))
++				return ret;
++		}
++		return 0;
++
++	case SNDCTL_DSP_CHANNELS:
++		if (get_user(val, (int *) arg))
++			return -EFAULT;
++		if (val != 0) {
++			if (file->f_mode & FMODE_READ) {
++				if (val < 0 || val > 2)
++					return -EINVAL;
++				stop_adc(s);
++				s->dma_adc.num_channels = val;
++				if ((ret = prog_dmabuf_adc(s)))
++					return ret;
++			}
++			if (file->f_mode & FMODE_WRITE) {
++				switch (val) {
++				case 1:
++				case 2:
++					break;
++				default:
++					return -EINVAL;
++				}
++
++				stop_dac(s);
++				s->dma_dac.num_channels = val;
++				if ((ret = prog_dmabuf_dac(s)))
++					return ret;
++			}
++		}
++		return put_user(val, (int *) arg);
++
++	case SNDCTL_DSP_GETFMTS:	/* Returns a mask */
++		return put_user(AFMT_S16_LE | AFMT_U8, (int *) arg);
++
++	case SNDCTL_DSP_SETFMT:	/* Selects ONE fmt */
++		if (get_user(val, (int *) arg))
++			return -EFAULT;
++		if (val != AFMT_QUERY) {
++			if (file->f_mode & FMODE_READ) {
++				stop_adc(s);
++				if (val == AFMT_S16_LE)
++					s->dma_adc.sample_size = 16;
++				else {
++					val = AFMT_U8;
++					s->dma_adc.sample_size = 8;
++				}
++				if ((ret = prog_dmabuf_adc(s)))
++					return ret;
++			}
++			if (file->f_mode & FMODE_WRITE) {
++				stop_dac(s);
++				if (val == AFMT_S16_LE)
++					s->dma_dac.sample_size = 16;
++				else {
++					val = AFMT_U8;
++					s->dma_dac.sample_size = 8;
++				}
++				if ((ret = prog_dmabuf_dac(s)))
++					return ret;
++			}
++		} else {
++			if (file->f_mode & FMODE_READ)
++				val = (s->dma_adc.sample_size == 16) ?
++					AFMT_S16_LE : AFMT_U8;
++			else
++				val = (s->dma_dac.sample_size == 16) ?
++					AFMT_S16_LE : AFMT_U8;
++		}
++		return put_user(val, (int *) arg);
++
++	case SNDCTL_DSP_POST:
++		return 0;
++
++	case SNDCTL_DSP_GETTRIGGER:
++		val = 0;
++		spin_lock_irqsave(&s->lock, flags);
++		if (file->f_mode & FMODE_READ && !s->dma_adc.stopped)
++			val |= PCM_ENABLE_INPUT;
++		if (file->f_mode & FMODE_WRITE && !s->dma_dac.stopped)
++			val |= PCM_ENABLE_OUTPUT;
++		spin_unlock_irqrestore(&s->lock, flags);
++		return put_user(val, (int *) arg);
++
++	case SNDCTL_DSP_SETTRIGGER:
++		if (get_user(val, (int *) arg))
++			return -EFAULT;
++		if (file->f_mode & FMODE_READ) {
++			if (val & PCM_ENABLE_INPUT)
++				start_adc(s);
++			else
++				stop_adc(s);
++		}
++		if (file->f_mode & FMODE_WRITE) {
++			if (val & PCM_ENABLE_OUTPUT)
++				start_dac(s);
++			else
++				stop_dac(s);
++		}
++		return 0;
++
++	case SNDCTL_DSP_GETOSPACE:
++		if (!(file->f_mode & FMODE_WRITE))
++			return -EINVAL;
++		abinfo.fragsize = s->dma_dac.fragsize;
++		spin_lock_irqsave(&s->lock, flags);
++		count = s->dma_dac.count;
++		count -= dma_count_done(&s->dma_dac);
++		spin_unlock_irqrestore(&s->lock, flags);
++		if (count < 0)
++			count = 0;
++		abinfo.bytes = (s->dma_dac.dmasize - count) /
++			s->dma_dac.cnt_factor;
++		abinfo.fragstotal = s->dma_dac.numfrag;
++		abinfo.fragments = abinfo.bytes >> s->dma_dac.fragshift;
++#ifdef AU1000_VERBOSE_DEBUG
++		dbg("bytes=%d, fragments=%d", abinfo.bytes, abinfo.fragments);
++#endif
++		return copy_to_user((void *) arg, &abinfo,
++				    sizeof(abinfo)) ? -EFAULT : 0;
++
++	case SNDCTL_DSP_GETISPACE:
++		if (!(file->f_mode & FMODE_READ))
++			return -EINVAL;
++		abinfo.fragsize = s->dma_adc.fragsize;
++		spin_lock_irqsave(&s->lock, flags);
++		count = s->dma_adc.count;
++		count += dma_count_done(&s->dma_adc);
++		spin_unlock_irqrestore(&s->lock, flags);
++		if (count < 0)
++			count = 0;
++		abinfo.bytes = count / s->dma_adc.cnt_factor;
++		abinfo.fragstotal = s->dma_adc.numfrag;
++		abinfo.fragments = abinfo.bytes >> s->dma_adc.fragshift;
++		return copy_to_user((void *) arg, &abinfo,
++				    sizeof(abinfo)) ? -EFAULT : 0;
++
++	case SNDCTL_DSP_NONBLOCK:
++		file->f_flags |= O_NONBLOCK;
++		return 0;
++
++	case SNDCTL_DSP_GETODELAY:
++		if (!(file->f_mode & FMODE_WRITE))
++			return -EINVAL;
++		spin_lock_irqsave(&s->lock, flags);
++		count = s->dma_dac.count;
++		count -= dma_count_done(&s->dma_dac);
++		spin_unlock_irqrestore(&s->lock, flags);
++		if (count < 0)
++			count = 0;
++		count /= s->dma_dac.cnt_factor;
++		return put_user(count, (int *) arg);
++
++	case SNDCTL_DSP_GETIPTR:
++		if (!(file->f_mode & FMODE_READ))
++			return -EINVAL;
++		spin_lock_irqsave(&s->lock, flags);
++		cinfo.bytes = s->dma_adc.total_bytes;
++		count = s->dma_adc.count;
++		if (!s->dma_adc.stopped) {
++			diff = dma_count_done(&s->dma_adc);
++			count += diff;
++			cinfo.bytes += diff;
++			cinfo.ptr =  virt_to_phys(s->dma_adc.nextIn) + diff -
++				virt_to_phys(s->dma_adc.rawbuf);
++		} else
++			cinfo.ptr = virt_to_phys(s->dma_adc.nextIn) -
++				virt_to_phys(s->dma_adc.rawbuf);
++		if (s->dma_adc.mapped)
++			s->dma_adc.count &= (s->dma_adc.dma_fragsize-1);
++		spin_unlock_irqrestore(&s->lock, flags);
++		if (count < 0)
++			count = 0;
++		cinfo.blocks = count >> s->dma_adc.fragshift;
++		return copy_to_user((void *) arg, &cinfo, sizeof(cinfo));
++
++	case SNDCTL_DSP_GETOPTR:
++		if (!(file->f_mode & FMODE_READ))
++			return -EINVAL;
++		spin_lock_irqsave(&s->lock, flags);
++		cinfo.bytes = s->dma_dac.total_bytes;
++		count = s->dma_dac.count;
++		if (!s->dma_dac.stopped) {
++			diff = dma_count_done(&s->dma_dac);
++			count -= diff;
++			cinfo.bytes += diff;
++			cinfo.ptr = virt_to_phys(s->dma_dac.nextOut) + diff -
++				virt_to_phys(s->dma_dac.rawbuf);
++		} else
++			cinfo.ptr = virt_to_phys(s->dma_dac.nextOut) -
++				virt_to_phys(s->dma_dac.rawbuf);
++		if (s->dma_dac.mapped)
++			s->dma_dac.count &= (s->dma_dac.dma_fragsize-1);
++		spin_unlock_irqrestore(&s->lock, flags);
++		if (count < 0)
++			count = 0;
++		cinfo.blocks = count >> s->dma_dac.fragshift;
++		return copy_to_user((void *) arg, &cinfo, sizeof(cinfo));
++
++	case SNDCTL_DSP_GETBLKSIZE:
++		if (file->f_mode & FMODE_WRITE)
++			return put_user(s->dma_dac.fragsize, (int *) arg);
++		else
++			return put_user(s->dma_adc.fragsize, (int *) arg);
++
++	case SNDCTL_DSP_SETFRAGMENT:
++		if (get_user(val, (int *) arg))
++			return -EFAULT;
++		if (file->f_mode & FMODE_READ) {
++			stop_adc(s);
++			s->dma_adc.ossfragshift = val & 0xffff;
++			s->dma_adc.ossmaxfrags = (val >> 16) & 0xffff;
++			if (s->dma_adc.ossfragshift < 4)
++				s->dma_adc.ossfragshift = 4;
++			if (s->dma_adc.ossfragshift > 15)
++				s->dma_adc.ossfragshift = 15;
++			if (s->dma_adc.ossmaxfrags < 4)
++				s->dma_adc.ossmaxfrags = 4;
++			if ((ret = prog_dmabuf_adc(s)))
++				return ret;
++		}
++		if (file->f_mode & FMODE_WRITE) {
++			stop_dac(s);
++			s->dma_dac.ossfragshift = val & 0xffff;
++			s->dma_dac.ossmaxfrags = (val >> 16) & 0xffff;
++			if (s->dma_dac.ossfragshift < 4)
++				s->dma_dac.ossfragshift = 4;
++			if (s->dma_dac.ossfragshift > 15)
++				s->dma_dac.ossfragshift = 15;
++			if (s->dma_dac.ossmaxfrags < 4)
++				s->dma_dac.ossmaxfrags = 4;
++			if ((ret = prog_dmabuf_dac(s)))
++				return ret;
++		}
++		return 0;
++
++	case SNDCTL_DSP_SUBDIVIDE:
++		if ((file->f_mode & FMODE_READ && s->dma_adc.subdivision) ||
++		    (file->f_mode & FMODE_WRITE && s->dma_dac.subdivision))
++			return -EINVAL;
++		if (get_user(val, (int *) arg))
++			return -EFAULT;
++		if (val != 1 && val != 2 && val != 4)
++			return -EINVAL;
++		if (file->f_mode & FMODE_READ) {
++			stop_adc(s);
++			s->dma_adc.subdivision = val;
++			if ((ret = prog_dmabuf_adc(s)))
++				return ret;
++		}
++		if (file->f_mode & FMODE_WRITE) {
++			stop_dac(s);
++			s->dma_dac.subdivision = val;
++			if ((ret = prog_dmabuf_dac(s)))
++				return ret;
++		}
++		return 0;
++
++	case SOUND_PCM_READ_RATE:
++		return put_user((file->f_mode & FMODE_READ) ?
++				s->dma_adc.sample_rate :
++				s->dma_dac.sample_rate,
++				(int *)arg);
++
++	case SOUND_PCM_READ_CHANNELS:
++		if (file->f_mode & FMODE_READ)
++			return put_user(s->dma_adc.num_channels, (int *)arg);
++		else
++			return put_user(s->dma_dac.num_channels, (int *)arg);
++
++	case SOUND_PCM_READ_BITS:
++		if (file->f_mode & FMODE_READ)
++			return put_user(s->dma_adc.sample_size, (int *)arg);
++		else
++			return put_user(s->dma_dac.sample_size, (int *)arg);
++
++	case SOUND_PCM_WRITE_FILTER:
++	case SNDCTL_DSP_SETSYNCRO:
++	case SOUND_PCM_READ_FILTER:
++		return -EINVAL;
++	}
++
++	return 0;
++}
++
++
++static int
++au1550_open(struct inode *inode, struct file *file)
++{
++	int             minor = MINOR(inode->i_rdev);
++	DECLARE_WAITQUEUE(wait, current);
++	struct au1550_state *s = &au1550_state;
++	int             ret;
++
++#ifdef AU1000_VERBOSE_DEBUG
++	if (file->f_flags & O_NONBLOCK)
++		dbg(__FUNCTION__ ": non-blocking");
++	else
++		dbg(__FUNCTION__ ": blocking");
++#endif
++
++	file->private_data = s;
++	/* wait for device to become free */
++	down(&s->open_sem);
++	while (s->open_mode & file->f_mode) {
++		if (file->f_flags & O_NONBLOCK) {
++			up(&s->open_sem);
++			return -EBUSY;
++		}
++		add_wait_queue(&s->open_wait, &wait);
++		__set_current_state(TASK_INTERRUPTIBLE);
++		up(&s->open_sem);
++		schedule();
++		remove_wait_queue(&s->open_wait, &wait);
++		set_current_state(TASK_RUNNING);
++		if (signal_pending(current))
++			return -ERESTARTSYS;
++		down(&s->open_sem);
++	}
++
++	stop_dac(s);
++	stop_adc(s);
++
++	if (file->f_mode & FMODE_READ) {
++		s->dma_adc.ossfragshift = s->dma_adc.ossmaxfrags =
++			s->dma_adc.subdivision = s->dma_adc.total_bytes = 0;
++		s->dma_adc.num_channels = 1;
++		s->dma_adc.sample_size = 8;
++		set_adc_rate(s, 8000);
++		if ((minor & 0xf) == SND_DEV_DSP16)
++			s->dma_adc.sample_size = 16;
++	}
++
++	if (file->f_mode & FMODE_WRITE) {
++		s->dma_dac.ossfragshift = s->dma_dac.ossmaxfrags =
++			s->dma_dac.subdivision = s->dma_dac.total_bytes = 0;
++		s->dma_dac.num_channels = 1;
++		s->dma_dac.sample_size = 8;
++		set_dac_rate(s, 8000);
++		if ((minor & 0xf) == SND_DEV_DSP16)
++			s->dma_dac.sample_size = 16;
++	}
++
++	if (file->f_mode & FMODE_READ) {
++		if ((ret = prog_dmabuf_adc(s)))
++			return ret;
++	}
++	if (file->f_mode & FMODE_WRITE) {
++		if ((ret = prog_dmabuf_dac(s)))
++			return ret;
++	}
++
++	s->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE);
++	up(&s->open_sem);
++	init_MUTEX(&s->sem);
++	return 0;
++}
++
++static int
++au1550_release(struct inode *inode, struct file *file)
++{
++	struct au1550_state *s = (struct au1550_state *)file->private_data;
++
++	lock_kernel();
++
++	if (file->f_mode & FMODE_WRITE) {
++		unlock_kernel();
++		drain_dac(s, file->f_flags & O_NONBLOCK);
++		lock_kernel();
++	}
++
++	down(&s->open_sem);
++	if (file->f_mode & FMODE_WRITE) {
++		stop_dac(s);
++		kfree(s->dma_dac.rawbuf);
++		s->dma_dac.rawbuf = NULL;
++	}
++	if (file->f_mode & FMODE_READ) {
++		stop_adc(s);
++		kfree(s->dma_adc.rawbuf);
++		s->dma_adc.rawbuf = NULL;
++	}
++	s->open_mode &= ((~file->f_mode) & (FMODE_READ|FMODE_WRITE));
++	up(&s->open_sem);
++	wake_up(&s->open_wait);
++	unlock_kernel();
++	return 0;
++}
++
++static struct file_operations au1550_audio_fops = {
++	owner:		THIS_MODULE,
++	llseek:		au1550_llseek,
++	read:		au1550_read,
++	write:		au1550_write,
++	poll:		au1550_poll,
++	ioctl:		au1550_ioctl,
++	mmap:		au1550_mmap,
++	open:		au1550_open,
++	release:	au1550_release,
++};
++
++/* Set up an internal clock for the PSC3.  This will then get
++ * driven out of the Au1550 as the master.
++ */
++static void
++intclk_setup(void)
++{
++	uint clk, rate;
++
++	/* Wire up Freq4 as a clock for the PSC3.
++	 * We know SMBus uses Freq3.
++	 * By making changes to this rate, plus the word strobe
++	 * size, we can make fine adjustments to the actual data rate.
++	 */
++	rate = get_au1x00_speed();
++#ifdef TRY_441KHz
++	rate /= (11 * 1000000);
++#else
++	rate /= (12 * 1000000);
++#endif
++
++	/* The FRDIV in the frequency control is (FRDIV + 1) * 2
++	*/
++	rate /=2;
++	rate--;
++	clk = au_readl(SYS_FREQCTRL1);
++	au_sync();
++	clk &= ~(SYS_FC_FRDIV4_MASK | SYS_FC_FS4);;
++	clk |= (rate << SYS_FC_FRDIV4_BIT);
++	clk |= SYS_FC_FE4;
++	au_writel(clk, SYS_FREQCTRL1);
++	au_sync();
++
++	/* Set up the clock source routing to get Freq4 to PSC3_intclk.
++	*/
++	clk = au_readl(SYS_CLKSRC);
++	au_sync();
++	clk &= ~0x01f00000;
++	clk |= (6 << 22);
++	au_writel(clk, SYS_CLKSRC);
++	au_sync();
++}
++
++static int __devinit
++au1550_probe(void)
++{
++	struct au1550_state *s = &au1550_state;
++	int val;
++	volatile psc_i2s_t *ip;
++#ifdef AU1550_DEBUG
++	char proc_str[80];
++#endif
++
++	memset(s, 0, sizeof(struct au1550_state));
++
++	init_waitqueue_head(&s->dma_adc.wait);
++	init_waitqueue_head(&s->dma_dac.wait);
++	init_waitqueue_head(&s->open_wait);
++	init_MUTEX(&s->open_sem);
++	spin_lock_init(&s->lock);
++
++	s->codec = &au1550_i2s_codec;
++	s->psc_addr = (volatile psc_i2s_t *)I2S_PSC_BASE;
++	ip = s->psc_addr;
++
++	if (!request_region(CPHYSADDR(ip),
++			    0x30, AU1550_MODULE_NAME)) {
++		pr_error("I2S Audio ports in use");
++	}
++
++	/* Allocate the DMA Channels
++	*/
++	if ((s->dma_dac.dmanr = au1xxx_dbdma_chan_alloc(DBDMA_MEM_CHAN,
++	    DBDMA_I2S_TX_CHAN, dac_dma_interrupt, (void *)s)) == 0) {
++		pr_error("Can't get DAC DMA");
++		goto err_dma1;
++	}
++	au1xxx_dbdma_set_devwidth(s->dma_dac.dmanr, 16);
++	if (au1xxx_dbdma_ring_alloc(s->dma_dac.dmanr,
++					NUM_DBDMA_DESCRIPTORS) == 0) {
++		pr_error("Can't get DAC DMA descriptors");
++		goto err_dma1;
++	}
++
++	if ((s->dma_adc.dmanr = au1xxx_dbdma_chan_alloc(DBDMA_I2S_RX_CHAN,
++	    DBDMA_MEM_CHAN, adc_dma_interrupt, (void *)s)) == 0) {
++		pr_error("Can't get ADC DMA");
++		goto err_dma2;
++	}
++	au1xxx_dbdma_set_devwidth(s->dma_adc.dmanr, 16);
++	if (au1xxx_dbdma_ring_alloc(s->dma_adc.dmanr,
++					NUM_DBDMA_DESCRIPTORS) == 0) {
++		pr_error("Can't get ADC DMA descriptors");
++		goto err_dma2;
++	}
++
++	pr_info("DAC: DMA%d, ADC: DMA%d", DBDMA_I2S_TX_CHAN, DBDMA_I2S_RX_CHAN);
++
++	/* register devices */
++
++	if ((s->dev_audio = register_sound_dsp(&au1550_audio_fops, -1)) < 0)
++		goto err_dev1;
++
++	if ((s->dev_mixer = register_sound_mixer(&au1550_mixer_fops, -1)) < 0)
++		goto err_dev2;
++
++#ifdef AU1550_DEBUG
++	/* intialize the debug proc device */
++	s->ps = create_proc_read_entry(AU1000_MODULE_NAME, 0, NULL,
++				       proc_au1550_dump, NULL);
++#endif /* AU1550_DEBUG */
++
++	intclk_setup();
++
++	/* The GPIO for the appropriate PSC was configured by the
++	 * board specific start up.
++	 *
++	 * configure PSC for I2S Audio
++	 */
++	ip->psc_ctrl = PSC_CTRL_DISABLE;	/* Disable PSC */
++	au_sync();
++	ip->psc_sel = (PSC_SEL_CLK_INTCLK | PSC_SEL_PS_I2SMODE);
++	au_sync();
++
++	/* Enable PSC
++	*/
++	ip->psc_ctrl = PSC_CTRL_ENABLE;
++	au_sync();
++
++	/* Wait for PSC ready.
++	*/
++	do {
++		val = ip->psc_i2sstat;
++		au_sync();
++	} while ((val & PSC_I2SSTAT_SR) == 0);
++
++	/* Configure I2S controller.
++	 * Deep FIFO, 16-bit sample, DMA, make sure DMA matches fifo size.
++	 * Actual I2S mode (first bit delayed by one clock).
++	 * Master mode (We provide the clock from the PSC).
++	 */
++	val = PSC_I2SCFG_SET_LEN(16);
++#ifdef TRY_441KHz
++	/* This really should be 250, but it appears that all of the
++	 * PLLs, dividers and so on in the chain shift it.  That's the
++	 * problem with sourceing the clock instead of letting the very
++	 * stable codec provide it.  But, the PSC doesn't appear to want
++	 * to work in slave mode, so this is what we get.  It's  not
++	 * studio quality timing, but it's good enough for listening
++	 * to mp3s.
++	 */
++	val |= PSC_I2SCFG_SET_WS(252);
++#else
++	val |= PSC_I2SCFG_SET_WS(250);
++#endif
++	val |= PSC_I2SCFG_RT_FIFO8 | PSC_I2SCFG_TT_FIFO8 | \
++					PSC_I2SCFG_BI | PSC_I2SCFG_XM;
++
++	ip->psc_i2scfg = val;
++	au_sync();
++	val |= PSC_I2SCFG_DE_ENABLE;
++	ip->psc_i2scfg = val;
++	au_sync();
++
++	/* Wait for Device ready.
++	*/
++	do {
++		val = ip->psc_i2sstat;
++		au_sync();
++	} while ((val & PSC_I2SSTAT_DR) == 0);
++
++	val = ip->psc_i2scfg;
++	au_sync();
++
++	s->codec->init_codec(s->codec);
++
++	return 0;
++
++ err_dev2:
++	unregister_sound_dsp(s->dev_audio);
++ err_dev1:
++	au1xxx_dbdma_chan_free(s->dma_adc.dmanr);
++ err_dma2:
++	au1xxx_dbdma_chan_free(s->dma_dac.dmanr);
++ err_dma1:
++	release_region(CPHYSADDR(I2S_PSC_BASE), 0x30);
++
++	return -1;
++}
++
++static void __devinit
++au1550_remove(void)
++{
++	struct au1550_state *s = &au1550_state;
++
++	if (!s)
++		return;
++#ifdef AU1550_DEBUG
++	if (s->ps)
++		remove_proc_entry(AU1000_MODULE_NAME, NULL);
++#endif /* AU1000_DEBUG */
++	synchronize_irq();
++	au1xxx_dbdma_chan_free(s->dma_adc.dmanr);
++	au1xxx_dbdma_chan_free(s->dma_dac.dmanr);
++	release_region(CPHYSADDR(I2S_PSC_BASE), 0x30);
++	unregister_sound_dsp(s->dev_audio);
++	unregister_sound_mixer(s->dev_mixer);
++}
++
++static int __init
++init_au1550(void)
++{
++	return au1550_probe();
++}
++
++static void __exit
++cleanup_au1550(void)
++{
++	au1550_remove();
++}
++
++module_init(init_au1550);
++module_exit(cleanup_au1550);
++
++MODULE_AUTHOR("Advanced Micro Devices (AMD), dan at embeddededge.com");
++MODULE_DESCRIPTION("Au1550 I2S Audio Driver");




More information about the patches mailing list